mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge tag 'platform-drivers-x86-v6.5-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86
Pull x86 platform driver updates from Hans de Goede: "AMD PMC and PMF drivers: - Various bugfixes - Improved debugging support Intel PMC: - Refactor to support hw with multiple PMCs - Various other improvements / new hw support Intel Speed Select Technology (ISST): - TPMI Uncore Frequency + Cluster Level Power Controls - Various bugfixes - tools/intel-speed-select: Misc improvements Dell-DDV: Add documentation INT3472 ACPI camera sensor glue code: - Evaluate device's _DSM method to control imaging clock - Drop the need to have a table with per sensor-model info Lenovo Yogabook: - Refactor / rework to also support Android models Think-LMI: - Multiple improvements and fixes WMI: - Add proper API documentation for the WMI bus x86-android-tablets: - Misc new hw support Miscellaneous other cleanups / fixes" * tag 'platform-drivers-x86-v6.5-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (91 commits) platform/x86:intel/pmc: Add Meteor Lake IOE-M PMC related maps platform/x86:intel/pmc: Add Meteor Lake IOE-P PMC related maps platform/x86:intel/pmc: Use SSRAM to discover pwrm base address of primary PMC platform/x86:intel/pmc: Discover PMC devices platform/x86:intel/pmc: Enable debugfs multiple PMC support platform/x86:intel/pmc: Add support to handle multiple PMCs platform/x86:intel/pmc: Combine core_init() and core_configure() platform/x86:intel/pmc: Update maps for Meteor Lake P/M platforms platform/x86/intel: tpmi: Remove hardcoded unit and offset platform/x86: int3472: discrete: Log a warning if the pin-numbers don't match platform/x86: int3472: discrete: Use FIELD_GET() on the GPIO _DSM return value platform/x86: int3472: discrete: Add alternative "AVDD" regulator supply name platform/x86: int3472: discrete: Add support for 1 GPIO regulator shared between 2 sensors platform/x86: int3472: discrete: Remove sensor_config-s platform/x86: int3472: discrete: Drop GPIO remapping support platform/x86: apple-gmux: don't use be32_to_cpu and cpu_to_be32 platform/x86/dell/dell-rbtn: Fix resources leaking on error path platform/x86: ISST: Fix usage counter platform/x86: ISST: Reset default callback on unregister platform/x86: int3472: Switch back to use struct i2c_driver's .probe() ...
This commit is contained in:
7
Documentation/ABI/stable/sysfs-platform-wmi-bmof
Normal file
7
Documentation/ABI/stable/sysfs-platform-wmi-bmof
Normal file
@@ -0,0 +1,7 @@
|
||||
What: /sys/bus/wmi/devices/05901221-D566-11D1-B2F0-00A0C9062910[-X]/bmof
|
||||
Date: Jun 2017
|
||||
KernelVersion: 4.13
|
||||
Description:
|
||||
Binary MOF metadata used to decribe the details of available ACPI WMI interfaces.
|
||||
|
||||
See Documentation/wmi/devices/wmi-bmof.rst for details.
|
||||
@@ -3,19 +3,32 @@ Date: September 2022
|
||||
KernelVersion: 6.1
|
||||
Contact: Armin Wolf <W_Armin@gmx.de>
|
||||
Description:
|
||||
This file contains the contents of the fan sensor information buffer,
|
||||
which contains fan sensor entries and a terminating character (0xFF).
|
||||
This file contains the contents of the fan sensor information
|
||||
buffer, which contains fan sensor entries and a terminating
|
||||
character (0xFF).
|
||||
|
||||
Each fan sensor entry consists of three bytes with an unknown meaning,
|
||||
interested people may use this file for reverse-engineering.
|
||||
Each fan sensor entry contains:
|
||||
|
||||
- fan type (single byte)
|
||||
- fan speed in RPM (two bytes, little endian)
|
||||
|
||||
See Documentation/wmi/devices/dell-wmi-ddv.rst for details.
|
||||
|
||||
What: /sys/kernel/debug/dell-wmi-ddv-<wmi_device_name>/thermal_sensor_information
|
||||
Date: September 2022
|
||||
KernelVersion: 6.1
|
||||
Contact: Armin Wolf <W_Armin@gmx.de>
|
||||
Description:
|
||||
This file contains the contents of the thermal sensor information buffer,
|
||||
which contains thermal sensor entries and a terminating character (0xFF).
|
||||
This file contains the contents of the thermal sensor information
|
||||
buffer, which contains thermal sensor entries and a terminating
|
||||
character (0xFF).
|
||||
|
||||
Each thermal sensor entry consists of five bytes with an unknown meaning,
|
||||
interested people may use this file for reverse-engineering.
|
||||
Each thermal sensor entry contains:
|
||||
|
||||
- thermal type (single byte)
|
||||
- current temperature (single byte)
|
||||
- min. temperature (single byte)
|
||||
- max. temperature (single byte)
|
||||
- unknown field (single byte)
|
||||
|
||||
See Documentation/wmi/devices/dell-wmi-ddv.rst for details.
|
||||
|
||||
@@ -243,8 +243,8 @@ Description:
|
||||
|
||||
index:
|
||||
Used with HDD and NVME authentication to set the drive index
|
||||
that is being referenced (e.g hdd0, hdd1 etc)
|
||||
This attribute defaults to device 0.
|
||||
that is being referenced (e.g hdd1, hdd2 etc)
|
||||
This attribute defaults to device 1.
|
||||
|
||||
certificate, signature, save_signature:
|
||||
These attributes are used for certificate based authentication. This is
|
||||
|
||||
@@ -3,5 +3,7 @@ Date: September 2022
|
||||
KernelVersion: 6.1
|
||||
Contact: Armin Wolf <W_Armin@gmx.de>
|
||||
Description:
|
||||
Reports the Dell ePPID (electronic Dell Piece Part Identification)
|
||||
Reports the Dell ePPID (electronic Piece Part Identification)
|
||||
of the ACPI battery.
|
||||
|
||||
See Documentation/wmi/devices/dell-wmi-ddv.rst for details.
|
||||
|
||||
@@ -75,3 +75,12 @@ KernelVersion: 6.4
|
||||
Contact: "Liming Sun <limings@nvidia.com>"
|
||||
Description:
|
||||
The file used to access the BlueField boot fifo.
|
||||
|
||||
What: /sys/bus/platform/devices/MLNXBF04:00/rsh_log
|
||||
Date: May 2023
|
||||
KernelVersion: 6.4
|
||||
Contact: "Liming Sun <limings@nvidia.com>"
|
||||
Description:
|
||||
The file used to write BlueField boot log with the format
|
||||
"[INFO|WARN|ERR|ASSERT ]<msg>". Log level 'INFO' is used by
|
||||
default if not specified.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
Intel Uncore Frequency Scaling
|
||||
==============================
|
||||
|
||||
:Copyright: |copy| 2022 Intel Corporation
|
||||
:Copyright: |copy| 2022-2023 Intel Corporation
|
||||
|
||||
:Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
|
||||
|
||||
@@ -58,3 +58,58 @@ Each package_*_die_* contains the following attributes:
|
||||
|
||||
``current_freq_khz``
|
||||
This attribute is used to get the current uncore frequency.
|
||||
|
||||
SoCs with TPMI (Topology Aware Register and PM Capsule Interface)
|
||||
-----------------------------------------------------------------
|
||||
|
||||
An SoC can contain multiple power domains with individual or collection
|
||||
of mesh partitions. This partition is called fabric cluster.
|
||||
|
||||
Certain type of meshes will need to run at the same frequency, they will
|
||||
be placed in the same fabric cluster. Benefit of fabric cluster is that it
|
||||
offers a scalable mechanism to deal with partitioned fabrics in a SoC.
|
||||
|
||||
The current sysfs interface supports controls at package and die level.
|
||||
This interface is not enough to support more granular control at
|
||||
fabric cluster level.
|
||||
|
||||
SoCs with the support of TPMI (Topology Aware Register and PM Capsule
|
||||
Interface), can have multiple power domains. Each power domain can
|
||||
contain one or more fabric clusters.
|
||||
|
||||
To represent controls at fabric cluster level in addition to the
|
||||
controls at package and die level (like systems without TPMI
|
||||
support), sysfs is enhanced. This granular interface is presented in the
|
||||
sysfs with directories names prefixed with "uncore". For example:
|
||||
uncore00, uncore01 etc.
|
||||
|
||||
The scope of control is specified by attributes "package_id", "domain_id"
|
||||
and "fabric_cluster_id" in the directory.
|
||||
|
||||
Attributes in each directory:
|
||||
|
||||
``domain_id``
|
||||
This attribute is used to get the power domain id of this instance.
|
||||
|
||||
``fabric_cluster_id``
|
||||
This attribute is used to get the fabric cluster id of this instance.
|
||||
|
||||
``package_id``
|
||||
This attribute is used to get the package id of this instance.
|
||||
|
||||
The other attributes are same as presented at package_*_die_* level.
|
||||
|
||||
In most of current use cases, the "max_freq_khz" and "min_freq_khz"
|
||||
is updated at "package_*_die_*" level. This model will be still supported
|
||||
with the following approach:
|
||||
|
||||
When user uses controls at "package_*_die_*" level, then every fabric
|
||||
cluster is affected in that package and die. For example: user changes
|
||||
"max_freq_khz" in the package_00_die_00, then "max_freq_khz" for uncore*
|
||||
directory with the same package id will be updated. In this case user can
|
||||
still update "max_freq_khz" at each uncore* level, which is more restrictive.
|
||||
Similarly, user can update "min_freq_khz" at "package_*_die_*" level
|
||||
to apply at each uncore* level.
|
||||
|
||||
Support for "current_freq_khz" is available only at each fabric cluster
|
||||
level (i.e., in uncore* directory).
|
||||
|
||||
@@ -113,6 +113,7 @@ available subsections can be seen below.
|
||||
xillybus
|
||||
zorro
|
||||
hte/index
|
||||
wmi
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
|
||||
21
Documentation/driver-api/wmi.rst
Normal file
21
Documentation/driver-api/wmi.rst
Normal file
@@ -0,0 +1,21 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
==============
|
||||
WMI Driver API
|
||||
==============
|
||||
|
||||
The WMI driver core supports a more modern bus-based interface for interacting
|
||||
with WMI devices, and an older GUID-based interface. The latter interface is
|
||||
considered to be deprecated, so new WMI drivers should generally avoid it since
|
||||
it has some issues with multiple WMI devices and events sharing the same GUIDs
|
||||
and/or notification IDs. The modern bus-based interface instead maps each
|
||||
WMI device to a :c:type:`struct wmi_device <wmi_device>`, so it supports
|
||||
WMI devices sharing GUIDs and/or notification IDs. Drivers can then register
|
||||
a :c:type:`struct wmi_driver <wmi_driver>`, which will be bound to compatible
|
||||
WMI devices by the driver core.
|
||||
|
||||
.. kernel-doc:: include/linux/wmi.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/platform/x86/wmi.c
|
||||
:export:
|
||||
@@ -71,3 +71,4 @@ Storage interfaces
|
||||
scheduler/index
|
||||
mhi/index
|
||||
peci/index
|
||||
wmi/index
|
||||
|
||||
96
Documentation/wmi/acpi-interface.rst
Normal file
96
Documentation/wmi/acpi-interface.rst
Normal file
@@ -0,0 +1,96 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
==================
|
||||
ACPI WMI interface
|
||||
==================
|
||||
|
||||
The ACPI WMI interface is a proprietary extension of the ACPI specification made
|
||||
by Microsoft to allow hardware vendors to embed WMI (Windows Management Instrumentation)
|
||||
objects inside their ACPI firmware. Typical functions implemented over ACPI WMI
|
||||
are hotkey events on modern notebooks and configuration of BIOS options.
|
||||
|
||||
PNP0C14 ACPI device
|
||||
-------------------
|
||||
|
||||
Discovery of WMI objects is handled by defining ACPI devices with a PNP ID
|
||||
of ``PNP0C14``. These devices will contain a set of ACPI buffers and methods
|
||||
used for mapping and execution of WMI methods and/or queries. If there exist
|
||||
multiple of such devices, then each device is required to have a
|
||||
unique ACPI UID.
|
||||
|
||||
_WDG buffer
|
||||
-----------
|
||||
|
||||
The ``_WDG`` buffer is used to discover WMI objects and is required to be
|
||||
static. Its internal structure consists of data blocks with a size of 20 bytes,
|
||||
containing the following data:
|
||||
|
||||
======= =============== =====================================================
|
||||
Offset Size (in bytes) Content
|
||||
======= =============== =====================================================
|
||||
0x00 16 128 bit Variant 2 object GUID.
|
||||
0x10 2 2 character method ID or single byte notification ID.
|
||||
0x12 1 Object instance count.
|
||||
0x13 1 Object flags.
|
||||
======= =============== =====================================================
|
||||
|
||||
The WMI object flags control whether the method or notification ID is used:
|
||||
|
||||
- 0x1: Data block usage is expensive and must be explicitly enabled/disabled.
|
||||
- 0x2: Data block contains WMI methods.
|
||||
- 0x4: Data block contains ASCIZ string.
|
||||
- 0x8: Data block describes a WMI event, use notification ID instead
|
||||
of method ID.
|
||||
|
||||
Each WMI object GUID can appear multiple times inside a system.
|
||||
The method/notification ID is used to construct the ACPI method names used for
|
||||
interacting with the WMI object.
|
||||
|
||||
WQxx ACPI methods
|
||||
-----------------
|
||||
|
||||
If a data block does not contain WMI methods, then its content can be retrieved
|
||||
by this required ACPI method. The last two characters of the ACPI method name
|
||||
are the method ID of the data block to query. Their single parameter is an
|
||||
integer describing the instance which should be queried. This parameter can be
|
||||
omitted if the data block contains only a single instance.
|
||||
|
||||
WSxx ACPI methods
|
||||
-----------------
|
||||
|
||||
Similar to the ``WQxx`` ACPI methods, except that it is optional and takes an
|
||||
additional buffer as its second argument. The instance argument also cannot
|
||||
be omitted.
|
||||
|
||||
WMxx ACPI methods
|
||||
-----------------
|
||||
|
||||
Used for executing WMI methods associated with a data block. The last two
|
||||
characters of the ACPI method name are the method ID of the data block
|
||||
containing the WMI methods. Their first parameter is a integer describing the
|
||||
instance which methods should be executed. The second parameter is an integer
|
||||
describing the WMI method ID to execute, and the third parameter is a buffer
|
||||
containing the WMI method parameters. If the data block is marked as containing
|
||||
an ASCIZ string, then this buffer should contain an ASCIZ string. The ACPI
|
||||
method will return the result of the executed WMI method.
|
||||
|
||||
WExx ACPI methods
|
||||
-----------------
|
||||
|
||||
Used for optionally enabling/disabling WMI events, the last two characters of
|
||||
the ACPI method are the notification ID of the data block describing the WMI
|
||||
event as hexadecimal value. Their first parameter is an integer with a value
|
||||
of 0 if the WMI event should be disabled, other values will enable
|
||||
the WMI event.
|
||||
|
||||
WCxx ACPI methods
|
||||
-----------------
|
||||
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.
|
||||
|
||||
_WED ACPI method
|
||||
----------------
|
||||
|
||||
Used to retrieve additional WMI event data, its single parameter is a integer
|
||||
holding the notification ID of the event.
|
||||
296
Documentation/wmi/devices/dell-wmi-ddv.rst
Normal file
296
Documentation/wmi/devices/dell-wmi-ddv.rst
Normal file
@@ -0,0 +1,296 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
============================================
|
||||
Dell DDV WMI interface driver (dell-wmi-ddv)
|
||||
============================================
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
Many Dell notebooks made after ~2020 support a WMI-based interface for
|
||||
retrieving various system data like battery temperature, ePPID, diagostic data
|
||||
and fan/thermal sensor data.
|
||||
|
||||
This interface is likely used by the `Dell Data Vault` software on Windows,
|
||||
so it was called `DDV`. Currently the ``dell-wmi-ddv`` driver supports
|
||||
version 2 and 3 of the interface, with support for new interface versions
|
||||
easily added.
|
||||
|
||||
.. warning:: The interface is regarded as internal by Dell, so no vendor
|
||||
documentation is available. All knowledge was thus obtained by
|
||||
trial-and-error, please keep that in mind.
|
||||
|
||||
Dell ePPID (electronic Piece Part Identification)
|
||||
=================================================
|
||||
|
||||
The Dell ePPID is used to uniquely identify components in Dell machines,
|
||||
including batteries. It has a form similar to `CC-PPPPPP-MMMMM-YMD-SSSS-FFF`
|
||||
and contains the following information:
|
||||
|
||||
* Country code of origin (CC).
|
||||
* Part number with the first character being a filling number (PPPPPP).
|
||||
* Manufacture Identification (MMMMM).
|
||||
* Manufacturing Year/Month/Date (YMD) in base 36, with Y being the last digit
|
||||
of the year.
|
||||
* Manufacture Sequence Number (SSSS).
|
||||
* Optional Firmware Version/Revision (FFF).
|
||||
|
||||
The `eppidtool <https://pypi.org/project/eppidtool>`_ python utility can be used
|
||||
to decode and display this information.
|
||||
|
||||
All information regarding the Dell ePPID was gathered using Dell support
|
||||
documentation and `this website <https://telcontar.net/KBK/Dell/date_codes>`_.
|
||||
|
||||
WMI interface description
|
||||
=========================
|
||||
|
||||
The WMI interface description can be decoded from the embedded binary MOF (bmof)
|
||||
data using the `bmfdec <https://github.com/pali/bmfdec>`_ utility:
|
||||
|
||||
::
|
||||
|
||||
[WMI, Dynamic, Provider("WmiProv"), Locale("MS\\0x409"), Description("WMI Function"), guid("{8A42EA14-4F2A-FD45-6422-0087F7A7E608}")]
|
||||
class DDVWmiMethodFunction {
|
||||
[key, read] string InstanceName;
|
||||
[read] boolean Active;
|
||||
|
||||
[WmiMethodId(1), Implemented, read, write, Description("Return Battery Design Capacity.")] void BatteryDesignCapacity([in] uint32 arg2, [out] uint32 argr);
|
||||
[WmiMethodId(2), Implemented, read, write, Description("Return Battery Full Charge Capacity.")] void BatteryFullChargeCapacity([in] uint32 arg2, [out] uint32 argr);
|
||||
[WmiMethodId(3), Implemented, read, write, Description("Return Battery Manufacture Name.")] void BatteryManufactureName([in] uint32 arg2, [out] string argr);
|
||||
[WmiMethodId(4), Implemented, read, write, Description("Return Battery Manufacture Date.")] void BatteryManufactureDate([in] uint32 arg2, [out] uint32 argr);
|
||||
[WmiMethodId(5), Implemented, read, write, Description("Return Battery Serial Number.")] void BatterySerialNumber([in] uint32 arg2, [out] uint32 argr);
|
||||
[WmiMethodId(6), Implemented, read, write, Description("Return Battery Chemistry Value.")] void BatteryChemistryValue([in] uint32 arg2, [out] string argr);
|
||||
[WmiMethodId(7), Implemented, read, write, Description("Return Battery Temperature.")] void BatteryTemperature([in] uint32 arg2, [out] uint32 argr);
|
||||
[WmiMethodId(8), Implemented, read, write, Description("Return Battery Current.")] void BatteryCurrent([in] uint32 arg2, [out] uint32 argr);
|
||||
[WmiMethodId(9), Implemented, read, write, Description("Return Battery Voltage.")] void BatteryVoltage([in] uint32 arg2, [out] uint32 argr);
|
||||
[WmiMethodId(10), Implemented, read, write, Description("Return Battery Manufacture Access(MA code).")] void BatteryManufactureAceess([in] uint32 arg2, [out] uint32 argr);
|
||||
[WmiMethodId(11), Implemented, read, write, Description("Return Battery Relative State-Of-Charge.")] void BatteryRelativeStateOfCharge([in] uint32 arg2, [out] uint32 argr);
|
||||
[WmiMethodId(12), Implemented, read, write, Description("Return Battery Cycle Count")] void BatteryCycleCount([in] uint32 arg2, [out] uint32 argr);
|
||||
[WmiMethodId(13), Implemented, read, write, Description("Return Battery ePPID")] void BatteryePPID([in] uint32 arg2, [out] string argr);
|
||||
[WmiMethodId(14), Implemented, read, write, Description("Return Battery Raw Analytics Start")] void BatteryeRawAnalyticsStart([in] uint32 arg2, [out] uint32 argr);
|
||||
[WmiMethodId(15), Implemented, read, write, Description("Return Battery Raw Analytics")] void BatteryeRawAnalytics([in] uint32 arg2, [out] uint32 RawSize, [out, WmiSizeIs("RawSize") : ToInstance] uint8 RawData[]);
|
||||
[WmiMethodId(16), Implemented, read, write, Description("Return Battery Design Voltage.")] void BatteryDesignVoltage([in] uint32 arg2, [out] uint32 argr);
|
||||
[WmiMethodId(17), Implemented, read, write, Description("Return Battery Raw Analytics A Block")] void BatteryeRawAnalyticsABlock([in] uint32 arg2, [out] uint32 RawSize, [out, WmiSizeIs("RawSize") : ToInstance] uint8 RawData[]);
|
||||
[WmiMethodId(18), Implemented, read, write, Description("Return Version.")] void ReturnVersion([in] uint32 arg2, [out] uint32 argr);
|
||||
[WmiMethodId(32), Implemented, read, write, Description("Return Fan Sensor Information")] void FanSensorInformation([in] uint32 arg2, [out] uint32 RawSize, [out, WmiSizeIs("RawSize") : ToInstance] uint8 RawData[]);
|
||||
[WmiMethodId(34), Implemented, read, write, Description("Return Thermal Sensor Information")] void ThermalSensorInformation([in] uint32 arg2, [out] uint32 RawSize, [out, WmiSizeIs("RawSize") : ToInstance] uint8 RawData[]);
|
||||
};
|
||||
|
||||
Each WMI method takes an ACPI buffer containing a 32-bit index as input argument,
|
||||
with the first 8 bit being used to specify the battery when using battery-related
|
||||
WMI methods. Other WMI methods may ignore this argument or interpret it
|
||||
differently. The WMI method output format varies:
|
||||
|
||||
* if the function has only a single output, then an ACPI object
|
||||
of the corresponding type is returned
|
||||
* if the function has multiple outputs, when an ACPI package
|
||||
containing the outputs in the same order is returned
|
||||
|
||||
The format of the output should be thoroughly checked, since many methods can
|
||||
return malformed data in case of an error.
|
||||
|
||||
The data format of many battery-related methods seems to be based on the
|
||||
`Smart Battery Data Specification`, so unknown battery-related methods are
|
||||
likely to follow this standard in some way.
|
||||
|
||||
WMI method GetBatteryDesignCapacity()
|
||||
-------------------------------------
|
||||
|
||||
Returns the design capacity of the battery in mAh as an u16.
|
||||
|
||||
WMI method BatteryFullCharge()
|
||||
------------------------------
|
||||
|
||||
Returns the full charge capacity of the battery in mAh as an u16.
|
||||
|
||||
WMI method BatteryManufactureName()
|
||||
-----------------------------------
|
||||
|
||||
Returns the manufacture name of the battery as an ASCII string.
|
||||
|
||||
WMI method BatteryManufactureDate()
|
||||
-----------------------------------
|
||||
|
||||
Returns the manufacture date of the battery as an u16.
|
||||
The date is encoded in the following manner:
|
||||
|
||||
- bits 0 to 4 contain the manufacture day.
|
||||
- bits 5 to 8 contain the manufacture month.
|
||||
- bits 9 to 15 contain the manufacture year biased by 1980.
|
||||
|
||||
.. note::
|
||||
The data format needs to be verified on more machines.
|
||||
|
||||
WMI method BatterySerialNumber()
|
||||
--------------------------------
|
||||
|
||||
Returns the serial number of the battery as an u16.
|
||||
|
||||
WMI method BatteryChemistryValue()
|
||||
----------------------------------
|
||||
|
||||
Returns the chemistry of the battery as an ASCII string.
|
||||
Known values are:
|
||||
|
||||
- "Li-I" for Li-Ion
|
||||
|
||||
WMI method BatteryTemperature()
|
||||
-------------------------------
|
||||
|
||||
Returns the temperature of the battery in tenth degree kelvin as an u16.
|
||||
|
||||
WMI method BatteryCurrent()
|
||||
---------------------------
|
||||
|
||||
Returns the current flow of the battery in mA as an s16.
|
||||
Negative values indicate discharging.
|
||||
|
||||
WMI method BatteryVoltage()
|
||||
---------------------------
|
||||
|
||||
Returns the voltage flow of the battery in mV as an u16.
|
||||
|
||||
WMI method BatteryManufactureAccess()
|
||||
-------------------------------------
|
||||
|
||||
Returns a manufacture-defined value as an u16.
|
||||
|
||||
WMI method BatteryRelativeStateOfCharge()
|
||||
-----------------------------------------
|
||||
|
||||
Returns the capacity of the battery in percent as an u16.
|
||||
|
||||
WMI method BatteryCycleCount()
|
||||
------------------------------
|
||||
|
||||
Returns the cycle count of the battery as an u16.
|
||||
|
||||
WMI method BatteryePPID()
|
||||
-------------------------
|
||||
|
||||
Returns the ePPID of the battery as an ASCII string.
|
||||
|
||||
WMI method BatteryeRawAnalyticsStart()
|
||||
--------------------------------------
|
||||
|
||||
Performs an analysis of the battery and returns a status code:
|
||||
|
||||
- ``0x0``: Success
|
||||
- ``0x1``: Interface not supported
|
||||
- ``0xfffffffe``: Error/Timeout
|
||||
|
||||
.. note::
|
||||
The meaning of this method is still largely unknown.
|
||||
|
||||
WMI method BatteryeRawAnalytics()
|
||||
---------------------------------
|
||||
|
||||
Returns a buffer usually containg 12 blocks of analytics data.
|
||||
Those blocks contain:
|
||||
- block number starting with 0 (u8)
|
||||
- 31 bytes of unknown data
|
||||
|
||||
.. note::
|
||||
The meaning of this method is still largely unknown.
|
||||
|
||||
WMI method BatteryDesignVoltage()
|
||||
---------------------------------
|
||||
|
||||
Returns the design voltage of the battery in mV as an u16.
|
||||
|
||||
WMI method BatteryeRawAnalyticsABlock()
|
||||
---------------------------------------
|
||||
|
||||
Returns a single block of analytics data, with the second byte
|
||||
of the index being used for selecting the block number.
|
||||
|
||||
*Supported since WMI interface version 3!*
|
||||
|
||||
.. note::
|
||||
The meaning of this method is still largely unknown.
|
||||
|
||||
WMI method ReturnVersion()
|
||||
--------------------------
|
||||
|
||||
Returns the WMI interface version as an u32.
|
||||
|
||||
WMI method FanSensorInformation()
|
||||
---------------------------------
|
||||
|
||||
Returns a buffer containg fan sensor entries, terminated
|
||||
with a single ``0xff``.
|
||||
Those entries contain:
|
||||
|
||||
- fan type (u8)
|
||||
- fan speed in RPM (little endian u16)
|
||||
|
||||
WMI method ThermalSensorInformation()
|
||||
-------------------------------------
|
||||
|
||||
Returns a buffer containing thermal sensor entries, terminated
|
||||
with a single ``0xff``.
|
||||
Those entries contain:
|
||||
|
||||
- thermal type (u8)
|
||||
- current temperature (s8)
|
||||
- min. temperature (s8)
|
||||
- max. temperature (s8)
|
||||
- unknown field (u8)
|
||||
|
||||
.. note::
|
||||
TODO: Find out what the meaning of the last byte is.
|
||||
|
||||
ACPI battery matching algorithm
|
||||
===============================
|
||||
|
||||
The algorithm used to match ACPI batteries to indices is based on information
|
||||
which was found inside the logging messages of the OEM software.
|
||||
|
||||
Basically for each new ACPI battery, the serial numbers of the batteries behind
|
||||
indices 1 till 3 are compared with the serial number of the ACPI battery.
|
||||
Since the serial number of the ACPI battery can either be encoded as a normal
|
||||
integer or as a hexadecimal value, both cases need to be checked. The first
|
||||
index with a matching serial number is then selected.
|
||||
|
||||
A serial number of 0 indicates that the corresponding index is not associated
|
||||
with an actual battery, or that the associated battery is not present.
|
||||
|
||||
Some machines like the Dell Inspiron 3505 only support a single battery and thus
|
||||
ignore the battery index. Because of this the driver depends on the ACPI battery
|
||||
hook mechanism to discover batteries.
|
||||
|
||||
.. note::
|
||||
The ACPI battery matching algorithm currently used inside the driver is
|
||||
outdated and does not match the algorithm described above. The reasons for
|
||||
this are differences in the handling of the ToHexString() ACPI opcode between
|
||||
Linux and Windows, which distorts the serial number of ACPI batteries on many
|
||||
machines. Until this issue is resolved, the driver cannot use the above
|
||||
algorithm.
|
||||
|
||||
Reverse-Engineering the DDV WMI interface
|
||||
=========================================
|
||||
|
||||
1. Find a supported Dell notebook, usually made after ~2020.
|
||||
2. Dump the ACPI tables and search for the WMI device (usually called "ADDV").
|
||||
3. Decode the corresponding bmof data and look at the ASL code.
|
||||
4. Try to deduce the meaning of a certain WMI method by comparing the control
|
||||
flow with other ACPI methods (_BIX or _BIF for battery related methods
|
||||
for example).
|
||||
5. Use the built-in UEFI diagostics to view sensor types/values for fan/thermal
|
||||
related methods (sometimes overwriting static ACPI data fields can be used
|
||||
to test different sensor type values, since on some machines this data is
|
||||
not reinitialized upon a warm reset).
|
||||
|
||||
Alternatively:
|
||||
|
||||
1. Load the ``dell-wmi-ddv`` driver, use the ``force`` module param
|
||||
if necessary.
|
||||
2. Use the debugfs interface to access the raw fan/thermal sensor buffer data.
|
||||
3. Compare the data with the built-in UEFI diagnostics.
|
||||
|
||||
In case the DDV WMI interface version available on your Dell notebook is not
|
||||
supported or you are seeing unknown fan/thermal sensors, please submit a
|
||||
bugreport on `bugzilla <https://bugzilla.kernel.org>`_ so they can be added
|
||||
to the ``dell-wmi-ddv`` driver.
|
||||
|
||||
See Documentation/admin-guide/reporting-issues.rst for further information.
|
||||
22
Documentation/wmi/devices/index.rst
Normal file
22
Documentation/wmi/devices/index.rst
Normal file
@@ -0,0 +1,22 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
=============================
|
||||
Driver-specific Documentation
|
||||
=============================
|
||||
|
||||
This section provides information about various devices supported by
|
||||
the Linux kernel, their protocols and driver details.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:numbered:
|
||||
:glob:
|
||||
|
||||
*
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
Indices
|
||||
=======
|
||||
|
||||
* :ref:`genindex`
|
||||
25
Documentation/wmi/devices/wmi-bmof.rst
Normal file
25
Documentation/wmi/devices/wmi-bmof.rst
Normal file
@@ -0,0 +1,25 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
==============================
|
||||
WMI embedded Binary MOF driver
|
||||
==============================
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
Many machines embed WMI Binary MOF (Managed Object Format) metadata used to
|
||||
describe the details of their ACPI WMI interfaces. The data can be decoded
|
||||
with tools like `bmfdec <https://github.com/pali/bmfdec>`_ to obtain a
|
||||
human readable WMI interface description, which is useful for developing
|
||||
new WMI drivers.
|
||||
|
||||
The Binary MOF data can be retrieved from the ``bmof`` sysfs attribute of the
|
||||
associated WMI device. Please note that multiple WMI devices containing Binary
|
||||
MOF data can exist on a given system.
|
||||
|
||||
WMI interface
|
||||
=============
|
||||
|
||||
The Binary MOF WMI device is identified by the WMI GUID ``05901221-D566-11D1-B2F0-00A0C9062910``.
|
||||
The Binary MOF can be obtained by doing a WMI data block query. The result is
|
||||
then returned as an ACPI buffer with a variable size.
|
||||
19
Documentation/wmi/index.rst
Normal file
19
Documentation/wmi/index.rst
Normal file
@@ -0,0 +1,19 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
=============
|
||||
WMI Subsystem
|
||||
=============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
acpi-interface
|
||||
devices/index
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
|
||||
Indices
|
||||
=======
|
||||
|
||||
* :ref:`genindex`
|
||||
10
MAINTAINERS
10
MAINTAINERS
@@ -456,6 +456,8 @@ F: include/linux/acpi_viot.h
|
||||
ACPI WMI DRIVER
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Orphan
|
||||
F: Documentation/driver-api/wmi.rst
|
||||
F: Documentation/wmi/
|
||||
F: drivers/platform/x86/wmi.c
|
||||
F: include/uapi/linux/wmi.h
|
||||
|
||||
@@ -5842,6 +5844,7 @@ M: Armin Wolf <W_Armin@gmx.de>
|
||||
S: Maintained
|
||||
F: Documentation/ABI/testing/debugfs-dell-wmi-ddv
|
||||
F: Documentation/ABI/testing/sysfs-platform-dell-wmi-ddv
|
||||
F: Documentation/wmi/devices/dell-wmi-ddv.rst
|
||||
F: drivers/platform/x86/dell/dell-wmi-ddv.c
|
||||
|
||||
DELL WMI DESCRIPTOR DRIVER
|
||||
@@ -22910,6 +22913,13 @@ L: linux-wireless@vger.kernel.org
|
||||
S: Odd fixes
|
||||
F: drivers/net/wireless/legacy/wl3501*
|
||||
|
||||
WMI BINARY MOF DRIVER
|
||||
L: platform-drivers-x86@vger.kernel.org
|
||||
S: Orphan
|
||||
F: Documentation/ABI/stable/sysfs-platform-wmi-bmof
|
||||
F: Documentation/wmi/devices/wmi-bmof.rst
|
||||
F: drivers/platform/x86/wmi-bmof.c
|
||||
|
||||
WOLFSON MICROELECTRONICS DRIVERS
|
||||
L: patches@opensource.cirrus.com
|
||||
S: Supported
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
@@ -45,10 +46,39 @@ static const char * const mlxbf_bootctl_lifecycle_states[] = {
|
||||
[3] = "RMA",
|
||||
};
|
||||
|
||||
/* Log header format. */
|
||||
#define MLXBF_RSH_LOG_TYPE_MASK GENMASK_ULL(59, 56)
|
||||
#define MLXBF_RSH_LOG_LEN_MASK GENMASK_ULL(54, 48)
|
||||
#define MLXBF_RSH_LOG_LEVEL_MASK GENMASK_ULL(7, 0)
|
||||
|
||||
/* Log module ID and type (only MSG type in Linux driver for now). */
|
||||
#define MLXBF_RSH_LOG_TYPE_MSG 0x04ULL
|
||||
|
||||
/* Log ctl/data register offset. */
|
||||
#define MLXBF_RSH_SCRATCH_BUF_CTL_OFF 0
|
||||
#define MLXBF_RSH_SCRATCH_BUF_DATA_OFF 0x10
|
||||
|
||||
/* Log message levels. */
|
||||
enum {
|
||||
MLXBF_RSH_LOG_INFO,
|
||||
MLXBF_RSH_LOG_WARN,
|
||||
MLXBF_RSH_LOG_ERR,
|
||||
MLXBF_RSH_LOG_ASSERT
|
||||
};
|
||||
|
||||
/* Mapped pointer for RSH_BOOT_FIFO_DATA and RSH_BOOT_FIFO_COUNT register. */
|
||||
static void __iomem *mlxbf_rsh_boot_data;
|
||||
static void __iomem *mlxbf_rsh_boot_cnt;
|
||||
|
||||
/* Mapped pointer for rsh log semaphore/ctrl/data register. */
|
||||
static void __iomem *mlxbf_rsh_semaphore;
|
||||
static void __iomem *mlxbf_rsh_scratch_buf_ctl;
|
||||
static void __iomem *mlxbf_rsh_scratch_buf_data;
|
||||
|
||||
/* Rsh log levels. */
|
||||
static const char * const mlxbf_rsh_log_level[] = {
|
||||
"INFO", "WARN", "ERR", "ASSERT"};
|
||||
|
||||
/* ARM SMC call which is atomic and no need for lock. */
|
||||
static int mlxbf_bootctl_smc(unsigned int smc_op, int smc_arg)
|
||||
{
|
||||
@@ -266,12 +296,108 @@ static ssize_t fw_reset_store(struct device *dev,
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Size(8-byte words) of the log buffer. */
|
||||
#define RSH_SCRATCH_BUF_CTL_IDX_MASK 0x7f
|
||||
|
||||
/* 100ms timeout */
|
||||
#define RSH_SCRATCH_BUF_POLL_TIMEOUT 100000
|
||||
|
||||
static int mlxbf_rsh_log_sem_lock(void)
|
||||
{
|
||||
unsigned long reg;
|
||||
|
||||
return readq_poll_timeout(mlxbf_rsh_semaphore, reg, !reg, 0,
|
||||
RSH_SCRATCH_BUF_POLL_TIMEOUT);
|
||||
}
|
||||
|
||||
static void mlxbf_rsh_log_sem_unlock(void)
|
||||
{
|
||||
writeq(0, mlxbf_rsh_semaphore);
|
||||
}
|
||||
|
||||
static ssize_t rsh_log_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int rc, idx, num, len, level = MLXBF_RSH_LOG_INFO;
|
||||
size_t size = count;
|
||||
u64 data;
|
||||
|
||||
if (!size)
|
||||
return -EINVAL;
|
||||
|
||||
if (!mlxbf_rsh_semaphore || !mlxbf_rsh_scratch_buf_ctl)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Ignore line break at the end. */
|
||||
if (buf[size - 1] == '\n')
|
||||
size--;
|
||||
|
||||
/* Check the message prefix. */
|
||||
for (idx = 0; idx < ARRAY_SIZE(mlxbf_rsh_log_level); idx++) {
|
||||
len = strlen(mlxbf_rsh_log_level[idx]);
|
||||
if (len + 1 < size &&
|
||||
!strncmp(buf, mlxbf_rsh_log_level[idx], len)) {
|
||||
buf += len;
|
||||
size -= len;
|
||||
level = idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ignore leading spaces. */
|
||||
while (size > 0 && buf[0] == ' ') {
|
||||
size--;
|
||||
buf++;
|
||||
}
|
||||
|
||||
/* Take the semaphore. */
|
||||
rc = mlxbf_rsh_log_sem_lock();
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Calculate how many words are available. */
|
||||
idx = readq(mlxbf_rsh_scratch_buf_ctl);
|
||||
num = min((int)DIV_ROUND_UP(size, sizeof(u64)),
|
||||
RSH_SCRATCH_BUF_CTL_IDX_MASK - idx - 1);
|
||||
if (num <= 0)
|
||||
goto done;
|
||||
|
||||
/* Write Header. */
|
||||
data = FIELD_PREP(MLXBF_RSH_LOG_TYPE_MASK, MLXBF_RSH_LOG_TYPE_MSG);
|
||||
data |= FIELD_PREP(MLXBF_RSH_LOG_LEN_MASK, num);
|
||||
data |= FIELD_PREP(MLXBF_RSH_LOG_LEVEL_MASK, level);
|
||||
writeq(data, mlxbf_rsh_scratch_buf_data);
|
||||
|
||||
/* Write message. */
|
||||
for (idx = 0; idx < num && size > 0; idx++) {
|
||||
if (size < sizeof(u64)) {
|
||||
data = 0;
|
||||
memcpy(&data, buf, size);
|
||||
size = 0;
|
||||
} else {
|
||||
memcpy(&data, buf, sizeof(u64));
|
||||
size -= sizeof(u64);
|
||||
buf += sizeof(u64);
|
||||
}
|
||||
writeq(data, mlxbf_rsh_scratch_buf_data);
|
||||
}
|
||||
|
||||
done:
|
||||
/* Release the semaphore. */
|
||||
mlxbf_rsh_log_sem_unlock();
|
||||
|
||||
/* Ignore the rest if no more space. */
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(post_reset_wdog);
|
||||
static DEVICE_ATTR_RW(reset_action);
|
||||
static DEVICE_ATTR_RW(second_reset_action);
|
||||
static DEVICE_ATTR_RO(lifecycle_state);
|
||||
static DEVICE_ATTR_RO(secure_boot_fuse_state);
|
||||
static DEVICE_ATTR_WO(fw_reset);
|
||||
static DEVICE_ATTR_WO(rsh_log);
|
||||
|
||||
static struct attribute *mlxbf_bootctl_attrs[] = {
|
||||
&dev_attr_post_reset_wdog.attr,
|
||||
@@ -280,6 +406,7 @@ static struct attribute *mlxbf_bootctl_attrs[] = {
|
||||
&dev_attr_lifecycle_state.attr,
|
||||
&dev_attr_secure_boot_fuse_state.attr,
|
||||
&dev_attr_fw_reset.attr,
|
||||
&dev_attr_rsh_log.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -345,19 +472,32 @@ static bool mlxbf_bootctl_guid_match(const guid_t *guid,
|
||||
static int mlxbf_bootctl_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct arm_smccc_res res = { 0 };
|
||||
void __iomem *reg;
|
||||
guid_t guid;
|
||||
int ret;
|
||||
|
||||
/* Get the resource of the bootfifo data register. */
|
||||
/* Map the resource of the bootfifo data register. */
|
||||
mlxbf_rsh_boot_data = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(mlxbf_rsh_boot_data))
|
||||
return PTR_ERR(mlxbf_rsh_boot_data);
|
||||
|
||||
/* Get the resource of the bootfifo counter register. */
|
||||
/* Map the resource of the bootfifo counter register. */
|
||||
mlxbf_rsh_boot_cnt = devm_platform_ioremap_resource(pdev, 1);
|
||||
if (IS_ERR(mlxbf_rsh_boot_cnt))
|
||||
return PTR_ERR(mlxbf_rsh_boot_cnt);
|
||||
|
||||
/* Map the resource of the rshim semaphore register. */
|
||||
mlxbf_rsh_semaphore = devm_platform_ioremap_resource(pdev, 2);
|
||||
if (IS_ERR(mlxbf_rsh_semaphore))
|
||||
return PTR_ERR(mlxbf_rsh_semaphore);
|
||||
|
||||
/* Map the resource of the scratch buffer (log) registers. */
|
||||
reg = devm_platform_ioremap_resource(pdev, 3);
|
||||
if (IS_ERR(reg))
|
||||
return PTR_ERR(reg);
|
||||
mlxbf_rsh_scratch_buf_ctl = reg + MLXBF_RSH_SCRATCH_BUF_CTL_OFF;
|
||||
mlxbf_rsh_scratch_buf_data = reg + MLXBF_RSH_SCRATCH_BUF_DATA_OFF;
|
||||
|
||||
/* Ensure we have the UUID we expect for this service. */
|
||||
arm_smccc_smc(MLXBF_BOOTCTL_SIP_SVC_UID, 0, 0, 0, 0, 0, 0, 0, &res);
|
||||
guid_parse(mlxbf_bootctl_svc_uuid_str, &guid);
|
||||
|
||||
@@ -573,7 +573,7 @@ static const struct acpi_device_id mshw0011_acpi_match[] = {
|
||||
MODULE_DEVICE_TABLE(acpi, mshw0011_acpi_match);
|
||||
|
||||
static struct i2c_driver mshw0011_driver = {
|
||||
.probe_new = mshw0011_probe,
|
||||
.probe = mshw0011_probe,
|
||||
.remove = mshw0011_remove,
|
||||
.driver = {
|
||||
.name = "mshw0011",
|
||||
|
||||
@@ -43,8 +43,8 @@ config WMI_BMOF
|
||||
default ACPI_WMI
|
||||
help
|
||||
Say Y here if you want to be able to read a firmware-embedded
|
||||
WMI Binary MOF data. Using this requires userspace tools and may be
|
||||
rather tedious.
|
||||
WMI Binary MOF (Managed Object Format) data. Using this requires
|
||||
userspace tools and may be rather tedious.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called wmi-bmof.
|
||||
@@ -121,10 +121,11 @@ config GIGABYTE_WMI
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called gigabyte-wmi.
|
||||
|
||||
config YOGABOOK_WMI
|
||||
tristate "Lenovo Yoga Book tablet WMI key driver"
|
||||
config YOGABOOK
|
||||
tristate "Lenovo Yoga Book tablet key driver"
|
||||
depends on ACPI_WMI
|
||||
depends on INPUT
|
||||
depends on I2C
|
||||
select LEDS_CLASS
|
||||
select NEW_LEDS
|
||||
help
|
||||
@@ -132,7 +133,7 @@ config YOGABOOK_WMI
|
||||
control on the Lenovo Yoga Book tablets.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called lenovo-yogabook-wmi.
|
||||
be called lenovo-yogabook.
|
||||
|
||||
config ACERHDF
|
||||
tristate "Acer Aspire One temperature and fan driver"
|
||||
|
||||
@@ -14,7 +14,6 @@ obj-$(CONFIG_MXM_WMI) += mxm-wmi.o
|
||||
obj-$(CONFIG_NVIDIA_WMI_EC_BACKLIGHT) += nvidia-wmi-ec-backlight.o
|
||||
obj-$(CONFIG_XIAOMI_WMI) += xiaomi-wmi.o
|
||||
obj-$(CONFIG_GIGABYTE_WMI) += gigabyte-wmi.o
|
||||
obj-$(CONFIG_YOGABOOK_WMI) += lenovo-yogabook-wmi.o
|
||||
|
||||
# Acer
|
||||
obj-$(CONFIG_ACERHDF) += acerhdf.o
|
||||
@@ -66,6 +65,7 @@ obj-$(CONFIG_LENOVO_YMC) += lenovo-ymc.o
|
||||
obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
|
||||
obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
|
||||
obj-$(CONFIG_THINKPAD_LMI) += think-lmi.o
|
||||
obj-$(CONFIG_YOGABOOK) += lenovo-yogabook.o
|
||||
|
||||
# Intel
|
||||
obj-y += intel/
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
#define AMD_PMC_STB_DUMMY_PC 0xC6000007
|
||||
|
||||
/* STB S2D(Spill to DRAM) has different message port offset */
|
||||
#define STB_SPILL_TO_DRAM 0xBE
|
||||
#define AMD_S2D_REGISTER_MESSAGE 0xA20
|
||||
#define AMD_S2D_REGISTER_RESPONSE 0xA80
|
||||
#define AMD_S2D_REGISTER_ARGUMENT 0xA88
|
||||
@@ -99,7 +98,6 @@
|
||||
#define PMC_MSG_DELAY_MIN_US 50
|
||||
#define RESPONSE_REGISTER_LOOP_MAX 20000
|
||||
|
||||
#define SOC_SUBSYSTEM_IP_MAX 12
|
||||
#define DELAY_MIN_US 2000
|
||||
#define DELAY_MAX_US 3000
|
||||
#define FIFO_SIZE 4096
|
||||
@@ -115,6 +113,7 @@ enum s2d_arg {
|
||||
S2D_PHYS_ADDR_LOW,
|
||||
S2D_PHYS_ADDR_HIGH,
|
||||
S2D_NUM_SAMPLES,
|
||||
S2D_DRAM_SIZE,
|
||||
};
|
||||
|
||||
struct amd_pmc_bit_map {
|
||||
@@ -132,9 +131,18 @@ static const struct amd_pmc_bit_map soc15_ip_blk[] = {
|
||||
{"ISP", BIT(6)},
|
||||
{"NBIO", BIT(7)},
|
||||
{"DF", BIT(8)},
|
||||
{"USB0", BIT(9)},
|
||||
{"USB1", BIT(10)},
|
||||
{"USB3_0", BIT(9)},
|
||||
{"USB3_1", BIT(10)},
|
||||
{"LAPIC", BIT(11)},
|
||||
{"USB3_2", BIT(12)},
|
||||
{"USB3_3", BIT(13)},
|
||||
{"USB3_4", BIT(14)},
|
||||
{"USB4_0", BIT(15)},
|
||||
{"USB4_1", BIT(16)},
|
||||
{"MPM", BIT(17)},
|
||||
{"JPEG", BIT(18)},
|
||||
{"IPU", BIT(19)},
|
||||
{"UMSCH", BIT(20)},
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -147,6 +155,9 @@ struct amd_pmc_dev {
|
||||
u32 base_addr;
|
||||
u32 cpu_id;
|
||||
u32 active_ips;
|
||||
u32 dram_size;
|
||||
u32 num_ips;
|
||||
u32 s2d_msg_id;
|
||||
/* SMU version information */
|
||||
u8 smu_program;
|
||||
u8 major;
|
||||
@@ -194,8 +205,8 @@ struct smu_metrics {
|
||||
u64 timein_s0i3_totaltime;
|
||||
u64 timein_swdrips_lastcapture;
|
||||
u64 timein_swdrips_totaltime;
|
||||
u64 timecondition_notmet_lastcapture[SOC_SUBSYSTEM_IP_MAX];
|
||||
u64 timecondition_notmet_totaltime[SOC_SUBSYSTEM_IP_MAX];
|
||||
u64 timecondition_notmet_lastcapture[32];
|
||||
u64 timecondition_notmet_totaltime[32];
|
||||
} __packed;
|
||||
|
||||
static int amd_pmc_stb_debugfs_open(struct inode *inode, struct file *filp)
|
||||
@@ -261,7 +272,7 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp)
|
||||
dev->msg_port = 1;
|
||||
|
||||
/* Get the num_samples to calculate the last push location */
|
||||
ret = amd_pmc_send_cmd(dev, S2D_NUM_SAMPLES, &num_samples, STB_SPILL_TO_DRAM, 1);
|
||||
ret = amd_pmc_send_cmd(dev, S2D_NUM_SAMPLES, &num_samples, dev->s2d_msg_id, true);
|
||||
/* Clear msg_port for other SMU operation */
|
||||
dev->msg_port = 0;
|
||||
if (ret) {
|
||||
@@ -308,6 +319,23 @@ static const struct file_operations amd_pmc_stb_debugfs_fops_v2 = {
|
||||
.release = amd_pmc_stb_debugfs_release_v2,
|
||||
};
|
||||
|
||||
static void amd_pmc_get_ip_info(struct amd_pmc_dev *dev)
|
||||
{
|
||||
switch (dev->cpu_id) {
|
||||
case AMD_CPU_ID_PCO:
|
||||
case AMD_CPU_ID_RN:
|
||||
case AMD_CPU_ID_YC:
|
||||
case AMD_CPU_ID_CB:
|
||||
dev->num_ips = 12;
|
||||
dev->s2d_msg_id = 0xBE;
|
||||
break;
|
||||
case AMD_CPU_ID_PS:
|
||||
dev->num_ips = 21;
|
||||
dev->s2d_msg_id = 0x85;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int amd_pmc_setup_smu_logging(struct amd_pmc_dev *dev)
|
||||
{
|
||||
if (dev->cpu_id == AMD_CPU_ID_PCO) {
|
||||
@@ -317,15 +345,15 @@ static int amd_pmc_setup_smu_logging(struct amd_pmc_dev *dev)
|
||||
|
||||
/* Get Active devices list from SMU */
|
||||
if (!dev->active_ips)
|
||||
amd_pmc_send_cmd(dev, 0, &dev->active_ips, SMU_MSG_GET_SUP_CONSTRAINTS, 1);
|
||||
amd_pmc_send_cmd(dev, 0, &dev->active_ips, SMU_MSG_GET_SUP_CONSTRAINTS, true);
|
||||
|
||||
/* Get dram address */
|
||||
if (!dev->smu_virt_addr) {
|
||||
u32 phys_addr_low, phys_addr_hi;
|
||||
u64 smu_phys_addr;
|
||||
|
||||
amd_pmc_send_cmd(dev, 0, &phys_addr_low, SMU_MSG_LOG_GETDRAM_ADDR_LO, 1);
|
||||
amd_pmc_send_cmd(dev, 0, &phys_addr_hi, SMU_MSG_LOG_GETDRAM_ADDR_HI, 1);
|
||||
amd_pmc_send_cmd(dev, 0, &phys_addr_low, SMU_MSG_LOG_GETDRAM_ADDR_LO, true);
|
||||
amd_pmc_send_cmd(dev, 0, &phys_addr_hi, SMU_MSG_LOG_GETDRAM_ADDR_HI, true);
|
||||
smu_phys_addr = ((u64)phys_addr_hi << 32 | phys_addr_low);
|
||||
|
||||
dev->smu_virt_addr = devm_ioremap(dev->dev, smu_phys_addr,
|
||||
@@ -335,8 +363,8 @@ static int amd_pmc_setup_smu_logging(struct amd_pmc_dev *dev)
|
||||
}
|
||||
|
||||
/* Start the logging */
|
||||
amd_pmc_send_cmd(dev, 0, NULL, SMU_MSG_LOG_RESET, 0);
|
||||
amd_pmc_send_cmd(dev, 0, NULL, SMU_MSG_LOG_START, 0);
|
||||
amd_pmc_send_cmd(dev, 0, NULL, SMU_MSG_LOG_RESET, false);
|
||||
amd_pmc_send_cmd(dev, 0, NULL, SMU_MSG_LOG_START, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -377,7 +405,7 @@ static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev)
|
||||
if (dev->cpu_id == AMD_CPU_ID_PCO)
|
||||
return -ENODEV;
|
||||
|
||||
rc = amd_pmc_send_cmd(dev, 0, &val, SMU_MSG_GETSMUVERSION, 1);
|
||||
rc = amd_pmc_send_cmd(dev, 0, &val, SMU_MSG_GETSMUVERSION, true);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@@ -469,7 +497,7 @@ static int smu_fw_info_show(struct seq_file *s, void *unused)
|
||||
table.timeto_resume_to_os_lastcapture);
|
||||
|
||||
seq_puts(s, "\n=== Active time (in us) ===\n");
|
||||
for (idx = 0 ; idx < SOC_SUBSYSTEM_IP_MAX ; idx++) {
|
||||
for (idx = 0 ; idx < dev->num_ips ; idx++) {
|
||||
if (soc15_ip_blk[idx].bit_mask & dev->active_ips)
|
||||
seq_printf(s, "%-8s : %lld\n", soc15_ip_blk[idx].name,
|
||||
table.timecondition_notmet_lastcapture[idx]);
|
||||
@@ -562,6 +590,18 @@ static void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev)
|
||||
debugfs_remove_recursive(dev->dbgfs_dir);
|
||||
}
|
||||
|
||||
static bool amd_pmc_is_stb_supported(struct amd_pmc_dev *dev)
|
||||
{
|
||||
switch (dev->cpu_id) {
|
||||
case AMD_CPU_ID_YC:
|
||||
case AMD_CPU_ID_CB:
|
||||
case AMD_CPU_ID_PS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev)
|
||||
{
|
||||
dev->dbgfs_dir = debugfs_create_dir("amd_pmc", NULL);
|
||||
@@ -573,8 +613,7 @@ static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev)
|
||||
&amd_pmc_idlemask_fops);
|
||||
/* Enable STB only when the module_param is set */
|
||||
if (enable_stb) {
|
||||
if (dev->cpu_id == AMD_CPU_ID_YC || dev->cpu_id == AMD_CPU_ID_CB ||
|
||||
dev->cpu_id == AMD_CPU_ID_PS)
|
||||
if (amd_pmc_is_stb_supported(dev))
|
||||
debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev,
|
||||
&amd_pmc_stb_debugfs_fops_v2);
|
||||
else
|
||||
@@ -794,7 +833,7 @@ static void amd_pmc_s2idle_prepare(void)
|
||||
}
|
||||
|
||||
msg = amd_pmc_get_os_hint(pdev);
|
||||
rc = amd_pmc_send_cmd(pdev, arg, NULL, msg, 0);
|
||||
rc = amd_pmc_send_cmd(pdev, arg, NULL, msg, false);
|
||||
if (rc) {
|
||||
dev_err(pdev->dev, "suspend failed: %d\n", rc);
|
||||
return;
|
||||
@@ -829,7 +868,7 @@ static int amd_pmc_dump_data(struct amd_pmc_dev *pdev)
|
||||
if (pdev->cpu_id == AMD_CPU_ID_PCO)
|
||||
return -ENODEV;
|
||||
|
||||
return amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_DUMP_DATA, 0);
|
||||
return amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_DUMP_DATA, false);
|
||||
}
|
||||
|
||||
static void amd_pmc_s2idle_restore(void)
|
||||
@@ -839,7 +878,7 @@ static void amd_pmc_s2idle_restore(void)
|
||||
u8 msg;
|
||||
|
||||
msg = amd_pmc_get_os_hint(pdev);
|
||||
rc = amd_pmc_send_cmd(pdev, 0, NULL, msg, 0);
|
||||
rc = amd_pmc_send_cmd(pdev, 0, NULL, msg, false);
|
||||
if (rc)
|
||||
dev_err(pdev->dev, "resume failed: %d\n", rc);
|
||||
|
||||
@@ -890,29 +929,65 @@ static const struct pci_device_id pmc_pci_ids[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
static int amd_pmc_get_dram_size(struct amd_pmc_dev *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (dev->cpu_id) {
|
||||
case AMD_CPU_ID_YC:
|
||||
if (!(dev->major > 90 || (dev->major == 90 && dev->minor > 39))) {
|
||||
ret = -EINVAL;
|
||||
goto err_dram_size;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto err_dram_size;
|
||||
}
|
||||
|
||||
ret = amd_pmc_send_cmd(dev, S2D_DRAM_SIZE, &dev->dram_size, dev->s2d_msg_id, true);
|
||||
if (ret || !dev->dram_size)
|
||||
goto err_dram_size;
|
||||
|
||||
return 0;
|
||||
|
||||
err_dram_size:
|
||||
dev_err(dev->dev, "DRAM size command not supported for this platform\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amd_pmc_s2d_init(struct amd_pmc_dev *dev)
|
||||
{
|
||||
u32 phys_addr_low, phys_addr_hi;
|
||||
u64 stb_phys_addr;
|
||||
u32 size = 0;
|
||||
int ret;
|
||||
|
||||
/* Spill to DRAM feature uses separate SMU message port */
|
||||
dev->msg_port = 1;
|
||||
|
||||
amd_pmc_send_cmd(dev, S2D_TELEMETRY_SIZE, &size, STB_SPILL_TO_DRAM, 1);
|
||||
/* Get num of IP blocks within the SoC */
|
||||
amd_pmc_get_ip_info(dev);
|
||||
|
||||
amd_pmc_send_cmd(dev, S2D_TELEMETRY_SIZE, &size, dev->s2d_msg_id, true);
|
||||
if (size != S2D_TELEMETRY_BYTES_MAX)
|
||||
return -EIO;
|
||||
|
||||
/* Get DRAM size */
|
||||
ret = amd_pmc_get_dram_size(dev);
|
||||
if (ret)
|
||||
dev->dram_size = S2D_TELEMETRY_DRAMBYTES_MAX;
|
||||
|
||||
/* Get STB DRAM address */
|
||||
amd_pmc_send_cmd(dev, S2D_PHYS_ADDR_LOW, &phys_addr_low, STB_SPILL_TO_DRAM, 1);
|
||||
amd_pmc_send_cmd(dev, S2D_PHYS_ADDR_HIGH, &phys_addr_hi, STB_SPILL_TO_DRAM, 1);
|
||||
amd_pmc_send_cmd(dev, S2D_PHYS_ADDR_LOW, &phys_addr_low, dev->s2d_msg_id, true);
|
||||
amd_pmc_send_cmd(dev, S2D_PHYS_ADDR_HIGH, &phys_addr_hi, dev->s2d_msg_id, true);
|
||||
|
||||
stb_phys_addr = ((u64)phys_addr_hi << 32 | phys_addr_low);
|
||||
|
||||
/* Clear msg_port for other SMU operation */
|
||||
dev->msg_port = 0;
|
||||
|
||||
dev->stb_virt_addr = devm_ioremap(dev->dev, stb_phys_addr, S2D_TELEMETRY_DRAMBYTES_MAX);
|
||||
dev->stb_virt_addr = devm_ioremap(dev->dev, stb_phys_addr, dev->dram_size);
|
||||
if (!dev->stb_virt_addr)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -1001,7 +1076,7 @@ static int amd_pmc_probe(struct platform_device *pdev)
|
||||
|
||||
mutex_init(&dev->lock);
|
||||
|
||||
if (enable_stb && (dev->cpu_id == AMD_CPU_ID_YC || dev->cpu_id == AMD_CPU_ID_CB)) {
|
||||
if (enable_stb && amd_pmc_is_stb_supported(dev)) {
|
||||
err = amd_pmc_s2d_init(dev);
|
||||
if (err)
|
||||
goto err_pci_dev_put;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user