platform-drivers-x86 for v6.15-1

Highlights:
 
  - alienware-wmi: Refactor and split WMAX/legacy drivers
 
  - dell-ddv:
 
     - Correct +0.1 offset in temperature
 
     - Use the power supply extension mechanism for battery temperatures
 
  - intel/pmc:
 
     - Refactor init to mostly use a common init function
 
     - Add support for Arrow Lake U/H
 
     - Add support for Panther Lake
 
  - intel/sst:
 
     - Improve multi die handling
 
     - Prefix header search path with sysroot (fixes cross-compiling)
 
  - lenovo-wmi-hotkey-utilities: Support for mic & audio mute LEDs
 
  - samsung-galaxybook: Add driver for Samsung Galaxy Book series
 
  - wmi:
 
     - Rework WCxx/WExx ACPI method handling
 
     - Enable data block collection when the data block is set
 
  - platform/arm:
 
     - Add Huawei Matebook E Go EC driver
 
  - platform/mellanox:
 
     - Relocate to drivers/platform/mellanox/
 
     - mlxbf-bootctl: RTC battery status sysfs support
 
  - Miscellaneous cleanups / refactoring / improvements
 
 The following is an automated shortlog grouped by driver:
 
 alienware-wmi:
  -  Add a state container for LED control feature
  -  Add a state container for thermal control methods
  -  Add alienware-wmi.h
  -  Add WMI Drivers
  -  Refactor hdmi, amplifier, deepslp methods
  -  Refactor LED control methods
  -  Refactor thermal control methods
  -  Rename alienware-wmi.c
  -  Split DMI table
  -  Split the alienware-wmi driver
  -  Update alienware-wmi config entries
  -  Update header and module information
 
 amd/pmc:
  -  fix leak in probe()
  -  Move macros and structures to the PMC header file
  -  Notify user when platform does not support s0ix transition
  -  Remove unnecessary line breaks
  -  Use managed APIs for mutex
 
 amd/pmf:
  -  convert timeouts to secs_to_jiffies()
 
 amd:
  -  Use *-y instead of *-objs in Makefiles
 
 arm64:
  -  add Huawei Matebook E Go EC driver
 
 arm64: dts: qcom: gaokun3:
  -  Add Embedded Controller node
 
 compal-laptop:
  -  Do not include <linux/fb.h>
 
 dell-ddv:
  -  Fix temperature calculation
  -  Use devm_battery_hook_register
  -  Use the power supply extension mechanism
 
 dell: dell-wmi-sysman:
  -  Use *-y instead of *-objs in Makefile
 
 dell:
  -  Modify Makefile alignment
  -  Use *-y instead of *-objs in Makefile
 
 dell-uart-backlight:
  -  Make dell_uart_bl_serdev_driver static
 
 dt-bindings: platform:
  -  Add Huawei Matebook E Go EC
 
 hp-bioscfg:
  -  Replace deprecated strncpy() with strscpy()
  -  Use wmi_instance_count()
 
 hp:
  -  Use *-y instead of *-objs in Makefile
 
 hwmon:
  -  (hp-wmi-sensors) Use the WMI bus API when accessing sensors
 
 ideapad-laptop:
  -  use dev_groups to register attribute groups
 
 int3472:
  -  Call "func" "con_id" instead
 
 intel/pmc:
  -  Add Arrow Lake U/H support to intel_pmc_core driver
  -  Add Panther Lake support to intel_pmc_core
  -  Create generic_core_init() for all platforms
  -  Make tgl_core_generic_init() static
  -  Move arch specific action to init function
  -  Remove duplicate enum
  -  Remove simple init functions
  -  Remove unnecessary declarations in header
  -  Remove unneeded extern keyword in header
 
 intel:
  -  Use *-y instead of *-objs in Makefile
 
 irqdomain: platform/x86:
  -  Switch to irq_domain_create_linear()
 
 lenovo-wmi-hotkey-utilities.c:
  -  Support for mic and audio mute LEDs
 
 lenovo-yoga-tab2-pro-1380-fastcharger:
  -  Make symbol static
 
 MAINTAINERS:
  -  Add documentation reference for Mellanox platform
  -  Update ALIENWARE WMI DRIVER entry
 
 mellanox:
  -  Relocate mlx-platform driver
 
 mlxbf-bootctl:
  -  Support sysfs entries for RTC battery status
 
 mlx-platform:
  -  Change register name
  -  Cosmetic changes
 
 samsung-galaxybook:
  -  Add samsung-galaxybook driver
  -  Fix block_recording not supported logic
 
 sonypi:
  -  Use str_on_off() helper in sonypi_display_info()
 
 think-lmi:
  -  Use ACPI object when extracting strings
  -  Use WMI bus API when accessing BIOS settings
 
 thinkpad_acpi:
  -  check the return value of devm_mutex_init()
  -  convert timeouts to secs_to_jiffies()
  -  Do not include <linux/fb.h>
  -  Move HWMON initialization to tpacpi_hwmon_pdriver's probe
  -  Move subdriver initialization to tpacpi_pdriver's probe.
 
 tools/power/x86/intel-speed-select:
  -  Die ID for IO dies
  -  Fix the condition to check multi die system
  -  Prefix header search path with sysroot
  -  Prevent increasing MAX_DIE_PER_PACKAGE
  -  v1.22 release
 
 wmi:
  -  Call WCxx methods when setting data blocks
  -  Rework WCxx/WExx ACPI method handling
  -  Update documentation regarding the GUID-based API
  -  Use devres to disable the WMI device
 
 x86-android-tablets:
  -  Add select POWER_SUPPLY to Kconfig
 
 Merges:
  -  Merge branch 'fixes' into for-next
  -  Merge branch 'intel-sst' of https://github.com/spandruvada/linux-kernel into review-ilpo-next
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQSCSUwRdwTNL2MhaBlZrE9hU+XOMQUCZ+QJyQAKCRBZrE9hU+XO
 MUPYAP4sjtB8DKTIHgiQqado7PJZmdgpeJfAplitwKGe4BOcEQEA1mhuqMA5n6S+
 jvbTtRF+jiKxis/5zAtAdChScM/pIgo=
 =W+gy
 -----END PGP SIGNATURE-----

Merge tag 'platform-drivers-x86-v6.15-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86

Pull x86 platform drivers updates from Ilpo Järvinen:

 - alienware-wmi:
     - Refactor and split WMAX/legacy drivers

 - dell-ddv:
     - Correct +0.1 offset in temperature
     - Use the power supply extension mechanism for battery temperatures

 - intel/pmc:
     - Refactor init to mostly use a common init function
     - Add support for Arrow Lake U/H
     - Add support for Panther Lake

 - intel/sst:
     - Improve multi die handling
     - Prefix header search path with sysroot (fixes cross-compiling)

 - lenovo-wmi-hotkey-utilities:
     - Support for mic & audio mute LEDs

 - samsung-galaxybook:
     - Add driver for Samsung Galaxy Book series

 - wmi:
     - Rework WCxx/WExx ACPI method handling
     - Enable data block collection when the data block is set

 - platform/arm:
     - Add Huawei Matebook E Go EC driver

 - platform/mellanox:
     - Relocate to drivers/platform/mellanox/
     - mlxbf-bootctl:
     - RTC battery status sysfs support

 - Miscellaneous cleanups / refactoring / improvements

* tag 'platform-drivers-x86-v6.15-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (75 commits)
  platform/x86: x86-android-tablets: Add select POWER_SUPPLY to Kconfig
  platform/x86/amd/pmf: convert timeouts to secs_to_jiffies()
  platform/x86: thinkpad_acpi: convert timeouts to secs_to_jiffies()
  irqdomain: platform/x86: Switch to irq_domain_create_linear()
  platform/x86/amd/pmc: fix leak in probe()
  tools/power/x86/intel-speed-select: v1.22 release
  tools/power/x86/intel-speed-select: Prefix header search path with sysroot
  tools/power/x86/intel-speed-select: Die ID for IO dies
  tools/power/x86/intel-speed-select: Fix the condition to check multi die system
  tools/power/x86/intel-speed-select: Prevent increasing MAX_DIE_PER_PACKAGE
  platform/x86/amd/pmc: Use managed APIs for mutex
  platform/x86/amd/pmc: Remove unnecessary line breaks
  platform/x86/amd/pmc: Move macros and structures to the PMC header file
  platform/x86/amd/pmc: Notify user when platform does not support s0ix transition
  platform/x86: dell-ddv: Use the power supply extension mechanism
  platform/x86: dell-ddv: Use devm_battery_hook_register
  platform/x86: dell-ddv: Fix temperature calculation
  platform/x86: thinkpad_acpi: check the return value of devm_mutex_init()
  platform/x86: samsung-galaxybook: Fix block_recording not supported logic
  platform/x86: dell-uart-backlight: Make dell_uart_bl_serdev_driver static
  ...
This commit is contained in:
Linus Torvalds 2025-03-26 09:54:40 -07:00
commit fb1ceb29b2
68 changed files with 5998 additions and 2198 deletions

View File

@ -150,3 +150,13 @@ Description:
The "mfg_lock" sysfs attribute is write-only.
A successful write to this attribute will latch the
board-level attributes into EEPROM, making them read-only.
What: /sys/bus/platform/devices/MLNXBF04:00/rtc_battery
Date: June 2025
KernelVersion: 6.15
Contact: "Xiangrong Li <xiangrongl@nvidia.com>"
Description:
The "rtc_battery" sysfs attribute is read-only.
A successful read from this attribute returns the status of
the board's RTC battery. The RTC battery status register is
also cleared upon successful read operation.

View File

@ -11,6 +11,7 @@ Laptop Drivers
disk-shock-protection
laptop-mode
lg-laptop
samsung-galaxybook
sony-laptop
sonypi
thinkpad-acpi

View File

@ -0,0 +1,174 @@
.. SPDX-License-Identifier: GPL-2.0-or-later
==========================
Samsung Galaxy Book Driver
==========================
Joshua Grisham <josh@joshuagrisham.com>
This is a Linux x86 platform driver for Samsung Galaxy Book series notebook
devices which utilizes Samsung's ``SCAI`` ACPI device in order to control
extra features and receive various notifications.
Supported devices
=================
Any device with one of the supported ACPI device IDs should be supported. This
covers most of the "Samsung Galaxy Book" series notebooks that are currently
available as of this writing, and could include other Samsung notebook devices
as well.
Status
======
The following features are currently supported:
- :ref:`Keyboard backlight <keyboard-backlight>` control
- :ref:`Performance mode <performance-mode>` control implemented using the
platform profile interface
- :ref:`Battery charge control end threshold
<battery-charge-control-end-threshold>` (stop charging battery at given
percentage value) implemented as a battery hook
- :ref:`Firmware Attributes <firmware-attributes>` to allow control of various
device settings
- :ref:`Handling of Fn hotkeys <keyboard-hotkey-actions>` for various actions
- :ref:`Handling of ACPI notifications and hotkeys
<acpi-notifications-and-hotkey-actions>`
Because different models of these devices can vary in their features, there is
logic built within the driver which attempts to test each implemented feature
for a valid response before enabling its support (registering additional devices
or extensions, adding sysfs attributes, etc). Therefore, it can be important to
note that not all features may be supported for your particular device.
The following features might be possible to implement but will require
additional investigation and are therefore not supported at this time:
- "Dolby Atmos" mode for the speakers
- "Outdoor Mode" for increasing screen brightness on models with ``SAM0427``
- "Silent Mode" on models with ``SAM0427``
.. _keyboard-backlight:
Keyboard backlight
==================
A new LED class named ``samsung-galaxybook::kbd_backlight`` is created which
will then expose the device using the standard sysfs-based LED interface at
``/sys/class/leds/samsung-galaxybook::kbd_backlight``. Brightness can be
controlled by writing the desired value to the ``brightness`` sysfs attribute or
with any other desired userspace utility.
.. note::
Most of these devices have an ambient light sensor which also turns
off the keyboard backlight under well-lit conditions. This behavior does not
seem possible to control at this time, but can be good to be aware of.
.. _performance-mode:
Performance mode
================
This driver implements the
Documentation/userspace-api/sysfs-platform_profile.rst interface for working
with the "performance mode" function of the Samsung ACPI device.
Mapping of each Samsung "performance mode" to its respective platform profile is
performed dynamically by the driver, as not all models support all of the same
performance modes. Your device might have one or more of the following mappings:
- "Silent" maps to ``low-power``
- "Quiet" maps to ``quiet``
- "Optimized" maps to ``balanced``
- "High performance" maps to ``performance``
The result of the mapping can be printed in the kernel log when the module is
loaded. Supported profiles can also be retrieved from
``/sys/firmware/acpi/platform_profile_choices``, while
``/sys/firmware/acpi/platform_profile`` can be used to read or write the
currently selected profile.
The ``balanced`` platform profile will be set during module load if no profile
has been previously set.
.. _battery-charge-control-end-threshold:
Battery charge control end threshold
====================================
This platform driver will add the ability to set the battery's charge control
end threshold, but does not have the ability to set a start threshold.
This feature is typically called "Battery Saver" by the various Samsung
applications in Windows, but in Linux we have implemented the standardized
"charge control threshold" sysfs interface on the battery device to allow for
controlling this functionality from the userspace.
The sysfs attribute
``/sys/class/power_supply/BAT1/charge_control_end_threshold`` can be used to
read or set the desired charge end threshold.
If you wish to maintain interoperability with the Samsung Settings application
in Windows, then you should set the value to 100 to represent "off", or enable
the feature using only one of the following values: 50, 60, 70, 80, or 90.
Otherwise, the driver will accept any value between 1 and 100 as the percentage
that you wish the battery to stop charging at.
.. note::
Some devices have been observed as automatically "turning off" the charge
control end threshold if an input value of less than 30 is given.
.. _firmware-attributes:
Firmware Attributes
===================
The following enumeration-typed firmware attributes are set up by this driver
and should be accessible under
``/sys/class/firmware-attributes/samsung-galaxybook/attributes/`` if your device
supports them:
- ``power_on_lid_open`` (device should power on when the lid is opened)
- ``usb_charging`` (USB ports can deliver power to connected devices even when
the device is powered off or in a low sleep state)
- ``block_recording`` (blocks access to camera and microphone)
All of these attributes are simple boolean-like enumeration values which use 0
to represent "off" and 1 to represent "on". Use the ``current_value`` attribute
to get or change the setting on the device.
Note that when ``block_recording`` is updated, the input device "Samsung Galaxy
Book Lens Cover" will receive a ``SW_CAMERA_LENS_COVER`` switch event which
reflects the current state.
.. _keyboard-hotkey-actions:
Keyboard hotkey actions (i8042 filter)
======================================
The i8042 filter will swallow the keyboard events for the Fn+F9 hotkey (Multi-
level keyboard backlight toggle) and Fn+F10 hotkey (Block recording toggle)
and instead execute their actions within the driver itself.
Fn+F9 will cycle through the brightness levels of the keyboard backlight. A
notification will be sent using ``led_classdev_notify_brightness_hw_changed``
so that the userspace can be aware of the change. This mimics the behavior of
other existing devices where the brightness level is cycled internally by the
embedded controller and then reported via a notification.
Fn+F10 will toggle the value of the "block recording" setting, which blocks
or allows usage of the built-in camera and microphone (and generates the same
Lens Cover switch event mentioned above).
.. _acpi-notifications-and-hotkey-actions:
ACPI notifications and hotkey actions
=====================================
ACPI notifications will generate ACPI netlink events under the device class
``samsung-galaxybook`` and bus ID matching the Samsung ACPI device ID found on
your device. The events can be received using userspace tools such as
``acpi_listen`` and ``acpid``.
The Fn+F11 Performance mode hotkey will be handled by the driver; each keypress
will cycle to the next available platform profile.

View File

@ -0,0 +1,124 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/platform/huawei,gaokun-ec.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Huawei Matebook E Go Embedded Controller
maintainers:
- Pengyu Luo <mitltlatltl@gmail.com>
description:
Different from other Qualcomm Snapdragon sc8180x and sc8280xp-based
machines, the Huawei Matebook E Go tablets use embedded controllers
while others use a system called PMIC GLink which handles battery,
UCSI, USB Type-C DP Alt Mode. In addition, Huawei's implementation
also handles additional features, such as charging thresholds, FN
lock, smart charging, tablet lid status, thermal sensors, and more.
properties:
compatible:
enum:
- huawei,gaokun3-ec
reg:
const: 0x38
'#address-cells':
const: 1
'#size-cells':
const: 0
interrupts:
maxItems: 1
patternProperties:
'^connector@[01]$':
$ref: /schemas/connector/usb-connector.yaml#
properties:
reg:
maxItems: 1
required:
- compatible
- reg
- interrupts
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
embedded-controller@38 {
compatible = "huawei,gaokun3-ec";
reg = <0x38>;
interrupts-extended = <&tlmm 107 IRQ_TYPE_LEVEL_LOW>;
#address-cells = <1>;
#size-cells = <0>;
connector@0 {
compatible = "usb-c-connector";
reg = <0>;
power-role = "dual";
data-role = "dual";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
ucsi0_ss_in: endpoint {
remote-endpoint = <&usb_0_qmpphy_out>;
};
};
port@1 {
reg = <1>;
ucsi0_sbu: endpoint {
remote-endpoint = <&usb0_sbu_mux>;
};
};
};
};
connector@1 {
compatible = "usb-c-connector";
reg = <1>;
power-role = "dual";
data-role = "dual";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
ucsi1_ss_in: endpoint {
remote-endpoint = <&usb_1_qmpphy_out>;
};
};
port@1 {
reg = <1>;
ucsi1_sbu: endpoint {
remote-endpoint = <&usb1_sbu_mux>;
};
};
};
};
};
};

View File

@ -89,6 +89,9 @@ Similar to the ``WExx`` ACPI methods, except that it controls data collection
instead of events and thus the last two characters of the ACPI method name are
the method ID of the data block to enable/disable.
Those ACPI methods are also called before setting data blocks to match the
behaviour of the Windows driver.
_WED ACPI method
----------------

View File

@ -96,6 +96,10 @@ on a given machine.
Because of this, WMI drivers should use the state container design pattern as described in
Documentation/driver-api/driver-model/design-patterns.rst.
.. warning:: Using both GUID-based and non-GUID-based functions for querying WMI data blocks and
handling WMI events simultaneously on the same device is guaranteed to corrupt the
WMI device state and might lead to erratic behaviour.
WMI method drivers
------------------

View File

@ -793,10 +793,12 @@ F: Documentation/admin-guide/perf/alibaba_pmu.rst
F: drivers/perf/alibaba_uncore_drw_pmu.c
ALIENWARE WMI DRIVER
M: Kurt Borja <kuurtb@gmail.com>
L: platform-driver-x86@vger.kernel.org
L: Dell.Client.Kernel@dell.com
S: Maintained
F: Documentation/wmi/devices/alienware-wmi.rst
F: drivers/platform/x86/dell/alienware-wmi.c
F: drivers/platform/x86/dell/alienware-wmi*
ALLEGRO DVT VIDEO IP CORE DRIVER
M: Michael Tretter <m.tretter@pengutronix.de>
@ -10750,6 +10752,13 @@ S: Maintained
F: Documentation/networking/device_drivers/ethernet/huawei/hinic.rst
F: drivers/net/ethernet/huawei/hinic/
HUAWEI MATEBOOK E GO EMBEDDED CONTROLLER DRIVER
M: Pengyu Luo <mitltlatltl@gmail.com>
S: Maintained
F: Documentation/devicetree/bindings/platform/huawei,gaokun-ec.yaml
F: drivers/platform/arm64/huawei-gaokun-ec.c
F: include/linux/platform_data/huawei-gaokun-ec.h
HUGETLB SUBSYSTEM
M: Muchun Song <muchun.song@linux.dev>
L: linux-mm@kvack.org
@ -13213,6 +13222,12 @@ S: Maintained
W: http://legousb.sourceforge.net/
F: drivers/usb/misc/legousbtower.c
LENOVO WMI HOTKEY UTILITIES DRIVER
M: Jackie Dong <xy-jackie@139.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/lenovo-wmi-hotkey-utilities.c
LETSKETCH HID TABLET DRIVER
M: Hans de Goede <hdegoede@redhat.com>
L: linux-input@vger.kernel.org
@ -15091,6 +15106,7 @@ M: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
M: Vadim Pasternak <vadimp@nvidia.com>
L: platform-driver-x86@vger.kernel.org
S: Supported
F: Documentation/ABI/stable/sysfs-driver-mlxreg-io
F: Documentation/ABI/testing/sysfs-platform-mellanox-bootctl
F: drivers/platform/mellanox/
F: include/linux/platform_data/mlxreg.h
@ -15161,12 +15177,6 @@ F: Documentation/leds/leds-mlxcpld.rst
F: drivers/leds/leds-mlxcpld.c
F: drivers/leds/leds-mlxreg.c
MELLANOX PLATFORM DRIVER
M: Vadim Pasternak <vadimp@nvidia.com>
L: platform-driver-x86@vger.kernel.org
S: Supported
F: drivers/platform/x86/mlx-platform.c
MEMBARRIER SUPPORT
M: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
M: "Paul E. McKenney" <paulmck@kernel.org>
@ -21094,6 +21104,13 @@ L: linux-fbdev@vger.kernel.org
S: Maintained
F: drivers/video/fbdev/s3c-fb.c
SAMSUNG GALAXY BOOK DRIVER
M: Joshua Grisham <josh@joshuagrisham.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: Documentation/admin-guide/laptops/samsung-galaxybook.rst
F: drivers/platform/x86/samsung-galaxybook.c
SAMSUNG INTERCONNECT DRIVERS
M: Sylwester Nawrocki <s.nawrocki@samsung.com>
M: Artur Świgoń <a.swigon@samsung.com>

View File

@ -28,6 +28,7 @@ / {
aliases {
i2c4 = &i2c4;
i2c15 = &i2c15;
serial1 = &uart2;
};
@ -216,6 +217,40 @@ map1 {
};
};
usb0-sbu-mux {
compatible = "pericom,pi3usb102", "gpio-sbu-mux";
select-gpios = <&tlmm 164 GPIO_ACTIVE_HIGH>;
pinctrl-0 = <&usb0_sbu_default>;
pinctrl-names = "default";
orientation-switch;
port {
usb0_sbu_mux: endpoint {
remote-endpoint = <&ucsi0_sbu>;
};
};
};
usb1-sbu-mux {
compatible = "pericom,pi3usb102", "gpio-sbu-mux";
select-gpios = <&tlmm 47 GPIO_ACTIVE_HIGH>;
pinctrl-0 = <&usb1_sbu_default>;
pinctrl-names = "default";
orientation-switch;
port {
usb1_sbu_mux: endpoint {
remote-endpoint = <&ucsi1_sbu>;
};
};
};
wcn6855-pmu {
compatible = "qcom,wcn6855-pmu";
@ -584,6 +619,97 @@ touchscreen@4f {
};
&i2c15 {
clock-frequency = <400000>;
pinctrl-0 = <&i2c15_default>;
pinctrl-names = "default";
status = "okay";
embedded-controller@38 {
compatible = "huawei,gaokun3-ec";
reg = <0x38>;
interrupts-extended = <&tlmm 107 IRQ_TYPE_LEVEL_LOW>;
#address-cells = <1>;
#size-cells = <0>;
connector@0 {
compatible = "usb-c-connector";
reg = <0>;
power-role = "dual";
data-role = "dual";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
ucsi0_hs_in: endpoint {
remote-endpoint = <&usb_0_dwc3_hs>;
};
};
port@1 {
reg = <1>;
ucsi0_ss_in: endpoint {
remote-endpoint = <&usb_0_qmpphy_out>;
};
};
port@2 {
reg = <2>;
ucsi0_sbu: endpoint {
remote-endpoint = <&usb0_sbu_mux>;
};
};
};
};
connector@1 {
compatible = "usb-c-connector";
reg = <1>;
power-role = "dual";
data-role = "dual";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
ucsi1_hs_in: endpoint {
remote-endpoint = <&usb_1_dwc3_hs>;
};
};
port@1 {
reg = <1>;
ucsi1_ss_in: endpoint {
remote-endpoint = <&usb_1_qmpphy_out>;
};
};
port@2 {
reg = <2>;
ucsi1_sbu: endpoint {
remote-endpoint = <&usb1_sbu_mux>;
};
};
};
};
};
};
&mdss0 {
status = "okay";
};
@ -1004,6 +1130,10 @@ &usb_0_dwc3 {
dr_mode = "host";
};
&usb_0_dwc3_hs {
remote-endpoint = <&ucsi0_hs_in>;
};
&usb_0_hsphy {
vdda-pll-supply = <&vreg_l9d>;
vdda18-supply = <&vreg_l1c>;
@ -1025,6 +1155,10 @@ &usb_0_qmpphy_dp_in {
remote-endpoint = <&mdss0_dp0_out>;
};
&usb_0_qmpphy_out {
remote-endpoint = <&ucsi0_ss_in>;
};
&usb_1 {
status = "okay";
};
@ -1033,6 +1167,10 @@ &usb_1_dwc3 {
dr_mode = "host";
};
&usb_1_dwc3_hs {
remote-endpoint = <&ucsi1_hs_in>;
};
&usb_1_hsphy {
vdda-pll-supply = <&vreg_l4b>;
vdda18-supply = <&vreg_l1c>;
@ -1054,6 +1192,10 @@ &usb_1_qmpphy_dp_in {
remote-endpoint = <&mdss0_dp1_out>;
};
&usb_1_qmpphy_out {
remote-endpoint = <&ucsi1_ss_in>;
};
&usb_2 {
status = "okay";
};
@ -1177,6 +1319,13 @@ i2c4_default: i2c4-default-state {
bias-disable;
};
i2c15_default: i2c15-default-state {
pins = "gpio36", "gpio37";
function = "qup15";
drive-strength = <2>;
bias-pull-up;
};
mode_pin_active: mode-pin-state {
pins = "gpio26";
function = "gpio";
@ -1301,6 +1450,20 @@ tx-pins {
};
};
usb0_sbu_default: usb0-sbu-state {
pins = "gpio164";
function = "gpio";
drive-strength = <16>;
bias-disable;
};
usb1_sbu_default: usb1-sbu-state {
pins = "gpio47";
function = "gpio";
drive-strength = <16>;
bias-disable;
};
wcd_default: wcd-default-state {
reset-pins {
pins = "gpio106";

View File

@ -37,6 +37,7 @@
#include <linux/kfifo.h>
#include <linux/platform_device.h>
#include <linux/gfp.h>
#include <linux/string_choices.h>
#include <linux/uaccess.h>
#include <asm/io.h>
@ -1268,12 +1269,12 @@ static void sonypi_display_info(void)
"compat = %s, mask = 0x%08lx, useinput = %s, acpi = %s\n",
sonypi_device.model,
verbose,
fnkeyinit ? "on" : "off",
camera ? "on" : "off",
compat ? "on" : "off",
str_on_off(fnkeyinit),
str_on_off(camera),
str_on_off(compat),
mask,
useinput ? "on" : "off",
SONYPI_ACPI_ACTIVE ? "on" : "off");
str_on_off(useinput),
str_on_off(SONYPI_ACPI_ACTIVE));
printk(KERN_INFO "sonypi: enabled at irq=%d, port1=0x%x, port2=0x%x\n",
sonypi_device.irq,
sonypi_device.ioport1, sonypi_device.ioport2);

View File

@ -1197,7 +1197,7 @@ static int hp_wmi_update_info(struct hp_wmi_sensors *state,
if (time_after(jiffies, info->last_updated + HZ)) {
mutex_lock(&state->lock);
wobj = hp_wmi_get_wobj(HP_WMI_NUMERIC_SENSOR_GUID, instance);
wobj = wmidev_block_query(state->wdev, instance);
if (!wobj) {
ret = -EIO;
goto out_unlock;
@ -1745,7 +1745,7 @@ static int init_numeric_sensors(struct hp_wmi_sensors *state,
return -ENOMEM;
for (i = 0, info = info_arr; i < icount; i++, info++) {
wobj = hp_wmi_get_wobj(HP_WMI_NUMERIC_SENSOR_GUID, i);
wobj = wmidev_block_query(state->wdev, i);
if (!wobj)
return -EIO;

View File

@ -33,6 +33,27 @@ config EC_ACER_ASPIRE1
laptop where this information is not properly exposed via the
standard ACPI devices.
config EC_HUAWEI_GAOKUN
tristate "Huawei Matebook E Go Embedded Controller driver"
depends on ARCH_QCOM || COMPILE_TEST
depends on I2C
depends on INPUT
depends on HWMON
select AUXILIARY_BUS
help
Say Y here to enable the EC driver for the Huawei Matebook E Go
which is a sc8280xp-based 2-in-1 tablet. The driver handles battery
(information, charge control) and USB Type-C DP HPD events as well
as some misc functions like the lid sensor and temperature sensors,
etc.
This driver provides battery and AC status support for the mentioned
laptop where this information is not properly exposed via the
standard ACPI devices.
Say M or Y here to include this support.
config EC_LENOVO_YOGA_C630
tristate "Lenovo Yoga C630 Embedded Controller driver"
depends on ARCH_QCOM || COMPILE_TEST

View File

@ -6,4 +6,5 @@
#
obj-$(CONFIG_EC_ACER_ASPIRE1) += acer-aspire1-ec.o
obj-$(CONFIG_EC_HUAWEI_GAOKUN) += huawei-gaokun-ec.o
obj-$(CONFIG_EC_LENOVO_YOGA_C630) += lenovo-yoga-c630.o

View File

@ -0,0 +1,825 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* huawei-gaokun-ec - An EC driver for HUAWEI Matebook E Go
*
* Copyright (C) 2024-2025 Pengyu Luo <mitltlatltl@gmail.com>
*/
#include <linux/auxiliary_bus.h>
#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/notifier.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_data/huawei-gaokun-ec.h>
#define EC_EVENT 0x06
/* Also can be found in ACPI specification 12.3 */
#define EC_READ 0x80
#define EC_WRITE 0x81
#define EC_BURST 0x82
#define EC_QUERY 0x84
#define EC_FN_LOCK_ON 0x5A
#define EC_FN_LOCK_OFF 0x55
#define EC_FN_LOCK_READ 0x6B
#define EC_FN_LOCK_WRITE 0x6C
#define EC_EVENT_LID 0x81
#define EC_LID_STATE 0x80
#define EC_LID_OPEN BIT(1)
#define EC_TEMP_REG 0x61
#define EC_STANDBY_REG 0xB2
#define EC_STANDBY_ENTER 0xDB
#define EC_STANDBY_EXIT 0xEB
enum gaokun_ec_smart_charge_cmd {
SMART_CHARGE_DATA_WRITE = 0xE3,
SMART_CHARGE_DATA_READ,
SMART_CHARGE_ENABLE_WRITE,
SMART_CHARGE_ENABLE_READ,
};
enum gaokun_ec_ucsi_cmd {
UCSI_REG_WRITE = 0xD2,
UCSI_REG_READ,
UCSI_DATA_WRITE,
UCSI_DATA_READ,
};
#define UCSI_REG_SIZE 7
/*
* For tx, command sequences are arranged as
* {master_cmd, slave_cmd, data_len, data_seq}
*/
#define REQ_HDR_SIZE 3
#define INPUT_SIZE_OFFSET 2
#define REQ_LEN(req) (REQ_HDR_SIZE + (req)[INPUT_SIZE_OFFSET])
/*
* For rx, data sequences are arranged as
* {status, data_len(unreliable), data_seq}
*/
#define RESP_HDR_SIZE 2
#define MKREQ(REG0, REG1, SIZE, ...) \
{ \
REG0, REG1, SIZE, \
/* ## will remove comma when SIZE is 0 */ \
## __VA_ARGS__, \
/* make sure len(pkt[3:]) >= SIZE */ \
[3 + (SIZE)] = 0, \
}
#define MKRESP(SIZE) \
{ \
[RESP_HDR_SIZE + (SIZE) - 1] = 0, \
}
/* Possible size 1, 4, 20, 24. Most of the time, the size is 1. */
static inline void refill_req(u8 *dest, const u8 *src, size_t size)
{
memcpy(dest + REQ_HDR_SIZE, src, size);
}
static inline void refill_req_byte(u8 *dest, const u8 *src)
{
dest[REQ_HDR_SIZE] = *src;
}
/* Possible size 1, 2, 4, 7, 20. Most of the time, the size is 1. */
static inline void extr_resp(u8 *dest, const u8 *src, size_t size)
{
memcpy(dest, src + RESP_HDR_SIZE, size);
}
static inline void extr_resp_byte(u8 *dest, const u8 *src)
{
*dest = src[RESP_HDR_SIZE];
}
static inline void *extr_resp_shallow(const u8 *src)
{
return (void *)(src + RESP_HDR_SIZE);
}
struct gaokun_ec {
struct i2c_client *client;
struct mutex lock; /* EC transaction lock */
struct blocking_notifier_head notifier_list;
struct device *hwmon_dev;
struct input_dev *idev;
bool suspended;
};
static int gaokun_ec_request(struct gaokun_ec *ec, const u8 *req,
size_t resp_len, u8 *resp)
{
struct i2c_client *client = ec->client;
struct i2c_msg msgs[] = {
{
.addr = client->addr,
.flags = client->flags,
.len = REQ_LEN(req),
.buf = (void *)req,
}, {
.addr = client->addr,
.flags = client->flags | I2C_M_RD,
.len = resp_len,
.buf = resp,
},
};
int ret;
guard(mutex)(&ec->lock);
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (ret != ARRAY_SIZE(msgs)) {
dev_err(&client->dev, "I2C transfer error %d\n", ret);
goto out_after_break;
}
ret = *resp;
if (ret)
dev_err(&client->dev, "EC transaction error %d\n", ret);
out_after_break:
usleep_range(2000, 2500); /* have a break, ACPI did this */
return ret;
}
/* -------------------------------------------------------------------------- */
/* Common API */
/**
* gaokun_ec_read - Read from EC
* @ec: The gaokun_ec structure
* @req: The sequence to request
* @resp_len: The size to read
* @resp: The buffer to store response sequence
*
* This function is used to read data after writing a magic sequence to EC.
* All EC operations depend on this function.
*
* Huawei uses magic sequences everywhere to complete various functions, all
* these sequences are passed to ECCD(a ACPI method which is quiet similar
* to gaokun_ec_request), there is no good abstraction to generalize these
* sequences, so just wrap it for now. Almost all magic sequences are kept
* in this file.
*
* Return: 0 on success or negative error code.
*/
int gaokun_ec_read(struct gaokun_ec *ec, const u8 *req,
size_t resp_len, u8 *resp)
{
return gaokun_ec_request(ec, req, resp_len, resp);
}
EXPORT_SYMBOL_GPL(gaokun_ec_read);
/**
* gaokun_ec_write - Write to EC
* @ec: The gaokun_ec structure
* @req: The sequence to request
*
* This function has no big difference from gaokun_ec_read. When caller care
* only write status and no actual data are returned, then use it.
*
* Return: 0 on success or negative error code.
*/
int gaokun_ec_write(struct gaokun_ec *ec, const u8 *req)
{
u8 ec_resp[] = MKRESP(0);
return gaokun_ec_request(ec, req, sizeof(ec_resp), ec_resp);
}
EXPORT_SYMBOL_GPL(gaokun_ec_write);
int gaokun_ec_read_byte(struct gaokun_ec *ec, const u8 *req, u8 *byte)
{
int ret;
u8 ec_resp[] = MKRESP(sizeof(*byte));
ret = gaokun_ec_read(ec, req, sizeof(ec_resp), ec_resp);
extr_resp_byte(byte, ec_resp);
return ret;
}
EXPORT_SYMBOL_GPL(gaokun_ec_read_byte);
/**
* gaokun_ec_register_notify - Register a notifier callback for EC events.
* @ec: The gaokun_ec structure
* @nb: Notifier block pointer to register
*
* Return: 0 on success or negative error code.
*/
int gaokun_ec_register_notify(struct gaokun_ec *ec, struct notifier_block *nb)
{
return blocking_notifier_chain_register(&ec->notifier_list, nb);
}
EXPORT_SYMBOL_GPL(gaokun_ec_register_notify);
/**
* gaokun_ec_unregister_notify - Unregister notifier callback for EC events.
* @ec: The gaokun_ec structure
* @nb: Notifier block pointer to unregister
*
* Unregister a notifier callback that was previously registered with
* gaokun_ec_register_notify().
*/
void gaokun_ec_unregister_notify(struct gaokun_ec *ec, struct notifier_block *nb)
{
blocking_notifier_chain_unregister(&ec->notifier_list, nb);
}
EXPORT_SYMBOL_GPL(gaokun_ec_unregister_notify);
/* -------------------------------------------------------------------------- */
/* API for PSY */
/**
* gaokun_ec_psy_multi_read - Read contiguous registers
* @ec: The gaokun_ec structure
* @reg: The start register
* @resp_len: The number of registers to be read
* @resp: The buffer to store response sequence
*
* Return: 0 on success or negative error code.
*/
int gaokun_ec_psy_multi_read(struct gaokun_ec *ec, u8 reg,
size_t resp_len, u8 *resp)
{
u8 ec_req[] = MKREQ(0x02, EC_READ, 1, 0);
u8 ec_resp[] = MKRESP(1);
int i, ret;
for (i = 0; i < resp_len; ++i, reg++) {
refill_req_byte(ec_req, &reg);
ret = gaokun_ec_read(ec, ec_req, sizeof(ec_resp), ec_resp);
if (ret)
return ret;
extr_resp_byte(&resp[i], ec_resp);
}
return 0;
}
EXPORT_SYMBOL_GPL(gaokun_ec_psy_multi_read);
/* Smart charge */
/**
* gaokun_ec_psy_get_smart_charge - Get smart charge data from EC
* @ec: The gaokun_ec structure
* @resp: The buffer to store response sequence (mode, delay, start, end)
*
* Return: 0 on success or negative error code.
*/
int gaokun_ec_psy_get_smart_charge(struct gaokun_ec *ec,
u8 resp[GAOKUN_SMART_CHARGE_DATA_SIZE])
{
/* GBCM */
u8 ec_req[] = MKREQ(0x02, SMART_CHARGE_DATA_READ, 0);
u8 ec_resp[] = MKRESP(GAOKUN_SMART_CHARGE_DATA_SIZE);
int ret;
ret = gaokun_ec_read(ec, ec_req, sizeof(ec_resp), ec_resp);
if (ret)
return ret;
extr_resp(resp, ec_resp, GAOKUN_SMART_CHARGE_DATA_SIZE);
return 0;
}
EXPORT_SYMBOL_GPL(gaokun_ec_psy_get_smart_charge);
static inline bool validate_battery_threshold_range(u8 start, u8 end)
{
return end != 0 && start <= end && end <= 100;
}
/**
* gaokun_ec_psy_set_smart_charge - Set smart charge data
* @ec: The gaokun_ec structure
* @req: The sequence to request (mode, delay, start, end)
*
* Return: 0 on success or negative error code.
*/
int gaokun_ec_psy_set_smart_charge(struct gaokun_ec *ec,
const u8 req[GAOKUN_SMART_CHARGE_DATA_SIZE])
{
/* SBCM */
u8 ec_req[] = MKREQ(0x02, SMART_CHARGE_DATA_WRITE,
GAOKUN_SMART_CHARGE_DATA_SIZE);
if (!validate_battery_threshold_range(req[2], req[3]))
return -EINVAL;
refill_req(ec_req, req, GAOKUN_SMART_CHARGE_DATA_SIZE);
return gaokun_ec_write(ec, ec_req);
}
EXPORT_SYMBOL_GPL(gaokun_ec_psy_set_smart_charge);
/* Smart charge enable */
/**
* gaokun_ec_psy_get_smart_charge_enable - Get smart charge state
* @ec: The gaokun_ec structure
* @on: The state
*
* Return: 0 on success or negative error code.
*/
int gaokun_ec_psy_get_smart_charge_enable(struct gaokun_ec *ec, bool *on)
{
/* GBAC */
u8 ec_req[] = MKREQ(0x02, SMART_CHARGE_ENABLE_READ, 0);
u8 state;
int ret;
ret = gaokun_ec_read_byte(ec, ec_req, &state);
if (ret)
return ret;
*on = !!state;
return 0;
}
EXPORT_SYMBOL_GPL(gaokun_ec_psy_get_smart_charge_enable);
/**
* gaokun_ec_psy_set_smart_charge_enable - Set smart charge state
* @ec: The gaokun_ec structure
* @on: The state
*
* Return: 0 on success or negative error code.
*/
int gaokun_ec_psy_set_smart_charge_enable(struct gaokun_ec *ec, bool on)
{
/* SBAC */
u8 ec_req[] = MKREQ(0x02, SMART_CHARGE_ENABLE_WRITE, 1, on);
return gaokun_ec_write(ec, ec_req);
}
EXPORT_SYMBOL_GPL(gaokun_ec_psy_set_smart_charge_enable);
/* -------------------------------------------------------------------------- */
/* API for UCSI */
/**
* gaokun_ec_ucsi_read - Read UCSI data from EC
* @ec: The gaokun_ec structure
* @resp: The buffer to store response sequence
*
* Read CCI and MSGI (used by UCSI subdriver).
*
* Return: 0 on success or negative error code.
*/
int gaokun_ec_ucsi_read(struct gaokun_ec *ec,
u8 resp[GAOKUN_UCSI_READ_SIZE])
{
u8 ec_req[] = MKREQ(0x03, UCSI_DATA_READ, 0);
u8 ec_resp[] = MKRESP(GAOKUN_UCSI_READ_SIZE);
int ret;
ret = gaokun_ec_read(ec, ec_req, sizeof(ec_resp), ec_resp);
if (ret)
return ret;
extr_resp(resp, ec_resp, GAOKUN_UCSI_READ_SIZE);
return 0;
}
EXPORT_SYMBOL_GPL(gaokun_ec_ucsi_read);
/**
* gaokun_ec_ucsi_write - Write UCSI data to EC
* @ec: The gaokun_ec structure
* @req: The sequence to request
*
* Write CTRL and MSGO (used by UCSI subdriver).
*
* Return: 0 on success or negative error code.
*/
int gaokun_ec_ucsi_write(struct gaokun_ec *ec,
const u8 req[GAOKUN_UCSI_WRITE_SIZE])
{
u8 ec_req[] = MKREQ(0x03, UCSI_DATA_WRITE, GAOKUN_UCSI_WRITE_SIZE);
refill_req(ec_req, req, GAOKUN_UCSI_WRITE_SIZE);
return gaokun_ec_write(ec, ec_req);
}
EXPORT_SYMBOL_GPL(gaokun_ec_ucsi_write);
/**
* gaokun_ec_ucsi_get_reg - Get UCSI register from EC
* @ec: The gaokun_ec structure
* @ureg: The gaokun ucsi register
*
* Get UCSI register data (used by UCSI subdriver).
*
* Return: 0 on success or negative error code.
*/
int gaokun_ec_ucsi_get_reg(struct gaokun_ec *ec, struct gaokun_ucsi_reg *ureg)
{
u8 ec_req[] = MKREQ(0x03, UCSI_REG_READ, 0);
u8 ec_resp[] = MKRESP(UCSI_REG_SIZE);
int ret;
ret = gaokun_ec_read(ec, ec_req, sizeof(ec_resp), ec_resp);
if (ret)
return ret;
extr_resp((u8 *)ureg, ec_resp, UCSI_REG_SIZE);
return 0;
}
EXPORT_SYMBOL_GPL(gaokun_ec_ucsi_get_reg);
/**
* gaokun_ec_ucsi_pan_ack - Ack pin assignment notifications from EC
* @ec: The gaokun_ec structure
* @port_id: The port id receiving and handling the notifications
*
* Ack pin assignment notifications (used by UCSI subdriver).
*
* Return: 0 on success or negative error code.
*/
int gaokun_ec_ucsi_pan_ack(struct gaokun_ec *ec, int port_id)
{
u8 ec_req[] = MKREQ(0x03, UCSI_REG_WRITE, 1);
u8 data = 1 << port_id;
if (port_id == GAOKUN_UCSI_NO_PORT_UPDATE)
data = 0;
refill_req_byte(ec_req, &data);
return gaokun_ec_write(ec, ec_req);
}
EXPORT_SYMBOL_GPL(gaokun_ec_ucsi_pan_ack);
/* -------------------------------------------------------------------------- */
/* EC Sysfs */
/* Fn lock */
static int gaokun_ec_get_fn_lock(struct gaokun_ec *ec, bool *on)
{
/* GFRS */
u8 ec_req[] = MKREQ(0x02, EC_FN_LOCK_READ, 0);
int ret;
u8 state;
ret = gaokun_ec_read_byte(ec, ec_req, &state);
if (ret)
return ret;
if (state == EC_FN_LOCK_ON)
*on = true;
else if (state == EC_FN_LOCK_OFF)
*on = false;
else
return -EIO;
return 0;
}
static int gaokun_ec_set_fn_lock(struct gaokun_ec *ec, bool on)
{
/* SFRS */
u8 ec_req[] = MKREQ(0x02, EC_FN_LOCK_WRITE, 1,
on ? EC_FN_LOCK_ON : EC_FN_LOCK_OFF);
return gaokun_ec_write(ec, ec_req);
}
static ssize_t fn_lock_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct gaokun_ec *ec = dev_get_drvdata(dev);
bool on;
int ret;
ret = gaokun_ec_get_fn_lock(ec, &on);
if (ret)
return ret;
return sysfs_emit(buf, "%d\n", on);
}
static ssize_t fn_lock_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct gaokun_ec *ec = dev_get_drvdata(dev);
bool on;
int ret;
if (kstrtobool(buf, &on))
return -EINVAL;
ret = gaokun_ec_set_fn_lock(ec, on);
if (ret)
return ret;
return size;
}
static DEVICE_ATTR_RW(fn_lock);
static struct attribute *gaokun_ec_attrs[] = {
&dev_attr_fn_lock.attr,
NULL,
};
ATTRIBUTE_GROUPS(gaokun_ec);
/* -------------------------------------------------------------------------- */
/* Thermal Zone HwMon */
/* Range from 0 to 0x2C, partially valid */
static const u8 temp_reg[] = {
0x05, 0x07, 0x08, 0x0E, 0x0F, 0x12, 0x15, 0x1E,
0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
0x27, 0x28, 0x29, 0x2A
};
static int gaokun_ec_get_temp(struct gaokun_ec *ec, u8 idx, long *temp)
{
/* GTMP */
u8 ec_req[] = MKREQ(0x02, EC_TEMP_REG, 1, temp_reg[idx]);
u8 ec_resp[] = MKRESP(sizeof(__le16));
__le16 *tmp;
int ret;
ret = gaokun_ec_read(ec, ec_req, sizeof(ec_resp), ec_resp);
if (ret)
return ret;
tmp = (__le16 *)extr_resp_shallow(ec_resp);
*temp = le16_to_cpu(*tmp) * 100; /* convert to HwMon's unit */
return 0;
}
static umode_t
gaokun_ec_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
u32 attr, int channel)
{
return type == hwmon_temp ? 0444 : 0;
}
static int
gaokun_ec_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
struct gaokun_ec *ec = dev_get_drvdata(dev);
if (type == hwmon_temp)
return gaokun_ec_get_temp(ec, channel, val);
return -EINVAL;
}
static const struct hwmon_ops gaokun_ec_hwmon_ops = {
.is_visible = gaokun_ec_hwmon_is_visible,
.read = gaokun_ec_hwmon_read,
};
static u32 gaokun_ec_temp_config[] = {
[0 ... ARRAY_SIZE(temp_reg) - 1] = HWMON_T_INPUT,
0
};
static const struct hwmon_channel_info gaokun_ec_temp = {
.type = hwmon_temp,
.config = gaokun_ec_temp_config,
};
static const struct hwmon_channel_info * const gaokun_ec_hwmon_info[] = {
&gaokun_ec_temp,
NULL
};
static const struct hwmon_chip_info gaokun_ec_hwmon_chip_info = {
.ops = &gaokun_ec_hwmon_ops,
.info = gaokun_ec_hwmon_info,
};
/* -------------------------------------------------------------------------- */
/* Modern Standby */
static int gaokun_ec_suspend(struct device *dev)
{
struct gaokun_ec *ec = dev_get_drvdata(dev);
u8 ec_req[] = MKREQ(0x02, EC_STANDBY_REG, 1, EC_STANDBY_ENTER);
int ret;
if (ec->suspended)
return 0;
ret = gaokun_ec_write(ec, ec_req);
if (ret)
return ret;
ec->suspended = true;
return 0;
}
static int gaokun_ec_resume(struct device *dev)
{
struct gaokun_ec *ec = dev_get_drvdata(dev);
u8 ec_req[] = MKREQ(0x02, EC_STANDBY_REG, 1, EC_STANDBY_EXIT);
int ret;
int i;
if (!ec->suspended)
return 0;
for (i = 0; i < 3; ++i) {
ret = gaokun_ec_write(ec, ec_req);
if (ret == 0)
break;
msleep(100); /* EC need time to resume */
};
ec->suspended = false;
return 0;
}
static void gaokun_aux_release(struct device *dev)
{
struct auxiliary_device *adev = to_auxiliary_dev(dev);
kfree(adev);
}
static void gaokun_aux_remove(void *data)
{
struct auxiliary_device *adev = data;
auxiliary_device_delete(adev);
auxiliary_device_uninit(adev);
}
static int gaokun_aux_init(struct device *parent, const char *name,
struct gaokun_ec *ec)
{
struct auxiliary_device *adev;
int ret;
adev = kzalloc(sizeof(*adev), GFP_KERNEL);
if (!adev)
return -ENOMEM;
adev->name = name;
adev->id = 0;
adev->dev.parent = parent;
adev->dev.release = gaokun_aux_release;
adev->dev.platform_data = ec;
/* Allow aux devices to access parent's DT nodes directly */
device_set_of_node_from_dev(&adev->dev, parent);
ret = auxiliary_device_init(adev);
if (ret) {
kfree(adev);
return ret;
}
ret = auxiliary_device_add(adev);
if (ret) {
auxiliary_device_uninit(adev);
return ret;
}
return devm_add_action_or_reset(parent, gaokun_aux_remove, adev);
}
/* -------------------------------------------------------------------------- */
/* EC */
static irqreturn_t gaokun_ec_irq_handler(int irq, void *data)
{
struct gaokun_ec *ec = data;
u8 ec_req[] = MKREQ(EC_EVENT, EC_QUERY, 0);
u8 status, id;
int ret;
ret = gaokun_ec_read_byte(ec, ec_req, &id);
if (ret)
return IRQ_HANDLED;
switch (id) {
case 0x0: /* No event */
break;
case EC_EVENT_LID:
gaokun_ec_psy_read_byte(ec, EC_LID_STATE, &status);
status &= EC_LID_OPEN;
input_report_switch(ec->idev, SW_LID, !status);
input_sync(ec->idev);
break;
default:
blocking_notifier_call_chain(&ec->notifier_list, id, ec);
}
return IRQ_HANDLED;
}
static int gaokun_ec_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct gaokun_ec *ec;
int ret;
ec = devm_kzalloc(dev, sizeof(*ec), GFP_KERNEL);
if (!ec)
return -ENOMEM;
ret = devm_mutex_init(dev, &ec->lock);
if (ret)
return ret;
ec->client = client;
i2c_set_clientdata(client, ec);
BLOCKING_INIT_NOTIFIER_HEAD(&ec->notifier_list);
/* Lid switch */
ec->idev = devm_input_allocate_device(dev);
if (!ec->idev)
return -ENOMEM;
ec->idev->name = "LID";
ec->idev->phys = "gaokun-ec/input0";
input_set_capability(ec->idev, EV_SW, SW_LID);
ret = input_register_device(ec->idev);
if (ret)
return dev_err_probe(dev, ret, "Failed to register input device\n");
ret = gaokun_aux_init(dev, GAOKUN_DEV_PSY, ec);
if (ret)
return ret;
ret = gaokun_aux_init(dev, GAOKUN_DEV_UCSI, ec);
if (ret)
return ret;
ret = devm_request_threaded_irq(dev, client->irq, NULL,
gaokun_ec_irq_handler, IRQF_ONESHOT,
dev_name(dev), ec);
if (ret)
return dev_err_probe(dev, ret, "Failed to request IRQ\n");
ec->hwmon_dev = devm_hwmon_device_register_with_info(dev, "gaokun_ec_hwmon",
ec, &gaokun_ec_hwmon_chip_info, NULL);
if (IS_ERR(ec->hwmon_dev))
return dev_err_probe(dev, PTR_ERR(ec->hwmon_dev),
"Failed to register hwmon device\n");
return 0;
}
static const struct i2c_device_id gaokun_ec_id[] = {
{ "gaokun-ec", },
{ }
};
MODULE_DEVICE_TABLE(i2c, gaokun_ec_id);
static const struct of_device_id gaokun_ec_of_match[] = {
{ .compatible = "huawei,gaokun3-ec", },
{ }
};
MODULE_DEVICE_TABLE(of, gaokun_ec_of_match);
static const struct dev_pm_ops gaokun_ec_pm_ops = {
NOIRQ_SYSTEM_SLEEP_PM_OPS(gaokun_ec_suspend, gaokun_ec_resume)
};
static struct i2c_driver gaokun_ec_driver = {
.driver = {
.name = "gaokun-ec",
.of_match_table = gaokun_ec_of_match,
.pm = &gaokun_ec_pm_ops,
.dev_groups = gaokun_ec_groups,
},
.probe = gaokun_ec_probe,
.id_table = gaokun_ec_id,
};
module_i2c_driver(gaokun_ec_driver);
MODULE_DESCRIPTION("HUAWEI Matebook E Go EC driver");
MODULE_AUTHOR("Pengyu Luo <mitltlatltl@gmail.com>");
MODULE_LICENSE("GPL");

View File

@ -14,6 +14,19 @@ menuconfig MELLANOX_PLATFORM
if MELLANOX_PLATFORM
config MLX_PLATFORM
tristate "Mellanox Technologies platform support"
depends on ACPI && I2C && PCI
select REGMAP
help
This option enables system support for the Mellanox Technologies
platform. The Mellanox systems provide data center networking
solutions based on Virtual Protocol Interconnect (VPI) technology
enable seamless connectivity to 56/100Gb/s InfiniBand or 10/40/56GbE
connection.
If you have a Mellanox system, say Y or M here.
config MLXREG_HOTPLUG
tristate "Mellanox platform hotplug driver support"
depends on HWMON

View File

@ -3,6 +3,7 @@
# Makefile for linux/drivers/platform/mellanox
# Mellanox Platform-Specific Drivers
#
obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
obj-$(CONFIG_MLXBF_BOOTCTL) += mlxbf-bootctl.o
obj-$(CONFIG_MLXBF_PMC) += mlxbf-pmc.o
obj-$(CONFIG_MLXBF_TMFIFO) += mlxbf-tmfifo.o

View File

@ -145,7 +145,7 @@
#define MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET 0xd1
#define MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET 0xd2
#define MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET 0xd3
#define MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET 0xd9
#define MLXPLAT_CPLD_LPC_REG_CPLD6_MVER_OFFSET 0xd9
#define MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET 0xdb
#define MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET 0xda
#define MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET 0xdc
@ -2247,7 +2247,7 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_modular_data = {
.mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
};
/* Platform hotplug for NVLink blade systems family data */
/* Platform hotplug for NVLink blade systems family data */
static struct mlxreg_core_data mlxplat_mlxcpld_global_wp_items_data[] = {
{
.label = "global_wp_grant",
@ -2279,7 +2279,7 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_chassis_blade_data = {
.mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
};
/* Platform hotplug for switch systems family data */
/* Platform hotplug for switch systems family data */
static struct mlxreg_core_data mlxplat_mlxcpld_erot_ap_items_data[] = {
{
.label = "erot1_ap",
@ -2387,7 +2387,7 @@ static struct mlxreg_core_hotplug_notifier mlxplat_mlxcpld_l1_switch_pwr_events_
.user_handler = mlxplat_mlxcpld_l1_switch_pwr_events_handler,
};
/* Platform hotplug for l1 switch systems family data */
/* Platform hotplug for l1 switch systems family data */
static struct mlxreg_core_data mlxplat_mlxcpld_l1_switch_pwr_events_items_data[] = {
{
.label = "power_button",
@ -4401,7 +4401,7 @@ static struct mlxreg_core_platform_data mlxplat_modular_regs_io_data = {
.counter = ARRAY_SIZE(mlxplat_mlxcpld_modular_regs_io_data),
};
/* Platform register access for chassis blade systems family data */
/* Platform register access for chassis blade systems family data */
static struct mlxreg_core_data mlxplat_mlxcpld_chassis_blade_regs_io_data[] = {
{
.label = "cpld1_version",
@ -5050,7 +5050,6 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET:
case MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET:
case MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET:
case MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET:
@ -5186,7 +5185,7 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD6_MVER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET:
case MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET:
case MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET:
@ -5343,7 +5342,7 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD6_MVER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET:
case MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET:
case MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET:
@ -6573,7 +6572,7 @@ static int mlxplat_probe(struct platform_device *pdev)
}
/* Set default registers. */
for (i = 0; i < mlxplat_regmap_config->num_reg_defaults; i++) {
for (i = 0; i < mlxplat_regmap_config->num_reg_defaults; i++) {
err = regmap_write(priv->regmap,
mlxplat_regmap_config->reg_defaults[i].reg,
mlxplat_regmap_config->reg_defaults[i].def);

View File

@ -91,6 +91,7 @@ static const char * const mlxbf_rsh_log_level[] = {
static DEFINE_MUTEX(icm_ops_lock);
static DEFINE_MUTEX(os_up_lock);
static DEFINE_MUTEX(mfg_ops_lock);
static DEFINE_MUTEX(rtc_ops_lock);
/*
* Objects are stored within the MFG partition per type.
@ -489,6 +490,23 @@ static ssize_t large_icm_store(struct device *dev,
return res.a0 ? -EPERM : count;
}
static ssize_t rtc_battery_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct arm_smccc_res res;
mutex_lock(&rtc_ops_lock);
arm_smccc_smc(MLNX_HANDLE_GET_RTC_LOW_BATT, 0, 0, 0, 0,
0, 0, 0, &res);
mutex_unlock(&rtc_ops_lock);
if (res.a0)
return -EPERM;
return sysfs_emit(buf, "0x%lx\n", res.a1);
}
static ssize_t os_up_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@ -906,6 +924,7 @@ static DEVICE_ATTR_RW(sn);
static DEVICE_ATTR_RW(uuid);
static DEVICE_ATTR_RW(rev);
static DEVICE_ATTR_WO(mfg_lock);
static DEVICE_ATTR_RO(rtc_battery);
static struct attribute *mlxbf_bootctl_attrs[] = {
&dev_attr_post_reset_wdog.attr,
@ -925,6 +944,7 @@ static struct attribute *mlxbf_bootctl_attrs[] = {
&dev_attr_uuid.attr,
&dev_attr_rev.attr,
&dev_attr_mfg_lock.attr,
&dev_attr_rtc_battery.attr,
NULL
};

View File

@ -103,6 +103,11 @@
*/
#define MLNX_HANDLE_OS_UP 0x82000014
/*
* SMC function ID to get and clear the RTC low voltage bit
*/
#define MLNX_HANDLE_GET_RTC_LOW_BATT 0x82000023
/* SMC function IDs for SiP Service queries */
#define MLXBF_BOOTCTL_SIP_SVC_CALL_COUNT 0x8200ff00
#define MLXBF_BOOTCTL_SIP_SVC_UID 0x8200ff01

View File

@ -475,6 +475,17 @@ config IDEAPAD_LAPTOP
This is a driver for Lenovo IdeaPad netbooks contains drivers for
rfkill switch, hotkey, fan control and backlight control.
config LENOVO_WMI_HOTKEY_UTILITIES
tristate "Lenovo Hotkey Utility WMI extras driver"
depends on ACPI_WMI
select NEW_LEDS
select LEDS_CLASS
imply IDEAPAD_LAPTOP
help
This driver provides WMI support for Lenovo customized hotkeys function,
such as LED control for audio/mic mute event for Ideapad, YOGA, XiaoXin,
Gaming, ThinkBook and so on.
config LENOVO_YMC
tristate "Lenovo Yoga Tablet Mode Control"
depends on ACPI_WMI
@ -778,6 +789,23 @@ config BARCO_P50_GPIO
To compile this driver as a module, choose M here: the module
will be called barco-p50-gpio.
config SAMSUNG_GALAXYBOOK
tristate "Samsung Galaxy Book driver"
depends on ACPI
depends on ACPI_BATTERY
depends on INPUT
depends on LEDS_CLASS
depends on SERIO_I8042
select ACPI_PLATFORM_PROFILE
select FW_ATTR_CLASS
help
This is a driver for Samsung Galaxy Book series notebooks. It adds
support for the keyboard backlight control, performance mode control,
function keys, and various firmware attributes.
For more information about this driver, see
<file:Documentation/admin-guide/laptops/samsung-galaxybook.rst>.
config SAMSUNG_LAPTOP
tristate "Samsung Laptop driver"
depends on RFKILL || RFKILL = n
@ -1012,19 +1040,6 @@ config SERIAL_MULTI_INSTANTIATE
To compile this driver as a module, choose M here: the module
will be called serial-multi-instantiate.
config MLX_PLATFORM
tristate "Mellanox Technologies platform support"
depends on ACPI && I2C && PCI
select REGMAP
help
This option enables system support for the Mellanox Technologies
platform. The Mellanox systems provide data center networking
solutions based on Virtual Protocol Interconnect (VPI) technology
enable seamless connectivity to 56/100Gb/s InfiniBand or 10/40/56GbE
connection.
If you have a Mellanox system, say Y or M here.
config TOUCHSCREEN_DMI
bool "DMI based touchscreen configuration info"
depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD

View File

@ -61,6 +61,7 @@ obj-$(CONFIG_UV_SYSFS) += uv_sysfs.o
# IBM Thinkpad and Lenovo
obj-$(CONFIG_IBM_RTL) += ibm_rtl.o
obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o
obj-$(CONFIG_LENOVO_WMI_HOTKEY_UTILITIES) += lenovo-wmi-hotkey-utilities.o
obj-$(CONFIG_LENOVO_YMC) += lenovo-ymc.o
obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
@ -95,8 +96,9 @@ obj-$(CONFIG_PCENGINES_APU2) += pcengines-apuv2.o
obj-$(CONFIG_BARCO_P50_GPIO) += barco-p50-gpio.o
# Samsung
obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o
obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o
obj-$(CONFIG_SAMSUNG_GALAXYBOOK) += samsung-galaxybook.o
obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o
obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o
# Toshiba
obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o
@ -122,7 +124,6 @@ obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
# Platform drivers
obj-$(CONFIG_FW_ATTR_CLASS) += firmware_attributes_class.o
obj-$(CONFIG_SERIAL_MULTI_INSTANTIATE) += serial-multi-instantiate.o
obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
obj-$(CONFIG_TOUCHSCREEN_DMI) += touchscreen_dmi.o
obj-$(CONFIG_WIRELESS_HOTKEY) += wireless-hotkey.o
obj-$(CONFIG_X86_ANDROID_TABLETS) += x86-android-tablets/

View File

@ -5,7 +5,7 @@
#
obj-$(CONFIG_AMD_3D_VCACHE) += amd_3d_vcache.o
amd_3d_vcache-objs := x3d_vcache.o
amd_3d_vcache-y := x3d_vcache.o
obj-$(CONFIG_AMD_PMC) += pmc/
obj-$(CONFIG_AMD_HSMP) += hsmp/
obj-$(CONFIG_AMD_PMF) += pmf/

View File

@ -5,8 +5,8 @@
#
obj-$(CONFIG_AMD_HSMP) += hsmp_common.o
hsmp_common-objs := hsmp.o
hsmp_common-y := hsmp.o
obj-$(CONFIG_AMD_HSMP_PLAT) += amd_hsmp.o
amd_hsmp-objs := plat.o
amd_hsmp-y := plat.o
obj-$(CONFIG_AMD_HSMP_ACPI) += hsmp_acpi.o
hsmp_acpi-objs := acpi.o
hsmp_acpi-y := acpi.o

View File

@ -4,6 +4,6 @@
# AMD Power Management Controller Driver
#
amd-pmc-objs := pmc.o pmc-quirks.o mp1_stb.o
obj-$(CONFIG_AMD_PMC) += amd-pmc.o
amd-pmc-$(CONFIG_AMD_MP2_STB) += mp2_stb.o
obj-$(CONFIG_AMD_PMC) += amd-pmc.o
amd-pmc-y := pmc.o pmc-quirks.o mp1_stb.o
amd-pmc-$(CONFIG_AMD_MP2_STB) += mp2_stb.o

View File

@ -32,70 +32,6 @@
#include "pmc.h"
/* SMU communication registers */
#define AMD_PMC_REGISTER_RESPONSE 0x980
#define AMD_PMC_REGISTER_ARGUMENT 0x9BC
/* PMC Scratch Registers */
#define AMD_PMC_SCRATCH_REG_CZN 0x94
#define AMD_PMC_SCRATCH_REG_YC 0xD14
#define AMD_PMC_SCRATCH_REG_1AH 0xF14
/* STB Registers */
#define AMD_PMC_STB_S2IDLE_PREPARE 0xC6000001
#define AMD_PMC_STB_S2IDLE_RESTORE 0xC6000002
#define AMD_PMC_STB_S2IDLE_CHECK 0xC6000003
/* Base address of SMU for mapping physical address to virtual address */
#define AMD_PMC_MAPPING_SIZE 0x01000
#define AMD_PMC_BASE_ADDR_OFFSET 0x10000
#define AMD_PMC_BASE_ADDR_LO 0x13B102E8
#define AMD_PMC_BASE_ADDR_HI 0x13B102EC
#define AMD_PMC_BASE_ADDR_LO_MASK GENMASK(15, 0)
#define AMD_PMC_BASE_ADDR_HI_MASK GENMASK(31, 20)
/* SMU Response Codes */
#define AMD_PMC_RESULT_OK 0x01
#define AMD_PMC_RESULT_CMD_REJECT_BUSY 0xFC
#define AMD_PMC_RESULT_CMD_REJECT_PREREQ 0xFD
#define AMD_PMC_RESULT_CMD_UNKNOWN 0xFE
#define AMD_PMC_RESULT_FAILED 0xFF
/* FCH SSC Registers */
#define FCH_S0I3_ENTRY_TIME_L_OFFSET 0x30
#define FCH_S0I3_ENTRY_TIME_H_OFFSET 0x34
#define FCH_S0I3_EXIT_TIME_L_OFFSET 0x38
#define FCH_S0I3_EXIT_TIME_H_OFFSET 0x3C
#define FCH_SSC_MAPPING_SIZE 0x800
#define FCH_BASE_PHY_ADDR_LOW 0xFED81100
#define FCH_BASE_PHY_ADDR_HIGH 0x00000000
/* SMU Message Definations */
#define SMU_MSG_GETSMUVERSION 0x02
#define SMU_MSG_LOG_GETDRAM_ADDR_HI 0x04
#define SMU_MSG_LOG_GETDRAM_ADDR_LO 0x05
#define SMU_MSG_LOG_START 0x06
#define SMU_MSG_LOG_RESET 0x07
#define SMU_MSG_LOG_DUMP_DATA 0x08
#define SMU_MSG_GET_SUP_CONSTRAINTS 0x09
#define PMC_MSG_DELAY_MIN_US 50
#define RESPONSE_REGISTER_LOOP_MAX 20000
#define DELAY_MIN_US 2000
#define DELAY_MAX_US 3000
enum amd_pmc_def {
MSG_TEST = 0x01,
MSG_OS_HINT_PCO,
MSG_OS_HINT_RN,
};
struct amd_pmc_bit_map {
const char *name;
u32 bit_mask;
};
static const struct amd_pmc_bit_map soc15_ip_blk_v2[] = {
{"DISPLAY", BIT(0)},
{"CPU", BIT(1)},
@ -165,23 +101,6 @@ static inline void amd_pmc_reg_write(struct amd_pmc_dev *dev, int reg_offset, u3
iowrite32(val, dev->regbase + reg_offset);
}
struct smu_metrics {
u32 table_version;
u32 hint_count;
u32 s0i3_last_entry_status;
u32 timein_s0i2;
u64 timeentering_s0i3_lastcapture;
u64 timeentering_s0i3_totaltime;
u64 timeto_resume_to_os_lastcapture;
u64 timeto_resume_to_os_totaltime;
u64 timein_s0i3_lastcapture;
u64 timein_s0i3_totaltime;
u64 timein_swdrips_lastcapture;
u64 timein_swdrips_totaltime;
u64 timecondition_notmet_lastcapture[32];
u64 timecondition_notmet_totaltime[32];
} __packed;
static void amd_pmc_get_ip_info(struct amd_pmc_dev *dev)
{
switch (dev->cpu_id) {
@ -247,11 +166,12 @@ static int amd_pmc_setup_smu_logging(struct amd_pmc_dev *dev)
static int get_metrics_table(struct amd_pmc_dev *pdev, struct smu_metrics *table)
{
if (!pdev->smu_virt_addr) {
int ret = amd_pmc_setup_smu_logging(pdev);
int rc;
if (ret)
return ret;
if (!pdev->smu_virt_addr) {
rc = amd_pmc_setup_smu_logging(pdev);
if (rc)
return rc;
}
if (pdev->cpu_id == AMD_CPU_ID_PCO)
@ -300,10 +220,10 @@ static ssize_t smu_fw_version_show(struct device *d, struct device_attribute *at
char *buf)
{
struct amd_pmc_dev *dev = dev_get_drvdata(d);
int rc;
if (!dev->major) {
int rc = amd_pmc_get_smu_version(dev);
rc = amd_pmc_get_smu_version(dev);
if (rc)
return rc;
}
@ -314,10 +234,10 @@ static ssize_t smu_program_show(struct device *d, struct device_attribute *attr,
char *buf)
{
struct amd_pmc_dev *dev = dev_get_drvdata(d);
int rc;
if (!dev->major) {
int rc = amd_pmc_get_smu_version(dev);
rc = amd_pmc_get_smu_version(dev);
if (rc)
return rc;
}
@ -778,14 +698,14 @@ static struct acpi_s2idle_dev_ops amd_pmc_s2idle_dev_ops = {
static int amd_pmc_suspend_handler(struct device *dev)
{
struct amd_pmc_dev *pdev = dev_get_drvdata(dev);
int rc;
/*
* Must be called only from the same set of dev_pm_ops handlers
* as i8042_pm_suspend() is called: currently just from .suspend.
*/
if (pdev->disable_8042_wakeup && !disable_workarounds) {
int rc = amd_pmc_wa_irq1(pdev);
rc = amd_pmc_wa_irq1(pdev);
if (rc) {
dev_err(pdev->dev, "failed to adjust keyboard wakeup: %d\n", rc);
return rc;
@ -808,6 +728,7 @@ static const struct pci_device_id pmc_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PCO) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RV) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_SP) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_SHP) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M20H_ROOT) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M60H_ROOT) },
{ }
@ -823,7 +744,6 @@ static int amd_pmc_probe(struct platform_device *pdev)
u32 val;
dev->dev = &pdev->dev;
rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
if (!rdev || !pci_match_id(pmc_pci_ids, rdev)) {
err = -ENODEV;
@ -831,8 +751,7 @@ static int amd_pmc_probe(struct platform_device *pdev)
}
dev->cpu_id = rdev->device;
if (dev->cpu_id == AMD_CPU_ID_SP) {
if (dev->cpu_id == AMD_CPU_ID_SP || dev->cpu_id == AMD_CPU_ID_SHP) {
dev_warn_once(dev->dev, "S0i3 is not supported on this hardware\n");
err = -ENODEV;
goto err_pci_dev_put;
@ -847,7 +766,6 @@ static int amd_pmc_probe(struct platform_device *pdev)
}
base_addr_lo = val & AMD_PMC_BASE_ADDR_HI_MASK;
err = amd_smn_read(0, AMD_PMC_BASE_ADDR_HI, &val);
if (err) {
dev_err(dev->dev, "error reading 0x%x\n", AMD_PMC_BASE_ADDR_HI);
@ -865,7 +783,9 @@ static int amd_pmc_probe(struct platform_device *pdev)
goto err_pci_dev_put;
}
mutex_init(&dev->lock);
err = devm_mutex_init(dev->dev, &dev->lock);
if (err)
goto err_pci_dev_put;
/* Get num of IP blocks within the SoC */
amd_pmc_get_ip_info(dev);
@ -904,7 +824,6 @@ static void amd_pmc_remove(struct platform_device *pdev)
pci_dev_put(dev->rdev);
if (IS_ENABLED(CONFIG_AMD_MP2_STB))
amd_mp2_stb_deinit(dev);
mutex_destroy(&dev->lock);
}
static const struct acpi_device_id amd_pmc_acpi_ids[] = {

View File

@ -14,6 +14,59 @@
#include <linux/types.h>
#include <linux/mutex.h>
/* SMU communication registers */
#define AMD_PMC_REGISTER_RESPONSE 0x980
#define AMD_PMC_REGISTER_ARGUMENT 0x9BC
/* PMC Scratch Registers */
#define AMD_PMC_SCRATCH_REG_CZN 0x94
#define AMD_PMC_SCRATCH_REG_YC 0xD14
#define AMD_PMC_SCRATCH_REG_1AH 0xF14
/* STB Registers */
#define AMD_PMC_STB_S2IDLE_PREPARE 0xC6000001
#define AMD_PMC_STB_S2IDLE_RESTORE 0xC6000002
#define AMD_PMC_STB_S2IDLE_CHECK 0xC6000003
/* Base address of SMU for mapping physical address to virtual address */
#define AMD_PMC_MAPPING_SIZE 0x01000
#define AMD_PMC_BASE_ADDR_OFFSET 0x10000
#define AMD_PMC_BASE_ADDR_LO 0x13B102E8
#define AMD_PMC_BASE_ADDR_HI 0x13B102EC
#define AMD_PMC_BASE_ADDR_LO_MASK GENMASK(15, 0)
#define AMD_PMC_BASE_ADDR_HI_MASK GENMASK(31, 20)
/* SMU Response Codes */
#define AMD_PMC_RESULT_OK 0x01
#define AMD_PMC_RESULT_CMD_REJECT_BUSY 0xFC
#define AMD_PMC_RESULT_CMD_REJECT_PREREQ 0xFD
#define AMD_PMC_RESULT_CMD_UNKNOWN 0xFE
#define AMD_PMC_RESULT_FAILED 0xFF
/* FCH SSC Registers */
#define FCH_S0I3_ENTRY_TIME_L_OFFSET 0x30
#define FCH_S0I3_ENTRY_TIME_H_OFFSET 0x34
#define FCH_S0I3_EXIT_TIME_L_OFFSET 0x38
#define FCH_S0I3_EXIT_TIME_H_OFFSET 0x3C
#define FCH_SSC_MAPPING_SIZE 0x800
#define FCH_BASE_PHY_ADDR_LOW 0xFED81100
#define FCH_BASE_PHY_ADDR_HIGH 0x00000000
/* SMU Message Definations */
#define SMU_MSG_GETSMUVERSION 0x02
#define SMU_MSG_LOG_GETDRAM_ADDR_HI 0x04
#define SMU_MSG_LOG_GETDRAM_ADDR_LO 0x05
#define SMU_MSG_LOG_START 0x06
#define SMU_MSG_LOG_RESET 0x07
#define SMU_MSG_LOG_DUMP_DATA 0x08
#define SMU_MSG_GET_SUP_CONSTRAINTS 0x09
#define PMC_MSG_DELAY_MIN_US 50
#define RESPONSE_REGISTER_LOOP_MAX 20000
#define DELAY_MIN_US 2000
#define DELAY_MAX_US 3000
enum s2d_msg_port {
MSG_PORT_PMC,
MSG_PORT_S2D,
@ -65,6 +118,34 @@ struct amd_pmc_dev {
struct stb_arg stb_arg;
};
struct amd_pmc_bit_map {
const char *name;
u32 bit_mask;
};
struct smu_metrics {
u32 table_version;
u32 hint_count;
u32 s0i3_last_entry_status;
u32 timein_s0i2;
u64 timeentering_s0i3_lastcapture;
u64 timeentering_s0i3_totaltime;
u64 timeto_resume_to_os_lastcapture;
u64 timeto_resume_to_os_totaltime;
u64 timein_s0i3_lastcapture;
u64 timein_s0i3_totaltime;
u64 timein_swdrips_lastcapture;
u64 timein_swdrips_totaltime;
u64 timecondition_notmet_lastcapture[32];
u64 timecondition_notmet_totaltime[32];
} __packed;
enum amd_pmc_def {
MSG_TEST = 0x01,
MSG_OS_HINT_PCO,
MSG_OS_HINT_RN,
};
void amd_pmc_process_restore_quirks(struct amd_pmc_dev *dev);
void amd_pmc_quirks_init(struct amd_pmc_dev *dev);
void amd_mp2_stb_init(struct amd_pmc_dev *dev);
@ -79,6 +160,7 @@ void amd_mp2_stb_deinit(struct amd_pmc_dev *dev);
#define AMD_CPU_ID_CB 0x14D8
#define AMD_CPU_ID_PS 0x14E8
#define AMD_CPU_ID_SP 0x14A4
#define AMD_CPU_ID_SHP 0x153A
#define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507
#define PCI_DEVICE_ID_AMD_1AH_M60H_ROOT 0x1122
#define PCI_DEVICE_ID_AMD_MP2_STB 0x172c

View File

@ -4,7 +4,7 @@
# AMD Platform Management Framework
#
obj-$(CONFIG_AMD_PMF) += amd-pmf.o
amd-pmf-objs := core.o acpi.o sps.o \
auto-mode.o cnqf.o \
tee-if.o spc.o
obj-$(CONFIG_AMD_PMF) += amd-pmf.o
amd-pmf-y := core.o acpi.o sps.o \
auto-mode.o cnqf.o \
tee-if.o spc.o

View File

@ -220,7 +220,7 @@ static void apmf_sbios_heartbeat_notify(struct work_struct *work)
if (!info)
return;
schedule_delayed_work(&dev->heart_beat, msecs_to_jiffies(dev->hb_interval * 1000));
schedule_delayed_work(&dev->heart_beat, secs_to_jiffies(dev->hb_interval));
kfree(info);
}

View File

@ -856,7 +856,7 @@ static int tf103c_dock_probe(struct i2c_client *client)
/* 5. Setup irqchip for touchpad IRQ pass-through */
dock->tp_irqchip.name = KBUILD_MODNAME;
dock->tp_irq_domain = irq_domain_add_linear(NULL, 1, &irq_domain_simple_ops, NULL);
dock->tp_irq_domain = irq_domain_create_linear(NULL, 1, &irq_domain_simple_ops, NULL);
if (!dock->tp_irq_domain)
return -ENOMEM;

View File

@ -69,7 +69,6 @@
#include <linux/hwmon-sysfs.h>
#include <linux/power_supply.h>
#include <linux/sysfs.h>
#include <linux/fb.h>
#include <acpi/video.h>
/* ======= */

View File

@ -18,15 +18,35 @@ config ALIENWARE_WMI
tristate "Alienware Special feature control"
default m
depends on ACPI
depends on ACPI_WMI
depends on DMI
depends on LEDS_CLASS
depends on NEW_LEDS
depends on ACPI_WMI
help
This is a driver for controlling Alienware WMI driven features.
On legacy devices, it exposes an interface for controlling the AlienFX
zones on Alienware machines that don't contain a dedicated
AlienFX USB MCU such as the X51 and X51-R2.
On newer devices, it exposes the AWCC thermal control interface through
known Kernel APIs.
config ALIENWARE_WMI_LEGACY
bool "Alienware Legacy WMI device driver"
default y
depends on ALIENWARE_WMI
help
Legacy Alienware WMI driver with AlienFX LED control capabilities.
config ALIENWARE_WMI_WMAX
bool "Alienware WMAX WMI device driver"
default y
depends on ALIENWARE_WMI
select ACPI_PLATFORM_PROFILE
help
This is a driver for controlling Alienware BIOS driven
features. It exposes an interface for controlling the AlienFX
zones on Alienware machines that don't contain a dedicated AlienFX
USB MCU such as the X51 and X51-R2.
Alienware WMI driver with AlienFX LED, HDMI, amplifier, deep sleep and
AWCC thermal control capabilities.
config DCDBAS
tristate "Dell Systems Management Base Driver"

View File

@ -4,24 +4,27 @@
# Dell x86 Platform-Specific Drivers
#
obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o
obj-$(CONFIG_DCDBAS) += dcdbas.o
obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o
obj-$(CONFIG_DELL_RBTN) += dell-rbtn.o
obj-$(CONFIG_DELL_RBU) += dell_rbu.o
obj-$(CONFIG_DELL_PC) += dell-pc.o
obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o
dell-smbios-objs := dell-smbios-base.o
dell-smbios-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o
dell-smbios-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o
obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o
obj-$(CONFIG_DELL_SMO8800) += dell-lis3lv02d.o
obj-$(CONFIG_DELL_UART_BACKLIGHT) += dell-uart-backlight.o
obj-$(CONFIG_DELL_WMI) += dell-wmi.o
dell-wmi-objs := dell-wmi-base.o
dell-wmi-$(CONFIG_DELL_WMI_PRIVACY) += dell-wmi-privacy.o
obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o
obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o
obj-$(CONFIG_DELL_WMI_DDV) += dell-wmi-ddv.o
obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o
obj-$(CONFIG_DELL_WMI_SYSMAN) += dell-wmi-sysman/
obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o
alienware-wmi-y := alienware-wmi-base.o
alienware-wmi-$(CONFIG_ALIENWARE_WMI_LEGACY) += alienware-wmi-legacy.o
alienware-wmi-$(CONFIG_ALIENWARE_WMI_WMAX) += alienware-wmi-wmax.o
obj-$(CONFIG_DCDBAS) += dcdbas.o
obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o
obj-$(CONFIG_DELL_RBTN) += dell-rbtn.o
obj-$(CONFIG_DELL_RBU) += dell_rbu.o
obj-$(CONFIG_DELL_PC) += dell-pc.o
obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o
dell-smbios-y := dell-smbios-base.o
dell-smbios-$(CONFIG_DELL_SMBIOS_WMI) += dell-smbios-wmi.o
dell-smbios-$(CONFIG_DELL_SMBIOS_SMM) += dell-smbios-smm.o
obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o
obj-$(CONFIG_DELL_SMO8800) += dell-lis3lv02d.o
obj-$(CONFIG_DELL_UART_BACKLIGHT) += dell-uart-backlight.o
obj-$(CONFIG_DELL_WMI) += dell-wmi.o
dell-wmi-y := dell-wmi-base.o
dell-wmi-$(CONFIG_DELL_WMI_PRIVACY) += dell-wmi-privacy.o
obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o
obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o
obj-$(CONFIG_DELL_WMI_DDV) += dell-wmi-ddv.o
obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o
obj-$(CONFIG_DELL_WMI_SYSMAN) += dell-wmi-sysman/

View File

@ -0,0 +1,491 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Alienware special feature control
*
* Copyright (C) 2014 Dell Inc <Dell.Client.Kernel@dell.com>
* Copyright (C) 2025 Kurt Borja <kuurtb@gmail.com>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/acpi.h>
#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/dmi.h>
#include <linux/leds.h>
#include "alienware-wmi.h"
MODULE_AUTHOR("Mario Limonciello <mario.limonciello@outlook.com>");
MODULE_AUTHOR("Kurt Borja <kuurtb@gmail.com>");
MODULE_DESCRIPTION("Alienware special feature control");
MODULE_LICENSE("GPL");
struct alienfx_quirks *alienfx;
static struct alienfx_quirks quirk_inspiron5675 = {
.num_zones = 2,
.hdmi_mux = false,
.amplifier = false,
.deepslp = false,
};
static struct alienfx_quirks quirk_unknown = {
.num_zones = 2,
.hdmi_mux = false,
.amplifier = false,
.deepslp = false,
};
static struct alienfx_quirks quirk_x51_r1_r2 = {
.num_zones = 3,
.hdmi_mux = false,
.amplifier = false,
.deepslp = false,
};
static struct alienfx_quirks quirk_x51_r3 = {
.num_zones = 4,
.hdmi_mux = false,
.amplifier = true,
.deepslp = false,
};
static struct alienfx_quirks quirk_asm100 = {
.num_zones = 2,
.hdmi_mux = true,
.amplifier = false,
.deepslp = false,
};
static struct alienfx_quirks quirk_asm200 = {
.num_zones = 2,
.hdmi_mux = true,
.amplifier = false,
.deepslp = true,
};
static struct alienfx_quirks quirk_asm201 = {
.num_zones = 2,
.hdmi_mux = true,
.amplifier = true,
.deepslp = true,
};
static int __init dmi_matched(const struct dmi_system_id *dmi)
{
alienfx = dmi->driver_data;
return 1;
}
static const struct dmi_system_id alienware_quirks[] __initconst = {
{
.callback = dmi_matched,
.ident = "Alienware ASM100",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "ASM100"),
},
.driver_data = &quirk_asm100,
},
{
.callback = dmi_matched,
.ident = "Alienware ASM200",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "ASM200"),
},
.driver_data = &quirk_asm200,
},
{
.callback = dmi_matched,
.ident = "Alienware ASM201",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "ASM201"),
},
.driver_data = &quirk_asm201,
},
{
.callback = dmi_matched,
.ident = "Alienware X51 R1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51"),
},
.driver_data = &quirk_x51_r1_r2,
},
{
.callback = dmi_matched,
.ident = "Alienware X51 R2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R2"),
},
.driver_data = &quirk_x51_r1_r2,
},
{
.callback = dmi_matched,
.ident = "Alienware X51 R3",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R3"),
},
.driver_data = &quirk_x51_r3,
},
{
.callback = dmi_matched,
.ident = "Dell Inc. Inspiron 5675",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5675"),
},
.driver_data = &quirk_inspiron5675,
},
{}
};
u8 alienware_interface;
int alienware_wmi_command(struct wmi_device *wdev, u32 method_id,
void *in_args, size_t in_size, u32 *out_data)
{
struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
struct acpi_buffer in = {in_size, in_args};
acpi_status ret;
ret = wmidev_evaluate_method(wdev, 0, method_id, &in, out_data ? &out : NULL);
if (ACPI_FAILURE(ret))
return -EIO;
union acpi_object *obj __free(kfree) = out.pointer;
if (out_data) {
if (obj && obj->type == ACPI_TYPE_INTEGER)
*out_data = (u32)obj->integer.value;
else
return -ENOMSG;
}
return 0;
}
/*
* Helpers used for zone control
*/
static int parse_rgb(const char *buf, struct color_platform *colors)
{
long unsigned int rgb;
int ret;
union color_union {
struct color_platform cp;
int package;
} repackager;
ret = kstrtoul(buf, 16, &rgb);
if (ret)
return ret;
/* RGB triplet notation is 24-bit hexadecimal */
if (rgb > 0xFFFFFF)
return -EINVAL;
repackager.package = rgb & 0x0f0f0f0f;
pr_debug("alienware-wmi: r: %d g:%d b: %d\n",
repackager.cp.red, repackager.cp.green, repackager.cp.blue);
*colors = repackager.cp;
return 0;
}
/*
* Individual RGB zone control
*/
static ssize_t zone_show(struct device *dev, struct device_attribute *attr,
char *buf, u8 location)
{
struct alienfx_priv *priv = dev_get_drvdata(dev);
struct color_platform *colors = &priv->colors[location];
return sprintf(buf, "red: %d, green: %d, blue: %d\n",
colors->red, colors->green, colors->blue);
}
static ssize_t zone_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count, u8 location)
{
struct alienfx_priv *priv = dev_get_drvdata(dev);
struct color_platform *colors = &priv->colors[location];
struct alienfx_platdata *pdata = dev_get_platdata(dev);
int ret;
ret = parse_rgb(buf, colors);
if (ret)
return ret;
ret = pdata->ops.upd_led(priv, pdata->wdev, location);
return ret ? ret : count;
}
static ssize_t zone00_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return zone_show(dev, attr, buf, 0);
}
static ssize_t zone00_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
return zone_store(dev, attr, buf, count, 0);
}
static DEVICE_ATTR_RW(zone00);
static ssize_t zone01_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return zone_show(dev, attr, buf, 1);
}
static ssize_t zone01_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
return zone_store(dev, attr, buf, count, 1);
}
static DEVICE_ATTR_RW(zone01);
static ssize_t zone02_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return zone_show(dev, attr, buf, 2);
}
static ssize_t zone02_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
return zone_store(dev, attr, buf, count, 2);
}
static DEVICE_ATTR_RW(zone02);
static ssize_t zone03_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return zone_show(dev, attr, buf, 3);
}
static ssize_t zone03_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
return zone_store(dev, attr, buf, count, 3);
}
static DEVICE_ATTR_RW(zone03);
/*
* Lighting control state device attribute (Global)
*/
static ssize_t lighting_control_state_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct alienfx_priv *priv = dev_get_drvdata(dev);
if (priv->lighting_control_state == LEGACY_BOOTING)
return sysfs_emit(buf, "[booting] running suspend\n");
else if (priv->lighting_control_state == LEGACY_SUSPEND)
return sysfs_emit(buf, "booting running [suspend]\n");
return sysfs_emit(buf, "booting [running] suspend\n");
}
static ssize_t lighting_control_state_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct alienfx_priv *priv = dev_get_drvdata(dev);
u8 val;
if (strcmp(buf, "booting\n") == 0)
val = LEGACY_BOOTING;
else if (strcmp(buf, "suspend\n") == 0)
val = LEGACY_SUSPEND;
else if (alienware_interface == LEGACY)
val = LEGACY_RUNNING;
else
val = WMAX_RUNNING;
priv->lighting_control_state = val;
pr_debug("alienware-wmi: updated control state to %d\n",
priv->lighting_control_state);
return count;
}
static DEVICE_ATTR_RW(lighting_control_state);
static umode_t zone_attr_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
if (n < alienfx->num_zones + 1)
return attr->mode;
return 0;
}
static bool zone_group_visible(struct kobject *kobj)
{
return alienfx->num_zones > 0;
}
DEFINE_SYSFS_GROUP_VISIBLE(zone);
static struct attribute *zone_attrs[] = {
&dev_attr_lighting_control_state.attr,
&dev_attr_zone00.attr,
&dev_attr_zone01.attr,
&dev_attr_zone02.attr,
&dev_attr_zone03.attr,
NULL
};
static struct attribute_group zone_attribute_group = {
.name = "rgb_zones",
.is_visible = SYSFS_GROUP_VISIBLE(zone),
.attrs = zone_attrs,
};
/*
* LED Brightness (Global)
*/
static void global_led_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct alienfx_priv *priv = container_of(led_cdev, struct alienfx_priv,
global_led);
struct alienfx_platdata *pdata = dev_get_platdata(&priv->pdev->dev);
int ret;
priv->global_brightness = brightness;
ret = pdata->ops.upd_brightness(priv, pdata->wdev, brightness);
if (ret)
pr_err("LED brightness update failed\n");
}
static enum led_brightness global_led_get(struct led_classdev *led_cdev)
{
struct alienfx_priv *priv = container_of(led_cdev, struct alienfx_priv,
global_led);
return priv->global_brightness;
}
/*
* Platform Driver
*/
static int alienfx_probe(struct platform_device *pdev)
{
struct alienfx_priv *priv;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
if (alienware_interface == WMAX)
priv->lighting_control_state = WMAX_RUNNING;
else
priv->lighting_control_state = LEGACY_RUNNING;
priv->pdev = pdev;
priv->global_led.name = "alienware::global_brightness";
priv->global_led.brightness_set = global_led_set;
priv->global_led.brightness_get = global_led_get;
priv->global_led.max_brightness = 0x0F;
priv->global_brightness = priv->global_led.max_brightness;
platform_set_drvdata(pdev, priv);
return devm_led_classdev_register(&pdev->dev, &priv->global_led);
}
static const struct attribute_group *alienfx_groups[] = {
&zone_attribute_group,
WMAX_DEV_GROUPS
NULL
};
static struct platform_driver platform_driver = {
.driver = {
.name = "alienware-wmi",
.dev_groups = alienfx_groups,
},
.probe = alienfx_probe,
};
static void alienware_alienfx_remove(void *data)
{
struct platform_device *pdev = data;
platform_device_unregister(pdev);
}
int alienware_alienfx_setup(struct alienfx_platdata *pdata)
{
struct device *dev = &pdata->wdev->dev;
struct platform_device *pdev;
int ret;
pdev = platform_device_register_data(NULL, "alienware-wmi",
PLATFORM_DEVID_NONE, pdata,
sizeof(*pdata));
if (IS_ERR(pdev))
return PTR_ERR(pdev);
dev_set_drvdata(dev, pdev);
ret = devm_add_action_or_reset(dev, alienware_alienfx_remove, pdev);
if (ret)
return ret;
return 0;
}
static int __init alienware_wmi_init(void)
{
int ret;
dmi_check_system(alienware_quirks);
if (!alienfx)
alienfx = &quirk_unknown;
ret = platform_driver_register(&platform_driver);
if (ret < 0)
return ret;
if (wmi_has_guid(WMAX_CONTROL_GUID)) {
alienware_interface = WMAX;
ret = alienware_wmax_wmi_init();
} else {
alienware_interface = LEGACY;
ret = alienware_legacy_wmi_init();
}
if (ret < 0)
platform_driver_unregister(&platform_driver);
return ret;
}
module_init(alienware_wmi_init);
static void __exit alienware_wmi_exit(void)
{
if (alienware_interface == WMAX)
alienware_wmax_wmi_exit();
else
alienware_legacy_wmi_exit();
platform_driver_unregister(&platform_driver);
}
module_exit(alienware_wmi_exit);

View File

@ -0,0 +1,95 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Alienware LEGACY WMI device driver
*
* Copyright (C) 2025 Kurt Borja <kuurtb@gmail.com>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/wmi.h>
#include "alienware-wmi.h"
struct legacy_led_args {
struct color_platform colors;
u8 brightness;
u8 state;
} __packed;
/*
* Legacy WMI driver
*/
static int legacy_wmi_update_led(struct alienfx_priv *priv,
struct wmi_device *wdev, u8 location)
{
struct legacy_led_args legacy_args = {
.colors = priv->colors[location],
.brightness = priv->global_brightness,
.state = 0,
};
struct acpi_buffer input;
acpi_status status;
if (legacy_args.state != LEGACY_RUNNING) {
legacy_args.state = priv->lighting_control_state;
input.length = sizeof(legacy_args);
input.pointer = &legacy_args;
status = wmi_evaluate_method(LEGACY_POWER_CONTROL_GUID, 0,
location + 1, &input, NULL);
if (ACPI_FAILURE(status))
return -EIO;
return 0;
}
return alienware_wmi_command(wdev, location + 1, &legacy_args,
sizeof(legacy_args), NULL);
}
static int legacy_wmi_update_brightness(struct alienfx_priv *priv,
struct wmi_device *wdev, u8 brightness)
{
return legacy_wmi_update_led(priv, wdev, 0);
}
static int legacy_wmi_probe(struct wmi_device *wdev, const void *context)
{
struct alienfx_platdata pdata = {
.wdev = wdev,
.ops = {
.upd_led = legacy_wmi_update_led,
.upd_brightness = legacy_wmi_update_brightness,
},
};
return alienware_alienfx_setup(&pdata);
}
static const struct wmi_device_id alienware_legacy_device_id_table[] = {
{ LEGACY_CONTROL_GUID, NULL },
{ },
};
MODULE_DEVICE_TABLE(wmi, alienware_legacy_device_id_table);
static struct wmi_driver alienware_legacy_wmi_driver = {
.driver = {
.name = "alienware-wmi-alienfx",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.id_table = alienware_legacy_device_id_table,
.probe = legacy_wmi_probe,
.no_singleton = true,
};
int __init alienware_legacy_wmi_init(void)
{
return wmi_driver_register(&alienware_legacy_wmi_driver);
}
void __exit alienware_legacy_wmi_exit(void)
{
wmi_driver_unregister(&alienware_legacy_wmi_driver);
}

View File

@ -0,0 +1,768 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Alienware WMAX WMI device driver
*
* Copyright (C) 2014 Dell Inc <Dell.Client.Kernel@dell.com>
* Copyright (C) 2025 Kurt Borja <kuurtb@gmail.com>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/dmi.h>
#include <linux/moduleparam.h>
#include <linux/platform_profile.h>
#include <linux/wmi.h>
#include "alienware-wmi.h"
#define WMAX_METHOD_HDMI_SOURCE 0x1
#define WMAX_METHOD_HDMI_STATUS 0x2
#define WMAX_METHOD_HDMI_CABLE 0x5
#define WMAX_METHOD_AMPLIFIER_CABLE 0x6
#define WMAX_METHOD_DEEP_SLEEP_CONTROL 0x0B
#define WMAX_METHOD_DEEP_SLEEP_STATUS 0x0C
#define WMAX_METHOD_BRIGHTNESS 0x3
#define WMAX_METHOD_ZONE_CONTROL 0x4
#define WMAX_METHOD_THERMAL_INFORMATION 0x14
#define WMAX_METHOD_THERMAL_CONTROL 0x15
#define WMAX_METHOD_GAME_SHIFT_STATUS 0x25
#define WMAX_THERMAL_MODE_GMODE 0xAB
#define WMAX_FAILURE_CODE 0xFFFFFFFF
#define WMAX_THERMAL_TABLE_MASK GENMASK(7, 4)
#define WMAX_THERMAL_MODE_MASK GENMASK(3, 0)
#define WMAX_SENSOR_ID_MASK BIT(8)
static bool force_platform_profile;
module_param_unsafe(force_platform_profile, bool, 0);
MODULE_PARM_DESC(force_platform_profile, "Forces auto-detecting thermal profiles without checking if WMI thermal backend is available");
static bool force_gmode;
module_param_unsafe(force_gmode, bool, 0);
MODULE_PARM_DESC(force_gmode, "Forces G-Mode when performance profile is selected");
struct awcc_quirks {
bool pprof;
bool gmode;
};
static struct awcc_quirks g_series_quirks = {
.pprof = true,
.gmode = true,
};
static struct awcc_quirks generic_quirks = {
.pprof = true,
.gmode = false,
};
static struct awcc_quirks empty_quirks;
static const struct dmi_system_id awcc_dmi_table[] __initconst = {
{
.ident = "Alienware m16 R1 AMD",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m16 R1 AMD"),
},
.driver_data = &generic_quirks,
},
{
.ident = "Alienware m17 R5",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m17 R5 AMD"),
},
.driver_data = &generic_quirks,
},
{
.ident = "Alienware m18 R2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m18 R2"),
},
.driver_data = &generic_quirks,
},
{
.ident = "Alienware x15 R1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x15 R1"),
},
.driver_data = &generic_quirks,
},
{
.ident = "Alienware x17 R2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x17 R2"),
},
.driver_data = &generic_quirks,
},
{
.ident = "Dell Inc. G15 5510",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5510"),
},
.driver_data = &g_series_quirks,
},
{
.ident = "Dell Inc. G15 5511",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5511"),
},
.driver_data = &g_series_quirks,
},
{
.ident = "Dell Inc. G15 5515",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5515"),
},
.driver_data = &g_series_quirks,
},
{
.ident = "Dell Inc. G3 3500",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "G3 3500"),
},
.driver_data = &g_series_quirks,
},
{
.ident = "Dell Inc. G3 3590",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "G3 3590"),
},
.driver_data = &g_series_quirks,
},
{
.ident = "Dell Inc. G5 5500",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "G5 5500"),
},
.driver_data = &g_series_quirks,
},
};
enum WMAX_THERMAL_INFORMATION_OPERATIONS {
WMAX_OPERATION_SYS_DESCRIPTION = 0x02,
WMAX_OPERATION_LIST_IDS = 0x03,
WMAX_OPERATION_CURRENT_PROFILE = 0x0B,
};
enum WMAX_THERMAL_CONTROL_OPERATIONS {
WMAX_OPERATION_ACTIVATE_PROFILE = 0x01,
};
enum WMAX_GAME_SHIFT_STATUS_OPERATIONS {
WMAX_OPERATION_TOGGLE_GAME_SHIFT = 0x01,
WMAX_OPERATION_GET_GAME_SHIFT_STATUS = 0x02,
};
enum WMAX_THERMAL_TABLES {
WMAX_THERMAL_TABLE_BASIC = 0x90,
WMAX_THERMAL_TABLE_USTT = 0xA0,
};
enum wmax_thermal_mode {
THERMAL_MODE_USTT_BALANCED,
THERMAL_MODE_USTT_BALANCED_PERFORMANCE,
THERMAL_MODE_USTT_COOL,
THERMAL_MODE_USTT_QUIET,
THERMAL_MODE_USTT_PERFORMANCE,
THERMAL_MODE_USTT_LOW_POWER,
THERMAL_MODE_BASIC_QUIET,
THERMAL_MODE_BASIC_BALANCED,
THERMAL_MODE_BASIC_BALANCED_PERFORMANCE,
THERMAL_MODE_BASIC_PERFORMANCE,
THERMAL_MODE_LAST,
};
struct wmax_led_args {
u32 led_mask;
struct color_platform colors;
u8 state;
} __packed;
struct wmax_brightness_args {
u32 led_mask;
u32 percentage;
};
struct wmax_basic_args {
u8 arg;
};
struct wmax_u32_args {
u8 operation;
u8 arg1;
u8 arg2;
u8 arg3;
};
struct awcc_priv {
struct wmi_device *wdev;
struct device *ppdev;
enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST];
};
static const enum platform_profile_option wmax_mode_to_platform_profile[THERMAL_MODE_LAST] = {
[THERMAL_MODE_USTT_BALANCED] = PLATFORM_PROFILE_BALANCED,
[THERMAL_MODE_USTT_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE,
[THERMAL_MODE_USTT_COOL] = PLATFORM_PROFILE_COOL,
[THERMAL_MODE_USTT_QUIET] = PLATFORM_PROFILE_QUIET,
[THERMAL_MODE_USTT_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE,
[THERMAL_MODE_USTT_LOW_POWER] = PLATFORM_PROFILE_LOW_POWER,
[THERMAL_MODE_BASIC_QUIET] = PLATFORM_PROFILE_QUIET,
[THERMAL_MODE_BASIC_BALANCED] = PLATFORM_PROFILE_BALANCED,
[THERMAL_MODE_BASIC_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE,
[THERMAL_MODE_BASIC_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE,
};
static struct awcc_quirks *awcc;
/*
* The HDMI mux sysfs node indicates the status of the HDMI input mux.
* It can toggle between standard system GPU output and HDMI input.
*/
static ssize_t cable_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct alienfx_platdata *pdata = dev_get_platdata(dev);
struct wmax_basic_args in_args = {
.arg = 0,
};
u32 out_data;
int ret;
ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_HDMI_CABLE,
&in_args, sizeof(in_args), &out_data);
if (!ret) {
if (out_data == 0)
return sysfs_emit(buf, "[unconnected] connected unknown\n");
else if (out_data == 1)
return sysfs_emit(buf, "unconnected [connected] unknown\n");
}
pr_err("alienware-wmi: unknown HDMI cable status: %d\n", ret);
return sysfs_emit(buf, "unconnected connected [unknown]\n");
}
static ssize_t source_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct alienfx_platdata *pdata = dev_get_platdata(dev);
struct wmax_basic_args in_args = {
.arg = 0,
};
u32 out_data;
int ret;
ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_HDMI_STATUS,
&in_args, sizeof(in_args), &out_data);
if (!ret) {
if (out_data == 1)
return sysfs_emit(buf, "[input] gpu unknown\n");
else if (out_data == 2)
return sysfs_emit(buf, "input [gpu] unknown\n");
}
pr_err("alienware-wmi: unknown HDMI source status: %u\n", ret);
return sysfs_emit(buf, "input gpu [unknown]\n");
}
static ssize_t source_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct alienfx_platdata *pdata = dev_get_platdata(dev);
struct wmax_basic_args args;
int ret;
if (strcmp(buf, "gpu\n") == 0)
args.arg = 1;
else if (strcmp(buf, "input\n") == 0)
args.arg = 2;
else
args.arg = 3;
pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf);
ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_HDMI_SOURCE, &args,
sizeof(args), NULL);
if (ret < 0)
pr_err("alienware-wmi: HDMI toggle failed: results: %u\n", ret);
return count;
}
static DEVICE_ATTR_RO(cable);
static DEVICE_ATTR_RW(source);
static bool hdmi_group_visible(struct kobject *kobj)
{
return alienware_interface == WMAX && alienfx->hdmi_mux;
}
DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(hdmi);
static struct attribute *hdmi_attrs[] = {
&dev_attr_cable.attr,
&dev_attr_source.attr,
NULL,
};
const struct attribute_group wmax_hdmi_attribute_group = {
.name = "hdmi",
.is_visible = SYSFS_GROUP_VISIBLE(hdmi),
.attrs = hdmi_attrs,
};
/*
* Alienware GFX amplifier support
* - Currently supports reading cable status
* - Leaving expansion room to possibly support dock/undock events later
*/
static ssize_t status_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct alienfx_platdata *pdata = dev_get_platdata(dev);
struct wmax_basic_args in_args = {
.arg = 0,
};
u32 out_data;
int ret;
ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_AMPLIFIER_CABLE,
&in_args, sizeof(in_args), &out_data);
if (!ret) {
if (out_data == 0)
return sysfs_emit(buf, "[unconnected] connected unknown\n");
else if (out_data == 1)
return sysfs_emit(buf, "unconnected [connected] unknown\n");
}
pr_err("alienware-wmi: unknown amplifier cable status: %d\n", ret);
return sysfs_emit(buf, "unconnected connected [unknown]\n");
}
static DEVICE_ATTR_RO(status);
static bool amplifier_group_visible(struct kobject *kobj)
{
return alienware_interface == WMAX && alienfx->amplifier;
}
DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(amplifier);
static struct attribute *amplifier_attrs[] = {
&dev_attr_status.attr,
NULL,
};
const struct attribute_group wmax_amplifier_attribute_group = {
.name = "amplifier",
.is_visible = SYSFS_GROUP_VISIBLE(amplifier),
.attrs = amplifier_attrs,
};
/*
* Deep Sleep Control support
* - Modifies BIOS setting for deep sleep control allowing extra wakeup events
*/
static ssize_t deepsleep_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct alienfx_platdata *pdata = dev_get_platdata(dev);
struct wmax_basic_args in_args = {
.arg = 0,
};
u32 out_data;
int ret;
ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_DEEP_SLEEP_STATUS,
&in_args, sizeof(in_args), &out_data);
if (!ret) {
if (out_data == 0)
return sysfs_emit(buf, "[disabled] s5 s5_s4\n");
else if (out_data == 1)
return sysfs_emit(buf, "disabled [s5] s5_s4\n");
else if (out_data == 2)
return sysfs_emit(buf, "disabled s5 [s5_s4]\n");
}
pr_err("alienware-wmi: unknown deep sleep status: %d\n", ret);
return sysfs_emit(buf, "disabled s5 s5_s4 [unknown]\n");
}
static ssize_t deepsleep_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct alienfx_platdata *pdata = dev_get_platdata(dev);
struct wmax_basic_args args;
int ret;
if (strcmp(buf, "disabled\n") == 0)
args.arg = 0;
else if (strcmp(buf, "s5\n") == 0)
args.arg = 1;
else
args.arg = 2;
pr_debug("alienware-wmi: setting deep sleep to %d : %s", args.arg, buf);
ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_DEEP_SLEEP_CONTROL,
&args, sizeof(args), NULL);
if (!ret)
pr_err("alienware-wmi: deep sleep control failed: results: %u\n", ret);
return count;
}
static DEVICE_ATTR_RW(deepsleep);
static bool deepsleep_group_visible(struct kobject *kobj)
{
return alienware_interface == WMAX && alienfx->deepslp;
}
DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(deepsleep);
static struct attribute *deepsleep_attrs[] = {
&dev_attr_deepsleep.attr,
NULL,
};
const struct attribute_group wmax_deepsleep_attribute_group = {
.name = "deepsleep",
.is_visible = SYSFS_GROUP_VISIBLE(deepsleep),
.attrs = deepsleep_attrs,
};
/*
* Thermal Profile control
* - Provides thermal profile control through the Platform Profile API
*/
static bool is_wmax_thermal_code(u32 code)
{
if (code & WMAX_SENSOR_ID_MASK)
return false;
if ((code & WMAX_THERMAL_MODE_MASK) >= THERMAL_MODE_LAST)
return false;
if ((code & WMAX_THERMAL_TABLE_MASK) == WMAX_THERMAL_TABLE_BASIC &&
(code & WMAX_THERMAL_MODE_MASK) >= THERMAL_MODE_BASIC_QUIET)
return true;
if ((code & WMAX_THERMAL_TABLE_MASK) == WMAX_THERMAL_TABLE_USTT &&
(code & WMAX_THERMAL_MODE_MASK) <= THERMAL_MODE_USTT_LOW_POWER)
return true;
return false;
}
static int wmax_thermal_information(struct wmi_device *wdev, u8 operation,
u8 arg, u32 *out_data)
{
struct wmax_u32_args in_args = {
.operation = operation,
.arg1 = arg,
.arg2 = 0,
.arg3 = 0,
};
int ret;
ret = alienware_wmi_command(wdev, WMAX_METHOD_THERMAL_INFORMATION,
&in_args, sizeof(in_args), out_data);
if (ret < 0)
return ret;
if (*out_data == WMAX_FAILURE_CODE)
return -EBADRQC;
return 0;
}
static int wmax_thermal_control(struct wmi_device *wdev, u8 profile)
{
struct wmax_u32_args in_args = {
.operation = WMAX_OPERATION_ACTIVATE_PROFILE,
.arg1 = profile,
.arg2 = 0,
.arg3 = 0,
};
u32 out_data;
int ret;
ret = alienware_wmi_command(wdev, WMAX_METHOD_THERMAL_CONTROL,
&in_args, sizeof(in_args), &out_data);
if (ret)
return ret;
if (out_data == WMAX_FAILURE_CODE)
return -EBADRQC;
return 0;
}
static int wmax_game_shift_status(struct wmi_device *wdev, u8 operation,
u32 *out_data)
{
struct wmax_u32_args in_args = {
.operation = operation,
.arg1 = 0,
.arg2 = 0,
.arg3 = 0,
};
int ret;
ret = alienware_wmi_command(wdev, WMAX_METHOD_GAME_SHIFT_STATUS,
&in_args, sizeof(in_args), out_data);
if (ret < 0)
return ret;
if (*out_data == WMAX_FAILURE_CODE)
return -EOPNOTSUPP;
return 0;
}
static int thermal_profile_get(struct device *dev,
enum platform_profile_option *profile)
{
struct awcc_priv *priv = dev_get_drvdata(dev);
u32 out_data;
int ret;
ret = wmax_thermal_information(priv->wdev, WMAX_OPERATION_CURRENT_PROFILE,
0, &out_data);
if (ret < 0)
return ret;
if (out_data == WMAX_THERMAL_MODE_GMODE) {
*profile = PLATFORM_PROFILE_PERFORMANCE;
return 0;
}
if (!is_wmax_thermal_code(out_data))
return -ENODATA;
out_data &= WMAX_THERMAL_MODE_MASK;
*profile = wmax_mode_to_platform_profile[out_data];
return 0;
}
static int thermal_profile_set(struct device *dev,
enum platform_profile_option profile)
{
struct awcc_priv *priv = dev_get_drvdata(dev);
if (awcc->gmode) {
u32 gmode_status;
int ret;
ret = wmax_game_shift_status(priv->wdev,
WMAX_OPERATION_GET_GAME_SHIFT_STATUS,
&gmode_status);
if (ret < 0)
return ret;
if ((profile == PLATFORM_PROFILE_PERFORMANCE && !gmode_status) ||
(profile != PLATFORM_PROFILE_PERFORMANCE && gmode_status)) {
ret = wmax_game_shift_status(priv->wdev,
WMAX_OPERATION_TOGGLE_GAME_SHIFT,
&gmode_status);
if (ret < 0)
return ret;
}
}
return wmax_thermal_control(priv->wdev,
priv->supported_thermal_profiles[profile]);
}
static int thermal_profile_probe(void *drvdata, unsigned long *choices)
{
enum platform_profile_option profile;
struct awcc_priv *priv = drvdata;
enum wmax_thermal_mode mode;
u8 sys_desc[4];
u32 first_mode;
u32 out_data;
int ret;
ret = wmax_thermal_information(priv->wdev, WMAX_OPERATION_SYS_DESCRIPTION,
0, (u32 *) &sys_desc);
if (ret < 0)
return ret;
first_mode = sys_desc[0] + sys_desc[1];
for (u32 i = 0; i < sys_desc[3]; i++) {
ret = wmax_thermal_information(priv->wdev, WMAX_OPERATION_LIST_IDS,
i + first_mode, &out_data);
if (ret == -EIO)
return ret;
if (ret == -EBADRQC)
break;
if (!is_wmax_thermal_code(out_data))
continue;
mode = out_data & WMAX_THERMAL_MODE_MASK;
profile = wmax_mode_to_platform_profile[mode];
priv->supported_thermal_profiles[profile] = out_data;
set_bit(profile, choices);
}
if (bitmap_empty(choices, PLATFORM_PROFILE_LAST))
return -ENODEV;
if (awcc->gmode) {
priv->supported_thermal_profiles[PLATFORM_PROFILE_PERFORMANCE] =
WMAX_THERMAL_MODE_GMODE;
set_bit(PLATFORM_PROFILE_PERFORMANCE, choices);
}
return 0;
}
static const struct platform_profile_ops awcc_platform_profile_ops = {
.probe = thermal_profile_probe,
.profile_get = thermal_profile_get,
.profile_set = thermal_profile_set,
};
static int awcc_platform_profile_init(struct wmi_device *wdev)
{
struct awcc_priv *priv = dev_get_drvdata(&wdev->dev);
priv->ppdev = devm_platform_profile_register(&wdev->dev, "alienware-wmi",
priv, &awcc_platform_profile_ops);
return PTR_ERR_OR_ZERO(priv->ppdev);
}
static int alienware_awcc_setup(struct wmi_device *wdev)
{
struct awcc_priv *priv;
int ret;
priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->wdev = wdev;
dev_set_drvdata(&wdev->dev, priv);
if (awcc->pprof) {
ret = awcc_platform_profile_init(wdev);
if (ret)
return ret;
}
return 0;
}
/*
* WMAX WMI driver
*/
static int wmax_wmi_update_led(struct alienfx_priv *priv,
struct wmi_device *wdev, u8 location)
{
struct wmax_led_args in_args = {
.led_mask = 1 << location,
.colors = priv->colors[location],
.state = priv->lighting_control_state,
};
return alienware_wmi_command(wdev, WMAX_METHOD_ZONE_CONTROL, &in_args,
sizeof(in_args), NULL);
}
static int wmax_wmi_update_brightness(struct alienfx_priv *priv,
struct wmi_device *wdev, u8 brightness)
{
struct wmax_brightness_args in_args = {
.led_mask = 0xFF,
.percentage = brightness,
};
return alienware_wmi_command(wdev, WMAX_METHOD_BRIGHTNESS, &in_args,
sizeof(in_args), NULL);
}
static int wmax_wmi_probe(struct wmi_device *wdev, const void *context)
{
struct alienfx_platdata pdata = {
.wdev = wdev,
.ops = {
.upd_led = wmax_wmi_update_led,
.upd_brightness = wmax_wmi_update_brightness,
},
};
int ret;
if (awcc)
ret = alienware_awcc_setup(wdev);
else
ret = alienware_alienfx_setup(&pdata);
return ret;
}
static const struct wmi_device_id alienware_wmax_device_id_table[] = {
{ WMAX_CONTROL_GUID, NULL },
{ },
};
MODULE_DEVICE_TABLE(wmi, alienware_wmax_device_id_table);
static struct wmi_driver alienware_wmax_wmi_driver = {
.driver = {
.name = "alienware-wmi-wmax",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.id_table = alienware_wmax_device_id_table,
.probe = wmax_wmi_probe,
.no_singleton = true,
};
int __init alienware_wmax_wmi_init(void)
{
const struct dmi_system_id *id;
id = dmi_first_match(awcc_dmi_table);
if (id)
awcc = id->driver_data;
if (force_platform_profile) {
if (!awcc)
awcc = &empty_quirks;
awcc->pprof = true;
}
if (force_gmode) {
if (awcc)
awcc->gmode = true;
else
pr_warn("force_gmode requires platform profile support\n");
}
return wmi_driver_register(&alienware_wmax_wmi_driver);
}
void __exit alienware_wmax_wmi_exit(void)
{
wmi_driver_unregister(&alienware_wmax_wmi_driver);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,117 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Alienware WMI special features driver
*
* Copyright (C) 2014 Dell Inc <Dell.Client.Kernel@dell.com>
* Copyright (C) 2024 Kurt Borja <kuurtb@gmail.com>
*/
#ifndef _ALIENWARE_WMI_H_
#define _ALIENWARE_WMI_H_
#include <linux/leds.h>
#include <linux/platform_device.h>
#include <linux/wmi.h>
#define LEGACY_CONTROL_GUID "A90597CE-A997-11DA-B012-B622A1EF5492"
#define LEGACY_POWER_CONTROL_GUID "A80593CE-A997-11DA-B012-B622A1EF5492"
#define WMAX_CONTROL_GUID "A70591CE-A997-11DA-B012-B622A1EF5492"
enum INTERFACE_FLAGS {
LEGACY,
WMAX,
};
enum LEGACY_CONTROL_STATES {
LEGACY_RUNNING = 1,
LEGACY_BOOTING = 0,
LEGACY_SUSPEND = 3,
};
enum WMAX_CONTROL_STATES {
WMAX_RUNNING = 0xFF,
WMAX_BOOTING = 0,
WMAX_SUSPEND = 3,
};
struct alienfx_quirks {
u8 num_zones;
bool hdmi_mux;
bool amplifier;
bool deepslp;
};
struct color_platform {
u8 blue;
u8 green;
u8 red;
} __packed;
struct alienfx_priv {
struct platform_device *pdev;
struct led_classdev global_led;
struct color_platform colors[4];
u8 global_brightness;
u8 lighting_control_state;
};
struct alienfx_ops {
int (*upd_led)(struct alienfx_priv *priv, struct wmi_device *wdev,
u8 location);
int (*upd_brightness)(struct alienfx_priv *priv, struct wmi_device *wdev,
u8 brightness);
};
struct alienfx_platdata {
struct wmi_device *wdev;
struct alienfx_ops ops;
};
extern u8 alienware_interface;
extern struct alienfx_quirks *alienfx;
int alienware_wmi_command(struct wmi_device *wdev, u32 method_id,
void *in_args, size_t in_size, u32 *out_data);
int alienware_alienfx_setup(struct alienfx_platdata *pdata);
#if IS_ENABLED(CONFIG_ALIENWARE_WMI_LEGACY)
int __init alienware_legacy_wmi_init(void);
void __exit alienware_legacy_wmi_exit(void);
#else
static inline int alienware_legacy_wmi_init(void)
{
return -ENODEV;
}
static inline void alienware_legacy_wmi_exit(void)
{
}
#endif
#if IS_ENABLED(CONFIG_ALIENWARE_WMI_WMAX)
extern const struct attribute_group wmax_hdmi_attribute_group;
extern const struct attribute_group wmax_amplifier_attribute_group;
extern const struct attribute_group wmax_deepsleep_attribute_group;
#define WMAX_DEV_GROUPS &wmax_hdmi_attribute_group, \
&wmax_amplifier_attribute_group, \
&wmax_deepsleep_attribute_group,
int __init alienware_wmax_wmi_init(void);
void __exit alienware_wmax_wmi_exit(void);
#else
#define WMAX_DEV_GROUPS
static inline int alienware_wmax_wmi_init(void)
{
return -ENODEV;
}
static inline void alienware_wmax_wmi_exit(void)
{
}
#endif
#endif

View File

@ -325,7 +325,7 @@ static int dell_uart_bl_serdev_probe(struct serdev_device *serdev)
return PTR_ERR_OR_ZERO(dell_bl->bl);
}
struct serdev_device_driver dell_uart_bl_serdev_driver = {
static struct serdev_device_driver dell_uart_bl_serdev_driver = {
.probe = dell_uart_bl_serdev_probe,
.driver = {
.name = KBUILD_MODNAME,

View File

@ -104,7 +104,6 @@ struct dell_wmi_ddv_sensors {
struct dell_wmi_ddv_data {
struct acpi_battery_hook hook;
struct device_attribute temp_attr;
struct device_attribute eppid_attr;
struct dell_wmi_ddv_sensors fans;
struct dell_wmi_ddv_sensors temps;
@ -651,24 +650,6 @@ static int dell_wmi_ddv_battery_index(struct acpi_device *acpi_dev, u32 *index)
return kstrtou32(uid_str, 10, index);
}
static ssize_t temp_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct dell_wmi_ddv_data *data = container_of(attr, struct dell_wmi_ddv_data, temp_attr);
u32 index, value;
int ret;
ret = dell_wmi_ddv_battery_index(to_acpi_device(dev->parent), &index);
if (ret < 0)
return ret;
ret = dell_wmi_ddv_query_integer(data->wdev, DELL_DDV_BATTERY_TEMPERATURE, index, &value);
if (ret < 0)
return ret;
/* Use 2731 instead of 2731.5 to avoid unnecessary rounding */
return sysfs_emit(buf, "%d\n", value - 2731);
}
static ssize_t eppid_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct dell_wmi_ddv_data *data = container_of(attr, struct dell_wmi_ddv_data, eppid_attr);
@ -695,6 +676,46 @@ static ssize_t eppid_show(struct device *dev, struct device_attribute *attr, cha
return ret;
}
static int dell_wmi_ddv_get_property(struct power_supply *psy, const struct power_supply_ext *ext,
void *drvdata, enum power_supply_property psp,
union power_supply_propval *val)
{
struct dell_wmi_ddv_data *data = drvdata;
u32 index, value;
int ret;
ret = dell_wmi_ddv_battery_index(to_acpi_device(psy->dev.parent), &index);
if (ret < 0)
return ret;
switch (psp) {
case POWER_SUPPLY_PROP_TEMP:
ret = dell_wmi_ddv_query_integer(data->wdev, DELL_DDV_BATTERY_TEMPERATURE, index,
&value);
if (ret < 0)
return ret;
/* Use 2732 instead of 2731.5 to avoid unnecessary rounding and to emulate
* the behaviour of the OEM application which seems to round down the result.
*/
val->intval = value - 2732;
return 0;
default:
return -EINVAL;
}
}
static const enum power_supply_property dell_wmi_ddv_properties[] = {
POWER_SUPPLY_PROP_TEMP,
};
static const struct power_supply_ext dell_wmi_ddv_extension = {
.name = DRIVER_NAME,
.properties = dell_wmi_ddv_properties,
.num_properties = ARRAY_SIZE(dell_wmi_ddv_properties),
.get_property = dell_wmi_ddv_get_property,
};
static int dell_wmi_ddv_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
{
struct dell_wmi_ddv_data *data = container_of(hook, struct dell_wmi_ddv_data, hook);
@ -706,13 +727,14 @@ static int dell_wmi_ddv_add_battery(struct power_supply *battery, struct acpi_ba
if (ret < 0)
return 0;
ret = device_create_file(&battery->dev, &data->temp_attr);
ret = device_create_file(&battery->dev, &data->eppid_attr);
if (ret < 0)
return ret;
ret = device_create_file(&battery->dev, &data->eppid_attr);
ret = power_supply_register_extension(battery, &dell_wmi_ddv_extension, &data->wdev->dev,
data);
if (ret < 0) {
device_remove_file(&battery->dev, &data->temp_attr);
device_remove_file(&battery->dev, &data->eppid_attr);
return ret;
}
@ -724,38 +746,24 @@ static int dell_wmi_ddv_remove_battery(struct power_supply *battery, struct acpi
{
struct dell_wmi_ddv_data *data = container_of(hook, struct dell_wmi_ddv_data, hook);
device_remove_file(&battery->dev, &data->temp_attr);
device_remove_file(&battery->dev, &data->eppid_attr);
power_supply_unregister_extension(battery, &dell_wmi_ddv_extension);
return 0;
}
static void dell_wmi_ddv_battery_remove(void *data)
{
struct acpi_battery_hook *hook = data;
battery_hook_unregister(hook);
}
static int dell_wmi_ddv_battery_add(struct dell_wmi_ddv_data *data)
{
data->hook.name = "Dell DDV Battery Extension";
data->hook.add_battery = dell_wmi_ddv_add_battery;
data->hook.remove_battery = dell_wmi_ddv_remove_battery;
sysfs_attr_init(&data->temp_attr.attr);
data->temp_attr.attr.name = "temp";
data->temp_attr.attr.mode = 0444;
data->temp_attr.show = temp_show;
sysfs_attr_init(&data->eppid_attr.attr);
data->eppid_attr.attr.name = "eppid";
data->eppid_attr.attr.mode = 0444;
data->eppid_attr.show = eppid_show;
battery_hook_register(&data->hook);
return devm_add_action_or_reset(&data->wdev->dev, dell_wmi_ddv_battery_remove, &data->hook);
return devm_battery_hook_register(&data->wdev->dev, &data->hook);
}
static int dell_wmi_ddv_buffer_read(struct seq_file *seq, enum dell_ddv_method method)

View File

@ -1,5 +1,5 @@
obj-$(CONFIG_DELL_WMI_SYSMAN) += dell-wmi-sysman.o
dell-wmi-sysman-objs := sysman.o \
dell-wmi-sysman-y := sysman.o \
enum-attributes.o \
int-attributes.o \
string-attributes.o \

View File

@ -1,6 +1,6 @@
obj-$(CONFIG_HP_BIOSCFG) := hp-bioscfg.o
hp-bioscfg-objs := bioscfg.o \
hp-bioscfg-y := bioscfg.o \
biosattr-interface.o \
enum-attributes.o \
int-attributes.o \

View File

@ -388,16 +388,13 @@ union acpi_object *hp_get_wmiobj_pointer(int instance_id, const char *guid_strin
*/
int hp_get_instance_count(const char *guid_string)
{
union acpi_object *wmi_obj = NULL;
int i = 0;
int ret;
do {
kfree(wmi_obj);
wmi_obj = hp_get_wmiobj_pointer(i, guid_string);
i++;
} while (wmi_obj);
ret = wmi_instance_count(guid_string);
if (ret < 0)
return 0;
return i - 1;
return ret;
}
/**
@ -448,7 +445,7 @@ int hp_convert_hexstr_to_str(const char *input, u32 input_len, char **str, int *
return -ENOMEM;
for (i = 0; i < input_len; i += 5) {
strncpy(tmp, input + i, strlen(tmp));
strscpy(tmp, input + i);
if (kstrtol(tmp, 16, &ch) == 0) {
// escape char
if (ch == '\\' ||

View File

@ -854,6 +854,7 @@ static const struct attribute_group ideapad_attribute_group = {
.is_visible = ideapad_is_visible,
.attrs = ideapad_attributes
};
__ATTRIBUTE_GROUPS(ideapad_attribute);
/*
* DYTC Platform profile
@ -1244,21 +1245,6 @@ static void ideapad_unregister_rfkill(struct ideapad_private *priv, int dev)
rfkill_destroy(priv->rfk[dev]);
}
/*
* Platform device
*/
static int ideapad_sysfs_init(struct ideapad_private *priv)
{
return device_add_group(&priv->platform_device->dev,
&ideapad_attribute_group);
}
static void ideapad_sysfs_exit(struct ideapad_private *priv)
{
device_remove_group(&priv->platform_device->dev,
&ideapad_attribute_group);
}
/*
* input device
*/
@ -2175,10 +2161,6 @@ static int ideapad_acpi_add(struct platform_device *pdev)
ideapad_check_features(priv);
err = ideapad_sysfs_init(priv);
if (err)
return err;
ideapad_debugfs_init(priv);
err = ideapad_input_init(priv);
@ -2265,7 +2247,6 @@ static int ideapad_acpi_add(struct platform_device *pdev)
input_failed:
ideapad_debugfs_exit(priv);
ideapad_sysfs_exit(priv);
return err;
}
@ -2293,7 +2274,6 @@ static void ideapad_acpi_remove(struct platform_device *pdev)
ideapad_kbd_bl_exit(priv);
ideapad_input_exit(priv);
ideapad_debugfs_exit(priv);
ideapad_sysfs_exit(priv);
}
#ifdef CONFIG_PM_SLEEP
@ -2325,6 +2305,7 @@ static struct platform_driver ideapad_acpi_driver = {
.name = "ideapad_acpi",
.pm = &ideapad_pm,
.acpi_match_table = ACPI_PTR(ideapad_device_ids),
.dev_groups = ideapad_attribute_groups,
},
};

View File

@ -1,3 +1,3 @@
obj-$(CONFIG_INTEL_IFS) += intel_ifs.o
intel_ifs-objs := core.o load.o runtest.o sysfs.o
intel_ifs-y := core.o load.o runtest.o sysfs.o

View File

@ -56,7 +56,7 @@ static void skl_int3472_log_sensor_module_name(struct int3472_discrete_device *i
static int skl_int3472_fill_gpiod_lookup(struct gpiod_lookup *table_entry,
struct acpi_resource_gpio *agpio,
const char *func, unsigned long gpio_flags)
const char *con_id, unsigned long gpio_flags)
{
char *path = agpio->resource_source.string_ptr;
struct acpi_device *adev;
@ -71,14 +71,14 @@ static int skl_int3472_fill_gpiod_lookup(struct gpiod_lookup *table_entry,
if (!adev)
return -ENODEV;
*table_entry = GPIO_LOOKUP(acpi_dev_name(adev), agpio->pin_table[0], func, gpio_flags);
*table_entry = GPIO_LOOKUP(acpi_dev_name(adev), agpio->pin_table[0], con_id, gpio_flags);
return 0;
}
static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int3472,
struct acpi_resource_gpio *agpio,
const char *func, unsigned long gpio_flags)
const char *con_id, unsigned long gpio_flags)
{
int ret;
@ -88,7 +88,7 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347
}
ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios],
agpio, func, gpio_flags);
agpio, con_id, gpio_flags);
if (ret)
return ret;
@ -101,7 +101,7 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347
static struct gpio_desc *
skl_int3472_gpiod_get_from_temp_lookup(struct int3472_discrete_device *int3472,
struct acpi_resource_gpio *agpio,
const char *func, unsigned long gpio_flags)
const char *con_id, unsigned long gpio_flags)
{
struct gpio_desc *desc;
int ret;
@ -112,12 +112,12 @@ skl_int3472_gpiod_get_from_temp_lookup(struct int3472_discrete_device *int3472,
return ERR_PTR(-ENOMEM);
lookup->dev_id = dev_name(int3472->dev);
ret = skl_int3472_fill_gpiod_lookup(&lookup->table[0], agpio, func, gpio_flags);
ret = skl_int3472_fill_gpiod_lookup(&lookup->table[0], agpio, con_id, gpio_flags);
if (ret)
return ERR_PTR(ret);
gpiod_add_lookup_table(lookup);
desc = devm_gpiod_get(int3472->dev, func, GPIOD_OUT_LOW);
desc = devm_gpiod_get(int3472->dev, con_id, GPIOD_OUT_LOW);
gpiod_remove_lookup_table(lookup);
return desc;
@ -129,7 +129,7 @@ skl_int3472_gpiod_get_from_temp_lookup(struct int3472_discrete_device *int3472,
* @hid: The ACPI HID of the device without the instance number e.g. INT347E
* @type_from: The GPIO type from ACPI ?SDT
* @type_to: The assigned GPIO type, typically same as @type_from
* @func: The function, e.g. "enable"
* @con_id: The name of the GPIO for the device
* @polarity_low: GPIO_ACTIVE_LOW true if the @polarity_low is true,
* GPIO_ACTIVE_HIGH otherwise
*/
@ -138,15 +138,15 @@ struct int3472_gpio_map {
u8 type_from;
u8 type_to;
bool polarity_low;
const char *func;
const char *con_id;
};
static const struct int3472_gpio_map int3472_gpio_map[] = {
{ "INT347E", INT3472_GPIO_TYPE_RESET, INT3472_GPIO_TYPE_RESET, false, "enable" },
};
static void int3472_get_func_and_polarity(struct acpi_device *adev, u8 *type,
const char **func, unsigned long *gpio_flags)
static void int3472_get_con_id_and_polarity(struct acpi_device *adev, u8 *type,
const char **con_id, unsigned long *gpio_flags)
{
unsigned int i;
@ -165,33 +165,33 @@ static void int3472_get_func_and_polarity(struct acpi_device *adev, u8 *type,
*type = int3472_gpio_map[i].type_to;
*gpio_flags = int3472_gpio_map[i].polarity_low ?
GPIO_ACTIVE_LOW : GPIO_ACTIVE_HIGH;
*func = int3472_gpio_map[i].func;
*con_id = int3472_gpio_map[i].con_id;
return;
}
switch (*type) {
case INT3472_GPIO_TYPE_RESET:
*func = "reset";
*con_id = "reset";
*gpio_flags = GPIO_ACTIVE_LOW;
break;
case INT3472_GPIO_TYPE_POWERDOWN:
*func = "powerdown";
*con_id = "powerdown";
*gpio_flags = GPIO_ACTIVE_LOW;
break;
case INT3472_GPIO_TYPE_CLK_ENABLE:
*func = "clk-enable";
*con_id = "clk-enable";
*gpio_flags = GPIO_ACTIVE_HIGH;
break;
case INT3472_GPIO_TYPE_PRIVACY_LED:
*func = "privacy-led";
*con_id = "privacy-led";
*gpio_flags = GPIO_ACTIVE_HIGH;
break;
case INT3472_GPIO_TYPE_POWER_ENABLE:
*func = "power-enable";
*con_id = "power-enable";
*gpio_flags = GPIO_ACTIVE_HIGH;
break;
default:
*func = "unknown";
*con_id = "unknown";
*gpio_flags = GPIO_ACTIVE_HIGH;
break;
}
@ -238,7 +238,7 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
union acpi_object *obj;
struct gpio_desc *gpio;
const char *err_msg;
const char *func;
const char *con_id;
unsigned long gpio_flags;
int ret;
@ -262,26 +262,26 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
type = FIELD_GET(INT3472_GPIO_DSM_TYPE, obj->integer.value);
int3472_get_func_and_polarity(int3472->sensor, &type, &func, &gpio_flags);
int3472_get_con_id_and_polarity(int3472->sensor, &type, &con_id, &gpio_flags);
pin = FIELD_GET(INT3472_GPIO_DSM_PIN, obj->integer.value);
/* Pin field is not really used under Windows and wraps around at 8 bits */
if (pin != (agpio->pin_table[0] & 0xff))
dev_dbg(int3472->dev, FW_BUG "%s %s pin number mismatch _DSM %d resource %d\n",
func, agpio->resource_source.string_ptr, pin, agpio->pin_table[0]);
con_id, agpio->resource_source.string_ptr, pin, agpio->pin_table[0]);
active_value = FIELD_GET(INT3472_GPIO_DSM_SENSOR_ON_VAL, obj->integer.value);
if (!active_value)
gpio_flags ^= GPIO_ACTIVE_LOW;
dev_dbg(int3472->dev, "%s %s pin %d active-%s\n", func,
dev_dbg(int3472->dev, "%s %s pin %d active-%s\n", con_id,
agpio->resource_source.string_ptr, agpio->pin_table[0],
str_high_low(gpio_flags == GPIO_ACTIVE_HIGH));
switch (type) {
case INT3472_GPIO_TYPE_RESET:
case INT3472_GPIO_TYPE_POWERDOWN:
ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, func, gpio_flags);
ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, con_id, gpio_flags);
if (ret)
err_msg = "Failed to map GPIO pin to sensor\n";
@ -289,7 +289,7 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
case INT3472_GPIO_TYPE_CLK_ENABLE:
case INT3472_GPIO_TYPE_PRIVACY_LED:
case INT3472_GPIO_TYPE_POWER_ENABLE:
gpio = skl_int3472_gpiod_get_from_temp_lookup(int3472, agpio, func, gpio_flags);
gpio = skl_int3472_gpiod_get_from_temp_lookup(int3472, agpio, con_id, gpio_flags);
if (IS_ERR(gpio)) {
ret = PTR_ERR(gpio);
err_msg = "Failed to get GPIO\n";

View File

@ -4,7 +4,7 @@
#
intel_pmc_core-y := core.o core_ssram.o spt.o cnp.o \
icl.o tgl.o adl.o mtl.o arl.o lnl.o
icl.o tgl.o adl.o mtl.o arl.o lnl.o ptl.o
obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o
intel_pmc_core_pltdrv-y := pltdrv.o
obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core_pltdrv.o

View File

@ -11,7 +11,7 @@
#include "core.h"
/* Alder Lake: PGD PFET Enable Ack Status Register(s) bitmap */
const struct pmc_bit_map adl_pfear_map[] = {
static const struct pmc_bit_map adl_pfear_map[] = {
{"SPI/eSPI", BIT(2)},
{"XHCI", BIT(3)},
{"SPA", BIT(4)},
@ -54,7 +54,7 @@ const struct pmc_bit_map adl_pfear_map[] = {
{}
};
const struct pmc_bit_map *ext_adl_pfear_map[] = {
static const struct pmc_bit_map *ext_adl_pfear_map[] = {
/*
* Check intel_pmc_core_ids[] users of cnp_reg_map for
* a list of core SoCs using this.
@ -63,7 +63,7 @@ const struct pmc_bit_map *ext_adl_pfear_map[] = {
NULL
};
const struct pmc_bit_map adl_ltr_show_map[] = {
static const struct pmc_bit_map adl_ltr_show_map[] = {
{"SOUTHPORT_A", CNP_PMC_LTR_SPA},
{"SOUTHPORT_B", CNP_PMC_LTR_SPB},
{"SATA", CNP_PMC_LTR_SATA},
@ -100,7 +100,7 @@ const struct pmc_bit_map adl_ltr_show_map[] = {
{}
};
const struct pmc_bit_map adl_clocksource_status_map[] = {
static const struct pmc_bit_map adl_clocksource_status_map[] = {
{"CLKPART1_OFF_STS", BIT(0)},
{"CLKPART2_OFF_STS", BIT(1)},
{"CLKPART3_OFF_STS", BIT(2)},
@ -128,7 +128,7 @@ const struct pmc_bit_map adl_clocksource_status_map[] = {
{}
};
const struct pmc_bit_map adl_power_gating_status_0_map[] = {
static const struct pmc_bit_map adl_power_gating_status_0_map[] = {
{"PMC_PGD0_PG_STS", BIT(0)},
{"DMI_PGD0_PG_STS", BIT(1)},
{"ESPISPI_PGD0_PG_STS", BIT(2)},
@ -158,7 +158,7 @@ const struct pmc_bit_map adl_power_gating_status_0_map[] = {
{}
};
const struct pmc_bit_map adl_power_gating_status_1_map[] = {
static const struct pmc_bit_map adl_power_gating_status_1_map[] = {
{"USBR0_PGD0_PG_STS", BIT(0)},
{"SMT1_PGD0_PG_STS", BIT(2)},
{"CSMERTC_PGD0_PG_STS", BIT(6)},
@ -170,14 +170,14 @@ const struct pmc_bit_map adl_power_gating_status_1_map[] = {
{}
};
const struct pmc_bit_map adl_power_gating_status_2_map[] = {
static const struct pmc_bit_map adl_power_gating_status_2_map[] = {
{"THC0_PGD0_PG_STS", BIT(7)},
{"THC1_PGD0_PG_STS", BIT(8)},
{"SPF_PGD0_PG_STS", BIT(14)},
{}
};
const struct pmc_bit_map adl_d3_status_0_map[] = {
static const struct pmc_bit_map adl_d3_status_0_map[] = {
{"ISH_D3_STS", BIT(2)},
{"LPSS_D3_STS", BIT(3)},
{"XDCI_D3_STS", BIT(4)},
@ -193,13 +193,13 @@ const struct pmc_bit_map adl_d3_status_0_map[] = {
{}
};
const struct pmc_bit_map adl_d3_status_1_map[] = {
static const struct pmc_bit_map adl_d3_status_1_map[] = {
{"GBE_D3_STS", BIT(19)},
{"CNVI_D3_STS", BIT(27)},
{}
};
const struct pmc_bit_map adl_d3_status_2_map[] = {
static const struct pmc_bit_map adl_d3_status_2_map[] = {
{"CSMERTC_D3_STS", BIT(1)},
{"CSE_D3_STS", BIT(4)},
{"KVMCC_D3_STS", BIT(5)},
@ -210,20 +210,20 @@ const struct pmc_bit_map adl_d3_status_2_map[] = {
{}
};
const struct pmc_bit_map adl_d3_status_3_map[] = {
static const struct pmc_bit_map adl_d3_status_3_map[] = {
{"THC0_D3_STS", BIT(14)},
{"THC1_D3_STS", BIT(15)},
{}
};
const struct pmc_bit_map adl_vnn_req_status_0_map[] = {
static const struct pmc_bit_map adl_vnn_req_status_0_map[] = {
{"ISH_VNN_REQ_STS", BIT(2)},
{"ESPISPI_VNN_REQ_STS", BIT(18)},
{"DSP_VNN_REQ_STS", BIT(19)},
{}
};
const struct pmc_bit_map adl_vnn_req_status_1_map[] = {
static const struct pmc_bit_map adl_vnn_req_status_1_map[] = {
{"NPK_VNN_REQ_STS", BIT(4)},
{"EXI_VNN_REQ_STS", BIT(9)},
{"GBE_VNN_REQ_STS", BIT(19)},
@ -232,7 +232,7 @@ const struct pmc_bit_map adl_vnn_req_status_1_map[] = {
{}
};
const struct pmc_bit_map adl_vnn_req_status_2_map[] = {
static const struct pmc_bit_map adl_vnn_req_status_2_map[] = {
{"CSMERTC_VNN_REQ_STS", BIT(1)},
{"CSE_VNN_REQ_STS", BIT(4)},
{"SMT1_VNN_REQ_STS", BIT(8)},
@ -245,12 +245,12 @@ const struct pmc_bit_map adl_vnn_req_status_2_map[] = {
{}
};
const struct pmc_bit_map adl_vnn_req_status_3_map[] = {
static const struct pmc_bit_map adl_vnn_req_status_3_map[] = {
{"GPIOCOM5_VNN_REQ_STS", BIT(11)},
{}
};
const struct pmc_bit_map adl_vnn_misc_status_map[] = {
static const struct pmc_bit_map adl_vnn_misc_status_map[] = {
{"CPU_C10_REQ_STS", BIT(0)},
{"PCIe_LPM_En_REQ_STS", BIT(3)},
{"ITH_REQ_STS", BIT(5)},
@ -265,7 +265,7 @@ const struct pmc_bit_map adl_vnn_misc_status_map[] = {
{}
};
const struct pmc_bit_map *adl_lpm_maps[] = {
static const struct pmc_bit_map *adl_lpm_maps[] = {
adl_clocksource_status_map,
adl_power_gating_status_0_map,
adl_power_gating_status_1_map,
@ -311,20 +311,8 @@ const struct pmc_reg_map adl_reg_map = {
.pson_residency_counter_step = TGL_PSON_RES_COUNTER_STEP,
};
int adl_core_init(struct pmc_dev *pmcdev)
{
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
int ret;
pmcdev->suspend = cnl_suspend;
pmcdev->resume = cnl_resume;
pmc->map = &adl_reg_map;
ret = get_primary_reg_base(pmc);
if (ret)
return ret;
pmc_core_get_low_power_modes(pmcdev);
return 0;
}
struct pmc_dev_info adl_pmc_dev = {
.map = &adl_reg_map,
.suspend = cnl_suspend,
.resume = cnl_resume,
};

View File

@ -16,10 +16,11 @@
#define IOEP_LPM_REQ_GUID 0x5077612
#define SOCS_LPM_REQ_GUID 0x8478657
#define PCHS_LPM_REQ_GUID 0x9684572
#define SOCM_LPM_REQ_GUID 0x2625030
static const u8 ARL_LPM_REG_INDEX[] = {0, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20};
const struct pmc_bit_map arl_socs_ltr_show_map[] = {
static const struct pmc_bit_map arl_socs_ltr_show_map[] = {
{"SOUTHPORT_A", CNP_PMC_LTR_SPA},
{"SOUTHPORT_B", CNP_PMC_LTR_SPB},
{"SATA", CNP_PMC_LTR_SATA},
@ -59,7 +60,7 @@ const struct pmc_bit_map arl_socs_ltr_show_map[] = {
{}
};
const struct pmc_bit_map arl_socs_clocksource_status_map[] = {
static const struct pmc_bit_map arl_socs_clocksource_status_map[] = {
{"AON2_OFF_STS", BIT(0)},
{"AON3_OFF_STS", BIT(1)},
{"AON4_OFF_STS", BIT(2)},
@ -87,7 +88,7 @@ const struct pmc_bit_map arl_socs_clocksource_status_map[] = {
{}
};
const struct pmc_bit_map arl_socs_power_gating_status_0_map[] = {
static const struct pmc_bit_map arl_socs_power_gating_status_0_map[] = {
{"PMC_PGD0_PG_STS", BIT(0)},
{"DMI_PGD0_PG_STS", BIT(1)},
{"ESPISPI_PGD0_PG_STS", BIT(2)},
@ -123,7 +124,7 @@ const struct pmc_bit_map arl_socs_power_gating_status_0_map[] = {
{}
};
const struct pmc_bit_map arl_socs_power_gating_status_1_map[] = {
static const struct pmc_bit_map arl_socs_power_gating_status_1_map[] = {
{"USBR0_PGD0_PG_STS", BIT(0)},
{"SUSRAM_PGD0_PG_STS", BIT(1)},
{"SMT1_PGD0_PG_STS", BIT(2)},
@ -159,7 +160,7 @@ const struct pmc_bit_map arl_socs_power_gating_status_1_map[] = {
{}
};
const struct pmc_bit_map arl_socs_power_gating_status_2_map[] = {
static const struct pmc_bit_map arl_socs_power_gating_status_2_map[] = {
{"PSF8_PGD0_PG_STS", BIT(0)},
{"FIA_PGD0_PG_STS", BIT(1)},
{"SOC_D2D_PGD3_PG_STS", BIT(2)},
@ -187,7 +188,7 @@ const struct pmc_bit_map arl_socs_power_gating_status_2_map[] = {
{}
};
const struct pmc_bit_map arl_socs_d3_status_2_map[] = {
static const struct pmc_bit_map arl_socs_d3_status_2_map[] = {
{"CSMERTC_D3_STS", BIT(1)},
{"SUSRAM_D3_STS", BIT(2)},
{"CSE_D3_STS", BIT(4)},
@ -206,7 +207,7 @@ const struct pmc_bit_map arl_socs_d3_status_2_map[] = {
{}
};
const struct pmc_bit_map arl_socs_d3_status_3_map[] = {
static const struct pmc_bit_map arl_socs_d3_status_3_map[] = {
{"GBETSN_D3_STS", BIT(13)},
{"THC0_D3_STS", BIT(14)},
{"THC1_D3_STS", BIT(15)},
@ -214,13 +215,13 @@ const struct pmc_bit_map arl_socs_d3_status_3_map[] = {
{}
};
const struct pmc_bit_map arl_socs_vnn_req_status_3_map[] = {
static const struct pmc_bit_map arl_socs_vnn_req_status_3_map[] = {
{"DTS0_VNN_REQ_STS", BIT(7)},
{"GPIOCOM5_VNN_REQ_STS", BIT(11)},
{}
};
const struct pmc_bit_map *arl_socs_lpm_maps[] = {
static const struct pmc_bit_map *arl_socs_lpm_maps[] = {
arl_socs_clocksource_status_map,
arl_socs_power_gating_status_0_map,
arl_socs_power_gating_status_1_map,
@ -238,7 +239,7 @@ const struct pmc_bit_map *arl_socs_lpm_maps[] = {
NULL
};
const struct pmc_bit_map arl_socs_pfear_map[] = {
static const struct pmc_bit_map arl_socs_pfear_map[] = {
{"RSVD64", BIT(0)},
{"RSVD65", BIT(1)},
{"RSVD66", BIT(2)},
@ -249,13 +250,13 @@ const struct pmc_bit_map arl_socs_pfear_map[] = {
{}
};
const struct pmc_bit_map *ext_arl_socs_pfear_map[] = {
static const struct pmc_bit_map *ext_arl_socs_pfear_map[] = {
mtl_socm_pfear_map,
arl_socs_pfear_map,
NULL
};
const struct pmc_reg_map arl_socs_reg_map = {
static const struct pmc_reg_map arl_socs_reg_map = {
.pfear_sts = ext_arl_socs_pfear_map,
.ppfear_buckets = ARL_SOCS_PPFEAR_NUM_ENTRIES,
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
@ -283,7 +284,7 @@ const struct pmc_reg_map arl_socs_reg_map = {
.pson_residency_counter_step = TGL_PSON_RES_COUNTER_STEP,
};
const struct pmc_bit_map arl_pchs_ltr_show_map[] = {
static const struct pmc_bit_map arl_pchs_ltr_show_map[] = {
{"SOUTHPORT_A", CNP_PMC_LTR_SPA},
{"SOUTHPORT_B", CNP_PMC_LTR_SPB},
{"SATA", CNP_PMC_LTR_SATA},
@ -323,7 +324,7 @@ const struct pmc_bit_map arl_pchs_ltr_show_map[] = {
{}
};
const struct pmc_bit_map arl_pchs_clocksource_status_map[] = {
static const struct pmc_bit_map arl_pchs_clocksource_status_map[] = {
{"AON2_OFF_STS", BIT(0)},
{"AON3_OFF_STS", BIT(1)},
{"AON4_OFF_STS", BIT(2)},
@ -358,7 +359,7 @@ const struct pmc_bit_map arl_pchs_clocksource_status_map[] = {
{}
};
const struct pmc_bit_map arl_pchs_power_gating_status_0_map[] = {
static const struct pmc_bit_map arl_pchs_power_gating_status_0_map[] = {
{"PMC_PGD0_PG_STS", BIT(0)},
{"DMI_PGD0_PG_STS", BIT(1)},
{"ESPISPI_PGD0_PG_STS", BIT(2)},
@ -394,7 +395,7 @@ const struct pmc_bit_map arl_pchs_power_gating_status_0_map[] = {
{}
};
const struct pmc_bit_map arl_pchs_power_gating_status_1_map[] = {
static const struct pmc_bit_map arl_pchs_power_gating_status_1_map[] = {
{"USBR0_PGD0_PG_STS", BIT(0)},
{"SUSRAM_PGD0_PG_STS", BIT(1)},
{"SMT1_PGD0_PG_STS", BIT(2)},
@ -430,7 +431,7 @@ const struct pmc_bit_map arl_pchs_power_gating_status_1_map[] = {
{}
};
const struct pmc_bit_map arl_pchs_power_gating_status_2_map[] = {
static const struct pmc_bit_map arl_pchs_power_gating_status_2_map[] = {
{"U3FPW2_PGD0_PG_STS", BIT(0)},
{"FIA_PGD0_PG_STS", BIT(1)},
{"FIACPCB_X_PGD0_PG_STS", BIT(2)},
@ -457,7 +458,7 @@ const struct pmc_bit_map arl_pchs_power_gating_status_2_map[] = {
{}
};
const struct pmc_bit_map arl_pchs_d3_status_0_map[] = {
static const struct pmc_bit_map arl_pchs_d3_status_0_map[] = {
{"SPF_D3_STS", BIT(0)},
{"LPSS_D3_STS", BIT(3)},
{"XDCI_D3_STS", BIT(4)},
@ -474,7 +475,7 @@ const struct pmc_bit_map arl_pchs_d3_status_0_map[] = {
{}
};
const struct pmc_bit_map arl_pchs_d3_status_1_map[] = {
static const struct pmc_bit_map arl_pchs_d3_status_1_map[] = {
{"GBETSN1_D3_STS", BIT(14)},
{"GBE_D3_STS", BIT(19)},
{"ITSS_D3_STS", BIT(23)},
@ -483,7 +484,7 @@ const struct pmc_bit_map arl_pchs_d3_status_1_map[] = {
{}
};
const struct pmc_bit_map arl_pchs_d3_status_2_map[] = {
static const struct pmc_bit_map arl_pchs_d3_status_2_map[] = {
{"CSMERTC_D3_STS", BIT(1)},
{"SUSRAM_D3_STS", BIT(2)},
{"CSE_D3_STS", BIT(4)},
@ -504,7 +505,7 @@ const struct pmc_bit_map arl_pchs_d3_status_2_map[] = {
{}
};
const struct pmc_bit_map arl_pchs_d3_status_3_map[] = {
static const struct pmc_bit_map arl_pchs_d3_status_3_map[] = {
{"ESE_D3_STS", BIT(3)},
{"GBETSN_D3_STS", BIT(13)},
{"THC0_D3_STS", BIT(14)},
@ -513,13 +514,13 @@ const struct pmc_bit_map arl_pchs_d3_status_3_map[] = {
{}
};
const struct pmc_bit_map arl_pchs_vnn_req_status_0_map[] = {
static const struct pmc_bit_map arl_pchs_vnn_req_status_0_map[] = {
{"FIA_VNN_REQ_STS", BIT(17)},
{"ESPISPI_VNN_REQ_STS", BIT(18)},
{}
};
const struct pmc_bit_map arl_pchs_vnn_req_status_1_map[] = {
static const struct pmc_bit_map arl_pchs_vnn_req_status_1_map[] = {
{"NPK_VNN_REQ_STS", BIT(4)},
{"DFXAGG_VNN_REQ_STS", BIT(8)},
{"EXI_VNN_REQ_STS", BIT(9)},
@ -530,7 +531,7 @@ const struct pmc_bit_map arl_pchs_vnn_req_status_1_map[] = {
{}
};
const struct pmc_bit_map arl_pchs_vnn_req_status_2_map[] = {
static const struct pmc_bit_map arl_pchs_vnn_req_status_2_map[] = {
{"FIA2_VNN_REQ_STS", BIT(0)},
{"CSMERTC_VNN_REQ_STS", BIT(1)},
{"CSE_VNN_REQ_STS", BIT(4)},
@ -548,7 +549,7 @@ const struct pmc_bit_map arl_pchs_vnn_req_status_2_map[] = {
{}
};
const struct pmc_bit_map arl_pchs_vnn_req_status_3_map[] = {
static const struct pmc_bit_map arl_pchs_vnn_req_status_3_map[] = {
{"ESE_VNN_REQ_STS", BIT(3)},
{"DTS0_VNN_REQ_STS", BIT(7)},
{"GPIOCOM5_VNN_REQ_STS", BIT(11)},
@ -556,7 +557,7 @@ const struct pmc_bit_map arl_pchs_vnn_req_status_3_map[] = {
{}
};
const struct pmc_bit_map arl_pchs_vnn_misc_status_map[] = {
static const struct pmc_bit_map arl_pchs_vnn_misc_status_map[] = {
{"CPU_C10_REQ_STS", BIT(0)},
{"TS_OFF_REQ_STS", BIT(1)},
{"PNDE_MET_REQ_STS", BIT(2)},
@ -586,7 +587,7 @@ const struct pmc_bit_map arl_pchs_vnn_misc_status_map[] = {
{}
};
const struct pmc_bit_map arl_pchs_signal_status_map[] = {
static const struct pmc_bit_map arl_pchs_signal_status_map[] = {
{"LSX_Wake0_STS", BIT(0)},
{"LSX_Wake1_STS", BIT(1)},
{"LSX_Wake2_STS", BIT(2)},
@ -606,7 +607,7 @@ const struct pmc_bit_map arl_pchs_signal_status_map[] = {
{}
};
const struct pmc_bit_map *arl_pchs_lpm_maps[] = {
static const struct pmc_bit_map *arl_pchs_lpm_maps[] = {
arl_pchs_clocksource_status_map,
arl_pchs_power_gating_status_0_map,
arl_pchs_power_gating_status_1_map,
@ -624,7 +625,7 @@ const struct pmc_bit_map *arl_pchs_lpm_maps[] = {
NULL
};
const struct pmc_reg_map arl_pchs_reg_map = {
static const struct pmc_reg_map arl_pchs_reg_map = {
.pfear_sts = ext_arl_socs_pfear_map,
.ppfear_buckets = ARL_SOCS_PPFEAR_NUM_ENTRIES,
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
@ -650,6 +651,7 @@ const struct pmc_reg_map arl_pchs_reg_map = {
.etr3_offset = ETR3_OFFSET,
};
#define PMC_DEVID_SOCM 0x777f
#define PMC_DEVID_SOCS 0xae7f
#define PMC_DEVID_IOEP 0x7ecf
#define PMC_DEVID_PCHS 0x7f27
@ -669,11 +671,17 @@ static struct pmc_info arl_pmc_info_list[] = {
.devid = PMC_DEVID_PCHS,
.map = &arl_pchs_reg_map,
},
{
.guid = SOCM_LPM_REQ_GUID,
.devid = PMC_DEVID_SOCM,
.map = &mtl_socm_reg_map,
},
{}
};
#define ARL_NPU_PCI_DEV 0xad1d
#define ARL_GNA_PCI_DEV 0xae4c
#define ARL_H_GNA_PCI_DEV 0x774c
/*
* Set power state of select devices that do not have drivers to D3
* so that they do not block Package C entry.
@ -684,6 +692,12 @@ static void arl_d3_fixup(void)
pmc_core_set_device_d3(ARL_GNA_PCI_DEV);
}
static void arl_h_d3_fixup(void)
{
pmc_core_set_device_d3(ARL_NPU_PCI_DEV);
pmc_core_set_device_d3(ARL_H_GNA_PCI_DEV);
}
static int arl_resume(struct pmc_dev *pmcdev)
{
arl_d3_fixup();
@ -691,40 +705,41 @@ static int arl_resume(struct pmc_dev *pmcdev)
return cnl_resume(pmcdev);
}
int arl_core_init(struct pmc_dev *pmcdev)
static int arl_h_resume(struct pmc_dev *pmcdev)
{
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_SOC];
int ret;
int func = 0;
bool ssram_init = true;
arl_h_d3_fixup();
arl_d3_fixup();
pmcdev->suspend = cnl_suspend;
pmcdev->resume = arl_resume;
pmcdev->regmap_list = arl_pmc_info_list;
/*
* If ssram init fails use legacy method to at least get the
* primary PMC
*/
ret = pmc_core_ssram_init(pmcdev, func);
if (ret) {
ssram_init = false;
pmc->map = &arl_socs_reg_map;
ret = get_primary_reg_base(pmc);
if (ret)
return ret;
}
pmc_core_get_low_power_modes(pmcdev);
pmc_core_punit_pmt_init(pmcdev, ARL_PMT_DMU_GUID);
if (ssram_init) {
ret = pmc_core_ssram_get_lpm_reqs(pmcdev);
if (ret)
return ret;
}
return 0;
return cnl_resume(pmcdev);
}
static int arl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
{
arl_d3_fixup();
return generic_core_init(pmcdev, pmc_dev_info);
}
static int arl_h_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
{
arl_h_d3_fixup();
return generic_core_init(pmcdev, pmc_dev_info);
}
struct pmc_dev_info arl_pmc_dev = {
.pci_func = 0,
.dmu_guid = ARL_PMT_DMU_GUID,
.regmap_list = arl_pmc_info_list,
.map = &arl_socs_reg_map,
.suspend = cnl_suspend,
.resume = arl_resume,
.init = arl_core_init,
};
struct pmc_dev_info arl_h_pmc_dev = {
.pci_func = 2,
.dmu_guid = ARL_PMT_DMU_GUID,
.regmap_list = arl_pmc_info_list,
.map = &mtl_socm_reg_map,
.suspend = cnl_suspend,
.resume = arl_h_resume,
.init = arl_h_core_init,
};

View File

@ -88,7 +88,7 @@ const struct pmc_bit_map cnp_pfear_map[] = {
{}
};
const struct pmc_bit_map *ext_cnp_pfear_map[] = {
static const struct pmc_bit_map *ext_cnp_pfear_map[] = {
/*
* Check intel_pmc_core_ids[] users of cnp_reg_map for
* a list of core SoCs using this.
@ -97,7 +97,7 @@ const struct pmc_bit_map *ext_cnp_pfear_map[] = {
NULL
};
const struct pmc_bit_map cnp_slps0_dbg0_map[] = {
static const struct pmc_bit_map cnp_slps0_dbg0_map[] = {
{"AUDIO_D3", BIT(0)},
{"OTG_D3", BIT(1)},
{"XHCI_D3", BIT(2)},
@ -110,7 +110,7 @@ const struct pmc_bit_map cnp_slps0_dbg0_map[] = {
{}
};
const struct pmc_bit_map cnp_slps0_dbg1_map[] = {
static const struct pmc_bit_map cnp_slps0_dbg1_map[] = {
{"SDIO_PLL_OFF", BIT(0)},
{"USB2_PLL_OFF", BIT(1)},
{"AUDIO_PLL_OFF", BIT(2)},
@ -127,7 +127,7 @@ const struct pmc_bit_map cnp_slps0_dbg1_map[] = {
{}
};
const struct pmc_bit_map cnp_slps0_dbg2_map[] = {
static const struct pmc_bit_map cnp_slps0_dbg2_map[] = {
{"MPHY_CORE_GATED", BIT(0)},
{"CSME_GATED", BIT(1)},
{"USB2_SUS_GATED", BIT(2)},
@ -274,20 +274,9 @@ int cnl_resume(struct pmc_dev *pmcdev)
return pmc_core_resume_common(pmcdev);
}
int cnp_core_init(struct pmc_dev *pmcdev)
{
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
int ret;
struct pmc_dev_info cnp_pmc_dev = {
.map = &cnp_reg_map,
.suspend = cnl_suspend,
.resume = cnl_resume,
};
pmcdev->suspend = cnl_suspend;
pmcdev->resume = cnl_resume;
pmc->map = &cnp_reg_map;
ret = get_primary_reg_base(pmc);
if (ret)
return ret;
pmc_core_get_low_power_modes(pmcdev);
return 0;
}

View File

@ -1345,40 +1345,80 @@ static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
}
}
/*
* When supported, ssram init is used to achieve all available PMCs.
* If ssram init fails, this function uses legacy method to at least get the
* primary PMC.
*/
int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
{
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
bool ssram;
int ret;
pmcdev->suspend = pmc_dev_info->suspend;
pmcdev->resume = pmc_dev_info->resume;
ssram = pmc_dev_info->regmap_list != NULL;
if (ssram) {
pmcdev->regmap_list = pmc_dev_info->regmap_list;
ret = pmc_core_ssram_init(pmcdev, pmc_dev_info->pci_func);
if (ret) {
dev_warn(&pmcdev->pdev->dev,
"ssram init failed, %d, using legacy init\n", ret);
ssram = false;
}
}
if (!ssram) {
pmc->map = pmc_dev_info->map;
ret = get_primary_reg_base(pmc);
if (ret)
return ret;
}
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 (ssram)
return pmc_core_ssram_get_lpm_reqs(pmcdev);
return 0;
}
static const struct x86_cpu_id intel_pmc_core_ids[] = {
X86_MATCH_VFM(INTEL_SKYLAKE_L, spt_core_init),
X86_MATCH_VFM(INTEL_SKYLAKE, spt_core_init),
X86_MATCH_VFM(INTEL_KABYLAKE_L, spt_core_init),
X86_MATCH_VFM(INTEL_KABYLAKE, spt_core_init),
X86_MATCH_VFM(INTEL_CANNONLAKE_L, cnp_core_init),
X86_MATCH_VFM(INTEL_ICELAKE_L, icl_core_init),
X86_MATCH_VFM(INTEL_ICELAKE_NNPI, icl_core_init),
X86_MATCH_VFM(INTEL_COMETLAKE, cnp_core_init),
X86_MATCH_VFM(INTEL_COMETLAKE_L, cnp_core_init),
X86_MATCH_VFM(INTEL_TIGERLAKE_L, tgl_l_core_init),
X86_MATCH_VFM(INTEL_TIGERLAKE, tgl_core_init),
X86_MATCH_VFM(INTEL_ATOM_TREMONT, tgl_l_core_init),
X86_MATCH_VFM(INTEL_ATOM_TREMONT_L, icl_core_init),
X86_MATCH_VFM(INTEL_ROCKETLAKE, tgl_core_init),
X86_MATCH_VFM(INTEL_ALDERLAKE_L, tgl_l_core_init),
X86_MATCH_VFM(INTEL_ATOM_GRACEMONT, tgl_l_core_init),
X86_MATCH_VFM(INTEL_ALDERLAKE, adl_core_init),
X86_MATCH_VFM(INTEL_RAPTORLAKE_P, tgl_l_core_init),
X86_MATCH_VFM(INTEL_RAPTORLAKE, adl_core_init),
X86_MATCH_VFM(INTEL_RAPTORLAKE_S, adl_core_init),
X86_MATCH_VFM(INTEL_METEORLAKE_L, mtl_core_init),
X86_MATCH_VFM(INTEL_ARROWLAKE, arl_core_init),
X86_MATCH_VFM(INTEL_LUNARLAKE_M, lnl_core_init),
X86_MATCH_VFM(INTEL_SKYLAKE_L, &spt_pmc_dev),
X86_MATCH_VFM(INTEL_SKYLAKE, &spt_pmc_dev),
X86_MATCH_VFM(INTEL_KABYLAKE_L, &spt_pmc_dev),
X86_MATCH_VFM(INTEL_KABYLAKE, &spt_pmc_dev),
X86_MATCH_VFM(INTEL_CANNONLAKE_L, &cnp_pmc_dev),
X86_MATCH_VFM(INTEL_ICELAKE_L, &icl_pmc_dev),
X86_MATCH_VFM(INTEL_ICELAKE_NNPI, &icl_pmc_dev),
X86_MATCH_VFM(INTEL_COMETLAKE, &cnp_pmc_dev),
X86_MATCH_VFM(INTEL_COMETLAKE_L, &cnp_pmc_dev),
X86_MATCH_VFM(INTEL_TIGERLAKE_L, &tgl_l_pmc_dev),
X86_MATCH_VFM(INTEL_TIGERLAKE, &tgl_pmc_dev),
X86_MATCH_VFM(INTEL_ATOM_TREMONT, &tgl_l_pmc_dev),
X86_MATCH_VFM(INTEL_ATOM_TREMONT_L, &icl_pmc_dev),
X86_MATCH_VFM(INTEL_ROCKETLAKE, &tgl_pmc_dev),
X86_MATCH_VFM(INTEL_ALDERLAKE_L, &tgl_l_pmc_dev),
X86_MATCH_VFM(INTEL_ATOM_GRACEMONT, &tgl_l_pmc_dev),
X86_MATCH_VFM(INTEL_ALDERLAKE, &adl_pmc_dev),
X86_MATCH_VFM(INTEL_RAPTORLAKE_P, &tgl_l_pmc_dev),
X86_MATCH_VFM(INTEL_RAPTORLAKE, &adl_pmc_dev),
X86_MATCH_VFM(INTEL_RAPTORLAKE_S, &adl_pmc_dev),
X86_MATCH_VFM(INTEL_METEORLAKE_L, &mtl_pmc_dev),
X86_MATCH_VFM(INTEL_ARROWLAKE, &arl_pmc_dev),
X86_MATCH_VFM(INTEL_ARROWLAKE_H, &arl_h_pmc_dev),
X86_MATCH_VFM(INTEL_ARROWLAKE_U, &arl_h_pmc_dev),
X86_MATCH_VFM(INTEL_LUNARLAKE_M, &lnl_pmc_dev),
X86_MATCH_VFM(INTEL_PANTHERLAKE_L, &ptl_pmc_dev),
{}
};
MODULE_DEVICE_TABLE(x86cpu, intel_pmc_core_ids);
static const struct pci_device_id pmc_pci_ids[] = {
{ PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID) },
{ }
};
/*
* This quirk can be used on those platforms where
* the platform BIOS enforces 24Mhz crystal to shutdown
@ -1452,7 +1492,7 @@ static int pmc_core_probe(struct platform_device *pdev)
static bool device_initialized;
struct pmc_dev *pmcdev;
const struct x86_cpu_id *cpu_id;
int (*core_init)(struct pmc_dev *pmcdev);
struct pmc_dev_info *pmc_dev_info;
struct pmc *primary_pmc;
int ret;
@ -1472,7 +1512,7 @@ static int pmc_core_probe(struct platform_device *pdev)
if (!cpu_id)
return -ENODEV;
core_init = (int (*)(struct pmc_dev *))cpu_id->driver_data;
pmc_dev_info = (struct pmc_dev_info *)cpu_id->driver_data;
/* Primary PMC */
primary_pmc = devm_kzalloc(&pdev->dev, sizeof(*primary_pmc), GFP_KERNEL);
@ -1489,16 +1529,13 @@ static int pmc_core_probe(struct platform_device *pdev)
if (!pmcdev->pkgc_res_cnt)
return -ENOMEM;
/*
* Coffee Lake has CPU ID of Kaby Lake and Cannon Lake PCH. So here
* Sunrisepoint PCH regmap can't be used. Use Cannon Lake PCH regmap
* in this case.
*/
if (core_init == spt_core_init && !pci_dev_present(pmc_pci_ids))
core_init = cnp_core_init;
mutex_init(&pmcdev->lock);
ret = core_init(pmcdev);
if (pmc_dev_info->init)
ret = pmc_dev_info->init(pmcdev, pmc_dev_info);
else
ret = generic_core_init(pmcdev, pmc_dev_info);
if (ret) {
pmc_core_clean_structure(pdev);
return ret;

View File

@ -285,6 +285,14 @@ enum ppfear_regs {
#define LNL_PPFEAR_NUM_ENTRIES 12
#define LNL_S0IX_BLOCKER_OFFSET 0x2004
/* Panther Lake Power Management Controller register offsets */
#define PTL_LPM_NUM_MAPS 14
#define PTL_PMC_LTR_SATA2 0x1B90
#define PTL_PMC_LTR_PMC 0x1BA8
#define PTL_PMC_LTR_CUR_ASLT 0x1C28
#define PTL_PMC_LTR_CUR_PLT 0x1C2C
#define PTL_PCD_PMC_MMIO_REG_LEN 0x31A8
extern const char *pmc_lpm_modes[];
struct pmc_bit_map {
@ -430,178 +438,77 @@ struct pmc_dev {
enum pmc_index {
PMC_IDX_MAIN,
PMC_IDX_SOC = PMC_IDX_MAIN,
PMC_IDX_IOE,
PMC_IDX_PCH,
PMC_IDX_MAX
};
/**
* struct pmc_dev_info - Structure to keep PMC device info
* @pci_func: Function number of the primary PMC
* @dmu_guid: 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.
* @map: Pointer to a pmc_reg_map struct that contains platform
* specific attributes of the primary PMC
* @suspend: Function to perform platform specific suspend
* @resume: Function to perform platform specific resume
* @init: Function to perform platform specific init action
*/
struct pmc_dev_info {
u8 pci_func;
u32 dmu_guid;
struct pmc_info *regmap_list;
const struct pmc_reg_map *map;
void (*suspend)(struct pmc_dev *pmcdev);
int (*resume)(struct pmc_dev *pmcdev);
int (*init)(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info);
};
extern const struct pmc_bit_map msr_map[];
extern const struct pmc_bit_map spt_pll_map[];
extern const struct pmc_bit_map spt_mphy_map[];
extern const struct pmc_bit_map spt_pfear_map[];
extern const struct pmc_bit_map *ext_spt_pfear_map[];
extern const struct pmc_bit_map spt_ltr_show_map[];
extern const struct pmc_reg_map spt_reg_map;
extern const struct pmc_bit_map cnp_pfear_map[];
extern const struct pmc_bit_map *ext_cnp_pfear_map[];
extern const struct pmc_bit_map cnp_slps0_dbg0_map[];
extern const struct pmc_bit_map cnp_slps0_dbg1_map[];
extern const struct pmc_bit_map cnp_slps0_dbg2_map[];
extern const struct pmc_bit_map *cnp_slps0_dbg_maps[];
extern const struct pmc_bit_map cnp_ltr_show_map[];
extern const struct pmc_reg_map cnp_reg_map;
extern const struct pmc_bit_map icl_pfear_map[];
extern const struct pmc_bit_map *ext_icl_pfear_map[];
extern const struct pmc_reg_map icl_reg_map;
extern const struct pmc_bit_map tgl_pfear_map[];
extern const struct pmc_bit_map *ext_tgl_pfear_map[];
extern const struct pmc_bit_map tgl_clocksource_status_map[];
extern const struct pmc_bit_map tgl_power_gating_status_map[];
extern const struct pmc_bit_map tgl_d3_status_map[];
extern const struct pmc_bit_map tgl_vnn_req_status_map[];
extern const struct pmc_bit_map tgl_vnn_misc_status_map[];
extern const struct pmc_bit_map tgl_signal_status_map[];
extern const struct pmc_bit_map *tgl_lpm_maps[];
extern const struct pmc_reg_map tgl_reg_map;
extern const struct pmc_reg_map tgl_h_reg_map;
extern const struct pmc_bit_map adl_pfear_map[];
extern const struct pmc_bit_map *ext_adl_pfear_map[];
extern const struct pmc_bit_map adl_ltr_show_map[];
extern const struct pmc_bit_map adl_clocksource_status_map[];
extern const struct pmc_bit_map adl_power_gating_status_0_map[];
extern const struct pmc_bit_map adl_power_gating_status_1_map[];
extern const struct pmc_bit_map adl_power_gating_status_2_map[];
extern const struct pmc_bit_map adl_d3_status_0_map[];
extern const struct pmc_bit_map adl_d3_status_1_map[];
extern const struct pmc_bit_map adl_d3_status_2_map[];
extern const struct pmc_bit_map adl_d3_status_3_map[];
extern const struct pmc_bit_map adl_vnn_req_status_0_map[];
extern const struct pmc_bit_map adl_vnn_req_status_1_map[];
extern const struct pmc_bit_map adl_vnn_req_status_2_map[];
extern const struct pmc_bit_map adl_vnn_req_status_3_map[];
extern const struct pmc_bit_map adl_vnn_misc_status_map[];
extern const struct pmc_bit_map *adl_lpm_maps[];
extern const struct pmc_reg_map adl_reg_map;
extern const struct pmc_bit_map mtl_socm_pfear_map[];
extern const struct pmc_bit_map *ext_mtl_socm_pfear_map[];
extern const struct pmc_bit_map mtl_socm_ltr_show_map[];
extern const struct pmc_bit_map mtl_socm_clocksource_status_map[];
extern const struct pmc_bit_map mtl_socm_power_gating_status_0_map[];
extern const struct pmc_bit_map mtl_socm_power_gating_status_1_map[];
extern const struct pmc_bit_map mtl_socm_power_gating_status_2_map[];
extern const struct pmc_bit_map mtl_socm_d3_status_0_map[];
extern const struct pmc_bit_map mtl_socm_d3_status_1_map[];
extern const struct pmc_bit_map mtl_socm_d3_status_2_map[];
extern const struct pmc_bit_map mtl_socm_d3_status_3_map[];
extern const struct pmc_bit_map mtl_socm_vnn_req_status_0_map[];
extern const struct pmc_bit_map mtl_socm_vnn_req_status_1_map[];
extern const struct pmc_bit_map mtl_socm_vnn_req_status_2_map[];
extern const struct pmc_bit_map mtl_socm_vnn_req_status_3_map[];
extern const struct pmc_bit_map mtl_socm_vnn_misc_status_map[];
extern const struct pmc_bit_map mtl_socm_signal_status_map[];
extern const struct pmc_bit_map *mtl_socm_lpm_maps[];
extern const struct pmc_reg_map mtl_socm_reg_map;
extern const struct pmc_bit_map mtl_ioep_pfear_map[];
extern const struct pmc_bit_map *ext_mtl_ioep_pfear_map[];
extern const struct pmc_bit_map mtl_ioep_ltr_show_map[];
extern const struct pmc_bit_map mtl_ioep_clocksource_status_map[];
extern const struct pmc_bit_map mtl_ioep_power_gating_status_0_map[];
extern const struct pmc_bit_map mtl_ioep_power_gating_status_1_map[];
extern const struct pmc_bit_map mtl_ioep_power_gating_status_2_map[];
extern const struct pmc_bit_map mtl_ioep_d3_status_0_map[];
extern const struct pmc_bit_map mtl_ioep_d3_status_1_map[];
extern const struct pmc_bit_map mtl_ioep_d3_status_2_map[];
extern const struct pmc_bit_map mtl_ioep_d3_status_3_map[];
extern const struct pmc_bit_map mtl_ioep_vnn_req_status_0_map[];
extern const struct pmc_bit_map mtl_ioep_vnn_req_status_1_map[];
extern const struct pmc_bit_map mtl_ioep_vnn_req_status_2_map[];
extern const struct pmc_bit_map mtl_ioep_vnn_req_status_3_map[];
extern const struct pmc_bit_map mtl_ioep_vnn_misc_status_map[];
extern const struct pmc_bit_map *mtl_ioep_lpm_maps[];
extern const struct pmc_reg_map mtl_ioep_reg_map;
extern const struct pmc_bit_map mtl_ioem_pfear_map[];
extern const struct pmc_bit_map *ext_mtl_ioem_pfear_map[];
extern const struct pmc_bit_map mtl_ioem_power_gating_status_1_map[];
extern const struct pmc_bit_map mtl_ioem_vnn_req_status_1_map[];
extern const struct pmc_bit_map *mtl_ioem_lpm_maps[];
extern const struct pmc_reg_map mtl_ioem_reg_map;
extern const struct pmc_reg_map lnl_socm_reg_map;
/* LNL */
extern const struct pmc_bit_map lnl_ltr_show_map[];
extern const struct pmc_bit_map lnl_clocksource_status_map[];
extern const struct pmc_bit_map lnl_power_gating_status_0_map[];
extern const struct pmc_bit_map lnl_power_gating_status_1_map[];
extern const struct pmc_bit_map lnl_power_gating_status_2_map[];
extern const struct pmc_bit_map lnl_d3_status_0_map[];
extern const struct pmc_bit_map lnl_d3_status_1_map[];
extern const struct pmc_bit_map lnl_d3_status_2_map[];
extern const struct pmc_bit_map lnl_d3_status_3_map[];
extern const struct pmc_bit_map lnl_vnn_req_status_0_map[];
extern const struct pmc_bit_map lnl_vnn_req_status_1_map[];
extern const struct pmc_bit_map lnl_vnn_req_status_2_map[];
extern const struct pmc_bit_map lnl_vnn_req_status_3_map[];
extern const struct pmc_bit_map lnl_vnn_misc_status_map[];
extern const struct pmc_bit_map *lnl_lpm_maps[];
extern const struct pmc_bit_map *lnl_blk_maps[];
extern const struct pmc_bit_map lnl_pfear_map[];
extern const struct pmc_bit_map *ext_lnl_pfear_map[];
extern const struct pmc_bit_map lnl_signal_status_map[];
/* ARL */
extern const struct pmc_bit_map arl_socs_ltr_show_map[];
extern const struct pmc_bit_map arl_socs_clocksource_status_map[];
extern const struct pmc_bit_map arl_socs_power_gating_status_0_map[];
extern const struct pmc_bit_map arl_socs_power_gating_status_1_map[];
extern const struct pmc_bit_map arl_socs_power_gating_status_2_map[];
extern const struct pmc_bit_map arl_socs_d3_status_2_map[];
extern const struct pmc_bit_map arl_socs_d3_status_3_map[];
extern const struct pmc_bit_map arl_socs_vnn_req_status_3_map[];
extern const struct pmc_bit_map *arl_socs_lpm_maps[];
extern const struct pmc_bit_map arl_socs_pfear_map[];
extern const struct pmc_bit_map *ext_arl_socs_pfear_map[];
extern const struct pmc_reg_map arl_socs_reg_map;
extern const struct pmc_bit_map arl_pchs_ltr_show_map[];
extern const struct pmc_bit_map arl_pchs_clocksource_status_map[];
extern const struct pmc_bit_map arl_pchs_power_gating_status_0_map[];
extern const struct pmc_bit_map arl_pchs_power_gating_status_1_map[];
extern const struct pmc_bit_map arl_pchs_power_gating_status_2_map[];
extern const struct pmc_bit_map arl_pchs_d3_status_0_map[];
extern const struct pmc_bit_map arl_pchs_d3_status_1_map[];
extern const struct pmc_bit_map arl_pchs_d3_status_2_map[];
extern const struct pmc_bit_map arl_pchs_d3_status_3_map[];
extern const struct pmc_bit_map arl_pchs_vnn_req_status_0_map[];
extern const struct pmc_bit_map arl_pchs_vnn_req_status_1_map[];
extern const struct pmc_bit_map arl_pchs_vnn_req_status_2_map[];
extern const struct pmc_bit_map arl_pchs_vnn_req_status_3_map[];
extern const struct pmc_bit_map arl_pchs_vnn_misc_status_map[];
extern const struct pmc_bit_map arl_pchs_signal_status_map[];
extern const struct pmc_bit_map *arl_pchs_lpm_maps[];
extern const struct pmc_reg_map arl_pchs_reg_map;
extern void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev);
extern int pmc_core_ssram_get_lpm_reqs(struct pmc_dev *pmcdev);
void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev);
int pmc_core_ssram_get_lpm_reqs(struct pmc_dev *pmcdev);
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);
extern void pmc_core_get_low_power_modes(struct pmc_dev *pmcdev);
extern void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 guid);
extern void pmc_core_set_device_d3(unsigned int device);
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_set_device_d3(unsigned int device);
extern int pmc_core_ssram_init(struct pmc_dev *pmcdev, int func);
int pmc_core_ssram_init(struct pmc_dev *pmcdev, int func);
int spt_core_init(struct pmc_dev *pmcdev);
int cnp_core_init(struct pmc_dev *pmcdev);
int icl_core_init(struct pmc_dev *pmcdev);
int tgl_core_init(struct pmc_dev *pmcdev);
int tgl_l_core_init(struct pmc_dev *pmcdev);
int tgl_core_generic_init(struct pmc_dev *pmcdev, int pch_tp);
int adl_core_init(struct pmc_dev *pmcdev);
int mtl_core_init(struct pmc_dev *pmcdev);
int arl_core_init(struct pmc_dev *pmcdev);
int lnl_core_init(struct pmc_dev *pmcdev);
int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info);
extern struct pmc_dev_info spt_pmc_dev;
extern struct pmc_dev_info cnp_pmc_dev;
extern struct pmc_dev_info icl_pmc_dev;
extern struct pmc_dev_info tgl_l_pmc_dev;
extern struct pmc_dev_info tgl_pmc_dev;
extern struct pmc_dev_info adl_pmc_dev;
extern struct pmc_dev_info mtl_pmc_dev;
extern struct pmc_dev_info arl_pmc_dev;
extern struct pmc_dev_info arl_h_pmc_dev;
extern struct pmc_dev_info lnl_pmc_dev;
extern struct pmc_dev_info ptl_pmc_dev;
void cnl_suspend(struct pmc_dev *pmcdev);
int cnl_resume(struct pmc_dev *pmcdev);

View File

@ -10,7 +10,7 @@
#include "core.h"
const struct pmc_bit_map icl_pfear_map[] = {
static const struct pmc_bit_map icl_pfear_map[] = {
{"RES_65", BIT(0)},
{"RES_66", BIT(1)},
{"RES_67", BIT(2)},
@ -22,7 +22,7 @@ const struct pmc_bit_map icl_pfear_map[] = {
{}
};
const struct pmc_bit_map *ext_icl_pfear_map[] = {
static const struct pmc_bit_map *ext_icl_pfear_map[] = {
/*
* Check intel_pmc_core_ids[] users of icl_reg_map for
* a list of core SoCs using this.
@ -32,7 +32,7 @@ const struct pmc_bit_map *ext_icl_pfear_map[] = {
NULL
};
const struct pmc_reg_map icl_reg_map = {
static const struct pmc_reg_map icl_reg_map = {
.pfear_sts = ext_icl_pfear_map,
.slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
.slp_s0_res_counter_step = ICL_PMC_SLP_S0_RES_COUNTER_STEP,
@ -50,18 +50,6 @@ const struct pmc_reg_map icl_reg_map = {
.etr3_offset = ETR3_OFFSET,
};
int icl_core_init(struct pmc_dev *pmcdev)
{
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
int ret;
pmc->map = &icl_reg_map;
ret = get_primary_reg_base(pmc);
if (ret)
return ret;
pmc_core_get_low_power_modes(pmcdev);
return ret;
}
struct pmc_dev_info icl_pmc_dev = {
.map = &icl_reg_map,
};

View File

@ -13,7 +13,7 @@
#include "core.h"
const struct pmc_bit_map lnl_ltr_show_map[] = {
static const struct pmc_bit_map lnl_ltr_show_map[] = {
{"SOUTHPORT_A", CNP_PMC_LTR_SPA},
{"SOUTHPORT_B", CNP_PMC_LTR_SPB},
{"SATA", CNP_PMC_LTR_SATA},
@ -55,7 +55,7 @@ const struct pmc_bit_map lnl_ltr_show_map[] = {
{}
};
const struct pmc_bit_map lnl_power_gating_status_0_map[] = {
static const struct pmc_bit_map lnl_power_gating_status_0_map[] = {
{"PMC_PGD0_PG_STS", BIT(0), 0},
{"FUSE_OSSE_PGD0_PG_STS", BIT(1), 0},
{"ESPISPI_PGD0_PG_STS", BIT(2), 0},
@ -91,7 +91,7 @@ const struct pmc_bit_map lnl_power_gating_status_0_map[] = {
{}
};
const struct pmc_bit_map lnl_power_gating_status_1_map[] = {
static const struct pmc_bit_map lnl_power_gating_status_1_map[] = {
{"USBR0_PGD0_PG_STS", BIT(0), 1},
{"SUSRAM_PGD0_PG_STS", BIT(1), 1},
{"SMT1_PGD0_PG_STS", BIT(2), 1},
@ -127,7 +127,7 @@ const struct pmc_bit_map lnl_power_gating_status_1_map[] = {
{}
};
const struct pmc_bit_map lnl_power_gating_status_2_map[] = {
static const struct pmc_bit_map lnl_power_gating_status_2_map[] = {
{"PSF8_PGD0_PG_STS", BIT(0), 0},
{"SBR16B2_PGD0_PG_STS", BIT(1), 0},
{"D2D_IPU_PGD0_PG_STS", BIT(2), 1},
@ -163,7 +163,7 @@ const struct pmc_bit_map lnl_power_gating_status_2_map[] = {
{}
};
const struct pmc_bit_map lnl_d3_status_0_map[] = {
static const struct pmc_bit_map lnl_d3_status_0_map[] = {
{"LPSS_D3_STS", BIT(3), 1},
{"XDCI_D3_STS", BIT(4), 1},
{"XHCI_D3_STS", BIT(5), 1},
@ -175,7 +175,7 @@ const struct pmc_bit_map lnl_d3_status_0_map[] = {
{}
};
const struct pmc_bit_map lnl_d3_status_1_map[] = {
static const struct pmc_bit_map lnl_d3_status_1_map[] = {
{"OSSE_SMT1_D3_STS", BIT(7), 0},
{"GBE_D3_STS", BIT(19), 0},
{"ITSS_D3_STS", BIT(23), 0},
@ -185,7 +185,7 @@ const struct pmc_bit_map lnl_d3_status_1_map[] = {
{}
};
const struct pmc_bit_map lnl_d3_status_2_map[] = {
static const struct pmc_bit_map lnl_d3_status_2_map[] = {
{"ESE_D3_STS", BIT(0), 0},
{"CSMERTC_D3_STS", BIT(1), 0},
{"SUSRAM_D3_STS", BIT(2), 0},
@ -205,7 +205,7 @@ const struct pmc_bit_map lnl_d3_status_2_map[] = {
{}
};
const struct pmc_bit_map lnl_d3_status_3_map[] = {
static const struct pmc_bit_map lnl_d3_status_3_map[] = {
{"THC0_D3_STS", BIT(14), 1},
{"THC1_D3_STS", BIT(15), 1},
{"OSSE_SMT3_D3_STS", BIT(21), 0},
@ -213,14 +213,14 @@ const struct pmc_bit_map lnl_d3_status_3_map[] = {
{}
};
const struct pmc_bit_map lnl_vnn_req_status_0_map[] = {
static const struct pmc_bit_map lnl_vnn_req_status_0_map[] = {
{"LPSS_VNN_REQ_STS", BIT(3), 1},
{"OSSE_VNN_REQ_STS", BIT(15), 1},
{"ESPISPI_VNN_REQ_STS", BIT(18), 1},
{}
};
const struct pmc_bit_map lnl_vnn_req_status_1_map[] = {
static const struct pmc_bit_map lnl_vnn_req_status_1_map[] = {
{"NPK_VNN_REQ_STS", BIT(4), 1},
{"OSSE_SMT1_VNN_REQ_STS", BIT(7), 1},
{"DFXAGG_VNN_REQ_STS", BIT(8), 0},
@ -232,7 +232,7 @@ const struct pmc_bit_map lnl_vnn_req_status_1_map[] = {
{}
};
const struct pmc_bit_map lnl_vnn_req_status_2_map[] = {
static const struct pmc_bit_map lnl_vnn_req_status_2_map[] = {
{"eSE_VNN_REQ_STS", BIT(0), 1},
{"CSMERTC_VNN_REQ_STS", BIT(1), 1},
{"CSE_VNN_REQ_STS", BIT(4), 1},
@ -249,14 +249,14 @@ const struct pmc_bit_map lnl_vnn_req_status_2_map[] = {
{}
};
const struct pmc_bit_map lnl_vnn_req_status_3_map[] = {
static const struct pmc_bit_map lnl_vnn_req_status_3_map[] = {
{"DISP_SHIM_VNN_REQ_STS", BIT(2), 0},
{"DTS0_VNN_REQ_STS", BIT(7), 0},
{"GPIOCOM5_VNN_REQ_STS", BIT(11), 2},
{}
};
const struct pmc_bit_map lnl_vnn_misc_status_map[] = {
static const struct pmc_bit_map lnl_vnn_misc_status_map[] = {
{"CPU_C10_REQ_STS", BIT(0), 0},
{"TS_OFF_REQ_STS", BIT(1), 0},
{"PNDE_MET_REQ_STS", BIT(2), 1},
@ -292,7 +292,7 @@ const struct pmc_bit_map lnl_vnn_misc_status_map[] = {
{}
};
const struct pmc_bit_map lnl_clocksource_status_map[] = {
static const struct pmc_bit_map lnl_clocksource_status_map[] = {
{"AON2_OFF_STS", BIT(0), 0},
{"AON3_OFF_STS", BIT(1), 1},
{"AON4_OFF_STS", BIT(2), 1},
@ -317,7 +317,7 @@ const struct pmc_bit_map lnl_clocksource_status_map[] = {
{}
};
const struct pmc_bit_map lnl_signal_status_map[] = {
static const struct pmc_bit_map lnl_signal_status_map[] = {
{"LSX_Wake0_STS", BIT(0), 0},
{"LSX_Wake1_STS", BIT(1), 0},
{"LSX_Wake2_STS", BIT(2), 0},
@ -337,7 +337,7 @@ const struct pmc_bit_map lnl_signal_status_map[] = {
{}
};
const struct pmc_bit_map lnl_rsc_status_map[] = {
static const struct pmc_bit_map lnl_rsc_status_map[] = {
{"Memory", 0, 1},
{"PSF0", 0, 1},
{"PSF4", 0, 1},
@ -349,7 +349,7 @@ const struct pmc_bit_map lnl_rsc_status_map[] = {
{}
};
const struct pmc_bit_map *lnl_lpm_maps[] = {
static const struct pmc_bit_map *lnl_lpm_maps[] = {
lnl_clocksource_status_map,
lnl_power_gating_status_0_map,
lnl_power_gating_status_1_map,
@ -367,7 +367,7 @@ const struct pmc_bit_map *lnl_lpm_maps[] = {
NULL
};
const struct pmc_bit_map *lnl_blk_maps[] = {
static const struct pmc_bit_map *lnl_blk_maps[] = {
lnl_power_gating_status_0_map,
lnl_power_gating_status_1_map,
lnl_power_gating_status_2_map,
@ -386,7 +386,7 @@ const struct pmc_bit_map *lnl_blk_maps[] = {
NULL
};
const struct pmc_bit_map lnl_pfear_map[] = {
static const struct pmc_bit_map lnl_pfear_map[] = {
{"PMC_0", BIT(0)},
{"FUSE_OSSE", BIT(1)},
{"ESPISPI", BIT(2)},
@ -498,12 +498,12 @@ const struct pmc_bit_map lnl_pfear_map[] = {
{}
};
const struct pmc_bit_map *ext_lnl_pfear_map[] = {
static const struct pmc_bit_map *ext_lnl_pfear_map[] = {
lnl_pfear_map,
NULL
};
const struct pmc_reg_map lnl_socm_reg_map = {
static const struct pmc_reg_map lnl_socm_reg_map = {
.pfear_sts = ext_lnl_pfear_map,
.slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
.slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP,
@ -550,22 +550,15 @@ static int lnl_resume(struct pmc_dev *pmcdev)
return cnl_resume(pmcdev);
}
int lnl_core_init(struct pmc_dev *pmcdev)
static int lnl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
{
int ret;
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_SOC];
lnl_d3_fixup();
pmcdev->suspend = cnl_suspend;
pmcdev->resume = lnl_resume;
pmc->map = &lnl_socm_reg_map;
ret = get_primary_reg_base(pmc);
if (ret)
return ret;
pmc_core_get_low_power_modes(pmcdev);
return 0;
return generic_core_init(pmcdev, pmc_dev_info);
}
struct pmc_dev_info lnl_pmc_dev = {
.map = &lnl_socm_reg_map,
.suspend = cnl_suspend,
.resume = lnl_resume,
.init = lnl_core_init,
};

View File

@ -102,12 +102,12 @@ const struct pmc_bit_map mtl_socm_pfear_map[] = {
{}
};
const struct pmc_bit_map *ext_mtl_socm_pfear_map[] = {
static const struct pmc_bit_map *ext_mtl_socm_pfear_map[] = {
mtl_socm_pfear_map,
NULL
};
const struct pmc_bit_map mtl_socm_ltr_show_map[] = {
static const struct pmc_bit_map mtl_socm_ltr_show_map[] = {
{"SOUTHPORT_A", CNP_PMC_LTR_SPA},
{"SOUTHPORT_B", CNP_PMC_LTR_SPB},
{"SATA", CNP_PMC_LTR_SATA},
@ -141,7 +141,7 @@ const struct pmc_bit_map mtl_socm_ltr_show_map[] = {
{}
};
const struct pmc_bit_map mtl_socm_clocksource_status_map[] = {
static const struct pmc_bit_map mtl_socm_clocksource_status_map[] = {
{"AON2_OFF_STS", BIT(0)},
{"AON3_OFF_STS", BIT(1)},
{"AON4_OFF_STS", BIT(2)},
@ -167,7 +167,7 @@ const struct pmc_bit_map mtl_socm_clocksource_status_map[] = {
{}
};
const struct pmc_bit_map mtl_socm_power_gating_status_0_map[] = {
static const struct pmc_bit_map mtl_socm_power_gating_status_0_map[] = {
{"PMC_PGD0_PG_STS", BIT(0)},
{"DMI_PGD0_PG_STS", BIT(1)},
{"ESPISPI_PGD0_PG_STS", BIT(2)},
@ -203,7 +203,7 @@ const struct pmc_bit_map mtl_socm_power_gating_status_0_map[] = {
{}
};
const struct pmc_bit_map mtl_socm_power_gating_status_1_map[] = {
static const struct pmc_bit_map mtl_socm_power_gating_status_1_map[] = {
{"USBR0_PGD0_PG_STS", BIT(0)},
{"SUSRAM_PGD0_PG_STS", BIT(1)},
{"SMT1_PGD0_PG_STS", BIT(2)},
@ -239,7 +239,7 @@ const struct pmc_bit_map mtl_socm_power_gating_status_1_map[] = {
{}
};
const struct pmc_bit_map mtl_socm_power_gating_status_2_map[] = {
static const struct pmc_bit_map mtl_socm_power_gating_status_2_map[] = {
{"PSF8_PGD0_PG_STS", BIT(0)},
{"FIA_PGD0_PG_STS", BIT(1)},
{"SOC_D2D_PGD1_PG_STS", BIT(2)},
@ -291,7 +291,7 @@ const struct pmc_bit_map mtl_socm_d3_status_1_map[] = {
{}
};
const struct pmc_bit_map mtl_socm_d3_status_2_map[] = {
static const struct pmc_bit_map mtl_socm_d3_status_2_map[] = {
{"GNA_D3_STS", BIT(0)},
{"CSMERTC_D3_STS", BIT(1)},
{"SUSRAM_D3_STS", BIT(2)},
@ -310,7 +310,7 @@ const struct pmc_bit_map mtl_socm_d3_status_2_map[] = {
{}
};
const struct pmc_bit_map mtl_socm_d3_status_3_map[] = {
static const struct pmc_bit_map mtl_socm_d3_status_3_map[] = {
{"ESE_D3_STS", BIT(2)},
{"GBETSN_D3_STS", BIT(13)},
{"THC0_D3_STS", BIT(14)},
@ -353,7 +353,7 @@ const struct pmc_bit_map mtl_socm_vnn_req_status_2_map[] = {
{}
};
const struct pmc_bit_map mtl_socm_vnn_req_status_3_map[] = {
static const struct pmc_bit_map mtl_socm_vnn_req_status_3_map[] = {
{"ESE_VNN_REQ_STS", BIT(2)},
{"DTS0_VNN_REQ_STS", BIT(7)},
{"GPIOCOM5_VNN_REQ_STS", BIT(11)},
@ -432,7 +432,7 @@ const struct pmc_bit_map mtl_socm_signal_status_map[] = {
{}
};
const struct pmc_bit_map *mtl_socm_lpm_maps[] = {
static const struct pmc_bit_map *mtl_socm_lpm_maps[] = {
mtl_socm_clocksource_status_map,
mtl_socm_power_gating_status_0_map,
mtl_socm_power_gating_status_1_map,
@ -476,7 +476,7 @@ const struct pmc_reg_map mtl_socm_reg_map = {
.lpm_reg_index = MTL_LPM_REG_INDEX,
};
const struct pmc_bit_map mtl_ioep_pfear_map[] = {
static const struct pmc_bit_map mtl_ioep_pfear_map[] = {
{"PMC_0", BIT(0)},
{"OPI", BIT(1)},
{"TCSS", BIT(2)},
@ -563,12 +563,12 @@ const struct pmc_bit_map mtl_ioep_pfear_map[] = {
{}
};
const struct pmc_bit_map *ext_mtl_ioep_pfear_map[] = {
static const struct pmc_bit_map *ext_mtl_ioep_pfear_map[] = {
mtl_ioep_pfear_map,
NULL
};
const struct pmc_bit_map mtl_ioep_ltr_show_map[] = {
static const struct pmc_bit_map mtl_ioep_ltr_show_map[] = {
{"SOUTHPORT_A", CNP_PMC_LTR_SPA},
{"SOUTHPORT_B", CNP_PMC_LTR_SPB},
{"SATA", CNP_PMC_LTR_SATA},
@ -600,7 +600,7 @@ const struct pmc_bit_map mtl_ioep_ltr_show_map[] = {
{}
};
const struct pmc_bit_map mtl_ioep_clocksource_status_map[] = {
static const struct pmc_bit_map mtl_ioep_clocksource_status_map[] = {
{"AON2_OFF_STS", BIT(0)},
{"AON3_OFF_STS", BIT(1)},
{"AON4_OFF_STS", BIT(2)},
@ -623,7 +623,7 @@ const struct pmc_bit_map mtl_ioep_clocksource_status_map[] = {
{}
};
const struct pmc_bit_map mtl_ioep_power_gating_status_0_map[] = {
static const struct pmc_bit_map mtl_ioep_power_gating_status_0_map[] = {
{"PMC_PGD0_PG_STS", BIT(0)},
{"DMI_PGD0_PG_STS", BIT(1)},
{"TCSS_PGD0_PG_STS", BIT(2)},
@ -650,7 +650,7 @@ const struct pmc_bit_map mtl_ioep_power_gating_status_0_map[] = {
{}
};
const struct pmc_bit_map mtl_ioep_power_gating_status_1_map[] = {
static const struct pmc_bit_map mtl_ioep_power_gating_status_1_map[] = {
{"PSF9_PGD0_PG_STS", BIT(0)},
{"MPFPW4_PGD0_PG_STS", BIT(1)},
{"SBR0_PGD0_PG_STS", BIT(8)},
@ -668,7 +668,7 @@ const struct pmc_bit_map mtl_ioep_power_gating_status_1_map[] = {
{}
};
const struct pmc_bit_map mtl_ioep_power_gating_status_2_map[] = {
static const struct pmc_bit_map mtl_ioep_power_gating_status_2_map[] = {
{"FIA_PGD0_PG_STS", BIT(1)},
{"FIA_P_PGD0_PG_STS", BIT(3)},
{"TAM_PGD0_PG_STS", BIT(4)},
@ -680,7 +680,7 @@ const struct pmc_bit_map mtl_ioep_power_gating_status_2_map[] = {
{}
};
const struct pmc_bit_map mtl_ioep_d3_status_0_map[] = {
static const struct pmc_bit_map mtl_ioep_d3_status_0_map[] = {
{"SPF_D3_STS", BIT(0)},
{"SPA_D3_STS", BIT(12)},
{"SPB_D3_STS", BIT(13)},
@ -691,43 +691,43 @@ const struct pmc_bit_map mtl_ioep_d3_status_0_map[] = {
{}
};
const struct pmc_bit_map mtl_ioep_d3_status_1_map[] = {
static const struct pmc_bit_map mtl_ioep_d3_status_1_map[] = {
{"GBETSN1_D3_STS", BIT(14)},
{"P2S_D3_STS", BIT(24)},
{}
};
const struct pmc_bit_map mtl_ioep_d3_status_2_map[] = {
static const struct pmc_bit_map mtl_ioep_d3_status_2_map[] = {
{}
};
const struct pmc_bit_map mtl_ioep_d3_status_3_map[] = {
static const struct pmc_bit_map mtl_ioep_d3_status_3_map[] = {
{"GBETSN_D3_STS", BIT(13)},
{"ACE_D3_STS", BIT(23)},
{}
};
const struct pmc_bit_map mtl_ioep_vnn_req_status_0_map[] = {
static const struct pmc_bit_map mtl_ioep_vnn_req_status_0_map[] = {
{"FIA_VNN_REQ_STS", BIT(17)},
{}
};
const struct pmc_bit_map mtl_ioep_vnn_req_status_1_map[] = {
static const struct pmc_bit_map mtl_ioep_vnn_req_status_1_map[] = {
{"DFXAGG_VNN_REQ_STS", BIT(8)},
{}
};
const struct pmc_bit_map mtl_ioep_vnn_req_status_2_map[] = {
static const struct pmc_bit_map mtl_ioep_vnn_req_status_2_map[] = {
{}
};
const struct pmc_bit_map mtl_ioep_vnn_req_status_3_map[] = {
static const struct pmc_bit_map mtl_ioep_vnn_req_status_3_map[] = {
{"DTS0_VNN_REQ_STS", BIT(7)},
{"DISP_VNN_REQ_STS", BIT(19)},
{}
};
const struct pmc_bit_map mtl_ioep_vnn_misc_status_map[] = {
static const struct pmc_bit_map mtl_ioep_vnn_misc_status_map[] = {
{"CPU_C10_REQ_STS", BIT(0)},
{"TS_OFF_REQ_STS", BIT(1)},
{"PNDE_MET_REQ_STS", BIT(2)},
@ -762,7 +762,7 @@ const struct pmc_bit_map mtl_ioep_vnn_misc_status_map[] = {
{}
};
const struct pmc_bit_map *mtl_ioep_lpm_maps[] = {
static const struct pmc_bit_map *mtl_ioep_lpm_maps[] = {
mtl_ioep_clocksource_status_map,
mtl_ioep_power_gating_status_0_map,
mtl_ioep_power_gating_status_1_map,
@ -800,7 +800,7 @@ const struct pmc_reg_map mtl_ioep_reg_map = {
.lpm_reg_index = MTL_LPM_REG_INDEX,
};
const struct pmc_bit_map mtl_ioem_pfear_map[] = {
static const struct pmc_bit_map mtl_ioem_pfear_map[] = {
{"PMC_0", BIT(0)},
{"OPI", BIT(1)},
{"TCSS", BIT(2)},
@ -887,12 +887,12 @@ const struct pmc_bit_map mtl_ioem_pfear_map[] = {
{}
};
const struct pmc_bit_map *ext_mtl_ioem_pfear_map[] = {
static const struct pmc_bit_map *ext_mtl_ioem_pfear_map[] = {
mtl_ioem_pfear_map,
NULL
};
const struct pmc_bit_map mtl_ioem_power_gating_status_1_map[] = {
static const struct pmc_bit_map mtl_ioem_power_gating_status_1_map[] = {
{"PSF9_PGD0_PG_STS", BIT(0)},
{"MPFPW4_PGD0_PG_STS", BIT(1)},
{"SBR0_PGD0_PG_STS", BIT(8)},
@ -909,7 +909,7 @@ const struct pmc_bit_map mtl_ioem_power_gating_status_1_map[] = {
{}
};
const struct pmc_bit_map *mtl_ioem_lpm_maps[] = {
static const struct pmc_bit_map *mtl_ioem_lpm_maps[] = {
mtl_ioep_clocksource_status_map,
mtl_ioep_power_gating_status_0_map,
mtl_ioem_power_gating_status_1_map,
@ -927,7 +927,7 @@ const struct pmc_bit_map *mtl_ioem_lpm_maps[] = {
NULL
};
const struct pmc_reg_map mtl_ioem_reg_map = {
static const struct pmc_reg_map mtl_ioem_reg_map = {
.regmap_length = MTL_IOE_PMC_MMIO_REG_LEN,
.pfear_sts = ext_mtl_ioem_pfear_map,
.ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
@ -990,39 +990,18 @@ static int mtl_resume(struct pmc_dev *pmcdev)
return cnl_resume(pmcdev);
}
int mtl_core_init(struct pmc_dev *pmcdev)
static int mtl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
{
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_SOC];
int ret;
int func = 2;
bool ssram_init = true;
mtl_d3_fixup();
pmcdev->suspend = cnl_suspend;
pmcdev->resume = mtl_resume;
pmcdev->regmap_list = mtl_pmc_info_list;
/*
* If ssram init fails use legacy method to at least get the
* primary PMC
*/
ret = pmc_core_ssram_init(pmcdev, func);
if (ret) {
ssram_init = false;
dev_warn(&pmcdev->pdev->dev,
"ssram init failed, %d, using legacy init\n", ret);
pmc->map = &mtl_socm_reg_map;
ret = get_primary_reg_base(pmc);
if (ret)
return ret;
}
pmc_core_get_low_power_modes(pmcdev);
pmc_core_punit_pmt_init(pmcdev, MTL_PMT_DMU_GUID);
if (ssram_init)
return pmc_core_ssram_get_lpm_reqs(pmcdev);
return 0;
return generic_core_init(pmcdev, pmc_dev_info);
}
struct pmc_dev_info mtl_pmc_dev = {
.pci_func = 2,
.dmu_guid = MTL_PMT_DMU_GUID,
.regmap_list = mtl_pmc_info_list,
.map = &mtl_socm_reg_map,
.suspend = cnl_suspend,
.resume = mtl_resume,
.init = mtl_core_init,
};

View File

@ -0,0 +1,550 @@
// SPDX-License-Identifier: GPL-2.0
/*
* This file contains platform specific structure definitions
* and init function used by Panther Lake PCH.
*
* Copyright (c) 2025, Intel Corporation.
*/
#include <linux/pci.h>
#include "core.h"
static const struct pmc_bit_map ptl_pcdp_pfear_map[] = {
{"PMC_0", BIT(0)},
{"FUSE_OSSE", BIT(1)},
{"ESPISPI", BIT(2)},
{"XHCI", BIT(3)},
{"SPA", BIT(4)},
{"SPB", BIT(5)},
{"MPFPW2", BIT(6)},
{"GBE", BIT(7)},
{"SBR16B20", BIT(0)},
{"SBR8B20", BIT(1)},
{"SBR16B21", BIT(2)},
{"DBG_SBR16B", BIT(3)},
{"OSSE_HOTHAM", BIT(4)},
{"D2D_DISP_1", BIT(5)},
{"LPSS", BIT(6)},
{"LPC", BIT(7)},
{"SMB", BIT(0)},
{"ISH", BIT(1)},
{"SBR16B2", BIT(2)},
{"NPK_0", BIT(3)},
{"D2D_NOC_1", BIT(4)},
{"SBR8B2", BIT(5)},
{"FUSE", BIT(6)},
{"SBR16B0", BIT(7)},
{"PSF0", BIT(0)},
{"XDCI", BIT(1)},
{"EXI", BIT(2)},
{"CSE", BIT(3)},
{"KVMCC", BIT(4)},
{"PMT", BIT(5)},
{"CLINK", BIT(6)},
{"PTIO", BIT(7)},
{"USBR0", BIT(0)},
{"SUSRAM", BIT(1)},
{"SMT1", BIT(2)},
{"MPFPW1", BIT(3)},
{"SMS2", BIT(4)},
{"SMS1", BIT(5)},
{"CSMERTC", BIT(6)},
{"CSMEPSF", BIT(7)},
{"D2D_NOC_0", BIT(0)},
{"ESE", BIT(1)},
{"P2SB8B", BIT(2)},
{"SBR16B7", BIT(3)},
{"SBR16B3", BIT(4)},
{"OSSE_SMT1", BIT(5)},
{"D2D_DISP", BIT(6)},
{"DBG_SBR", BIT(7)},
{"U3FPW1", BIT(0)},
{"FIA_X", BIT(1)},
{"PSF4", BIT(2)},
{"CNVI", BIT(3)},
{"UFSX2", BIT(4)},
{"ENDBG", BIT(5)},
{"DBC", BIT(6)},
{"FIA_PG", BIT(7)},
{"D2D_IPU", BIT(0)},
{"NPK1", BIT(1)},
{"FIACPCB_X", BIT(2)},
{"SBR8B4", BIT(3)},
{"DBG_PSF", BIT(4)},
{"PSF6", BIT(5)},
{"UFSPW1", BIT(6)},
{"FIA_U", BIT(7)},
{"PSF8", BIT(0)},
{"SBR16B4", BIT(1)},
{"SBR16B5", BIT(2)},
{"FIACPCB_U", BIT(3)},
{"TAM", BIT(4)},
{"D2D_NOC_2", BIT(5)},
{"TBTLSX", BIT(6)},
{"THC0", BIT(7)},
{"THC1", BIT(0)},
{"PMC_1", BIT(1)},
{"SBR8B1", BIT(2)},
{"TCSS", BIT(3)},
{"DISP_PGA", BIT(4)},
{"SBR16B1", BIT(5)},
{"SBRG", BIT(6)},
{"PSF5", BIT(7)},
{"P2SB16B", BIT(0)},
{"ACE_0", BIT(1)},
{"ACE_1", BIT(2)},
{"ACE_2", BIT(3)},
{"ACE_3", BIT(4)},
{"ACE_4", BIT(5)},
{"ACE_5", BIT(6)},
{"ACE_6", BIT(7)},
{"ACE_7", BIT(0)},
{"ACE_8", BIT(1)},
{"ACE_9", BIT(2)},
{"ACE_10", BIT(3)},
{"FIACPCB_PG", BIT(4)},
{"SBR16B6", BIT(5)},
{"OSSE", BIT(6)},
{"SBR8B0", BIT(7)},
{}
};
static const struct pmc_bit_map *ext_ptl_pcdp_pfear_map[] = {
ptl_pcdp_pfear_map,
NULL
};
static const struct pmc_bit_map ptl_pcdp_ltr_show_map[] = {
{"SOUTHPORT_A", CNP_PMC_LTR_SPA},
{"SOUTHPORT_B", CNP_PMC_LTR_SPB},
{"SATA", CNP_PMC_LTR_SATA},
{"GIGABIT_ETHERNET", CNP_PMC_LTR_GBE},
{"XHCI", CNP_PMC_LTR_XHCI},
{"SOUTHPORT_F", ADL_PMC_LTR_SPF},
{"ME", CNP_PMC_LTR_ME},
{"SATA1", CNP_PMC_LTR_EVA},
{"SOUTHPORT_C", CNP_PMC_LTR_SPC},
{"HD_AUDIO", CNP_PMC_LTR_AZ},
{"CNV", CNP_PMC_LTR_CNV},
{"LPSS", CNP_PMC_LTR_LPSS},
{"SOUTHPORT_D", CNP_PMC_LTR_SPD},
{"SOUTHPORT_E", CNP_PMC_LTR_SPE},
{"SATA2", PTL_PMC_LTR_SATA2},
{"ESPI", CNP_PMC_LTR_ESPI},
{"SCC", CNP_PMC_LTR_SCC},
{"ISH", CNP_PMC_LTR_ISH},
{"UFSX2", CNP_PMC_LTR_UFSX2},
{"EMMC", CNP_PMC_LTR_EMMC},
{"WIGIG", ICL_PMC_LTR_WIGIG},
{"THC0", TGL_PMC_LTR_THC0},
{"THC1", TGL_PMC_LTR_THC1},
{"SOUTHPORT_G", MTL_PMC_LTR_SPG},
{"ESE", MTL_PMC_LTR_ESE},
{"IOE_PMC", MTL_PMC_LTR_IOE_PMC},
{"DMI3", ARL_PMC_LTR_DMI3},
{"OSSE", LNL_PMC_LTR_OSSE},
/* Below two cannot be used for LTR_IGNORE */
{"CURRENT_PLATFORM", PTL_PMC_LTR_CUR_PLT},
{"AGGREGATED_SYSTEM", PTL_PMC_LTR_CUR_ASLT},
{}
};
static const struct pmc_bit_map ptl_pcdp_clocksource_status_map[] = {
{"AON2_OFF_STS", BIT(0), 1},
{"AON3_OFF_STS", BIT(1), 0},
{"AON4_OFF_STS", BIT(2), 1},
{"AON5_OFF_STS", BIT(3), 1},
{"AON1_OFF_STS", BIT(4), 0},
{"XTAL_LVM_OFF_STS", BIT(5), 0},
{"MPFPW1_0_PLL_OFF_STS", BIT(6), 1},
{"USB3_PLL_OFF_STS", BIT(8), 1},
{"AON3_SPL_OFF_STS", BIT(9), 1},
{"MPFPW2_0_PLL_OFF_STS", BIT(12), 1},
{"XTAL_AGGR_OFF_STS", BIT(17), 1},
{"USB2_PLL_OFF_STS", BIT(18), 0},
{"SAF_PLL_OFF_STS", BIT(19), 1},
{"SE_TCSS_PLL_OFF_STS", BIT(20), 1},
{"DDI_PLL_OFF_STS", BIT(21), 1},
{"FILTER_PLL_OFF_STS", BIT(22), 1},
{"ACE_PLL_OFF_STS", BIT(24), 0},
{"FABRIC_PLL_OFF_STS", BIT(25), 1},
{"SOC_PLL_OFF_STS", BIT(26), 1},
{"REF_PLL_OFF_STS", BIT(28), 1},
{"IMG_PLL_OFF_STS", BIT(29), 1},
{"RTC_PLL_OFF_STS", BIT(31), 0},
{}
};
static const struct pmc_bit_map ptl_pcdp_power_gating_status_0_map[] = {
{"PMC_PGD0_PG_STS", BIT(0), 0},
{"FUSE_OSSE_PGD0_PG_STS", BIT(1), 0},
{"ESPISPI_PGD0_PG_STS", BIT(2), 0},
{"XHCI_PGD0_PG_STS", BIT(3), 1},
{"SPA_PGD0_PG_STS", BIT(4), 1},
{"SPB_PGD0_PG_STS", BIT(5), 1},
{"MPFPW2_PGD0_PG_STS", BIT(6), 0},
{"GBE_PGD0_PG_STS", BIT(7), 1},
{"SBR16B20_PGD0_PG_STS", BIT(8), 0},
{"SBR8B20_PGD0_PG_STS", BIT(9), 0},
{"SBR16B21_PGD0_PG_STS", BIT(10), 0},
{"DBG_PGD0_PG_STS", BIT(11), 0},
{"OSSE_HOTHAM_PGD0_PG_STS", BIT(12), 1},
{"D2D_DISP_PGD1_PG_STS", BIT(13), 1},
{"LPSS_PGD0_PG_STS", BIT(14), 1},
{"LPC_PGD0_PG_STS", BIT(15), 0},
{"SMB_PGD0_PG_STS", BIT(16), 0},
{"ISH_PGD0_PG_STS", BIT(17), 0},
{"SBR16B2_PGD0_PG_STS", BIT(18), 0},
{"NPK_PGD0_PG_STS", BIT(19), 0},
{"D2D_NOC_PGD1_PG_STS", BIT(20), 1},
{"SBR8B2_PGD0_PG_STS", BIT(21), 0},
{"FUSE_PGD0_PG_STS", BIT(22), 0},
{"SBR16B0_PGD0_PG_STS", BIT(23), 0},
{"PSF0_PGD0_PG_STS", BIT(24), 0},
{"XDCI_PGD0_PG_STS", BIT(25), 1},
{"EXI_PGD0_PG_STS", BIT(26), 0},
{"CSE_PGD0_PG_STS", BIT(27), 1},
{"KVMCC_PGD0_PG_STS", BIT(28), 1},
{"PMT_PGD0_PG_STS", BIT(29), 1},
{"CLINK_PGD0_PG_STS", BIT(30), 1},
{"PTIO_PGD0_PG_STS", BIT(31), 1},
{}
};
static const struct pmc_bit_map ptl_pcdp_power_gating_status_1_map[] = {
{"USBR0_PGD0_PG_STS", BIT(0), 1},
{"SUSRAM_PGD0_PG_STS", BIT(1), 1},
{"SMT1_PGD0_PG_STS", BIT(2), 1},
{"MPFPW1_PGD0_PG_STS", BIT(3), 0},
{"SMS2_PGD0_PG_STS", BIT(4), 1},
{"SMS1_PGD0_PG_STS", BIT(5), 1},
{"CSMERTC_PGD0_PG_STS", BIT(6), 0},
{"CSMEPSF_PGD0_PG_STS", BIT(7), 0},
{"D2D_NOC_PGD0_PG_STS", BIT(8), 0},
{"ESE_PGD0_PG_STS", BIT(9), 1},
{"P2SB8B_PGD0_PG_STS", BIT(10), 1},
{"SBR16B7_PGD0_PG_STS", BIT(11), 0},
{"SBR16B3_PGD0_PG_STS", BIT(12), 0},
{"OSSE_SMT1_PGD0_PG_STS", BIT(13), 1},
{"D2D_DISP_PGD0_PG_STS", BIT(14), 1},
{"DBG_SBR_PGD0_PG_STS", BIT(15), 0},
{"U3FPW1_PGD0_PG_STS", BIT(16), 0},
{"FIA_X_PGD0_PG_STS", BIT(17), 0},
{"PSF4_PGD0_PG_STS", BIT(18), 0},
{"CNVI_PGD0_PG_STS", BIT(19), 0},
{"UFSX2_PGD0_PG_STS", BIT(20), 1},
{"ENDBG_PGD0_PG_STS", BIT(21), 0},
{"DBC_PGD0_PG_STS", BIT(22), 0},
{"FIA_PG_PGD0_PG_STS", BIT(23), 0},
{"D2D_IPU_PGD0_PG_STS", BIT(24), 1},
{"NPK_PGD1_PG_STS", BIT(25), 0},
{"FIACPCB_X_PGD0_PG_STS", BIT(26), 0},
{"SBR8B4_PGD0_PG_STS", BIT(27), 0},
{"DBG_PSF_PGD0_PG_STS", BIT(28), 0},
{"PSF6_PGD0_PG_STS", BIT(29), 0},
{"UFSPW1_PGD0_PG_STS", BIT(30), 0},
{"FIA_U_PGD0_PG_STS", BIT(31), 0},
{}
};
static const struct pmc_bit_map ptl_pcdp_power_gating_status_2_map[] = {
{"PSF8_PGD0_PG_STS", BIT(0), 0},
{"SBR16B4_PGD0_PG_STS", BIT(1), 0},
{"SBR16B5_PGD0_PG_STS", BIT(2), 0},
{"FIACPCB_U_PGD0_PG_STS", BIT(3), 0},
{"TAM_PGD0_PG_STS", BIT(4), 1},
{"D2D_NOC_PGD0_PG_STS", BIT(5), 1},
{"TBTLSX_PGD0_PG_STS", BIT(6), 1},
{"THC0_PGD0_PG_STS", BIT(7), 1},
{"THC1_PGD0_PG_STS", BIT(8), 1},
{"PMC_PGD1_PG_STS", BIT(9), 0},
{"SBR8B1_PGD0_PG_STS", BIT(10), 0},
{"TCSS_PGD0_PG_STS", BIT(11), 0},
{"DISP_PGA_PGD0_PG_STS", BIT(12), 0},
{"SBR16B1_PGD0_PG_STS", BIT(13), 0},
{"SBRG_PGD0_PG_STS", BIT(14), 0},
{"PSF5_PGD0_PG_STS", BIT(15), 0},
{"P2SB16B_PGD0_PG_STS", BIT(16), 1},
{"ACE_PGD0_PG_STS", BIT(17), 0},
{"ACE_PGD1_PG_STS", BIT(18), 0},
{"ACE_PGD2_PG_STS", BIT(19), 0},
{"ACE_PGD3_PG_STS", BIT(20), 0},
{"ACE_PGD4_PG_STS", BIT(21), 0},
{"ACE_PGD5_PG_STS", BIT(22), 0},
{"ACE_PGD6_PG_STS", BIT(23), 0},
{"ACE_PGD7_PG_STS", BIT(24), 0},
{"ACE_PGD8_PG_STS", BIT(25), 0},
{"ACE_PGD9_PG_STS", BIT(26), 0},
{"ACE_PGD10_PG_STS", BIT(27), 0},
{"FIACPCB_PG_PGD0_PG_STS", BIT(28), 0},
{"SBR16B6_PGD0_PG_STS", BIT(29), 0},
{"OSSE_PGD0_PG_STS", BIT(30), 1},
{"SBR8B0_PGD0_PG_STS", BIT(31), 0},
{}
};
static const struct pmc_bit_map ptl_pcdp_d3_status_0_map[] = {
{"LPSS_D3_STS", BIT(3), 1},
{"XDCI_D3_STS", BIT(4), 1},
{"XHCI_D3_STS", BIT(5), 1},
{"OSSE_D3_STS", BIT(6), 0},
{"SPA_D3_STS", BIT(12), 0},
{"SPB_D3_STS", BIT(13), 0},
{"ESPISPI_D3_STS", BIT(18), 0},
{"PSTH_D3_STS", BIT(21), 0},
{"OSSE_SMT1_D3_STS", BIT(30), 0},
{}
};
static const struct pmc_bit_map ptl_pcdp_d3_status_1_map[] = {
{"GBE_D3_STS", BIT(19), 0},
{"ITSS_D3_STS", BIT(23), 0},
{"CNVI_D3_STS", BIT(27), 0},
{"UFSX2_D3_STS", BIT(28), 1},
{"OSSE_HOTHAM_D3_STS", BIT(29), 0},
{"ESE_D3_STS", BIT(30), 0},
{}
};
static const struct pmc_bit_map ptl_pcdp_d3_status_2_map[] = {
{"CSMERTC_D3_STS", BIT(1), 0},
{"SUSRAM_D3_STS", BIT(2), 0},
{"CSE_D3_STS", BIT(4), 0},
{"KVMCC_D3_STS", BIT(5), 0},
{"USBR0_D3_STS", BIT(6), 0},
{"ISH_D3_STS", BIT(7), 0},
{"SMT1_D3_STS", BIT(8), 0},
{"SMT2_D3_STS", BIT(9), 0},
{"SMT3_D3_STS", BIT(10), 0},
{"OSSE_SMT2_D3_STS", BIT(12), 0},
{"CLINK_D3_STS", BIT(14), 0},
{"PTIO_D3_STS", BIT(16), 0},
{"PMT_D3_STS", BIT(17), 0},
{"SMS1_D3_STS", BIT(18), 0},
{"SMS2_D3_STS", BIT(19), 0},
{}
};
static const struct pmc_bit_map ptl_pcdp_d3_status_3_map[] = {
{"THC0_D3_STS", BIT(14), 1},
{"THC1_D3_STS", BIT(15), 1},
{"OSSE_SMT3_D3_STS", BIT(18), 0},
{"ACE_D3_STS", BIT(23), 0},
{}
};
static const struct pmc_bit_map ptl_pcdp_vnn_req_status_0_map[] = {
{"LPSS_VNN_REQ_STS", BIT(3), 1},
{"OSSE_VNN_REQ_STS", BIT(6), 1},
{"ESPISPI_VNN_REQ_STS", BIT(18), 1},
{"OSSE_SMT1_VNN_REQ_STS", BIT(30), 1},
{}
};
static const struct pmc_bit_map ptl_pcdp_vnn_req_status_1_map[] = {
{"NPK_VNN_REQ_STS", BIT(4), 1},
{"DFXAGG_VNN_REQ_STS", BIT(8), 0},
{"EXI_VNN_REQ_STS", BIT(9), 1},
{"P2D_VNN_REQ_STS", BIT(18), 1},
{"GBE_VNN_REQ_STS", BIT(19), 1},
{"SMB_VNN_REQ_STS", BIT(25), 1},
{"LPC_VNN_REQ_STS", BIT(26), 0},
{"ESE_VNN_REQ_STS", BIT(30), 1},
{}
};
static const struct pmc_bit_map ptl_pcdp_vnn_req_status_2_map[] = {
{"CSMERTC_VNN_REQ_STS", BIT(1), 1},
{"CSE_VNN_REQ_STS", BIT(4), 1},
{"ISH_VNN_REQ_STS", BIT(7), 1},
{"SMT1_VNN_REQ_STS", BIT(8), 1},
{"CLINK_VNN_REQ_STS", BIT(14), 1},
{"SMS1_VNN_REQ_STS", BIT(18), 1},
{"SMS2_VNN_REQ_STS", BIT(19), 1},
{"GPIOCOM4_VNN_REQ_STS", BIT(20), 1},
{"GPIOCOM3_VNN_REQ_STS", BIT(21), 1},
{"GPIOCOM1_VNN_REQ_STS", BIT(23), 1},
{"GPIOCOM0_VNN_REQ_STS", BIT(24), 1},
{"DISP_SHIM_VNN_REQ_STS", BIT(26), 1},
{}
};
static const struct pmc_bit_map ptl_pcdp_vnn_req_status_3_map[] = {
{"DTS0_VNN_REQ_STS", BIT(7), 0},
{"GPIOCOM5_VNN_REQ_STS", BIT(11), 1},
{}
};
static const struct pmc_bit_map ptl_pcdp_vnn_misc_status_map[] = {
{"CPU_C10_REQ_STS", BIT(0), 0},
{"TS_OFF_REQ_STS", BIT(1), 0},
{"PNDE_MET_REQ_STS", BIT(2), 1},
{"PG5_PMA0_REQ_STS", BIT(3), 0},
{"FW_THROTTLE_ALLOWED_REQ_STS", BIT(4), 0},
{"VNN_SOC_REQ_STS", BIT(6), 1},
{"ISH_VNNAON_REQ_STS", BIT(7), 0},
{"D2D_NOC_CFI_QACTIVE_REQ_STS", BIT(8), 1},
{"D2D_NOC_GPSB_QACTIVE_REQ_STS", BIT(9), 1},
{"D2D_IPU_QACTIVE_REQ_STS", BIT(10), 1},
{"PLT_GREATER_REQ_STS", BIT(11), 1},
{"ALL_SBR_IDLE_REQ_STS", BIT(12), 0},
{"PMC_IDLE_FB_OCP_REQ_STS", BIT(13), 0},
{"PM_SYNC_STATES_REQ_STS", BIT(14), 0},
{"EA_REQ_STS", BIT(15), 0},
{"MPHY_CORE_OFF_REQ_STS", BIT(16), 0},
{"BRK_EV_EN_REQ_STS", BIT(17), 0},
{"AUTO_DEMO_EN_REQ_STS", BIT(18), 0},
{"ITSS_CLK_SRC_REQ_STS", BIT(19), 1},
{"ARC_IDLE_REQ_STS", BIT(21), 0},
{"PG5_PMA1_REQ_STS", BIT(22), 0},
{"FIA_DEEP_PM_REQ_STS", BIT(23), 0},
{"XDCI_ATTACHED_REQ_STS", BIT(24), 1},
{"ARC_INTERRUPT_WAKE_REQ_STS", BIT(25), 0},
{"D2D_DISP_DDI_QACTIVE_REQ_STS", BIT(26), 1},
{"PRE_WAKE0_REQ_STS", BIT(27), 1},
{"PRE_WAKE1_REQ_STS", BIT(28), 1},
{"PRE_WAKE2_REQ_STS", BIT(29), 1},
{"D2D_DISP_EDP_QACTIVE_REQ_STS", BIT(31), 1},
{}
};
static const struct pmc_bit_map ptl_pcdp_signal_status_map[] = {
{"LSX_Wake0_STS", BIT(0), 0},
{"LSX_Wake1_STS", BIT(1), 0},
{"LSX_Wake2_STS", BIT(2), 0},
{"LSX_Wake3_STS", BIT(3), 0},
{"LSX_Wake4_STS", BIT(4), 0},
{"LSX_Wake5_STS", BIT(5), 0},
{"LSX_Wake6_STS", BIT(6), 0},
{"LSX_Wake7_STS", BIT(7), 0},
{"LPSS_Wake0_STS", BIT(8), 1},
{"LPSS_Wake1_STS", BIT(9), 1},
{"Int_Timer_SS_Wake0_STS", BIT(10), 1},
{"Int_Timer_SS_Wake1_STS", BIT(11), 1},
{"Int_Timer_SS_Wake2_STS", BIT(12), 1},
{"Int_Timer_SS_Wake3_STS", BIT(13), 1},
{"Int_Timer_SS_Wake4_STS", BIT(14), 1},
{"Int_Timer_SS_Wake5_STS", BIT(15), 1},
{}
};
static const struct pmc_bit_map ptl_pcdp_rsc_status_map[] = {
{"Memory", 0, 1},
{"PSF0", 0, 1},
{"PSF4", 0, 1},
{"PSF5", 0, 1},
{"PSF6", 0, 1},
{"PSF8", 0, 1},
{"SAF_CFI_LINK", 0, 1},
{"SB", 0, 1},
{}
};
static const struct pmc_bit_map *ptl_pcdp_lpm_maps[] = {
ptl_pcdp_clocksource_status_map,
ptl_pcdp_power_gating_status_0_map,
ptl_pcdp_power_gating_status_1_map,
ptl_pcdp_power_gating_status_2_map,
ptl_pcdp_d3_status_0_map,
ptl_pcdp_d3_status_1_map,
ptl_pcdp_d3_status_2_map,
ptl_pcdp_d3_status_3_map,
ptl_pcdp_vnn_req_status_0_map,
ptl_pcdp_vnn_req_status_1_map,
ptl_pcdp_vnn_req_status_2_map,
ptl_pcdp_vnn_req_status_3_map,
ptl_pcdp_vnn_misc_status_map,
ptl_pcdp_signal_status_map,
NULL
};
static const struct pmc_bit_map *ptl_pcdp_blk_maps[] = {
ptl_pcdp_power_gating_status_0_map,
ptl_pcdp_power_gating_status_1_map,
ptl_pcdp_power_gating_status_2_map,
ptl_pcdp_rsc_status_map,
ptl_pcdp_vnn_req_status_0_map,
ptl_pcdp_vnn_req_status_1_map,
ptl_pcdp_vnn_req_status_2_map,
ptl_pcdp_vnn_req_status_3_map,
ptl_pcdp_d3_status_0_map,
ptl_pcdp_d3_status_1_map,
ptl_pcdp_d3_status_2_map,
ptl_pcdp_d3_status_3_map,
ptl_pcdp_clocksource_status_map,
ptl_pcdp_vnn_misc_status_map,
ptl_pcdp_signal_status_map,
NULL
};
static const struct pmc_reg_map ptl_pcdp_reg_map = {
.pfear_sts = ext_ptl_pcdp_pfear_map,
.slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
.slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP,
.ltr_show_sts = ptl_pcdp_ltr_show_map,
.msr_sts = msr_map,
.ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
.regmap_length = PTL_PCD_PMC_MMIO_REG_LEN,
.ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
.ppfear_buckets = LNL_PPFEAR_NUM_ENTRIES,
.pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
.lpm_num_maps = PTL_LPM_NUM_MAPS,
.ltr_ignore_max = LNL_NUM_IP_IGN_ALLOWED,
.lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2,
.etr3_offset = ETR3_OFFSET,
.lpm_sts_latch_en_offset = MTL_LPM_STATUS_LATCH_EN_OFFSET,
.lpm_priority_offset = MTL_LPM_PRI_OFFSET,
.lpm_en_offset = MTL_LPM_EN_OFFSET,
.lpm_residency_offset = MTL_LPM_RESIDENCY_OFFSET,
.lpm_sts = ptl_pcdp_lpm_maps,
.lpm_status_offset = MTL_LPM_STATUS_OFFSET,
.lpm_live_status_offset = MTL_LPM_LIVE_STATUS_OFFSET,
.s0ix_blocker_maps = ptl_pcdp_blk_maps,
.s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET,
};
#define PTL_NPU_PCI_DEV 0xb03e
#define PTL_IPU_PCI_DEV 0xb05d
/*
* Set power state of select devices that do not have drivers to D3
* so that they do not block Package C entry.
*/
static void ptl_d3_fixup(void)
{
pmc_core_set_device_d3(PTL_IPU_PCI_DEV);
pmc_core_set_device_d3(PTL_NPU_PCI_DEV);
}
static int ptl_resume(struct pmc_dev *pmcdev)
{
ptl_d3_fixup();
return cnl_resume(pmcdev);
}
static int ptl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
{
ptl_d3_fixup();
return generic_core_init(pmcdev, pmc_dev_info);
}
struct pmc_dev_info ptl_pmc_dev = {
.map = &ptl_pcdp_reg_map,
.suspend = cnl_suspend,
.resume = ptl_resume,
.init = ptl_core_init,
};

View File

@ -8,9 +8,11 @@
*
*/
#include <linux/pci.h>
#include "core.h"
const struct pmc_bit_map spt_pll_map[] = {
static const struct pmc_bit_map spt_pll_map[] = {
{"MIPI PLL", SPT_PMC_BIT_MPHY_CMN_LANE0},
{"GEN2 USB2PCIE2 PLL", SPT_PMC_BIT_MPHY_CMN_LANE1},
{"DMIPCIE3 PLL", SPT_PMC_BIT_MPHY_CMN_LANE2},
@ -18,7 +20,7 @@ const struct pmc_bit_map spt_pll_map[] = {
{}
};
const struct pmc_bit_map spt_mphy_map[] = {
static const struct pmc_bit_map spt_mphy_map[] = {
{"MPHY CORE LANE 0", SPT_PMC_BIT_MPHY_LANE0},
{"MPHY CORE LANE 1", SPT_PMC_BIT_MPHY_LANE1},
{"MPHY CORE LANE 2", SPT_PMC_BIT_MPHY_LANE2},
@ -38,7 +40,7 @@ const struct pmc_bit_map spt_mphy_map[] = {
{}
};
const struct pmc_bit_map spt_pfear_map[] = {
static const struct pmc_bit_map spt_pfear_map[] = {
{"PMC", SPT_PMC_BIT_PMC},
{"OPI-DMI", SPT_PMC_BIT_OPI},
{"SPI / eSPI", SPT_PMC_BIT_SPI},
@ -82,7 +84,7 @@ const struct pmc_bit_map spt_pfear_map[] = {
{}
};
const struct pmc_bit_map *ext_spt_pfear_map[] = {
static const struct pmc_bit_map *ext_spt_pfear_map[] = {
/*
* Check intel_pmc_core_ids[] users of spt_reg_map for
* a list of core SoCs using this.
@ -91,7 +93,7 @@ const struct pmc_bit_map *ext_spt_pfear_map[] = {
NULL
};
const struct pmc_bit_map spt_ltr_show_map[] = {
static const struct pmc_bit_map spt_ltr_show_map[] = {
{"SOUTHPORT_A", SPT_PMC_LTR_SPA},
{"SOUTHPORT_B", SPT_PMC_LTR_SPB},
{"SATA", SPT_PMC_LTR_SATA},
@ -116,7 +118,7 @@ const struct pmc_bit_map spt_ltr_show_map[] = {
{}
};
const struct pmc_reg_map spt_reg_map = {
static const struct pmc_reg_map spt_reg_map = {
.pfear_sts = ext_spt_pfear_map,
.mphy_sts = spt_mphy_map,
.pll_sts = spt_pll_map,
@ -134,18 +136,25 @@ const struct pmc_reg_map spt_reg_map = {
.pm_vric1_offset = SPT_PMC_VRIC1_OFFSET,
};
int spt_core_init(struct pmc_dev *pmcdev)
static const struct pci_device_id spt_pmc_pci_id[] = {
{ PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID) },
{ }
};
static int spt_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
{
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
int ret;
/*
* Coffee Lake has CPU ID of Kaby Lake and Cannon Lake PCH. So here
* Sunrisepoint PCH regmap can't be used. Use Cannon Lake PCH regmap
* in this case.
*/
if (!pci_dev_present(spt_pmc_pci_id))
return generic_core_init(pmcdev, &cnp_pmc_dev);
pmc->map = &spt_reg_map;
ret = get_primary_reg_base(pmc);
if (ret)
return ret;
pmc_core_get_low_power_modes(pmcdev);
return ret;
return generic_core_init(pmcdev, pmc_dev_info);
}
struct pmc_dev_info spt_pmc_dev = {
.map = &spt_reg_map,
.init = spt_core_init,
};

View File

@ -18,7 +18,7 @@ enum pch_type {
PCH_LP
};
const struct pmc_bit_map tgl_pfear_map[] = {
static const struct pmc_bit_map tgl_pfear_map[] = {
{"PSF9", BIT(0)},
{"RES_66", BIT(1)},
{"RES_67", BIT(2)},
@ -29,7 +29,7 @@ const struct pmc_bit_map tgl_pfear_map[] = {
{}
};
const struct pmc_bit_map *ext_tgl_pfear_map[] = {
static const struct pmc_bit_map *ext_tgl_pfear_map[] = {
/*
* Check intel_pmc_core_ids[] users of tgl_reg_map for
* a list of core SoCs using this.
@ -39,7 +39,7 @@ const struct pmc_bit_map *ext_tgl_pfear_map[] = {
NULL
};
const struct pmc_bit_map tgl_clocksource_status_map[] = {
static const struct pmc_bit_map tgl_clocksource_status_map[] = {
{"USB2PLL_OFF_STS", BIT(18)},
{"PCIe/USB3.1_Gen2PLL_OFF_STS", BIT(19)},
{"PCIe_Gen3PLL_OFF_STS", BIT(20)},
@ -55,7 +55,7 @@ const struct pmc_bit_map tgl_clocksource_status_map[] = {
{}
};
const struct pmc_bit_map tgl_power_gating_status_map[] = {
static const struct pmc_bit_map tgl_power_gating_status_map[] = {
{"CSME_PG_STS", BIT(0)},
{"SATA_PG_STS", BIT(1)},
{"xHCI_PG_STS", BIT(2)},
@ -83,7 +83,7 @@ const struct pmc_bit_map tgl_power_gating_status_map[] = {
{}
};
const struct pmc_bit_map tgl_d3_status_map[] = {
static const struct pmc_bit_map tgl_d3_status_map[] = {
{"ADSP_D3_STS", BIT(0)},
{"SATA_D3_STS", BIT(1)},
{"xHCI0_D3_STS", BIT(2)},
@ -98,7 +98,7 @@ const struct pmc_bit_map tgl_d3_status_map[] = {
{}
};
const struct pmc_bit_map tgl_vnn_req_status_map[] = {
static const struct pmc_bit_map tgl_vnn_req_status_map[] = {
{"GPIO_COM0_VNN_REQ_STS", BIT(1)},
{"GPIO_COM1_VNN_REQ_STS", BIT(2)},
{"GPIO_COM2_VNN_REQ_STS", BIT(3)},
@ -123,7 +123,7 @@ const struct pmc_bit_map tgl_vnn_req_status_map[] = {
{}
};
const struct pmc_bit_map tgl_vnn_misc_status_map[] = {
static const struct pmc_bit_map tgl_vnn_misc_status_map[] = {
{"CPU_C10_REQ_STS_0", BIT(0)},
{"PCIe_LPM_En_REQ_STS_3", BIT(3)},
{"ITH_REQ_STS_5", BIT(5)},
@ -175,7 +175,7 @@ const struct pmc_bit_map tgl_signal_status_map[] = {
{}
};
const struct pmc_bit_map *tgl_lpm_maps[] = {
static const struct pmc_bit_map *tgl_lpm_maps[] = {
tgl_clocksource_status_map,
tgl_power_gating_status_map,
tgl_d3_status_map,
@ -185,7 +185,7 @@ const struct pmc_bit_map *tgl_lpm_maps[] = {
NULL
};
const struct pmc_reg_map tgl_reg_map = {
static const struct pmc_reg_map tgl_reg_map = {
.pfear_sts = ext_tgl_pfear_map,
.slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
.slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP,
@ -210,7 +210,7 @@ const struct pmc_reg_map tgl_reg_map = {
.etr3_offset = ETR3_OFFSET,
};
const struct pmc_reg_map tgl_h_reg_map = {
static const struct pmc_reg_map tgl_h_reg_map = {
.pfear_sts = ext_tgl_pfear_map,
.slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
.slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP,
@ -285,35 +285,28 @@ void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev)
ACPI_FREE(out_obj);
}
int tgl_l_core_init(struct pmc_dev *pmcdev)
static int tgl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
{
return tgl_core_generic_init(pmcdev, PCH_LP);
}
int tgl_core_init(struct pmc_dev *pmcdev)
{
return tgl_core_generic_init(pmcdev, PCH_H);
}
int tgl_core_generic_init(struct pmc_dev *pmcdev, int pch_tp)
{
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
int ret;
if (pch_tp == PCH_H)
pmc->map = &tgl_h_reg_map;
else
pmc->map = &tgl_reg_map;
pmcdev->suspend = cnl_suspend;
pmcdev->resume = cnl_resume;
ret = get_primary_reg_base(pmc);
ret = generic_core_init(pmcdev, pmc_dev_info);
if (ret)
return ret;
pmc_core_get_low_power_modes(pmcdev);
pmc_core_get_tgl_lpm_reqs(pmcdev->pdev);
return 0;
}
struct pmc_dev_info tgl_l_pmc_dev = {
.map = &tgl_reg_map,
.suspend = cnl_suspend,
.resume = cnl_resume,
.init = tgl_core_init,
};
struct pmc_dev_info tgl_pmc_dev = {
.map = &tgl_h_reg_map,
.suspend = cnl_suspend,
.resume = cnl_resume,
.init = tgl_core_init,
};

View File

@ -0,0 +1,212 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Lenovo Super Hotkey Utility WMI extras driver for Ideapad laptop
*
* Copyright (C) 2025 Lenovo
*/
#include <linux/cleanup.h>
#include <linux/dev_printk.h>
#include <linux/device.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/wmi.h>
/* Lenovo Super Hotkey WMI GUIDs */
#define LUD_WMI_METHOD_GUID "CE6C0974-0407-4F50-88BA-4FC3B6559AD8"
/* Lenovo Utility Data WMI method_id */
#define WMI_LUD_GET_SUPPORT 1
#define WMI_LUD_SET_FEATURE 2
#define WMI_LUD_GET_MICMUTE_LED_VER 20
#define WMI_LUD_GET_AUDIOMUTE_LED_VER 26
#define WMI_LUD_SUPPORT_MICMUTE_LED_VER 25
#define WMI_LUD_SUPPORT_AUDIOMUTE_LED_VER 27
/* Input parameters to mute/unmute audio LED and Mic LED */
struct wmi_led_args {
u8 id;
u8 subid;
u16 value;
};
/* Values of input parameters to SetFeature of audio LED and Mic LED */
enum hotkey_set_feature {
MIC_MUTE_LED_ON = 1,
MIC_MUTE_LED_OFF = 2,
AUDIO_MUTE_LED_ON = 4,
AUDIO_MUTE_LED_OFF = 5,
};
#define LSH_ACPI_LED_MAX 2
struct lenovo_super_hotkey_wmi_private {
struct led_classdev cdev[LSH_ACPI_LED_MAX];
struct wmi_device *led_wdev;
};
enum mute_led_type {
MIC_MUTE,
AUDIO_MUTE,
};
static int lsh_wmi_mute_led_set(enum mute_led_type led_type, struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct lenovo_super_hotkey_wmi_private *wpriv = container_of(led_cdev,
struct lenovo_super_hotkey_wmi_private, cdev[led_type]);
struct wmi_led_args led_arg = {0, 0, 0};
struct acpi_buffer input;
acpi_status status;
switch (led_type) {
case MIC_MUTE:
led_arg.id = brightness == LED_ON ? MIC_MUTE_LED_ON : MIC_MUTE_LED_OFF;
break;
case AUDIO_MUTE:
led_arg.id = brightness == LED_ON ? AUDIO_MUTE_LED_ON : AUDIO_MUTE_LED_OFF;
break;
default:
return -EINVAL;
}
input.length = sizeof(led_arg);
input.pointer = &led_arg;
status = wmidev_evaluate_method(wpriv->led_wdev, 0, WMI_LUD_SET_FEATURE, &input, NULL);
if (ACPI_FAILURE(status))
return -EIO;
return 0;
}
static int lsh_wmi_audiomute_led_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
return lsh_wmi_mute_led_set(AUDIO_MUTE, led_cdev, brightness);
}
static int lsh_wmi_micmute_led_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
return lsh_wmi_mute_led_set(MIC_MUTE, led_cdev, brightness);
}
static int lenovo_super_hotkey_wmi_led_init(enum mute_led_type led_type, struct device *dev)
{
struct lenovo_super_hotkey_wmi_private *wpriv = dev_get_drvdata(dev);
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_buffer input;
int led_version, err = 0;
unsigned int wmiarg;
acpi_status status;
switch (led_type) {
case MIC_MUTE:
wmiarg = WMI_LUD_GET_MICMUTE_LED_VER;
break;
case AUDIO_MUTE:
wmiarg = WMI_LUD_GET_AUDIOMUTE_LED_VER;
break;
default:
return -EINVAL;
}
input.length = sizeof(wmiarg);
input.pointer = &wmiarg;
status = wmidev_evaluate_method(wpriv->led_wdev, 0, WMI_LUD_GET_SUPPORT, &input, &output);
if (ACPI_FAILURE(status))
return -EIO;
union acpi_object *obj __free(kfree) = output.pointer;
if (obj && obj->type == ACPI_TYPE_INTEGER)
led_version = obj->integer.value;
else
return -EIO;
wpriv->cdev[led_type].max_brightness = LED_ON;
wpriv->cdev[led_type].flags = LED_CORE_SUSPENDRESUME;
switch (led_type) {
case MIC_MUTE:
if (led_version != WMI_LUD_SUPPORT_MICMUTE_LED_VER)
return -EIO;
wpriv->cdev[led_type].name = "platform::micmute";
wpriv->cdev[led_type].brightness_set_blocking = &lsh_wmi_micmute_led_set;
wpriv->cdev[led_type].default_trigger = "audio-micmute";
break;
case AUDIO_MUTE:
if (led_version != WMI_LUD_SUPPORT_AUDIOMUTE_LED_VER)
return -EIO;
wpriv->cdev[led_type].name = "platform::mute";
wpriv->cdev[led_type].brightness_set_blocking = &lsh_wmi_audiomute_led_set;
wpriv->cdev[led_type].default_trigger = "audio-mute";
break;
default:
dev_err(dev, "Unknown LED type %d\n", led_type);
return -EINVAL;
}
err = devm_led_classdev_register(dev, &wpriv->cdev[led_type]);
if (err < 0) {
dev_err(dev, "Could not register mute LED %d : %d\n", led_type, err);
return err;
}
return 0;
}
static int lenovo_super_hotkey_wmi_leds_setup(struct device *dev)
{
int err;
err = lenovo_super_hotkey_wmi_led_init(MIC_MUTE, dev);
if (err)
return err;
err = lenovo_super_hotkey_wmi_led_init(AUDIO_MUTE, dev);
if (err)
return err;
return 0;
}
static int lenovo_super_hotkey_wmi_probe(struct wmi_device *wdev, const void *context)
{
struct lenovo_super_hotkey_wmi_private *wpriv;
wpriv = devm_kzalloc(&wdev->dev, sizeof(*wpriv), GFP_KERNEL);
if (!wpriv)
return -ENOMEM;
dev_set_drvdata(&wdev->dev, wpriv);
wpriv->led_wdev = wdev;
return lenovo_super_hotkey_wmi_leds_setup(&wdev->dev);
}
static const struct wmi_device_id lenovo_super_hotkey_wmi_id_table[] = {
{ LUD_WMI_METHOD_GUID, NULL }, /* Utility data */
{ }
};
MODULE_DEVICE_TABLE(wmi, lenovo_super_hotkey_wmi_id_table);
static struct wmi_driver lenovo_wmi_hotkey_utilities_driver = {
.driver = {
.name = "lenovo_wmi_hotkey_utilities",
.probe_type = PROBE_PREFER_ASYNCHRONOUS
},
.id_table = lenovo_super_hotkey_wmi_id_table,
.probe = lenovo_super_hotkey_wmi_probe,
.no_singleton = true,
};
module_wmi_driver(lenovo_wmi_hotkey_utilities_driver);
MODULE_AUTHOR("Jackie Dong <dongeg1@lenovo.com>");
MODULE_DESCRIPTION("Lenovo Super Hotkey Utility WMI extras driver");
MODULE_LICENSE("GPL");

View File

@ -219,7 +219,7 @@ static int yt2_1380_fc_serdev_probe(struct serdev_device *serdev)
return 0;
}
struct serdev_device_driver yt2_1380_fc_serdev_driver = {
static struct serdev_device_driver yt2_1380_fc_serdev_driver = {
.probe = yt2_1380_fc_serdev_probe,
.driver = {
.name = KBUILD_MODNAME,

File diff suppressed because it is too large Load Diff

View File

@ -262,16 +262,11 @@ static int tlmi_simple_call(const char *guid, const char *arg)
return 0;
}
/* Extract output string from WMI return buffer */
static int tlmi_extract_output_string(const struct acpi_buffer *output,
char **string)
/* Extract output string from WMI return value */
static int tlmi_extract_output_string(union acpi_object *obj, char **string)
{
const union acpi_object *obj;
char *s;
obj = output->pointer;
if (!obj)
return -ENOMEM;
if (obj->type != ACPI_TYPE_STRING || !obj->string.pointer)
return -EIO;
@ -349,20 +344,18 @@ static int tlmi_opcode_setting(char *setting, const char *value)
return ret;
}
static int tlmi_setting(int item, char **value, const char *guid_string)
static int tlmi_setting(struct wmi_device *wdev, int item, char **value)
{
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
acpi_status status;
union acpi_object *obj;
int ret;
status = wmi_query_block(guid_string, item, &output);
if (ACPI_FAILURE(status)) {
kfree(output.pointer);
obj = wmidev_block_query(wdev, item);
if (!obj)
return -EIO;
}
ret = tlmi_extract_output_string(&output, value);
kfree(output.pointer);
ret = tlmi_extract_output_string(obj, value);
kfree(obj);
return ret;
}
@ -370,19 +363,22 @@ static int tlmi_get_bios_selections(const char *item, char **value)
{
const struct acpi_buffer input = { strlen(item), (char *)item };
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
acpi_status status;
int ret;
status = wmi_evaluate_method(LENOVO_GET_BIOS_SELECTIONS_GUID,
0, 0, &input, &output);
if (ACPI_FAILURE(status)) {
kfree(output.pointer);
if (ACPI_FAILURE(status))
return -EIO;
}
ret = tlmi_extract_output_string(&output, value);
kfree(output.pointer);
obj = output.pointer;
if (!obj)
return -ENODATA;
ret = tlmi_extract_output_string(obj, value);
kfree(obj);
return ret;
}
@ -993,7 +989,7 @@ static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *a
char *item, *value;
int ret;
ret = tlmi_setting(setting->index, &item, LENOVO_BIOS_SETTING_GUID);
ret = tlmi_setting(setting->wdev, setting->index, &item);
if (ret)
return ret;
@ -1586,7 +1582,7 @@ static struct tlmi_pwd_setting *tlmi_create_auth(const char *pwd_type,
return new_pwd;
}
static int tlmi_analyze(void)
static int tlmi_analyze(struct wmi_device *wdev)
{
int i, ret;
@ -1623,7 +1619,7 @@ static int tlmi_analyze(void)
char *item = NULL;
tlmi_priv.setting[i] = NULL;
ret = tlmi_setting(i, &item, LENOVO_BIOS_SETTING_GUID);
ret = tlmi_setting(wdev, i, &item);
if (ret)
break;
if (!item)
@ -1646,6 +1642,7 @@ static int tlmi_analyze(void)
kfree(item);
goto fail_clear_attr;
}
setting->wdev = wdev;
setting->index = i;
strscpy(setting->display_name, item);
/* If BIOS selections supported, load those */
@ -1664,7 +1661,7 @@ static int tlmi_analyze(void)
*/
char *optitem, *optstart, *optend;
if (!tlmi_setting(setting->index, &optitem, LENOVO_BIOS_SETTING_GUID)) {
if (!tlmi_setting(setting->wdev, setting->index, &optitem)) {
optstart = strstr(optitem, "[Optional:");
if (optstart) {
optstart += strlen("[Optional:");
@ -1789,7 +1786,7 @@ static int tlmi_probe(struct wmi_device *wdev, const void *context)
{
int ret;
ret = tlmi_analyze();
ret = tlmi_analyze(wdev);
if (ret)
return ret;

View File

@ -4,6 +4,7 @@
#define _THINK_LMI_H_
#include <linux/types.h>
#include <linux/wmi.h>
#define TLMI_SETTINGS_COUNT 256
#define TLMI_SETTINGS_MAXLEN 512
@ -87,6 +88,7 @@ struct tlmi_pwd_setting {
/* Attribute setting details */
struct tlmi_attr_setting {
struct kobject kobj;
struct wmi_device *wdev;
int index;
char display_name[TLMI_SETTINGS_MAXLEN];
char *possible_values;

View File

@ -39,7 +39,6 @@
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/fb.h>
#include <linux/freezer.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
@ -368,9 +367,6 @@ static struct {
u32 beep_needs_two_args:1;
u32 mixer_no_level_control:1;
u32 battery_force_primary:1;
u32 input_device_registered:1;
u32 platform_drv_registered:1;
u32 sensors_pdrv_registered:1;
u32 hotkey_poll_active:1;
u32 has_adaptive_kbd:1;
u32 kbd_lang:1;
@ -8513,7 +8509,7 @@ static void fan_watchdog_reset(void)
if (fan_watchdog_maxinterval > 0 &&
tpacpi_lifecycle != TPACPI_LIFE_EXITING)
mod_delayed_work(tpacpi_wq, &fan_watchdog_task,
msecs_to_jiffies(fan_watchdog_maxinterval * 1000));
secs_to_jiffies(fan_watchdog_maxinterval));
else
cancel_delayed_work(&fan_watchdog_task);
}
@ -11817,36 +11813,18 @@ MODULE_PARM_DESC(profile_force, "Force profile mode. -1=off, 1=MMC, 2=PSC");
static void thinkpad_acpi_module_exit(void)
{
struct ibm_struct *ibm, *itmp;
tpacpi_lifecycle = TPACPI_LIFE_EXITING;
if (tpacpi_hwmon)
hwmon_device_unregister(tpacpi_hwmon);
if (tp_features.sensors_pdrv_registered)
if (tpacpi_sensors_pdev) {
platform_driver_unregister(&tpacpi_hwmon_pdriver);
if (tp_features.platform_drv_registered)
platform_driver_unregister(&tpacpi_pdriver);
list_for_each_entry_safe_reverse(ibm, itmp,
&tpacpi_all_drivers,
all_drivers) {
ibm_exit(ibm);
}
dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
if (tpacpi_inputdev) {
if (tp_features.input_device_registered)
input_unregister_device(tpacpi_inputdev);
else
input_free_device(tpacpi_inputdev);
}
if (tpacpi_sensors_pdev)
platform_device_unregister(tpacpi_sensors_pdev);
if (tpacpi_pdev)
}
if (tpacpi_pdev) {
platform_driver_unregister(&tpacpi_pdriver);
platform_device_unregister(tpacpi_pdev);
}
if (proc_dir)
remove_proc_entry(TPACPI_PROC_DIR, acpi_root_dir);
if (tpacpi_wq)
@ -11858,11 +11836,76 @@ static void thinkpad_acpi_module_exit(void)
kfree(thinkpad_id.nummodel_str);
}
static void tpacpi_subdrivers_release(void *data)
{
struct ibm_struct *ibm, *itmp;
list_for_each_entry_safe_reverse(ibm, itmp, &tpacpi_all_drivers, all_drivers)
ibm_exit(ibm);
dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
}
static int __init tpacpi_pdriver_probe(struct platform_device *pdev)
{
int ret;
ret = devm_mutex_init(&pdev->dev, &tpacpi_inputdev_send_mutex);
if (ret)
return ret;
tpacpi_inputdev = devm_input_allocate_device(&pdev->dev);
if (!tpacpi_inputdev)
return -ENOMEM;
tpacpi_inputdev->name = "ThinkPad Extra Buttons";
tpacpi_inputdev->phys = TPACPI_DRVR_NAME "/input0";
tpacpi_inputdev->id.bustype = BUS_HOST;
tpacpi_inputdev->id.vendor = thinkpad_id.vendor;
tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT;
tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION;
tpacpi_inputdev->dev.parent = &tpacpi_pdev->dev;
/* Init subdriver dependencies */
tpacpi_detect_brightness_capabilities();
/* Init subdrivers */
for (unsigned int i = 0; i < ARRAY_SIZE(ibms_init); i++) {
ret = ibm_init(&ibms_init[i]);
if (ret >= 0 && *ibms_init[i].param)
ret = ibms_init[i].data->write(ibms_init[i].param);
if (ret < 0) {
tpacpi_subdrivers_release(NULL);
return ret;
}
}
ret = devm_add_action_or_reset(&pdev->dev, tpacpi_subdrivers_release, NULL);
if (ret)
return ret;
ret = input_register_device(tpacpi_inputdev);
if (ret < 0)
pr_err("unable to register input device\n");
return ret;
}
static int __init tpacpi_hwmon_pdriver_probe(struct platform_device *pdev)
{
tpacpi_hwmon = devm_hwmon_device_register_with_groups(
&tpacpi_sensors_pdev->dev, TPACPI_NAME, NULL, tpacpi_hwmon_groups);
if (IS_ERR(tpacpi_hwmon))
pr_err("unable to register hwmon device\n");
return PTR_ERR_OR_ZERO(tpacpi_hwmon);
}
static int __init thinkpad_acpi_module_init(void)
{
const struct dmi_system_id *dmi_id;
int ret, i;
int ret;
acpi_object_type obj_type;
tpacpi_lifecycle = TPACPI_LIFE_INIT;
@ -11922,93 +11965,29 @@ static int __init thinkpad_acpi_module_init(void)
tp_features.quirks = dmi_id->driver_data;
/* Device initialization */
tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, PLATFORM_DEVID_NONE,
NULL, 0);
tpacpi_pdev = platform_create_bundle(&tpacpi_pdriver, tpacpi_pdriver_probe,
NULL, 0, NULL, 0);
if (IS_ERR(tpacpi_pdev)) {
ret = PTR_ERR(tpacpi_pdev);
tpacpi_pdev = NULL;
pr_err("unable to register platform device\n");
pr_err("unable to register platform device/driver bundle\n");
thinkpad_acpi_module_exit();
return ret;
}
tpacpi_sensors_pdev = platform_device_register_simple(
TPACPI_HWMON_DRVR_NAME,
PLATFORM_DEVID_NONE, NULL, 0);
tpacpi_sensors_pdev = platform_create_bundle(&tpacpi_hwmon_pdriver,
tpacpi_hwmon_pdriver_probe,
NULL, 0, NULL, 0);
if (IS_ERR(tpacpi_sensors_pdev)) {
ret = PTR_ERR(tpacpi_sensors_pdev);
tpacpi_sensors_pdev = NULL;
pr_err("unable to register hwmon platform device\n");
pr_err("unable to register hwmon platform device/driver bundle\n");
thinkpad_acpi_module_exit();
return ret;
}
mutex_init(&tpacpi_inputdev_send_mutex);
tpacpi_inputdev = input_allocate_device();
if (!tpacpi_inputdev) {
thinkpad_acpi_module_exit();
return -ENOMEM;
} else {
/* Prepare input device, but don't register */
tpacpi_inputdev->name = "ThinkPad Extra Buttons";
tpacpi_inputdev->phys = TPACPI_DRVR_NAME "/input0";
tpacpi_inputdev->id.bustype = BUS_HOST;
tpacpi_inputdev->id.vendor = thinkpad_id.vendor;
tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT;
tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION;
tpacpi_inputdev->dev.parent = &tpacpi_pdev->dev;
}
/* Init subdriver dependencies */
tpacpi_detect_brightness_capabilities();
/* Init subdrivers */
for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
ret = ibm_init(&ibms_init[i]);
if (ret >= 0 && *ibms_init[i].param)
ret = ibms_init[i].data->write(ibms_init[i].param);
if (ret < 0) {
thinkpad_acpi_module_exit();
return ret;
}
}
tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
ret = platform_driver_register(&tpacpi_pdriver);
if (ret) {
pr_err("unable to register main platform driver\n");
thinkpad_acpi_module_exit();
return ret;
}
tp_features.platform_drv_registered = 1;
ret = platform_driver_register(&tpacpi_hwmon_pdriver);
if (ret) {
pr_err("unable to register hwmon platform driver\n");
thinkpad_acpi_module_exit();
return ret;
}
tp_features.sensors_pdrv_registered = 1;
tpacpi_hwmon = hwmon_device_register_with_groups(
&tpacpi_sensors_pdev->dev, TPACPI_NAME, NULL, tpacpi_hwmon_groups);
if (IS_ERR(tpacpi_hwmon)) {
ret = PTR_ERR(tpacpi_hwmon);
tpacpi_hwmon = NULL;
pr_err("unable to register hwmon device\n");
thinkpad_acpi_module_exit();
return ret;
}
ret = input_register_device(tpacpi_inputdev);
if (ret < 0) {
pr_err("unable to register input device\n");
thinkpad_acpi_module_exit();
return ret;
} else {
tp_features.input_device_registered = 1;
}
return 0;
}

View File

@ -123,24 +123,6 @@ static const void *find_guid_context(struct wmi_block *wblock,
return NULL;
}
static acpi_status wmi_method_enable(struct wmi_block *wblock, bool enable)
{
struct guid_block *block;
char method[5];
acpi_status status;
acpi_handle handle;
block = &wblock->gblock;
handle = wblock->acpi_device->handle;
snprintf(method, 5, "WE%02X", block->notify_id);
status = acpi_execute_simple_method(handle, method, enable);
if (status == AE_NOT_FOUND)
return AE_OK;
return status;
}
#define WMI_ACPI_METHOD_NAME_SIZE 5
static inline void get_acpi_method_name(const struct wmi_block *wblock,
@ -184,6 +166,44 @@ static int wmidev_match_guid(struct device *dev, const void *data)
static const struct bus_type wmi_bus_type;
static const struct device_type wmi_type_event;
static const struct device_type wmi_type_method;
static int wmi_device_enable(struct wmi_device *wdev, bool enable)
{
struct wmi_block *wblock = container_of(wdev, struct wmi_block, dev);
char method[WMI_ACPI_METHOD_NAME_SIZE];
acpi_handle handle;
acpi_status status;
if (!(wblock->gblock.flags & ACPI_WMI_EXPENSIVE))
return 0;
if (wblock->dev.dev.type == &wmi_type_method)
return 0;
if (wblock->dev.dev.type == &wmi_type_event)
snprintf(method, sizeof(method), "WE%02X", wblock->gblock.notify_id);
else
get_acpi_method_name(wblock, 'C', method);
/*
* Not all WMI devices marked as expensive actually implement the
* necessary ACPI method. Ignore this missing ACPI method to match
* the behaviour of the Windows driver.
*/
status = acpi_get_handle(wblock->acpi_device->handle, method, &handle);
if (ACPI_FAILURE(status))
return 0;
status = acpi_execute_simple_method(handle, NULL, enable);
if (ACPI_FAILURE(status))
return -EIO;
return 0;
}
static struct wmi_device *wmi_find_device_by_guid(const char *guid_string)
{
struct device *dev;
@ -337,10 +357,8 @@ static acpi_status __query_block(struct wmi_block *wblock, u8 instance,
{
struct guid_block *block;
acpi_handle handle;
acpi_status status, wc_status = AE_ERROR;
struct acpi_object_list input;
union acpi_object wq_params[1];
char wc_method[WMI_ACPI_METHOD_NAME_SIZE];
char method[WMI_ACPI_METHOD_NAME_SIZE];
if (!out)
@ -364,40 +382,9 @@ static acpi_status __query_block(struct wmi_block *wblock, u8 instance,
if (instance == 0 && test_bit(WMI_READ_TAKES_NO_ARGS, &wblock->flags))
input.count = 0;
/*
* If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
* enable collection.
*/
if (block->flags & ACPI_WMI_EXPENSIVE) {
get_acpi_method_name(wblock, 'C', wc_method);
/*
* Some GUIDs break the specification by declaring themselves
* expensive, but have no corresponding WCxx method. So we
* should not fail if this happens.
*/
wc_status = acpi_execute_simple_method(handle, wc_method, 1);
}
get_acpi_method_name(wblock, 'Q', method);
status = acpi_evaluate_object(handle, method, &input, out);
/*
* If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
* the WQxx method failed - we should disable collection anyway.
*/
if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) {
/*
* Ignore whether this WCxx call succeeds or not since
* the previously executed WQxx method call might have
* succeeded, and returning the failing status code
* of this call would throw away the result of the WQxx
* call, potentially leaking memory.
*/
acpi_execute_simple_method(handle, wc_method, 0);
}
return status;
return acpi_evaluate_object(handle, method, &input, out);
}
/**
@ -421,9 +408,15 @@ acpi_status wmi_query_block(const char *guid_string, u8 instance,
if (IS_ERR(wdev))
return AE_ERROR;
if (wmi_device_enable(wdev, true) < 0)
dev_warn(&wdev->dev, "Failed to enable device\n");
wblock = container_of(wdev, struct wmi_block, dev);
status = __query_block(wblock, instance, out);
if (wmi_device_enable(wdev, false) < 0)
dev_warn(&wdev->dev, "Failed to disable device\n");
wmi_device_put(wdev);
return status;
@ -470,7 +463,14 @@ acpi_status wmi_set_block(const char *guid_string, u8 instance, const struct acp
if (IS_ERR(wdev))
return AE_ERROR;
if (wmi_device_enable(wdev, true) < 0)
dev_warn(&wdev->dev, "Failed to enable device\n");
status = wmidev_block_set(wdev, instance, in);
if (wmi_device_enable(wdev, false) < 0)
dev_warn(&wdev->dev, "Failed to disable device\n");
wmi_device_put(wdev);
return status;
@ -551,7 +551,7 @@ acpi_status wmi_install_notify_handler(const char *guid,
wblock->handler = handler;
wblock->handler_data = data;
if (ACPI_FAILURE(wmi_method_enable(wblock, true)))
if (wmi_device_enable(wdev, true) < 0)
dev_warn(&wblock->dev.dev, "Failed to enable device\n");
status = AE_OK;
@ -588,7 +588,7 @@ acpi_status wmi_remove_notify_handler(const char *guid)
if (!wblock->handler) {
status = AE_NULL_ENTRY;
} else {
if (ACPI_FAILURE(wmi_method_enable(wblock, false)))
if (wmi_device_enable(wdev, false) < 0)
dev_warn(&wblock->dev.dev, "Failed to disable device\n");
wblock->handler = NULL;
@ -821,11 +821,19 @@ static int wmi_dev_match(struct device *dev, const struct device_driver *driver)
return 0;
}
static void wmi_dev_disable(void *data)
{
struct device *dev = data;
if (wmi_device_enable(to_wmi_device(dev), false) < 0)
dev_warn(dev, "Failed to disable device\n");
}
static int wmi_dev_probe(struct device *dev)
{
struct wmi_block *wblock = dev_to_wblock(dev);
struct wmi_driver *wdriver = to_wmi_driver(dev->driver);
int ret = 0;
int ret;
/* Some older WMI drivers will break if instantiated multiple times,
* so they are blocked from probing WMI devices with a duplicated GUID.
@ -844,18 +852,22 @@ static int wmi_dev_probe(struct device *dev)
return -ENODEV;
}
if (ACPI_FAILURE(wmi_method_enable(wblock, true)))
if (wmi_device_enable(to_wmi_device(dev), true) < 0)
dev_warn(dev, "failed to enable device -- probing anyway\n");
/*
* We have to make sure that all devres-managed resources are released first because
* some might still want to access the underlying WMI device.
*/
ret = devm_add_action_or_reset(dev, wmi_dev_disable, dev);
if (ret < 0)
return ret;
if (wdriver->probe) {
ret = wdriver->probe(to_wmi_device(dev),
find_guid_context(wblock, wdriver));
if (ret) {
if (ACPI_FAILURE(wmi_method_enable(wblock, false)))
dev_warn(dev, "Failed to disable device\n");
if (ret)
return ret;
}
}
down_write(&wblock->notify_lock);
@ -876,9 +888,6 @@ static void wmi_dev_remove(struct device *dev)
if (wdriver->remove)
wdriver->remove(to_wmi_device(dev));
if (ACPI_FAILURE(wmi_method_enable(wblock, false)))
dev_warn(dev, "failed to disable device\n");
}
static void wmi_dev_shutdown(struct device *dev)
@ -902,7 +911,11 @@ static void wmi_dev_shutdown(struct device *dev)
if (wdriver->shutdown)
wdriver->shutdown(to_wmi_device(dev));
if (ACPI_FAILURE(wmi_method_enable(wblock, false)))
/*
* We still need to disable the WMI device here since devres-managed resources
* like wmi_dev_disable() will not be release during shutdown.
*/
if (wmi_device_enable(to_wmi_device(dev), false) < 0)
dev_warn(dev, "Failed to disable device\n");
}
}

View File

@ -10,6 +10,7 @@ config X86_ANDROID_TABLETS
depends on ACPI && EFI && PCI
select NEW_LEDS
select LEDS_CLASS
select POWER_SUPPLY
help
X86 tablets which ship with Android as (part of) the factory image
typically have various problems with their DSDTs. The factory kernels

View File

@ -0,0 +1,79 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Huawei Matebook E Go Embedded Controller
*
* Copyright (C) 2024-2025 Pengyu Luo <mitltlatltl@gmail.com>
*/
#ifndef __HUAWEI_GAOKUN_EC_H__
#define __HUAWEI_GAOKUN_EC_H__
#define GAOKUN_UCSI_CCI_SIZE 4
#define GAOKUN_UCSI_MSGI_SIZE 16
#define GAOKUN_UCSI_READ_SIZE (GAOKUN_UCSI_CCI_SIZE + GAOKUN_UCSI_MSGI_SIZE)
#define GAOKUN_UCSI_WRITE_SIZE 24 /* 8B CTRL, 16B MSGO */
#define GAOKUN_UCSI_NO_PORT_UPDATE (-1)
#define GAOKUN_SMART_CHARGE_DATA_SIZE 4 /* mode, delay, start, end */
/* -------------------------------------------------------------------------- */
struct gaokun_ec;
struct gaokun_ucsi_reg;
struct notifier_block;
#define GAOKUN_MOD_NAME "huawei_gaokun_ec"
#define GAOKUN_DEV_PSY "psy"
#define GAOKUN_DEV_UCSI "ucsi"
/* -------------------------------------------------------------------------- */
/* Common API */
int gaokun_ec_register_notify(struct gaokun_ec *ec,
struct notifier_block *nb);
void gaokun_ec_unregister_notify(struct gaokun_ec *ec,
struct notifier_block *nb);
int gaokun_ec_read(struct gaokun_ec *ec, const u8 *req,
size_t resp_len, u8 *resp);
int gaokun_ec_write(struct gaokun_ec *ec, const u8 *req);
int gaokun_ec_read_byte(struct gaokun_ec *ec, const u8 *req, u8 *byte);
/* -------------------------------------------------------------------------- */
/* API for PSY */
int gaokun_ec_psy_multi_read(struct gaokun_ec *ec, u8 reg,
size_t resp_len, u8 *resp);
static inline int gaokun_ec_psy_read_byte(struct gaokun_ec *ec,
u8 reg, u8 *byte)
{
return gaokun_ec_psy_multi_read(ec, reg, sizeof(*byte), byte);
}
static inline int gaokun_ec_psy_read_word(struct gaokun_ec *ec,
u8 reg, u16 *word)
{
return gaokun_ec_psy_multi_read(ec, reg, sizeof(*word), (u8 *)word);
}
int gaokun_ec_psy_get_smart_charge(struct gaokun_ec *ec,
u8 resp[GAOKUN_SMART_CHARGE_DATA_SIZE]);
int gaokun_ec_psy_set_smart_charge(struct gaokun_ec *ec,
const u8 req[GAOKUN_SMART_CHARGE_DATA_SIZE]);
int gaokun_ec_psy_get_smart_charge_enable(struct gaokun_ec *ec, bool *on);
int gaokun_ec_psy_set_smart_charge_enable(struct gaokun_ec *ec, bool on);
/* -------------------------------------------------------------------------- */
/* API for UCSI */
int gaokun_ec_ucsi_read(struct gaokun_ec *ec, u8 resp[GAOKUN_UCSI_READ_SIZE]);
int gaokun_ec_ucsi_write(struct gaokun_ec *ec,
const u8 req[GAOKUN_UCSI_WRITE_SIZE]);
int gaokun_ec_ucsi_get_reg(struct gaokun_ec *ec, struct gaokun_ucsi_reg *ureg);
int gaokun_ec_ucsi_pan_ack(struct gaokun_ec *ec, int port_id);
#endif /* __HUAWEI_GAOKUN_EC_H__ */

View File

@ -13,7 +13,7 @@ endif
# Do not use make's built-in rules
# (this improves performance and avoids hard-to-debug behaviour);
MAKEFLAGS += -r
override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include -I/usr/include/libnl3
override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include -I$(shell $(CC) -print-sysroot)/usr/include/libnl3
override LDFLAGS += -lnl-genl-3 -lnl-3
ALL_TARGETS := intel-speed-select

View File

@ -16,7 +16,7 @@ struct process_cmd_struct {
int arg;
};
static const char *version_str = "v1.21";
static const char *version_str = "v1.22";
static const int supported_api_ver = 3;
static struct isst_if_platform_info isst_platform_info;
@ -46,8 +46,9 @@ static int force_online_offline;
static int auto_mode;
static int fact_enable_fail;
static int cgroupv2;
static int max_pkg_id;
static int max_die_id;
static int max_punit_id;
static int max_die_id_package_0;
/* clos related */
static int current_clos = -1;
@ -557,6 +558,8 @@ void for_each_online_power_domain_in_set(void (*callback)(struct isst_id *, void
if (id.pkg < 0 || id.die < 0 || id.punit < 0)
continue;
id.die = id.die % (max_die_id_package_0 + 1);
valid_mask[id.pkg][id.die] = 1;
if (cpus[id.pkg][id.die][id.punit] == -1)
@ -564,11 +567,11 @@ void for_each_online_power_domain_in_set(void (*callback)(struct isst_id *, void
}
for (i = 0; i < MAX_PACKAGE_COUNT; i++) {
if (max_die_id == max_punit_id) {
if (max_die_id > max_pkg_id) {
for (k = 0; k < MAX_PUNIT_PER_DIE && k < MAX_DIE_PER_PACKAGE; k++) {
id.cpu = cpus[i][k][k];
id.pkg = i;
id.die = k;
id.die = get_physical_die_id(id.cpu);
id.punit = k;
if (isst_is_punit_valid(&id))
callback(&id, arg1, arg2, arg3, arg4);
@ -586,7 +589,10 @@ void for_each_online_power_domain_in_set(void (*callback)(struct isst_id *, void
for (k = 0; k < MAX_PUNIT_PER_DIE; k++) {
id.cpu = cpus[i][j][k];
id.pkg = i;
id.die = j;
if (id.cpu >= 0)
id.die = get_physical_die_id(id.cpu);
else
id.die = id.pkg;
id.punit = k;
if (isst_is_punit_valid(&id))
callback(&id, arg1, arg2, arg3, arg4);
@ -788,6 +794,8 @@ static void create_cpu_map(void)
cpu_map[i].die_id = die_id;
cpu_map[i].core_id = core_id;
if (max_pkg_id < pkg_id)
max_pkg_id = pkg_id;
punit_id = 0;
@ -812,8 +820,8 @@ static void create_cpu_map(void)
if (max_die_id < die_id)
max_die_id = die_id;
if (max_punit_id < cpu_map[i].punit_id)
max_punit_id = cpu_map[i].punit_id;
if (!pkg_id && max_die_id_package_0 < die_id)
max_die_id_package_0 = die_id;
debug_printf(
"map logical_cpu:%d core: %d die:%d pkg:%d punit:%d punit_cpu:%d punit_core:%d\n",

View File

@ -173,7 +173,11 @@ static int print_package_info(struct isst_id *id, FILE *outf)
if (out_format_is_json()) {
if (api_version() > 1) {
if (id->cpu < 0)
if (id->die < 0 && id->cpu < 0)
snprintf(header, sizeof(header),
"package-%d:die-IO:powerdomain-%d:cpu-None",
id->pkg, id->punit);
else if (id->cpu < 0)
snprintf(header, sizeof(header),
"package-%d:die-%d:powerdomain-%d:cpu-None",
id->pkg, id->die, id->punit);
@ -190,7 +194,10 @@ static int print_package_info(struct isst_id *id, FILE *outf)
}
snprintf(header, sizeof(header), "package-%d", id->pkg);
format_and_print(outf, level++, header, NULL);
snprintf(header, sizeof(header), "die-%d", id->die);
if (id->die < 0)
snprintf(header, sizeof(header), "die-IO");
else
snprintf(header, sizeof(header), "die-%d", id->die);
format_and_print(outf, level++, header, NULL);
if (api_version() > 1) {
snprintf(header, sizeof(header), "powerdomain-%d", id->punit);