platform-drivers-x86 for v6.19-1
Highlights:
- acer-wmi: Add PH16-72, PHN16-72, and PT14-51 fan control support
- acpi: platform_profile: Add max-power profile option (power draw limited
by the cooling hardware, may exceed battery power
draw limit when on AC power)
- amd/hsmp: Allow >1 data-fabric per socket
- asus-armoury: Add WMI attributes driver to expose miscellaneous
WMI functions through fw_attributes (deprecates
the custom BIOS features interface through asus-wmi)
- asus-wmi: Use brightness_set_blocking() for kbd led
- ayaneo-ec: Add Ayaneo Embedded Controller driver
- fs/nls:
- Fix utf16 -> utf8 string conversion in output size restricted cases
- Improve error code consistency for utf8 -> utf32 conversions
- ideapad-laptop: Fast (Rapid Charge) charge type support
- intel/hid: Add Dell Pro Rugged 10/12 tablet to VGBS DMI quirks
- intel/pmc:
- Arrow Lake telemetry GUID improvements
- Add support for Wildcat Lake PMC information
- intel_pmc_ipc: Fix ACPI buffer memleak
- intel/punit_ipc: Fix memory corruption
- intel/vsec: Wildcat Lake PMT telemetry support
- lenovo-wmi-gamezone: Map "Extreme" performance mode to max-power
- lg-laptop: Add support for the HDAP opregion field
- serial-multi-instantiate: Add IRQ_RESOURCE_OPT for IRQ missing projects
- thinkpad-t14s-ec: Improve suspend/resume support (lid LEDs, keyboard
backlight)
- uniwill: Add Uniwill laptop driver
- wmi: Move under drivers/platform/wmi as non-x86 WMI support is around
the corner and other WMI features will require adding more C
files as well
- tools/power/x86/intel-speed-select: v1.24
- Check feature status to check if the feature enablement was successful
- Reset SST-TF bucket structure to display valid bucket info
- Miscellaneous cleanups / refactoring / improvements
The following is an automated shortlog grouped by driver:
acer-wmi:
- Add fan control support
- Add support for PHN16-72
- Enable fan control for PH16-72 and PT14-51
- Fix setting of fan behavior
acpi:
- platform_profile - Add max-power profile option
Add Uniwill laptop driver:
- Add Uniwill laptop driver
alienware-wmi-wmax:
- Simplify FW profile to pprof matching
amd: hfi:
- Remove redundant assignment to .owner
- Remove unused cpumask from cpuinfo struct
amd/hsmp:
- Replace amd_num_nodes() with topology_max_packages()
amd/pmf:
- Add BIOS_INPUTS_MAX macro to replace hardcoded array size
- Refactor repetitive BIOS output handling
- Rename IPU metrics fields to NPU for consistency
- Replace magic table id with METRICS_TABLE_ID
- Use devm_mutex_init() for mutex initialization
- Use explicit SET_CMD/GET_CMD flags in amd_pmf_send_cmd()
arm64: thinkpad-t14s-ec:
- add suspend handler for keyboard backlight
- add system PM hooks
asus-armoury:
- add apu-mem control support
- add panel_hd_mode attribute
- add ppt_* and nv_* tuning knobs
- add screen auto-brightness toggle
- add support for FA507UV
- add support for GA503QR
- Fix error code in mini_led_mode_current_value_store()
- fix mini-led mode show
- fix only DC tunables being available
- move existing tunings to asus-armoury module
asus-wmi:
- deprecate bios features
- export symbols used for read/write WMI
- rename ASUS_WMI_DEVID_PPT_FPPT
- use brightness_set_blocking() for kbd led
ayaneo-ec:
- Add Ayaneo Embedded Controller platform driver
- Add charge control support
- Add controller power and modules attributes
- Add hwmon support
- Add suspend hook
- Move Ayaneo devices from oxpec to ayaneo-ec
Documentation: laptops:
- Add documentation for uniwill laptops
fs/nls:
- Fix inconsistency between utf8_to_utf32() and utf32_to_utf8()
- Fix utf16 to utf8 conversion
hp-wmi:
- Order DMI board name arrays
ideapad-laptop: Add charge_types:
- Fast (Rapid Charge)
ideapad-laptop:
- Protect GBMD/SBMC calls with mutex
- Support multiple power_supply_ext definitions
- Use str_on_off() helper
intel/hid:
- Add Dell Pro Rugged 10/12 tablet to VGBS DMI quirks
intel/pmc:
- Add DMU GUID to Arrow Lake U/H
- Add support for multiple DMU GUIDs
- Enable SSRAM support for Wildcat Lake
intel_pmc_ipc:
- fix ACPI buffer memory leak
intel/pmc:
- Relocate lpm_req_guid to pmc_reg_map
- Remove redundant has_die_c6 variable
- Rename PMC index variable to pmc_idx
- Update Arrow Lake telemetry GUID
intel/vsec:
- Add support for Wildcat Lake
lenovo-wmi-gamezone Use max-power rather than balanced-performance:
- lenovo-wmi-gamezone Use max-power rather than balanced-performance
lg-laptop:
- Add support for the HDAP opregion field
serial-multi-instantiate:
- Add IRQ_RESOURCE_OPT for IRQ missing projects
surface: acpi-notify:
- add WQ_PERCPU to alloc_workqueue users
surface: aggregator:
- Omit a variable reassignment in ssam_serial_hub_probe()
surface:
- replace use of system_wq with system_percpu_wq
tools/power/x86/intel-speed-select:
- Check feature status
- Reset isst_turbo_freq_info for invalid buckets
- v1.24 release
uniwill:
- Add TUXEDO devices
- Handle more WMI events required for TUXEDO devices
wmi-gamezone:
- Add Legion Go 2 Quirks
wmi:
- Move WMI core code into a separate directory
- Remove extern keyword from prototypes
- Use correct type when populating ACPI objects
x86-android-tablets:
- Omit a variable reassignment in lenovo_yoga_tab2_830_1050_init_codec()
x86:
- replace use of system_wq with system_percpu_wq
Merges:
- Merge branch 'fixes' of into for-next
- Merge branch 'intel-sst' of https://github.com/spandruvada/linux-kernel into for-next
-----BEGIN PGP SIGNATURE-----
iHUEABYIAB0WIQSCSUwRdwTNL2MhaBlZrE9hU+XOMQUCaTgl5wAKCRBZrE9hU+XO
McWDAP4nmj5+EeHsg3Kl0kQ1lqF9llWI4EM2NeRd6MwrV5klxgD9FLW6djGkmP2j
RjtZ4CULbtQ3QMl7kmXhfAjRwJfiSgk=
=yFvQ
-----END PGP SIGNATURE-----
Merge tag 'platform-drivers-x86-v6.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86
Pull x86 platform driver updates from Ilpo Järvinen:
- acer-wmi: Add PH16-72, PHN16-72, and PT14-51 fan control support
- acpi: platform_profile: Add max-power profile option (power draw
limited by the cooling hardware, may exceed battery power draw limit
when on AC power)
- amd/hsmp: Allow more than one data-fabric per socket
- asus-armoury: Add WMI attributes driver to expose miscellaneous WMI
functions through fw_attributes (deprecates the custom BIOS features
interface through asus-wmi)
- asus-wmi: Use brightness_set_blocking() for kbd led
- ayaneo-ec: Add Ayaneo Embedded Controller driver
- fs/nls:
- Fix utf16 to utf8 string conversion when output size restricted
- Improve error code consistency for utf8 to utf32 conversions
- ideapad-laptop: Fast (Rapid Charge) charge type support
- intel/hid: Add Dell Pro Rugged 10/12 tablet to VGBS DMI quirks
- intel/pmc:
- Arrow Lake telemetry GUID improvements
- Add support for Wildcat Lake PMC information
- intel_pmc_ipc: Fix ACPI buffer memleak
- intel/punit_ipc: Fix memory corruption
- intel/vsec: Wildcat Lake PMT telemetry support
- lenovo-wmi-gamezone: Map "Extreme" performance mode to max-power
- lg-laptop: Add support for the HDAP opregion field
- serial-multi-instantiate: Add IRQ_RESOURCE_OPT for IRQ missing
projects
- thinkpad-t14s-ec: Improve suspend/resume support (lid LEDs, keyboard
backlight)
- uniwill: Add Uniwill laptop driver
- wmi: Move under drivers/platform/wmi as non-x86 WMI support is around
the corner and other WMI features will require adding more C files as
well
- tools/power/x86/intel-speed-select: v1.24
- Check feature status to check if the feature enablement was
successful
- Reset SST-TF bucket structure to display valid bucket info
- Miscellaneous cleanups / refactoring / improvements
* tag 'platform-drivers-x86-v6.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (73 commits)
tools/power/x86/intel-speed-select: v1.24 release
tools/power/x86/intel-speed-select: Reset isst_turbo_freq_info for invalid buckets
tools/power/x86/intel-speed-select: Check feature status
platform/x86: asus-wmi: use brightness_set_blocking() for kbd led
fs/nls: Fix inconsistency between utf8_to_utf32() and utf32_to_utf8()
platform/x86: asus-armoury: add support for GA503QR
platform/x86: intel_pmc_ipc: fix ACPI buffer memory leak
platform/x86: hp-wmi: Order DMI board name arrays
platform/x86/intel/hid: Add Dell Pro Rugged 10/12 tablet to VGBS DMI quirks
platform: surface: replace use of system_wq with system_percpu_wq
platform: x86: replace use of system_wq with system_percpu_wq
platform/surface: acpi-notify: add WQ_PERCPU to alloc_workqueue users
platform/x86: wmi-gamezone: Add Legion Go 2 Quirks
platform/x86: lenovo-wmi-gamezone Use max-power rather than balanced-performance
acpi: platform_profile - Add max-power profile option
platform/x86/amd/pmf: Use devm_mutex_init() for mutex initialization
platform/x86/amd/pmf: Add BIOS_INPUTS_MAX macro to replace hardcoded array size
platform/x86: serial-multi-instantiate: Add IRQ_RESOURCE_OPT for IRQ missing projects
platform/x86/amd/pmf: Refactor repetitive BIOS output handling
platform/x86/uniwill: Add TUXEDO devices
...
master
commit
9d588a1140
|
|
@ -23,6 +23,8 @@ Description: This file contains a space-separated list of profiles supported
|
|||
power consumption with a slight bias
|
||||
towards performance
|
||||
performance High performance operation
|
||||
max-power Higher performance operation that may exceed
|
||||
internal battery draw limits when on AC power
|
||||
custom Driver defined custom profile
|
||||
==================== ========================================
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
What: /sys/bus/platform/devices/INOU0000:XX/fn_lock_toggle_enable
|
||||
Date: November 2025
|
||||
KernelVersion: 6.19
|
||||
Contact: Armin Wolf <W_Armin@gmx.de>
|
||||
Description:
|
||||
Allows userspace applications to enable/disable the FN lock feature
|
||||
of the integrated keyboard by writing "1"/"0" into this file.
|
||||
|
||||
Reading this file returns the current enable status of the FN lock functionality.
|
||||
|
||||
What: /sys/bus/platform/devices/INOU0000:XX/super_key_toggle_enable
|
||||
Date: November 2025
|
||||
KernelVersion: 6.19
|
||||
Contact: Armin Wolf <W_Armin@gmx.de>
|
||||
Description:
|
||||
Allows userspace applications to enable/disable the super key functionality
|
||||
of the integrated keyboard by writing "1"/"0" into this file.
|
||||
|
||||
Reading this file returns the current enable status of the super key functionality.
|
||||
|
||||
What: /sys/bus/platform/devices/INOU0000:XX/touchpad_toggle_enable
|
||||
Date: November 2025
|
||||
KernelVersion: 6.19
|
||||
Contact: Armin Wolf <W_Armin@gmx.de>
|
||||
Description:
|
||||
Allows userspace applications to enable/disable the touchpad toggle functionality
|
||||
of the integrated touchpad by writing "1"/"0" into this file.
|
||||
|
||||
Reading this file returns the current enable status of the touchpad toggle
|
||||
functionality.
|
||||
|
||||
What: /sys/bus/platform/devices/INOU0000:XX/rainbow_animation
|
||||
Date: November 2025
|
||||
KernelVersion: 6.19
|
||||
Contact: Armin Wolf <W_Armin@gmx.de>
|
||||
Description:
|
||||
Forces the integrated lightbar to display a rainbow animation when the machine
|
||||
is not suspended. Writing "1"/"0" into this file enables/disables this
|
||||
functionality.
|
||||
|
||||
Reading this file returns the current status of the rainbow animation functionality.
|
||||
|
||||
What: /sys/bus/platform/devices/INOU0000:XX/breathing_in_suspend
|
||||
Date: November 2025
|
||||
KernelVersion: 6.19
|
||||
Contact: Armin Wolf <W_Armin@gmx.de>
|
||||
Description:
|
||||
Causes the integrated lightbar to display a breathing animation when the machine
|
||||
has been suspended and is running on AC power. Writing "1"/"0" into this file
|
||||
enables/disables this functionality.
|
||||
|
||||
Reading this file returns the current status of the breathing animation
|
||||
functionality.
|
||||
|
|
@ -63,6 +63,7 @@ Date: Aug 2022
|
|||
KernelVersion: 6.1
|
||||
Contact: "Luke Jones" <luke@ljones.dev>
|
||||
Description:
|
||||
DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
|
||||
Switch the GPU hardware MUX mode. Laptops with this feature can
|
||||
can be toggled to boot with only the dGPU (discrete mode) or in
|
||||
standard Optimus/Hybrid mode. On switch a reboot is required:
|
||||
|
|
@ -75,6 +76,7 @@ Date: Aug 2022
|
|||
KernelVersion: 5.17
|
||||
Contact: "Luke Jones" <luke@ljones.dev>
|
||||
Description:
|
||||
DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
|
||||
Disable discrete GPU:
|
||||
* 0 - Enable dGPU,
|
||||
* 1 - Disable dGPU
|
||||
|
|
@ -84,6 +86,7 @@ Date: Aug 2022
|
|||
KernelVersion: 5.17
|
||||
Contact: "Luke Jones" <luke@ljones.dev>
|
||||
Description:
|
||||
DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
|
||||
Enable the external GPU paired with ROG X-Flow laptops.
|
||||
Toggling this setting will also trigger ACPI to disable the dGPU:
|
||||
|
||||
|
|
@ -95,6 +98,7 @@ Date: Aug 2022
|
|||
KernelVersion: 5.17
|
||||
Contact: "Luke Jones" <luke@ljones.dev>
|
||||
Description:
|
||||
DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
|
||||
Enable an LCD response-time boost to reduce or remove ghosting:
|
||||
* 0 - Disable,
|
||||
* 1 - Enable
|
||||
|
|
@ -104,6 +108,7 @@ Date: Jun 2023
|
|||
KernelVersion: 6.5
|
||||
Contact: "Luke Jones" <luke@ljones.dev>
|
||||
Description:
|
||||
DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
|
||||
Get the current charging mode being used:
|
||||
* 1 - Barrel connected charger,
|
||||
* 2 - USB-C charging
|
||||
|
|
@ -114,6 +119,7 @@ Date: Jun 2023
|
|||
KernelVersion: 6.5
|
||||
Contact: "Luke Jones" <luke@ljones.dev>
|
||||
Description:
|
||||
DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
|
||||
Show if the egpu (XG Mobile) is correctly connected:
|
||||
* 0 - False,
|
||||
* 1 - True
|
||||
|
|
@ -123,6 +129,7 @@ Date: Jun 2023
|
|||
KernelVersion: 6.5
|
||||
Contact: "Luke Jones" <luke@ljones.dev>
|
||||
Description:
|
||||
DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
|
||||
Change the mini-LED mode:
|
||||
* 0 - Single-zone,
|
||||
* 1 - Multi-zone
|
||||
|
|
@ -133,6 +140,7 @@ Date: Apr 2024
|
|||
KernelVersion: 6.10
|
||||
Contact: "Luke Jones" <luke@ljones.dev>
|
||||
Description:
|
||||
DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
|
||||
List the available mini-led modes.
|
||||
|
||||
What: /sys/devices/platform/<platform>/ppt_pl1_spl
|
||||
|
|
@ -140,6 +148,7 @@ Date: Jun 2023
|
|||
KernelVersion: 6.5
|
||||
Contact: "Luke Jones" <luke@ljones.dev>
|
||||
Description:
|
||||
DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
|
||||
Set the Package Power Target total of CPU: PL1 on Intel, SPL on AMD.
|
||||
Shown on Intel+Nvidia or AMD+Nvidia based systems:
|
||||
|
||||
|
|
@ -150,6 +159,7 @@ Date: Jun 2023
|
|||
KernelVersion: 6.5
|
||||
Contact: "Luke Jones" <luke@ljones.dev>
|
||||
Description:
|
||||
DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
|
||||
Set the Slow Package Power Tracking Limit of CPU: PL2 on Intel, SPPT,
|
||||
on AMD. Shown on Intel+Nvidia or AMD+Nvidia based systems:
|
||||
|
||||
|
|
@ -160,6 +170,7 @@ Date: Jun 2023
|
|||
KernelVersion: 6.5
|
||||
Contact: "Luke Jones" <luke@ljones.dev>
|
||||
Description:
|
||||
DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
|
||||
Set the Fast Package Power Tracking Limit of CPU. AMD+Nvidia only:
|
||||
* min=5, max=250
|
||||
|
||||
|
|
@ -168,6 +179,7 @@ Date: Jun 2023
|
|||
KernelVersion: 6.5
|
||||
Contact: "Luke Jones" <luke@ljones.dev>
|
||||
Description:
|
||||
DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
|
||||
Set the APU SPPT limit. Shown on full AMD systems only:
|
||||
* min=5, max=130
|
||||
|
||||
|
|
@ -176,6 +188,7 @@ Date: Jun 2023
|
|||
KernelVersion: 6.5
|
||||
Contact: "Luke Jones" <luke@ljones.dev>
|
||||
Description:
|
||||
DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
|
||||
Set the platform SPPT limit. Shown on full AMD systems only:
|
||||
* min=5, max=130
|
||||
|
||||
|
|
@ -184,6 +197,7 @@ Date: Jun 2023
|
|||
KernelVersion: 6.5
|
||||
Contact: "Luke Jones" <luke@ljones.dev>
|
||||
Description:
|
||||
DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
|
||||
Set the dynamic boost limit of the Nvidia dGPU:
|
||||
* min=5, max=25
|
||||
|
||||
|
|
@ -192,6 +206,7 @@ Date: Jun 2023
|
|||
KernelVersion: 6.5
|
||||
Contact: "Luke Jones" <luke@ljones.dev>
|
||||
Description:
|
||||
DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
|
||||
Set the target temperature limit of the Nvidia dGPU:
|
||||
* min=75, max=87
|
||||
|
||||
|
|
@ -200,6 +215,7 @@ Date: Apr 2024
|
|||
KernelVersion: 6.10
|
||||
Contact: "Luke Jones" <luke@ljones.dev>
|
||||
Description:
|
||||
DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
|
||||
Set if the BIOS POST sound is played on boot.
|
||||
* 0 - False,
|
||||
* 1 - True
|
||||
|
|
@ -209,6 +225,7 @@ Date: Apr 2024
|
|||
KernelVersion: 6.10
|
||||
Contact: "Luke Jones" <luke@ljones.dev>
|
||||
Description:
|
||||
DEPRECATED, WILL BE REMOVED SOON: please use asus-armoury
|
||||
Set if the MCU can go in to low-power mode on system sleep
|
||||
* 0 - False,
|
||||
* 1 - True
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
What: /sys/devices/platform/ayaneo-ec/controller_power
|
||||
Date: Nov 2025
|
||||
KernelVersion: 6.19
|
||||
Contact: "Antheas Kapenekakis" <lkml@antheas.dev>
|
||||
Description:
|
||||
Current controller power state. Allows turning on and off
|
||||
the controller power (e.g. for power savings). Write 1 to
|
||||
turn on, 0 to turn off. File is readable and writable.
|
||||
|
||||
What: /sys/devices/platform/ayaneo-ec/controller_modules
|
||||
Date: Nov 2025
|
||||
KernelVersion: 6.19
|
||||
Contact: "Antheas Kapenekakis" <lkml@antheas.dev>
|
||||
Description:
|
||||
Shows which controller modules are currently connected to
|
||||
the device. Possible values are "left", "right" and "both".
|
||||
File is read-only. The Windows software for this device
|
||||
will only set controller power to 1 if both module sides
|
||||
are connected (i.e. this file returns "both").
|
||||
|
|
@ -17,3 +17,4 @@ Laptop Drivers
|
|||
sonypi
|
||||
thinkpad-acpi
|
||||
toshiba_haps
|
||||
uniwill-laptop
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
Uniwill laptop extra features
|
||||
=============================
|
||||
|
||||
On laptops manufactured by Uniwill (either directly or as ODM), the ``uniwill-laptop`` driver
|
||||
handles various platform-specific features.
|
||||
|
||||
Module Loading
|
||||
--------------
|
||||
|
||||
The ``uniwill-laptop`` driver relies on a DMI table to automatically load on supported devices.
|
||||
When using the ``force`` module parameter, this DMI check will be omitted, allowing the driver
|
||||
to be loaded on unsupported devices for testing purposes.
|
||||
|
||||
Hotkeys
|
||||
-------
|
||||
|
||||
Usually the FN keys work without a special driver. However as soon as the ``uniwill-laptop`` driver
|
||||
is loaded, the FN keys need to be handled manually. This is done automatically by the driver itself.
|
||||
|
||||
Keyboard settings
|
||||
-----------------
|
||||
|
||||
The ``uniwill-laptop`` driver allows the user to enable/disable:
|
||||
|
||||
- the FN and super key lock functionality of the integrated keyboard
|
||||
- the touchpad toggle functionality of the integrated touchpad
|
||||
|
||||
See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for details.
|
||||
|
||||
Hwmon interface
|
||||
---------------
|
||||
|
||||
The ``uniwill-laptop`` driver supports reading of the CPU and GPU temperature and supports up to
|
||||
two fans. Userspace applications can access sensor readings over the hwmon sysfs interface.
|
||||
|
||||
Platform profile
|
||||
----------------
|
||||
|
||||
Support for changing the platform performance mode is currently not implemented.
|
||||
|
||||
Battery Charging Control
|
||||
------------------------
|
||||
|
||||
The ``uniwill-laptop`` driver supports controlling the battery charge limit. This happens over
|
||||
the standard ``charge_control_end_threshold`` power supply sysfs attribute. All values
|
||||
between 1 and 100 percent are supported.
|
||||
|
||||
Additionally the driver signals the presence of battery charging issues through the standard
|
||||
``health`` power supply sysfs attribute.
|
||||
|
||||
Lightbar
|
||||
--------
|
||||
|
||||
The ``uniwill-laptop`` driver exposes the lightbar found on some models as a standard multicolor
|
||||
LED class device. The default name of this LED class device is ``uniwill:multicolor:status``.
|
||||
|
||||
See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for details on how to control the various
|
||||
animation modes of the lightbar.
|
||||
|
|
@ -16,5 +16,5 @@ which will be bound to compatible WMI devices by the driver core.
|
|||
.. kernel-doc:: include/linux/wmi.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/platform/x86/wmi.c
|
||||
.. kernel-doc:: drivers/platform/wmi/core.c
|
||||
:export:
|
||||
|
|
|
|||
|
|
@ -19,27 +19,26 @@ WMI GUID ``887B54E3-DDDC-4B2C-8B88-68A26A8835D0``
|
|||
The Gamezone Data WMI interface provides platform-profile and fan curve
|
||||
settings for devices that fall under the "Gaming Series" of Lenovo devices.
|
||||
It uses a notifier chain to inform other Lenovo WMI interface drivers of the
|
||||
current platform profile when it changes.
|
||||
current platform profile when it changes. The currently set profile can be
|
||||
determined by the user on the hardware by looking at the color of the power
|
||||
or profile LED, depending on the model.
|
||||
|
||||
The following platform profiles are supported:
|
||||
- low-power
|
||||
- balanced
|
||||
- balanced-performance
|
||||
- performance
|
||||
- custom
|
||||
- low-power, blue LED
|
||||
- balanced, white LED
|
||||
- performance, red LED
|
||||
- max-power, purple LED
|
||||
- custom, purple LED
|
||||
|
||||
Balanced-Performance
|
||||
Extreme Mode
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
Some newer Lenovo "Gaming Series" laptops have an "Extreme Mode" profile
|
||||
enabled in their BIOS. For these devices, the performance platform profile
|
||||
corresponds to the BIOS Extreme Mode, while the balanced-performance
|
||||
platform profile corresponds to the BIOS Performance mode. For legacy
|
||||
devices, the performance platform profile will correspond with the BIOS
|
||||
Performance mode.
|
||||
enabled in their BIOS. When available, this mode will be represented by the
|
||||
max-power platform profile.
|
||||
|
||||
For some newer devices the "Extreme Mode" profile is incomplete in the BIOS
|
||||
and setting it will cause undefined behavior. A BIOS bug quirk table is
|
||||
provided to ensure these devices cannot set "Extreme Mode" from the driver.
|
||||
For a subset of these devices the "Extreme Mode" profile is incomplete in
|
||||
the BIOS and setting it will cause undefined behavior. A BIOS bug quirk table
|
||||
is provided to ensure these devices cannot set "Extreme Mode" from the driver.
|
||||
|
||||
Custom Profile
|
||||
~~~~~~~~~~~~~~
|
||||
|
|
|
|||
|
|
@ -0,0 +1,198 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
========================================
|
||||
Uniwill Notebook driver (uniwill-laptop)
|
||||
========================================
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
Many notebooks manufactured by Uniwill (either directly or as ODM) provide a EC interface
|
||||
for controlling various platform settings like sensors and fan control. This interface is
|
||||
used by the ``uniwill-laptop`` driver to map those features onto standard kernel interfaces.
|
||||
|
||||
EC WMI interface description
|
||||
============================
|
||||
|
||||
The EC WMI interface description can be decoded from the embedded binary MOF (bmof)
|
||||
data using the `bmfdec <https://github.com/pali/bmfdec>`_ utility:
|
||||
|
||||
::
|
||||
|
||||
[WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"),
|
||||
Description("Class used to operate methods on a ULong"),
|
||||
guid("{ABBC0F6F-8EA1-11d1-00A0-C90629100000}")]
|
||||
class AcpiTest_MULong {
|
||||
[key, read] string InstanceName;
|
||||
[read] boolean Active;
|
||||
|
||||
[WmiMethodId(1), Implemented, read, write, Description("Return the contents of a ULong")]
|
||||
void GetULong([out, Description("Ulong Data")] uint32 Data);
|
||||
|
||||
[WmiMethodId(2), Implemented, read, write, Description("Set the contents of a ULong")]
|
||||
void SetULong([in, Description("Ulong Data")] uint32 Data);
|
||||
|
||||
[WmiMethodId(3), Implemented, read, write,
|
||||
Description("Generate an event containing ULong data")]
|
||||
void FireULong([in, Description("WMI requires a parameter")] uint32 Hack);
|
||||
|
||||
[WmiMethodId(4), Implemented, read, write, Description("Get and Set the contents of a ULong")]
|
||||
void GetSetULong([in, Description("Ulong Data")] uint64 Data,
|
||||
[out, Description("Ulong Data")] uint32 Return);
|
||||
|
||||
[WmiMethodId(5), Implemented, read, write,
|
||||
Description("Get and Set the contents of a ULong for Dollby button")]
|
||||
void GetButton([in, Description("Ulong Data")] uint64 Data,
|
||||
[out, Description("Ulong Data")] uint32 Return);
|
||||
};
|
||||
|
||||
Most of the WMI-related code was copied from the Windows driver samples, which unfortunately means
|
||||
that the WMI-GUID is not unique. This makes the WMI-GUID unusable for autoloading.
|
||||
|
||||
WMI method GetULong()
|
||||
---------------------
|
||||
|
||||
This WMI method was copied from the Windows driver samples and has no function.
|
||||
|
||||
WMI method SetULong()
|
||||
---------------------
|
||||
|
||||
This WMI method was copied from the Windows driver samples and has no function.
|
||||
|
||||
WMI method FireULong()
|
||||
----------------------
|
||||
|
||||
This WMI method allows to inject a WMI event with a 32-bit payload. Its primary purpose seems
|
||||
to be debugging.
|
||||
|
||||
WMI method GetSetULong()
|
||||
------------------------
|
||||
|
||||
This WMI method is used to communicate with the EC. The ``Data`` argument holds the following
|
||||
information (starting with the least significant byte):
|
||||
|
||||
1. 16-bit address
|
||||
2. 16-bit data (set to ``0x0000`` when reading)
|
||||
3. 16-bit operation (``0x0100`` for reading and ``0x0000`` for writing)
|
||||
4. 16-bit reserved (set to ``0x0000``)
|
||||
|
||||
The first 8 bits of the ``Return`` value contain the data returned by the EC when reading.
|
||||
The special value ``0xFEFEFEFE`` is used to indicate a communication failure with the EC.
|
||||
|
||||
WMI method GetButton()
|
||||
----------------------
|
||||
|
||||
This WMI method is not implemented on all machines and has an unknown purpose.
|
||||
|
||||
Reverse-Engineering the EC WMI interface
|
||||
========================================
|
||||
|
||||
.. warning:: Randomly poking the EC can potentially cause damage to the machine and other unwanted
|
||||
side effects, please be careful.
|
||||
|
||||
The EC behind the ``GetSetULong`` method is used by the OEM software supplied by the manufacturer.
|
||||
Reverse-engineering of this software is difficult since it uses an obfuscator, however some parts
|
||||
are not obfuscated. In this case `dnSpy <https://github.com/dnSpy/dnSpy>`_ could also be helpful.
|
||||
|
||||
The EC can be accessed under Windows using powershell (requires admin privileges):
|
||||
|
||||
::
|
||||
|
||||
> $obj = Get-CimInstance -Namespace root/wmi -ClassName AcpiTest_MULong | Select-Object -First 1
|
||||
> Invoke-CimMethod -InputObject $obj -MethodName GetSetULong -Arguments @{Data = <input>}
|
||||
|
||||
WMI event interface description
|
||||
===============================
|
||||
|
||||
The WMI interface description can also be decoded from the embedded binary MOF (bmof)
|
||||
data:
|
||||
|
||||
::
|
||||
|
||||
[WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"),
|
||||
Description("Class containing event generated ULong data"),
|
||||
guid("{ABBC0F72-8EA1-11d1-00A0-C90629100000}")]
|
||||
class AcpiTest_EventULong : WmiEvent {
|
||||
[key, read] string InstanceName;
|
||||
[read] boolean Active;
|
||||
|
||||
[WmiDataId(1), read, write, Description("ULong Data")] uint32 ULong;
|
||||
};
|
||||
|
||||
Most of the WMI-related code was again copied from the Windows driver samples, causing this WMI
|
||||
interface to suffer from the same restrictions as the EC WMI interface described above.
|
||||
|
||||
WMI event data
|
||||
--------------
|
||||
|
||||
The WMI event data contains a single 32-bit value which is used to indicate various platform events.
|
||||
|
||||
Reverse-Engineering the Uniwill WMI event interface
|
||||
===================================================
|
||||
|
||||
The driver logs debug messages when receiving a WMI event. Thus enabling debug messages will be
|
||||
useful for finding unknown event codes.
|
||||
|
||||
EC ACPI interface description
|
||||
=============================
|
||||
|
||||
The ``INOU0000`` ACPI device is a virtual device used to access various hardware registers
|
||||
available on notebooks manufactured by Uniwill. Reading and writing those registers happens
|
||||
by calling ACPI control methods. The ``uniwill-laptop`` driver uses this device to communicate
|
||||
with the EC because the ACPI control methods are faster than the WMI methods described above.
|
||||
|
||||
ACPI control methods used for reading registers take a single ACPI integer containing the address
|
||||
of the register to read and return a ACPI integer containing the data inside said register. ACPI
|
||||
control methods used for writing registers however take two ACPI integers, with the additional
|
||||
ACPI integer containing the data to be written into the register. Such ACPI control methods return
|
||||
nothing.
|
||||
|
||||
System memory
|
||||
-------------
|
||||
|
||||
System memory can be accessed with a granularity of either a single byte (``MMRB`` for reading and
|
||||
``MMWB`` for writing) or four bytes (``MMRD`` for reading and ``MMWD`` for writing). Those ACPI
|
||||
control methods are unused because they provide no benefit when compared to the native memory
|
||||
access functions provided by the kernel.
|
||||
|
||||
EC RAM
|
||||
------
|
||||
|
||||
The internal RAM of the EC can be accessed with a granularity of a single byte using the ``ECRR``
|
||||
(read) and ``ECRW`` (write) ACPI control methods, with the maximum register address being ``0xFFF``.
|
||||
The OEM software waits 6 ms after calling one of those ACPI control methods, likely to avoid
|
||||
overwhelming the EC when being connected over LPC.
|
||||
|
||||
PCI config space
|
||||
----------------
|
||||
|
||||
The PCI config space can be accessed with a granularity of four bytes using the ``PCRD`` (read) and
|
||||
``PCWD`` (write) ACPI control methods. The exact address format is unknown, and poking random PCI
|
||||
devices might confuse the PCI subsystem. Because of this those ACPI control methods are not used.
|
||||
|
||||
IO ports
|
||||
--------
|
||||
|
||||
IO ports can be accessed with a granularity of four bytes using the ``IORD`` (read) and ``IOWD``
|
||||
(write) ACPI control methods. Those ACPI control methods are unused because they provide no benefit
|
||||
when compared to the native IO port access functions provided by the kernel.
|
||||
|
||||
CMOS RAM
|
||||
--------
|
||||
|
||||
The CMOS RAM can be accessed with a granularity of a single byte using the ``RCMS`` (read) and
|
||||
``WCMS`` ACPI control methods. Using those ACPI methods might interfere with the native CMOS RAM
|
||||
access functions provided by the kernel due to the usage of indexed IO, so they are unused.
|
||||
|
||||
Indexed IO
|
||||
----------
|
||||
|
||||
Indexed IO with IO ports with a granularity of a single byte can be performed using the ``RIOP``
|
||||
(read) and ``WIOP`` (write) ACPI control methods. Those ACPI methods are unused because they
|
||||
provide no benifit when compared to the native IO port access functions provided by the kernel.
|
||||
|
||||
Special thanks go to github user `pobrn` which developed the
|
||||
`qc71_laptop <https://github.com/pobrn/qc71_laptop>`_ driver on which this driver is partly based.
|
||||
The same is true for Tuxedo Computers, which developed the
|
||||
`tuxedo-drivers <https://gitlab.com/tuxedocomputers/development/packages/tuxedo-drivers>`_ package
|
||||
which also served as a foundation for this driver.
|
||||
20
MAINTAINERS
20
MAINTAINERS
|
|
@ -402,7 +402,7 @@ S: Maintained
|
|||
F: Documentation/ABI/testing/sysfs-bus-wmi
|
||||
F: Documentation/driver-api/wmi.rst
|
||||
F: Documentation/wmi/
|
||||
F: drivers/platform/x86/wmi.c
|
||||
F: drivers/platform/wmi/
|
||||
F: include/uapi/linux/wmi.h
|
||||
|
||||
ACRN HYPERVISOR SERVICE MODULE
|
||||
|
|
@ -4262,6 +4262,13 @@ W: https://ez.analog.com/linux-software-drivers
|
|||
F: Documentation/devicetree/bindings/pwm/adi,axi-pwmgen.yaml
|
||||
F: drivers/pwm/pwm-axi-pwmgen.c
|
||||
|
||||
AYANEO PLATFORM EC DRIVER
|
||||
M: Antheas Kapenekakis <lkml@antheas.dev>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/ABI/testing/sysfs-platform-ayaneo
|
||||
F: drivers/platform/x86/ayaneo-ec.c
|
||||
|
||||
AZ6007 DVB DRIVER
|
||||
M: Mauro Carvalho Chehab <mchehab@kernel.org>
|
||||
L: linux-media@vger.kernel.org
|
||||
|
|
@ -26789,6 +26796,17 @@ L: linux-scsi@vger.kernel.org
|
|||
S: Maintained
|
||||
F: drivers/ufs/host/ufs-renesas.c
|
||||
|
||||
UNIWILL LAPTOP DRIVER
|
||||
M: Armin Wolf <W_Armin@gmx.de>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/ABI/testing/sysfs-driver-uniwill-laptop
|
||||
F: Documentation/admin-guide/laptops/uniwill-laptop.rst
|
||||
F: Documentation/wmi/devices/uniwill-laptop.rst
|
||||
F: drivers/platform/x86/uniwill/uniwill-acpi.c
|
||||
F: drivers/platform/x86/uniwill/uniwill-wmi.c
|
||||
F: drivers/platform/x86/uniwill/uniwill-wmi.h
|
||||
|
||||
UNSORTED BLOCK IMAGES (UBI)
|
||||
M: Richard Weinberger <richard@nod.at>
|
||||
R: Zhihao Cheng <chengzhihao1@huawei.com>
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ static const char * const profile_names[] = {
|
|||
[PLATFORM_PROFILE_BALANCED] = "balanced",
|
||||
[PLATFORM_PROFILE_BALANCED_PERFORMANCE] = "balanced-performance",
|
||||
[PLATFORM_PROFILE_PERFORMANCE] = "performance",
|
||||
[PLATFORM_PROFILE_MAX_POWER] = "max-power",
|
||||
[PLATFORM_PROFILE_CUSTOM] = "custom",
|
||||
};
|
||||
static_assert(ARRAY_SIZE(profile_names) == PLATFORM_PROFILE_LAST);
|
||||
|
|
@ -506,7 +507,8 @@ int platform_profile_cycle(void)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (profile == PLATFORM_PROFILE_CUSTOM ||
|
||||
if (profile == PLATFORM_PROFILE_MAX_POWER ||
|
||||
profile == PLATFORM_PROFILE_CUSTOM ||
|
||||
profile == PLATFORM_PROFILE_LAST)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -515,7 +517,8 @@ int platform_profile_cycle(void)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
/* never iterate into a custom if all drivers supported it */
|
||||
/* never iterate into a custom or max power if all drivers supported it */
|
||||
clear_bit(PLATFORM_PROFILE_MAX_POWER, data.aggregate);
|
||||
clear_bit(PLATFORM_PROFILE_CUSTOM, data.aggregate);
|
||||
|
||||
next = find_next_bit_wrap(data.aggregate,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/x86/asus-wmi.h>
|
||||
#include <linux/platform_data/x86/asus-wmi-leds-ids.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/usb.h> /* For to_usb_interface for T100 touchpad intf check */
|
||||
#include <linux/power_supply.h>
|
||||
|
|
|
|||
|
|
@ -20,3 +20,5 @@ source "drivers/platform/x86/Kconfig"
|
|||
source "drivers/platform/arm64/Kconfig"
|
||||
|
||||
source "drivers/platform/raspberrypi/Kconfig"
|
||||
|
||||
source "drivers/platform/wmi/Kconfig"
|
||||
|
|
|
|||
|
|
@ -14,3 +14,4 @@ obj-$(CONFIG_CZNIC_PLATFORMS) += cznic/
|
|||
obj-$(CONFIG_SURFACE_PLATFORMS) += surface/
|
||||
obj-$(CONFIG_ARM64_PLATFORM_DEVICES) += arm64/
|
||||
obj-$(CONFIG_BCM2835_VCHIQ) += raspberrypi/
|
||||
obj-$(CONFIG_ACPI_WMI) += wmi/
|
||||
|
|
|
|||
|
|
@ -20,19 +20,23 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
#define T14S_EC_CMD_ECRD 0x02
|
||||
#define T14S_EC_CMD_ECWR 0x03
|
||||
#define T14S_EC_CMD_EVT 0xf0
|
||||
|
||||
#define T14S_EC_REG_LED 0x0c
|
||||
#define T14S_EC_REG_KBD_BL1 0x0d
|
||||
#define T14S_EC_REG_KBD_BL2 0xe1
|
||||
#define T14S_EC_KBD_BL1_MASK GENMASK_U8(7, 6)
|
||||
#define T14S_EC_KBD_BL2_MASK GENMASK_U8(3, 2)
|
||||
#define T14S_EC_REG_AUD 0x30
|
||||
#define T14S_EC_MIC_MUTE_LED BIT(5)
|
||||
#define T14S_EC_SPK_MUTE_LED BIT(6)
|
||||
#define T14S_EC_REG_LED 0x0c
|
||||
#define T14S_EC_REG_KBD_BL1 0x0d
|
||||
#define T14S_EC_REG_MODERN_STANDBY 0xe0
|
||||
#define T14S_EC_MODERN_STANDBY_ENTRY BIT(1)
|
||||
#define T14S_EC_MODERN_STANDBY_EXIT BIT(0)
|
||||
#define T14S_EC_REG_KBD_BL2 0xe1
|
||||
#define T14S_EC_KBD_BL1_MASK GENMASK_U8(7, 6)
|
||||
#define T14S_EC_KBD_BL2_MASK GENMASK_U8(3, 2)
|
||||
#define T14S_EC_REG_AUD 0x30
|
||||
#define T14S_EC_MIC_MUTE_LED BIT(5)
|
||||
#define T14S_EC_SPK_MUTE_LED BIT(6)
|
||||
|
||||
#define T14S_EC_EVT_NONE 0x00
|
||||
#define T14S_EC_EVT_KEY_FN_4 0x13
|
||||
|
|
@ -202,6 +206,14 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void t14s_ec_write_sequence(struct t14s_ec *ec, u8 reg, u8 val, u8 cnt)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cnt; i++)
|
||||
regmap_write(ec->regmap, reg, val);
|
||||
}
|
||||
|
||||
static int t14s_led_set_status(struct t14s_ec *ec,
|
||||
struct t14s_ec_led_classdev *led,
|
||||
const enum t14s_ec_led_status_t ledstatus)
|
||||
|
|
@ -554,6 +566,7 @@ static int t14s_ec_probe(struct i2c_client *client)
|
|||
return -ENOMEM;
|
||||
|
||||
ec->dev = dev;
|
||||
i2c_set_clientdata(client, ec);
|
||||
|
||||
ec->regmap = devm_regmap_init(dev, &t14s_ec_regmap_bus,
|
||||
ec, &t14s_ec_regmap_config);
|
||||
|
|
@ -593,6 +606,30 @@ static int t14s_ec_probe(struct i2c_client *client)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int t14s_ec_suspend(struct device *dev)
|
||||
{
|
||||
struct t14s_ec *ec = dev_get_drvdata(dev);
|
||||
|
||||
led_classdev_suspend(&ec->kbd_backlight);
|
||||
|
||||
t14s_ec_write_sequence(ec, T14S_EC_REG_MODERN_STANDBY,
|
||||
T14S_EC_MODERN_STANDBY_ENTRY, 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int t14s_ec_resume(struct device *dev)
|
||||
{
|
||||
struct t14s_ec *ec = dev_get_drvdata(dev);
|
||||
|
||||
t14s_ec_write_sequence(ec, T14S_EC_REG_MODERN_STANDBY,
|
||||
T14S_EC_MODERN_STANDBY_EXIT, 3);
|
||||
|
||||
led_classdev_resume(&ec->kbd_backlight);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id t14s_ec_of_match[] = {
|
||||
{ .compatible = "lenovo,thinkpad-t14s-ec" },
|
||||
{}
|
||||
|
|
@ -605,10 +642,15 @@ static const struct i2c_device_id t14s_ec_i2c_id_table[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(i2c, t14s_ec_i2c_id_table);
|
||||
|
||||
static const struct dev_pm_ops t14s_ec_pm_ops = {
|
||||
SYSTEM_SLEEP_PM_OPS(t14s_ec_suspend, t14s_ec_resume)
|
||||
};
|
||||
|
||||
static struct i2c_driver t14s_ec_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "thinkpad-t14s-ec",
|
||||
.of_match_table = t14s_ec_of_match,
|
||||
.pm = &t14s_ec_pm_ops,
|
||||
},
|
||||
.probe = t14s_ec_probe,
|
||||
.id_table = t14s_ec_i2c_id_table,
|
||||
|
|
|
|||
|
|
@ -676,7 +676,7 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
|
|||
|
||||
status = ssam_serdev_setup(ssh, serdev);
|
||||
if (status) {
|
||||
status = dev_err_probe(dev, status, "failed to setup serdev\n");
|
||||
dev_err_probe(dev, status, "failed to setup serdev\n");
|
||||
goto err_devinit;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -671,7 +671,7 @@ static void ssh_ptl_timeout_reaper_mod(struct ssh_ptl *ptl, ktime_t now,
|
|||
/* Re-adjust / schedule reaper only if it is above resolution delta. */
|
||||
if (ktime_before(aexp, ptl->rtx_timeout.expires)) {
|
||||
ptl->rtx_timeout.expires = expires;
|
||||
mod_delayed_work(system_wq, &ptl->rtx_timeout.reaper, delta);
|
||||
mod_delayed_work(system_percpu_wq, &ptl->rtx_timeout.reaper, delta);
|
||||
}
|
||||
|
||||
spin_unlock(&ptl->rtx_timeout.lock);
|
||||
|
|
|
|||
|
|
@ -434,7 +434,7 @@ static void ssh_rtl_timeout_reaper_mod(struct ssh_rtl *rtl, ktime_t now,
|
|||
/* Re-adjust / schedule reaper only if it is above resolution delta. */
|
||||
if (ktime_before(aexp, rtl->rtx_timeout.expires)) {
|
||||
rtl->rtx_timeout.expires = expires;
|
||||
mod_delayed_work(system_wq, &rtl->rtx_timeout.reaper, delta);
|
||||
mod_delayed_work(system_percpu_wq, &rtl->rtx_timeout.reaper, delta);
|
||||
}
|
||||
|
||||
spin_unlock(&rtl->rtx_timeout.lock);
|
||||
|
|
|
|||
|
|
@ -862,7 +862,7 @@ static int __init san_init(void)
|
|||
{
|
||||
int ret;
|
||||
|
||||
san_wq = alloc_workqueue("san_wq", 0, 0);
|
||||
san_wq = alloc_workqueue("san_wq", WQ_PERCPU, 0);
|
||||
if (!san_wq)
|
||||
return -ENOMEM;
|
||||
ret = platform_driver_register(&surface_acpi_notify);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# ACPI WMI Core
|
||||
#
|
||||
|
||||
menuconfig ACPI_WMI
|
||||
tristate "ACPI-WMI support"
|
||||
depends on ACPI && X86
|
||||
help
|
||||
This option enables support for the ACPI-WMI driver core.
|
||||
|
||||
The ACPI-WMI interface is a proprietary extension of ACPI allowing
|
||||
the platform firmware to expose WMI (Windows Management Instrumentation)
|
||||
objects used for managing various aspects of the underlying system.
|
||||
Mapping between ACPI control methods and WMI objects happens through
|
||||
special mapper devices (PNP0C14) defined inside the ACPI tables.
|
||||
|
||||
Enabling this option is necessary for building the vendor specific
|
||||
ACPI-WMI client drivers for Acer, Dell an HP machines (among others).
|
||||
|
||||
It is safe to enable this option even for machines that do not contain
|
||||
any ACPI-WMI mapper devices at all.
|
||||
|
||||
if ACPI_WMI
|
||||
|
||||
config ACPI_WMI_LEGACY_DEVICE_NAMES
|
||||
bool "Use legacy WMI device naming scheme"
|
||||
help
|
||||
Say Y here to force the WMI driver core to use the old WMI device naming
|
||||
scheme when creating WMI devices. Doing so might be necessary for some
|
||||
userspace applications but will cause the registration of WMI devices with
|
||||
the same GUID to fail in some corner cases.
|
||||
|
||||
endif # ACPI_WMI
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Makefile for linux/drivers/platform/wmi
|
||||
# ACPI WMI core
|
||||
#
|
||||
|
||||
wmi-y := core.o
|
||||
obj-$(CONFIG_ACPI_WMI) += wmi.o
|
||||
|
|
@ -142,14 +142,6 @@ static inline void get_acpi_method_name(const struct wmi_block *wblock,
|
|||
buffer[4] = '\0';
|
||||
}
|
||||
|
||||
static inline acpi_object_type get_param_acpi_type(const struct wmi_block *wblock)
|
||||
{
|
||||
if (wblock->gblock.flags & ACPI_WMI_STRING)
|
||||
return ACPI_TYPE_STRING;
|
||||
else
|
||||
return ACPI_TYPE_BUFFER;
|
||||
}
|
||||
|
||||
static int wmidev_match_guid(struct device *dev, const void *data)
|
||||
{
|
||||
struct wmi_block *wblock = dev_to_wblock(dev);
|
||||
|
|
@ -351,9 +343,16 @@ acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance, u32 met
|
|||
params[0].integer.value = instance;
|
||||
params[1].type = ACPI_TYPE_INTEGER;
|
||||
params[1].integer.value = method_id;
|
||||
params[2].type = get_param_acpi_type(wblock);
|
||||
params[2].buffer.length = in->length;
|
||||
params[2].buffer.pointer = in->pointer;
|
||||
|
||||
if (wblock->gblock.flags & ACPI_WMI_STRING) {
|
||||
params[2].type = ACPI_TYPE_STRING;
|
||||
params[2].string.length = in->length;
|
||||
params[2].string.pointer = in->pointer;
|
||||
} else {
|
||||
params[2].type = ACPI_TYPE_BUFFER;
|
||||
params[2].buffer.length = in->length;
|
||||
params[2].buffer.pointer = in->pointer;
|
||||
}
|
||||
|
||||
get_acpi_method_name(wblock, 'M', method);
|
||||
|
||||
|
|
@ -519,9 +518,16 @@ acpi_status wmidev_block_set(struct wmi_device *wdev, u8 instance, const struct
|
|||
input.pointer = params;
|
||||
params[0].type = ACPI_TYPE_INTEGER;
|
||||
params[0].integer.value = instance;
|
||||
params[1].type = get_param_acpi_type(wblock);
|
||||
params[1].buffer.length = in->length;
|
||||
params[1].buffer.pointer = in->pointer;
|
||||
|
||||
if (wblock->gblock.flags & ACPI_WMI_STRING) {
|
||||
params[1].type = ACPI_TYPE_STRING;
|
||||
params[1].string.length = in->length;
|
||||
params[1].string.pointer = in->pointer;
|
||||
} else {
|
||||
params[1].type = ACPI_TYPE_BUFFER;
|
||||
params[1].buffer.length = in->length;
|
||||
params[1].buffer.pointer = in->pointer;
|
||||
}
|
||||
|
||||
get_acpi_method_name(wblock, 'S', method);
|
||||
|
||||
|
|
@ -16,36 +16,6 @@ menuconfig X86_PLATFORM_DEVICES
|
|||
|
||||
if X86_PLATFORM_DEVICES
|
||||
|
||||
config ACPI_WMI
|
||||
tristate "WMI"
|
||||
depends on ACPI
|
||||
help
|
||||
This driver adds support for the ACPI-WMI (Windows Management
|
||||
Instrumentation) mapper device (PNP0C14) found on some systems.
|
||||
|
||||
ACPI-WMI is a proprietary extension to ACPI to expose parts of the
|
||||
ACPI firmware to userspace - this is done through various vendor
|
||||
defined methods and data blocks in a PNP0C14 device, which are then
|
||||
made available for userspace to call.
|
||||
|
||||
The implementation of this in Linux currently only exposes this to
|
||||
other kernel space drivers.
|
||||
|
||||
This driver is a required dependency to build the firmware specific
|
||||
drivers needed on many machines, including Acer and HP laptops.
|
||||
|
||||
It is safe to enable this driver even if your DSDT doesn't define
|
||||
any ACPI-WMI devices.
|
||||
|
||||
config ACPI_WMI_LEGACY_DEVICE_NAMES
|
||||
bool "Use legacy WMI device naming scheme"
|
||||
depends on ACPI_WMI
|
||||
help
|
||||
Say Y here to force the WMI driver core to use the old WMI device naming
|
||||
scheme when creating WMI devices. Doing so might be necessary for some
|
||||
userspace applications but will cause the registration of WMI devices with
|
||||
the same GUID to fail in some corner cases.
|
||||
|
||||
config WMI_BMOF
|
||||
tristate "WMI embedded Binary MOF driver"
|
||||
depends on ACPI_WMI
|
||||
|
|
@ -74,6 +44,8 @@ config HUAWEI_WMI
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called huawei-wmi.
|
||||
|
||||
source "drivers/platform/x86/uniwill/Kconfig"
|
||||
|
||||
config UV_SYSFS
|
||||
tristate "Sysfs structure for UV systems"
|
||||
depends on X86_UV
|
||||
|
|
@ -262,6 +234,18 @@ config ASUS_WIRELESS
|
|||
If you choose to compile this driver as a module the module will be
|
||||
called asus-wireless.
|
||||
|
||||
config ASUS_ARMOURY
|
||||
tristate "ASUS Armoury driver"
|
||||
depends on ASUS_WMI
|
||||
select FW_ATTR_CLASS
|
||||
help
|
||||
Say Y here if you have a WMI aware Asus machine and would like to use the
|
||||
firmware_attributes API to control various settings typically exposed in
|
||||
the ASUS Armoury Crate application available on Windows.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called asus-armoury.
|
||||
|
||||
config ASUS_WMI
|
||||
tristate "ASUS WMI Driver"
|
||||
depends on ACPI_WMI
|
||||
|
|
@ -284,6 +268,17 @@ config ASUS_WMI
|
|||
To compile this driver as a module, choose M here: the module will
|
||||
be called asus-wmi.
|
||||
|
||||
config ASUS_WMI_DEPRECATED_ATTRS
|
||||
bool "BIOS option support in WMI platform (DEPRECATED)"
|
||||
depends on ASUS_WMI
|
||||
default y
|
||||
help
|
||||
Say Y to expose the configurable BIOS options through the asus-wmi
|
||||
driver.
|
||||
|
||||
This can be used with or without the asus-armoury driver which
|
||||
has the same attributes, but more, and better features.
|
||||
|
||||
config ASUS_NB_WMI
|
||||
tristate "Asus Notebook WMI Driver"
|
||||
depends on ASUS_WMI
|
||||
|
|
@ -316,6 +311,19 @@ config ASUS_TF103C_DOCK
|
|||
If you have an Asus TF103C tablet say Y or M here, for a generic x86
|
||||
distro config say M here.
|
||||
|
||||
config AYANEO_EC
|
||||
tristate "Ayaneo EC platform control"
|
||||
depends on DMI
|
||||
depends on ACPI_EC
|
||||
depends on ACPI_BATTERY
|
||||
depends on HWMON
|
||||
help
|
||||
Enables support for the platform EC of Ayaneo devices. This
|
||||
includes fan control, fan speed, charge limit, magic
|
||||
module detection, and controller power control.
|
||||
|
||||
If you have an Ayaneo device, say Y or M here.
|
||||
|
||||
config MERAKI_MX100
|
||||
tristate "Cisco Meraki MX100 Platform Driver"
|
||||
depends on GPIOLIB
|
||||
|
|
@ -1031,9 +1039,7 @@ config OXP_EC
|
|||
help
|
||||
Enables support for the platform EC of OneXPlayer and AOKZOE
|
||||
handheld devices. This includes fan speed, fan controls, and
|
||||
disabling the default TDP behavior of the device. Due to legacy
|
||||
reasons, this driver also provides hwmon functionality to Ayaneo
|
||||
devices and the OrangePi Neo.
|
||||
disabling the default TDP behavior of the device.
|
||||
|
||||
source "drivers/platform/x86/tuxedo/Kconfig"
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
#
|
||||
|
||||
# Windows Management Interface
|
||||
obj-$(CONFIG_ACPI_WMI) += wmi.o
|
||||
obj-$(CONFIG_WMI_BMOF) += wmi-bmof.o
|
||||
|
||||
# WMI drivers
|
||||
|
|
@ -33,12 +32,16 @@ obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o
|
|||
# ASUS
|
||||
obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
|
||||
obj-$(CONFIG_ASUS_WIRELESS) += asus-wireless.o
|
||||
obj-$(CONFIG_ASUS_ARMOURY) += asus-armoury.o
|
||||
obj-$(CONFIG_ASUS_WMI) += asus-wmi.o
|
||||
obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o
|
||||
obj-$(CONFIG_ASUS_TF103C_DOCK) += asus-tf103c-dock.o
|
||||
obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
|
||||
obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o
|
||||
|
||||
# Ayaneo
|
||||
obj-$(CONFIG_AYANEO_EC) += ayaneo-ec.o
|
||||
|
||||
# Cisco/Meraki
|
||||
obj-$(CONFIG_MERAKI_MX100) += meraki-mx100.o
|
||||
|
||||
|
|
@ -110,6 +113,9 @@ obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o
|
|||
# before toshiba_acpi initializes
|
||||
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
|
||||
|
||||
# Uniwill
|
||||
obj-y += uniwill/
|
||||
|
||||
# Inspur
|
||||
obj-$(CONFIG_INSPUR_PLATFORM_PROFILE) += inspur_platform_profile.o
|
||||
|
||||
|
|
|
|||
|
|
@ -12,10 +12,12 @@
|
|||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/fixp-arith.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
|
@ -68,10 +70,27 @@ MODULE_LICENSE("GPL");
|
|||
#define ACER_WMID_SET_GAMING_LED_METHODID 2
|
||||
#define ACER_WMID_GET_GAMING_LED_METHODID 4
|
||||
#define ACER_WMID_GET_GAMING_SYS_INFO_METHODID 5
|
||||
#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR 14
|
||||
#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR_METHODID 14
|
||||
#define ACER_WMID_GET_GAMING_FAN_BEHAVIOR_METHODID 15
|
||||
#define ACER_WMID_SET_GAMING_FAN_SPEED_METHODID 16
|
||||
#define ACER_WMID_GET_GAMING_FAN_SPEED_METHODID 17
|
||||
#define ACER_WMID_SET_GAMING_MISC_SETTING_METHODID 22
|
||||
#define ACER_WMID_GET_GAMING_MISC_SETTING_METHODID 23
|
||||
|
||||
#define ACER_GAMING_FAN_BEHAVIOR_CPU BIT(0)
|
||||
#define ACER_GAMING_FAN_BEHAVIOR_GPU BIT(3)
|
||||
|
||||
#define ACER_GAMING_FAN_BEHAVIOR_STATUS_MASK GENMASK_ULL(7, 0)
|
||||
#define ACER_GAMING_FAN_BEHAVIOR_ID_MASK GENMASK_ULL(15, 0)
|
||||
#define ACER_GAMING_FAN_BEHAVIOR_SET_CPU_MODE_MASK GENMASK(17, 16)
|
||||
#define ACER_GAMING_FAN_BEHAVIOR_SET_GPU_MODE_MASK GENMASK(23, 22)
|
||||
#define ACER_GAMING_FAN_BEHAVIOR_GET_CPU_MODE_MASK GENMASK(9, 8)
|
||||
#define ACER_GAMING_FAN_BEHAVIOR_GET_GPU_MODE_MASK GENMASK(15, 14)
|
||||
|
||||
#define ACER_GAMING_FAN_SPEED_STATUS_MASK GENMASK_ULL(7, 0)
|
||||
#define ACER_GAMING_FAN_SPEED_ID_MASK GENMASK_ULL(7, 0)
|
||||
#define ACER_GAMING_FAN_SPEED_VALUE_MASK GENMASK_ULL(15, 8)
|
||||
|
||||
#define ACER_GAMING_MISC_SETTING_STATUS_MASK GENMASK_ULL(7, 0)
|
||||
#define ACER_GAMING_MISC_SETTING_INDEX_MASK GENMASK_ULL(7, 0)
|
||||
#define ACER_GAMING_MISC_SETTING_VALUE_MASK GENMASK_ULL(15, 8)
|
||||
|
|
@ -122,6 +141,17 @@ enum acer_wmi_predator_v4_sensor_id {
|
|||
ACER_WMID_SENSOR_GPU_TEMPERATURE = 0x0A,
|
||||
};
|
||||
|
||||
enum acer_wmi_gaming_fan_id {
|
||||
ACER_WMID_CPU_FAN = 0x01,
|
||||
ACER_WMID_GPU_FAN = 0x04,
|
||||
};
|
||||
|
||||
enum acer_wmi_gaming_fan_mode {
|
||||
ACER_WMID_FAN_MODE_AUTO = 0x01,
|
||||
ACER_WMID_FAN_MODE_TURBO = 0x02,
|
||||
ACER_WMID_FAN_MODE_CUSTOM = 0x03,
|
||||
};
|
||||
|
||||
enum acer_wmi_predator_v4_oc {
|
||||
ACER_WMID_OC_NORMAL = 0x0000,
|
||||
ACER_WMID_OC_TURBO = 0x0002,
|
||||
|
|
@ -279,6 +309,7 @@ struct hotkey_function_type_aa {
|
|||
#define ACER_CAP_TURBO_FAN BIT(9)
|
||||
#define ACER_CAP_PLATFORM_PROFILE BIT(10)
|
||||
#define ACER_CAP_HWMON BIT(11)
|
||||
#define ACER_CAP_PWM BIT(12)
|
||||
|
||||
/*
|
||||
* Interface type flags
|
||||
|
|
@ -373,6 +404,7 @@ struct quirk_entry {
|
|||
u8 cpu_fans;
|
||||
u8 gpu_fans;
|
||||
u8 predator_v4;
|
||||
u8 pwm;
|
||||
};
|
||||
|
||||
static struct quirk_entry *quirks;
|
||||
|
|
@ -392,6 +424,9 @@ static void __init set_quirks(void)
|
|||
if (quirks->predator_v4)
|
||||
interface->capability |= ACER_CAP_PLATFORM_PROFILE |
|
||||
ACER_CAP_HWMON;
|
||||
|
||||
if (quirks->pwm)
|
||||
interface->capability |= ACER_CAP_PWM;
|
||||
}
|
||||
|
||||
static int __init dmi_matched(const struct dmi_system_id *dmi)
|
||||
|
|
@ -431,6 +466,7 @@ static struct quirk_entry quirk_acer_predator_ph16_72 = {
|
|||
.cpu_fans = 1,
|
||||
.gpu_fans = 1,
|
||||
.predator_v4 = 1,
|
||||
.pwm = 1,
|
||||
};
|
||||
|
||||
static struct quirk_entry quirk_acer_predator_pt14_51 = {
|
||||
|
|
@ -438,6 +474,7 @@ static struct quirk_entry quirk_acer_predator_pt14_51 = {
|
|||
.cpu_fans = 1,
|
||||
.gpu_fans = 1,
|
||||
.predator_v4 = 1,
|
||||
.pwm = 1,
|
||||
};
|
||||
|
||||
static struct quirk_entry quirk_acer_predator_v4 = {
|
||||
|
|
@ -656,6 +693,15 @@ static const struct dmi_system_id acer_quirks[] __initconst = {
|
|||
},
|
||||
.driver_data = &quirk_acer_predator_ph16_72,
|
||||
},
|
||||
{
|
||||
.callback = dmi_matched,
|
||||
.ident = "Acer Predator Helios Neo 16",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Predator PHN16-72"),
|
||||
},
|
||||
.driver_data = &quirk_acer_predator_ph16_72,
|
||||
},
|
||||
{
|
||||
.callback = dmi_matched,
|
||||
.ident = "Acer Predator PH18-71",
|
||||
|
|
@ -1564,9 +1610,6 @@ static acpi_status WMID_gaming_set_u64(u64 value, u32 cap)
|
|||
case ACER_CAP_TURBO_LED:
|
||||
method_id = ACER_WMID_SET_GAMING_LED_METHODID;
|
||||
break;
|
||||
case ACER_CAP_TURBO_FAN:
|
||||
method_id = ACER_WMID_SET_GAMING_FAN_BEHAVIOR;
|
||||
break;
|
||||
default:
|
||||
return AE_BAD_PARAMETER;
|
||||
}
|
||||
|
|
@ -1617,25 +1660,125 @@ static int WMID_gaming_get_sys_info(u32 command, u64 *out)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void WMID_gaming_set_fan_mode(u8 fan_mode)
|
||||
static int WMID_gaming_set_fan_behavior(u16 fan_bitmap, enum acer_wmi_gaming_fan_mode mode)
|
||||
{
|
||||
/* fan_mode = 1 is used for auto, fan_mode = 2 used for turbo*/
|
||||
u64 gpu_fan_config1 = 0, gpu_fan_config2 = 0;
|
||||
int i;
|
||||
acpi_status status;
|
||||
u64 input = 0;
|
||||
u64 result;
|
||||
|
||||
input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_ID_MASK, fan_bitmap);
|
||||
|
||||
if (fan_bitmap & ACER_GAMING_FAN_BEHAVIOR_CPU)
|
||||
input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_SET_CPU_MODE_MASK, mode);
|
||||
|
||||
if (fan_bitmap & ACER_GAMING_FAN_BEHAVIOR_GPU)
|
||||
input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_SET_GPU_MODE_MASK, mode);
|
||||
|
||||
status = WMI_gaming_execute_u64(ACER_WMID_SET_GAMING_FAN_BEHAVIOR_METHODID, input,
|
||||
&result);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
|
||||
/* The return status must be zero for the operation to have succeeded */
|
||||
if (FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_STATUS_MASK, result))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int WMID_gaming_get_fan_behavior(u16 fan_bitmap, enum acer_wmi_gaming_fan_mode *mode)
|
||||
{
|
||||
acpi_status status;
|
||||
u32 input = 0;
|
||||
u64 result;
|
||||
int value;
|
||||
|
||||
input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_ID_MASK, fan_bitmap);
|
||||
status = WMI_gaming_execute_u32_u64(ACER_WMID_GET_GAMING_FAN_BEHAVIOR_METHODID, input,
|
||||
&result);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
|
||||
/* The return status must be zero for the operation to have succeeded */
|
||||
if (FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_STATUS_MASK, result))
|
||||
return -EIO;
|
||||
|
||||
/* Theoretically multiple fans can be specified, but this is currently unused */
|
||||
if (fan_bitmap & ACER_GAMING_FAN_BEHAVIOR_CPU)
|
||||
value = FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_GET_CPU_MODE_MASK, result);
|
||||
else if (fan_bitmap & ACER_GAMING_FAN_BEHAVIOR_GPU)
|
||||
value = FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_GET_GPU_MODE_MASK, result);
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
if (value < ACER_WMID_FAN_MODE_AUTO || value > ACER_WMID_FAN_MODE_CUSTOM)
|
||||
return -ENXIO;
|
||||
|
||||
*mode = value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void WMID_gaming_set_fan_mode(enum acer_wmi_gaming_fan_mode mode)
|
||||
{
|
||||
u16 fan_bitmap = 0;
|
||||
|
||||
if (quirks->cpu_fans > 0)
|
||||
gpu_fan_config2 |= 1;
|
||||
for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i)
|
||||
gpu_fan_config2 |= 1 << (i + 1);
|
||||
for (i = 0; i < quirks->gpu_fans; ++i)
|
||||
gpu_fan_config2 |= 1 << (i + 3);
|
||||
if (quirks->cpu_fans > 0)
|
||||
gpu_fan_config1 |= fan_mode;
|
||||
for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i)
|
||||
gpu_fan_config1 |= fan_mode << (2 * i + 2);
|
||||
for (i = 0; i < quirks->gpu_fans; ++i)
|
||||
gpu_fan_config1 |= fan_mode << (2 * i + 6);
|
||||
WMID_gaming_set_u64(gpu_fan_config2 | gpu_fan_config1 << 16, ACER_CAP_TURBO_FAN);
|
||||
fan_bitmap |= ACER_GAMING_FAN_BEHAVIOR_CPU;
|
||||
|
||||
if (quirks->gpu_fans > 0)
|
||||
fan_bitmap |= ACER_GAMING_FAN_BEHAVIOR_GPU;
|
||||
|
||||
WMID_gaming_set_fan_behavior(fan_bitmap, mode);
|
||||
}
|
||||
|
||||
static int WMID_gaming_set_gaming_fan_speed(u8 fan, u8 speed)
|
||||
{
|
||||
acpi_status status;
|
||||
u64 input = 0;
|
||||
u64 result;
|
||||
|
||||
if (speed > 100)
|
||||
return -EINVAL;
|
||||
|
||||
input |= FIELD_PREP(ACER_GAMING_FAN_SPEED_ID_MASK, fan);
|
||||
input |= FIELD_PREP(ACER_GAMING_FAN_SPEED_VALUE_MASK, speed);
|
||||
|
||||
status = WMI_gaming_execute_u64(ACER_WMID_SET_GAMING_FAN_SPEED_METHODID, input, &result);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
|
||||
switch (FIELD_GET(ACER_GAMING_FAN_SPEED_STATUS_MASK, result)) {
|
||||
case 0x00:
|
||||
return 0;
|
||||
case 0x01:
|
||||
return -ENODEV;
|
||||
case 0x02:
|
||||
return -EINVAL;
|
||||
default:
|
||||
return -ENXIO;
|
||||
}
|
||||
}
|
||||
|
||||
static int WMID_gaming_get_gaming_fan_speed(u8 fan, u8 *speed)
|
||||
{
|
||||
acpi_status status;
|
||||
u32 input = 0;
|
||||
u64 result;
|
||||
|
||||
input |= FIELD_PREP(ACER_GAMING_FAN_SPEED_ID_MASK, fan);
|
||||
|
||||
status = WMI_gaming_execute_u32_u64(ACER_WMID_GET_GAMING_FAN_SPEED_METHODID, input,
|
||||
&result);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
|
||||
if (FIELD_GET(ACER_GAMING_FAN_SPEED_STATUS_MASK, result))
|
||||
return -ENODEV;
|
||||
|
||||
*speed = FIELD_GET(ACER_GAMING_FAN_SPEED_VALUE_MASK, result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int WMID_gaming_set_misc_setting(enum acer_wmi_gaming_misc_setting setting, u8 value)
|
||||
|
|
@ -1922,7 +2065,7 @@ static int acer_toggle_turbo(void)
|
|||
WMID_gaming_set_u64(0x1, ACER_CAP_TURBO_LED);
|
||||
|
||||
/* Set FAN mode to auto */
|
||||
WMID_gaming_set_fan_mode(0x1);
|
||||
WMID_gaming_set_fan_mode(ACER_WMID_FAN_MODE_AUTO);
|
||||
|
||||
/* Set OC to normal */
|
||||
if (has_cap(ACER_CAP_TURBO_OC)) {
|
||||
|
|
@ -1936,7 +2079,7 @@ static int acer_toggle_turbo(void)
|
|||
WMID_gaming_set_u64(0x10001, ACER_CAP_TURBO_LED);
|
||||
|
||||
/* Set FAN mode to turbo */
|
||||
WMID_gaming_set_fan_mode(0x2);
|
||||
WMID_gaming_set_fan_mode(ACER_WMID_FAN_MODE_TURBO);
|
||||
|
||||
/* Set OC to turbo mode */
|
||||
if (has_cap(ACER_CAP_TURBO_OC)) {
|
||||
|
|
@ -2767,6 +2910,16 @@ static const enum acer_wmi_predator_v4_sensor_id acer_wmi_fan_channel_to_sensor_
|
|||
[1] = ACER_WMID_SENSOR_GPU_FAN_SPEED,
|
||||
};
|
||||
|
||||
static const enum acer_wmi_gaming_fan_id acer_wmi_fan_channel_to_fan_id[] = {
|
||||
[0] = ACER_WMID_CPU_FAN,
|
||||
[1] = ACER_WMID_GPU_FAN,
|
||||
};
|
||||
|
||||
static const u16 acer_wmi_fan_channel_to_fan_bitmap[] = {
|
||||
[0] = ACER_GAMING_FAN_BEHAVIOR_CPU,
|
||||
[1] = ACER_GAMING_FAN_BEHAVIOR_GPU,
|
||||
};
|
||||
|
||||
static umode_t acer_wmi_hwmon_is_visible(const void *data,
|
||||
enum hwmon_sensor_types type, u32 attr,
|
||||
int channel)
|
||||
|
|
@ -2778,6 +2931,11 @@ static umode_t acer_wmi_hwmon_is_visible(const void *data,
|
|||
case hwmon_temp:
|
||||
sensor_id = acer_wmi_temp_channel_to_sensor_id[channel];
|
||||
break;
|
||||
case hwmon_pwm:
|
||||
if (!has_cap(ACER_CAP_PWM))
|
||||
return 0;
|
||||
|
||||
fallthrough;
|
||||
case hwmon_fan:
|
||||
sensor_id = acer_wmi_fan_channel_to_sensor_id[channel];
|
||||
break;
|
||||
|
|
@ -2785,8 +2943,12 @@ static umode_t acer_wmi_hwmon_is_visible(const void *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (*supported_sensors & BIT(sensor_id - 1))
|
||||
if (*supported_sensors & BIT(sensor_id - 1)) {
|
||||
if (type == hwmon_pwm)
|
||||
return 0644;
|
||||
|
||||
return 0444;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2795,6 +2957,9 @@ static int acer_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
u32 attr, int channel, long *val)
|
||||
{
|
||||
u64 command = ACER_WMID_CMD_GET_PREDATOR_V4_SENSOR_READING;
|
||||
enum acer_wmi_gaming_fan_mode mode;
|
||||
u16 fan_bitmap;
|
||||
u8 fan, speed;
|
||||
u64 result;
|
||||
int ret;
|
||||
|
||||
|
|
@ -2820,6 +2985,80 @@ static int acer_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
|
||||
*val = FIELD_GET(ACER_PREDATOR_V4_SENSOR_READING_BIT_MASK, result);
|
||||
return 0;
|
||||
case hwmon_pwm:
|
||||
switch (attr) {
|
||||
case hwmon_pwm_input:
|
||||
fan = acer_wmi_fan_channel_to_fan_id[channel];
|
||||
ret = WMID_gaming_get_gaming_fan_speed(fan, &speed);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = fixp_linear_interpolate(0, 0, 100, U8_MAX, speed);
|
||||
return 0;
|
||||
case hwmon_pwm_enable:
|
||||
fan_bitmap = acer_wmi_fan_channel_to_fan_bitmap[channel];
|
||||
ret = WMID_gaming_get_fan_behavior(fan_bitmap, &mode);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (mode) {
|
||||
case ACER_WMID_FAN_MODE_AUTO:
|
||||
*val = 2;
|
||||
return 0;
|
||||
case ACER_WMID_FAN_MODE_TURBO:
|
||||
*val = 0;
|
||||
return 0;
|
||||
case ACER_WMID_FAN_MODE_CUSTOM:
|
||||
*val = 1;
|
||||
return 0;
|
||||
default:
|
||||
return -ENXIO;
|
||||
}
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int acer_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long val)
|
||||
{
|
||||
enum acer_wmi_gaming_fan_mode mode;
|
||||
u16 fan_bitmap;
|
||||
u8 fan, speed;
|
||||
|
||||
switch (type) {
|
||||
case hwmon_pwm:
|
||||
switch (attr) {
|
||||
case hwmon_pwm_input:
|
||||
fan = acer_wmi_fan_channel_to_fan_id[channel];
|
||||
speed = fixp_linear_interpolate(0, 0, U8_MAX, 100,
|
||||
clamp_val(val, 0, U8_MAX));
|
||||
|
||||
return WMID_gaming_set_gaming_fan_speed(fan, speed);
|
||||
case hwmon_pwm_enable:
|
||||
fan_bitmap = acer_wmi_fan_channel_to_fan_bitmap[channel];
|
||||
|
||||
switch (val) {
|
||||
case 0:
|
||||
mode = ACER_WMID_FAN_MODE_TURBO;
|
||||
break;
|
||||
case 1:
|
||||
mode = ACER_WMID_FAN_MODE_CUSTOM;
|
||||
break;
|
||||
case 2:
|
||||
mode = ACER_WMID_FAN_MODE_AUTO;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return WMID_gaming_set_fan_behavior(fan_bitmap, mode);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
@ -2835,11 +3074,16 @@ static const struct hwmon_channel_info *const acer_wmi_hwmon_info[] = {
|
|||
HWMON_F_INPUT,
|
||||
HWMON_F_INPUT
|
||||
),
|
||||
HWMON_CHANNEL_INFO(pwm,
|
||||
HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
|
||||
HWMON_PWM_INPUT | HWMON_PWM_ENABLE
|
||||
),
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct hwmon_ops acer_wmi_hwmon_ops = {
|
||||
.read = acer_wmi_hwmon_read,
|
||||
.write = acer_wmi_hwmon_write,
|
||||
.is_visible = acer_wmi_hwmon_is_visible,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/init.h>
|
||||
|
|
@ -95,7 +94,6 @@ struct amd_hfi_classes {
|
|||
* struct amd_hfi_cpuinfo - HFI workload class info per CPU
|
||||
* @cpu: CPU index
|
||||
* @apic_id: APIC id of the current CPU
|
||||
* @cpus: mask of CPUs associated with amd_hfi_cpuinfo
|
||||
* @class_index: workload class ID index
|
||||
* @nr_class: max number of workload class supported
|
||||
* @ipcc_scores: ipcc scores for each class
|
||||
|
|
@ -106,7 +104,6 @@ struct amd_hfi_classes {
|
|||
struct amd_hfi_cpuinfo {
|
||||
int cpu;
|
||||
u32 apic_id;
|
||||
cpumask_var_t cpus;
|
||||
s16 class_index;
|
||||
u8 nr_class;
|
||||
int *ipcc_scores;
|
||||
|
|
@ -295,11 +292,6 @@ static int amd_hfi_online(unsigned int cpu)
|
|||
|
||||
guard(mutex)(&hfi_cpuinfo_lock);
|
||||
|
||||
if (!zalloc_cpumask_var(&hfi_info->cpus, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
cpumask_set_cpu(cpu, hfi_info->cpus);
|
||||
|
||||
ret = amd_hfi_set_state(cpu, true);
|
||||
if (ret)
|
||||
pr_err("WCT enable failed for CPU %u\n", cpu);
|
||||
|
|
@ -329,8 +321,6 @@ static int amd_hfi_offline(unsigned int cpu)
|
|||
if (ret)
|
||||
pr_err("WCT disable failed for CPU %u\n", cpu);
|
||||
|
||||
free_cpumask_var(hfi_info->cpus);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -515,7 +505,6 @@ static int amd_hfi_probe(struct platform_device *pdev)
|
|||
static struct platform_driver amd_hfi_driver = {
|
||||
.driver = {
|
||||
.name = AMD_HFI_DRIVER,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &amd_hfi_pm_ops,
|
||||
.acpi_match_table = ACPI_PTR(amd_hfi_platform_match),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -22,12 +22,11 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/topology.h>
|
||||
#include <linux/uuid.h>
|
||||
|
||||
#include <uapi/asm-generic/errno-base.h>
|
||||
|
||||
#include <asm/amd/node.h>
|
||||
|
||||
#include "hsmp.h"
|
||||
|
||||
#define DRIVER_NAME "hsmp_acpi"
|
||||
|
|
@ -586,9 +585,9 @@ static int hsmp_acpi_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
if (!hsmp_pdev->is_probed) {
|
||||
hsmp_pdev->num_sockets = amd_num_nodes();
|
||||
if (hsmp_pdev->num_sockets == 0 || hsmp_pdev->num_sockets > MAX_AMD_NUM_NODES) {
|
||||
dev_err(&pdev->dev, "Wrong number of sockets\n");
|
||||
hsmp_pdev->num_sockets = topology_max_packages();
|
||||
if (!hsmp_pdev->num_sockets) {
|
||||
dev_err(&pdev->dev, "No CPU sockets detected\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -114,14 +114,14 @@ static void amd_pmf_set_automode(struct amd_pmf_dev *dev, int idx,
|
|||
{
|
||||
struct power_table_control *pwr_ctrl = &config_store.mode_set[idx].power_control;
|
||||
|
||||
amd_pmf_send_cmd(dev, SET_SPL, false, pwr_ctrl->spl, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_FPPT, false, pwr_ctrl->fppt, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_SPPT, false, pwr_ctrl->sppt, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pwr_ctrl->sppt_apu_only, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pwr_ctrl->stt_min, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
|
||||
amd_pmf_send_cmd(dev, SET_SPL, SET_CMD, pwr_ctrl->spl, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_FPPT, SET_CMD, pwr_ctrl->fppt, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_SPPT, SET_CMD, pwr_ctrl->sppt, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, SET_CMD, pwr_ctrl->sppt_apu_only, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, SET_CMD, pwr_ctrl->stt_min, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, SET_CMD,
|
||||
fixp_q88_fromint(pwr_ctrl->stt_skin_temp[STT_TEMP_APU]), NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, SET_CMD,
|
||||
fixp_q88_fromint(pwr_ctrl->stt_skin_temp[STT_TEMP_HS2]), NULL);
|
||||
|
||||
if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX))
|
||||
|
|
|
|||
|
|
@ -76,14 +76,14 @@ static int amd_pmf_set_cnqf(struct amd_pmf_dev *dev, int src, int idx,
|
|||
|
||||
pc = &config_store.mode_set[src][idx].power_control;
|
||||
|
||||
amd_pmf_send_cmd(dev, SET_SPL, false, pc->spl, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_FPPT, false, pc->fppt, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_SPPT, false, pc->sppt, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pc->sppt_apu_only, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pc->stt_min, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
|
||||
amd_pmf_send_cmd(dev, SET_SPL, SET_CMD, pc->spl, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_FPPT, SET_CMD, pc->fppt, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_SPPT, SET_CMD, pc->sppt, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, SET_CMD, pc->sppt_apu_only, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, SET_CMD, pc->stt_min, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, SET_CMD,
|
||||
fixp_q88_fromint(pc->stt_skin_temp[STT_TEMP_APU]), NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, SET_CMD,
|
||||
fixp_q88_fromint(pc->stt_skin_temp[STT_TEMP_HS2]), NULL);
|
||||
|
||||
if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX))
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ static void amd_pmf_get_metrics(struct work_struct *work)
|
|||
|
||||
/* Transfer table contents */
|
||||
memset(dev->buf, 0, sizeof(dev->m_table));
|
||||
amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, 0, 7, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, SET_CMD, METRICS_TABLE_ID, NULL);
|
||||
memcpy(&dev->m_table, dev->buf, sizeof(dev->m_table));
|
||||
|
||||
time_elapsed_ms = ktime_to_ms(ktime_get()) - dev->start_time;
|
||||
|
|
@ -289,8 +289,8 @@ int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev, bool alloc_buffer)
|
|||
hi = phys_addr >> 32;
|
||||
low = phys_addr & GENMASK(31, 0);
|
||||
|
||||
amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, 0, hi, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, 0, low, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, SET_CMD, hi, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, SET_CMD, low, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -465,9 +465,17 @@ static int amd_pmf_probe(struct platform_device *pdev)
|
|||
if (!dev->regbase)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&dev->lock);
|
||||
mutex_init(&dev->update_mutex);
|
||||
mutex_init(&dev->cb_mutex);
|
||||
err = devm_mutex_init(dev->dev, &dev->lock);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = devm_mutex_init(dev->dev, &dev->update_mutex);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = devm_mutex_init(dev->dev, &dev->cb_mutex);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
apmf_acpi_init(dev);
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
|
@ -491,9 +499,6 @@ static void amd_pmf_remove(struct platform_device *pdev)
|
|||
amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_UNLOAD);
|
||||
apmf_acpi_deinit(dev);
|
||||
amd_pmf_dbgfs_unregister(dev);
|
||||
mutex_destroy(&dev->lock);
|
||||
mutex_destroy(&dev->update_mutex);
|
||||
mutex_destroy(&dev->cb_mutex);
|
||||
}
|
||||
|
||||
static const struct attribute_group *amd_pmf_driver_groups[] = {
|
||||
|
|
|
|||
|
|
@ -119,6 +119,13 @@ struct cookie_header {
|
|||
|
||||
#define APTS_MAX_STATES 16
|
||||
#define CUSTOM_BIOS_INPUT_BITS GENMASK(16, 7)
|
||||
#define BIOS_INPUTS_MAX 10
|
||||
|
||||
/* amd_pmf_send_cmd() set/get */
|
||||
#define SET_CMD false
|
||||
#define GET_CMD true
|
||||
|
||||
#define METRICS_TABLE_ID 7
|
||||
|
||||
typedef void (*apmf_event_handler_t)(acpi_handle handle, u32 event, void *data);
|
||||
|
||||
|
|
@ -204,7 +211,7 @@ struct apmf_sbios_req_v1 {
|
|||
u8 skin_temp_apu;
|
||||
u8 skin_temp_hs2;
|
||||
u8 enable_cnqf;
|
||||
u32 custom_policy[10];
|
||||
u32 custom_policy[BIOS_INPUTS_MAX];
|
||||
} __packed;
|
||||
|
||||
struct apmf_sbios_req_v2 {
|
||||
|
|
@ -216,7 +223,7 @@ struct apmf_sbios_req_v2 {
|
|||
u32 stt_min_limit;
|
||||
u8 skin_temp_apu;
|
||||
u8 skin_temp_hs2;
|
||||
u32 custom_policy[10];
|
||||
u32 custom_policy[BIOS_INPUTS_MAX];
|
||||
} __packed;
|
||||
|
||||
struct apmf_fan_idx {
|
||||
|
|
@ -243,12 +250,12 @@ struct smu_pmf_metrics_v2 {
|
|||
u16 vclk_freq; /* MHz */
|
||||
u16 vcn_activity; /* VCN busy % [0-100] */
|
||||
u16 vpeclk_freq; /* MHz */
|
||||
u16 ipuclk_freq; /* MHz */
|
||||
u16 ipu_busy[8]; /* NPU busy % [0-100] */
|
||||
u16 npuclk_freq; /* MHz */
|
||||
u16 npu_busy[8]; /* NPU busy % [0-100] */
|
||||
u16 dram_reads; /* MB/sec */
|
||||
u16 dram_writes; /* MB/sec */
|
||||
u16 core_c0residency[16]; /* C0 residency % [0-100] */
|
||||
u16 ipu_power; /* mW */
|
||||
u16 npu_power; /* mW */
|
||||
u32 apu_power; /* mW */
|
||||
u32 gfx_power; /* mW */
|
||||
u32 dgpu_power; /* mW */
|
||||
|
|
@ -257,9 +264,9 @@ struct smu_pmf_metrics_v2 {
|
|||
u32 filter_alpha_value; /* time constant [us] */
|
||||
u32 metrics_counter;
|
||||
u16 memclk_freq; /* MHz */
|
||||
u16 mpipuclk_freq; /* MHz */
|
||||
u16 ipu_reads; /* MB/sec */
|
||||
u16 ipu_writes; /* MB/sec */
|
||||
u16 mpnpuclk_freq; /* MHz */
|
||||
u16 npu_reads; /* MB/sec */
|
||||
u16 npu_writes; /* MB/sec */
|
||||
u32 throttle_residency_prochot;
|
||||
u32 throttle_residency_spl;
|
||||
u32 throttle_residency_fppt;
|
||||
|
|
@ -355,7 +362,7 @@ enum power_modes_v2 {
|
|||
};
|
||||
|
||||
struct pmf_bios_inputs_prev {
|
||||
u32 custom_bios_inputs[10];
|
||||
u32 custom_bios_inputs[BIOS_INPUTS_MAX];
|
||||
};
|
||||
|
||||
struct amd_pmf_dev {
|
||||
|
|
@ -451,7 +458,7 @@ struct os_power_slider {
|
|||
struct amd_pmf_notify_smart_pc_update {
|
||||
u16 size;
|
||||
u32 pending_req;
|
||||
u32 custom_bios[10];
|
||||
u32 custom_bios[BIOS_INPUTS_MAX];
|
||||
} __packed;
|
||||
|
||||
struct fan_table_control {
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ static void amd_pmf_get_smu_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_ta
|
|||
{
|
||||
/* Get the updated metrics table data */
|
||||
memset(dev->buf, 0, dev->mtable_size);
|
||||
amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, 0, 7, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, SET_CMD, METRICS_TABLE_ID, NULL);
|
||||
|
||||
switch (dev->cpu_id) {
|
||||
case AMD_CPU_ID_PS:
|
||||
|
|
|
|||
|
|
@ -192,15 +192,15 @@ static void amd_pmf_load_defaults_sps(struct amd_pmf_dev *dev)
|
|||
|
||||
static void amd_pmf_update_slider_v2(struct amd_pmf_dev *dev, int idx)
|
||||
{
|
||||
amd_pmf_send_cmd(dev, SET_PMF_PPT, false, apts_config_store.val[idx].pmf_ppt, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_PMF_PPT_APU_ONLY, false,
|
||||
amd_pmf_send_cmd(dev, SET_PMF_PPT, SET_CMD, apts_config_store.val[idx].pmf_ppt, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_PMF_PPT_APU_ONLY, SET_CMD,
|
||||
apts_config_store.val[idx].ppt_pmf_apu_only, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false,
|
||||
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, SET_CMD,
|
||||
apts_config_store.val[idx].stt_min_limit, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, SET_CMD,
|
||||
fixp_q88_fromint(apts_config_store.val[idx].stt_skin_temp_limit_apu),
|
||||
NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, SET_CMD,
|
||||
fixp_q88_fromint(apts_config_store.val[idx].stt_skin_temp_limit_hs2),
|
||||
NULL);
|
||||
}
|
||||
|
|
@ -211,30 +211,30 @@ void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx,
|
|||
int src = amd_pmf_get_power_source();
|
||||
|
||||
if (op == SLIDER_OP_SET) {
|
||||
amd_pmf_send_cmd(dev, SET_SPL, false, config_store.prop[src][idx].spl, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_FPPT, false, config_store.prop[src][idx].fppt, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_SPPT, false, config_store.prop[src][idx].sppt, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false,
|
||||
amd_pmf_send_cmd(dev, SET_SPL, SET_CMD, config_store.prop[src][idx].spl, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_FPPT, SET_CMD, config_store.prop[src][idx].fppt, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_SPPT, SET_CMD, config_store.prop[src][idx].sppt, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, SET_CMD,
|
||||
config_store.prop[src][idx].sppt_apu_only, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false,
|
||||
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, SET_CMD,
|
||||
config_store.prop[src][idx].stt_min, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, SET_CMD,
|
||||
fixp_q88_fromint(config_store.prop[src][idx].stt_skin_temp[STT_TEMP_APU]),
|
||||
NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, SET_CMD,
|
||||
fixp_q88_fromint(config_store.prop[src][idx].stt_skin_temp[STT_TEMP_HS2]),
|
||||
NULL);
|
||||
} else if (op == SLIDER_OP_GET) {
|
||||
amd_pmf_send_cmd(dev, GET_SPL, true, ARG_NONE, &table->prop[src][idx].spl);
|
||||
amd_pmf_send_cmd(dev, GET_FPPT, true, ARG_NONE, &table->prop[src][idx].fppt);
|
||||
amd_pmf_send_cmd(dev, GET_SPPT, true, ARG_NONE, &table->prop[src][idx].sppt);
|
||||
amd_pmf_send_cmd(dev, GET_SPPT_APU_ONLY, true, ARG_NONE,
|
||||
amd_pmf_send_cmd(dev, GET_SPL, GET_CMD, ARG_NONE, &table->prop[src][idx].spl);
|
||||
amd_pmf_send_cmd(dev, GET_FPPT, GET_CMD, ARG_NONE, &table->prop[src][idx].fppt);
|
||||
amd_pmf_send_cmd(dev, GET_SPPT, GET_CMD, ARG_NONE, &table->prop[src][idx].sppt);
|
||||
amd_pmf_send_cmd(dev, GET_SPPT_APU_ONLY, GET_CMD, ARG_NONE,
|
||||
&table->prop[src][idx].sppt_apu_only);
|
||||
amd_pmf_send_cmd(dev, GET_STT_MIN_LIMIT, true, ARG_NONE,
|
||||
amd_pmf_send_cmd(dev, GET_STT_MIN_LIMIT, GET_CMD, ARG_NONE,
|
||||
&table->prop[src][idx].stt_min);
|
||||
amd_pmf_send_cmd(dev, GET_STT_LIMIT_APU, true, ARG_NONE,
|
||||
amd_pmf_send_cmd(dev, GET_STT_LIMIT_APU, GET_CMD, ARG_NONE,
|
||||
(u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_APU]);
|
||||
amd_pmf_send_cmd(dev, GET_STT_LIMIT_HS2, true, ARG_NONE,
|
||||
amd_pmf_send_cmd(dev, GET_STT_LIMIT_HS2, GET_CMD, ARG_NONE,
|
||||
(u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_HS2]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,17 +73,56 @@ static void amd_pmf_update_uevents(struct amd_pmf_dev *dev, u16 event)
|
|||
input_sync(dev->pmf_idev);
|
||||
}
|
||||
|
||||
static int amd_pmf_get_bios_output_idx(u32 action_idx)
|
||||
{
|
||||
switch (action_idx) {
|
||||
case PMF_POLICY_BIOS_OUTPUT_1:
|
||||
return 0;
|
||||
case PMF_POLICY_BIOS_OUTPUT_2:
|
||||
return 1;
|
||||
case PMF_POLICY_BIOS_OUTPUT_3:
|
||||
return 2;
|
||||
case PMF_POLICY_BIOS_OUTPUT_4:
|
||||
return 3;
|
||||
case PMF_POLICY_BIOS_OUTPUT_5:
|
||||
return 4;
|
||||
case PMF_POLICY_BIOS_OUTPUT_6:
|
||||
return 5;
|
||||
case PMF_POLICY_BIOS_OUTPUT_7:
|
||||
return 6;
|
||||
case PMF_POLICY_BIOS_OUTPUT_8:
|
||||
return 7;
|
||||
case PMF_POLICY_BIOS_OUTPUT_9:
|
||||
return 8;
|
||||
case PMF_POLICY_BIOS_OUTPUT_10:
|
||||
return 9;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static void amd_pmf_update_bios_output(struct amd_pmf_dev *pdev, struct ta_pmf_action *action)
|
||||
{
|
||||
u32 bios_idx;
|
||||
|
||||
bios_idx = amd_pmf_get_bios_output_idx(action->action_index);
|
||||
|
||||
amd_pmf_smartpc_apply_bios_output(pdev, action->value, BIT(bios_idx), bios_idx);
|
||||
}
|
||||
|
||||
static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_result *out)
|
||||
{
|
||||
struct ta_pmf_action *action;
|
||||
u32 val;
|
||||
int idx;
|
||||
|
||||
for (idx = 0; idx < out->actions_count; idx++) {
|
||||
val = out->actions_list[idx].value;
|
||||
switch (out->actions_list[idx].action_index) {
|
||||
action = &out->actions_list[idx];
|
||||
val = action->value;
|
||||
switch (action->action_index) {
|
||||
case PMF_POLICY_SPL:
|
||||
if (dev->prev_data->spl != val) {
|
||||
amd_pmf_send_cmd(dev, SET_SPL, false, val, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_SPL, SET_CMD, val, NULL);
|
||||
dev_dbg(dev->dev, "update SPL: %u\n", val);
|
||||
dev->prev_data->spl = val;
|
||||
}
|
||||
|
|
@ -91,7 +130,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
|
|||
|
||||
case PMF_POLICY_SPPT:
|
||||
if (dev->prev_data->sppt != val) {
|
||||
amd_pmf_send_cmd(dev, SET_SPPT, false, val, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_SPPT, SET_CMD, val, NULL);
|
||||
dev_dbg(dev->dev, "update SPPT: %u\n", val);
|
||||
dev->prev_data->sppt = val;
|
||||
}
|
||||
|
|
@ -99,7 +138,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
|
|||
|
||||
case PMF_POLICY_FPPT:
|
||||
if (dev->prev_data->fppt != val) {
|
||||
amd_pmf_send_cmd(dev, SET_FPPT, false, val, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_FPPT, SET_CMD, val, NULL);
|
||||
dev_dbg(dev->dev, "update FPPT: %u\n", val);
|
||||
dev->prev_data->fppt = val;
|
||||
}
|
||||
|
|
@ -107,7 +146,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
|
|||
|
||||
case PMF_POLICY_SPPT_APU_ONLY:
|
||||
if (dev->prev_data->sppt_apuonly != val) {
|
||||
amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, val, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, SET_CMD, val, NULL);
|
||||
dev_dbg(dev->dev, "update SPPT_APU_ONLY: %u\n", val);
|
||||
dev->prev_data->sppt_apuonly = val;
|
||||
}
|
||||
|
|
@ -115,7 +154,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
|
|||
|
||||
case PMF_POLICY_STT_MIN:
|
||||
if (dev->prev_data->stt_minlimit != val) {
|
||||
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, val, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, SET_CMD, val, NULL);
|
||||
dev_dbg(dev->dev, "update STT_MIN: %u\n", val);
|
||||
dev->prev_data->stt_minlimit = val;
|
||||
}
|
||||
|
|
@ -123,7 +162,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
|
|||
|
||||
case PMF_POLICY_STT_SKINTEMP_APU:
|
||||
if (dev->prev_data->stt_skintemp_apu != val) {
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, SET_CMD,
|
||||
fixp_q88_fromint(val), NULL);
|
||||
dev_dbg(dev->dev, "update STT_SKINTEMP_APU: %u\n", val);
|
||||
dev->prev_data->stt_skintemp_apu = val;
|
||||
|
|
@ -132,7 +171,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
|
|||
|
||||
case PMF_POLICY_STT_SKINTEMP_HS2:
|
||||
if (dev->prev_data->stt_skintemp_hs2 != val) {
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, SET_CMD,
|
||||
fixp_q88_fromint(val), NULL);
|
||||
dev_dbg(dev->dev, "update STT_SKINTEMP_HS2: %u\n", val);
|
||||
dev->prev_data->stt_skintemp_hs2 = val;
|
||||
|
|
@ -141,7 +180,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
|
|||
|
||||
case PMF_POLICY_P3T:
|
||||
if (dev->prev_data->p3t_limit != val) {
|
||||
amd_pmf_send_cmd(dev, SET_P3T, false, val, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_P3T, SET_CMD, val, NULL);
|
||||
dev_dbg(dev->dev, "update P3T: %u\n", val);
|
||||
dev->prev_data->p3t_limit = val;
|
||||
}
|
||||
|
|
@ -149,7 +188,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
|
|||
|
||||
case PMF_POLICY_PMF_PPT:
|
||||
if (dev->prev_data->pmf_ppt != val) {
|
||||
amd_pmf_send_cmd(dev, SET_PMF_PPT, false, val, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_PMF_PPT, SET_CMD, val, NULL);
|
||||
dev_dbg(dev->dev, "update PMF PPT: %u\n", val);
|
||||
dev->prev_data->pmf_ppt = val;
|
||||
}
|
||||
|
|
@ -157,7 +196,7 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
|
|||
|
||||
case PMF_POLICY_PMF_PPT_APU_ONLY:
|
||||
if (dev->prev_data->pmf_ppt_apu_only != val) {
|
||||
amd_pmf_send_cmd(dev, SET_PMF_PPT_APU_ONLY, false, val, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_PMF_PPT_APU_ONLY, SET_CMD, val, NULL);
|
||||
dev_dbg(dev->dev, "update PMF PPT APU ONLY: %u\n", val);
|
||||
dev->prev_data->pmf_ppt_apu_only = val;
|
||||
}
|
||||
|
|
@ -183,43 +222,16 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
|
|||
break;
|
||||
|
||||
case PMF_POLICY_BIOS_OUTPUT_1:
|
||||
amd_pmf_smartpc_apply_bios_output(dev, val, BIT(0), 0);
|
||||
break;
|
||||
|
||||
case PMF_POLICY_BIOS_OUTPUT_2:
|
||||
amd_pmf_smartpc_apply_bios_output(dev, val, BIT(1), 1);
|
||||
break;
|
||||
|
||||
case PMF_POLICY_BIOS_OUTPUT_3:
|
||||
amd_pmf_smartpc_apply_bios_output(dev, val, BIT(2), 2);
|
||||
break;
|
||||
|
||||
case PMF_POLICY_BIOS_OUTPUT_4:
|
||||
amd_pmf_smartpc_apply_bios_output(dev, val, BIT(3), 3);
|
||||
break;
|
||||
|
||||
case PMF_POLICY_BIOS_OUTPUT_5:
|
||||
amd_pmf_smartpc_apply_bios_output(dev, val, BIT(4), 4);
|
||||
break;
|
||||
|
||||
case PMF_POLICY_BIOS_OUTPUT_6:
|
||||
amd_pmf_smartpc_apply_bios_output(dev, val, BIT(5), 5);
|
||||
break;
|
||||
|
||||
case PMF_POLICY_BIOS_OUTPUT_7:
|
||||
amd_pmf_smartpc_apply_bios_output(dev, val, BIT(6), 6);
|
||||
break;
|
||||
|
||||
case PMF_POLICY_BIOS_OUTPUT_8:
|
||||
amd_pmf_smartpc_apply_bios_output(dev, val, BIT(7), 7);
|
||||
break;
|
||||
|
||||
case PMF_POLICY_BIOS_OUTPUT_9:
|
||||
amd_pmf_smartpc_apply_bios_output(dev, val, BIT(8), 8);
|
||||
break;
|
||||
|
||||
case PMF_POLICY_BIOS_OUTPUT_10:
|
||||
amd_pmf_smartpc_apply_bios_output(dev, val, BIT(9), 9);
|
||||
amd_pmf_update_bios_output(dev, action);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmi.h>
|
||||
|
|
@ -30,6 +31,7 @@
|
|||
#include <linux/pci.h>
|
||||
#include <linux/pci_hotplug.h>
|
||||
#include <linux/platform_data/x86/asus-wmi.h>
|
||||
#include <linux/platform_data/x86/asus-wmi-leds-ids.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_profile.h>
|
||||
#include <linux/power_supply.h>
|
||||
|
|
@ -55,8 +57,6 @@ module_param(fnlock_default, bool, 0444);
|
|||
#define to_asus_wmi_driver(pdrv) \
|
||||
(container_of((pdrv), struct asus_wmi_driver, platform_driver))
|
||||
|
||||
#define ASUS_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66"
|
||||
|
||||
#define NOTIFY_BRNUP_MIN 0x11
|
||||
#define NOTIFY_BRNUP_MAX 0x1f
|
||||
#define NOTIFY_BRNDOWN_MIN 0x20
|
||||
|
|
@ -105,8 +105,6 @@ module_param(fnlock_default, bool, 0444);
|
|||
#define USB_INTEL_XUSB2PR 0xD0
|
||||
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
|
||||
|
||||
#define ASUS_ACPI_UID_ASUSWMI "ASUSWMI"
|
||||
|
||||
#define WMI_EVENT_MASK 0xFFFF
|
||||
|
||||
#define FAN_CURVE_POINTS 8
|
||||
|
|
@ -340,6 +338,13 @@ struct asus_wmi {
|
|||
/* Global to allow setting externally without requiring driver data */
|
||||
static enum asus_ally_mcu_hack use_ally_mcu_hack = ASUS_WMI_ALLY_MCU_HACK_INIT;
|
||||
|
||||
#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
|
||||
static void asus_wmi_show_deprecated(void)
|
||||
{
|
||||
pr_notice_once("Accessing attributes through /sys/bus/platform/asus_wmi is deprecated and will be removed in a future release. Please switch over to /sys/class/firmware_attributes.\n");
|
||||
}
|
||||
#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
|
||||
|
||||
/* WMI ************************************************************************/
|
||||
|
||||
static int asus_wmi_evaluate_method3(u32 method_id,
|
||||
|
|
@ -390,7 +395,7 @@ int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval)
|
|||
{
|
||||
return asus_wmi_evaluate_method3(method_id, arg0, arg1, 0, retval);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(asus_wmi_evaluate_method);
|
||||
EXPORT_SYMBOL_NS_GPL(asus_wmi_evaluate_method, "ASUS_WMI");
|
||||
|
||||
static int asus_wmi_evaluate_method5(u32 method_id,
|
||||
u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4, u32 *retval)
|
||||
|
|
@ -554,12 +559,52 @@ static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param,
|
||||
u32 *retval)
|
||||
/**
|
||||
* asus_wmi_get_devstate_dsts() - Get the WMI function state.
|
||||
* @dev_id: The WMI method ID to call.
|
||||
* @retval: A pointer to where to store the value returned from WMI.
|
||||
*
|
||||
* Returns:
|
||||
* * %-ENODEV - method ID is unsupported.
|
||||
* * %0 - successful and retval is filled.
|
||||
* * %other - error from WMI call.
|
||||
*/
|
||||
int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, 0, retval);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if ((*retval & ASUS_WMI_DSTS_PRESENCE_BIT) == 0x00)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(asus_wmi_get_devstate_dsts, "ASUS_WMI");
|
||||
|
||||
/**
|
||||
* asus_wmi_set_devstate() - Set the WMI function state.
|
||||
*
|
||||
* Note: an asus_wmi_set_devstate() call must be paired with a
|
||||
* asus_wmi_get_devstate_dsts() to check if the WMI function is supported.
|
||||
*
|
||||
* @dev_id: The WMI function to call.
|
||||
* @ctrl_param: The argument to be used for this WMI function.
|
||||
* @retval: A pointer to where to store the value returned from WMI.
|
||||
*
|
||||
* Returns:
|
||||
* * %-ENODEV - method ID is unsupported.
|
||||
* * %0 - successful and retval is filled.
|
||||
* * %other - error from WMI call.
|
||||
*/
|
||||
int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval)
|
||||
{
|
||||
return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id,
|
||||
ctrl_param, retval);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(asus_wmi_set_devstate, "ASUS_WMI");
|
||||
|
||||
/* Helper for special devices with magic return codes */
|
||||
static int asus_wmi_get_devstate_bits(struct asus_wmi *asus,
|
||||
|
|
@ -692,6 +737,7 @@ static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus)
|
|||
}
|
||||
|
||||
/* Charging mode, 1=Barrel, 2=USB ******************************************/
|
||||
#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
|
||||
static ssize_t charge_mode_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
|
@ -702,12 +748,16 @@ static ssize_t charge_mode_show(struct device *dev,
|
|||
if (result < 0)
|
||||
return result;
|
||||
|
||||
asus_wmi_show_deprecated();
|
||||
|
||||
return sysfs_emit(buf, "%d\n", value & 0xff);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(charge_mode);
|
||||
#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
|
||||
|
||||
/* dGPU ********************************************************************/
|
||||
#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
|
||||
static ssize_t dgpu_disable_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
|
@ -718,6 +768,8 @@ static ssize_t dgpu_disable_show(struct device *dev,
|
|||
if (result < 0)
|
||||
return result;
|
||||
|
||||
asus_wmi_show_deprecated();
|
||||
|
||||
return sysfs_emit(buf, "%d\n", result);
|
||||
}
|
||||
|
||||
|
|
@ -771,8 +823,10 @@ static ssize_t dgpu_disable_store(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(dgpu_disable);
|
||||
#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
|
||||
|
||||
/* eGPU ********************************************************************/
|
||||
#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
|
||||
static ssize_t egpu_enable_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
|
@ -783,6 +837,8 @@ static ssize_t egpu_enable_show(struct device *dev,
|
|||
if (result < 0)
|
||||
return result;
|
||||
|
||||
asus_wmi_show_deprecated();
|
||||
|
||||
return sysfs_emit(buf, "%d\n", result);
|
||||
}
|
||||
|
||||
|
|
@ -839,8 +895,10 @@ static ssize_t egpu_enable_store(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(egpu_enable);
|
||||
#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
|
||||
|
||||
/* Is eGPU connected? *********************************************************/
|
||||
#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
|
||||
static ssize_t egpu_connected_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
|
@ -851,12 +909,16 @@ static ssize_t egpu_connected_show(struct device *dev,
|
|||
if (result < 0)
|
||||
return result;
|
||||
|
||||
asus_wmi_show_deprecated();
|
||||
|
||||
return sysfs_emit(buf, "%d\n", result);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(egpu_connected);
|
||||
#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
|
||||
|
||||
/* gpu mux switch *************************************************************/
|
||||
#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
|
||||
static ssize_t gpu_mux_mode_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
|
@ -867,6 +929,8 @@ static ssize_t gpu_mux_mode_show(struct device *dev,
|
|||
if (result < 0)
|
||||
return result;
|
||||
|
||||
asus_wmi_show_deprecated();
|
||||
|
||||
return sysfs_emit(buf, "%d\n", result);
|
||||
}
|
||||
|
||||
|
|
@ -925,6 +989,7 @@ static ssize_t gpu_mux_mode_store(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(gpu_mux_mode);
|
||||
#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
|
||||
|
||||
/* TUF Laptop Keyboard RGB Modes **********************************************/
|
||||
static ssize_t kbd_rgb_mode_store(struct device *dev,
|
||||
|
|
@ -1048,6 +1113,7 @@ static const struct attribute_group *kbd_rgb_mode_groups[] = {
|
|||
};
|
||||
|
||||
/* Tunable: PPT: Intel=PL1, AMD=SPPT *****************************************/
|
||||
#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
|
||||
static ssize_t ppt_pl2_sppt_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
|
|
@ -1086,6 +1152,8 @@ static ssize_t ppt_pl2_sppt_show(struct device *dev,
|
|||
{
|
||||
struct asus_wmi *asus = dev_get_drvdata(dev);
|
||||
|
||||
asus_wmi_show_deprecated();
|
||||
|
||||
return sysfs_emit(buf, "%u\n", asus->ppt_pl2_sppt);
|
||||
}
|
||||
static DEVICE_ATTR_RW(ppt_pl2_sppt);
|
||||
|
|
@ -1128,6 +1196,8 @@ static ssize_t ppt_pl1_spl_show(struct device *dev,
|
|||
{
|
||||
struct asus_wmi *asus = dev_get_drvdata(dev);
|
||||
|
||||
asus_wmi_show_deprecated();
|
||||
|
||||
return sysfs_emit(buf, "%u\n", asus->ppt_pl1_spl);
|
||||
}
|
||||
static DEVICE_ATTR_RW(ppt_pl1_spl);
|
||||
|
|
@ -1148,7 +1218,7 @@ static ssize_t ppt_fppt_store(struct device *dev,
|
|||
if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_FPPT, value, &result);
|
||||
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PL3_FPPT, value, &result);
|
||||
if (err) {
|
||||
pr_warn("Failed to set ppt_fppt: %d\n", err);
|
||||
return err;
|
||||
|
|
@ -1171,6 +1241,8 @@ static ssize_t ppt_fppt_show(struct device *dev,
|
|||
{
|
||||
struct asus_wmi *asus = dev_get_drvdata(dev);
|
||||
|
||||
asus_wmi_show_deprecated();
|
||||
|
||||
return sysfs_emit(buf, "%u\n", asus->ppt_fppt);
|
||||
}
|
||||
static DEVICE_ATTR_RW(ppt_fppt);
|
||||
|
|
@ -1214,6 +1286,8 @@ static ssize_t ppt_apu_sppt_show(struct device *dev,
|
|||
{
|
||||
struct asus_wmi *asus = dev_get_drvdata(dev);
|
||||
|
||||
asus_wmi_show_deprecated();
|
||||
|
||||
return sysfs_emit(buf, "%u\n", asus->ppt_apu_sppt);
|
||||
}
|
||||
static DEVICE_ATTR_RW(ppt_apu_sppt);
|
||||
|
|
@ -1257,6 +1331,8 @@ static ssize_t ppt_platform_sppt_show(struct device *dev,
|
|||
{
|
||||
struct asus_wmi *asus = dev_get_drvdata(dev);
|
||||
|
||||
asus_wmi_show_deprecated();
|
||||
|
||||
return sysfs_emit(buf, "%u\n", asus->ppt_platform_sppt);
|
||||
}
|
||||
static DEVICE_ATTR_RW(ppt_platform_sppt);
|
||||
|
|
@ -1300,6 +1376,8 @@ static ssize_t nv_dynamic_boost_show(struct device *dev,
|
|||
{
|
||||
struct asus_wmi *asus = dev_get_drvdata(dev);
|
||||
|
||||
asus_wmi_show_deprecated();
|
||||
|
||||
return sysfs_emit(buf, "%u\n", asus->nv_dynamic_boost);
|
||||
}
|
||||
static DEVICE_ATTR_RW(nv_dynamic_boost);
|
||||
|
|
@ -1343,9 +1421,12 @@ static ssize_t nv_temp_target_show(struct device *dev,
|
|||
{
|
||||
struct asus_wmi *asus = dev_get_drvdata(dev);
|
||||
|
||||
asus_wmi_show_deprecated();
|
||||
|
||||
return sysfs_emit(buf, "%u\n", asus->nv_temp_target);
|
||||
}
|
||||
static DEVICE_ATTR_RW(nv_temp_target);
|
||||
#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
|
||||
|
||||
/* Ally MCU Powersave ********************************************************/
|
||||
|
||||
|
|
@ -1386,6 +1467,7 @@ void set_ally_mcu_powersave(bool enabled)
|
|||
}
|
||||
EXPORT_SYMBOL_NS_GPL(set_ally_mcu_powersave, "ASUS_WMI");
|
||||
|
||||
#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
|
||||
static ssize_t mcu_powersave_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
|
@ -1396,6 +1478,8 @@ static ssize_t mcu_powersave_show(struct device *dev,
|
|||
if (result < 0)
|
||||
return result;
|
||||
|
||||
asus_wmi_show_deprecated();
|
||||
|
||||
return sysfs_emit(buf, "%d\n", result);
|
||||
}
|
||||
|
||||
|
|
@ -1431,6 +1515,7 @@ static ssize_t mcu_powersave_store(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(mcu_powersave);
|
||||
#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
|
||||
|
||||
/* Battery ********************************************************************/
|
||||
|
||||
|
|
@ -1619,14 +1704,14 @@ static void do_kbd_led_set(struct led_classdev *led_cdev, int value)
|
|||
kbd_led_update(asus);
|
||||
}
|
||||
|
||||
static void kbd_led_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
static int kbd_led_set(struct led_classdev *led_cdev, enum led_brightness value)
|
||||
{
|
||||
/* Prevent disabling keyboard backlight on module unregister */
|
||||
if (led_cdev->flags & LED_UNREGISTERING)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
do_kbd_led_set(led_cdev, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kbd_led_set_by_kbd(struct asus_wmi *asus, enum led_brightness value)
|
||||
|
|
@ -1802,7 +1887,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
|
|||
asus->kbd_led_wk = led_val;
|
||||
asus->kbd_led.name = "asus::kbd_backlight";
|
||||
asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED;
|
||||
asus->kbd_led.brightness_set = kbd_led_set;
|
||||
asus->kbd_led.brightness_set_blocking = kbd_led_set;
|
||||
asus->kbd_led.brightness_get = kbd_led_get;
|
||||
asus->kbd_led.max_brightness = 3;
|
||||
|
||||
|
|
@ -2304,6 +2389,7 @@ exit:
|
|||
}
|
||||
|
||||
/* Panel Overdrive ************************************************************/
|
||||
#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
|
||||
static ssize_t panel_od_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
|
@ -2314,6 +2400,8 @@ static ssize_t panel_od_show(struct device *dev,
|
|||
if (result < 0)
|
||||
return result;
|
||||
|
||||
asus_wmi_show_deprecated();
|
||||
|
||||
return sysfs_emit(buf, "%d\n", result);
|
||||
}
|
||||
|
||||
|
|
@ -2350,9 +2438,10 @@ static ssize_t panel_od_store(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(panel_od);
|
||||
#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
|
||||
|
||||
/* Bootup sound ***************************************************************/
|
||||
|
||||
#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
|
||||
static ssize_t boot_sound_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
|
@ -2363,6 +2452,8 @@ static ssize_t boot_sound_show(struct device *dev,
|
|||
if (result < 0)
|
||||
return result;
|
||||
|
||||
asus_wmi_show_deprecated();
|
||||
|
||||
return sysfs_emit(buf, "%d\n", result);
|
||||
}
|
||||
|
||||
|
|
@ -2398,8 +2489,10 @@ static ssize_t boot_sound_store(struct device *dev,
|
|||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(boot_sound);
|
||||
#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
|
||||
|
||||
/* Mini-LED mode **************************************************************/
|
||||
#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
|
||||
static ssize_t mini_led_mode_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
|
@ -2430,6 +2523,8 @@ static ssize_t mini_led_mode_show(struct device *dev,
|
|||
}
|
||||
}
|
||||
|
||||
asus_wmi_show_deprecated();
|
||||
|
||||
return sysfs_emit(buf, "%d\n", value);
|
||||
}
|
||||
|
||||
|
|
@ -2500,10 +2595,13 @@ static ssize_t available_mini_led_mode_show(struct device *dev,
|
|||
return sysfs_emit(buf, "0 1 2\n");
|
||||
}
|
||||
|
||||
asus_wmi_show_deprecated();
|
||||
|
||||
return sysfs_emit(buf, "0\n");
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(available_mini_led_mode);
|
||||
#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
|
||||
|
||||
/* Quirks *********************************************************************/
|
||||
|
||||
|
|
@ -3791,6 +3889,7 @@ static int throttle_thermal_policy_set_default(struct asus_wmi *asus)
|
|||
return throttle_thermal_policy_write(asus);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
|
||||
static ssize_t throttle_thermal_policy_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
|
@ -3834,6 +3933,7 @@ static ssize_t throttle_thermal_policy_store(struct device *dev,
|
|||
* Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent
|
||||
*/
|
||||
static DEVICE_ATTR_RW(throttle_thermal_policy);
|
||||
#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
|
||||
|
||||
/* Platform profile ***********************************************************/
|
||||
static int asus_wmi_platform_profile_get(struct device *dev,
|
||||
|
|
@ -4435,27 +4535,29 @@ static struct attribute *platform_attributes[] = {
|
|||
&dev_attr_camera.attr,
|
||||
&dev_attr_cardr.attr,
|
||||
&dev_attr_touchpad.attr,
|
||||
&dev_attr_charge_mode.attr,
|
||||
&dev_attr_egpu_enable.attr,
|
||||
&dev_attr_egpu_connected.attr,
|
||||
&dev_attr_dgpu_disable.attr,
|
||||
&dev_attr_gpu_mux_mode.attr,
|
||||
&dev_attr_lid_resume.attr,
|
||||
&dev_attr_als_enable.attr,
|
||||
&dev_attr_fan_boost_mode.attr,
|
||||
&dev_attr_throttle_thermal_policy.attr,
|
||||
&dev_attr_ppt_pl2_sppt.attr,
|
||||
&dev_attr_ppt_pl1_spl.attr,
|
||||
&dev_attr_ppt_fppt.attr,
|
||||
&dev_attr_ppt_apu_sppt.attr,
|
||||
&dev_attr_ppt_platform_sppt.attr,
|
||||
&dev_attr_nv_dynamic_boost.attr,
|
||||
&dev_attr_nv_temp_target.attr,
|
||||
&dev_attr_mcu_powersave.attr,
|
||||
&dev_attr_boot_sound.attr,
|
||||
&dev_attr_panel_od.attr,
|
||||
&dev_attr_mini_led_mode.attr,
|
||||
&dev_attr_available_mini_led_mode.attr,
|
||||
#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
|
||||
&dev_attr_charge_mode.attr,
|
||||
&dev_attr_egpu_enable.attr,
|
||||
&dev_attr_egpu_connected.attr,
|
||||
&dev_attr_dgpu_disable.attr,
|
||||
&dev_attr_gpu_mux_mode.attr,
|
||||
&dev_attr_ppt_pl2_sppt.attr,
|
||||
&dev_attr_ppt_pl1_spl.attr,
|
||||
&dev_attr_ppt_fppt.attr,
|
||||
&dev_attr_ppt_apu_sppt.attr,
|
||||
&dev_attr_ppt_platform_sppt.attr,
|
||||
&dev_attr_nv_dynamic_boost.attr,
|
||||
&dev_attr_nv_temp_target.attr,
|
||||
&dev_attr_mcu_powersave.attr,
|
||||
&dev_attr_boot_sound.attr,
|
||||
&dev_attr_panel_od.attr,
|
||||
&dev_attr_mini_led_mode.attr,
|
||||
&dev_attr_available_mini_led_mode.attr,
|
||||
&dev_attr_throttle_thermal_policy.attr,
|
||||
#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -4477,7 +4579,11 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
|
|||
devid = ASUS_WMI_DEVID_LID_RESUME;
|
||||
else if (attr == &dev_attr_als_enable.attr)
|
||||
devid = ASUS_WMI_DEVID_ALS_ENABLE;
|
||||
else if (attr == &dev_attr_charge_mode.attr)
|
||||
else if (attr == &dev_attr_fan_boost_mode.attr)
|
||||
ok = asus->fan_boost_mode_available;
|
||||
|
||||
#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
|
||||
if (attr == &dev_attr_charge_mode.attr)
|
||||
devid = ASUS_WMI_DEVID_CHARGE_MODE;
|
||||
else if (attr == &dev_attr_egpu_enable.attr)
|
||||
ok = asus->egpu_enable_available;
|
||||
|
|
@ -4496,7 +4602,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
|
|||
else if (attr == &dev_attr_ppt_pl1_spl.attr)
|
||||
devid = ASUS_WMI_DEVID_PPT_PL1_SPL;
|
||||
else if (attr == &dev_attr_ppt_fppt.attr)
|
||||
devid = ASUS_WMI_DEVID_PPT_FPPT;
|
||||
devid = ASUS_WMI_DEVID_PPT_PL3_FPPT;
|
||||
else if (attr == &dev_attr_ppt_apu_sppt.attr)
|
||||
devid = ASUS_WMI_DEVID_PPT_APU_SPPT;
|
||||
else if (attr == &dev_attr_ppt_platform_sppt.attr)
|
||||
|
|
@ -4515,6 +4621,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
|
|||
ok = asus->mini_led_dev_id != 0;
|
||||
else if (attr == &dev_attr_available_mini_led_mode.attr)
|
||||
ok = asus->mini_led_dev_id != 0;
|
||||
#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
|
||||
|
||||
if (devid != -1) {
|
||||
ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
|
||||
|
|
@ -4770,6 +4877,7 @@ static int asus_wmi_add(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/* ensure defaults for tunables */
|
||||
#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
|
||||
asus->ppt_pl2_sppt = 5;
|
||||
asus->ppt_pl1_spl = 5;
|
||||
asus->ppt_apu_sppt = 5;
|
||||
|
|
@ -4792,17 +4900,18 @@ static int asus_wmi_add(struct platform_device *pdev)
|
|||
asus->gpu_mux_dev = ASUS_WMI_DEVID_GPU_MUX;
|
||||
else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX_VIVO))
|
||||
asus->gpu_mux_dev = ASUS_WMI_DEVID_GPU_MUX_VIVO;
|
||||
|
||||
if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE))
|
||||
asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE;
|
||||
else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE2))
|
||||
asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE2;
|
||||
#endif /* IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) */
|
||||
|
||||
if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY))
|
||||
asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY;
|
||||
else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO))
|
||||
asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO;
|
||||
|
||||
if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE))
|
||||
asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE;
|
||||
else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE2))
|
||||
asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE2;
|
||||
|
||||
err = fan_boost_mode_check_present(asus);
|
||||
if (err)
|
||||
goto fail_fan_boost_mode;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,593 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Platform driver for the Embedded Controller (EC) of Ayaneo devices. Handles
|
||||
* hwmon (fan speed, fan control), battery charge limits, and magic module
|
||||
* control (connected modules, controller disconnection).
|
||||
*
|
||||
* Copyright (C) 2025 Antheas Kapenekakis <lkml@antheas.dev>
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <acpi/battery.h>
|
||||
|
||||
#define AYANEO_PWM_ENABLE_REG 0x4A
|
||||
#define AYANEO_PWM_REG 0x4B
|
||||
#define AYANEO_PWM_MODE_AUTO 0x00
|
||||
#define AYANEO_PWM_MODE_MANUAL 0x01
|
||||
|
||||
#define AYANEO_FAN_REG 0x76
|
||||
|
||||
#define EC_CHARGE_CONTROL_BEHAVIOURS \
|
||||
(BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) | \
|
||||
BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE))
|
||||
#define AYANEO_CHARGE_REG 0x1e
|
||||
#define AYANEO_CHARGE_VAL_AUTO 0xaa
|
||||
#define AYANEO_CHARGE_VAL_INHIBIT 0x55
|
||||
|
||||
#define AYANEO_POWER_REG 0x2d
|
||||
#define AYANEO_POWER_OFF 0xfe
|
||||
#define AYANEO_POWER_ON 0xff
|
||||
#define AYANEO_MODULE_REG 0x2f
|
||||
#define AYANEO_MODULE_LEFT BIT(0)
|
||||
#define AYANEO_MODULE_RIGHT BIT(1)
|
||||
#define AYANEO_MODULE_MASK (AYANEO_MODULE_LEFT | AYANEO_MODULE_RIGHT)
|
||||
|
||||
struct ayaneo_ec_quirk {
|
||||
bool has_fan_control;
|
||||
bool has_charge_control;
|
||||
bool has_magic_modules;
|
||||
};
|
||||
|
||||
struct ayaneo_ec_platform_data {
|
||||
struct platform_device *pdev;
|
||||
struct ayaneo_ec_quirk *quirks;
|
||||
struct acpi_battery_hook battery_hook;
|
||||
|
||||
// Protects access to restore_pwm
|
||||
struct mutex hwmon_lock;
|
||||
bool restore_charge_limit;
|
||||
bool restore_pwm;
|
||||
};
|
||||
|
||||
static const struct ayaneo_ec_quirk quirk_fan = {
|
||||
.has_fan_control = true,
|
||||
};
|
||||
|
||||
static const struct ayaneo_ec_quirk quirk_charge_limit = {
|
||||
.has_fan_control = true,
|
||||
.has_charge_control = true,
|
||||
};
|
||||
|
||||
static const struct ayaneo_ec_quirk quirk_ayaneo3 = {
|
||||
.has_fan_control = true,
|
||||
.has_charge_control = true,
|
||||
.has_magic_modules = true,
|
||||
};
|
||||
|
||||
static const struct dmi_system_id dmi_table[] = {
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "AYANEO 2"),
|
||||
},
|
||||
.driver_data = (void *)&quirk_fan,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "FLIP"),
|
||||
},
|
||||
.driver_data = (void *)&quirk_fan,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "GEEK"),
|
||||
},
|
||||
.driver_data = (void *)&quirk_fan,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
|
||||
},
|
||||
.driver_data = (void *)&quirk_charge_limit,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR 1S"),
|
||||
},
|
||||
.driver_data = (void *)&quirk_charge_limit,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "AB05-Mendocino"),
|
||||
},
|
||||
.driver_data = (void *)&quirk_charge_limit,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
|
||||
},
|
||||
.driver_data = (void *)&quirk_charge_limit,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "KUN"),
|
||||
},
|
||||
.driver_data = (void *)&quirk_charge_limit,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "AYANEO 3"),
|
||||
},
|
||||
.driver_data = (void *)&quirk_ayaneo3,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
/* Callbacks for hwmon interface */
|
||||
static umode_t ayaneo_ec_hwmon_is_visible(const void *drvdata,
|
||||
enum hwmon_sensor_types type, u32 attr,
|
||||
int channel)
|
||||
{
|
||||
switch (type) {
|
||||
case hwmon_fan:
|
||||
return 0444;
|
||||
case hwmon_pwm:
|
||||
return 0644;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int ayaneo_ec_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long *val)
|
||||
{
|
||||
u8 tmp;
|
||||
int ret;
|
||||
|
||||
switch (type) {
|
||||
case hwmon_fan:
|
||||
switch (attr) {
|
||||
case hwmon_fan_input:
|
||||
ret = ec_read(AYANEO_FAN_REG, &tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
*val = tmp << 8;
|
||||
ret = ec_read(AYANEO_FAN_REG + 1, &tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
*val |= tmp;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case hwmon_pwm:
|
||||
switch (attr) {
|
||||
case hwmon_pwm_input:
|
||||
ret = ec_read(AYANEO_PWM_REG, &tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (tmp > 100)
|
||||
return -EIO;
|
||||
*val = (255 * tmp) / 100;
|
||||
return 0;
|
||||
case hwmon_pwm_enable:
|
||||
ret = ec_read(AYANEO_PWM_ENABLE_REG, &tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (tmp == AYANEO_PWM_MODE_MANUAL)
|
||||
*val = 1;
|
||||
else if (tmp == AYANEO_PWM_MODE_AUTO)
|
||||
*val = 2;
|
||||
else
|
||||
return -EIO;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int ayaneo_ec_write(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long val)
|
||||
{
|
||||
struct ayaneo_ec_platform_data *data = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&data->hwmon_lock);
|
||||
|
||||
switch (type) {
|
||||
case hwmon_pwm:
|
||||
switch (attr) {
|
||||
case hwmon_pwm_enable:
|
||||
data->restore_pwm = false;
|
||||
switch (val) {
|
||||
case 1:
|
||||
return ec_write(AYANEO_PWM_ENABLE_REG,
|
||||
AYANEO_PWM_MODE_MANUAL);
|
||||
case 2:
|
||||
return ec_write(AYANEO_PWM_ENABLE_REG,
|
||||
AYANEO_PWM_MODE_AUTO);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
case hwmon_pwm_input:
|
||||
if (val < 0 || val > 255)
|
||||
return -EINVAL;
|
||||
if (data->restore_pwm) {
|
||||
/*
|
||||
* Defer restoring PWM control to after
|
||||
* userspace resumes successfully
|
||||
*/
|
||||
ret = ec_write(AYANEO_PWM_ENABLE_REG,
|
||||
AYANEO_PWM_MODE_MANUAL);
|
||||
if (ret)
|
||||
return ret;
|
||||
data->restore_pwm = false;
|
||||
}
|
||||
return ec_write(AYANEO_PWM_REG, (val * 100) / 255);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static const struct hwmon_ops ayaneo_ec_hwmon_ops = {
|
||||
.is_visible = ayaneo_ec_hwmon_is_visible,
|
||||
.read = ayaneo_ec_read,
|
||||
.write = ayaneo_ec_write,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *const ayaneo_ec_sensors[] = {
|
||||
HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),
|
||||
HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct hwmon_chip_info ayaneo_ec_chip_info = {
|
||||
.ops = &ayaneo_ec_hwmon_ops,
|
||||
.info = ayaneo_ec_sensors,
|
||||
};
|
||||
|
||||
static int ayaneo_psy_ext_get_prop(struct power_supply *psy,
|
||||
const struct power_supply_ext *ext,
|
||||
void *data,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
int ret;
|
||||
u8 tmp;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
|
||||
ret = ec_read(AYANEO_CHARGE_REG, &tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tmp == AYANEO_CHARGE_VAL_INHIBIT)
|
||||
val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE;
|
||||
else
|
||||
val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO;
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ayaneo_psy_ext_set_prop(struct power_supply *psy,
|
||||
const struct power_supply_ext *ext,
|
||||
void *data,
|
||||
enum power_supply_property psp,
|
||||
const union power_supply_propval *val)
|
||||
{
|
||||
u8 raw_val;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
|
||||
switch (val->intval) {
|
||||
case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO:
|
||||
raw_val = AYANEO_CHARGE_VAL_AUTO;
|
||||
break;
|
||||
case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE:
|
||||
raw_val = AYANEO_CHARGE_VAL_INHIBIT;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return ec_write(AYANEO_CHARGE_REG, raw_val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ayaneo_psy_prop_is_writeable(struct power_supply *psy,
|
||||
const struct power_supply_ext *ext,
|
||||
void *data,
|
||||
enum power_supply_property psp)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static const enum power_supply_property ayaneo_psy_ext_props[] = {
|
||||
POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR,
|
||||
};
|
||||
|
||||
static const struct power_supply_ext ayaneo_psy_ext = {
|
||||
.name = "ayaneo-charge-control",
|
||||
.properties = ayaneo_psy_ext_props,
|
||||
.num_properties = ARRAY_SIZE(ayaneo_psy_ext_props),
|
||||
.charge_behaviours = EC_CHARGE_CONTROL_BEHAVIOURS,
|
||||
.get_property = ayaneo_psy_ext_get_prop,
|
||||
.set_property = ayaneo_psy_ext_set_prop,
|
||||
.property_is_writeable = ayaneo_psy_prop_is_writeable,
|
||||
};
|
||||
|
||||
static int ayaneo_add_battery(struct power_supply *battery,
|
||||
struct acpi_battery_hook *hook)
|
||||
{
|
||||
struct ayaneo_ec_platform_data *data =
|
||||
container_of(hook, struct ayaneo_ec_platform_data, battery_hook);
|
||||
|
||||
return power_supply_register_extension(battery, &ayaneo_psy_ext,
|
||||
&data->pdev->dev, NULL);
|
||||
}
|
||||
|
||||
static int ayaneo_remove_battery(struct power_supply *battery,
|
||||
struct acpi_battery_hook *hook)
|
||||
{
|
||||
power_supply_unregister_extension(battery, &ayaneo_psy_ext);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t controller_power_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
bool value;
|
||||
int ret;
|
||||
|
||||
ret = kstrtobool(buf, &value);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ec_write(AYANEO_POWER_REG, value ? AYANEO_POWER_ON : AYANEO_POWER_OFF);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t controller_power_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int ret;
|
||||
u8 val;
|
||||
|
||||
ret = ec_read(AYANEO_POWER_REG, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%d\n", val == AYANEO_POWER_ON);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(controller_power);
|
||||
|
||||
static ssize_t controller_modules_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
u8 unconnected_modules;
|
||||
char *out;
|
||||
int ret;
|
||||
|
||||
ret = ec_read(AYANEO_MODULE_REG, &unconnected_modules);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (~unconnected_modules & AYANEO_MODULE_MASK) {
|
||||
case AYANEO_MODULE_LEFT | AYANEO_MODULE_RIGHT:
|
||||
out = "both";
|
||||
break;
|
||||
case AYANEO_MODULE_LEFT:
|
||||
out = "left";
|
||||
break;
|
||||
case AYANEO_MODULE_RIGHT:
|
||||
out = "right";
|
||||
break;
|
||||
default:
|
||||
out = "none";
|
||||
break;
|
||||
}
|
||||
|
||||
return sysfs_emit(buf, "%s\n", out);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(controller_modules);
|
||||
|
||||
static struct attribute *aya_mm_attrs[] = {
|
||||
&dev_attr_controller_power.attr,
|
||||
&dev_attr_controller_modules.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static umode_t aya_mm_is_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int n)
|
||||
{
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
if (data->quirks->has_magic_modules)
|
||||
return attr->mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct attribute_group aya_mm_attribute_group = {
|
||||
.is_visible = aya_mm_is_visible,
|
||||
.attrs = aya_mm_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *ayaneo_ec_groups[] = {
|
||||
&aya_mm_attribute_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int ayaneo_ec_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct dmi_system_id *dmi_entry;
|
||||
struct ayaneo_ec_platform_data *data;
|
||||
struct device *hwdev;
|
||||
int ret;
|
||||
|
||||
dmi_entry = dmi_first_match(dmi_table);
|
||||
if (!dmi_entry)
|
||||
return -ENODEV;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->pdev = pdev;
|
||||
data->quirks = dmi_entry->driver_data;
|
||||
ret = devm_mutex_init(&pdev->dev, &data->hwmon_lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
if (data->quirks->has_fan_control) {
|
||||
hwdev = devm_hwmon_device_register_with_info(&pdev->dev,
|
||||
"ayaneo_ec", data, &ayaneo_ec_chip_info, NULL);
|
||||
if (IS_ERR(hwdev))
|
||||
return PTR_ERR(hwdev);
|
||||
}
|
||||
|
||||
if (data->quirks->has_charge_control) {
|
||||
data->battery_hook.add_battery = ayaneo_add_battery;
|
||||
data->battery_hook.remove_battery = ayaneo_remove_battery;
|
||||
data->battery_hook.name = "Ayaneo Battery";
|
||||
ret = devm_battery_hook_register(&pdev->dev, &data->battery_hook);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ayaneo_freeze(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
u8 tmp;
|
||||
|
||||
if (data->quirks->has_charge_control) {
|
||||
ret = ec_read(AYANEO_CHARGE_REG, &tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data->restore_charge_limit = tmp == AYANEO_CHARGE_VAL_INHIBIT;
|
||||
}
|
||||
|
||||
if (data->quirks->has_fan_control) {
|
||||
ret = ec_read(AYANEO_PWM_ENABLE_REG, &tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data->restore_pwm = tmp == AYANEO_PWM_MODE_MANUAL;
|
||||
|
||||
/*
|
||||
* Release the fan when entering hibernation to avoid
|
||||
* overheating if hibernation fails and hangs.
|
||||
*/
|
||||
if (data->restore_pwm) {
|
||||
ret = ec_write(AYANEO_PWM_ENABLE_REG, AYANEO_PWM_MODE_AUTO);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ayaneo_restore(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct ayaneo_ec_platform_data *data = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
if (data->quirks->has_charge_control && data->restore_charge_limit) {
|
||||
ret = ec_write(AYANEO_CHARGE_REG, AYANEO_CHARGE_VAL_INHIBIT);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops ayaneo_pm_ops = {
|
||||
.freeze = ayaneo_freeze,
|
||||
.restore = ayaneo_restore,
|
||||
};
|
||||
|
||||
static struct platform_driver ayaneo_platform_driver = {
|
||||
.driver = {
|
||||
.name = "ayaneo-ec",
|
||||
.dev_groups = ayaneo_ec_groups,
|
||||
.pm = pm_sleep_ptr(&ayaneo_pm_ops),
|
||||
},
|
||||
.probe = ayaneo_ec_probe,
|
||||
};
|
||||
|
||||
static struct platform_device *ayaneo_platform_device;
|
||||
|
||||
static int __init ayaneo_ec_init(void)
|
||||
{
|
||||
ayaneo_platform_device =
|
||||
platform_create_bundle(&ayaneo_platform_driver,
|
||||
ayaneo_ec_probe, NULL, 0, NULL, 0);
|
||||
|
||||
return PTR_ERR_OR_ZERO(ayaneo_platform_device);
|
||||
}
|
||||
|
||||
static void __exit ayaneo_ec_exit(void)
|
||||
{
|
||||
platform_device_unregister(ayaneo_platform_device);
|
||||
platform_driver_unregister(&ayaneo_platform_driver);
|
||||
}
|
||||
|
||||
MODULE_DEVICE_TABLE(dmi, dmi_table);
|
||||
|
||||
module_init(ayaneo_ec_init);
|
||||
module_exit(ayaneo_ec_exit);
|
||||
|
||||
MODULE_AUTHOR("Antheas Kapenekakis <lkml@antheas.dev>");
|
||||
MODULE_DESCRIPTION("Ayaneo Embedded Controller (EC) platform features");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -235,11 +235,6 @@ enum AWCC_THERMAL_TABLES {
|
|||
AWCC_THERMAL_TABLE_USTT = 0xA,
|
||||
};
|
||||
|
||||
enum AWCC_SPECIAL_THERMAL_CODES {
|
||||
AWCC_SPECIAL_PROFILE_CUSTOM = 0x00,
|
||||
AWCC_SPECIAL_PROFILE_GMODE = 0xAB,
|
||||
};
|
||||
|
||||
enum AWCC_TEMP_SENSOR_TYPES {
|
||||
AWCC_TEMP_SENSOR_CPU = 0x01,
|
||||
AWCC_TEMP_SENSOR_FRONT = 0x03,
|
||||
|
|
@ -266,17 +261,18 @@ enum AWCC_FAN_TYPES {
|
|||
};
|
||||
|
||||
enum awcc_thermal_profile {
|
||||
AWCC_PROFILE_USTT_BALANCED,
|
||||
AWCC_PROFILE_USTT_BALANCED_PERFORMANCE,
|
||||
AWCC_PROFILE_USTT_COOL,
|
||||
AWCC_PROFILE_USTT_QUIET,
|
||||
AWCC_PROFILE_USTT_PERFORMANCE,
|
||||
AWCC_PROFILE_USTT_LOW_POWER,
|
||||
AWCC_PROFILE_LEGACY_QUIET,
|
||||
AWCC_PROFILE_LEGACY_BALANCED,
|
||||
AWCC_PROFILE_LEGACY_BALANCED_PERFORMANCE,
|
||||
AWCC_PROFILE_LEGACY_PERFORMANCE,
|
||||
AWCC_PROFILE_LAST,
|
||||
AWCC_PROFILE_SPECIAL_CUSTOM = 0x00,
|
||||
AWCC_PROFILE_LEGACY_QUIET = 0x96,
|
||||
AWCC_PROFILE_LEGACY_BALANCED = 0x97,
|
||||
AWCC_PROFILE_LEGACY_BALANCED_PERFORMANCE = 0x98,
|
||||
AWCC_PROFILE_LEGACY_PERFORMANCE = 0x99,
|
||||
AWCC_PROFILE_USTT_BALANCED = 0xA0,
|
||||
AWCC_PROFILE_USTT_BALANCED_PERFORMANCE = 0xA1,
|
||||
AWCC_PROFILE_USTT_COOL = 0xA2,
|
||||
AWCC_PROFILE_USTT_QUIET = 0xA3,
|
||||
AWCC_PROFILE_USTT_PERFORMANCE = 0xA4,
|
||||
AWCC_PROFILE_USTT_LOW_POWER = 0xA5,
|
||||
AWCC_PROFILE_SPECIAL_GMODE = 0xAB,
|
||||
};
|
||||
|
||||
struct wmax_led_args {
|
||||
|
|
@ -332,19 +328,6 @@ struct awcc_priv {
|
|||
u32 gpio_count;
|
||||
};
|
||||
|
||||
static const enum platform_profile_option awcc_mode_to_platform_profile[AWCC_PROFILE_LAST] = {
|
||||
[AWCC_PROFILE_USTT_BALANCED] = PLATFORM_PROFILE_BALANCED,
|
||||
[AWCC_PROFILE_USTT_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE,
|
||||
[AWCC_PROFILE_USTT_COOL] = PLATFORM_PROFILE_COOL,
|
||||
[AWCC_PROFILE_USTT_QUIET] = PLATFORM_PROFILE_QUIET,
|
||||
[AWCC_PROFILE_USTT_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE,
|
||||
[AWCC_PROFILE_USTT_LOW_POWER] = PLATFORM_PROFILE_LOW_POWER,
|
||||
[AWCC_PROFILE_LEGACY_QUIET] = PLATFORM_PROFILE_QUIET,
|
||||
[AWCC_PROFILE_LEGACY_BALANCED] = PLATFORM_PROFILE_BALANCED,
|
||||
[AWCC_PROFILE_LEGACY_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE,
|
||||
[AWCC_PROFILE_LEGACY_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE,
|
||||
};
|
||||
|
||||
static struct awcc_quirks *awcc;
|
||||
|
||||
/*
|
||||
|
|
@ -562,21 +545,41 @@ const struct attribute_group wmax_deepsleep_attribute_group = {
|
|||
/*
|
||||
* AWCC Helpers
|
||||
*/
|
||||
static bool is_awcc_thermal_profile_id(u8 code)
|
||||
static int awcc_profile_to_pprof(enum awcc_thermal_profile profile,
|
||||
enum platform_profile_option *pprof)
|
||||
{
|
||||
u8 table = FIELD_GET(AWCC_THERMAL_TABLE_MASK, code);
|
||||
u8 mode = FIELD_GET(AWCC_THERMAL_MODE_MASK, code);
|
||||
switch (profile) {
|
||||
case AWCC_PROFILE_SPECIAL_CUSTOM:
|
||||
*pprof = PLATFORM_PROFILE_CUSTOM;
|
||||
break;
|
||||
case AWCC_PROFILE_LEGACY_QUIET:
|
||||
case AWCC_PROFILE_USTT_QUIET:
|
||||
*pprof = PLATFORM_PROFILE_QUIET;
|
||||
break;
|
||||
case AWCC_PROFILE_LEGACY_BALANCED:
|
||||
case AWCC_PROFILE_USTT_BALANCED:
|
||||
*pprof = PLATFORM_PROFILE_BALANCED;
|
||||
break;
|
||||
case AWCC_PROFILE_LEGACY_BALANCED_PERFORMANCE:
|
||||
case AWCC_PROFILE_USTT_BALANCED_PERFORMANCE:
|
||||
*pprof = PLATFORM_PROFILE_BALANCED_PERFORMANCE;
|
||||
break;
|
||||
case AWCC_PROFILE_LEGACY_PERFORMANCE:
|
||||
case AWCC_PROFILE_USTT_PERFORMANCE:
|
||||
case AWCC_PROFILE_SPECIAL_GMODE:
|
||||
*pprof = PLATFORM_PROFILE_PERFORMANCE;
|
||||
break;
|
||||
case AWCC_PROFILE_USTT_COOL:
|
||||
*pprof = PLATFORM_PROFILE_COOL;
|
||||
break;
|
||||
case AWCC_PROFILE_USTT_LOW_POWER:
|
||||
*pprof = PLATFORM_PROFILE_LOW_POWER;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (mode >= AWCC_PROFILE_LAST)
|
||||
return false;
|
||||
|
||||
if (table == AWCC_THERMAL_TABLE_LEGACY && mode >= AWCC_PROFILE_LEGACY_QUIET)
|
||||
return true;
|
||||
|
||||
if (table == AWCC_THERMAL_TABLE_USTT && mode <= AWCC_PROFILE_USTT_LOW_POWER)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int awcc_wmi_command(struct wmi_device *wdev, u32 method_id,
|
||||
|
|
@ -1225,24 +1228,7 @@ static int awcc_platform_profile_get(struct device *dev,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (out_data) {
|
||||
case AWCC_SPECIAL_PROFILE_CUSTOM:
|
||||
*profile = PLATFORM_PROFILE_CUSTOM;
|
||||
return 0;
|
||||
case AWCC_SPECIAL_PROFILE_GMODE:
|
||||
*profile = PLATFORM_PROFILE_PERFORMANCE;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_awcc_thermal_profile_id(out_data))
|
||||
return -ENODATA;
|
||||
|
||||
out_data = FIELD_GET(AWCC_THERMAL_MODE_MASK, out_data);
|
||||
*profile = awcc_mode_to_platform_profile[out_data];
|
||||
|
||||
return 0;
|
||||
return awcc_profile_to_pprof(out_data, profile);
|
||||
}
|
||||
|
||||
static int awcc_platform_profile_set(struct device *dev,
|
||||
|
|
@ -1279,7 +1265,6 @@ static int awcc_platform_profile_probe(void *drvdata, unsigned long *choices)
|
|||
{
|
||||
enum platform_profile_option profile;
|
||||
struct awcc_priv *priv = drvdata;
|
||||
enum awcc_thermal_profile mode;
|
||||
u8 id, offset = 0;
|
||||
int ret;
|
||||
|
||||
|
|
@ -1301,15 +1286,20 @@ static int awcc_platform_profile_probe(void *drvdata, unsigned long *choices)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!is_awcc_thermal_profile_id(id)) {
|
||||
/*
|
||||
* G-Mode profile ID is not listed consistently across modeles
|
||||
* that support it, therefore we handle it through quirks.
|
||||
*/
|
||||
if (id == AWCC_PROFILE_SPECIAL_GMODE)
|
||||
continue;
|
||||
|
||||
ret = awcc_profile_to_pprof(id, &profile);
|
||||
if (ret) {
|
||||
dev_dbg(&priv->wdev->dev, "Unmapped thermal profile ID 0x%02x\n", id);
|
||||
continue;
|
||||
}
|
||||
|
||||
mode = FIELD_GET(AWCC_THERMAL_MODE_MASK, id);
|
||||
profile = awcc_mode_to_platform_profile[mode];
|
||||
priv->supported_profiles[profile] = id;
|
||||
|
||||
__set_bit(profile, choices);
|
||||
}
|
||||
|
||||
|
|
@ -1318,14 +1308,14 @@ static int awcc_platform_profile_probe(void *drvdata, unsigned long *choices)
|
|||
|
||||
if (awcc->gmode) {
|
||||
priv->supported_profiles[PLATFORM_PROFILE_PERFORMANCE] =
|
||||
AWCC_SPECIAL_PROFILE_GMODE;
|
||||
AWCC_PROFILE_SPECIAL_GMODE;
|
||||
|
||||
__set_bit(PLATFORM_PROFILE_PERFORMANCE, choices);
|
||||
}
|
||||
|
||||
/* Every model supports the "custom" profile */
|
||||
priv->supported_profiles[PLATFORM_PROFILE_CUSTOM] =
|
||||
AWCC_SPECIAL_PROFILE_CUSTOM;
|
||||
AWCC_PROFILE_SPECIAL_CUSTOM;
|
||||
|
||||
__set_bit(PLATFORM_PROFILE_CUSTOM, choices);
|
||||
|
||||
|
|
|
|||
|
|
@ -112,14 +112,14 @@ set_speed:
|
|||
gpd_pocket_fan_set_speed(fan, speed);
|
||||
|
||||
/* When mostly idle (low temp/speed), slow down the poll interval. */
|
||||
queue_delayed_work(system_wq, &fan->work,
|
||||
queue_delayed_work(system_percpu_wq, &fan->work,
|
||||
msecs_to_jiffies(4000 / (speed + 1)));
|
||||
}
|
||||
|
||||
static void gpd_pocket_fan_force_update(struct gpd_pocket_fan_data *fan)
|
||||
{
|
||||
fan->last_speed = -1;
|
||||
mod_delayed_work(system_wq, &fan->work, 0);
|
||||
mod_delayed_work(system_percpu_wq, &fan->work, 0);
|
||||
}
|
||||
|
||||
static int gpd_pocket_fan_probe(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -63,12 +63,16 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45E9-BE91-3D44E2C707E4");
|
|||
* contains "PerformanceControl".
|
||||
*/
|
||||
static const char * const omen_thermal_profile_boards[] = {
|
||||
"84DA", "84DB", "84DC", "8574", "8575", "860A", "87B5", "8572", "8573",
|
||||
"8600", "8601", "8602", "8605", "8606", "8607", "8746", "8747", "8749",
|
||||
"874A", "8603", "8604", "8748", "886B", "886C", "878A", "878B", "878C",
|
||||
"88C8", "88CB", "8786", "8787", "8788", "88D1", "88D2", "88F4", "88FD",
|
||||
"88F5", "88F6", "88F7", "88FE", "88FF", "8900", "8901", "8902", "8912",
|
||||
"8917", "8918", "8949", "894A", "89EB", "8BAD", "8A42", "8A15"
|
||||
"84DA", "84DB", "84DC",
|
||||
"8572", "8573", "8574", "8575",
|
||||
"8600", "8601", "8602", "8603", "8604", "8605", "8606", "8607", "860A",
|
||||
"8746", "8747", "8748", "8749", "874A", "8786", "8787", "8788", "878A",
|
||||
"878B", "878C", "87B5",
|
||||
"886B", "886C", "88C8", "88CB", "88D1", "88D2", "88F4", "88F5", "88F6",
|
||||
"88F7", "88FD", "88FE", "88FF",
|
||||
"8900", "8901", "8902", "8912", "8917", "8918", "8949", "894A", "89EB",
|
||||
"8A15", "8A42",
|
||||
"8BAD",
|
||||
};
|
||||
|
||||
/* DMI Board names of Omen laptops that are specifically set to be thermal
|
||||
|
|
@ -76,7 +80,8 @@ static const char * const omen_thermal_profile_boards[] = {
|
|||
* the get system design information WMI call returns
|
||||
*/
|
||||
static const char * const omen_thermal_profile_force_v0_boards[] = {
|
||||
"8607", "8746", "8747", "8749", "874A", "8748"
|
||||
"8607",
|
||||
"8746", "8747", "8748", "8749", "874A",
|
||||
};
|
||||
|
||||
/* DMI board names of Omen laptops that have a thermal profile timer which will
|
||||
|
|
@ -84,12 +89,13 @@ static const char * const omen_thermal_profile_force_v0_boards[] = {
|
|||
* "balanced" when reaching zero.
|
||||
*/
|
||||
static const char * const omen_timed_thermal_profile_boards[] = {
|
||||
"8BAD", "8A42", "8A15"
|
||||
"8A15", "8A42",
|
||||
"8BAD",
|
||||
};
|
||||
|
||||
/* DMI Board names of Victus 16-d1xxx laptops */
|
||||
static const char * const victus_thermal_profile_boards[] = {
|
||||
"8A25"
|
||||
"8A25",
|
||||
};
|
||||
|
||||
/* DMI Board names of Victus 16-r and Victus 16-s laptops */
|
||||
|
|
|
|||
|
|
@ -177,6 +177,18 @@ static const struct dmi_system_id dmi_vgbs_allow_list[] = {
|
|||
DMI_MATCH(DMI_PRODUCT_NAME, "HP Elite Dragonfly G2 Notebook PC"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Dell Pro Rugged 10 Tablet RA00260"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Dell Pro Rugged 12 Tablet RA02260"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -281,6 +281,7 @@ static const struct pmc_reg_map arl_socs_reg_map = {
|
|||
.etr3_offset = ETR3_OFFSET,
|
||||
.pson_residency_offset = TGL_PSON_RESIDENCY_OFFSET,
|
||||
.pson_residency_counter_step = TGL_PSON_RES_COUNTER_STEP,
|
||||
.lpm_req_guid = SOCS_LPM_REQ_GUID,
|
||||
};
|
||||
|
||||
static const struct pmc_bit_map arl_pchs_ltr_show_map[] = {
|
||||
|
|
@ -648,26 +649,23 @@ static const struct pmc_reg_map arl_pchs_reg_map = {
|
|||
.lpm_num_maps = ADL_LPM_NUM_MAPS,
|
||||
.lpm_reg_index = ARL_LPM_REG_INDEX,
|
||||
.etr3_offset = ETR3_OFFSET,
|
||||
.lpm_req_guid = PCHS_LPM_REQ_GUID,
|
||||
};
|
||||
|
||||
static struct pmc_info arl_pmc_info_list[] = {
|
||||
{
|
||||
.guid = IOEP_LPM_REQ_GUID,
|
||||
.devid = PMC_DEVID_ARL_IOEP,
|
||||
.map = &mtl_ioep_reg_map,
|
||||
},
|
||||
{
|
||||
.guid = SOCS_LPM_REQ_GUID,
|
||||
.devid = PMC_DEVID_ARL_SOCS,
|
||||
.map = &arl_socs_reg_map,
|
||||
},
|
||||
{
|
||||
.guid = PCHS_LPM_REQ_GUID,
|
||||
.devid = PMC_DEVID_ARL_PCHS,
|
||||
.map = &arl_pchs_reg_map,
|
||||
},
|
||||
{
|
||||
.guid = SOCM_LPM_REQ_GUID,
|
||||
.devid = PMC_DEVID_ARL_SOCM,
|
||||
.map = &mtl_socm_reg_map,
|
||||
},
|
||||
|
|
@ -720,9 +718,10 @@ static int arl_h_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_
|
|||
return generic_core_init(pmcdev, pmc_dev_info);
|
||||
}
|
||||
|
||||
static u32 ARL_PMT_DMU_GUIDS[] = {ARL_PMT_DMU_GUID, 0x0};
|
||||
struct pmc_dev_info arl_pmc_dev = {
|
||||
.pci_func = 0,
|
||||
.dmu_guid = ARL_PMT_DMU_GUID,
|
||||
.dmu_guids = ARL_PMT_DMU_GUIDS,
|
||||
.regmap_list = arl_pmc_info_list,
|
||||
.map = &arl_socs_reg_map,
|
||||
.sub_req_show = &pmc_core_substate_req_regs_fops,
|
||||
|
|
@ -732,9 +731,10 @@ struct pmc_dev_info arl_pmc_dev = {
|
|||
.sub_req = pmc_core_pmt_get_lpm_req,
|
||||
};
|
||||
|
||||
static u32 ARL_H_PMT_DMU_GUIDS[] = {ARL_PMT_DMU_GUID, ARL_H_PMT_DMU_GUID, 0x0};
|
||||
struct pmc_dev_info arl_h_pmc_dev = {
|
||||
.pci_func = 2,
|
||||
.dmu_guid = ARL_PMT_DMU_GUID,
|
||||
.dmu_guids = ARL_H_PMT_DMU_GUIDS,
|
||||
.regmap_list = arl_pmc_info_list,
|
||||
.map = &mtl_socm_reg_map,
|
||||
.sub_req_show = &pmc_core_substate_req_regs_fops,
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ enum header_type {
|
|||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
|
@ -311,20 +312,20 @@ static inline u8 pmc_core_reg_read_byte(struct pmc *pmc, int offset)
|
|||
}
|
||||
|
||||
static void pmc_core_display_map(struct seq_file *s, int index, int idx, int ip,
|
||||
int pmc_index, u8 pf_reg, const struct pmc_bit_map **pf_map)
|
||||
int pmc_idx, u8 pf_reg, const struct pmc_bit_map **pf_map)
|
||||
{
|
||||
seq_printf(s, "PMC%d:PCH IP: %-2d - %-32s\tState: %s\n",
|
||||
pmc_index, ip, pf_map[idx][index].name,
|
||||
pmc_idx, ip, pf_map[idx][index].name,
|
||||
pf_map[idx][index].bit_mask & pf_reg ? "Off" : "On");
|
||||
}
|
||||
|
||||
static int pmc_core_ppfear_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct pmc_dev *pmcdev = s->private;
|
||||
unsigned int i;
|
||||
unsigned int pmc_idx;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
|
||||
struct pmc *pmc = pmcdev->pmcs[i];
|
||||
for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
|
||||
struct pmc *pmc = pmcdev->pmcs[pmc_idx];
|
||||
const struct pmc_bit_map **maps;
|
||||
u8 pf_regs[PPFEAR_MAX_NUM_ENTRIES];
|
||||
unsigned int index, iter, idx, ip = 0;
|
||||
|
|
@ -342,7 +343,7 @@ static int pmc_core_ppfear_show(struct seq_file *s, void *unused)
|
|||
for (idx = 0; maps[idx]; idx++) {
|
||||
for (index = 0; maps[idx][index].name &&
|
||||
index < pmc->map->ppfear_buckets * 8; ip++, index++)
|
||||
pmc_core_display_map(s, index, idx, ip, i,
|
||||
pmc_core_display_map(s, index, idx, ip, pmc_idx,
|
||||
pf_regs[index / 8], maps);
|
||||
}
|
||||
}
|
||||
|
|
@ -471,7 +472,7 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore)
|
|||
struct pmc *pmc;
|
||||
const struct pmc_reg_map *map;
|
||||
u32 reg;
|
||||
unsigned int pmc_index;
|
||||
unsigned int pmc_idx;
|
||||
int ltr_index;
|
||||
|
||||
ltr_index = value;
|
||||
|
|
@ -479,8 +480,8 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore)
|
|||
* is based on the contiguous indexes from ltr_show output.
|
||||
* pmc index and ltr index needs to be calculated from it.
|
||||
*/
|
||||
for (pmc_index = 0; pmc_index < ARRAY_SIZE(pmcdev->pmcs) && ltr_index >= 0; pmc_index++) {
|
||||
pmc = pmcdev->pmcs[pmc_index];
|
||||
for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs) && ltr_index >= 0; pmc_idx++) {
|
||||
pmc = pmcdev->pmcs[pmc_idx];
|
||||
|
||||
if (!pmc)
|
||||
continue;
|
||||
|
|
@ -497,10 +498,10 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore)
|
|||
ltr_index = ltr_index - (map->ltr_ignore_max + 2) - 1;
|
||||
}
|
||||
|
||||
if (pmc_index >= ARRAY_SIZE(pmcdev->pmcs) || ltr_index < 0)
|
||||
if (pmc_idx >= ARRAY_SIZE(pmcdev->pmcs) || ltr_index < 0)
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("ltr_ignore for pmc%d: ltr_index:%d\n", pmc_index, ltr_index);
|
||||
pr_debug("ltr_ignore for pmc%d: ltr_index:%d\n", pmc_idx, ltr_index);
|
||||
|
||||
guard(mutex)(&pmcdev->lock);
|
||||
|
||||
|
|
@ -635,14 +636,14 @@ static int pmc_core_ltr_show(struct seq_file *s, void *unused)
|
|||
u64 decoded_snoop_ltr, decoded_non_snoop_ltr, val;
|
||||
u32 ltr_raw_data, scale;
|
||||
u16 snoop_ltr, nonsnoop_ltr;
|
||||
unsigned int i, index, ltr_index = 0;
|
||||
unsigned int pmc_idx, index, ltr_index = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
|
||||
for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
|
||||
struct pmc *pmc;
|
||||
const struct pmc_bit_map *map;
|
||||
u32 ltr_ign_reg;
|
||||
|
||||
pmc = pmcdev->pmcs[i];
|
||||
pmc = pmcdev->pmcs[pmc_idx];
|
||||
if (!pmc)
|
||||
continue;
|
||||
|
||||
|
|
@ -676,7 +677,7 @@ static int pmc_core_ltr_show(struct seq_file *s, void *unused)
|
|||
}
|
||||
|
||||
seq_printf(s, "%d\tPMC%d:%-32s\tLTR: RAW: 0x%-16x\tNon-Snoop(ns): %-16llu\tSnoop(ns): %-16llu\tLTR_IGNORE: %d\n",
|
||||
ltr_index, i, map[index].name, ltr_raw_data,
|
||||
ltr_index, pmc_idx, map[index].name, ltr_raw_data,
|
||||
decoded_non_snoop_ltr,
|
||||
decoded_snoop_ltr, ltr_ign_data);
|
||||
ltr_index++;
|
||||
|
|
@ -689,15 +690,15 @@ DEFINE_SHOW_ATTRIBUTE(pmc_core_ltr);
|
|||
static int pmc_core_s0ix_blocker_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct pmc_dev *pmcdev = s->private;
|
||||
unsigned int pmcidx;
|
||||
unsigned int pmc_idx;
|
||||
|
||||
for (pmcidx = 0; pmcidx < ARRAY_SIZE(pmcdev->pmcs); pmcidx++) {
|
||||
for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); pmc_idx++) {
|
||||
const struct pmc_bit_map **maps;
|
||||
unsigned int arr_size, r_idx;
|
||||
u32 offset, counter;
|
||||
struct pmc *pmc;
|
||||
|
||||
pmc = pmcdev->pmcs[pmcidx];
|
||||
pmc = pmcdev->pmcs[pmc_idx];
|
||||
if (!pmc)
|
||||
continue;
|
||||
maps = pmc->map->s0ix_blocker_maps;
|
||||
|
|
@ -711,7 +712,7 @@ static int pmc_core_s0ix_blocker_show(struct seq_file *s, void *unused)
|
|||
if (!map->blk)
|
||||
continue;
|
||||
counter = pmc_core_reg_read(pmc, offset);
|
||||
seq_printf(s, "PMC%d:%-30s %-30d\n", pmcidx,
|
||||
seq_printf(s, "PMC%d:%-30s %-30d\n", pmc_idx,
|
||||
map->name, counter);
|
||||
offset += map->blk * S0IX_BLK_SIZE;
|
||||
}
|
||||
|
|
@ -723,13 +724,13 @@ DEFINE_SHOW_ATTRIBUTE(pmc_core_s0ix_blocker);
|
|||
|
||||
static void pmc_core_ltr_ignore_all(struct pmc_dev *pmcdev)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int pmc_idx;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); i++) {
|
||||
for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); pmc_idx++) {
|
||||
struct pmc *pmc;
|
||||
u32 ltr_ign;
|
||||
|
||||
pmc = pmcdev->pmcs[i];
|
||||
pmc = pmcdev->pmcs[pmc_idx];
|
||||
if (!pmc)
|
||||
continue;
|
||||
|
||||
|
|
@ -750,12 +751,12 @@ static void pmc_core_ltr_ignore_all(struct pmc_dev *pmcdev)
|
|||
|
||||
static void pmc_core_ltr_restore_all(struct pmc_dev *pmcdev)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int pmc_idx;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); i++) {
|
||||
for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); pmc_idx++) {
|
||||
struct pmc *pmc;
|
||||
|
||||
pmc = pmcdev->pmcs[i];
|
||||
pmc = pmcdev->pmcs[pmc_idx];
|
||||
if (!pmc)
|
||||
continue;
|
||||
|
||||
|
|
@ -794,10 +795,10 @@ DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_res);
|
|||
static int pmc_core_substate_sts_regs_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct pmc_dev *pmcdev = s->private;
|
||||
unsigned int i;
|
||||
unsigned int pmc_idx;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
|
||||
struct pmc *pmc = pmcdev->pmcs[i];
|
||||
for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
|
||||
struct pmc *pmc = pmcdev->pmcs[pmc_idx];
|
||||
const struct pmc_bit_map **maps;
|
||||
u32 offset;
|
||||
|
||||
|
|
@ -805,7 +806,7 @@ static int pmc_core_substate_sts_regs_show(struct seq_file *s, void *unused)
|
|||
continue;
|
||||
maps = pmc->map->lpm_sts;
|
||||
offset = pmc->map->lpm_status_offset;
|
||||
pmc_core_lpm_display(pmc, NULL, s, offset, i, "STATUS", maps);
|
||||
pmc_core_lpm_display(pmc, NULL, s, offset, pmc_idx, "STATUS", maps);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -815,10 +816,10 @@ DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_sts_regs);
|
|||
static int pmc_core_substate_l_sts_regs_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct pmc_dev *pmcdev = s->private;
|
||||
unsigned int i;
|
||||
unsigned int pmc_idx;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
|
||||
struct pmc *pmc = pmcdev->pmcs[i];
|
||||
for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
|
||||
struct pmc *pmc = pmcdev->pmcs[pmc_idx];
|
||||
const struct pmc_bit_map **maps;
|
||||
u32 offset;
|
||||
|
||||
|
|
@ -826,7 +827,7 @@ static int pmc_core_substate_l_sts_regs_show(struct seq_file *s, void *unused)
|
|||
continue;
|
||||
maps = pmc->map->lpm_sts;
|
||||
offset = pmc->map->lpm_live_status_offset;
|
||||
pmc_core_lpm_display(pmc, NULL, s, offset, i, "LIVE_STATUS", maps);
|
||||
pmc_core_lpm_display(pmc, NULL, s, offset, pmc_idx, "LIVE_STATUS", maps);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -919,11 +920,11 @@ static int pmc_core_substate_req_regs_show(struct seq_file *s, void *unused)
|
|||
u32 sts_offset;
|
||||
u32 sts_offset_live;
|
||||
u32 *lpm_req_regs;
|
||||
unsigned int mp, pmc_index;
|
||||
unsigned int mp, pmc_idx;
|
||||
int num_maps;
|
||||
|
||||
for (pmc_index = 0; pmc_index < ARRAY_SIZE(pmcdev->pmcs); ++pmc_index) {
|
||||
struct pmc *pmc = pmcdev->pmcs[pmc_index];
|
||||
for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
|
||||
struct pmc *pmc = pmcdev->pmcs[pmc_idx];
|
||||
const struct pmc_bit_map **maps;
|
||||
|
||||
if (!pmc)
|
||||
|
|
@ -944,7 +945,7 @@ static int pmc_core_substate_req_regs_show(struct seq_file *s, void *unused)
|
|||
continue;
|
||||
|
||||
/* Display the header */
|
||||
pmc_core_substate_req_header_show(s, pmc_index, HEADER_STATUS);
|
||||
pmc_core_substate_req_header_show(s, pmc_idx, HEADER_STATUS);
|
||||
|
||||
/* Loop over maps */
|
||||
for (mp = 0; mp < num_maps; mp++) {
|
||||
|
|
@ -982,7 +983,7 @@ static int pmc_core_substate_req_regs_show(struct seq_file *s, void *unused)
|
|||
}
|
||||
|
||||
/* Display the element name in the first column */
|
||||
seq_printf(s, "pmc%d: %34s |", pmc_index, map[i].name);
|
||||
seq_printf(s, "pmc%d: %34s |", pmc_idx, map[i].name);
|
||||
|
||||
/* Loop over the enabled states and display if required */
|
||||
pmc_for_each_mode(mode, pmcdev) {
|
||||
|
|
@ -1281,7 +1282,20 @@ int get_primary_reg_base(struct pmc *pmc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 guid)
|
||||
static struct telem_endpoint *pmc_core_register_endpoint(struct pci_dev *pcidev, u32 *guids)
|
||||
{
|
||||
struct telem_endpoint *ep;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; guids[i]; i++) {
|
||||
ep = pmt_telem_find_and_register_endpoint(pcidev, guids[i], 0);
|
||||
if (!IS_ERR(ep))
|
||||
return ep;
|
||||
}
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 *guids)
|
||||
{
|
||||
struct telem_endpoint *ep;
|
||||
struct pci_dev *pcidev;
|
||||
|
|
@ -1292,7 +1306,7 @@ void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 guid)
|
|||
return;
|
||||
}
|
||||
|
||||
ep = pmt_telem_find_and_register_endpoint(pcidev, guid, 0);
|
||||
ep = pmc_core_register_endpoint(pcidev, guids);
|
||||
pci_dev_put(pcidev);
|
||||
if (IS_ERR(ep)) {
|
||||
dev_err(&pmcdev->pdev->dev,
|
||||
|
|
@ -1302,8 +1316,6 @@ void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 guid)
|
|||
}
|
||||
|
||||
pmcdev->punit_ep = ep;
|
||||
|
||||
pmcdev->has_die_c6 = true;
|
||||
pmcdev->die_c6_offset = MTL_PMT_DMU_DIE_C6_OFFSET;
|
||||
}
|
||||
|
||||
|
|
@ -1423,22 +1435,13 @@ static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev, struct pmc_dev_info
|
|||
pmcdev->dbgfs_dir, primary_pmc, &pmc_core_pson_residency);
|
||||
}
|
||||
|
||||
if (pmcdev->has_die_c6) {
|
||||
if (pmcdev->punit_ep) {
|
||||
debugfs_create_file("die_c6_us_show", 0444,
|
||||
pmcdev->dbgfs_dir, pmcdev,
|
||||
&pmc_core_die_c6_us_fops);
|
||||
}
|
||||
}
|
||||
|
||||
static u32 pmc_core_find_guid(struct pmc_info *list, const struct pmc_reg_map *map)
|
||||
{
|
||||
for (; list->map; ++list)
|
||||
if (list->map == map)
|
||||
return list->guid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function retrieves low power mode requirement data from PMC Low
|
||||
* Power Mode (LPM) table.
|
||||
|
|
@ -1553,26 +1556,24 @@ static int pmc_core_get_telem_info(struct pmc_dev *pmcdev, struct pmc_dev_info *
|
|||
{
|
||||
struct pci_dev *pcidev __free(pci_dev_put) = NULL;
|
||||
struct telem_endpoint *ep;
|
||||
unsigned int i;
|
||||
u32 guid;
|
||||
unsigned int pmc_idx;
|
||||
int ret;
|
||||
|
||||
pcidev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(20, pmc_dev_info->pci_func));
|
||||
if (!pcidev)
|
||||
return -ENODEV;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
|
||||
for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
|
||||
struct pmc *pmc;
|
||||
|
||||
pmc = pmcdev->pmcs[i];
|
||||
pmc = pmcdev->pmcs[pmc_idx];
|
||||
if (!pmc)
|
||||
continue;
|
||||
|
||||
guid = pmc_core_find_guid(pmcdev->regmap_list, pmc->map);
|
||||
if (!guid)
|
||||
if (!pmc->map->lpm_req_guid)
|
||||
return -ENXIO;
|
||||
|
||||
ep = pmt_telem_find_and_register_endpoint(pcidev, guid, 0);
|
||||
ep = pmt_telem_find_and_register_endpoint(pcidev, pmc->map->lpm_req_guid, 0);
|
||||
if (IS_ERR(ep)) {
|
||||
dev_dbg(&pmcdev->pdev->dev, "couldn't get telem endpoint %pe", ep);
|
||||
return -EPROBE_DEFER;
|
||||
|
|
@ -1596,7 +1597,7 @@ static const struct pmc_reg_map *pmc_core_find_regmap(struct pmc_info *list, u16
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_index)
|
||||
static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_idx)
|
||||
|
||||
{
|
||||
struct pmc_ssram_telemetry pmc_ssram_telemetry;
|
||||
|
|
@ -1604,7 +1605,7 @@ static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_index)
|
|||
struct pmc *pmc;
|
||||
int ret;
|
||||
|
||||
ret = pmc_ssram_telemetry_get_pmc_info(pmc_index, &pmc_ssram_telemetry);
|
||||
ret = pmc_ssram_telemetry_get_pmc_info(pmc_idx, &pmc_ssram_telemetry);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -1612,7 +1613,7 @@ static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_index)
|
|||
if (!map)
|
||||
return -ENODEV;
|
||||
|
||||
pmc = pmcdev->pmcs[pmc_index];
|
||||
pmc = pmcdev->pmcs[pmc_idx];
|
||||
/* Memory for primary PMC has been allocated */
|
||||
if (!pmc) {
|
||||
pmc = devm_kzalloc(&pmcdev->pdev->dev, sizeof(*pmc), GFP_KERNEL);
|
||||
|
|
@ -1629,7 +1630,7 @@ static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_index)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pmcdev->pmcs[pmc_index] = pmc;
|
||||
pmcdev->pmcs[pmc_idx] = pmc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1689,8 +1690,8 @@ int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
|
|||
}
|
||||
|
||||
pmc_core_get_low_power_modes(pmcdev);
|
||||
if (pmc_dev_info->dmu_guid)
|
||||
pmc_core_punit_pmt_init(pmcdev, pmc_dev_info->dmu_guid);
|
||||
if (pmc_dev_info->dmu_guids)
|
||||
pmc_core_punit_pmt_init(pmcdev, pmc_dev_info->dmu_guids);
|
||||
|
||||
if (ssram) {
|
||||
ret = pmc_core_get_telem_info(pmcdev, pmc_dev_info);
|
||||
|
|
@ -1701,8 +1702,8 @@ int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
|
|||
return 0;
|
||||
|
||||
unmap_regbase:
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
|
||||
struct pmc *pmc = pmcdev->pmcs[i];
|
||||
for (unsigned int pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
|
||||
struct pmc *pmc = pmcdev->pmcs[pmc_idx];
|
||||
|
||||
if (pmc && pmc->regbase)
|
||||
iounmap(pmc->regbase);
|
||||
|
|
@ -1795,10 +1796,10 @@ static void pmc_core_do_dmi_quirks(struct pmc *pmc)
|
|||
static void pmc_core_clean_structure(struct platform_device *pdev)
|
||||
{
|
||||
struct pmc_dev *pmcdev = platform_get_drvdata(pdev);
|
||||
unsigned int i;
|
||||
unsigned int pmc_idx;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
|
||||
struct pmc *pmc = pmcdev->pmcs[i];
|
||||
for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
|
||||
struct pmc *pmc = pmcdev->pmcs[pmc_idx];
|
||||
|
||||
if (pmc && pmc->regbase)
|
||||
iounmap(pmc->regbase);
|
||||
|
|
@ -1958,7 +1959,7 @@ int pmc_core_resume_common(struct pmc_dev *pmcdev)
|
|||
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
|
||||
const struct pmc_bit_map **maps = pmc->map->lpm_sts;
|
||||
int offset = pmc->map->lpm_status_offset;
|
||||
unsigned int i;
|
||||
unsigned int pmc_idx, i;
|
||||
|
||||
/* Check if the syspend used S0ix */
|
||||
if (pm_suspend_via_firmware())
|
||||
|
|
@ -1996,13 +1997,13 @@ int pmc_core_resume_common(struct pmc_dev *pmcdev)
|
|||
if (pmc->map->slps0_dbg_maps)
|
||||
pmc_core_slps0_display(pmc, dev, NULL);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) {
|
||||
struct pmc *pmc = pmcdev->pmcs[i];
|
||||
for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
|
||||
struct pmc *pmc = pmcdev->pmcs[pmc_idx];
|
||||
|
||||
if (!pmc)
|
||||
continue;
|
||||
if (pmc->map->lpm_sts)
|
||||
pmc_core_lpm_display(pmc, dev, NULL, offset, i, "STATUS", maps);
|
||||
pmc_core_lpm_display(pmc, dev, NULL, offset, pmc_idx, "STATUS", maps);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -282,7 +282,8 @@ enum ppfear_regs {
|
|||
/* Die C6 from PUNIT telemetry */
|
||||
#define MTL_PMT_DMU_DIE_C6_OFFSET 15
|
||||
#define MTL_PMT_DMU_GUID 0x1A067102
|
||||
#define ARL_PMT_DMU_GUID 0x1A06A000
|
||||
#define ARL_PMT_DMU_GUID 0x1A06A102
|
||||
#define ARL_H_PMT_DMU_GUID 0x1A06A101
|
||||
|
||||
#define LNL_PMC_MMIO_REG_LEN 0x2708
|
||||
#define LNL_PMC_LTR_OSSE 0x1B88
|
||||
|
|
@ -303,6 +304,8 @@ enum ppfear_regs {
|
|||
/* Wildcat Lake */
|
||||
#define WCL_PMC_LTR_RESERVED 0x1B64
|
||||
#define WCL_PCD_PMC_MMIO_REG_LEN 0x3178
|
||||
#define WCL_NUM_S0IX_BLOCKER 94
|
||||
#define WCL_BLK_REQ_OFFSET 50
|
||||
|
||||
/* SSRAM PMC Device ID */
|
||||
/* LNL */
|
||||
|
|
@ -355,6 +358,7 @@ struct pmc_bit_map {
|
|||
* @s0ix_blocker_offset PWRMBASE offset to S0ix blocker counter
|
||||
* @num_s0ix_blocker: Number of S0ix blockers
|
||||
* @blocker_req_offset: Telemetry offset to S0ix blocker low power mode substate requirement table
|
||||
* @lpm_req_guid: Telemetry GUID to read low power mode substate requirement table
|
||||
*
|
||||
* Each PCH has unique set of register offsets and bit indexes. This structure
|
||||
* captures them to have a common implementation.
|
||||
|
|
@ -396,6 +400,8 @@ struct pmc_reg_map {
|
|||
const u8 *lpm_reg_index;
|
||||
const u32 pson_residency_offset;
|
||||
const u32 pson_residency_counter_step;
|
||||
/* GUID for telemetry regions */
|
||||
const u32 lpm_req_guid;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -405,7 +411,6 @@ struct pmc_reg_map {
|
|||
* specific attributes
|
||||
*/
|
||||
struct pmc_info {
|
||||
u32 guid;
|
||||
u16 devid;
|
||||
const struct pmc_reg_map *map;
|
||||
};
|
||||
|
|
@ -465,7 +470,6 @@ struct pmc_dev {
|
|||
u64 *pkgc_res_cnt;
|
||||
u8 num_of_pkgc;
|
||||
|
||||
bool has_die_c6;
|
||||
u32 die_c6_offset;
|
||||
struct telem_endpoint *punit_ep;
|
||||
struct pmc_info *regmap_list;
|
||||
|
|
@ -481,7 +485,7 @@ enum pmc_index {
|
|||
/**
|
||||
* struct pmc_dev_info - Structure to keep PMC device info
|
||||
* @pci_func: Function number of the primary PMC
|
||||
* @dmu_guid: Die Management Unit GUID
|
||||
* @dmu_guids: List of Die Management Unit GUID
|
||||
* @regmap_list: Pointer to a list of pmc_info structure that could be
|
||||
* available for the platform. When set, this field implies
|
||||
* SSRAM support.
|
||||
|
|
@ -495,7 +499,7 @@ enum pmc_index {
|
|||
*/
|
||||
struct pmc_dev_info {
|
||||
u8 pci_func;
|
||||
u32 dmu_guid;
|
||||
u32 *dmu_guids;
|
||||
struct pmc_info *regmap_list;
|
||||
const struct pmc_reg_map *map;
|
||||
const struct file_operations *sub_req_show;
|
||||
|
|
@ -532,7 +536,7 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore);
|
|||
int pmc_core_resume_common(struct pmc_dev *pmcdev);
|
||||
int get_primary_reg_base(struct pmc *pmc);
|
||||
void pmc_core_get_low_power_modes(struct pmc_dev *pmcdev);
|
||||
void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 guid);
|
||||
void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 *guids);
|
||||
void pmc_core_set_device_d3(unsigned int device);
|
||||
|
||||
int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info);
|
||||
|
|
|
|||
|
|
@ -533,11 +533,11 @@ static const struct pmc_reg_map lnl_socm_reg_map = {
|
|||
.s0ix_blocker_maps = lnl_blk_maps,
|
||||
.s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET,
|
||||
.lpm_reg_index = LNL_LPM_REG_INDEX,
|
||||
.lpm_req_guid = SOCM_LPM_REQ_GUID,
|
||||
};
|
||||
|
||||
static struct pmc_info lnl_pmc_info_list[] = {
|
||||
{
|
||||
.guid = SOCM_LPM_REQ_GUID,
|
||||
.devid = PMC_DEVID_LNL_SOCM,
|
||||
.map = &lnl_socm_reg_map,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -473,6 +473,7 @@ const struct pmc_reg_map mtl_socm_reg_map = {
|
|||
.lpm_status_offset = MTL_LPM_STATUS_OFFSET,
|
||||
.lpm_live_status_offset = MTL_LPM_LIVE_STATUS_OFFSET,
|
||||
.lpm_reg_index = MTL_LPM_REG_INDEX,
|
||||
.lpm_req_guid = SOCP_LPM_REQ_GUID,
|
||||
};
|
||||
|
||||
static const struct pmc_bit_map mtl_ioep_pfear_map[] = {
|
||||
|
|
@ -797,6 +798,7 @@ const struct pmc_reg_map mtl_ioep_reg_map = {
|
|||
.lpm_en_offset = MTL_LPM_EN_OFFSET,
|
||||
.lpm_sts_latch_en_offset = MTL_LPM_STATUS_LATCH_EN_OFFSET,
|
||||
.lpm_reg_index = MTL_LPM_REG_INDEX,
|
||||
.lpm_req_guid = IOEP_LPM_REQ_GUID,
|
||||
};
|
||||
|
||||
static const struct pmc_bit_map mtl_ioem_pfear_map[] = {
|
||||
|
|
@ -944,21 +946,19 @@ static const struct pmc_reg_map mtl_ioem_reg_map = {
|
|||
.lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2,
|
||||
.lpm_residency_offset = MTL_LPM_RESIDENCY_OFFSET,
|
||||
.lpm_reg_index = MTL_LPM_REG_INDEX,
|
||||
.lpm_req_guid = IOEM_LPM_REQ_GUID,
|
||||
};
|
||||
|
||||
static struct pmc_info mtl_pmc_info_list[] = {
|
||||
{
|
||||
.guid = SOCP_LPM_REQ_GUID,
|
||||
.devid = PMC_DEVID_MTL_SOCM,
|
||||
.map = &mtl_socm_reg_map,
|
||||
},
|
||||
{
|
||||
.guid = IOEP_LPM_REQ_GUID,
|
||||
.devid = PMC_DEVID_MTL_IOEP,
|
||||
.map = &mtl_ioep_reg_map,
|
||||
},
|
||||
{
|
||||
.guid = IOEM_LPM_REQ_GUID,
|
||||
.devid = PMC_DEVID_MTL_IOEM,
|
||||
.map = &mtl_ioem_reg_map
|
||||
},
|
||||
|
|
@ -992,9 +992,10 @@ static int mtl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_in
|
|||
return generic_core_init(pmcdev, pmc_dev_info);
|
||||
}
|
||||
|
||||
static u32 MTL_PMT_DMU_GUIDS[] = {MTL_PMT_DMU_GUID, 0x0};
|
||||
struct pmc_dev_info mtl_pmc_dev = {
|
||||
.pci_func = 2,
|
||||
.dmu_guid = MTL_PMT_DMU_GUID,
|
||||
.dmu_guids = MTL_PMT_DMU_GUIDS,
|
||||
.regmap_list = mtl_pmc_info_list,
|
||||
.map = &mtl_socm_reg_map,
|
||||
.sub_req_show = &pmc_core_substate_req_regs_fops,
|
||||
|
|
|
|||
|
|
@ -528,16 +528,15 @@ static const struct pmc_reg_map ptl_pcdp_reg_map = {
|
|||
.s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET,
|
||||
.num_s0ix_blocker = PTL_NUM_S0IX_BLOCKER,
|
||||
.blocker_req_offset = PTL_BLK_REQ_OFFSET,
|
||||
.lpm_req_guid = PCDP_LPM_REQ_GUID,
|
||||
};
|
||||
|
||||
static struct pmc_info ptl_pmc_info_list[] = {
|
||||
{
|
||||
.guid = PCDP_LPM_REQ_GUID,
|
||||
.devid = PMC_DEVID_PTL_PCDH,
|
||||
.map = &ptl_pcdp_reg_map,
|
||||
},
|
||||
{
|
||||
.guid = PCDP_LPM_REQ_GUID,
|
||||
.devid = PMC_DEVID_PTL_PCDP,
|
||||
.map = &ptl_pcdp_reg_map,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
#include "core.h"
|
||||
|
||||
/* PMC SSRAM PMT Telemetry GUIDS */
|
||||
#define PCDN_LPM_REQ_GUID 0x33747648
|
||||
|
||||
static const struct pmc_bit_map wcl_pcdn_pfear_map[] = {
|
||||
{"PMC_0", BIT(0)},
|
||||
{"FUSE_OSSE", BIT(1)},
|
||||
|
|
@ -453,6 +456,17 @@ static const struct pmc_reg_map wcl_pcdn_reg_map = {
|
|||
.lpm_live_status_offset = MTL_LPM_LIVE_STATUS_OFFSET,
|
||||
.s0ix_blocker_maps = wcl_pcdn_blk_maps,
|
||||
.s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET,
|
||||
.num_s0ix_blocker = WCL_NUM_S0IX_BLOCKER,
|
||||
.blocker_req_offset = WCL_BLK_REQ_OFFSET,
|
||||
.lpm_req_guid = PCDN_LPM_REQ_GUID,
|
||||
};
|
||||
|
||||
static struct pmc_info wcl_pmc_info_list[] = {
|
||||
{
|
||||
.devid = PMC_DEVID_WCL_PCDN,
|
||||
.map = &wcl_pcdn_reg_map,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
#define WCL_NPU_PCI_DEV 0xfd3e
|
||||
|
|
@ -479,8 +493,12 @@ static int wcl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_in
|
|||
}
|
||||
|
||||
struct pmc_dev_info wcl_pmc_dev = {
|
||||
.pci_func = 2,
|
||||
.regmap_list = wcl_pmc_info_list,
|
||||
.map = &wcl_pcdn_reg_map,
|
||||
.sub_req_show = &pmc_core_substate_blk_req_fops,
|
||||
.suspend = cnl_suspend,
|
||||
.resume = wcl_resume,
|
||||
.init = wcl_core_init,
|
||||
.sub_req = pmc_core_pmt_get_blk_sub_req,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -765,6 +765,7 @@ static const struct intel_vsec_platform_info lnl_info = {
|
|||
#define PCI_DEVICE_ID_INTEL_VSEC_TGL 0x9a0d
|
||||
#define PCI_DEVICE_ID_INTEL_VSEC_LNL_M 0x647d
|
||||
#define PCI_DEVICE_ID_INTEL_VSEC_PTL 0xb07d
|
||||
#define PCI_DEVICE_ID_INTEL_VSEC_WCL 0xfd7d
|
||||
static const struct pci_device_id intel_vsec_pci_ids[] = {
|
||||
{ PCI_DEVICE_DATA(INTEL, VSEC_ADL, &tgl_info) },
|
||||
{ PCI_DEVICE_DATA(INTEL, VSEC_DG1, &dg1_info) },
|
||||
|
|
@ -776,6 +777,7 @@ static const struct pci_device_id intel_vsec_pci_ids[] = {
|
|||
{ PCI_DEVICE_DATA(INTEL, VSEC_TGL, &tgl_info) },
|
||||
{ PCI_DEVICE_DATA(INTEL, VSEC_LNL_M, &lnl_info) },
|
||||
{ PCI_DEVICE_DATA(INTEL, VSEC_PTL, &mtl_info) },
|
||||
{ PCI_DEVICE_DATA(INTEL, VSEC_WCL, &mtl_info) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, intel_vsec_pci_ids);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include <linux/power_supply.h>
|
||||
#include <linux/rfkill.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/string_choices.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/wmi.h>
|
||||
|
|
@ -62,13 +63,27 @@ enum {
|
|||
CFG_OSD_CAM_BIT = 31,
|
||||
};
|
||||
|
||||
/*
|
||||
* There are two charge modes supported by the GBMD/SBMC interface:
|
||||
* - "Rapid Charge": increase power to speed up charging
|
||||
* - "Conservation Mode": stop charging at 60-80% (depends on model)
|
||||
*
|
||||
* The interface doesn't prohibit enabling both modes at the same time.
|
||||
* However, doing so is essentially meaningless, and the manufacturer utilities
|
||||
* on Windows always make them mutually exclusive.
|
||||
*/
|
||||
|
||||
enum {
|
||||
GBMD_RAPID_CHARGE_STATE_BIT = 2,
|
||||
GBMD_CONSERVATION_STATE_BIT = 5,
|
||||
GBMD_RAPID_CHARGE_SUPPORTED_BIT = 17,
|
||||
};
|
||||
|
||||
enum {
|
||||
SBMC_CONSERVATION_ON = 3,
|
||||
SBMC_CONSERVATION_OFF = 5,
|
||||
SBMC_RAPID_CHARGE_ON = 7,
|
||||
SBMC_RAPID_CHARGE_OFF = 8,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
@ -158,6 +173,7 @@ struct ideapad_rfk_priv {
|
|||
struct ideapad_private {
|
||||
struct acpi_device *adev;
|
||||
struct mutex vpc_mutex; /* protects the VPC calls */
|
||||
struct mutex gbmd_sbmc_mutex; /* protects GBMD/SBMC calls */
|
||||
struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];
|
||||
struct ideapad_rfk_priv rfk_priv[IDEAPAD_RFKILL_DEV_NUM];
|
||||
struct platform_device *platform_device;
|
||||
|
|
@ -166,9 +182,11 @@ struct ideapad_private {
|
|||
struct ideapad_dytc_priv *dytc;
|
||||
struct dentry *debug;
|
||||
struct acpi_battery_hook battery_hook;
|
||||
const struct power_supply_ext *battery_ext;
|
||||
unsigned long cfg;
|
||||
unsigned long r_touchpad_val;
|
||||
struct {
|
||||
bool rapid_charge : 1;
|
||||
bool conservation_mode : 1;
|
||||
bool dytc : 1;
|
||||
bool fan_mode : 1;
|
||||
|
|
@ -455,37 +473,40 @@ static int debugfs_status_show(struct seq_file *s, void *data)
|
|||
struct ideapad_private *priv = s->private;
|
||||
unsigned long value;
|
||||
|
||||
guard(mutex)(&priv->vpc_mutex);
|
||||
scoped_guard(mutex, &priv->vpc_mutex) {
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &value))
|
||||
seq_printf(s, "Backlight max: %lu\n", value);
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL, &value))
|
||||
seq_printf(s, "Backlight now: %lu\n", value);
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &value))
|
||||
seq_printf(s, "BL power value: %s (%lu)\n", str_on_off(value), value);
|
||||
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &value))
|
||||
seq_printf(s, "Backlight max: %lu\n", value);
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL, &value))
|
||||
seq_printf(s, "Backlight now: %lu\n", value);
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &value))
|
||||
seq_printf(s, "BL power value: %s (%lu)\n", value ? "on" : "off", value);
|
||||
seq_puts(s, "=====================\n");
|
||||
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_RF, &value))
|
||||
seq_printf(s, "Radio status: %s (%lu)\n", str_on_off(value), value);
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_WIFI, &value))
|
||||
seq_printf(s, "Wifi status: %s (%lu)\n", str_on_off(value), value);
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_BT, &value))
|
||||
seq_printf(s, "BT status: %s (%lu)\n", str_on_off(value), value);
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_3G, &value))
|
||||
seq_printf(s, "3G status: %s (%lu)\n", str_on_off(value), value);
|
||||
|
||||
seq_puts(s, "=====================\n");
|
||||
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value))
|
||||
seq_printf(s, "Touchpad status: %s (%lu)\n", str_on_off(value), value);
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &value))
|
||||
seq_printf(s, "Camera status: %s (%lu)\n", str_on_off(value), value);
|
||||
}
|
||||
|
||||
seq_puts(s, "=====================\n");
|
||||
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_RF, &value))
|
||||
seq_printf(s, "Radio status: %s (%lu)\n", value ? "on" : "off", value);
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_WIFI, &value))
|
||||
seq_printf(s, "Wifi status: %s (%lu)\n", value ? "on" : "off", value);
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_BT, &value))
|
||||
seq_printf(s, "BT status: %s (%lu)\n", value ? "on" : "off", value);
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_3G, &value))
|
||||
seq_printf(s, "3G status: %s (%lu)\n", value ? "on" : "off", value);
|
||||
scoped_guard(mutex, &priv->gbmd_sbmc_mutex) {
|
||||
if (!eval_gbmd(priv->adev->handle, &value))
|
||||
seq_printf(s, "GBMD: %#010lx\n", value);
|
||||
}
|
||||
|
||||
seq_puts(s, "=====================\n");
|
||||
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value))
|
||||
seq_printf(s, "Touchpad status: %s (%lu)\n", value ? "on" : "off", value);
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &value))
|
||||
seq_printf(s, "Camera status: %s (%lu)\n", value ? "on" : "off", value);
|
||||
|
||||
seq_puts(s, "=====================\n");
|
||||
|
||||
if (!eval_gbmd(priv->adev->handle, &value))
|
||||
seq_printf(s, "GBMD: %#010lx\n", value);
|
||||
if (!eval_hals(priv->adev->handle, &value))
|
||||
seq_printf(s, "HALS: %#010lx\n", value);
|
||||
|
||||
|
|
@ -622,10 +643,16 @@ static ssize_t conservation_mode_show(struct device *dev,
|
|||
|
||||
show_conservation_mode_deprecation_warning(dev);
|
||||
|
||||
err = eval_gbmd(priv->adev->handle, &result);
|
||||
if (err)
|
||||
return err;
|
||||
scoped_guard(mutex, &priv->gbmd_sbmc_mutex) {
|
||||
err = eval_gbmd(priv->adev->handle, &result);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* For backward compatibility, ignore Rapid Charge while reporting the
|
||||
* state of Conservation Mode.
|
||||
*/
|
||||
return sysfs_emit(buf, "%d\n", !!test_bit(GBMD_CONSERVATION_STATE_BIT, &result));
|
||||
}
|
||||
|
||||
|
|
@ -643,6 +670,18 @@ static ssize_t conservation_mode_store(struct device *dev,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
guard(mutex)(&priv->gbmd_sbmc_mutex);
|
||||
|
||||
/*
|
||||
* Prevent mutually exclusive modes from being set at the same time,
|
||||
* but do not disable Rapid Charge while disabling Conservation Mode.
|
||||
*/
|
||||
if (priv->features.rapid_charge && state) {
|
||||
err = exec_sbmc(priv->adev->handle, SBMC_RAPID_CHARGE_OFF);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = exec_sbmc(priv->adev->handle, state ? SBMC_CONSERVATION_ON : SBMC_CONSERVATION_OFF);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
@ -2007,15 +2046,39 @@ static int ideapad_psy_ext_set_prop(struct power_supply *psy,
|
|||
const union power_supply_propval *val)
|
||||
{
|
||||
struct ideapad_private *priv = ext_data;
|
||||
unsigned long op1, op2;
|
||||
int err;
|
||||
|
||||
switch (val->intval) {
|
||||
case POWER_SUPPLY_CHARGE_TYPE_FAST:
|
||||
if (WARN_ON(!priv->features.rapid_charge))
|
||||
return -EINVAL;
|
||||
|
||||
op1 = SBMC_CONSERVATION_OFF;
|
||||
op2 = SBMC_RAPID_CHARGE_ON;
|
||||
break;
|
||||
case POWER_SUPPLY_CHARGE_TYPE_LONGLIFE:
|
||||
return exec_sbmc(priv->adev->handle, SBMC_CONSERVATION_ON);
|
||||
op1 = SBMC_RAPID_CHARGE_OFF;
|
||||
op2 = SBMC_CONSERVATION_ON;
|
||||
break;
|
||||
case POWER_SUPPLY_CHARGE_TYPE_STANDARD:
|
||||
return exec_sbmc(priv->adev->handle, SBMC_CONSERVATION_OFF);
|
||||
op1 = SBMC_RAPID_CHARGE_OFF;
|
||||
op2 = SBMC_CONSERVATION_OFF;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
guard(mutex)(&priv->gbmd_sbmc_mutex);
|
||||
|
||||
/* If !rapid_charge, op1 must be SBMC_RAPID_CHARGE_OFF. Skip it. */
|
||||
if (priv->features.rapid_charge) {
|
||||
err = exec_sbmc(priv->adev->handle, op1);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return exec_sbmc(priv->adev->handle, op2);
|
||||
}
|
||||
|
||||
static int ideapad_psy_ext_get_prop(struct power_supply *psy,
|
||||
|
|
@ -2025,14 +2088,29 @@ static int ideapad_psy_ext_get_prop(struct power_supply *psy,
|
|||
union power_supply_propval *val)
|
||||
{
|
||||
struct ideapad_private *priv = ext_data;
|
||||
bool is_rapid_charge, is_conservation;
|
||||
unsigned long result;
|
||||
int err;
|
||||
|
||||
err = eval_gbmd(priv->adev->handle, &result);
|
||||
if (err)
|
||||
return err;
|
||||
scoped_guard(mutex, &priv->gbmd_sbmc_mutex) {
|
||||
err = eval_gbmd(priv->adev->handle, &result);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (test_bit(GBMD_CONSERVATION_STATE_BIT, &result))
|
||||
is_rapid_charge = (priv->features.rapid_charge &&
|
||||
test_bit(GBMD_RAPID_CHARGE_STATE_BIT, &result));
|
||||
is_conservation = test_bit(GBMD_CONSERVATION_STATE_BIT, &result);
|
||||
|
||||
if (unlikely(is_rapid_charge && is_conservation)) {
|
||||
dev_err(&priv->platform_device->dev,
|
||||
"unexpected charge_types: both [Fast] and [Long_Life] are enabled\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (is_rapid_charge)
|
||||
val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
|
||||
else if (is_conservation)
|
||||
val->intval = POWER_SUPPLY_CHARGE_TYPE_LONGLIFE;
|
||||
else
|
||||
val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
|
||||
|
|
@ -2052,29 +2130,42 @@ static const enum power_supply_property ideapad_power_supply_props[] = {
|
|||
POWER_SUPPLY_PROP_CHARGE_TYPES,
|
||||
};
|
||||
|
||||
static const struct power_supply_ext ideapad_battery_ext = {
|
||||
.name = "ideapad_laptop",
|
||||
.properties = ideapad_power_supply_props,
|
||||
.num_properties = ARRAY_SIZE(ideapad_power_supply_props),
|
||||
.charge_types = (BIT(POWER_SUPPLY_CHARGE_TYPE_STANDARD) |
|
||||
BIT(POWER_SUPPLY_CHARGE_TYPE_LONGLIFE)),
|
||||
.get_property = ideapad_psy_ext_get_prop,
|
||||
.set_property = ideapad_psy_ext_set_prop,
|
||||
.property_is_writeable = ideapad_psy_prop_is_writeable,
|
||||
};
|
||||
#define DEFINE_IDEAPAD_POWER_SUPPLY_EXTENSION(_name, _charge_types) \
|
||||
static const struct power_supply_ext _name = { \
|
||||
.name = "ideapad_laptop", \
|
||||
.properties = ideapad_power_supply_props, \
|
||||
.num_properties = ARRAY_SIZE(ideapad_power_supply_props), \
|
||||
.charge_types = _charge_types, \
|
||||
.get_property = ideapad_psy_ext_get_prop, \
|
||||
.set_property = ideapad_psy_ext_set_prop, \
|
||||
.property_is_writeable = ideapad_psy_prop_is_writeable, \
|
||||
}
|
||||
|
||||
DEFINE_IDEAPAD_POWER_SUPPLY_EXTENSION(ideapad_battery_ext_v1,
|
||||
(BIT(POWER_SUPPLY_CHARGE_TYPE_STANDARD) |
|
||||
BIT(POWER_SUPPLY_CHARGE_TYPE_LONGLIFE))
|
||||
);
|
||||
|
||||
DEFINE_IDEAPAD_POWER_SUPPLY_EXTENSION(ideapad_battery_ext_v2,
|
||||
(BIT(POWER_SUPPLY_CHARGE_TYPE_STANDARD) |
|
||||
BIT(POWER_SUPPLY_CHARGE_TYPE_FAST) |
|
||||
BIT(POWER_SUPPLY_CHARGE_TYPE_LONGLIFE))
|
||||
);
|
||||
|
||||
static int ideapad_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
|
||||
{
|
||||
struct ideapad_private *priv = container_of(hook, struct ideapad_private, battery_hook);
|
||||
|
||||
return power_supply_register_extension(battery, &ideapad_battery_ext,
|
||||
return power_supply_register_extension(battery, priv->battery_ext,
|
||||
&priv->platform_device->dev, priv);
|
||||
}
|
||||
|
||||
static int ideapad_battery_remove(struct power_supply *battery,
|
||||
struct acpi_battery_hook *hook)
|
||||
{
|
||||
power_supply_unregister_extension(battery, &ideapad_battery_ext);
|
||||
struct ideapad_private *priv = container_of(hook, struct ideapad_private, battery_hook);
|
||||
|
||||
power_supply_unregister_extension(battery, priv->battery_ext);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2099,14 +2190,25 @@ static int ideapad_check_features(struct ideapad_private *priv)
|
|||
priv->features.fan_mode = true;
|
||||
|
||||
if (acpi_has_method(handle, "GBMD") && acpi_has_method(handle, "SBMC")) {
|
||||
priv->features.conservation_mode = true;
|
||||
priv->battery_hook.add_battery = ideapad_battery_add;
|
||||
priv->battery_hook.remove_battery = ideapad_battery_remove;
|
||||
priv->battery_hook.name = "Ideapad Battery Extension";
|
||||
/* Not acquiring gbmd_sbmc_mutex as race condition is impossible on init */
|
||||
if (!eval_gbmd(handle, &val)) {
|
||||
priv->features.conservation_mode = true;
|
||||
priv->features.rapid_charge = test_bit(GBMD_RAPID_CHARGE_SUPPORTED_BIT,
|
||||
&val);
|
||||
|
||||
err = devm_battery_hook_register(&priv->platform_device->dev, &priv->battery_hook);
|
||||
if (err)
|
||||
return err;
|
||||
priv->battery_ext = priv->features.rapid_charge
|
||||
? &ideapad_battery_ext_v2
|
||||
: &ideapad_battery_ext_v1;
|
||||
|
||||
priv->battery_hook.add_battery = ideapad_battery_add;
|
||||
priv->battery_hook.remove_battery = ideapad_battery_remove;
|
||||
priv->battery_hook.name = "Ideapad Battery Extension";
|
||||
|
||||
err = devm_battery_hook_register(&priv->platform_device->dev,
|
||||
&priv->battery_hook);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (acpi_has_method(handle, "DYTC"))
|
||||
|
|
@ -2292,6 +2394,10 @@ static int ideapad_acpi_add(struct platform_device *pdev)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
err = devm_mutex_init(&pdev->dev, &priv->gbmd_sbmc_mutex);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = ideapad_check_features(priv);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -171,14 +171,10 @@ static int lwmi_gz_profile_get(struct device *dev,
|
|||
*profile = PLATFORM_PROFILE_BALANCED;
|
||||
break;
|
||||
case LWMI_GZ_THERMAL_MODE_PERFORMANCE:
|
||||
if (priv->extreme_supported) {
|
||||
*profile = PLATFORM_PROFILE_BALANCED_PERFORMANCE;
|
||||
break;
|
||||
}
|
||||
*profile = PLATFORM_PROFILE_PERFORMANCE;
|
||||
break;
|
||||
case LWMI_GZ_THERMAL_MODE_EXTREME:
|
||||
*profile = PLATFORM_PROFILE_PERFORMANCE;
|
||||
*profile = PLATFORM_PROFILE_MAX_POWER;
|
||||
break;
|
||||
case LWMI_GZ_THERMAL_MODE_CUSTOM:
|
||||
*profile = PLATFORM_PROFILE_CUSTOM;
|
||||
|
|
@ -218,15 +214,11 @@ static int lwmi_gz_profile_set(struct device *dev,
|
|||
case PLATFORM_PROFILE_BALANCED:
|
||||
mode = LWMI_GZ_THERMAL_MODE_BALANCED;
|
||||
break;
|
||||
case PLATFORM_PROFILE_BALANCED_PERFORMANCE:
|
||||
case PLATFORM_PROFILE_PERFORMANCE:
|
||||
mode = LWMI_GZ_THERMAL_MODE_PERFORMANCE;
|
||||
break;
|
||||
case PLATFORM_PROFILE_PERFORMANCE:
|
||||
if (priv->extreme_supported) {
|
||||
mode = LWMI_GZ_THERMAL_MODE_EXTREME;
|
||||
break;
|
||||
}
|
||||
mode = LWMI_GZ_THERMAL_MODE_PERFORMANCE;
|
||||
case PLATFORM_PROFILE_MAX_POWER:
|
||||
mode = LWMI_GZ_THERMAL_MODE_EXTREME;
|
||||
break;
|
||||
case PLATFORM_PROFILE_CUSTOM:
|
||||
mode = LWMI_GZ_THERMAL_MODE_CUSTOM;
|
||||
|
|
@ -274,8 +266,23 @@ static const struct dmi_system_id fwbug_list[] = {
|
|||
},
|
||||
.driver_data = &quirk_no_extreme_bug,
|
||||
},
|
||||
{
|
||||
.ident = "Legion Go 8ASP2",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Legion Go 8ASP2"),
|
||||
},
|
||||
.driver_data = &quirk_no_extreme_bug,
|
||||
},
|
||||
{
|
||||
.ident = "Legion Go 8AHP2",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Legion Go 8AHP2"),
|
||||
},
|
||||
.driver_data = &quirk_no_extreme_bug,
|
||||
},
|
||||
{},
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -338,7 +345,7 @@ static int lwmi_gz_platform_profile_probe(void *drvdata, unsigned long *choices)
|
|||
|
||||
priv->extreme_supported = lwmi_gz_extreme_supported(profile_support_ver);
|
||||
if (priv->extreme_supported)
|
||||
set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, choices);
|
||||
set_bit(PLATFORM_PROFILE_MAX_POWER, choices);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/leds.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/string_choices.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <acpi/battery.h>
|
||||
|
|
@ -42,6 +43,7 @@ MODULE_PARM_DESC(fw_debug, "Enable printing of firmware debug messages");
|
|||
#define LG_ADDRESS_SPACE_ID 0x8F
|
||||
|
||||
#define LG_ADDRESS_SPACE_DEBUG_FLAG_ADR 0x00
|
||||
#define LG_ADDRESS_SPACE_HD_AUDIO_POWER_ADDR 0x01
|
||||
#define LG_ADDRESS_SPACE_FAN_MODE_ADR 0x03
|
||||
|
||||
#define LG_ADDRESS_SPACE_DTTM_FLAG_ADR 0x20
|
||||
|
|
@ -668,6 +670,15 @@ static acpi_status lg_laptop_address_space_write(struct device *dev, acpi_physic
|
|||
byte = value & 0xFF;
|
||||
|
||||
switch (address) {
|
||||
case LG_ADDRESS_SPACE_HD_AUDIO_POWER_ADDR:
|
||||
/*
|
||||
* The HD audio power field is not affected by the DTTM flag,
|
||||
* so we have to manually check fw_debug.
|
||||
*/
|
||||
if (fw_debug)
|
||||
dev_dbg(dev, "HD audio power %s\n", str_enabled_disabled(byte));
|
||||
|
||||
return AE_OK;
|
||||
case LG_ADDRESS_SPACE_FAN_MODE_ADR:
|
||||
/*
|
||||
* The fan mode field is not affected by the DTTM flag, so we
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Platform driver for OneXPlayer and AOKZOE devices. For the time being,
|
||||
* it also exposes fan controls for AYANEO, and OrangePi Handhelds via
|
||||
* hwmon sysfs.
|
||||
* Platform driver for OneXPlayer and AOKZOE devices.
|
||||
*
|
||||
* Fan control is provided via pwm interface in the range [0-255].
|
||||
* Old AMD boards use [0-100] as range in the EC, the written value is
|
||||
|
|
@ -43,14 +41,6 @@ static bool unlock_global_acpi_lock(void)
|
|||
|
||||
enum oxp_board {
|
||||
aok_zoe_a1 = 1,
|
||||
aya_neo_2,
|
||||
aya_neo_air,
|
||||
aya_neo_air_1s,
|
||||
aya_neo_air_plus_mendo,
|
||||
aya_neo_air_pro,
|
||||
aya_neo_flip,
|
||||
aya_neo_geek,
|
||||
aya_neo_kun,
|
||||
orange_pi_neo,
|
||||
oxp_2,
|
||||
oxp_fly,
|
||||
|
|
@ -131,62 +121,6 @@ static const struct dmi_system_id dmi_table[] = {
|
|||
},
|
||||
.driver_data = (void *)oxp_fly,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "AYANEO 2"),
|
||||
},
|
||||
.driver_data = (void *)aya_neo_2,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
|
||||
},
|
||||
.driver_data = (void *)aya_neo_air,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR 1S"),
|
||||
},
|
||||
.driver_data = (void *)aya_neo_air_1s,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "AB05-Mendocino"),
|
||||
},
|
||||
.driver_data = (void *)aya_neo_air_plus_mendo,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
|
||||
},
|
||||
.driver_data = (void *)aya_neo_air_pro,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "FLIP"),
|
||||
},
|
||||
.driver_data = (void *)aya_neo_flip,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "GEEK"),
|
||||
},
|
||||
.driver_data = (void *)aya_neo_geek,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "KUN"),
|
||||
},
|
||||
.driver_data = (void *)aya_neo_kun,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "OrangePi"),
|
||||
|
|
@ -672,13 +606,6 @@ static int oxp_pwm_enable(void)
|
|||
case orange_pi_neo:
|
||||
return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL);
|
||||
case aok_zoe_a1:
|
||||
case aya_neo_2:
|
||||
case aya_neo_air:
|
||||
case aya_neo_air_plus_mendo:
|
||||
case aya_neo_air_pro:
|
||||
case aya_neo_flip:
|
||||
case aya_neo_geek:
|
||||
case aya_neo_kun:
|
||||
case oxp_2:
|
||||
case oxp_fly:
|
||||
case oxp_mini_amd:
|
||||
|
|
@ -699,14 +626,6 @@ static int oxp_pwm_disable(void)
|
|||
case orange_pi_neo:
|
||||
return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO);
|
||||
case aok_zoe_a1:
|
||||
case aya_neo_2:
|
||||
case aya_neo_air:
|
||||
case aya_neo_air_1s:
|
||||
case aya_neo_air_plus_mendo:
|
||||
case aya_neo_air_pro:
|
||||
case aya_neo_flip:
|
||||
case aya_neo_geek:
|
||||
case aya_neo_kun:
|
||||
case oxp_2:
|
||||
case oxp_fly:
|
||||
case oxp_mini_amd:
|
||||
|
|
@ -727,14 +646,6 @@ static int oxp_pwm_read(long *val)
|
|||
case orange_pi_neo:
|
||||
return read_from_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, 1, val);
|
||||
case aok_zoe_a1:
|
||||
case aya_neo_2:
|
||||
case aya_neo_air:
|
||||
case aya_neo_air_1s:
|
||||
case aya_neo_air_plus_mendo:
|
||||
case aya_neo_air_pro:
|
||||
case aya_neo_flip:
|
||||
case aya_neo_geek:
|
||||
case aya_neo_kun:
|
||||
case oxp_2:
|
||||
case oxp_fly:
|
||||
case oxp_mini_amd:
|
||||
|
|
@ -774,14 +685,6 @@ static int oxp_pwm_fan_speed(long *val)
|
|||
case oxp_g1_i:
|
||||
return read_from_ec(OXP_2_SENSOR_FAN_REG, 2, val);
|
||||
case aok_zoe_a1:
|
||||
case aya_neo_2:
|
||||
case aya_neo_air:
|
||||
case aya_neo_air_1s:
|
||||
case aya_neo_air_plus_mendo:
|
||||
case aya_neo_air_pro:
|
||||
case aya_neo_flip:
|
||||
case aya_neo_geek:
|
||||
case aya_neo_kun:
|
||||
case oxp_fly:
|
||||
case oxp_mini_amd:
|
||||
case oxp_mini_amd_a07:
|
||||
|
|
@ -810,14 +713,6 @@ static int oxp_pwm_input_write(long val)
|
|||
/* scale to range [0-184] */
|
||||
val = (val * 184) / 255;
|
||||
return write_to_ec(OXP_SENSOR_PWM_REG, val);
|
||||
case aya_neo_2:
|
||||
case aya_neo_air:
|
||||
case aya_neo_air_1s:
|
||||
case aya_neo_air_plus_mendo:
|
||||
case aya_neo_air_pro:
|
||||
case aya_neo_flip:
|
||||
case aya_neo_geek:
|
||||
case aya_neo_kun:
|
||||
case oxp_mini_amd:
|
||||
case oxp_mini_amd_a07:
|
||||
/* scale to range [0-100] */
|
||||
|
|
@ -854,14 +749,6 @@ static int oxp_pwm_input_read(long *val)
|
|||
/* scale from range [0-184] */
|
||||
*val = (*val * 255) / 184;
|
||||
break;
|
||||
case aya_neo_2:
|
||||
case aya_neo_air:
|
||||
case aya_neo_air_1s:
|
||||
case aya_neo_air_plus_mendo:
|
||||
case aya_neo_air_pro:
|
||||
case aya_neo_flip:
|
||||
case aya_neo_geek:
|
||||
case aya_neo_kun:
|
||||
case oxp_mini_amd:
|
||||
case oxp_mini_amd_a07:
|
||||
ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#define IRQ_RESOURCE_GPIO 1
|
||||
#define IRQ_RESOURCE_APIC 2
|
||||
#define IRQ_RESOURCE_AUTO 3
|
||||
#define IRQ_RESOURCE_OPT BIT(2)
|
||||
|
||||
enum smi_bus_type {
|
||||
SMI_I2C,
|
||||
|
|
@ -64,6 +65,10 @@ static int smi_get_irq(struct platform_device *pdev, struct acpi_device *adev,
|
|||
dev_dbg(&pdev->dev, "Using platform irq\n");
|
||||
break;
|
||||
}
|
||||
if (inst->flags & IRQ_RESOURCE_OPT) {
|
||||
dev_dbg(&pdev->dev, "No irq\n");
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case IRQ_RESOURCE_GPIO:
|
||||
ret = acpi_dev_gpio_irq_get(adev, inst->irq_idx);
|
||||
|
|
@ -386,10 +391,10 @@ static const struct smi_node cs35l57_hda = {
|
|||
|
||||
static const struct smi_node tas2781_hda = {
|
||||
.instances = {
|
||||
{ "tas2781-hda", IRQ_RESOURCE_AUTO, 0 },
|
||||
{ "tas2781-hda", IRQ_RESOURCE_AUTO, 0 },
|
||||
{ "tas2781-hda", IRQ_RESOURCE_AUTO, 0 },
|
||||
{ "tas2781-hda", IRQ_RESOURCE_AUTO, 0 },
|
||||
{ "tas2781-hda", IRQ_RESOURCE_AUTO | IRQ_RESOURCE_OPT, 0 },
|
||||
{ "tas2781-hda", IRQ_RESOURCE_AUTO | IRQ_RESOURCE_OPT, 0 },
|
||||
{ "tas2781-hda", IRQ_RESOURCE_AUTO | IRQ_RESOURCE_OPT, 0 },
|
||||
{ "tas2781-hda", IRQ_RESOURCE_AUTO | IRQ_RESOURCE_OPT, 0 },
|
||||
{}
|
||||
},
|
||||
.bus_type = SMI_AUTO_DETECT,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Uniwill X86 Platform Specific Drivers
|
||||
#
|
||||
|
||||
menuconfig X86_PLATFORM_DRIVERS_UNIWILL
|
||||
bool "Uniwill X86 Platform Specific Device Drivers"
|
||||
depends on X86_PLATFORM_DEVICES
|
||||
help
|
||||
Say Y here to see options for device drivers for various
|
||||
Uniwill x86 platforms, including many OEM laptops originally
|
||||
manufactured by Uniwill.
|
||||
This option alone does not add any kernel code.
|
||||
|
||||
If you say N, all options in this submenu will be skipped and disabled.
|
||||
|
||||
if X86_PLATFORM_DRIVERS_UNIWILL
|
||||
|
||||
config UNIWILL_LAPTOP
|
||||
tristate "Uniwill Laptop Extras"
|
||||
default m
|
||||
depends on ACPI
|
||||
depends on ACPI_WMI
|
||||
depends on ACPI_BATTERY
|
||||
depends on HWMON
|
||||
depends on INPUT
|
||||
depends on LEDS_CLASS_MULTICOLOR
|
||||
depends on DMI
|
||||
select REGMAP
|
||||
select INPUT_SPARSEKMAP
|
||||
help
|
||||
This driver adds support for various extra features found on Uniwill laptops,
|
||||
like the lightbar, hwmon sensors and hotkeys. It also supports many OEM laptops
|
||||
originally manufactured by Uniwill.
|
||||
|
||||
If you have such a laptop, say Y or M here.
|
||||
|
||||
endif
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Makefile for linux/drivers/platform/x86/uniwill
|
||||
# Uniwill X86 Platform Specific Drivers
|
||||
#
|
||||
|
||||
obj-$(CONFIG_UNIWILL_LAPTOP) += uniwill-laptop.o
|
||||
uniwill-laptop-y := uniwill-acpi.o uniwill-wmi.o
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,92 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Linux hotkey driver for Uniwill notebooks.
|
||||
*
|
||||
* Special thanks go to Pőcze Barnabás, Christoffer Sandberg and Werner Sembach
|
||||
* for supporting the development of this driver either through prior work or
|
||||
* by answering questions regarding the underlying WMI interface.
|
||||
*
|
||||
* Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de>
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/wmi.h>
|
||||
|
||||
#include "uniwill-wmi.h"
|
||||
|
||||
#define DRIVER_NAME "uniwill-wmi"
|
||||
#define UNIWILL_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000"
|
||||
|
||||
static BLOCKING_NOTIFIER_HEAD(uniwill_wmi_chain_head);
|
||||
|
||||
static void devm_uniwill_wmi_unregister_notifier(void *data)
|
||||
{
|
||||
struct notifier_block *nb = data;
|
||||
|
||||
blocking_notifier_chain_unregister(&uniwill_wmi_chain_head, nb);
|
||||
}
|
||||
|
||||
int devm_uniwill_wmi_register_notifier(struct device *dev, struct notifier_block *nb)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = blocking_notifier_chain_register(&uniwill_wmi_chain_head, nb);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return devm_add_action_or_reset(dev, devm_uniwill_wmi_unregister_notifier, nb);
|
||||
}
|
||||
|
||||
static void uniwill_wmi_notify(struct wmi_device *wdev, union acpi_object *obj)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
if (obj->type != ACPI_TYPE_INTEGER)
|
||||
return;
|
||||
|
||||
value = obj->integer.value;
|
||||
|
||||
dev_dbg(&wdev->dev, "Received WMI event %u\n", value);
|
||||
|
||||
blocking_notifier_call_chain(&uniwill_wmi_chain_head, value, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* We cannot fully trust this GUID since Uniwill just copied the WMI GUID
|
||||
* from the Windows driver example, and others probably did the same.
|
||||
*
|
||||
* Because of this we cannot use this WMI GUID for autoloading. Instead the
|
||||
* associated driver will be registered manually after matching a DMI table.
|
||||
*/
|
||||
static const struct wmi_device_id uniwill_wmi_id_table[] = {
|
||||
{ UNIWILL_EVENT_GUID, NULL },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct wmi_driver uniwill_wmi_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
.id_table = uniwill_wmi_id_table,
|
||||
.notify = uniwill_wmi_notify,
|
||||
.no_singleton = true,
|
||||
};
|
||||
|
||||
int __init uniwill_wmi_register_driver(void)
|
||||
{
|
||||
return wmi_driver_register(&uniwill_wmi_driver);
|
||||
}
|
||||
|
||||
void __exit uniwill_wmi_unregister_driver(void)
|
||||
{
|
||||
wmi_driver_unregister(&uniwill_wmi_driver);
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Linux hotkey driver for Uniwill notebooks.
|
||||
*
|
||||
* Copyright (C) 2025 Armin Wolf <W_Armin@gmx.de>
|
||||
*/
|
||||
|
||||
#ifndef UNIWILL_WMI_H
|
||||
#define UNIWILL_WMI_H
|
||||
|
||||
#include <linux/init.h>
|
||||
|
||||
#define UNIWILL_OSD_CAPSLOCK 0x01
|
||||
#define UNIWILL_OSD_NUMLOCK 0x02
|
||||
#define UNIWILL_OSD_SCROLLLOCK 0x03
|
||||
|
||||
#define UNIWILL_OSD_TOUCHPAD_ON 0x04
|
||||
#define UNIWILL_OSD_TOUCHPAD_OFF 0x05
|
||||
|
||||
#define UNIWILL_OSD_SILENT_MODE_ON 0x06
|
||||
#define UNIWILL_OSD_SILENT_MODE_OFF 0x07
|
||||
|
||||
#define UNIWILL_OSD_WLAN_ON 0x08
|
||||
#define UNIWILL_OSD_WLAN_OFF 0x09
|
||||
|
||||
#define UNIWILL_OSD_WIMAX_ON 0x0A
|
||||
#define UNIWILL_OSD_WIMAX_OFF 0x0B
|
||||
|
||||
#define UNIWILL_OSD_BLUETOOTH_ON 0x0C
|
||||
#define UNIWILL_OSD_BLUETOOTH_OFF 0x0D
|
||||
|
||||
#define UNIWILL_OSD_RF_ON 0x0E
|
||||
#define UNIWILL_OSD_RF_OFF 0x0F
|
||||
|
||||
#define UNIWILL_OSD_3G_ON 0x10
|
||||
#define UNIWILL_OSD_3G_OFF 0x11
|
||||
|
||||
#define UNIWILL_OSD_WEBCAM_ON 0x12
|
||||
#define UNIWILL_OSD_WEBCAM_OFF 0x13
|
||||
|
||||
#define UNIWILL_OSD_BRIGHTNESSUP 0x14
|
||||
#define UNIWILL_OSD_BRIGHTNESSDOWN 0x15
|
||||
|
||||
#define UNIWILL_OSD_RADIOON 0x1A
|
||||
#define UNIWILL_OSD_RADIOOFF 0x1B
|
||||
|
||||
#define UNIWILL_OSD_POWERSAVE_ON 0x31
|
||||
#define UNIWILL_OSD_POWERSAVE_OFF 0x32
|
||||
|
||||
#define UNIWILL_OSD_MENU 0x34
|
||||
|
||||
#define UNIWILL_OSD_MUTE 0x35
|
||||
#define UNIWILL_OSD_VOLUMEDOWN 0x36
|
||||
#define UNIWILL_OSD_VOLUMEUP 0x37
|
||||
|
||||
#define UNIWILL_OSD_MENU_2 0x38
|
||||
|
||||
#define UNIWILL_OSD_LIGHTBAR_ON 0x39
|
||||
#define UNIWILL_OSD_LIGHTBAR_OFF 0x3A
|
||||
|
||||
#define UNIWILL_OSD_KB_LED_LEVEL0 0x3B
|
||||
#define UNIWILL_OSD_KB_LED_LEVEL1 0x3C
|
||||
#define UNIWILL_OSD_KB_LED_LEVEL2 0x3D
|
||||
#define UNIWILL_OSD_KB_LED_LEVEL3 0x3E
|
||||
#define UNIWILL_OSD_KB_LED_LEVEL4 0x3F
|
||||
|
||||
#define UNIWILL_OSD_SUPER_KEY_LOCK_ENABLE 0x40
|
||||
#define UNIWILL_OSD_SUPER_KEY_LOCK_DISABLE 0x41
|
||||
|
||||
#define UNIWILL_OSD_MENU_JP 0x42
|
||||
|
||||
#define UNIWILL_OSD_CAMERA_ON 0x90
|
||||
#define UNIWILL_OSD_CAMERA_OFF 0x91
|
||||
|
||||
#define UNIWILL_OSD_RFKILL 0xA4
|
||||
|
||||
#define UNIWILL_OSD_SUPER_KEY_LOCK_CHANGED 0xA5
|
||||
|
||||
#define UNIWILL_OSD_LIGHTBAR_STATE_CHANGED 0xA6
|
||||
|
||||
#define UNIWILL_OSD_FAN_BOOST_STATE_CHANGED 0xA7
|
||||
|
||||
#define UNIWILL_OSD_LCD_SW 0xA9
|
||||
|
||||
#define UNIWILL_OSD_FAN_OVERTEMP 0xAA
|
||||
|
||||
#define UNIWILL_OSD_DC_ADAPTER_CHANGED 0xAB
|
||||
|
||||
#define UNIWILL_OSD_BAT_HP_OFF 0xAC
|
||||
|
||||
#define UNIWILL_OSD_FAN_DOWN_TEMP 0xAD
|
||||
|
||||
#define UNIWILL_OSD_BATTERY_ALERT 0xAE
|
||||
|
||||
#define UNIWILL_OSD_TIMAP_HAIERLB_SW 0xAF
|
||||
|
||||
#define UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE 0xB0
|
||||
|
||||
#define UNIWILL_OSD_KBDILLUMDOWN 0xB1
|
||||
#define UNIWILL_OSD_KBDILLUMUP 0xB2
|
||||
|
||||
#define UNIWILL_OSD_BACKLIGHT_LEVEL_CHANGE 0xB3
|
||||
#define UNIWILL_OSD_BACKLIGHT_POWER_CHANGE 0xB4
|
||||
|
||||
#define UNIWILL_OSD_MIC_MUTE 0xB7
|
||||
|
||||
#define UNIWILL_OSD_FN_LOCK 0xB8
|
||||
#define UNIWILL_OSD_KBDILLUMTOGGLE 0xB9
|
||||
|
||||
#define UNIWILL_OSD_BAT_CHARGE_FULL_24_H 0xBE
|
||||
|
||||
#define UNIWILL_OSD_BAT_ERM_UPDATE 0xBF
|
||||
|
||||
#define UNIWILL_OSD_BENCHMARK_MODE_TOGGLE 0xC0
|
||||
|
||||
#define UNIWILL_OSD_WEBCAM_TOGGLE 0xCF
|
||||
|
||||
#define UNIWILL_OSD_KBD_BACKLIGHT_CHANGED 0xF0
|
||||
|
||||
struct device;
|
||||
struct notifier_block;
|
||||
|
||||
int devm_uniwill_wmi_register_notifier(struct device *dev, struct notifier_block *nb);
|
||||
|
||||
int __init uniwill_wmi_register_driver(void);
|
||||
|
||||
void __exit uniwill_wmi_unregister_driver(void);
|
||||
|
||||
#endif /* UNIWILL_WMI_H */
|
||||
|
|
@ -543,7 +543,7 @@ static int __init lenovo_yoga_tab2_830_1050_init_codec(void)
|
|||
|
||||
ret = device_add_software_node(codec_dev, &lenovo_yoga_tab2_830_1050_wm5102);
|
||||
if (ret) {
|
||||
ret = dev_err_probe(codec_dev, ret, "adding software node\n");
|
||||
dev_err_probe(codec_dev, ret, "adding software node\n");
|
||||
goto err_put_pinctrl;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ static void atla10_ec_external_power_changed(struct power_supply *psy)
|
|||
struct atla10_ec_data *data = power_supply_get_drvdata(psy);
|
||||
|
||||
/* After charger plug in/out wait 0.5s for things to stabilize */
|
||||
mod_delayed_work(system_wq, &data->work, HZ / 2);
|
||||
mod_delayed_work(system_percpu_wq, &data->work, HZ / 2);
|
||||
}
|
||||
|
||||
static const enum power_supply_property atla10_ec_psy_props[] = {
|
||||
|
|
|
|||
|
|
@ -67,19 +67,22 @@ int utf8_to_utf32(const u8 *s, int inlen, unicode_t *pu)
|
|||
l &= t->lmask;
|
||||
if (l < t->lval || l > UNICODE_MAX ||
|
||||
(l & SURROGATE_MASK) == SURROGATE_PAIR)
|
||||
return -1;
|
||||
return -EILSEQ;
|
||||
|
||||
*pu = (unicode_t) l;
|
||||
return nc;
|
||||
}
|
||||
if (inlen <= nc)
|
||||
return -1;
|
||||
return -EOVERFLOW;
|
||||
|
||||
s++;
|
||||
c = (*s ^ 0x80) & 0xFF;
|
||||
if (c & 0xC0)
|
||||
return -1;
|
||||
return -EILSEQ;
|
||||
|
||||
l = (l << 6) | c;
|
||||
}
|
||||
return -1;
|
||||
return -EILSEQ;
|
||||
}
|
||||
EXPORT_SYMBOL(utf8_to_utf32);
|
||||
|
||||
|
|
@ -94,7 +97,7 @@ int utf32_to_utf8(unicode_t u, u8 *s, int maxout)
|
|||
|
||||
l = u;
|
||||
if (l > UNICODE_MAX || (l & SURROGATE_MASK) == SURROGATE_PAIR)
|
||||
return -1;
|
||||
return -EILSEQ;
|
||||
|
||||
nc = 0;
|
||||
for (t = utf8_table; t->cmask && maxout; t++, maxout--) {
|
||||
|
|
@ -110,7 +113,7 @@ int utf32_to_utf8(unicode_t u, u8 *s, int maxout)
|
|||
return nc;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
EXPORT_SYMBOL(utf32_to_utf8);
|
||||
|
||||
|
|
@ -217,8 +220,16 @@ int utf16s_to_utf8s(const wchar_t *pwcs, int inlen, enum utf16_endian endian,
|
|||
inlen--;
|
||||
}
|
||||
size = utf32_to_utf8(u, op, maxout);
|
||||
if (size == -1) {
|
||||
/* Ignore character and move on */
|
||||
if (size < 0) {
|
||||
if (size == -EILSEQ) {
|
||||
/* Ignore character and move on */
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Stop filling the buffer with data once a character
|
||||
* does not fit anymore.
|
||||
*/
|
||||
break;
|
||||
} else {
|
||||
op += size;
|
||||
maxout -= size;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __PLATFORM_DATA_X86_ASUS_WMI_LEDS_IDS_H
|
||||
#define __PLATFORM_DATA_X86_ASUS_WMI_LEDS_IDS_H
|
||||
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* To be used by both hid-asus and asus-wmi to determine which controls kbd_brightness */
|
||||
#if IS_REACHABLE(CONFIG_ASUS_WMI) || IS_REACHABLE(CONFIG_HID_ASUS)
|
||||
static const struct dmi_system_id asus_use_hid_led_dmi_ids[] = {
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Zephyrus"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Strix"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Flow"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_PRODUCT_FAMILY, "ProArt P16"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "GA403U"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "GU605M"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "RC71L"),
|
||||
},
|
||||
},
|
||||
{ },
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* __PLATFORM_DATA_X86_ASUS_WMI_LEDS_IDS_H */
|
||||
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/dmi.h>
|
||||
|
||||
#define ASUS_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66"
|
||||
#define ASUS_ACPI_UID_ASUSWMI "ASUSWMI"
|
||||
|
||||
/* WMI Methods */
|
||||
#define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */
|
||||
|
|
@ -73,12 +75,14 @@
|
|||
#define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO 0x00110019
|
||||
|
||||
/* Misc */
|
||||
#define ASUS_WMI_DEVID_PANEL_HD 0x0005001C
|
||||
#define ASUS_WMI_DEVID_PANEL_OD 0x00050019
|
||||
#define ASUS_WMI_DEVID_CAMERA 0x00060013
|
||||
#define ASUS_WMI_DEVID_LID_FLIP 0x00060062
|
||||
#define ASUS_WMI_DEVID_LID_FLIP_ROG 0x00060077
|
||||
#define ASUS_WMI_DEVID_MINI_LED_MODE 0x0005001E
|
||||
#define ASUS_WMI_DEVID_MINI_LED_MODE2 0x0005002E
|
||||
#define ASUS_WMI_DEVID_SCREEN_AUTO_BRIGHTNESS 0x0005002A
|
||||
|
||||
/* Storage */
|
||||
#define ASUS_WMI_DEVID_CARDREADER 0x00080013
|
||||
|
|
@ -103,7 +107,7 @@
|
|||
#define ASUS_WMI_DEVID_PPT_PL1_SPL 0x001200A3
|
||||
#define ASUS_WMI_DEVID_PPT_APU_SPPT 0x001200B0
|
||||
#define ASUS_WMI_DEVID_PPT_PLAT_SPPT 0x001200B1
|
||||
#define ASUS_WMI_DEVID_PPT_FPPT 0x001200C1
|
||||
#define ASUS_WMI_DEVID_PPT_PL3_FPPT 0x001200C1
|
||||
#define ASUS_WMI_DEVID_NV_DYN_BOOST 0x001200C0
|
||||
#define ASUS_WMI_DEVID_NV_THERM_TARGET 0x001200C2
|
||||
|
||||
|
|
@ -133,6 +137,11 @@
|
|||
/* dgpu on/off */
|
||||
#define ASUS_WMI_DEVID_DGPU 0x00090020
|
||||
|
||||
#define ASUS_WMI_DEVID_APU_MEM 0x000600C1
|
||||
|
||||
#define ASUS_WMI_DEVID_DGPU_BASE_TGP 0x00120099
|
||||
#define ASUS_WMI_DEVID_DGPU_SET_TGP 0x00120098
|
||||
|
||||
/* gpu mux switch, 0 = dGPU, 1 = Optimus */
|
||||
#define ASUS_WMI_DEVID_GPU_MUX 0x00090016
|
||||
#define ASUS_WMI_DEVID_GPU_MUX_VIVO 0x00090026
|
||||
|
|
@ -166,6 +175,7 @@ enum asus_ally_mcu_hack {
|
|||
#if IS_REACHABLE(CONFIG_ASUS_WMI)
|
||||
void set_ally_mcu_hack(enum asus_ally_mcu_hack status);
|
||||
void set_ally_mcu_powersave(bool enabled);
|
||||
int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval);
|
||||
int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval);
|
||||
int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval);
|
||||
#else
|
||||
|
|
@ -179,6 +189,10 @@ static inline int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval)
|
|||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1,
|
||||
u32 *retval)
|
||||
{
|
||||
|
|
@ -186,44 +200,4 @@ static inline int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1,
|
|||
}
|
||||
#endif
|
||||
|
||||
/* To be used by both hid-asus and asus-wmi to determine which controls kbd_brightness */
|
||||
static const struct dmi_system_id asus_use_hid_led_dmi_ids[] = {
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Zephyrus"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Strix"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Flow"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_PRODUCT_FAMILY, "ProArt P16"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "GA403U"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "GU605M"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "RC71L"),
|
||||
},
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
#endif /* __PLATFORM_DATA_X86_ASUS_WMI_H */
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#ifndef INTEL_PMC_IPC_H
|
||||
#define INTEL_PMC_IPC_H
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/cleanup.h>
|
||||
|
||||
#define IPC_SOC_REGISTER_ACCESS 0xAA
|
||||
#define IPC_SOC_SUB_CMD_READ 0x00
|
||||
|
|
@ -48,7 +49,6 @@ static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf
|
|||
{.type = ACPI_TYPE_INTEGER,},
|
||||
};
|
||||
struct acpi_object_list arg_list = { PMC_IPCS_PARAM_COUNT, params };
|
||||
union acpi_object *obj;
|
||||
int status;
|
||||
|
||||
if (!ipc_cmd || !rbuf)
|
||||
|
|
@ -72,7 +72,7 @@ static inline int intel_pmc_ipc(struct pmc_ipc_cmd *ipc_cmd, struct pmc_ipc_rbuf
|
|||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
obj = buffer.pointer;
|
||||
union acpi_object *obj __free(kfree) = buffer.pointer;
|
||||
|
||||
if (obj && obj->type == ACPI_TYPE_PACKAGE &&
|
||||
obj->package.count == VALID_IPC_RESPONSE) {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ enum platform_profile_option {
|
|||
PLATFORM_PROFILE_BALANCED,
|
||||
PLATFORM_PROFILE_BALANCED_PERFORMANCE,
|
||||
PLATFORM_PROFILE_PERFORMANCE,
|
||||
PLATFORM_PROFILE_MAX_POWER,
|
||||
PLATFORM_PROFILE_CUSTOM,
|
||||
PLATFORM_PROFILE_LAST, /*must always be last */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -36,13 +36,10 @@ struct wmi_device {
|
|||
*/
|
||||
#define to_wmi_device(device) container_of_const(device, struct wmi_device, dev)
|
||||
|
||||
extern acpi_status wmidev_evaluate_method(struct wmi_device *wdev,
|
||||
u8 instance, u32 method_id,
|
||||
const struct acpi_buffer *in,
|
||||
struct acpi_buffer *out);
|
||||
acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance, u32 method_id,
|
||||
const struct acpi_buffer *in, struct acpi_buffer *out);
|
||||
|
||||
extern union acpi_object *wmidev_block_query(struct wmi_device *wdev,
|
||||
u8 instance);
|
||||
union acpi_object *wmidev_block_query(struct wmi_device *wdev, u8 instance);
|
||||
|
||||
acpi_status wmidev_block_set(struct wmi_device *wdev, u8 instance, const struct acpi_buffer *in);
|
||||
|
||||
|
|
@ -81,9 +78,9 @@ struct wmi_driver {
|
|||
*/
|
||||
#define to_wmi_driver(drv) container_of_const(drv, struct wmi_driver, driver)
|
||||
|
||||
extern int __must_check __wmi_driver_register(struct wmi_driver *driver,
|
||||
struct module *owner);
|
||||
extern void wmi_driver_unregister(struct wmi_driver *driver);
|
||||
int __must_check __wmi_driver_register(struct wmi_driver *driver, struct module *owner);
|
||||
|
||||
void wmi_driver_unregister(struct wmi_driver *driver);
|
||||
|
||||
/**
|
||||
* wmi_driver_register() - Helper macro to register a WMI driver
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ struct process_cmd_struct {
|
|||
int arg;
|
||||
};
|
||||
|
||||
static const char *version_str = "v1.23";
|
||||
static const char *version_str = "v1.24";
|
||||
|
||||
static const int supported_api_ver = 3;
|
||||
static struct isst_if_platform_info isst_platform_info;
|
||||
|
|
|
|||
|
|
@ -452,13 +452,16 @@ static int tpmi_get_pbf_info(struct isst_id *id, int level,
|
|||
return _pbf_get_coremask_info(id, level, pbf_info);
|
||||
}
|
||||
|
||||
#define FEATURE_ENABLE_WAIT_US 1000
|
||||
#define FEATURE_ENABLE_RETRIES 5
|
||||
|
||||
static int tpmi_set_pbf_fact_status(struct isst_id *id, int pbf, int enable)
|
||||
{
|
||||
struct isst_pkg_ctdp pkg_dev;
|
||||
struct isst_pkg_ctdp_level_info ctdp_level;
|
||||
int current_level;
|
||||
struct isst_perf_feature_control info;
|
||||
int ret;
|
||||
int ret, i;
|
||||
|
||||
ret = isst_get_ctdp_levels(id, &pkg_dev);
|
||||
if (ret)
|
||||
|
|
@ -503,6 +506,30 @@ static int tpmi_set_pbf_fact_status(struct isst_id *id, int pbf, int enable)
|
|||
if (ret == -1)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < FEATURE_ENABLE_RETRIES; ++i) {
|
||||
|
||||
usleep(FEATURE_ENABLE_WAIT_US);
|
||||
|
||||
/* Check status */
|
||||
ret = isst_get_ctdp_control(id, current_level, &ctdp_level);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
debug_printf("pbf_enabled:%d fact_enabled:%d\n",
|
||||
ctdp_level.pbf_enabled, ctdp_level.fact_enabled);
|
||||
|
||||
if (pbf) {
|
||||
if (ctdp_level.pbf_enabled == enable)
|
||||
break;
|
||||
} else {
|
||||
if (ctdp_level.fact_enabled == enable)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == FEATURE_ENABLE_RETRIES)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -513,6 +540,7 @@ static int tpmi_get_fact_info(struct isst_id *id, int level, int fact_bucket,
|
|||
int i, j;
|
||||
int ret;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.socket_id = id->pkg;
|
||||
info.power_domain_id = id->punit;
|
||||
info.level = level;
|
||||
|
|
@ -659,7 +687,8 @@ static int tpmi_pm_qos_config(struct isst_id *id, int enable_clos,
|
|||
int priority_type)
|
||||
{
|
||||
struct isst_core_power info;
|
||||
int i, ret, saved_punit;
|
||||
int cp_state = 0, cp_cap = 0;
|
||||
int i, j, ret, saved_punit;
|
||||
|
||||
info.get_set = 1;
|
||||
info.socket_id = id->pkg;
|
||||
|
|
@ -679,6 +708,19 @@ static int tpmi_pm_qos_config(struct isst_id *id, int enable_clos,
|
|||
id->punit = saved_punit;
|
||||
return ret;
|
||||
}
|
||||
/* Get status */
|
||||
for (j = 0; j < FEATURE_ENABLE_RETRIES; ++j) {
|
||||
usleep(FEATURE_ENABLE_WAIT_US);
|
||||
ret = tpmi_read_pm_config(id, &cp_state, &cp_cap);
|
||||
debug_printf("ret:%d cp_state:%d enable_clos:%d\n", ret,
|
||||
cp_state, enable_clos);
|
||||
if (ret || cp_state == enable_clos)
|
||||
break;
|
||||
}
|
||||
if (j == FEATURE_ENABLE_RETRIES) {
|
||||
id->punit = saved_punit;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue