Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

Pull x86 platform drivers updates from Ilpo Järvinen:
"The changes are mostly business as usual. Besides pdx86 changes, there
are a few power supply changes needed for related pdx86 features, move
of oxpec driver from hwmon (oxp-sensors) to pdx86, and one FW version
warning to hid-asus.

Highlights:

- alienware-wmi-wmax:
- Add HWMON support
- Add ABI and admin-guide documentation
- Expose GPIO debug methods through debug FS
- Support manual fan control and "custom" thermal profile

- amd/hsmp:
- Add sysfs files to show HSMP telemetry
- Report power readings and limits via hwmon

- amd/isp4: Add AMD ISP platform config for OV05C10

- asus-wmi:
- Refactor Ally suspend/resume to work better with older FW
- hid-asus: check ROG Ally MCU version and warn about old FW versions

- dasharo-acpi:
- Add driver for Dasharo devices supporting fans and temperatures
monitoring

- dell-ddv:
- Expose the battery health and manufacture date to userspace
using power supply extensions
- Implement the battery matching algorithm

- dell-pc:
- Improve error propagation
- Use faux device

- int3472:
- Add delays to avoid GPIO regulator spikes
- Add handshake pin support
- Make regulator supply name configurable and allow registering
more than 1 GPIO regulator
- Map mt9m114 powerdown pin to powerenable

- intel/pmc: Add separate SSRAM Telemetry driver

- intel-uncore-freq: Add attributes to show agent types and die ID

- ISST:
- Support SST-TF revision 2 (allows more cores per bucket)
- Support SST-PP revision 2 (fabric 1 frequencies)
- Remove unnecessary SST MSRs restore (the package retains MSRs
despite CPU offlining)

- mellanox: Add support for SN2201, SN4280, SN5610, and SN5640

- mellanox: mlxbf-pmc: Support additional PMC blocks

- oxpec:
- Add OneXFly variants
- Add support for charge limit, charge thresholds, and turbo LED
- Distinguish current X1 variants to avoid unwanted matching to
new variants
- Follow hwmon conventions
- Move from hwmon/oxp-sensors to platform/x86 to match the
enlarged scope

- power supply:
- Add inhibit-charge-awake (needed by oxpec)
- Add additional battery health status values ("blown fuse" and
"cell imbalance") (needed by dell-ddv)

- powerwell-ec: Add driver for Portwell EC supporting GPIO and watchdog

- thinkpad-acpi: Support camera shutter switch hotkey

- tuxedo: Add virtual LampArray for TUXEDO NB04 devices

- tools/power/x86/intel-speed-select:
- Support displaying SST-PP revision 2 fields
- Skip uncore frequency update on newer generations of CPUs

- Miscellaneous cleanups / refactoring / improvements"

* tag 'platform-drivers-x86-v6.16-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (112 commits)
thermal/drivers/acerhdf: Constify struct thermal_zone_device_ops
platform/x86/amd/hsmp: fix building with CONFIG_HWMON=m
platform/x86: asus-wmi: fix build without CONFIG_SUSPEND
docs: ABI: Fix "aassociated" to "associated"
platform/x86: Add AMD ISP platform config for OV05C10
Documentation: admin-guide: pm: Add documentation for die_id
platform/x86/intel-uncore-freq: Add attributes to show die_id
platform/x86/intel: power-domains: Add interface to get Linux die ID
Documentation: admin-guide: pm: Add documentation for agent_types
platform/x86/intel-uncore-freq: Add attributes to show agent types
platform/x86/tuxedo: Prevent invalid Kconfig state
platform/x86: dell-ddv: Expose the battery health to userspace
platform/x86: dell-ddv: Expose the battery manufacture date to userspace
platform/x86: dell-ddv: Implement the battery matching algorithm
power: supply: core: Add additional health status values
platform/x86/amd/hsmp: acpi: Add sysfs files to display HSMP telemetry
platform/x86/amd/hsmp: Report power via hwmon sensors
platform/x86/amd/hsmp: Use a single DRIVER_VERSION for all hsmp modules
platform/mellanox: mlxreg-dpu: Fix smatch warnings
platform: mellanox: nvsw-sn2200: Fix .items in nvsw_sn2201_busbar_hotplug
...

+9273 -2167
+98
Documentation/ABI/stable/sysfs-driver-mlxreg-io
··· 715 715 switch board. 716 716 717 717 The file is read only. 718 + 719 + What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/global_wp_request 720 + Date: May 2025 721 + KernelVersion: 6.16 722 + Contact: Vadim Pasternak <vadimp@nvidia.com> 723 + Description: This file when written 1 activates request to allow access to 724 + the write protected flashes. Such request can be performed only 725 + for system equipped with BMC (Board Management Controller), 726 + which can grant access to protected flashes. In case BMC allows 727 + access - it will respond with "global_wp_response". BMC decides 728 + regarding time window of granted access. After granted window is 729 + expired, BMC will change value back to 0. 730 + Default value is 0. 731 + 732 + The file is read/write. 733 + 734 + What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/global_wp_response 735 + Date: May 2025 736 + KernelVersion: 6.16 737 + Contact: Vadim Pasternak <vadimp@nvidia.com> 738 + Description: This file, when set 1, indicates that access to protected 739 + flashes have been granted to host CPU by BMC. 740 + Default value is 0. 741 + 742 + The file is read only. 743 + 744 + What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/shutdown_unlock 745 + Date: May 2025 746 + KernelVersion: 6.16 747 + Contact: Vadim Pasternak <vadimp@nvidia.com> 748 + Description: When ASICs are getting overheated, system protection 749 + hardware mechanism enforces system reboot. After system 750 + reboot ASICs come up in locked state. To unlock ASICs, 751 + this file should be written 1 752 + Default value is 0. 753 + 754 + The file is read/write. 755 + 756 + What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/*-00**/mlxreg-io.*/hwmon/hwmon*/boot_progress 757 + Date: May 2025 758 + KernelVersion: 6.16 759 + Contact: Vadim Pasternak <vadimp@nvidia.com> 760 + Description: These files show the Data Process Unit board boot progress 761 + state. Valid states are: 762 + - 4 : OS starting. 763 + - 5 : OS running. 764 + - 6 : Low-Power Standby. 765 + 766 + The file is read only. 767 + 768 + What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/*-00**/mlxreg-io.*/hwmon/hwmon*/dpu_id 769 + Date: May 2025 770 + KernelVersion: 6.16 771 + Contact: Vadim Pasternak <vadimp@nvidia.com> 772 + Description: This file shows hardware Id of Data Process Unit board. 773 + 774 + The file is read only. 775 + 776 + What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/*-00**/mlxreg-io.*/hwmon/hwmon*/reset_aux_pwr_or_reload 777 + What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/*-00**/mlxreg-io.*/hwmon/hwmon*/reset_dpu_thermal 778 + What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/*-00**/mlxreg-io.*/hwmon/hwmon*/reset_from_main_board 779 + Date: May 2025 780 + KernelVersion: 6.16 781 + Contact: Vadim Pasternak <vadimp@nvidia.com> 782 + Description: These files expose the cause of the most recent reset of the Data 783 + Processing Unit (DPU) board. The possible causes are: 784 + - Power auxiliary outage or power reload. 785 + - Thermal shutdown. 786 + - Reset request from the main board. 787 + Value 1 in file means this is reset cause, 0 - otherwise. Only one of 788 + the above causes could be 1 at the same time, representing only last 789 + reset cause. 790 + 791 + The files are read only. 792 + 793 + What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/*-00**/mlxreg-io.*/hwmon/hwmon*/perst_rst 794 + What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/*-00**/mlxreg-io.*/hwmon/hwmon*/phy_rst 795 + What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/*-00**/mlxreg-io.*/hwmon/hwmon*/tpm_rst 796 + What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/*-00**/mlxreg-io.*/hwmon/hwmon*/usbphy_rst 797 + Date: May 2025 798 + KernelVersion: 6.16 799 + Contact: Vadim Pasternak <vadimp@nvidia.com> 800 + Description: These files allow to reset hardware components of Data Process 801 + Unit board. Respectively PCI, Ethernet PHY, TPM and USB PHY 802 + resets. 803 + Default values for all the attributes is 1. Writing 0 will 804 + cause reset of the related component. 805 + 806 + The files are read/write. 807 + 808 + What: /sys/devices/platform/mlxplat/i2c_mlxcpld.*/i2c-*/i2c-*/*-00**/mlxreg-io.*/hwmon/hwmon*/ufm_upgrade 809 + Date: May 2025 810 + KernelVersion: 6.16 811 + Contact: Vadim Pasternak <vadimp@nvidia.com> 812 + Description: These files show status of Unified Fabric Manager upgrade. 813 + state. 0 - means upgrade is done, 1 - otherwise. 814 + 815 + The file is read only.
+64
Documentation/ABI/testing/debugfs-alienware-wmi
··· 1 + What: /sys/kernel/debug/alienware-wmi-<wmi_device_name>/system_description 2 + Date: March 2025 3 + KernelVersion: 6.15 4 + Contact: Kurt Borja <kuurtb@gmail.com> 5 + Description: 6 + This file exposes the raw ``system_description`` number reported 7 + by the WMAX device. 8 + 9 + Only present on devices with the AWCC interface. 10 + 11 + See Documentation/admin-guide/laptops/alienware-wmi.rst for 12 + details. 13 + 14 + RO 15 + 16 + What: /sys/kernel/debug/alienware-wmi-<wmi_device_name>/hwmon_data 17 + Date: March 2025 18 + KernelVersion: 6.15 19 + Contact: Kurt Borja <kuurtb@gmail.com> 20 + Description: 21 + This file exposes HWMON private data. 22 + 23 + Includes fan sensor count, temperature sensor count, internal 24 + fan IDs and internal temp IDs. 25 + 26 + See Documentation/admin-guide/laptops/alienware-wmi.rst for 27 + details. 28 + 29 + RO 30 + 31 + What: /sys/kernel/debug/alienware-wmi-<wmi_device_name>/pprof_data 32 + Date: March 2025 33 + KernelVersion: 6.15 34 + Contact: Kurt Borja <kuurtb@gmail.com> 35 + Description: 36 + This file exposes Platform Profile private data. 37 + 38 + Includes internal mapping to platform profiles and thermal 39 + profile IDs. 40 + 41 + See Documentation/admin-guide/laptops/alienware-wmi.rst for 42 + details. 43 + 44 + RO 45 + 46 + What: /sys/kernel/debug/alienware-wmi-<wmi_device_name>/gpio_ctl/total_gpios 47 + Date: May 2025 48 + KernelVersion: 6.16 49 + Contact: Kurt Borja <kuurtb@gmail.com> 50 + Description: 51 + Total number of GPIO pins reported by the device. 52 + 53 + RO 54 + 55 + What: /sys/kernel/debug/alienware-wmi-<wmi_device_name>/gpio_ctl/pinX 56 + Date: May 2025 57 + KernelVersion: 6.16 58 + Contact: Kurt Borja <kuurtb@gmail.com> 59 + Description: 60 + This file controls GPIO pin X status. 61 + 62 + See Documentation/wmi/devices/alienware-wmi.rst for details. 63 + 64 + RW
+1 -1
Documentation/ABI/testing/sysfs-bus-wmi
··· 76 76 Contact: Darren Hart (VMware) <dvhart@infradead.org> 77 77 Description: 78 78 This file contains a boolean flags signaling the data block 79 - aassociated with the given WMI device is writable. If the 79 + associated with the given WMI device is writable. If the 80 80 given WMI device is not associated with a data block, then 81 81 this file will not exist.
+7 -6
Documentation/ABI/testing/sysfs-class-power
··· 456 456 "Over voltage", "Under voltage", "Unspecified failure", "Cold", 457 457 "Watchdog timer expire", "Safety timer expire", 458 458 "Over current", "Calibration required", "Warm", 459 - "Cool", "Hot", "No battery" 459 + "Cool", "Hot", "No battery", "Blown fuse", "Cell imbalance" 460 460 461 461 What: /sys/class/power_supply/<supply_name>/precharge_current 462 462 Date: June 2017 ··· 508 508 Access: Read, Write 509 509 510 510 Valid values: 511 - ================ ==================================== 512 - auto: Charge normally, respect thresholds 513 - inhibit-charge: Do not charge while AC is attached 514 - force-discharge: Force discharge while AC is attached 515 - ================ ==================================== 511 + ===================== ======================================== 512 + auto: Charge normally, respect thresholds 513 + inhibit-charge: Do not charge while AC is attached 514 + inhibit-charge-awake: inhibit-charge only when device is awake 515 + force-discharge: Force discharge while AC is attached 516 + ===================== ======================================== 516 517 517 518 What: /sys/class/power_supply/<supply_name>/technology 518 519 Date: May 2007
+14
Documentation/ABI/testing/sysfs-platform-alienware-wmi
··· 1 + What: /sys/class/hwmon/hwmonX/fanY_boost 2 + Date: March 2025 3 + KernelVersion: 6.15 4 + Contact: Kurt Borja <kuurtb@gmail.com> 5 + Description: 6 + This file exposes fan boost control for Dell gaming laptops with 7 + the AWCC WMI interface. 8 + 9 + See Documentation/admin-guide/laptops/alienware-wmi.rst for 10 + details. 11 + 12 + Integer value in the range 0 to 255 13 + 14 + RW
+25
Documentation/ABI/testing/sysfs-platform-oxp
··· 1 + What: /sys/devices/platform/<platform>/tt_toggle 2 + Date: Jun 2023 3 + KernelVersion: 6.5 4 + Contact: "Antheas Kapenekakis" <lkml@antheas.dev> 5 + Description: 6 + Takeover TDP controls from the device. OneXPlayer devices have a 7 + turbo button that can be used to switch between two TDP modes 8 + (usually 15W and 25W). By setting this attribute to 1, this 9 + functionality is disabled, handing TDP control over to (Windows) 10 + userspace software and the Turbo button turns into a keyboard 11 + shortcut over the AT keyboard of the device. In addition, 12 + using this setting is a prerequisite for PWM control for most 13 + newer models (otherwise it NOOPs). 14 + 15 + What: /sys/devices/platform/<platform>/tt_led 16 + Date: April 2025 17 + KernelVersion: 6.16 18 + Contact: "Antheas Kapenekakis" <lkml@antheas.dev> 19 + Description: 20 + Some OneXPlayer devices (e.g., X1 series) feature a little LED 21 + nested in the Turbo button. This LED is illuminated when the 22 + device is in the higher TDP mode (e.g., 25W). Once tt_toggle 23 + is engaged, this LED is left dangling to its last state. This 24 + attribute allows userspace to control the LED state manually 25 + (either with 1 or 0). Only a subset of devices contain this LED.
+127
Documentation/admin-guide/laptops/alienware-wmi.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0-or-later 2 + 3 + ==================== 4 + Alienware WMI Driver 5 + ==================== 6 + 7 + Kurt Borja <kuurtb@gmail.com> 8 + 9 + This is a driver for the "WMAX" WMI device, which is found in most Dell gaming 10 + laptops and controls various special features. 11 + 12 + Before the launch of M-Series laptops (~2018), the "WMAX" device controlled 13 + basic RGB lighting, deep sleep mode, HDMI mode and amplifier status. 14 + 15 + Later, this device was completely repurpused. Now it mostly deals with thermal 16 + profiles, sensor monitoring and overclocking. This interface is named "AWCC" and 17 + is known to be used by the AWCC OEM application to control these features. 18 + 19 + The alienware-wmi driver controls both interfaces. 20 + 21 + AWCC Interface 22 + ============== 23 + 24 + WMI device documentation: Documentation/wmi/devices/alienware-wmi.rst 25 + 26 + Supported devices 27 + ----------------- 28 + 29 + - Alienware M-Series laptops 30 + - Alienware X-Series laptops 31 + - Alienware Aurora Desktops 32 + - Dell G-Series laptops 33 + 34 + If you believe your device supports the AWCC interface and you don't have any of 35 + the features described in this document, try the following alienware-wmi module 36 + parameters: 37 + 38 + - ``force_platform_profile=1``: Forces probing for platform profile support 39 + - ``force_hwmon=1``: Forces probing for HWMON support 40 + 41 + If the module loads successfully with these parameters, consider submitting a 42 + patch adding your model to the ``awcc_dmi_table`` located in 43 + ``drivers/platform/x86/dell/alienware-wmi-wmax.c`` or contacting the maintainer 44 + for further guidance. 45 + 46 + Status 47 + ------ 48 + 49 + The following features are currently supported: 50 + 51 + - :ref:`Platform Profile <platform-profile>`: 52 + 53 + - Thermal profile control 54 + 55 + - G-Mode toggling 56 + 57 + - :ref:`HWMON <hwmon>`: 58 + 59 + - Sensor monitoring 60 + 61 + - Manual fan control 62 + 63 + .. _platform-profile: 64 + 65 + Platform Profile 66 + ---------------- 67 + 68 + The AWCC interface exposes various firmware defined thermal profiles. These are 69 + exposed to user-space through the Platform Profile class interface. Refer to 70 + :ref:`sysfs-class-platform-profile <abi_file_testing_sysfs_class_platform_profile>` 71 + for more information. 72 + 73 + The name of the platform-profile class device exported by this driver is 74 + "alienware-wmi" and it's path can be found with: 75 + 76 + :: 77 + 78 + grep -l "alienware-wmi" /sys/class/platform-profile/platform-profile-*/name | sed 's|/[^/]*$||' 79 + 80 + If the device supports G-Mode, it is also toggled when selecting the 81 + ``performance`` profile. 82 + 83 + .. note:: 84 + You may set the ``force_gmode`` module parameter to always try to toggle this 85 + feature, without checking if your model supports it. 86 + 87 + .. _hwmon: 88 + 89 + HWMON 90 + ----- 91 + 92 + The AWCC interface also supports sensor monitoring and manual fan control. Both 93 + of these features are exposed to user-space through the HWMON interface. 94 + 95 + The name of the hwmon class device exported by this driver is "alienware_wmi" 96 + and it's path can be found with: 97 + 98 + :: 99 + 100 + grep -l "alienware_wmi" /sys/class/hwmon/hwmon*/name | sed 's|/[^/]*$||' 101 + 102 + Sensor monitoring is done through the standard HWMON interface. Refer to 103 + :ref:`sysfs-class-hwmon <abi_file_testing_sysfs_class_hwmon>` for more 104 + information. 105 + 106 + Manual fan control on the other hand, is not exposed directly by the AWCC 107 + interface. Instead it let's us control a fan `boost` value. This `boost` value 108 + has the following aproximate behavior over the fan pwm: 109 + 110 + :: 111 + 112 + pwm = pwm_base + (fan_boost / 255) * (pwm_max - pwm_base) 113 + 114 + Due to the above behavior, the fan `boost` control is exposed to user-space 115 + through the following, custom hwmon sysfs attribute: 116 + 117 + =============================== ======= ======================================= 118 + Name Perm Description 119 + =============================== ======= ======================================= 120 + fan[1-4]_boost RW Fan boost value. 121 + 122 + Integer value between 0 and 255 123 + =============================== ======= ======================================= 124 + 125 + .. note:: 126 + In some devices, manual fan control only works reliably if the ``custom`` 127 + platform profile is selected.
+1
Documentation/admin-guide/laptops/index.rst
··· 7 7 .. toctree:: 8 8 :maxdepth: 1 9 9 10 + alienware-wmi 10 11 asus-laptop 11 12 disk-shock-protection 12 13 laptop-mode
+10
Documentation/admin-guide/pm/intel_uncore_frequency_scaling.rst
··· 91 91 ``domain_id`` 92 92 This attribute is used to get the power domain id of this instance. 93 93 94 + ``die_id`` 95 + This attribute is used to get the Linux die id of this instance. 96 + This attribute is only present for domains with core agents and 97 + when the CPUID leaf 0x1f presents die ID. 98 + 94 99 ``fabric_cluster_id`` 95 100 This attribute is used to get the fabric cluster id of this instance. 96 101 97 102 ``package_id`` 98 103 This attribute is used to get the package id of this instance. 104 + 105 + ``agent_types`` 106 + This attribute displays all the hardware agents present within the 107 + domain. Each agent has the capability to control one or more hardware 108 + subsystems, which include: core, cache, memory, and I/O. 99 109 100 110 The other attributes are same as presented at package_*_die_* level. 101 111
+30
Documentation/arch/x86/amd_hsmp.rst
··· 71 71 Metrics table definitions will be documented as part of Public PPR. 72 72 The same is defined in the amd_hsmp.h header. 73 73 74 + 2. HSMP telemetry sysfs files 75 + 76 + Following sysfs files are available at /sys/devices/platform/AMDI0097:0X/. 77 + 78 + * c0_residency_input: Percentage of cores in C0 state. 79 + * prochot_status: Reports 1 if the processor is at thermal threshold value, 80 + 0 otherwise. 81 + * smu_fw_version: SMU firmware version. 82 + * protocol_version: HSMP interface version. 83 + * ddr_max_bw: Theoretical maximum DDR bandwidth in GB/s. 84 + * ddr_utilised_bw_input: Current utilized DDR bandwidth in GB/s. 85 + * ddr_utilised_bw_perc_input(%): Percentage of current utilized DDR bandwidth. 86 + * mclk_input: Memory clock in MHz. 87 + * fclk_input: Fabric clock in MHz. 88 + * clk_fmax: Maximum frequency of socket in MHz. 89 + * clk_fmin: Minimum frequency of socket in MHz. 90 + * cclk_freq_limit_input: Core clock frequency limit per socket in MHz. 91 + * pwr_current_active_freq_limit: Current active frequency limit of socket 92 + in MHz. 93 + * pwr_current_active_freq_limit_source: Source of current active frequency 94 + limit. 95 + 74 96 ACPI device object format 75 97 ========================= 76 98 The ACPI object format expected from the amd_hsmp driver ··· 138 116 }) 139 117 } 140 118 119 + HSMP HWMON interface 120 + ==================== 121 + HSMP power sensors are registered with the hwmon interface. A separate hwmon 122 + directory is created for each socket and the following files are generated 123 + within the hwmon directory. 124 + - power1_input (read only) 125 + - power1_cap_max (read only) 126 + - power1_cap (read, write) 141 127 142 128 An example 143 129 ==========
-1
Documentation/hwmon/index.rst
··· 189 189 nzxt-kraken3 190 190 nzxt-smart2 191 191 occ 192 - oxp-sensors 193 192 pc87360 194 193 pc87427 195 194 pcf8591
-89
Documentation/hwmon/oxp-sensors.rst
··· 1 - .. SPDX-License-Identifier: GPL-2.0-or-later 2 - 3 - Kernel driver oxp-sensors 4 - ========================= 5 - 6 - Authors: 7 - - Derek John Clark <derekjohn.clark@gmail.com> 8 - - Joaquín Ignacio Aramendía <samsagax@gmail.com> 9 - 10 - Description: 11 - ------------ 12 - 13 - Handheld devices from OneNetbook, AOKZOE, AYANEO, And OrangePi provide fan 14 - readings and fan control through their embedded controllers. 15 - 16 - Currently supports OneXPlayer devices, AOKZOE, AYANEO, and OrangePi 17 - handheld devices. AYANEO devices preceding the AIR and OneXPlayer devices 18 - preceding the Mini A07 are not supportable as the EC model is different 19 - and do not have manual control capabilities. 20 - 21 - Some OneXPlayer and AOKZOE models have a toggle for changing the behaviour 22 - of the "Turbo/Silent" button of the device. It will change the key event 23 - that it triggers with a flip of the `tt_toggle` attribute. See below for 24 - boards that support this function. 25 - 26 - Supported devices 27 - ----------------- 28 - 29 - Currently the driver supports the following handhelds: 30 - 31 - - AOKZOE A1 32 - - AOKZOE A1 PRO 33 - - AYANEO 2 34 - - AYANEO 2S 35 - - AYANEO AIR 36 - - AYANEO AIR 1S 37 - - AYANEO AIR Plus (Mendocino) 38 - - AYANEO AIR Pro 39 - - AYANEO Flip DS 40 - - AYANEO Flip KB 41 - - AYANEO Geek 42 - - AYANEO Geek 1S 43 - - AYANEO KUN 44 - - OneXPlayer 2 45 - - OneXPlayer 2 Pro 46 - - OneXPlayer AMD 47 - - OneXPlayer mini AMD 48 - - OneXPlayer mini AMD PRO 49 - - OneXPlayer OneXFly 50 - - OneXPlayer X1 A 51 - - OneXPlayer X1 i 52 - - OneXPlayer X1 mini 53 - - OrangePi NEO-01 54 - 55 - "Turbo/Silent" button behaviour toggle is only supported on: 56 - - AOK ZOE A1 57 - - AOK ZOE A1 PRO 58 - - OneXPlayer 2 59 - - OneXPlayer 2 Pro 60 - - OneXPlayer mini AMD (only with updated alpha BIOS) 61 - - OneXPlayer mini AMD PRO 62 - - OneXPlayer OneXFly 63 - - OneXPlayer X1 A 64 - - OneXPlayer X1 i 65 - - OneXPlayer X1 mini 66 - 67 - Sysfs entries 68 - ------------- 69 - 70 - The following attributes are supported: 71 - 72 - fan1_input 73 - Read Only. Reads current fan RPM. 74 - 75 - pwm1_enable 76 - Read Write. Enable manual fan control. Write "1" to set to manual, write "0" 77 - to let the EC control de fan speed. Read this attribute to see current status. 78 - 79 - pwm1 80 - Read Write. Read this attribute to see current duty cycle in the range [0-255]. 81 - When pwm1_enable is set to "1" (manual) write any value in the range [0-255] 82 - to set fan speed. 83 - 84 - tt_toggle 85 - Read Write. Read this attribute to check the status of the turbo/silent 86 - button behaviour function. Write "1" to activate the switch and "0" to 87 - deactivate it. The specific keycodes and behaviour is specific to the device 88 - both with this function on and off. This attribute is attached to the platform 89 - driver and not to the hwmon driver (/sys/devices/platform/oxp-platform/tt_toggle)
+173 -248
Documentation/wmi/devices/alienware-wmi.rst
··· 11 11 models. Throughout these models, two implementations have been identified. The 12 12 first one, used by older systems, deals with HDMI, brightness, RGB, amplifier 13 13 and deep sleep control. The second one used by newer systems deals primarily 14 - with thermal, overclocking, and GPIO control. 14 + with thermal control and overclocking. 15 15 16 16 It is suspected that the latter is used by Alienware Command Center (AWCC) to 17 17 manage manufacturer predefined thermal profiles. The alienware-wmi driver ··· 69 69 [WmiMethodId(164), Implemented, read, write, Description("Tobii Camera Power Off.")] void TobiiCameraPowerOff([out] uint32 argr); 70 70 }; 71 71 72 - Some of these methods get quite intricate so we will describe them using 73 - pseudo-code that vaguely resembles the original ASL code. 74 - 75 72 Methods not described in the following document have unknown behavior. 76 73 77 74 Argument Structure ··· 84 87 Thermal Methods 85 88 =============== 86 89 90 + WMI method GetFanSensors([in] uint32 arg2, [out] uint32 argr) 91 + ------------------------------------------------------------- 92 + 93 + +--------------------+------------------------------------+--------------------+ 94 + | Operation (Byte 0) | Description | Arguments | 95 + +====================+====================================+====================+ 96 + | 0x01 | Get the number of temperature | - Byte 1: Fan ID | 97 + | | sensors related with a fan ID | | 98 + +--------------------+------------------------------------+--------------------+ 99 + | 0x02 | Get the temperature sensor IDs | - Byte 1: Fan ID | 100 + | | related to a fan sensor ID | - Byte 2: Index | 101 + +--------------------+------------------------------------+--------------------+ 102 + 87 103 WMI method Thermal_Information([in] uint32 arg2, [out] uint32 argr) 88 104 ------------------------------------------------------------------- 89 105 90 - :: 91 - 92 - if BYTE_0(arg2) == 0x01: 93 - argr = 1 94 - 95 - if BYTE_0(arg2) == 0x02: 96 - argr = SYSTEM_DESCRIPTION 97 - 98 - if BYTE_0(arg2) == 0x03: 99 - if BYTE_1(arg2) == 0x00: 100 - argr = FAN_ID_0 101 - 102 - if BYTE_1(arg2) == 0x01: 103 - argr = FAN_ID_1 104 - 105 - if BYTE_1(arg2) == 0x02: 106 - argr = FAN_ID_2 107 - 108 - if BYTE_1(arg2) == 0x03: 109 - argr = FAN_ID_3 110 - 111 - if BYTE_1(arg2) == 0x04: 112 - argr = SENSOR_ID_CPU | 0x0100 113 - 114 - if BYTE_1(arg2) == 0x05: 115 - argr = SENSOR_ID_GPU | 0x0100 116 - 117 - if BYTE_1(arg2) == 0x06: 118 - argr = THERMAL_MODE_QUIET_ID 119 - 120 - if BYTE_1(arg2) == 0x07: 121 - argr = THERMAL_MODE_BALANCED_ID 122 - 123 - if BYTE_1(arg2) == 0x08: 124 - argr = THERMAL_MODE_BALANCED_PERFORMANCE_ID 125 - 126 - if BYTE_1(arg2) == 0x09: 127 - argr = THERMAL_MODE_PERFORMANCE_ID 128 - 129 - if BYTE_1(arg2) == 0x0A: 130 - argr = THERMAL_MODE_LOW_POWER_ID 131 - 132 - if BYTE_1(arg2) == 0x0B: 133 - argr = THERMAL_MODE_GMODE_ID 134 - 135 - else: 136 - argr = 0xFFFFFFFF 137 - 138 - if BYTE_0(arg2) == 0x04: 139 - if is_valid_sensor(BYTE_1(arg2)): 140 - argr = SENSOR_TEMP_C 141 - else: 142 - argr = 0xFFFFFFFF 143 - 144 - if BYTE_0(arg2) == 0x05: 145 - if is_valid_fan(BYTE_1(arg2)): 146 - argr = FAN_RPM() 147 - 148 - if BYTE_0(arg2) == 0x06: 149 - skip 150 - 151 - if BYTE_0(arg2) == 0x07: 152 - argr = 0 153 - 154 - If BYTE_0(arg2) == 0x08: 155 - if is_valid_fan(BYTE_1(arg2)): 156 - argr = 0 157 - else: 158 - argr = 0xFFFFFFFF 159 - 160 - if BYTE_0(arg2) == 0x09: 161 - if is_valid_fan(BYTE_1(arg2)): 162 - argr = FAN_UNKNOWN_STAT_0() 163 - 164 - else: 165 - argr = 0xFFFFFFFF 166 - 167 - if BYTE_0(arg2) == 0x0A: 168 - argr = THERMAL_MODE_BALANCED_ID 169 - 170 - if BYTE_0(arg2) == 0x0B: 171 - argr = CURRENT_THERMAL_MODE() 172 - 173 - if BYTE_0(arg2) == 0x0C: 174 - if is_valid_fan(BYTE_1(arg2)): 175 - argr = FAN_UNKNOWN_STAT_1() 176 - else: 177 - argr = 0xFFFFFFFF 178 - 179 - Operation 0x02 returns a *system description* buffer with the following 180 - structure: 181 - 182 - :: 183 - 184 - out[0] -> Number of fans 185 - out[1] -> Number of sensors 186 - out[2] -> 0x00 187 - out[3] -> Number of thermal modes 188 - 189 - Operation 0x03 list all available fan IDs, sensor IDs and thermal profile 190 - codes in order, but different models may have different number of fans and 191 - thermal profiles. These are the known ranges: 192 - 193 - * Fan IDs: from 2 up to 4 194 - * Sensor IDs: 2 195 - * Thermal profile codes: from 1 up to 7 196 - 197 - In total BYTE_1(ARG2) may range from 0x5 up to 0xD depending on the model. 106 + +--------------------+------------------------------------+--------------------+ 107 + | Operation (Byte 0) | Description | Arguments | 108 + +====================+====================================+====================+ 109 + | 0x01 | Unknown. | - None | 110 + +--------------------+------------------------------------+--------------------+ 111 + | 0x02 | Get system description number with | - None | 112 + | | the following structure: | | 113 + | | | | 114 + | | - Byte 0: Number of fans | | 115 + | | - Byte 1: Number of temperature | | 116 + | | sensors | | 117 + | | - Byte 2: Unknown | | 118 + | | - Byte 3: Number of thermal | | 119 + | | profiles | | 120 + +--------------------+------------------------------------+--------------------+ 121 + | 0x03 | List an ID or resource at a given | - Byte 1: Index | 122 + | | index. Fan IDs, temperature IDs, | | 123 + | | unknown IDs and thermal profile | | 124 + | | IDs are listed in that exact | | 125 + | | order. | | 126 + | | | | 127 + | | Operation 0x02 is used to know | | 128 + | | which indexes map to which | | 129 + | | resources. | | 130 + | | | | 131 + | | **Returns:** ID at a given index | | 132 + +--------------------+------------------------------------+--------------------+ 133 + | 0x04 | Get the current temperature for a | - Byte 1: Sensor | 134 + | | given temperature sensor. | ID | 135 + +--------------------+------------------------------------+--------------------+ 136 + | 0x05 | Get the current RPM for a given | - Byte 1: Fan ID | 137 + | | fan. | | 138 + +--------------------+------------------------------------+--------------------+ 139 + | 0x06 | Get fan speed percentage. (not | - Byte 1: Fan ID | 140 + | | implemented in every model) | | 141 + +--------------------+------------------------------------+--------------------+ 142 + | 0x07 | Unknown. | - Unknown | 143 + +--------------------+------------------------------------+--------------------+ 144 + | 0x08 | Get minimum RPM for a given FAN | - Byte 1: Fan ID | 145 + | | ID. | | 146 + +--------------------+------------------------------------+--------------------+ 147 + | 0x09 | Get maximum RPM for a given FAN | - Byte 1: Fan ID | 148 + | | ID. | | 149 + +--------------------+------------------------------------+--------------------+ 150 + | 0x0A | Get balanced thermal profile ID. | - None | 151 + +--------------------+------------------------------------+--------------------+ 152 + | 0x0B | Get current thermal profile ID. | - None | 153 + +--------------------+------------------------------------+--------------------+ 154 + | 0x0C | Get current `boost` value for a | - Byte 1: Fan ID | 155 + | | given fan ID. | | 156 + +--------------------+------------------------------------+--------------------+ 198 157 199 158 WMI method Thermal_Control([in] uint32 arg2, [out] uint32 argr) 200 159 --------------------------------------------------------------- 201 160 202 - :: 203 - 204 - if BYTE_0(arg2) == 0x01: 205 - if is_valid_thermal_profile(BYTE_1(arg2)): 206 - SET_THERMAL_PROFILE(BYTE_1(arg2)) 207 - argr = 0 208 - 209 - if BYTE_0(arg2) == 0x02: 210 - if is_valid_fan(BYTE_1(arg2)): 211 - SET_FAN_SPEED_MULTIPLIER(BYTE_2(arg2)) 212 - argr = 0 213 - else: 214 - argr = 0xFFFFFFFF 215 - 216 - .. note:: 217 - While you can manually change the fan speed multiplier with this method, 218 - Dell's BIOS tends to overwrite this changes anyway. 161 + +--------------------+------------------------------------+--------------------+ 162 + | Operation (Byte 0) | Description | Arguments | 163 + +====================+====================================+====================+ 164 + | 0x01 | Activate a given thermal profile. | - Byte 1: Thermal | 165 + | | | profile ID | 166 + +--------------------+------------------------------------+--------------------+ 167 + | 0x02 | Set a `boost` value for a given | - Byte 1: Fan ID | 168 + | | fan ID. | - Byte 2: Boost | 169 + +--------------------+------------------------------------+--------------------+ 219 170 220 171 These are the known thermal profile codes: 221 172 222 - :: 173 + +------------------------------+----------+------+ 174 + | Thermal Profile | Type | ID | 175 + +==============================+==========+======+ 176 + | Custom | Special | 0x00 | 177 + +------------------------------+----------+------+ 178 + | G-Mode | Special | 0xAB | 179 + +------------------------------+----------+------+ 180 + | Quiet | Legacy | 0x96 | 181 + +------------------------------+----------+------+ 182 + | Balanced | Legacy | 0x97 | 183 + +------------------------------+----------+------+ 184 + | Balanced Performance | Legacy | 0x98 | 185 + +------------------------------+----------+------+ 186 + | Performance | Legacy | 0x99 | 187 + +------------------------------+----------+------+ 188 + | Balanced | USTT | 0xA0 | 189 + +------------------------------+----------+------+ 190 + | Balanced Performance | USTT | 0xA1 | 191 + +------------------------------+----------+------+ 192 + | Cool | USTT | 0xA2 | 193 + +------------------------------+----------+------+ 194 + | Quiet | USTT | 0xA3 | 195 + +------------------------------+----------+------+ 196 + | Performance | USTT | 0xA4 | 197 + +------------------------------+----------+------+ 198 + | Low Power | USTT | 0xA5 | 199 + +------------------------------+----------+------+ 223 200 224 - CUSTOM 0x00 201 + If a model supports the User Selectable Thermal Tables (USTT) profiles, it will 202 + not support the Legacy profiles and vice-versa. 225 203 226 - BALANCED_USTT 0xA0 227 - BALANCED_PERFORMANCE_USTT 0xA1 228 - COOL_USTT 0xA2 229 - QUIET_USTT 0xA3 230 - PERFORMANCE_USTT 0xA4 231 - LOW_POWER_USTT 0xA5 232 - 233 - QUIET 0x96 234 - BALANCED 0x97 235 - BALANCED_PERFORMANCE 0x98 236 - PERFORMANCE 0x99 237 - 238 - GMODE 0xAB 239 - 240 - Usually if a model doesn't support the first four profiles they will support 241 - the User Selectable Thermal Tables (USTT) profiles and vice-versa. 242 - 243 - GMODE replaces PERFORMANCE in G-Series laptops. 204 + Every model supports the CUSTOM (0x00) thermal profile. GMODE replaces 205 + PERFORMANCE in G-Series laptops. 244 206 245 207 WMI method GameShiftStatus([in] uint32 arg2, [out] uint32 argr) 246 208 --------------------------------------------------------------- 247 209 248 - :: 249 - 250 - if BYTE_0(arg2) == 0x1: 251 - TOGGLE_GAME_SHIFT() 252 - argr = GET_GAME_SHIFT_STATUS() 253 - 254 - if BYTE_0(arg2) == 0x2: 255 - argr = GET_GAME_SHIFT_STATUS() 210 + +--------------------+------------------------------------+--------------------+ 211 + | Operation (Byte 0) | Description | Arguments | 212 + +====================+====================================+====================+ 213 + | 0x01 | Toggle *Game Shift*. | - None | 214 + +--------------------+------------------------------------+--------------------+ 215 + | 0x02 | Get *Game Shift* status. | - None | 216 + +--------------------+------------------------------------+--------------------+ 256 217 257 218 Game Shift Status does not change the fan speed profile but it could be some 258 219 sort of CPU/GPU power profile. Benchmarks have not been done. ··· 222 267 G-key on Dell's G-Series laptops also changes Game Shift status, so both are 223 268 directly related. 224 269 225 - WMI method GetFanSensors([in] uint32 arg2, [out] uint32 argr) 226 - ------------------------------------------------------------- 227 - 228 - :: 229 - 230 - if BYTE_0(arg2) == 0x1: 231 - if is_valid_fan(BYTE_1(arg2)): 232 - argr = 1 233 - else: 234 - argr = 0 235 - 236 - if BYTE_0(arg2) == 0x2: 237 - if is_valid_fan(BYTE_1(arg2)): 238 - if BYTE_2(arg2) == 0: 239 - argr == SENSOR_ID 240 - else 241 - argr == 0xFFFFFFFF 242 - else: 243 - argr = 0 244 - 245 270 Overclocking Methods 246 271 ==================== 247 - 248 - .. warning:: 249 - These methods have not been tested and are only partially reverse 250 - engineered. 251 - 252 - WMI method Return_OverclockingReport([out] uint32 argr) 253 - ------------------------------------------------------- 254 - 255 - :: 256 - 257 - CSMI (0xE3, 0x99) 258 - argr = 0 259 - 260 - CSMI is an unknown operation. 261 - 262 - WMI method Set_OCUIBIOSControl([in] uint32 arg2, [out] uint32 argr) 263 - ------------------------------------------------------------------- 264 - 265 - :: 266 - 267 - CSMI (0xE3, 0x99) 268 - argr = 0 269 - 270 - CSMI is an unknown operation. 271 - 272 - WMI method Clear_OCFailSafeFlag([out] uint32 argr) 273 - -------------------------------------------------- 274 - 275 - :: 276 - 277 - CSMI (0xE3, 0x99) 278 - argr = 0 279 - 280 - CSMI is an unknown operation. 281 - 282 272 283 273 WMI method MemoryOCControl([in] uint32 arg2, [out] uint32 argr) 284 274 --------------------------------------------------------------- ··· 231 331 AWCC supports memory overclocking, but this method is very intricate and has 232 332 not been deciphered yet. 233 333 234 - GPIO methods 235 - ============ 334 + GPIO control Methods 335 + ==================== 236 336 237 - These methods are probably related to some kind of firmware update system, 238 - through a GPIO device. 337 + Alienware and Dell G Series devices with the AWCC interface usually have an 338 + embedded STM32 RGB lighting controller with USB/HID capabilities. It's vendor ID 339 + is ``187c`` while it's product ID may vary from model to model. 239 340 240 - .. warning:: 241 - These methods have not been tested and are only partially reverse 242 - engineered. 341 + The control of two GPIO pins of this MCU is exposed as WMI methods for debugging 342 + purposes. 343 + 344 + +--------------+--------------------------------------------------------------+ 345 + | Pin | Description | 346 + +==============+===============================+==============================+ 347 + | 0 | Device Firmware Update (DFU) | **HIGH**: Enables DFU mode | 348 + | | mode pin. | on next MCU boot. | 349 + | | +------------------------------+ 350 + | | | **LOW**: Disables DFU mode | 351 + | | | on next MCU boot. | 352 + +--------------+-------------------------------+------------------------------+ 353 + | 1 | Negative Reset (NRST) pin. | **HIGH**: MCU is ON. | 354 + | | | | 355 + | | +------------------------------+ 356 + | | | **LOW**: MCU is OFF. | 357 + | | | | 358 + +--------------+-------------------------------+------------------------------+ 359 + 360 + See :ref:`acknowledgements` for more information on this MCU. 361 + 362 + .. note:: 363 + Some GPIO control methods break the usual argument structure and take a 364 + **Pin number** instead of an operation on the first byte. 243 365 244 366 WMI method FWUpdateGPIOtoggle([in] uint32 arg2, [out] uint32 argr) 245 367 ------------------------------------------------------------------ 246 368 247 - :: 248 - 249 - if BYTE_0(arg2) == 0: 250 - if BYTE_1(arg2) == 1: 251 - SET_PIN_A_HIGH() 252 - else: 253 - SET_PIN_A_LOW() 254 - 255 - if BYTE_0(arg2) == 1: 256 - if BYTE_1(arg2) == 1: 257 - SET_PIN_B_HIGH() 258 - 259 - else: 260 - SET_PIN_B_LOW() 261 - 262 - else: 263 - argr = 1 369 + +--------------------+------------------------------------+--------------------+ 370 + | Operation (Byte 0) | Description | Arguments | 371 + +====================+====================================+====================+ 372 + | Pin number | Set the pin status | - Byte 1: Pin | 373 + | | | status | 374 + +--------------------+------------------------------------+--------------------+ 264 375 265 376 WMI method ReadTotalofGPIOs([out] uint32 argr) 266 377 ---------------------------------------------- 267 378 268 - :: 379 + +--------------------+------------------------------------+--------------------+ 380 + | Operation (Byte 0) | Description | Arguments | 381 + +====================+====================================+====================+ 382 + | N/A | Get the total number of GPIOs | - None | 383 + +--------------------+------------------------------------+--------------------+ 269 384 270 - argr = 0x02 385 + .. note:: 386 + Due to how WMI methods are implemented on the firmware level, this method 387 + requires a dummy uint32 input argument when invoked. 271 388 272 389 WMI method ReadGPIOpPinStatus([in] uint32 arg2, [out] uint32 argr) 273 390 ------------------------------------------------------------------ 274 391 275 - :: 392 + +--------------------+------------------------------------+--------------------+ 393 + | Operation (Byte 0) | Description | Arguments | 394 + +====================+====================================+====================+ 395 + | Pin number | Get the pin status | - None | 396 + +--------------------+------------------------------------+--------------------+ 276 397 277 - if BYTE_0(arg2) == 0: 278 - argr = PIN_A_STATUS 279 - 280 - if BYTE_0(arg2) == 1: 281 - argr = PIN_B_STATUS 398 + .. note:: 399 + There known firmware bug in some laptops where reading the status of a pin 400 + also flips it. 282 401 283 402 Other information Methods 284 403 ========================= ··· 305 386 WMI method ReadChassisColor([out] uint32 argr) 306 387 ---------------------------------------------- 307 388 308 - :: 389 + Returns the chassis color internal ID. 309 390 310 - argr = CHASSIS_COLOR_ID 391 + .. _acknowledgements: 311 392 312 393 Acknowledgements 313 394 ================ 314 395 315 - Kudos to `AlexIII <https://github.com/AlexIII/tcc-g15>`_ for documenting 316 - and testing available thermal profile codes. 396 + Kudos to 397 + 398 + * `AlexIII <https://github.com/AlexIII/tcc-g15>`_ 399 + * `T-Troll <https://github.com/T-Troll/alienfx-tools/>`_ 400 + * `Gabriel Marcano <https://gabriel.marcanobrady.family/blog/2024/12/16/dell-g5-5505-se-acpi-or-figuring-out-how-to-reset-the-rgb-controller/>`_ 401 + 402 + for documenting and testing some of this device's functionality, making it 403 + possible to generalize this driver.
+34 -12
Documentation/wmi/devices/dell-wmi-ddv.rst
··· 118 118 - bits 5 to 8 contain the manufacture month. 119 119 - bits 9 to 15 contain the manufacture year biased by 1980. 120 120 121 - .. note:: 122 - The data format needs to be verified on more machines. 123 - 124 121 WMI method BatterySerialNumber() 125 122 -------------------------------- 126 123 ··· 150 153 WMI method BatteryManufactureAccess() 151 154 ------------------------------------- 152 155 153 - Returns a manufacture-defined value as an u16. 156 + Returns the health status of the battery as a u16. 157 + The health status encoded in the following manner: 158 + 159 + - the third nibble contains the general failure mode 160 + - the fourth nibble contains the specific failure code 161 + 162 + Valid failure modes are: 163 + 164 + - permanent failure (``0x9``) 165 + - overheat failure (``0xa``) 166 + - overcurrent failure (``0xb``) 167 + 168 + All other failure modes are to be considered normal. 169 + 170 + The following failure codes are valid for a permanent failure: 171 + 172 + - fuse blown (``0x0``) 173 + - cell imbalance (``0x1``) 174 + - overvoltage (``0x2``) 175 + - fet failure (``0x3``) 176 + 177 + The last two bits of the failure code are to be ignored when the battery 178 + signals a permanent failure. 179 + 180 + The following failure codes a valid for a overheat failure: 181 + 182 + - overheat at start of charging (``0x5``) 183 + - overheat during charging (``0x7``) 184 + - overheat during discharging (``0x8``) 185 + 186 + The following failure codes are valid for a overcurrent failure: 187 + 188 + - overcurrent during charging (``0x6``) 189 + - overcurrent during discharging (``0xb``) 154 190 155 191 WMI method BatteryRelativeStateOfCharge() 156 192 ----------------------------------------- ··· 289 259 Some machines like the Dell Inspiron 3505 only support a single battery and thus 290 260 ignore the battery index. Because of this the driver depends on the ACPI battery 291 261 hook mechanism to discover batteries. 292 - 293 - .. note:: 294 - The ACPI battery matching algorithm currently used inside the driver is 295 - outdated and does not match the algorithm described above. The reasons for 296 - this are differences in the handling of the ToHexString() ACPI opcode between 297 - Linux and Windows, which distorts the serial number of ACPI batteries on many 298 - machines. Until this issue is resolved, the driver cannot use the above 299 - algorithm. 300 262 301 263 Reverse-Engineering the DDV WMI interface 302 264 =========================================
+26 -4
MAINTAINERS
··· 805 805 L: platform-driver-x86@vger.kernel.org 806 806 L: Dell.Client.Kernel@dell.com 807 807 S: Maintained 808 + F: Documentation/ABI/testing/debugfs-alienware-wmi 809 + F: Documentation/ABI/testing/sysfs-platform-alienware-wmi 810 + F: Documentation/admin-guide/laptops/alienware-wmi.rst 808 811 F: Documentation/wmi/devices/alienware-wmi.rst 809 812 F: drivers/platform/x86/dell/alienware-wmi* 810 813 ··· 6580 6577 F: net/ax25/ax25_out.c 6581 6578 F: net/ax25/ax25_timer.c 6582 6579 F: net/ax25/sysctl_net_ax25.c 6580 + 6581 + DASHARO ACPI PLATFORM DRIVER 6582 + M: Michał Kopeć <michal.kopec@3mdeb.com> 6583 + S: Maintained 6584 + W: https://docs.dasharo.com/ 6585 + F: drivers/platform/x86/dasharo-acpi.c 6583 6586 6584 6587 DATA ACCESS MONITOR 6585 6588 M: SeongJae Park <sj@kernel.org> ··· 12364 12355 M: Daniel Scally <djrscally@gmail.com> 12365 12356 S: Maintained 12366 12357 F: drivers/platform/x86/intel/int3472/ 12358 + F: include/linux/platform_data/x86/int3472.h 12367 12359 12368 12360 INTEL SPEED SELECT TECHNOLOGY 12369 12361 M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> ··· 18357 18347 F: drivers/mtd/nand/onenand/ 18358 18348 F: include/linux/mtd/onenand*.h 18359 18349 18360 - ONEXPLAYER FAN DRIVER 18350 + ONEXPLAYER PLATFORM EC DRIVER 18351 + M: Antheas Kapenekakis <lkml@antheas.dev> 18361 18352 M: Derek John Clark <derekjohn.clark@gmail.com> 18362 18353 M: Joaquín Ignacio Aramendía <samsagax@gmail.com> 18363 - L: linux-hwmon@vger.kernel.org 18354 + L: platform-driver-x86@vger.kernel.org 18364 18355 S: Maintained 18365 - F: drivers/hwmon/oxp-sensors.c 18356 + F: drivers/platform/x86/oxpec.c 18366 18357 18367 18358 ONIE TLV NVMEM LAYOUT DRIVER 18368 18359 M: Miquel Raynal <miquel.raynal@bootlin.com> ··· 19574 19563 S: Maintained 19575 19564 F: drivers/pnp/ 19576 19565 F: include/linux/pnp.h 19566 + 19567 + PORTWELL EC DRIVER 19568 + M: Yen-Chi Huang <jesse.huang@portwell.com.tw> 19569 + L: platform-driver-x86@vger.kernel.org 19570 + S: Maintained 19571 + F: drivers/platform/x86/portwell-ec.c 19577 19572 19578 19573 POSIX CLOCKS and TIMERS 19579 19574 M: Anna-Maria Behnsen <anna-maria@linutronix.de> ··· 22988 22971 F: Documentation/admin-guide/laptops/sony-laptop.rst 22989 22972 F: drivers/char/sonypi.c 22990 22973 F: drivers/platform/x86/sony-laptop.c 22991 - F: include/linux/sony-laptop.h 22992 22974 22993 22975 SOPHGO DEVICETREES and DRIVERS 22994 22976 M: Chen Wang <unicorn_wang@outlook.com> ··· 25059 25043 T: git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git turbostat 25060 25044 F: tools/power/x86/turbostat/ 25061 25045 F: tools/testing/selftests/turbostat/ 25046 + 25047 + TUXEDO DRIVERS 25048 + M: Werner Sembach <wse@tuxedocomputers.com> 25049 + L: platform-driver-x86@vger.kernel.org 25050 + S: Supported 25051 + F: drivers/platform/x86/tuxedo/ 25062 25052 25063 25053 TW5864 VIDEO4LINUX DRIVER 25064 25054 M: Bluecherry Maintainers <maintainers@bluecherrydvr.com>
+109 -2
drivers/hid/hid-asus.c
··· 52 52 #define FEATURE_KBD_LED_REPORT_ID1 0x5d 53 53 #define FEATURE_KBD_LED_REPORT_ID2 0x5e 54 54 55 + #define ROG_ALLY_REPORT_SIZE 64 56 + #define ROG_ALLY_X_MIN_MCU 313 57 + #define ROG_ALLY_MIN_MCU 319 58 + 55 59 #define SUPPORT_KBD_BACKLIGHT BIT(0) 56 60 57 61 #define MAX_TOUCH_MAJOR 8 ··· 88 84 #define QUIRK_MEDION_E1239T BIT(10) 89 85 #define QUIRK_ROG_NKEY_KEYBOARD BIT(11) 90 86 #define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12) 87 + #define QUIRK_ROG_ALLY_XPAD BIT(13) 91 88 92 89 #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ 93 90 QUIRK_NO_INIT_REPORTS | \ ··· 539 534 return !!(value & ASUS_WMI_DSTS_PRESENCE_BIT); 540 535 } 541 536 537 + /* 538 + * We don't care about any other part of the string except the version section. 539 + * Example strings: FGA80100.RC72LA.312_T01, FGA80100.RC71LS.318_T01 540 + * The bytes "5a 05 03 31 00 1a 13" and possibly more come before the version 541 + * string, and there may be additional bytes after the version string such as 542 + * "75 00 74 00 65 00" or a postfix such as "_T01" 543 + */ 544 + static int mcu_parse_version_string(const u8 *response, size_t response_size) 545 + { 546 + const u8 *end = response + response_size; 547 + const u8 *p = response; 548 + int dots, err, version; 549 + char buf[4]; 550 + 551 + dots = 0; 552 + while (p < end && dots < 2) { 553 + if (*p++ == '.') 554 + dots++; 555 + } 556 + 557 + if (dots != 2 || p >= end || (p + 3) >= end) 558 + return -EINVAL; 559 + 560 + memcpy(buf, p, 3); 561 + buf[3] = '\0'; 562 + 563 + err = kstrtoint(buf, 10, &version); 564 + if (err || version < 0) 565 + return -EINVAL; 566 + 567 + return version; 568 + } 569 + 570 + static int mcu_request_version(struct hid_device *hdev) 571 + { 572 + u8 *response __free(kfree) = kzalloc(ROG_ALLY_REPORT_SIZE, GFP_KERNEL); 573 + const u8 request[] = { 0x5a, 0x05, 0x03, 0x31, 0x00, 0x20 }; 574 + int ret; 575 + 576 + if (!response) 577 + return -ENOMEM; 578 + 579 + ret = asus_kbd_set_report(hdev, request, sizeof(request)); 580 + if (ret < 0) 581 + return ret; 582 + 583 + ret = hid_hw_raw_request(hdev, FEATURE_REPORT_ID, response, 584 + ROG_ALLY_REPORT_SIZE, HID_FEATURE_REPORT, 585 + HID_REQ_GET_REPORT); 586 + if (ret < 0) 587 + return ret; 588 + 589 + ret = mcu_parse_version_string(response, ROG_ALLY_REPORT_SIZE); 590 + if (ret < 0) { 591 + pr_err("Failed to parse MCU version: %d\n", ret); 592 + print_hex_dump(KERN_ERR, "MCU: ", DUMP_PREFIX_NONE, 593 + 16, 1, response, ROG_ALLY_REPORT_SIZE, false); 594 + } 595 + 596 + return ret; 597 + } 598 + 599 + static void validate_mcu_fw_version(struct hid_device *hdev, int idProduct) 600 + { 601 + int min_version, version; 602 + 603 + version = mcu_request_version(hdev); 604 + if (version < 0) 605 + return; 606 + 607 + switch (idProduct) { 608 + case USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY: 609 + min_version = ROG_ALLY_MIN_MCU; 610 + break; 611 + case USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X: 612 + min_version = ROG_ALLY_X_MIN_MCU; 613 + break; 614 + default: 615 + min_version = 0; 616 + } 617 + 618 + if (version < min_version) { 619 + hid_warn(hdev, 620 + "The MCU firmware version must be %d or greater to avoid issues with suspend.\n", 621 + min_version); 622 + } else { 623 + set_ally_mcu_hack(ASUS_WMI_ALLY_MCU_HACK_DISABLED); 624 + set_ally_mcu_powersave(true); 625 + } 626 + } 627 + 542 628 static int asus_kbd_register_leds(struct hid_device *hdev) 543 629 { 544 630 struct asus_drvdata *drvdata = hid_get_drvdata(hdev); 631 + struct usb_interface *intf; 632 + struct usb_device *udev; 545 633 unsigned char kbd_func; 546 634 int ret; 547 635 ··· 658 560 if (ret < 0) 659 561 return ret; 660 562 } 563 + 564 + if (drvdata->quirks & QUIRK_ROG_ALLY_XPAD) { 565 + intf = to_usb_interface(hdev->dev.parent); 566 + udev = interface_to_usbdev(intf); 567 + validate_mcu_fw_version(hdev, 568 + le16_to_cpu(udev->descriptor.idProduct)); 569 + } 570 + 661 571 } else { 662 572 /* Initialize keyboard */ 663 573 ret = asus_kbd_init(hdev, FEATURE_KBD_REPORT_ID); ··· 1386 1280 QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, 1387 1281 { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, 1388 1282 USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY), 1389 - QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, 1283 + QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD}, 1390 1284 { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, 1391 1285 USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X), 1392 - QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, 1286 + QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD }, 1393 1287 { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, 1394 1288 USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD), 1395 1289 QUIRK_ROG_CLAYMORE_II_KEYBOARD }, ··· 1433 1327 }; 1434 1328 module_hid_driver(asus_driver); 1435 1329 1330 + MODULE_IMPORT_NS("ASUS_WMI"); 1436 1331 MODULE_LICENSE("GPL");
-11
drivers/hwmon/Kconfig
··· 1795 1795 1796 1796 source "drivers/hwmon/occ/Kconfig" 1797 1797 1798 - config SENSORS_OXP 1799 - tristate "OneXPlayer EC fan control" 1800 - depends on ACPI_EC 1801 - depends on X86 1802 - help 1803 - If you say yes here you get support for fan readings and control over 1804 - OneXPlayer handheld devices. Only OneXPlayer mini AMD handheld variant 1805 - boards are supported. 1806 - 1807 - Can also be built as a module. In that case it will be called oxp-sensors. 1808 - 1809 1798 config SENSORS_PCF8591 1810 1799 tristate "Philips PCF8591 ADC/DAC" 1811 1800 depends on I2C
-1
drivers/hwmon/Makefile
··· 183 183 obj-$(CONFIG_SENSORS_NZXT_KRAKEN2) += nzxt-kraken2.o 184 184 obj-$(CONFIG_SENSORS_NZXT_KRAKEN3) += nzxt-kraken3.o 185 185 obj-$(CONFIG_SENSORS_NZXT_SMART2) += nzxt-smart2.o 186 - obj-$(CONFIG_SENSORS_OXP) += oxp-sensors.o 187 186 obj-$(CONFIG_SENSORS_PC87360) += pc87360.o 188 187 obj-$(CONFIG_SENSORS_PC87427) += pc87427.o 189 188 obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
-716
drivers/hwmon/oxp-sensors.c
··· 1 - // SPDX-License-Identifier: GPL-2.0+ 2 - /* 3 - * Platform driver for OneXPlayer, AOKZOE, AYANEO, and OrangePi Handhelds 4 - * that expose fan reading and control via hwmon sysfs. 5 - * 6 - * Old OXP boards have the same DMI strings and they are told apart by 7 - * the boot cpu vendor (Intel/AMD). Of these older models only AMD is 8 - * supported. 9 - * 10 - * Fan control is provided via pwm interface in the range [0-255]. 11 - * Old AMD boards use [0-100] as range in the EC, the written value is 12 - * scaled to accommodate for that. Newer boards like the mini PRO and 13 - * AOKZOE are not scaled but have the same EC layout. Newer models 14 - * like the 2 and X1 are [0-184] and are scaled to 0-255. OrangePi 15 - * are [1-244] and scaled to 0-255. 16 - * 17 - * Copyright (C) 2022 Joaquín I. Aramendía <samsagax@gmail.com> 18 - * Copyright (C) 2024 Derek J. Clark <derekjohn.clark@gmail.com> 19 - */ 20 - 21 - #include <linux/acpi.h> 22 - #include <linux/dmi.h> 23 - #include <linux/hwmon.h> 24 - #include <linux/init.h> 25 - #include <linux/kernel.h> 26 - #include <linux/module.h> 27 - #include <linux/platform_device.h> 28 - #include <linux/processor.h> 29 - 30 - /* Handle ACPI lock mechanism */ 31 - static u32 oxp_mutex; 32 - 33 - #define ACPI_LOCK_DELAY_MS 500 34 - 35 - static bool lock_global_acpi_lock(void) 36 - { 37 - return ACPI_SUCCESS(acpi_acquire_global_lock(ACPI_LOCK_DELAY_MS, &oxp_mutex)); 38 - } 39 - 40 - static bool unlock_global_acpi_lock(void) 41 - { 42 - return ACPI_SUCCESS(acpi_release_global_lock(oxp_mutex)); 43 - } 44 - 45 - enum oxp_board { 46 - aok_zoe_a1 = 1, 47 - aya_neo_2, 48 - aya_neo_air, 49 - aya_neo_air_1s, 50 - aya_neo_air_plus_mendo, 51 - aya_neo_air_pro, 52 - aya_neo_flip, 53 - aya_neo_geek, 54 - aya_neo_kun, 55 - orange_pi_neo, 56 - oxp_2, 57 - oxp_fly, 58 - oxp_mini_amd, 59 - oxp_mini_amd_a07, 60 - oxp_mini_amd_pro, 61 - oxp_x1, 62 - }; 63 - 64 - static enum oxp_board board; 65 - 66 - /* Fan reading and PWM */ 67 - #define OXP_SENSOR_FAN_REG 0x76 /* Fan reading is 2 registers long */ 68 - #define OXP_2_SENSOR_FAN_REG 0x58 /* Fan reading is 2 registers long */ 69 - #define OXP_SENSOR_PWM_ENABLE_REG 0x4A /* PWM enable is 1 register long */ 70 - #define OXP_SENSOR_PWM_REG 0x4B /* PWM reading is 1 register long */ 71 - #define PWM_MODE_AUTO 0x00 72 - #define PWM_MODE_MANUAL 0x01 73 - 74 - /* OrangePi fan reading and PWM */ 75 - #define ORANGEPI_SENSOR_FAN_REG 0x78 /* Fan reading is 2 registers long */ 76 - #define ORANGEPI_SENSOR_PWM_ENABLE_REG 0x40 /* PWM enable is 1 register long */ 77 - #define ORANGEPI_SENSOR_PWM_REG 0x38 /* PWM reading is 1 register long */ 78 - 79 - /* Turbo button takeover function 80 - * Different boards have different values and EC registers 81 - * for the same function 82 - */ 83 - #define OXP_TURBO_SWITCH_REG 0xF1 /* Mini Pro, OneXFly, AOKZOE */ 84 - #define OXP_2_TURBO_SWITCH_REG 0xEB /* OXP2 and X1 */ 85 - #define OXP_MINI_TURBO_SWITCH_REG 0x1E /* Mini AO7 */ 86 - 87 - #define OXP_MINI_TURBO_TAKE_VAL 0x01 /* Mini AO7 */ 88 - #define OXP_TURBO_TAKE_VAL 0x40 /* All other models */ 89 - 90 - #define OXP_TURBO_RETURN_VAL 0x00 /* Common return val */ 91 - 92 - static const struct dmi_system_id dmi_table[] = { 93 - { 94 - .matches = { 95 - DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"), 96 - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 AR07"), 97 - }, 98 - .driver_data = (void *)aok_zoe_a1, 99 - }, 100 - { 101 - .matches = { 102 - DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"), 103 - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 Pro"), 104 - }, 105 - .driver_data = (void *)aok_zoe_a1, 106 - }, 107 - { 108 - .matches = { 109 - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 110 - DMI_MATCH(DMI_BOARD_NAME, "AYANEO 2"), 111 - }, 112 - .driver_data = (void *)aya_neo_2, 113 - }, 114 - { 115 - .matches = { 116 - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 117 - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"), 118 - }, 119 - .driver_data = (void *)aya_neo_air, 120 - }, 121 - { 122 - .matches = { 123 - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 124 - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR 1S"), 125 - }, 126 - .driver_data = (void *)aya_neo_air_1s, 127 - }, 128 - { 129 - .matches = { 130 - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 131 - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AB05-Mendocino"), 132 - }, 133 - .driver_data = (void *)aya_neo_air_plus_mendo, 134 - }, 135 - { 136 - .matches = { 137 - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 138 - DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"), 139 - }, 140 - .driver_data = (void *)aya_neo_air_pro, 141 - }, 142 - { 143 - .matches = { 144 - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 145 - DMI_MATCH(DMI_BOARD_NAME, "FLIP"), 146 - }, 147 - .driver_data = (void *)aya_neo_flip, 148 - }, 149 - { 150 - .matches = { 151 - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 152 - DMI_MATCH(DMI_BOARD_NAME, "GEEK"), 153 - }, 154 - .driver_data = (void *)aya_neo_geek, 155 - }, 156 - { 157 - .matches = { 158 - DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 159 - DMI_EXACT_MATCH(DMI_BOARD_NAME, "KUN"), 160 - }, 161 - .driver_data = (void *)aya_neo_kun, 162 - }, 163 - { 164 - .matches = { 165 - DMI_MATCH(DMI_BOARD_VENDOR, "OrangePi"), 166 - DMI_EXACT_MATCH(DMI_BOARD_NAME, "NEO-01"), 167 - }, 168 - .driver_data = (void *)orange_pi_neo, 169 - }, 170 - { 171 - .matches = { 172 - DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 173 - DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONE XPLAYER"), 174 - }, 175 - .driver_data = (void *)oxp_mini_amd, 176 - }, 177 - { 178 - .matches = { 179 - DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 180 - DMI_MATCH(DMI_BOARD_NAME, "ONEXPLAYER 2"), 181 - }, 182 - .driver_data = (void *)oxp_2, 183 - }, 184 - { 185 - .matches = { 186 - DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 187 - DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1"), 188 - }, 189 - .driver_data = (void *)oxp_fly, 190 - }, 191 - { 192 - .matches = { 193 - DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 194 - DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER mini A07"), 195 - }, 196 - .driver_data = (void *)oxp_mini_amd_a07, 197 - }, 198 - { 199 - .matches = { 200 - DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 201 - DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER Mini Pro"), 202 - }, 203 - .driver_data = (void *)oxp_mini_amd_pro, 204 - }, 205 - { 206 - .matches = { 207 - DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 208 - DMI_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1"), 209 - }, 210 - .driver_data = (void *)oxp_x1, 211 - }, 212 - {}, 213 - }; 214 - 215 - /* Helper functions to handle EC read/write */ 216 - static int read_from_ec(u8 reg, int size, long *val) 217 - { 218 - int i; 219 - int ret; 220 - u8 buffer; 221 - 222 - if (!lock_global_acpi_lock()) 223 - return -EBUSY; 224 - 225 - *val = 0; 226 - for (i = 0; i < size; i++) { 227 - ret = ec_read(reg + i, &buffer); 228 - if (ret) 229 - return ret; 230 - *val <<= i * 8; 231 - *val += buffer; 232 - } 233 - 234 - if (!unlock_global_acpi_lock()) 235 - return -EBUSY; 236 - 237 - return 0; 238 - } 239 - 240 - static int write_to_ec(u8 reg, u8 value) 241 - { 242 - int ret; 243 - 244 - if (!lock_global_acpi_lock()) 245 - return -EBUSY; 246 - 247 - ret = ec_write(reg, value); 248 - 249 - if (!unlock_global_acpi_lock()) 250 - return -EBUSY; 251 - 252 - return ret; 253 - } 254 - 255 - /* Turbo button toggle functions */ 256 - static int tt_toggle_enable(void) 257 - { 258 - u8 reg; 259 - u8 val; 260 - 261 - switch (board) { 262 - case oxp_mini_amd_a07: 263 - reg = OXP_MINI_TURBO_SWITCH_REG; 264 - val = OXP_MINI_TURBO_TAKE_VAL; 265 - break; 266 - case aok_zoe_a1: 267 - case oxp_fly: 268 - case oxp_mini_amd_pro: 269 - reg = OXP_TURBO_SWITCH_REG; 270 - val = OXP_TURBO_TAKE_VAL; 271 - break; 272 - case oxp_2: 273 - case oxp_x1: 274 - reg = OXP_2_TURBO_SWITCH_REG; 275 - val = OXP_TURBO_TAKE_VAL; 276 - break; 277 - default: 278 - return -EINVAL; 279 - } 280 - return write_to_ec(reg, val); 281 - } 282 - 283 - static int tt_toggle_disable(void) 284 - { 285 - u8 reg; 286 - u8 val; 287 - 288 - switch (board) { 289 - case oxp_mini_amd_a07: 290 - reg = OXP_MINI_TURBO_SWITCH_REG; 291 - val = OXP_TURBO_RETURN_VAL; 292 - break; 293 - case aok_zoe_a1: 294 - case oxp_fly: 295 - case oxp_mini_amd_pro: 296 - reg = OXP_TURBO_SWITCH_REG; 297 - val = OXP_TURBO_RETURN_VAL; 298 - break; 299 - case oxp_2: 300 - case oxp_x1: 301 - reg = OXP_2_TURBO_SWITCH_REG; 302 - val = OXP_TURBO_RETURN_VAL; 303 - break; 304 - default: 305 - return -EINVAL; 306 - } 307 - return write_to_ec(reg, val); 308 - } 309 - 310 - /* Callbacks for turbo toggle attribute */ 311 - static umode_t tt_toggle_is_visible(struct kobject *kobj, 312 - struct attribute *attr, int n) 313 - { 314 - switch (board) { 315 - case aok_zoe_a1: 316 - case oxp_2: 317 - case oxp_fly: 318 - case oxp_mini_amd_a07: 319 - case oxp_mini_amd_pro: 320 - case oxp_x1: 321 - return attr->mode; 322 - default: 323 - break; 324 - } 325 - return 0; 326 - } 327 - 328 - static ssize_t tt_toggle_store(struct device *dev, 329 - struct device_attribute *attr, const char *buf, 330 - size_t count) 331 - { 332 - int rval; 333 - bool value; 334 - 335 - rval = kstrtobool(buf, &value); 336 - if (rval) 337 - return rval; 338 - 339 - if (value) { 340 - rval = tt_toggle_enable(); 341 - } else { 342 - rval = tt_toggle_disable(); 343 - } 344 - if (rval) 345 - return rval; 346 - 347 - return count; 348 - } 349 - 350 - static ssize_t tt_toggle_show(struct device *dev, 351 - struct device_attribute *attr, char *buf) 352 - { 353 - int retval; 354 - u8 reg; 355 - long val; 356 - 357 - switch (board) { 358 - case oxp_mini_amd_a07: 359 - reg = OXP_MINI_TURBO_SWITCH_REG; 360 - break; 361 - case aok_zoe_a1: 362 - case oxp_fly: 363 - case oxp_mini_amd_pro: 364 - reg = OXP_TURBO_SWITCH_REG; 365 - break; 366 - case oxp_2: 367 - case oxp_x1: 368 - reg = OXP_2_TURBO_SWITCH_REG; 369 - break; 370 - default: 371 - return -EINVAL; 372 - } 373 - 374 - retval = read_from_ec(reg, 1, &val); 375 - if (retval) 376 - return retval; 377 - 378 - return sysfs_emit(buf, "%d\n", !!val); 379 - } 380 - 381 - static DEVICE_ATTR_RW(tt_toggle); 382 - 383 - /* PWM enable/disable functions */ 384 - static int oxp_pwm_enable(void) 385 - { 386 - switch (board) { 387 - case orange_pi_neo: 388 - return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL); 389 - case aok_zoe_a1: 390 - case aya_neo_2: 391 - case aya_neo_air: 392 - case aya_neo_air_plus_mendo: 393 - case aya_neo_air_pro: 394 - case aya_neo_flip: 395 - case aya_neo_geek: 396 - case aya_neo_kun: 397 - case oxp_2: 398 - case oxp_fly: 399 - case oxp_mini_amd: 400 - case oxp_mini_amd_a07: 401 - case oxp_mini_amd_pro: 402 - case oxp_x1: 403 - return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL); 404 - default: 405 - return -EINVAL; 406 - } 407 - } 408 - 409 - static int oxp_pwm_disable(void) 410 - { 411 - switch (board) { 412 - case orange_pi_neo: 413 - return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO); 414 - case aok_zoe_a1: 415 - case aya_neo_2: 416 - case aya_neo_air: 417 - case aya_neo_air_1s: 418 - case aya_neo_air_plus_mendo: 419 - case aya_neo_air_pro: 420 - case aya_neo_flip: 421 - case aya_neo_geek: 422 - case aya_neo_kun: 423 - case oxp_2: 424 - case oxp_fly: 425 - case oxp_mini_amd: 426 - case oxp_mini_amd_a07: 427 - case oxp_mini_amd_pro: 428 - case oxp_x1: 429 - return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO); 430 - default: 431 - return -EINVAL; 432 - } 433 - } 434 - 435 - /* Callbacks for hwmon interface */ 436 - static umode_t oxp_ec_hwmon_is_visible(const void *drvdata, 437 - enum hwmon_sensor_types type, u32 attr, int channel) 438 - { 439 - switch (type) { 440 - case hwmon_fan: 441 - return 0444; 442 - case hwmon_pwm: 443 - return 0644; 444 - default: 445 - return 0; 446 - } 447 - } 448 - 449 - static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type, 450 - u32 attr, int channel, long *val) 451 - { 452 - int ret; 453 - 454 - switch (type) { 455 - case hwmon_fan: 456 - switch (attr) { 457 - case hwmon_fan_input: 458 - switch (board) { 459 - case orange_pi_neo: 460 - return read_from_ec(ORANGEPI_SENSOR_FAN_REG, 2, val); 461 - case oxp_2: 462 - case oxp_x1: 463 - return read_from_ec(OXP_2_SENSOR_FAN_REG, 2, val); 464 - case aok_zoe_a1: 465 - case aya_neo_2: 466 - case aya_neo_air: 467 - case aya_neo_air_1s: 468 - case aya_neo_air_plus_mendo: 469 - case aya_neo_air_pro: 470 - case aya_neo_flip: 471 - case aya_neo_geek: 472 - case aya_neo_kun: 473 - case oxp_fly: 474 - case oxp_mini_amd: 475 - case oxp_mini_amd_a07: 476 - case oxp_mini_amd_pro: 477 - return read_from_ec(OXP_SENSOR_FAN_REG, 2, val); 478 - default: 479 - break; 480 - } 481 - break; 482 - default: 483 - break; 484 - } 485 - break; 486 - case hwmon_pwm: 487 - switch (attr) { 488 - case hwmon_pwm_input: 489 - switch (board) { 490 - case orange_pi_neo: 491 - ret = read_from_ec(ORANGEPI_SENSOR_PWM_REG, 1, val); 492 - if (ret) 493 - return ret; 494 - /* scale from range [1-244] */ 495 - *val = ((*val - 1) * 254 / 243) + 1; 496 - break; 497 - case oxp_2: 498 - case oxp_x1: 499 - ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val); 500 - if (ret) 501 - return ret; 502 - /* scale from range [0-184] */ 503 - *val = (*val * 255) / 184; 504 - break; 505 - case aya_neo_2: 506 - case aya_neo_air: 507 - case aya_neo_air_1s: 508 - case aya_neo_air_plus_mendo: 509 - case aya_neo_air_pro: 510 - case aya_neo_flip: 511 - case aya_neo_geek: 512 - case aya_neo_kun: 513 - case oxp_mini_amd: 514 - case oxp_mini_amd_a07: 515 - ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val); 516 - if (ret) 517 - return ret; 518 - /* scale from range [0-100] */ 519 - *val = (*val * 255) / 100; 520 - break; 521 - case aok_zoe_a1: 522 - case oxp_fly: 523 - case oxp_mini_amd_pro: 524 - default: 525 - ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val); 526 - if (ret) 527 - return ret; 528 - break; 529 - } 530 - return 0; 531 - case hwmon_pwm_enable: 532 - switch (board) { 533 - case orange_pi_neo: 534 - return read_from_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, 1, val); 535 - case aok_zoe_a1: 536 - case aya_neo_2: 537 - case aya_neo_air: 538 - case aya_neo_air_1s: 539 - case aya_neo_air_plus_mendo: 540 - case aya_neo_air_pro: 541 - case aya_neo_flip: 542 - case aya_neo_geek: 543 - case aya_neo_kun: 544 - case oxp_2: 545 - case oxp_fly: 546 - case oxp_mini_amd: 547 - case oxp_mini_amd_a07: 548 - case oxp_mini_amd_pro: 549 - case oxp_x1: 550 - return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val); 551 - default: 552 - break; 553 - } 554 - break; 555 - default: 556 - break; 557 - } 558 - break; 559 - default: 560 - break; 561 - } 562 - return -EOPNOTSUPP; 563 - } 564 - 565 - static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type, 566 - u32 attr, int channel, long val) 567 - { 568 - switch (type) { 569 - case hwmon_pwm: 570 - switch (attr) { 571 - case hwmon_pwm_enable: 572 - if (val == 1) 573 - return oxp_pwm_enable(); 574 - else if (val == 0) 575 - return oxp_pwm_disable(); 576 - return -EINVAL; 577 - case hwmon_pwm_input: 578 - if (val < 0 || val > 255) 579 - return -EINVAL; 580 - switch (board) { 581 - case orange_pi_neo: 582 - /* scale to range [1-244] */ 583 - val = ((val - 1) * 243 / 254) + 1; 584 - return write_to_ec(ORANGEPI_SENSOR_PWM_REG, val); 585 - case oxp_2: 586 - case oxp_x1: 587 - /* scale to range [0-184] */ 588 - val = (val * 184) / 255; 589 - return write_to_ec(OXP_SENSOR_PWM_REG, val); 590 - case aya_neo_2: 591 - case aya_neo_air: 592 - case aya_neo_air_1s: 593 - case aya_neo_air_plus_mendo: 594 - case aya_neo_air_pro: 595 - case aya_neo_flip: 596 - case aya_neo_geek: 597 - case aya_neo_kun: 598 - case oxp_mini_amd: 599 - case oxp_mini_amd_a07: 600 - /* scale to range [0-100] */ 601 - val = (val * 100) / 255; 602 - return write_to_ec(OXP_SENSOR_PWM_REG, val); 603 - case aok_zoe_a1: 604 - case oxp_fly: 605 - case oxp_mini_amd_pro: 606 - return write_to_ec(OXP_SENSOR_PWM_REG, val); 607 - default: 608 - break; 609 - } 610 - break; 611 - default: 612 - break; 613 - } 614 - break; 615 - default: 616 - break; 617 - } 618 - return -EOPNOTSUPP; 619 - } 620 - 621 - /* Known sensors in the OXP EC controllers */ 622 - static const struct hwmon_channel_info * const oxp_platform_sensors[] = { 623 - HWMON_CHANNEL_INFO(fan, 624 - HWMON_F_INPUT), 625 - HWMON_CHANNEL_INFO(pwm, 626 - HWMON_PWM_INPUT | HWMON_PWM_ENABLE), 627 - NULL, 628 - }; 629 - 630 - static struct attribute *oxp_ec_attrs[] = { 631 - &dev_attr_tt_toggle.attr, 632 - NULL 633 - }; 634 - 635 - static struct attribute_group oxp_ec_attribute_group = { 636 - .is_visible = tt_toggle_is_visible, 637 - .attrs = oxp_ec_attrs, 638 - }; 639 - 640 - static const struct attribute_group *oxp_ec_groups[] = { 641 - &oxp_ec_attribute_group, 642 - NULL 643 - }; 644 - 645 - static const struct hwmon_ops oxp_ec_hwmon_ops = { 646 - .is_visible = oxp_ec_hwmon_is_visible, 647 - .read = oxp_platform_read, 648 - .write = oxp_platform_write, 649 - }; 650 - 651 - static const struct hwmon_chip_info oxp_ec_chip_info = { 652 - .ops = &oxp_ec_hwmon_ops, 653 - .info = oxp_platform_sensors, 654 - }; 655 - 656 - /* Initialization logic */ 657 - static int oxp_platform_probe(struct platform_device *pdev) 658 - { 659 - struct device *dev = &pdev->dev; 660 - struct device *hwdev; 661 - 662 - hwdev = devm_hwmon_device_register_with_info(dev, "oxpec", NULL, 663 - &oxp_ec_chip_info, NULL); 664 - 665 - return PTR_ERR_OR_ZERO(hwdev); 666 - } 667 - 668 - static struct platform_driver oxp_platform_driver = { 669 - .driver = { 670 - .name = "oxp-platform", 671 - .dev_groups = oxp_ec_groups, 672 - }, 673 - .probe = oxp_platform_probe, 674 - }; 675 - 676 - static struct platform_device *oxp_platform_device; 677 - 678 - static int __init oxp_platform_init(void) 679 - { 680 - const struct dmi_system_id *dmi_entry; 681 - 682 - dmi_entry = dmi_first_match(dmi_table); 683 - if (!dmi_entry) 684 - return -ENODEV; 685 - 686 - board = (enum oxp_board)(unsigned long)dmi_entry->driver_data; 687 - 688 - /* 689 - * Have to check for AMD processor here because DMI strings are the same 690 - * between Intel and AMD boards on older OneXPlayer devices, the only way 691 - * to tell them apart is the CPU. Old Intel boards have an unsupported EC. 692 - */ 693 - if (board == oxp_mini_amd && boot_cpu_data.x86_vendor != X86_VENDOR_AMD) 694 - return -ENODEV; 695 - 696 - oxp_platform_device = 697 - platform_create_bundle(&oxp_platform_driver, 698 - oxp_platform_probe, NULL, 0, NULL, 0); 699 - 700 - return PTR_ERR_OR_ZERO(oxp_platform_device); 701 - } 702 - 703 - static void __exit oxp_platform_exit(void) 704 - { 705 - platform_device_unregister(oxp_platform_device); 706 - platform_driver_unregister(&oxp_platform_driver); 707 - } 708 - 709 - MODULE_DEVICE_TABLE(dmi, dmi_table); 710 - 711 - module_init(oxp_platform_init); 712 - module_exit(oxp_platform_exit); 713 - 714 - MODULE_AUTHOR("Joaquín Ignacio Aramendía <samsagax@gmail.com>"); 715 - MODULE_DESCRIPTION("Platform driver that handles EC sensors of OneXPlayer devices"); 716 - MODULE_LICENSE("GPL");
+1 -1
drivers/platform/arm64/Kconfig
··· 6 6 menuconfig ARM64_PLATFORM_DEVICES 7 7 bool "ARM64 Platform-Specific Device Drivers" 8 8 depends on ARM64 || COMPILE_TEST 9 - default y 9 + default ARM64 10 10 help 11 11 Say Y here to get to see options for platform-specific device drivers 12 12 for arm64 based devices, primarily EC-like device drivers.
+1 -1
drivers/platform/arm64/huawei-gaokun-ec.c
··· 651 651 break; 652 652 653 653 msleep(100); /* EC need time to resume */ 654 - }; 654 + } 655 655 656 656 ec->suspended = false; 657 657
+13
drivers/platform/mellanox/Kconfig
··· 27 27 28 28 If you have a Mellanox system, say Y or M here. 29 29 30 + config MLXREG_DPU 31 + tristate "Nvidia Data Processor Unit platform driver support" 32 + depends on I2C 33 + select REGMAP_I2C 34 + help 35 + This driver provides support for the Nvidia BF3 Data Processor Units, 36 + which are the part of SN4280 Ethernet smart switch systems 37 + providing a high performance switching solution for Enterprise Data 38 + Centers (EDC) for building Ethernet based clusters, High-Performance 39 + Computing (HPC) and embedded environments. 40 + 41 + If you have a Nvidia smart switch system, say Y or M here. 42 + 30 43 config MLXREG_HOTPLUG 31 44 tristate "Mellanox platform hotplug driver support" 32 45 depends on HWMON
+1
drivers/platform/mellanox/Makefile
··· 7 7 obj-$(CONFIG_MLXBF_BOOTCTL) += mlxbf-bootctl.o 8 8 obj-$(CONFIG_MLXBF_PMC) += mlxbf-pmc.o 9 9 obj-$(CONFIG_MLXBF_TMFIFO) += mlxbf-tmfifo.o 10 + obj-$(CONFIG_MLXREG_DPU) += mlxreg-dpu.o 10 11 obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o 11 12 obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o 12 13 obj-$(CONFIG_MLXREG_LC) += mlxreg-lc.o
+1529 -17
drivers/platform/mellanox/mlx-platform.c
··· 38 38 #define MLXPLAT_CPLD_LPC_REG_CPLD4_PN1_OFFSET 0x0b 39 39 #define MLXPLAT_CPLD_LPC_REG_RESET_GP1_OFFSET 0x17 40 40 #define MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET 0x19 41 + #define MLXPLAT_CPLD_LPC_REG_RESET_GP3_OFFSET 0x1b 41 42 #define MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET 0x1c 42 43 #define MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET 0x1d 43 44 #define MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET 0x1e ··· 50 49 #define MLXPLAT_CPLD_LPC_REG_LED5_OFFSET 0x24 51 50 #define MLXPLAT_CPLD_LPC_REG_LED6_OFFSET 0x25 52 51 #define MLXPLAT_CPLD_LPC_REG_LED7_OFFSET 0x26 52 + #define MLXPLAT_CPLD_LPC_REG_LED8_OFFSET 0x27 53 53 #define MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION 0x2a 54 54 #define MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET 0x2b 55 55 #define MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET 0x2d 56 + #define MLXPLAT_CPLD_LPC_REG_GP1_RO_OFFSET 0x2c 56 57 #define MLXPLAT_CPLD_LPC_REG_GP0_OFFSET 0x2e 57 58 #define MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET 0x2f 58 59 #define MLXPLAT_CPLD_LPC_REG_GP1_OFFSET 0x30 ··· 74 71 #define MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET 0x43 75 72 #define MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET 0x44 76 73 #define MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET 0x45 74 + #define MLXPLAT_CPLD_LPC_REG_GP3_OFFSET 0x46 77 75 #define MLXPLAT_CPLD_LPC_REG_BRD_OFFSET 0x47 78 76 #define MLXPLAT_CPLD_LPC_REG_BRD_EVENT_OFFSET 0x48 79 77 #define MLXPLAT_CPLD_LPC_REG_BRD_MASK_OFFSET 0x49 80 78 #define MLXPLAT_CPLD_LPC_REG_GWP_OFFSET 0x4a 81 79 #define MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET 0x4b 82 80 #define MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET 0x4c 81 + #define MLXPLAT_CPLD_LPC_REG_GPI_MASK_OFFSET 0x4e 83 82 #define MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET 0x50 84 83 #define MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET 0x51 85 84 #define MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET 0x52 ··· 93 88 #define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58 94 89 #define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET 0x59 95 90 #define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET 0x5a 91 + #define MLXPLAT_CPLD_LPC_REG_PSU_AC_OFFSET 0x5e 96 92 #define MLXPLAT_CPLD_LPC_REG_PWR_OFFSET 0x64 97 93 #define MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET 0x65 98 94 #define MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET 0x66 95 + #define MLXPLAT_CPLD_LPC_REG_PSU_ALERT_OFFSET 0x6a 99 96 #define MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET 0x70 100 97 #define MLXPLAT_CPLD_LPC_REG_LC_IN_EVENT_OFFSET 0x71 101 98 #define MLXPLAT_CPLD_LPC_REG_LC_IN_MASK_OFFSET 0x72 102 99 #define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88 103 100 #define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89 104 101 #define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a 102 + #define MLXPLAT_CPLD_LPC_REG_FAN2_OFFSET 0x8b 103 + #define MLXPLAT_CPLD_LPC_REG_FAN2_EVENT_OFFSET 0x8c 104 + #define MLXPLAT_CPLD_LPC_REG_FAN2_MASK_OFFSET 0x8d 105 105 #define MLXPLAT_CPLD_LPC_REG_CPLD5_VER_OFFSET 0x8e 106 106 #define MLXPLAT_CPLD_LPC_REG_CPLD5_PN_OFFSET 0x8f 107 107 #define MLXPLAT_CPLD_LPC_REG_CPLD5_PN1_OFFSET 0x90 ··· 138 128 #define MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET 0xaa 139 129 #define MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET 0xab 140 130 #define MLXPLAT_CPLD_LPC_REG_LC_PWR_ON 0xb2 131 + #define MLXPLAT_CPLD_LPC_REG_TACHO19_OFFSET 0xb4 132 + #define MLXPLAT_CPLD_LPC_REG_TACHO20_OFFSET 0xb5 141 133 #define MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET 0xb6 142 134 #define MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET 0xb7 143 135 #define MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET 0xb8 144 136 #define MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET 0xb9 137 + #define MLXPLAT_CPLD_LPC_REG_TACHO17_OFFSET 0xba 138 + #define MLXPLAT_CPLD_LPC_REG_TACHO18_OFFSET 0xbb 139 + #define MLXPLAT_CPLD_LPC_REG_ASIC_CAP_OFFSET 0xc1 145 140 #define MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET 0xc2 146 141 #define MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT 0xc3 147 142 #define MLXPLAT_CPLD_LPC_REG_CPLD5_MVER_OFFSET 0xc4 ··· 197 182 #define MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET 0xfb 198 183 #define MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET 0xfc 199 184 #define MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET 0xfd 185 + #define MLXPLAT_CPLD_LPC_REG_TACHO15_OFFSET 0xfe 186 + #define MLXPLAT_CPLD_LPC_REG_TACHO16_OFFSET 0xff 187 + 200 188 #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 201 189 202 190 #define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL ··· 228 210 #define MLXPLAT_CPLD_AGGR_MASK_NG_DEF 0x04 229 211 #define MLXPLAT_CPLD_AGGR_MASK_COMEX BIT(0) 230 212 #define MLXPLAT_CPLD_AGGR_MASK_LC BIT(3) 213 + #define MLXPLAT_CPLD_AGGR_MASK_DPU_BRD BIT(4) 214 + #define MLXPLAT_CPLD_AGGR_MASK_DPU_CORE BIT(5) 231 215 #define MLXPLAT_CPLD_AGGR_MASK_MODULAR (MLXPLAT_CPLD_AGGR_MASK_NG_DEF | \ 232 216 MLXPLAT_CPLD_AGGR_MASK_COMEX | \ 233 217 MLXPLAT_CPLD_AGGR_MASK_LC) 218 + #define MLXPLAT_CPLD_AGGR_MASK_SMART_SW (MLXPLAT_CPLD_AGGR_MASK_COMEX | \ 219 + MLXPLAT_CPLD_AGGR_MASK_NG_DEF | \ 220 + MLXPLAT_CPLD_AGGR_MASK_DPU_BRD | \ 221 + MLXPLAT_CPLD_AGGR_MASK_DPU_CORE) 234 222 #define MLXPLAT_CPLD_AGGR_MASK_LC_PRSNT BIT(0) 235 223 #define MLXPLAT_CPLD_AGGR_MASK_LC_RDY BIT(1) 236 224 #define MLXPLAT_CPLD_AGGR_MASK_LC_PG BIT(2) ··· 259 235 #define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0) 260 236 #define MLXPLAT_CPLD_PSU_EXT_MASK GENMASK(3, 0) 261 237 #define MLXPLAT_CPLD_PWR_EXT_MASK GENMASK(3, 0) 238 + #define MLXPLAT_CPLD_PSU_XDR_MASK GENMASK(7, 0) 239 + #define MLXPLAT_CPLD_PWR_XDR_MASK GENMASK(7, 0) 262 240 #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) 263 241 #define MLXPLAT_CPLD_ASIC_MASK GENMASK(1, 0) 242 + #define MLXPLAT_CPLD_ASIC_XDR_MASK GENMASK(3, 0) 264 243 #define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(6, 0) 244 + #define MLXPLAT_CPLD_FAN_XDR_MASK GENMASK(7, 0) 265 245 #define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK GENMASK(7, 4) 266 246 #define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0) 267 247 #define MLXPLAT_CPLD_VOLTREG_UPD_MASK GENMASK(5, 4) 268 248 #define MLXPLAT_CPLD_GWP_MASK GENMASK(0, 0) 269 249 #define MLXPLAT_CPLD_EROT_MASK GENMASK(1, 0) 270 250 #define MLXPLAT_CPLD_FU_CAP_MASK GENMASK(1, 0) 251 + #define MLXPLAT_CPLD_BIOS_STATUS_MASK GENMASK(3, 1) 252 + #define MLXPLAT_CPLD_DPU_MASK GENMASK(3, 0) 271 253 #define MLXPLAT_CPLD_PWR_BUTTON_MASK BIT(0) 272 254 #define MLXPLAT_CPLD_LATCH_RST_MASK BIT(6) 273 255 #define MLXPLAT_CPLD_THERMAL1_PDB_MASK BIT(3) ··· 296 266 297 267 /* Masks for aggregation for modular systems */ 298 268 #define MLXPLAT_CPLD_LPC_LC_MASK GENMASK(7, 0) 269 + 270 + /* Masks for aggregation for smart switch systems */ 271 + #define MLXPLAT_CPLD_LPC_SM_SW_MASK GENMASK(7, 0) 299 272 300 273 #define MLXPLAT_CPLD_HALT_MASK BIT(3) 301 274 #define MLXPLAT_CPLD_RESET_MASK GENMASK(7, 1) ··· 330 297 #define MLXPLAT_CPLD_NR_NONE -1 331 298 #define MLXPLAT_CPLD_PSU_DEFAULT_NR 10 332 299 #define MLXPLAT_CPLD_PSU_MSNXXXX_NR 4 300 + #define MLXPLAT_CPLD_PSU_XDR_NR 3 333 301 #define MLXPLAT_CPLD_FAN1_DEFAULT_NR 11 334 302 #define MLXPLAT_CPLD_FAN2_DEFAULT_NR 12 335 303 #define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13 336 304 #define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14 337 305 #define MLXPLAT_CPLD_NR_ASIC 3 338 306 #define MLXPLAT_CPLD_NR_LC_BASE 34 307 + #define MLXPLAT_CPLD_NR_DPU_BASE 18 339 308 340 309 #define MLXPLAT_CPLD_NR_LC_SET(nr) (MLXPLAT_CPLD_NR_LC_BASE + (nr)) 341 310 #define MLXPLAT_CPLD_LC_ADDR 0x32 311 + #define MLXPLAT_CPLD_DPU_ADDR 0x68 342 312 343 313 /* Masks and default values for watchdogs */ 344 314 #define MLXPLAT_CPLD_WD1_CLEAR_MASK GENMASK(7, 1) ··· 356 320 #define MLXPLAT_CPLD_WD_DFLT_TIMEOUT 30 357 321 #define MLXPLAT_CPLD_WD3_DFLT_TIMEOUT 600 358 322 #define MLXPLAT_CPLD_WD_MAX_DEVS 2 323 + #define MLXPLAT_CPLD_DPU_MAX_DEVS 4 359 324 360 325 #define MLXPLAT_CPLD_LPC_SYSIRQ 17 361 326 ··· 383 346 * @pdev_io_regs - register access platform devices 384 347 * @pdev_fan - FAN platform devices 385 348 * @pdev_wd - array of watchdog platform devices 349 + * pdev_dpu - array of Data Processor Unit platform devices 386 350 * @regmap: device register map 387 351 * @hotplug_resources: system hotplug resources 388 352 * @hotplug_resources_size: size of system hotplug resources ··· 398 360 struct platform_device *pdev_io_regs; 399 361 struct platform_device *pdev_fan; 400 362 struct platform_device *pdev_wd[MLXPLAT_CPLD_WD_MAX_DEVS]; 363 + struct platform_device *pdev_dpu[MLXPLAT_CPLD_DPU_MAX_DEVS]; 401 364 void *regmap; 402 365 struct resource *hotplug_resources; 403 366 unsigned int hotplug_resources_size; ··· 665 626 }, 666 627 }; 667 628 629 + static struct i2c_board_info mlxplat_mlxcpld_xdr_pwr[] = { 630 + { 631 + I2C_BOARD_INFO("dps460", 0x5d), 632 + }, 633 + { 634 + I2C_BOARD_INFO("dps460", 0x5c), 635 + }, 636 + { 637 + I2C_BOARD_INFO("dps460", 0x5e), 638 + }, 639 + { 640 + I2C_BOARD_INFO("dps460", 0x5f), 641 + }, 642 + }; 643 + 668 644 static struct i2c_board_info mlxplat_mlxcpld_fan[] = { 669 645 { 670 646 I2C_BOARD_INFO("24c32", 0x50), ··· 906 852 static 907 853 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = { 908 854 .items = mlxplat_mlxcpld_default_items, 909 - .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items), 855 + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_items), 910 856 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 911 857 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, 912 858 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, ··· 946 892 static 947 893 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_wc_data = { 948 894 .items = mlxplat_mlxcpld_default_wc_items, 949 - .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_wc_items), 895 + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_wc_items), 950 896 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 951 897 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, 952 898 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, ··· 956 902 static 957 903 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_comex_data = { 958 904 .items = mlxplat_mlxcpld_comex_items, 959 - .counter = ARRAY_SIZE(mlxplat_mlxcpld_comex_items), 905 + .count = ARRAY_SIZE(mlxplat_mlxcpld_comex_items), 960 906 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 961 907 .mask = MLXPLAT_CPLD_AGGR_MASK_CARR_DEF, 962 908 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET, ··· 1003 949 static 1004 950 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { 1005 951 .items = mlxplat_mlxcpld_msn21xx_items, 1006 - .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items), 952 + .count = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items), 1007 953 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 1008 954 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, 1009 955 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, ··· 1112 1058 static 1113 1059 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn274x_data = { 1114 1060 .items = mlxplat_mlxcpld_msn274x_items, 1115 - .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_items), 1061 + .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_items), 1116 1062 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 1117 1063 .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 1118 1064 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, ··· 1159 1105 static 1160 1106 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn201x_data = { 1161 1107 .items = mlxplat_mlxcpld_msn201x_items, 1162 - .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_items), 1108 + .count = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_items), 1163 1109 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 1164 1110 .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, 1165 1111 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, ··· 1283 1229 static 1284 1230 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { 1285 1231 .items = mlxplat_mlxcpld_default_ng_items, 1286 - .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items), 1232 + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items), 1287 1233 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 1288 1234 .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX, 1289 1235 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, ··· 1443 1389 static 1444 1390 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_ext_data = { 1445 1391 .items = mlxplat_mlxcpld_ext_items, 1446 - .counter = ARRAY_SIZE(mlxplat_mlxcpld_ext_items), 1392 + .count = ARRAY_SIZE(mlxplat_mlxcpld_ext_items), 1447 1393 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 1448 1394 .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX, 1449 1395 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, ··· 1453 1399 static 1454 1400 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_ng800_data = { 1455 1401 .items = mlxplat_mlxcpld_ng800_items, 1456 - .counter = ARRAY_SIZE(mlxplat_mlxcpld_ng800_items), 1402 + .count = ARRAY_SIZE(mlxplat_mlxcpld_ng800_items), 1457 1403 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 1458 1404 .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX, 1459 1405 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, ··· 2294 2240 static 2295 2241 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_modular_data = { 2296 2242 .items = mlxplat_mlxcpld_modular_items, 2297 - .counter = ARRAY_SIZE(mlxplat_mlxcpld_modular_items), 2243 + .count = ARRAY_SIZE(mlxplat_mlxcpld_modular_items), 2298 2244 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 2299 2245 .mask = MLXPLAT_CPLD_AGGR_MASK_MODULAR, 2300 2246 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, ··· 2326 2272 static 2327 2273 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_chassis_blade_data = { 2328 2274 .items = mlxplat_mlxcpld_chassis_blade_items, 2329 - .counter = ARRAY_SIZE(mlxplat_mlxcpld_chassis_blade_items), 2275 + .count = ARRAY_SIZE(mlxplat_mlxcpld_chassis_blade_items), 2330 2276 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 2331 2277 .mask = MLXPLAT_CPLD_AGGR_MASK_COMEX, 2332 2278 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, ··· 2417 2363 static 2418 2364 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_rack_switch_data = { 2419 2365 .items = mlxplat_mlxcpld_rack_switch_items, 2420 - .counter = ARRAY_SIZE(mlxplat_mlxcpld_rack_switch_items), 2366 + .count = ARRAY_SIZE(mlxplat_mlxcpld_rack_switch_items), 2421 2367 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 2422 2368 .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX, 2423 2369 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, 2424 2370 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, 2371 + }; 2372 + 2373 + /* Platform hotplug XDR and smart switch system family data */ 2374 + static struct mlxreg_core_data mlxplat_mlxcpld_xdr_psu_items_data[] = { 2375 + { 2376 + .label = "psu1", 2377 + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 2378 + .mask = BIT(0), 2379 + .slot = 1, 2380 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2381 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2382 + }, 2383 + { 2384 + .label = "psu2", 2385 + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 2386 + .mask = BIT(1), 2387 + .slot = 2, 2388 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2389 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2390 + }, 2391 + { 2392 + .label = "psu3", 2393 + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 2394 + .mask = BIT(2), 2395 + .slot = 3, 2396 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2397 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2398 + }, 2399 + { 2400 + .label = "psu4", 2401 + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 2402 + .mask = BIT(3), 2403 + .slot = 4, 2404 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2405 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2406 + }, 2407 + { 2408 + .label = "psu5", 2409 + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 2410 + .mask = BIT(4), 2411 + .slot = 5, 2412 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2413 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2414 + }, 2415 + { 2416 + .label = "psu6", 2417 + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 2418 + .mask = BIT(5), 2419 + .slot = 6, 2420 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2421 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2422 + }, 2423 + { 2424 + .label = "psu7", 2425 + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 2426 + .mask = BIT(6), 2427 + .slot = 7, 2428 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2429 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2430 + }, 2431 + { 2432 + .label = "psu8", 2433 + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 2434 + .mask = BIT(7), 2435 + .slot = 8, 2436 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2437 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2438 + }, 2439 + }; 2440 + 2441 + static struct mlxreg_core_data mlxplat_mlxcpld_xdr_pwr_items_data[] = { 2442 + { 2443 + .label = "pwr1", 2444 + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 2445 + .mask = BIT(0), 2446 + .slot = 1, 2447 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2448 + .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0], 2449 + .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, 2450 + }, 2451 + { 2452 + .label = "pwr2", 2453 + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 2454 + .mask = BIT(1), 2455 + .slot = 2, 2456 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2457 + .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1], 2458 + .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, 2459 + }, 2460 + { 2461 + .label = "pwr3", 2462 + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 2463 + .mask = BIT(2), 2464 + .slot = 3, 2465 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2466 + .hpdev.brdinfo = &mlxplat_mlxcpld_ext_pwr[0], 2467 + .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, 2468 + }, 2469 + { 2470 + .label = "pwr4", 2471 + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 2472 + .mask = BIT(3), 2473 + .slot = 4, 2474 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2475 + .hpdev.brdinfo = &mlxplat_mlxcpld_ext_pwr[1], 2476 + .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, 2477 + }, 2478 + { 2479 + .label = "pwr5", 2480 + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 2481 + .mask = BIT(4), 2482 + .slot = 5, 2483 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2484 + .hpdev.brdinfo = &mlxplat_mlxcpld_xdr_pwr[0], 2485 + .hpdev.nr = MLXPLAT_CPLD_PSU_XDR_NR, 2486 + }, 2487 + { 2488 + .label = "pwr6", 2489 + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 2490 + .mask = BIT(5), 2491 + .slot = 6, 2492 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2493 + .hpdev.brdinfo = &mlxplat_mlxcpld_xdr_pwr[1], 2494 + .hpdev.nr = MLXPLAT_CPLD_PSU_XDR_NR, 2495 + }, 2496 + { 2497 + .label = "pwr7", 2498 + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 2499 + .mask = BIT(6), 2500 + .slot = 7, 2501 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2502 + .hpdev.brdinfo = &mlxplat_mlxcpld_xdr_pwr[2], 2503 + .hpdev.nr = MLXPLAT_CPLD_PSU_XDR_NR, 2504 + }, 2505 + { 2506 + .label = "pwr8", 2507 + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 2508 + .mask = BIT(7), 2509 + .slot = 8, 2510 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2511 + .hpdev.brdinfo = &mlxplat_mlxcpld_xdr_pwr[3], 2512 + .hpdev.nr = MLXPLAT_CPLD_PSU_XDR_NR, 2513 + }, 2514 + }; 2515 + 2516 + static struct mlxreg_core_data mlxplat_mlxcpld_xdr_fan_items_data[] = { 2517 + { 2518 + .label = "fan1", 2519 + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 2520 + .mask = BIT(0), 2521 + .slot = 1, 2522 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 2523 + .bit = BIT(0), 2524 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2525 + }, 2526 + { 2527 + .label = "fan2", 2528 + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 2529 + .mask = BIT(1), 2530 + .slot = 2, 2531 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 2532 + .bit = BIT(1), 2533 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2534 + }, 2535 + { 2536 + .label = "fan3", 2537 + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 2538 + .mask = BIT(2), 2539 + .slot = 3, 2540 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 2541 + .bit = BIT(2), 2542 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2543 + }, 2544 + { 2545 + .label = "fan4", 2546 + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 2547 + .mask = BIT(3), 2548 + .slot = 4, 2549 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 2550 + .bit = BIT(3), 2551 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2552 + }, 2553 + { 2554 + .label = "fan5", 2555 + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 2556 + .mask = BIT(4), 2557 + .slot = 5, 2558 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 2559 + .bit = BIT(4), 2560 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2561 + }, 2562 + { 2563 + .label = "fan6", 2564 + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 2565 + .mask = BIT(5), 2566 + .slot = 6, 2567 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 2568 + .bit = BIT(5), 2569 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2570 + }, 2571 + { 2572 + .label = "fan7", 2573 + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 2574 + .mask = BIT(6), 2575 + .slot = 7, 2576 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 2577 + .bit = BIT(6), 2578 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2579 + }, 2580 + { 2581 + .label = "fan8", 2582 + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 2583 + .mask = BIT(7), 2584 + .slot = 8, 2585 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 2586 + .bit = BIT(7), 2587 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2588 + }, 2589 + }; 2590 + 2591 + static struct mlxreg_core_data mlxplat_mlxcpld_xdr_asic1_items_data[] = { 2592 + { 2593 + .label = "asic1", 2594 + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, 2595 + .mask = MLXPLAT_CPLD_ASIC_MASK, 2596 + .slot = 1, 2597 + .capability = MLXPLAT_CPLD_LPC_REG_ASIC_CAP_OFFSET, 2598 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2599 + } 2600 + }; 2601 + 2602 + /* Platform hotplug for smart switch systems families data */ 2603 + static struct mlxreg_core_data mlxplat_mlxcpld_smart_switch_dpu_ready_data[] = { 2604 + { 2605 + .label = "dpu1_ready", 2606 + .reg = MLXPLAT_CPLD_LPC_REG_LC_RD_OFFSET, 2607 + .mask = BIT(0), 2608 + .slot = 1, 2609 + .capability = MLXPLAT_CPLD_LPC_REG_SLOT_QTY_OFFSET, 2610 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2611 + }, 2612 + { 2613 + .label = "dpu2_ready", 2614 + .reg = MLXPLAT_CPLD_LPC_REG_LC_RD_OFFSET, 2615 + .mask = BIT(1), 2616 + .slot = 2, 2617 + .capability = MLXPLAT_CPLD_LPC_REG_SLOT_QTY_OFFSET, 2618 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2619 + }, 2620 + { 2621 + .label = "dpu3_ready", 2622 + .reg = MLXPLAT_CPLD_LPC_REG_LC_RD_OFFSET, 2623 + .mask = BIT(2), 2624 + .slot = 3, 2625 + .capability = MLXPLAT_CPLD_LPC_REG_SLOT_QTY_OFFSET, 2626 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2627 + }, 2628 + { 2629 + .label = "dpu4_ready", 2630 + .reg = MLXPLAT_CPLD_LPC_REG_LC_RD_OFFSET, 2631 + .mask = BIT(3), 2632 + .slot = 4, 2633 + .capability = MLXPLAT_CPLD_LPC_REG_SLOT_QTY_OFFSET, 2634 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2635 + }, 2636 + }; 2637 + 2638 + static struct mlxreg_core_data mlxplat_mlxcpld_smart_switch_dpu_shtdn_ready_data[] = { 2639 + { 2640 + .label = "dpu1_shtdn_ready", 2641 + .reg = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, 2642 + .mask = BIT(0), 2643 + .slot = 1, 2644 + .capability = MLXPLAT_CPLD_LPC_REG_SLOT_QTY_OFFSET, 2645 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2646 + }, 2647 + { 2648 + .label = "dpu2_shtdn_ready", 2649 + .reg = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, 2650 + .mask = BIT(1), 2651 + .slot = 2, 2652 + .capability = MLXPLAT_CPLD_LPC_REG_SLOT_QTY_OFFSET, 2653 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2654 + }, 2655 + { 2656 + .label = "dpu3_shtdn_ready", 2657 + .reg = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, 2658 + .mask = BIT(2), 2659 + .slot = 3, 2660 + .capability = MLXPLAT_CPLD_LPC_REG_SLOT_QTY_OFFSET, 2661 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2662 + }, 2663 + { 2664 + .label = "dpu4_shtdn_ready", 2665 + .reg = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, 2666 + .mask = BIT(3), 2667 + .slot = 4, 2668 + .capability = MLXPLAT_CPLD_LPC_REG_SLOT_QTY_OFFSET, 2669 + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, 2670 + }, 2671 + }; 2672 + 2673 + static struct mlxreg_core_item mlxplat_mlxcpld_smart_switch_items[] = { 2674 + { 2675 + .data = mlxplat_mlxcpld_xdr_psu_items_data, 2676 + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 2677 + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 2678 + .mask = MLXPLAT_CPLD_PSU_XDR_MASK, 2679 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2680 + .count = ARRAY_SIZE(mlxplat_mlxcpld_xdr_psu_items_data), 2681 + .inversed = 1, 2682 + .health = false, 2683 + }, 2684 + { 2685 + .data = mlxplat_mlxcpld_xdr_pwr_items_data, 2686 + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 2687 + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 2688 + .mask = MLXPLAT_CPLD_PWR_XDR_MASK, 2689 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2690 + .count = ARRAY_SIZE(mlxplat_mlxcpld_xdr_pwr_items_data), 2691 + .inversed = 0, 2692 + .health = false, 2693 + }, 2694 + { 2695 + .data = mlxplat_mlxcpld_xdr_fan_items_data, 2696 + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 2697 + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 2698 + .mask = MLXPLAT_CPLD_FAN_XDR_MASK, 2699 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 2700 + .count = ARRAY_SIZE(mlxplat_mlxcpld_xdr_fan_items_data), 2701 + .inversed = 1, 2702 + .health = false, 2703 + }, 2704 + { 2705 + .data = mlxplat_mlxcpld_xdr_asic1_items_data, 2706 + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 2707 + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, 2708 + .mask = MLXPLAT_CPLD_ASIC_XDR_MASK, 2709 + .capability = MLXPLAT_CPLD_LPC_REG_ASIC_CAP_OFFSET, 2710 + .count = ARRAY_SIZE(mlxplat_mlxcpld_xdr_asic1_items_data), 2711 + .inversed = 0, 2712 + .health = true, 2713 + }, 2714 + { 2715 + .data = mlxplat_mlxcpld_smart_switch_dpu_ready_data, 2716 + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_DPU_CORE, 2717 + .reg = MLXPLAT_CPLD_LPC_REG_LC_RD_OFFSET, 2718 + .mask = MLXPLAT_CPLD_DPU_MASK, 2719 + .capability = MLXPLAT_CPLD_LPC_REG_SLOT_QTY_OFFSET, 2720 + .count = ARRAY_SIZE(mlxplat_mlxcpld_smart_switch_dpu_ready_data), 2721 + .inversed = 1, 2722 + .health = false, 2723 + }, 2724 + { 2725 + .data = mlxplat_mlxcpld_smart_switch_dpu_shtdn_ready_data, 2726 + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_DPU_CORE, 2727 + .reg = MLXPLAT_CPLD_LPC_REG_LC_SN_OFFSET, 2728 + .mask = MLXPLAT_CPLD_DPU_MASK, 2729 + .capability = MLXPLAT_CPLD_LPC_REG_SLOT_QTY_OFFSET, 2730 + .count = ARRAY_SIZE(mlxplat_mlxcpld_smart_switch_dpu_shtdn_ready_data), 2731 + .inversed = 1, 2732 + .health = false, 2733 + }, 2734 + }; 2735 + 2736 + static 2737 + struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_smart_switch_data = { 2738 + .items = mlxplat_mlxcpld_smart_switch_items, 2739 + .count = ARRAY_SIZE(mlxplat_mlxcpld_smart_switch_items), 2740 + .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 2741 + .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX | 2742 + MLXPLAT_CPLD_AGGR_MASK_DPU_BRD | MLXPLAT_CPLD_AGGR_MASK_DPU_CORE, 2743 + .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, 2744 + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, 2745 + }; 2746 + 2747 + /* Smart switch data processor units data */ 2748 + static struct i2c_board_info mlxplat_mlxcpld_smart_switch_dpu_devs[] = { 2749 + { 2750 + I2C_BOARD_INFO("mlxreg-dpu", MLXPLAT_CPLD_DPU_ADDR), 2751 + .irq = MLXPLAT_CPLD_LPC_SYSIRQ, 2752 + }, 2753 + { 2754 + I2C_BOARD_INFO("mlxreg-dpu", MLXPLAT_CPLD_DPU_ADDR), 2755 + .irq = MLXPLAT_CPLD_LPC_SYSIRQ, 2756 + }, 2757 + { 2758 + I2C_BOARD_INFO("mlxreg-dpu", MLXPLAT_CPLD_DPU_ADDR), 2759 + .irq = MLXPLAT_CPLD_LPC_SYSIRQ, 2760 + }, 2761 + { 2762 + I2C_BOARD_INFO("mlxreg-dpu", MLXPLAT_CPLD_DPU_ADDR), 2763 + .irq = MLXPLAT_CPLD_LPC_SYSIRQ, 2764 + }, 2765 + }; 2766 + 2767 + static struct mlxreg_core_data mlxplat_mlxcpld_smart_switch_dpu_data[] = { 2768 + { 2769 + .label = "dpu1", 2770 + .hpdev.brdinfo = &mlxplat_mlxcpld_smart_switch_dpu_devs[0], 2771 + .hpdev.nr = MLXPLAT_CPLD_NR_DPU_BASE, 2772 + .slot = 1, 2773 + }, 2774 + { 2775 + .label = "dpu2", 2776 + .hpdev.brdinfo = &mlxplat_mlxcpld_smart_switch_dpu_devs[1], 2777 + .hpdev.nr = MLXPLAT_CPLD_NR_DPU_BASE + 1, 2778 + .slot = 2, 2779 + }, 2780 + { 2781 + .label = "dpu3", 2782 + .hpdev.brdinfo = &mlxplat_mlxcpld_smart_switch_dpu_devs[2], 2783 + .hpdev.nr = MLXPLAT_CPLD_NR_DPU_BASE + 2, 2784 + .slot = 3, 2785 + }, 2786 + { 2787 + .label = "dpu4", 2788 + .hpdev.brdinfo = &mlxplat_mlxcpld_smart_switch_dpu_devs[3], 2789 + .hpdev.nr = MLXPLAT_CPLD_NR_DPU_BASE + 3, 2790 + .slot = 4, 2791 + }, 2425 2792 }; 2426 2793 2427 2794 /* Callback performs graceful shutdown after notification about power button event */ ··· 2993 2518 static 2994 2519 struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_l1_switch_data = { 2995 2520 .items = mlxplat_mlxcpld_l1_switch_events_items, 2996 - .counter = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_events_items), 2521 + .count = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_events_items), 2997 2522 .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 2998 2523 .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX, 2999 2524 .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, 3000 2525 .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW | MLXPLAT_CPLD_LOW_AGGR_MASK_PWR_BUT, 2526 + }; 2527 + 2528 + /* Platform hotplug for 800G systems family data */ 2529 + static struct mlxreg_core_item mlxplat_mlxcpld_ng800_hi171_items[] = { 2530 + { 2531 + .data = mlxplat_mlxcpld_ext_psu_items_data, 2532 + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 2533 + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, 2534 + .mask = MLXPLAT_CPLD_PSU_EXT_MASK, 2535 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2536 + .count = ARRAY_SIZE(mlxplat_mlxcpld_ext_psu_items_data), 2537 + .inversed = 1, 2538 + .health = false, 2539 + }, 2540 + { 2541 + .data = mlxplat_mlxcpld_modular_pwr_items_data, 2542 + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 2543 + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, 2544 + .mask = MLXPLAT_CPLD_PWR_EXT_MASK, 2545 + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, 2546 + .count = ARRAY_SIZE(mlxplat_mlxcpld_ext_pwr_items_data), 2547 + .inversed = 0, 2548 + .health = false, 2549 + }, 2550 + { 2551 + .data = mlxplat_mlxcpld_xdr_fan_items_data, 2552 + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 2553 + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 2554 + .mask = MLXPLAT_CPLD_FAN_XDR_MASK, 2555 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 2556 + .count = ARRAY_SIZE(mlxplat_mlxcpld_xdr_fan_items_data), 2557 + .inversed = 1, 2558 + .health = false, 2559 + }, 2560 + { 2561 + .data = mlxplat_mlxcpld_default_asic_items_data, 2562 + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, 2563 + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, 2564 + .mask = MLXPLAT_CPLD_ASIC_MASK, 2565 + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), 2566 + .inversed = 0, 2567 + .health = true, 2568 + }, 2569 + }; 2570 + 2571 + static 2572 + struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_ng800_hi171_data = { 2573 + .items = mlxplat_mlxcpld_ng800_hi171_items, 2574 + .count = ARRAY_SIZE(mlxplat_mlxcpld_ng800_hi171_items), 2575 + .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, 2576 + .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX, 2577 + .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, 2578 + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW | MLXPLAT_CPLD_LOW_AGGR_MASK_ASIC2, 3001 2579 }; 3002 2580 3003 2581 /* Platform led default data */ ··· 3688 3160 static struct mlxreg_core_platform_data mlxplat_l1_switch_led_data = { 3689 3161 .data = mlxplat_mlxcpld_l1_switch_led_data, 3690 3162 .counter = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_led_data), 3163 + }; 3164 + 3165 + /* Platform led data for XDR and smart switch systems */ 3166 + static struct mlxreg_core_data mlxplat_mlxcpld_xdr_led_data[] = { 3167 + { 3168 + .label = "status:green", 3169 + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, 3170 + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 3171 + }, 3172 + { 3173 + .label = "status:orange", 3174 + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, 3175 + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 3176 + }, 3177 + { 3178 + .label = "psu:green", 3179 + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, 3180 + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 3181 + }, 3182 + { 3183 + .label = "psu:orange", 3184 + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, 3185 + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 3186 + }, 3187 + { 3188 + .label = "fan1:green", 3189 + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, 3190 + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 3191 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3192 + .slot = 1, 3193 + }, 3194 + { 3195 + .label = "fan1:orange", 3196 + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, 3197 + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 3198 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3199 + .slot = 1, 3200 + }, 3201 + { 3202 + .label = "fan2:green", 3203 + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, 3204 + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 3205 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3206 + .slot = 2, 3207 + }, 3208 + { 3209 + .label = "fan2:orange", 3210 + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, 3211 + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 3212 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3213 + .slot = 2, 3214 + }, 3215 + { 3216 + .label = "fan3:green", 3217 + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, 3218 + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 3219 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3220 + .slot = 3, 3221 + }, 3222 + { 3223 + .label = "fan3:orange", 3224 + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, 3225 + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 3226 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3227 + .slot = 3, 3228 + }, 3229 + { 3230 + .label = "fan4:green", 3231 + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, 3232 + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 3233 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3234 + .slot = 4, 3235 + }, 3236 + { 3237 + .label = "fan4:orange", 3238 + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, 3239 + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 3240 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3241 + .slot = 4, 3242 + }, 3243 + { 3244 + .label = "fan5:green", 3245 + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, 3246 + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 3247 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3248 + .slot = 5, 3249 + }, 3250 + { 3251 + .label = "fan5:orange", 3252 + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, 3253 + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 3254 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3255 + .slot = 5, 3256 + }, 3257 + { 3258 + .label = "fan6:green", 3259 + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, 3260 + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 3261 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3262 + .slot = 6, 3263 + }, 3264 + { 3265 + .label = "fan6:orange", 3266 + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, 3267 + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 3268 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3269 + .slot = 6, 3270 + }, 3271 + { 3272 + .label = "fan7:green", 3273 + .reg = MLXPLAT_CPLD_LPC_REG_LED6_OFFSET, 3274 + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 3275 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3276 + .slot = 7, 3277 + }, 3278 + { 3279 + .label = "fan7:orange", 3280 + .reg = MLXPLAT_CPLD_LPC_REG_LED6_OFFSET, 3281 + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 3282 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3283 + .slot = 7, 3284 + }, 3285 + { 3286 + .label = "fan8:green", 3287 + .reg = MLXPLAT_CPLD_LPC_REG_LED7_OFFSET, 3288 + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 3289 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3290 + .slot = 8, 3291 + }, 3292 + { 3293 + .label = "fan8:orange", 3294 + .reg = MLXPLAT_CPLD_LPC_REG_LED7_OFFSET, 3295 + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 3296 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3297 + .slot = 8, 3298 + }, 3299 + { 3300 + .label = "fan9:green", 3301 + .reg = MLXPLAT_CPLD_LPC_REG_LED7_OFFSET, 3302 + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 3303 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3304 + .slot = 9, 3305 + }, 3306 + { 3307 + .label = "fan9:orange", 3308 + .reg = MLXPLAT_CPLD_LPC_REG_LED7_OFFSET, 3309 + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, 3310 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3311 + .slot = 9, 3312 + }, 3313 + { 3314 + .label = "fan10:green", 3315 + .reg = MLXPLAT_CPLD_LPC_REG_LED8_OFFSET, 3316 + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 3317 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3318 + .slot = 10, 3319 + }, 3320 + { 3321 + .label = "fan10:orange", 3322 + .reg = MLXPLAT_CPLD_LPC_REG_LED8_OFFSET, 3323 + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 3324 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 3325 + .slot = 10, 3326 + }, 3327 + { 3328 + .label = "uid:blue", 3329 + .reg = MLXPLAT_CPLD_LPC_REG_LED5_OFFSET, 3330 + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, 3331 + }, 3332 + }; 3333 + 3334 + static struct mlxreg_core_platform_data mlxplat_xdr_led_data = { 3335 + .data = mlxplat_mlxcpld_xdr_led_data, 3336 + .counter = ARRAY_SIZE(mlxplat_mlxcpld_xdr_led_data), 3691 3337 }; 3692 3338 3693 3339 /* Platform register access default */ ··· 4537 3835 .label = "pcie_asic_reset_dis", 4538 3836 .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, 4539 3837 .mask = GENMASK(7, 0) & ~BIT(4), 3838 + .mode = 0644, 3839 + }, 3840 + { 3841 + .label = "shutdown_unlock", 3842 + .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, 3843 + .mask = GENMASK(7, 0) & ~BIT(5), 4540 3844 .mode = 0644, 4541 3845 }, 4542 3846 { ··· 5318 4610 .counter = ARRAY_SIZE(mlxplat_mlxcpld_chassis_blade_regs_io_data), 5319 4611 }; 5320 4612 4613 + /* Platform register access for smart switch systems families data */ 4614 + static struct mlxreg_core_data mlxplat_mlxcpld_smart_switch_regs_io_data[] = { 4615 + { 4616 + .label = "cpld1_version", 4617 + .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET, 4618 + .bit = GENMASK(7, 0), 4619 + .mode = 0444, 4620 + }, 4621 + { 4622 + .label = "cpld2_version", 4623 + .reg = MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET, 4624 + .bit = GENMASK(7, 0), 4625 + .mode = 0444, 4626 + }, 4627 + { 4628 + .label = "cpld3_version", 4629 + .reg = MLXPLAT_CPLD_LPC_REG_CPLD3_VER_OFFSET, 4630 + .bit = GENMASK(7, 0), 4631 + .mode = 0444, 4632 + }, 4633 + { 4634 + .label = "cpld1_pn", 4635 + .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_PN_OFFSET, 4636 + .bit = GENMASK(15, 0), 4637 + .mode = 0444, 4638 + .regnum = 2, 4639 + }, 4640 + { 4641 + .label = "cpld2_pn", 4642 + .reg = MLXPLAT_CPLD_LPC_REG_CPLD2_PN_OFFSET, 4643 + .bit = GENMASK(15, 0), 4644 + .mode = 0444, 4645 + .regnum = 2, 4646 + }, 4647 + { 4648 + .label = "cpld3_pn", 4649 + .reg = MLXPLAT_CPLD_LPC_REG_CPLD3_PN_OFFSET, 4650 + .bit = GENMASK(15, 0), 4651 + .mode = 0444, 4652 + .regnum = 2, 4653 + }, 4654 + { 4655 + .label = "cpld1_version_min", 4656 + .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET, 4657 + .bit = GENMASK(7, 0), 4658 + .mode = 0444, 4659 + }, 4660 + { 4661 + .label = "cpld2_version_min", 4662 + .reg = MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET, 4663 + .bit = GENMASK(7, 0), 4664 + .mode = 0444, 4665 + }, 4666 + { 4667 + .label = "cpld3_version_min", 4668 + .reg = MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET, 4669 + .bit = GENMASK(7, 0), 4670 + .mode = 0444, 4671 + }, 4672 + { 4673 + .label = "kexec_activated", 4674 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP1_OFFSET, 4675 + .mask = GENMASK(7, 0) & ~BIT(1), 4676 + .mode = 0644, 4677 + }, 4678 + { 4679 + .label = "asic_reset", 4680 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET, 4681 + .mask = GENMASK(7, 0) & ~BIT(3), 4682 + .mode = 0644, 4683 + }, 4684 + { 4685 + .label = "eth_switch_reset", 4686 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET, 4687 + .mask = GENMASK(7, 0) & ~BIT(4), 4688 + .mode = 0644, 4689 + }, 4690 + { 4691 + .label = "dpu1_rst", 4692 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP3_OFFSET, 4693 + .mask = GENMASK(7, 0) & ~BIT(0), 4694 + .mode = 0200, 4695 + }, 4696 + { 4697 + .label = "dpu2_rst", 4698 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP3_OFFSET, 4699 + .mask = GENMASK(7, 0) & ~BIT(1), 4700 + .mode = 0200, 4701 + }, 4702 + { 4703 + .label = "dpu3_rst", 4704 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP3_OFFSET, 4705 + .mask = GENMASK(7, 0) & ~BIT(2), 4706 + .mode = 0200, 4707 + }, 4708 + { 4709 + .label = "dpu4_rst", 4710 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP3_OFFSET, 4711 + .mask = GENMASK(7, 0) & ~BIT(3), 4712 + .mode = 0200, 4713 + }, 4714 + { 4715 + .label = "dpu1_pwr", 4716 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, 4717 + .mask = GENMASK(7, 0) & ~BIT(0), 4718 + .mode = 0200, 4719 + }, 4720 + { 4721 + .label = "dpu2_pwr", 4722 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, 4723 + .mask = GENMASK(7, 0) & ~BIT(1), 4724 + .mode = 0200, 4725 + }, 4726 + { 4727 + .label = "dpu3_pwr", 4728 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, 4729 + .mask = GENMASK(7, 0) & ~BIT(2), 4730 + .mode = 0200, 4731 + }, 4732 + { 4733 + .label = "dpu4_pwr", 4734 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET, 4735 + .mask = GENMASK(7, 0) & ~BIT(3), 4736 + .mode = 0200, 4737 + }, 4738 + { 4739 + .label = "reset_long_pb", 4740 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, 4741 + .mask = GENMASK(7, 0) & ~BIT(0), 4742 + .mode = 0444, 4743 + }, 4744 + { 4745 + .label = "reset_short_pb", 4746 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, 4747 + .mask = GENMASK(7, 0) & ~BIT(1), 4748 + .mode = 0444, 4749 + }, 4750 + { 4751 + .label = "reset_aux_pwr_or_ref", 4752 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, 4753 + .mask = GENMASK(7, 0) & ~BIT(2), 4754 + .mode = 0444, 4755 + }, 4756 + { 4757 + .label = "reset_swb_dc_dc_pwr_fail", 4758 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, 4759 + .mask = GENMASK(7, 0) & ~BIT(3), 4760 + .mode = 0444, 4761 + }, 4762 + { 4763 + .label = "reset_swb_wd", 4764 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, 4765 + .mask = GENMASK(7, 0) & ~BIT(6), 4766 + .mode = 0444, 4767 + }, 4768 + { 4769 + .label = "reset_asic_thermal", 4770 + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, 4771 + .mask = GENMASK(7, 0) & ~BIT(7), 4772 + .mode = 0444, 4773 + }, 4774 + { 4775 + .label = "reset_sw_reset", 4776 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, 4777 + .mask = GENMASK(7, 0) & ~BIT(0), 4778 + .mode = 0444, 4779 + }, 4780 + { 4781 + .label = "reset_aux_pwr_or_reload", 4782 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, 4783 + .mask = GENMASK(7, 0) & ~BIT(2), 4784 + .mode = 0444, 4785 + }, 4786 + { 4787 + .label = "reset_comex_pwr_fail", 4788 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, 4789 + .mask = GENMASK(7, 0) & ~BIT(3), 4790 + .mode = 0444, 4791 + }, 4792 + { 4793 + .label = "reset_platform", 4794 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, 4795 + .mask = GENMASK(7, 0) & ~BIT(4), 4796 + .mode = 0444, 4797 + }, 4798 + { 4799 + .label = "reset_soc", 4800 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, 4801 + .mask = GENMASK(7, 0) & ~BIT(5), 4802 + .mode = 0444, 4803 + }, 4804 + { 4805 + .label = "reset_pwr", 4806 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, 4807 + .mask = GENMASK(7, 0) & ~BIT(7), 4808 + .mode = 0444, 4809 + }, 4810 + { 4811 + .label = "reset_pwr_converter_fail", 4812 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, 4813 + .mask = GENMASK(7, 0) & ~BIT(0), 4814 + .mode = 0444, 4815 + }, 4816 + { 4817 + .label = "reset_system", 4818 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, 4819 + .mask = GENMASK(7, 0) & ~BIT(1), 4820 + .mode = 0444, 4821 + }, 4822 + { 4823 + .label = "reset_sw_pwr_off", 4824 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, 4825 + .mask = GENMASK(7, 0) & ~BIT(2), 4826 + .mode = 0444, 4827 + }, 4828 + { 4829 + .label = "reset_comex_thermal", 4830 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, 4831 + .mask = GENMASK(7, 0) & ~BIT(3), 4832 + .mode = 0444, 4833 + }, 4834 + { 4835 + .label = "reset_ac_pwr_fail", 4836 + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, 4837 + .mask = GENMASK(7, 0) & ~BIT(6), 4838 + .mode = 0444, 4839 + }, 4840 + { 4841 + .label = "voltreg_update_status", 4842 + .reg = MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET, 4843 + .mask = MLXPLAT_CPLD_VOLTREG_UPD_MASK, 4844 + .bit = 5, 4845 + .mode = 0444, 4846 + }, 4847 + { 4848 + .label = "port80", 4849 + .reg = MLXPLAT_CPLD_LPC_REG_GP1_RO_OFFSET, 4850 + .bit = GENMASK(7, 0), 4851 + .mode = 0444, 4852 + }, 4853 + { 4854 + .label = "bios_status", 4855 + .reg = MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET, 4856 + .mask = MLXPLAT_CPLD_BIOS_STATUS_MASK, 4857 + .bit = 2, 4858 + .mode = 0444, 4859 + }, 4860 + { 4861 + .label = "bios_start_retry", 4862 + .reg = MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET, 4863 + .mask = GENMASK(7, 0) & ~BIT(4), 4864 + .mode = 0444, 4865 + }, 4866 + { 4867 + .label = "bios_active_image", 4868 + .reg = MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET, 4869 + .mask = GENMASK(7, 0) & ~BIT(5), 4870 + .mode = 0444, 4871 + }, 4872 + { 4873 + .label = "vpd_wp", 4874 + .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, 4875 + .mask = GENMASK(7, 0) & ~BIT(3), 4876 + .mode = 0644, 4877 + }, 4878 + { 4879 + .label = "pcie_asic_reset_dis", 4880 + .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, 4881 + .mask = GENMASK(7, 0) & ~BIT(4), 4882 + .mode = 0644, 4883 + }, 4884 + { 4885 + .label = "shutdown_unlock", 4886 + .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, 4887 + .mask = GENMASK(7, 0) & ~BIT(5), 4888 + .mode = 0644, 4889 + }, 4890 + { 4891 + .label = "fan_dir", 4892 + .reg = MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION, 4893 + .bit = GENMASK(7, 0), 4894 + .mode = 0444, 4895 + }, 4896 + { 4897 + .label = "dpu1_rst_en", 4898 + .reg = MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET, 4899 + .mask = GENMASK(7, 0) & ~BIT(0), 4900 + .mode = 0200, 4901 + }, 4902 + { 4903 + .label = "dpu2_rst_en", 4904 + .reg = MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET, 4905 + .mask = GENMASK(7, 0) & ~BIT(1), 4906 + .mode = 0200, 4907 + }, 4908 + { 4909 + .label = "dpu3_rst_en", 4910 + .reg = MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET, 4911 + .mask = GENMASK(7, 0) & ~BIT(2), 4912 + .mode = 0200, 4913 + }, 4914 + { 4915 + .label = "dpu4_rst_en", 4916 + .reg = MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET, 4917 + .mask = GENMASK(7, 0) & ~BIT(3), 4918 + .mode = 0200, 4919 + }, 4920 + { 4921 + .label = "psu1_on", 4922 + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, 4923 + .mask = GENMASK(7, 0) & ~BIT(0), 4924 + .mode = 0200, 4925 + }, 4926 + { 4927 + .label = "psu2_on", 4928 + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, 4929 + .mask = GENMASK(7, 0) & ~BIT(1), 4930 + .mode = 0200, 4931 + }, 4932 + { 4933 + .label = "pwr_cycle", 4934 + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, 4935 + .mask = GENMASK(7, 0) & ~BIT(2), 4936 + .mode = 0200, 4937 + }, 4938 + { 4939 + .label = "pwr_down", 4940 + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, 4941 + .mask = GENMASK(7, 0) & ~BIT(3), 4942 + .mode = 0200, 4943 + }, 4944 + { 4945 + .label = "jtag_cap", 4946 + .reg = MLXPLAT_CPLD_LPC_REG_FU_CAP_OFFSET, 4947 + .mask = MLXPLAT_CPLD_FU_CAP_MASK, 4948 + .bit = 1, 4949 + .mode = 0444, 4950 + }, 4951 + { 4952 + .label = "jtag_enable", 4953 + .reg = MLXPLAT_CPLD_LPC_REG_FIELD_UPGRADE, 4954 + .mask = GENMASK(1, 0), 4955 + .bit = 1, 4956 + .mode = 0644, 4957 + }, 4958 + { 4959 + .label = "non_active_bios_select", 4960 + .reg = MLXPLAT_CPLD_LPC_SAFE_BIOS_OFFSET, 4961 + .mask = GENMASK(7, 0) & ~BIT(4), 4962 + .mode = 0644, 4963 + }, 4964 + { 4965 + .label = "bios_upgrade_fail", 4966 + .reg = MLXPLAT_CPLD_LPC_SAFE_BIOS_OFFSET, 4967 + .mask = GENMASK(7, 0) & ~BIT(5), 4968 + .mode = 0444, 4969 + }, 4970 + { 4971 + .label = "bios_image_invert", 4972 + .reg = MLXPLAT_CPLD_LPC_SAFE_BIOS_OFFSET, 4973 + .mask = GENMASK(7, 0) & ~BIT(6), 4974 + .mode = 0644, 4975 + }, 4976 + { 4977 + .label = "me_reboot", 4978 + .reg = MLXPLAT_CPLD_LPC_SAFE_BIOS_OFFSET, 4979 + .mask = GENMASK(7, 0) & ~BIT(7), 4980 + .mode = 0644, 4981 + }, 4982 + { 4983 + .label = "dpu1_pwr_force", 4984 + .reg = MLXPLAT_CPLD_LPC_REG_GP3_OFFSET, 4985 + .mask = GENMASK(7, 0) & ~BIT(0), 4986 + .mode = 0200, 4987 + }, 4988 + { 4989 + .label = "dpu2_pwr_force", 4990 + .reg = MLXPLAT_CPLD_LPC_REG_GP3_OFFSET, 4991 + .mask = GENMASK(7, 0) & ~BIT(1), 4992 + .mode = 0200, 4993 + }, 4994 + { 4995 + .label = "dpu3_pwr_force", 4996 + .reg = MLXPLAT_CPLD_LPC_REG_GP3_OFFSET, 4997 + .mask = GENMASK(7, 0) & ~BIT(2), 4998 + .mode = 0200, 4999 + }, 5000 + { 5001 + .label = "dpu4_pwr_force", 5002 + .reg = MLXPLAT_CPLD_LPC_REG_GP3_OFFSET, 5003 + .mask = GENMASK(7, 0) & ~BIT(3), 5004 + .mode = 0200, 5005 + }, 5006 + { 5007 + .label = "ufm_done", 5008 + .reg = MLXPLAT_CPLD_LPC_REG_GPI_MASK_OFFSET, 5009 + .bit = GENMASK(7, 0), 5010 + .mode = 0444, 5011 + }, 5012 + { 5013 + .label = "asic_health", 5014 + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, 5015 + .mask = MLXPLAT_CPLD_ASIC_MASK, 5016 + .bit = 1, 5017 + .mode = 0444, 5018 + }, 5019 + { 5020 + .label = "psu1_ac_ok", 5021 + .reg = MLXPLAT_CPLD_LPC_REG_PSU_AC_OFFSET, 5022 + .mask = GENMASK(7, 0) & ~BIT(0), 5023 + .mode = 0644, 5024 + }, 5025 + { 5026 + .label = "psu2_ac_ok", 5027 + .reg = MLXPLAT_CPLD_LPC_REG_PSU_AC_OFFSET, 5028 + .mask = GENMASK(7, 0) & ~BIT(1), 5029 + .mode = 0644, 5030 + }, 5031 + { 5032 + .label = "psu1_no_alert", 5033 + .reg = MLXPLAT_CPLD_LPC_REG_PSU_ALERT_OFFSET, 5034 + .mask = GENMASK(7, 0) & ~BIT(0), 5035 + .mode = 0644, 5036 + }, 5037 + { 5038 + .label = "psu2_no_alert", 5039 + .reg = MLXPLAT_CPLD_LPC_REG_PSU_ALERT_OFFSET, 5040 + .mask = GENMASK(7, 0) & ~BIT(1), 5041 + .mode = 0644, 5042 + }, 5043 + { 5044 + .label = "asic_pg_fail", 5045 + .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, 5046 + .mask = GENMASK(7, 0) & ~BIT(7), 5047 + .mode = 0444, 5048 + }, 5049 + { 5050 + .label = "spi_chnl_select", 5051 + .reg = MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT, 5052 + .mask = GENMASK(7, 0), 5053 + .bit = 1, 5054 + .mode = 0644, 5055 + }, 5056 + { 5057 + .label = "config1", 5058 + .reg = MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET, 5059 + .bit = GENMASK(7, 0), 5060 + .mode = 0444, 5061 + }, 5062 + { 5063 + .label = "config2", 5064 + .reg = MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET, 5065 + .bit = GENMASK(7, 0), 5066 + .mode = 0444, 5067 + }, 5068 + { 5069 + .label = "config3", 5070 + .reg = MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET, 5071 + .bit = GENMASK(7, 0), 5072 + .mode = 0444, 5073 + }, 5074 + { 5075 + .label = "ufm_version", 5076 + .reg = MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET, 5077 + .bit = GENMASK(7, 0), 5078 + .mode = 0444, 5079 + }, 5080 + }; 5081 + 5082 + static struct mlxreg_core_platform_data mlxplat_smart_switch_regs_io_data = { 5083 + .data = mlxplat_mlxcpld_smart_switch_regs_io_data, 5084 + .counter = ARRAY_SIZE(mlxplat_mlxcpld_smart_switch_regs_io_data), 5085 + }; 5086 + 5321 5087 /* Platform FAN default */ 5322 5088 static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = { 5323 5089 { ··· 5931 4749 .data = mlxplat_mlxcpld_default_fan_data, 5932 4750 .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_fan_data), 5933 4751 .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 4752 + }; 4753 + 4754 + /* XDR and smart switch platform fan data */ 4755 + static struct mlxreg_core_data mlxplat_mlxcpld_xdr_fan_data[] = { 4756 + { 4757 + .label = "pwm1", 4758 + .reg = MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET, 4759 + }, 4760 + { 4761 + .label = "tacho1", 4762 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET, 4763 + .mask = GENMASK(7, 0), 4764 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4765 + .slot = 1, 4766 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 4767 + }, 4768 + { 4769 + .label = "tacho2", 4770 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET, 4771 + .mask = GENMASK(7, 0), 4772 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4773 + .slot = 2, 4774 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 4775 + }, 4776 + { 4777 + .label = "tacho3", 4778 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET, 4779 + .mask = GENMASK(7, 0), 4780 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4781 + .slot = 3, 4782 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 4783 + }, 4784 + { 4785 + .label = "tacho4", 4786 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET, 4787 + .mask = GENMASK(7, 0), 4788 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4789 + .slot = 4, 4790 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 4791 + }, 4792 + { 4793 + .label = "tacho5", 4794 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET, 4795 + .mask = GENMASK(7, 0), 4796 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4797 + .slot = 5, 4798 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 4799 + }, 4800 + { 4801 + .label = "tacho6", 4802 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET, 4803 + .mask = GENMASK(7, 0), 4804 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4805 + .slot = 6, 4806 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 4807 + }, 4808 + { 4809 + .label = "tacho7", 4810 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET, 4811 + .mask = GENMASK(7, 0), 4812 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4813 + .slot = 7, 4814 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 4815 + }, 4816 + { 4817 + .label = "tacho8", 4818 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET, 4819 + .mask = GENMASK(7, 0), 4820 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4821 + .slot = 8, 4822 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 4823 + }, 4824 + { 4825 + .label = "tacho9", 4826 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET, 4827 + .mask = GENMASK(7, 0), 4828 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4829 + .slot = 9, 4830 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 4831 + }, 4832 + { 4833 + .label = "tacho10", 4834 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET, 4835 + .mask = GENMASK(7, 0), 4836 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4837 + .slot = 10, 4838 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 4839 + }, 4840 + { 4841 + .label = "tacho11", 4842 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET, 4843 + .mask = GENMASK(7, 0), 4844 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4845 + .slot = 11, 4846 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 4847 + }, 4848 + { 4849 + .label = "tacho12", 4850 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET, 4851 + .mask = GENMASK(7, 0), 4852 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4853 + .slot = 12, 4854 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 4855 + }, 4856 + { 4857 + .label = "tacho13", 4858 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO13_OFFSET, 4859 + .mask = GENMASK(7, 0), 4860 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4861 + .slot = 13, 4862 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 4863 + }, 4864 + { 4865 + .label = "tacho14", 4866 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO14_OFFSET, 4867 + .mask = GENMASK(7, 0), 4868 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4869 + .slot = 14, 4870 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 4871 + }, 4872 + { 4873 + .label = "tacho15", 4874 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO15_OFFSET, 4875 + .mask = GENMASK(7, 0), 4876 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4877 + .slot = 15, 4878 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 4879 + }, 4880 + { 4881 + .label = "tacho16", 4882 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO16_OFFSET, 4883 + .mask = GENMASK(7, 0), 4884 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4885 + .slot = 16, 4886 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, 4887 + }, 4888 + { 4889 + .label = "tacho17", 4890 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO17_OFFSET, 4891 + .mask = GENMASK(7, 0), 4892 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4893 + .slot = 17, 4894 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN2_OFFSET, 4895 + }, 4896 + { 4897 + .label = "tacho18", 4898 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO18_OFFSET, 4899 + .mask = GENMASK(7, 0), 4900 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4901 + .slot = 18, 4902 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN2_OFFSET, 4903 + }, 4904 + { 4905 + .label = "tacho19", 4906 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO19_OFFSET, 4907 + .mask = GENMASK(7, 0), 4908 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4909 + .slot = 19, 4910 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN2_OFFSET, 4911 + }, 4912 + { 4913 + .label = "tacho20", 4914 + .reg = MLXPLAT_CPLD_LPC_REG_TACHO20_OFFSET, 4915 + .mask = GENMASK(7, 0), 4916 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET, 4917 + .slot = 20, 4918 + .reg_prsnt = MLXPLAT_CPLD_LPC_REG_FAN2_OFFSET, 4919 + }, 4920 + { 4921 + .label = "conf", 4922 + .capability = MLXPLAT_CPLD_LPC_REG_TACHO_SPEED_OFFSET, 4923 + }, 4924 + }; 4925 + 4926 + static struct mlxreg_core_platform_data mlxplat_xdr_fan_data = { 4927 + .data = mlxplat_mlxcpld_xdr_fan_data, 4928 + .counter = ARRAY_SIZE(mlxplat_mlxcpld_xdr_fan_data), 4929 + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, 4930 + .version = 1, 5934 4931 }; 5935 4932 5936 4933 /* Watchdog type1: hardware implementation version1 ··· 6336 4975 { 6337 4976 switch (reg) { 6338 4977 case MLXPLAT_CPLD_LPC_REG_RESET_GP1_OFFSET: 4978 + case MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET: 4979 + case MLXPLAT_CPLD_LPC_REG_RESET_GP3_OFFSET: 6339 4980 case MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET: 6340 4981 case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: 6341 4982 case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: ··· 6346 4983 case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: 6347 4984 case MLXPLAT_CPLD_LPC_REG_LED6_OFFSET: 6348 4985 case MLXPLAT_CPLD_LPC_REG_LED7_OFFSET: 4986 + case MLXPLAT_CPLD_LPC_REG_LED8_OFFSET: 6349 4987 case MLXPLAT_CPLD_LPC_REG_GP0_OFFSET: 6350 4988 case MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET: 6351 4989 case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: 6352 4990 case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET: 6353 4991 case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: 6354 4992 case MLXPLAT_CPLD_LPC_REG_WP2_OFFSET: 4993 + case MLXPLAT_CPLD_LPC_REG_GP3_OFFSET: 6355 4994 case MLXPLAT_CPLD_LPC_REG_FIELD_UPGRADE: 6356 4995 case MLXPLAT_CPLD_LPC_SAFE_BIOS_OFFSET: 6357 4996 case MLXPLAT_CPLD_LPC_SAFE_BIOS_WP_OFFSET: ··· 6377 5012 case MLXPLAT_CPLD_LPC_REG_ASIC2_MASK_OFFSET: 6378 5013 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: 6379 5014 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: 5015 + case MLXPLAT_CPLD_LPC_REG_PSU_AC_OFFSET: 6380 5016 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: 6381 5017 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: 5018 + case MLXPLAT_CPLD_LPC_REG_PSU_ALERT_OFFSET: 6382 5019 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: 6383 5020 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: 5021 + case MLXPLAT_CPLD_LPC_REG_FAN2_EVENT_OFFSET: 5022 + case MLXPLAT_CPLD_LPC_REG_FAN2_MASK_OFFSET: 6384 5023 case MLXPLAT_CPLD_LPC_REG_EROT_EVENT_OFFSET: 6385 5024 case MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET: 6386 5025 case MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET: ··· 6452 5083 case MLXPLAT_CPLD_LPC_REG_CPLD5_PN_OFFSET: 6453 5084 case MLXPLAT_CPLD_LPC_REG_CPLD5_PN1_OFFSET: 6454 5085 case MLXPLAT_CPLD_LPC_REG_RESET_GP1_OFFSET: 5086 + case MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET: 5087 + case MLXPLAT_CPLD_LPC_REG_RESET_GP3_OFFSET: 6455 5088 case MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET: 6456 5089 case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: 6457 5090 case MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET: ··· 6465 5094 case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: 6466 5095 case MLXPLAT_CPLD_LPC_REG_LED6_OFFSET: 6467 5096 case MLXPLAT_CPLD_LPC_REG_LED7_OFFSET: 5097 + case MLXPLAT_CPLD_LPC_REG_LED8_OFFSET: 6468 5098 case MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION: 6469 5099 case MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET: 6470 5100 case MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET: 5101 + case MLXPLAT_CPLD_LPC_REG_GP1_RO_OFFSET: 6471 5102 case MLXPLAT_CPLD_LPC_REG_GP0_OFFSET: 6472 5103 case MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET: 6473 5104 case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: 6474 5105 case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET: 6475 5106 case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: 6476 5107 case MLXPLAT_CPLD_LPC_REG_WP2_OFFSET: 5108 + case MLXPLAT_CPLD_LPC_REG_GP3_OFFSET: 6477 5109 case MLXPLAT_CPLD_LPC_REG_FIELD_UPGRADE: 6478 5110 case MLXPLAT_CPLD_LPC_SAFE_BIOS_OFFSET: 6479 5111 case MLXPLAT_CPLD_LPC_SAFE_BIOS_WP_OFFSET: ··· 6496 5122 case MLXPLAT_CPLD_LPC_REG_GWP_OFFSET: 6497 5123 case MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET: 6498 5124 case MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET: 5125 + case MLXPLAT_CPLD_LPC_REG_GPI_MASK_OFFSET: 6499 5126 case MLXPLAT_CPLD_LPC_REG_BRD_OFFSET: 6500 5127 case MLXPLAT_CPLD_LPC_REG_BRD_EVENT_OFFSET: 6501 5128 case MLXPLAT_CPLD_LPC_REG_BRD_MASK_OFFSET: ··· 6509 5134 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: 6510 5135 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: 6511 5136 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: 5137 + case MLXPLAT_CPLD_LPC_REG_PSU_AC_OFFSET: 6512 5138 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET: 6513 5139 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: 6514 5140 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: 5141 + case MLXPLAT_CPLD_LPC_REG_PSU_ALERT_OFFSET: 6515 5142 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: 6516 5143 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: 6517 5144 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: 5145 + case MLXPLAT_CPLD_LPC_REG_FAN2_OFFSET: 5146 + case MLXPLAT_CPLD_LPC_REG_FAN2_EVENT_OFFSET: 5147 + case MLXPLAT_CPLD_LPC_REG_FAN2_MASK_OFFSET: 6518 5148 case MLXPLAT_CPLD_LPC_REG_EROT_OFFSET: 6519 5149 case MLXPLAT_CPLD_LPC_REG_EROT_EVENT_OFFSET: 6520 5150 case MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET: ··· 6593 5213 case MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET: 6594 5214 case MLXPLAT_CPLD_LPC_REG_TACHO13_OFFSET: 6595 5215 case MLXPLAT_CPLD_LPC_REG_TACHO14_OFFSET: 5216 + case MLXPLAT_CPLD_LPC_REG_TACHO15_OFFSET: 5217 + case MLXPLAT_CPLD_LPC_REG_TACHO16_OFFSET: 5218 + case MLXPLAT_CPLD_LPC_REG_TACHO17_OFFSET: 5219 + case MLXPLAT_CPLD_LPC_REG_TACHO18_OFFSET: 5220 + case MLXPLAT_CPLD_LPC_REG_TACHO19_OFFSET: 5221 + case MLXPLAT_CPLD_LPC_REG_TACHO20_OFFSET: 5222 + case MLXPLAT_CPLD_LPC_REG_ASIC_CAP_OFFSET: 6596 5223 case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: 6597 5224 case MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET: 6598 5225 case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET: ··· 6635 5248 case MLXPLAT_CPLD_LPC_REG_CPLD5_PN_OFFSET: 6636 5249 case MLXPLAT_CPLD_LPC_REG_CPLD5_PN1_OFFSET: 6637 5250 case MLXPLAT_CPLD_LPC_REG_RESET_GP1_OFFSET: 5251 + case MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET: 5252 + case MLXPLAT_CPLD_LPC_REG_RESET_GP3_OFFSET: 6638 5253 case MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET: 6639 5254 case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: 6640 5255 case MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET: ··· 6648 5259 case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: 6649 5260 case MLXPLAT_CPLD_LPC_REG_LED6_OFFSET: 6650 5261 case MLXPLAT_CPLD_LPC_REG_LED7_OFFSET: 5262 + case MLXPLAT_CPLD_LPC_REG_LED8_OFFSET: 6651 5263 case MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION: 6652 5264 case MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET: 6653 5265 case MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET: 5266 + case MLXPLAT_CPLD_LPC_REG_GP1_RO_OFFSET: 6654 5267 case MLXPLAT_CPLD_LPC_REG_GP0_OFFSET: 6655 5268 case MLXPLAT_CPLD_LPC_REG_GP_RST_OFFSET: 6656 5269 case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: 6657 5270 case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: 5271 + case MLXPLAT_CPLD_LPC_REG_GP3_OFFSET: 6658 5272 case MLXPLAT_CPLD_LPC_REG_FIELD_UPGRADE: 6659 5273 case MLXPLAT_CPLD_LPC_SAFE_BIOS_OFFSET: 6660 5274 case MLXPLAT_CPLD_LPC_SAFE_BIOS_WP_OFFSET: ··· 6677 5285 case MLXPLAT_CPLD_LPC_REG_GWP_OFFSET: 6678 5286 case MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET: 6679 5287 case MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET: 5288 + case MLXPLAT_CPLD_LPC_REG_GPI_MASK_OFFSET: 6680 5289 case MLXPLAT_CPLD_LPC_REG_BRD_OFFSET: 6681 5290 case MLXPLAT_CPLD_LPC_REG_BRD_EVENT_OFFSET: 6682 5291 case MLXPLAT_CPLD_LPC_REG_BRD_MASK_OFFSET: ··· 6690 5297 case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: 6691 5298 case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: 6692 5299 case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: 5300 + case MLXPLAT_CPLD_LPC_REG_PSU_AC_OFFSET: 6693 5301 case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET: 6694 5302 case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: 6695 5303 case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: 5304 + case MLXPLAT_CPLD_LPC_REG_PSU_ALERT_OFFSET: 6696 5305 case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: 6697 5306 case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: 6698 5307 case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: ··· 6765 5370 case MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET: 6766 5371 case MLXPLAT_CPLD_LPC_REG_TACHO13_OFFSET: 6767 5372 case MLXPLAT_CPLD_LPC_REG_TACHO14_OFFSET: 5373 + case MLXPLAT_CPLD_LPC_REG_TACHO15_OFFSET: 5374 + case MLXPLAT_CPLD_LPC_REG_TACHO16_OFFSET: 5375 + case MLXPLAT_CPLD_LPC_REG_TACHO17_OFFSET: 5376 + case MLXPLAT_CPLD_LPC_REG_TACHO18_OFFSET: 5377 + case MLXPLAT_CPLD_LPC_REG_TACHO19_OFFSET: 5378 + case MLXPLAT_CPLD_LPC_REG_TACHO20_OFFSET: 5379 + case MLXPLAT_CPLD_LPC_REG_ASIC_CAP_OFFSET: 6768 5380 case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: 6769 5381 case MLXPLAT_CPLD_LPC_REG_FAN_CAP1_OFFSET: 6770 5382 case MLXPLAT_CPLD_LPC_REG_FAN_CAP2_OFFSET: ··· 6831 5429 { MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, 0x00 }, 6832 5430 { MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET, 6833 5431 MLXPLAT_CPLD_AGGR_MASK_LC_LOW }, 5432 + }; 5433 + 5434 + static const struct reg_default mlxplat_mlxcpld_regmap_smart_switch[] = { 5435 + { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, 5436 + { MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET, 0x00 }, 5437 + { MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, 0x00 }, 5438 + { MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, 0x00 }, 5439 + { MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET, MLXPLAT_CPLD_LPC_SM_SW_MASK }, 6834 5440 }; 6835 5441 6836 5442 struct mlxplat_mlxcpld_regmap_context { ··· 6949 5539 .reg_write = mlxplat_mlxcpld_reg_write, 6950 5540 }; 6951 5541 5542 + static const struct regmap_config mlxplat_mlxcpld_regmap_config_smart_switch = { 5543 + .reg_bits = 8, 5544 + .val_bits = 8, 5545 + .max_register = 255, 5546 + .cache_type = REGCACHE_FLAT, 5547 + .writeable_reg = mlxplat_mlxcpld_writeable_reg, 5548 + .readable_reg = mlxplat_mlxcpld_readable_reg, 5549 + .volatile_reg = mlxplat_mlxcpld_volatile_reg, 5550 + .reg_defaults = mlxplat_mlxcpld_regmap_smart_switch, 5551 + .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_smart_switch), 5552 + .reg_read = mlxplat_mlxcpld_reg_read, 5553 + .reg_write = mlxplat_mlxcpld_reg_write, 5554 + }; 5555 + 6952 5556 static struct resource mlxplat_mlxcpld_resources[] = { 6953 5557 [0] = DEFINE_RES_IRQ_NAMED(MLXPLAT_CPLD_LPC_SYSIRQ, "mlxreg-hotplug"), 6954 5558 }; ··· 6974 5550 static struct mlxreg_core_platform_data *mlxplat_fan; 6975 5551 static struct mlxreg_core_platform_data 6976 5552 *mlxplat_wd_data[MLXPLAT_CPLD_WD_MAX_DEVS]; 5553 + static struct mlxreg_core_data *mlxplat_dpu_data[MLXPLAT_CPLD_DPU_MAX_DEVS]; 6977 5554 static const struct regmap_config *mlxplat_regmap_config; 6978 5555 static struct pci_dev *lpc_bridge; 6979 5556 static struct pci_dev *i2c_bridge; ··· 7346 5921 return mlxplat_register_platform_device(); 7347 5922 } 7348 5923 5924 + static int __init mlxplat_dmi_smart_switch_matched(const struct dmi_system_id *dmi) 5925 + { 5926 + int i; 5927 + 5928 + mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; 5929 + mlxplat_mux_num = ARRAY_SIZE(mlxplat_ng800_mux_data); 5930 + mlxplat_mux_data = mlxplat_ng800_mux_data; 5931 + mlxplat_hotplug = &mlxplat_mlxcpld_smart_switch_data; 5932 + mlxplat_hotplug->deferred_nr = 5933 + mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; 5934 + mlxplat_led = &mlxplat_xdr_led_data; 5935 + mlxplat_regs_io = &mlxplat_smart_switch_regs_io_data; 5936 + mlxplat_fan = &mlxplat_xdr_fan_data; 5937 + 5938 + for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++) 5939 + mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i]; 5940 + for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_smart_switch_dpu_data); i++) 5941 + mlxplat_dpu_data[i] = &mlxplat_mlxcpld_smart_switch_dpu_data[i]; 5942 + 5943 + mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; 5944 + mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_smart_switch; 5945 + 5946 + return mlxplat_register_platform_device(); 5947 + } 5948 + 5949 + static int __init mlxplat_dmi_ng400_hi171_matched(const struct dmi_system_id *dmi) 5950 + { 5951 + unsigned int i; 5952 + 5953 + mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; 5954 + mlxplat_mux_num = ARRAY_SIZE(mlxplat_ng800_mux_data); 5955 + mlxplat_mux_data = mlxplat_ng800_mux_data; 5956 + mlxplat_hotplug = &mlxplat_mlxcpld_ng800_hi171_data; 5957 + mlxplat_hotplug->deferred_nr = 5958 + mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; 5959 + mlxplat_led = &mlxplat_default_ng_led_data; 5960 + mlxplat_regs_io = &mlxplat_default_ng_regs_io_data; 5961 + mlxplat_fan = &mlxplat_xdr_fan_data; 5962 + 5963 + for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type3); i++) 5964 + mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type3[i]; 5965 + 5966 + mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; 5967 + mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_ng400; 5968 + 5969 + return mlxplat_register_platform_device(); 5970 + } 5971 + 7349 5972 static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { 7350 5973 { 7351 5974 .callback = mlxplat_dmi_default_wc_matched, ··· 7486 6013 .callback = mlxplat_dmi_l1_switch_matched, 7487 6014 .matches = { 7488 6015 DMI_MATCH(DMI_BOARD_NAME, "VMOD0017"), 6016 + }, 6017 + }, 6018 + { 6019 + .callback = mlxplat_dmi_smart_switch_matched, 6020 + .matches = { 6021 + DMI_MATCH(DMI_BOARD_NAME, "VMOD0019"), 6022 + }, 6023 + }, 6024 + { 6025 + .callback = mlxplat_dmi_ng400_hi171_matched, 6026 + .matches = { 6027 + DMI_MATCH(DMI_BOARD_NAME, "VMOD0022"), 6028 + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "HI171"), 6029 + }, 6030 + }, 6031 + { 6032 + .callback = mlxplat_dmi_ng400_hi171_matched, 6033 + .matches = { 6034 + DMI_MATCH(DMI_BOARD_NAME, "VMOD0022"), 6035 + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "HI172"), 7489 6036 }, 7490 6037 }, 7491 6038 { ··· 7883 6390 } 7884 6391 } 7885 6392 6393 + /* Add DPU drivers. */ 6394 + for (i = 0; i < MLXPLAT_CPLD_DPU_MAX_DEVS; i++) { 6395 + if (!mlxplat_dpu_data[i]) 6396 + continue; 6397 + priv->pdev_dpu[i] = 6398 + platform_device_register_resndata(&mlxplat_dev->dev, "mlxreg-dpu", 6399 + i, NULL, 0, mlxplat_dpu_data[i], 6400 + sizeof(*mlxplat_dpu_data[i])); 6401 + if (IS_ERR(priv->pdev_dpu[i])) { 6402 + err = PTR_ERR(priv->pdev_dpu[i]); 6403 + goto fail_platform_dpu_register; 6404 + } 6405 + } 6406 + 7886 6407 return 0; 7887 6408 6409 + fail_platform_dpu_register: 6410 + while (i--) 6411 + platform_device_unregister(priv->pdev_dpu[i]); 7888 6412 fail_platform_wd_register: 7889 - while (--i >= 0) 6413 + while (i--) 7890 6414 platform_device_unregister(priv->pdev_wd[i]); 7891 6415 fail_platform_fan_register: 7892 6416 if (mlxplat_regs_io) ··· 7922 6412 { 7923 6413 int i; 7924 6414 7925 - for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--) 6415 + for (i = MLXPLAT_CPLD_DPU_MAX_DEVS - 1; i >= 0; i--) 6416 + platform_device_unregister(priv->pdev_dpu[i]); 6417 + for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0; i--) 7926 6418 platform_device_unregister(priv->pdev_wd[i]); 7927 6419 if (priv->pdev_fan) 7928 6420 platform_device_unregister(priv->pdev_fan); ··· 7969 6457 return mlxplat_i2c_mux_complition_notify(priv, NULL, NULL); 7970 6458 7971 6459 fail_platform_mux_register: 7972 - while (--i >= 0) 6460 + while (i--) 7973 6461 platform_device_unregister(priv->pdev_mux[i]); 7974 6462 return err; 7975 6463 } ··· 7978 6466 { 7979 6467 int i; 7980 6468 7981 - for (i = mlxplat_mux_num - 1; i >= 0 ; i--) { 6469 + for (i = mlxplat_mux_num - 1; i >= 0; i--) { 7982 6470 if (priv->pdev_mux[i]) 7983 6471 platform_device_unregister(priv->pdev_mux[i]); 7984 6472 }
+150 -5
drivers/platform/mellanox/mlxbf-pmc.c
··· 33 33 #define MLXBF_PMC_EVENT_SET_BF3 2 34 34 #define MLXBF_PMC_EVENT_INFO_LEN 100 35 35 36 - #define MLXBF_PMC_MAX_BLOCKS 30 36 + #define MLXBF_PMC_MAX_BLOCKS 40 37 37 #define MLXBF_PMC_MAX_ATTRS 70 38 38 #define MLXBF_PMC_INFO_SZ 4 39 39 #define MLXBF_PMC_REG_SIZE 8 ··· 139 139 * @pdev: The kernel structure representing the device 140 140 * @total_blocks: Total number of blocks 141 141 * @tile_count: Number of tiles in the system 142 + * @apt_enable: Info on enabled APTs 142 143 * @llt_enable: Info on enabled LLTs 143 144 * @mss_enable: Info on enabled MSSs 144 145 * @group_num: Group number assigned to each valid block ··· 155 154 struct platform_device *pdev; 156 155 u32 total_blocks; 157 156 u32 tile_count; 157 + u8 apt_enable; 158 158 u8 llt_enable; 159 159 u8 mss_enable; 160 160 u32 group_num; ··· 895 893 { 0x6c, "REFERENCE_WINDOW_WIDTH_REF_156" }, 896 894 }; 897 895 896 + static const struct mlxbf_pmc_events mlxbf_pmc_gga_events[] = { 897 + { 0, "GGA_PERF_DESC_WQE_STRB" }, 898 + { 5, "GGA_PERF_DESC_CQE_STRB" }, 899 + { 8, "GGA_PERF_DESC_TPT_REQUEST_STRB" }, 900 + { 17, "GGA_PERF_DESC_TPT_RESPONSESTRB" }, 901 + { 120, "GGA_PERF_DESC_ENGINE0_IN_DATA_STRB" }, 902 + { 121, "GGA_PERF_DESC_ENGINE1_IN_DATA_STRB" }, 903 + { 122, "GGA_PERF_DESC_ENGINE2_IN_DATA_STRB" }, 904 + { 123, "GGA_PERF_DESC_ENGINE3_IN_DATA_STRB" }, 905 + { 124, "GGA_PERF_DESC_ENGINE4_IN_DATA_STRB" }, 906 + { 125, "GGA_PERF_DESC_ENGINE5_IN_DATA_STRB" }, 907 + { 126, "GGA_PERF_DESC_ENGINE6_IN_DATA_STRB" }, 908 + { 127, "GGA_PERF_DESC_ENGINE7_IN_DATA_STRB" }, 909 + { 128, "GGA_PERF_DESC_ENGINE8_IN_DATA_STRB" }, 910 + { 129, "GGA_PERF_DESC_ENGINE9_IN_DATA_STRB" }, 911 + { 130, "GGA_PERF_DESC_ENGINE10_IN_DATA_STRB" }, 912 + { 131, "GGA_PERF_DESC_ENGINE11_IN_DATA_STRB" }, 913 + { 132, "GGA_PERF_DESC_ENGINE12_IN_DATA_STRB" }, 914 + { 133, "GGA_PERF_DESC_ENGINE13_IN_DATA_STRB" }, 915 + { 134, "GGA_PERF_DESC_ENGINE14_IN_DATA_STRB" }, 916 + { 195, "GGA_PERF_DESC_ENGINE0_OUT_DATA_STRB" }, 917 + { 196, "GGA_PERF_DESC_ENGINE1_OUT_DATA_STRB" }, 918 + { 197, "GGA_PERF_DESC_ENGINE2_OUT_DATA_STRB" }, 919 + { 198, "GGA_PERF_DESC_ENGINE3_OUT_DATA_STRB" }, 920 + { 199, "GGA_PERF_DESC_ENGINE4_OUT_DATA_STRB" }, 921 + { 200, "GGA_PERF_DESC_ENGINE5_OUT_DATA_STRB" }, 922 + { 201, "GGA_PERF_DESC_ENGINE6_OUT_DATA_STRB" }, 923 + { 202, "GGA_PERF_DESC_ENGINE7_OUT_DATA_STRB" }, 924 + { 203, "GGA_PERF_DESC_ENGINE8_OUT_DATA_STRB" }, 925 + { 204, "GGA_PERF_DESC_ENGINE9_OUT_DATA_STRB" }, 926 + { 205, "GGA_PERF_DESC_ENGINE10_OUT_DATA_STRB" }, 927 + { 206, "GGA_PERF_DESC_ENGINE11_OUT_DATA_STRB" }, 928 + { 207, "GGA_PERF_DESC_ENGINE12_OUT_DATA_STRB" }, 929 + { 208, "GGA_PERF_DESC_ENGINE13_OUT_DATA_STRB" }, 930 + { 209, "GGA_PERF_DESC_ENGINE14_OUT_DATA_STRB" }, 931 + }; 932 + 933 + static const struct mlxbf_pmc_events mlxbf_pmc_apt_events[] = { 934 + { 0, "APT_DATA_0" }, 935 + { 1, "APT_DATA_1" }, 936 + { 2, "APT_DATA_2" }, 937 + { 3, "APT_DATA_3" }, 938 + { 4, "APT_DATA_4" }, 939 + { 5, "APT_DATA_5" }, 940 + { 6, "APT_DATA_6" }, 941 + { 7, "APT_DATA_7" }, 942 + { 8, "APT_DATA_8" }, 943 + { 9, "APT_DATA_9" }, 944 + { 10, "APT_DATA_10" }, 945 + { 11, "APT_DATA_11" }, 946 + { 12, "APT_DATA_12" }, 947 + { 13, "APT_DATA_13" }, 948 + { 14, "APT_DATA_14" }, 949 + { 15, "APT_DATA_15" }, 950 + { 16, "APT_DATA_16" }, 951 + { 17, "APT_DATA_17" }, 952 + { 18, "APT_DATA_18" }, 953 + { 19, "APT_DATA_19" }, 954 + { 20, "APT_DATA_20" }, 955 + { 21, "APT_DATA_21" }, 956 + }; 957 + 958 + static const struct mlxbf_pmc_events mlxbf_pmc_emi_events[] = { 959 + { 0, "MCH_WR_IN_MCH_REQ_IN_STRB" }, 960 + { 10, "MCH_RD_IN_MCH_REQ_IN_STRB" }, 961 + { 20, "MCH_RD_RESP_DATA_MCH_RESP_OUT_STRB" }, 962 + { 98, "EMI_ARBITER_EARB2CTRL_STRB" }, 963 + { 99, "EMI_ARBITER_EARB2CTRL_RAS_STRB" }, 964 + { 100, "EMI_ARBITER_EARB2CTRL_CAS_STRB" }, 965 + }; 966 + 967 + static const struct mlxbf_pmc_events mlxbf_pmc_prnf_events[] = { 968 + { 0, "PRNF_DMA_RD_TLP_REQ" }, 969 + { 1, "PRNF_DMA_RD_ICMC_BYPASS_REQ" }, 970 + { 8, "PRNF_DMA_RD_TLP_SENT_TO_CHI" }, 971 + { 11, "PRNF_DMA_RD_CHI_RES" }, 972 + { 17, "PRNF_DMA_RD_TLP_RES_SENT" }, 973 + { 18, "PRNF_DMA_WR_WR0_SLICE_ALLOC_RO" }, 974 + { 19, "PRNF_DMA_WR_WR0_SLICE_ALLOC_NRO" }, 975 + { 24, "PRNF_DMA_WR_WR1_SLICE_ALLOC_RO" }, 976 + { 25, "PRNF_DMA_WR_WR1_SLICE_ALLOC_NRO" }, 977 + { 30, "PRNF_PIO_POSTED_REQ_PUSH" }, 978 + { 31, "PRNF_PIO_POSTED_REQ_POP" }, 979 + { 32, "PRNF_PIO_NP_REQ_PUSH" }, 980 + { 33, "PRNF_PIO_NP_REQ_POP" }, 981 + { 34, "PRNF_PIO_COMP_RO_PUSH" }, 982 + { 35, "PRNF_PIO_COMP_RO_POP" }, 983 + { 36, "PRNF_PIO_COMP_NRO_PUSH" }, 984 + { 37, "PRNF_PIO_COMP_NRO_POP" }, 985 + }; 986 + 987 + static const struct mlxbf_pmc_events mlxbf_pmc_msn_events[] = { 988 + { 46, "MSN_CORE_MMA_WQE_DONE_PUSH_STRB" }, 989 + { 116, "MSN_CORE_MSN2MMA_WQE_STRB" }, 990 + { 164, "MSN_CORE_WQE_TOP_TILE_WQE_STRB" }, 991 + { 168, "MSN_CORE_TPT_TOP_GGA_REQ_STRB" }, 992 + { 171, "MSN_CORE_TPT_TOP_MMA_REQ_STRB" }, 993 + { 174, "MSN_CORE_TPT_TOP_GGA_RES_STRB" }, 994 + { 177, "MSN_CORE_TPT_TOP_MMA_RES_STRB" }, 995 + }; 996 + 898 997 static struct mlxbf_pmc_context *pmc; 899 998 900 999 /* UUID used to probe ATF service. */ ··· 1172 1069 } else if (strstr(blk, "clock_measure")) { 1173 1070 events = mlxbf_pmc_clock_events; 1174 1071 size = ARRAY_SIZE(mlxbf_pmc_clock_events); 1072 + } else if (strstr(blk, "gga")) { 1073 + events = mlxbf_pmc_gga_events; 1074 + size = ARRAY_SIZE(mlxbf_pmc_gga_events); 1075 + } else if (strstr(blk, "apt")) { 1076 + events = mlxbf_pmc_apt_events; 1077 + size = ARRAY_SIZE(mlxbf_pmc_apt_events); 1078 + } else if (strstr(blk, "emi")) { 1079 + events = mlxbf_pmc_emi_events; 1080 + size = ARRAY_SIZE(mlxbf_pmc_emi_events); 1081 + } else if (strstr(blk, "prnf")) { 1082 + events = mlxbf_pmc_prnf_events; 1083 + size = ARRAY_SIZE(mlxbf_pmc_prnf_events); 1084 + } else if (strstr(blk, "msn")) { 1085 + events = mlxbf_pmc_msn_events; 1086 + size = ARRAY_SIZE(mlxbf_pmc_msn_events); 1175 1087 } else { 1176 1088 events = NULL; 1177 1089 size = 0; ··· 2174 2056 continue; 2175 2057 } 2176 2058 2059 + /* Create sysfs only for enabled EMI blocks */ 2060 + if (strstr(pmc->block_name[i], "emi") && 2061 + pmc->event_set == MLXBF_PMC_EVENT_SET_BF3) { 2062 + unsigned int emi_num; 2063 + 2064 + if (sscanf(pmc->block_name[i], "emi%u", &emi_num) != 1) 2065 + continue; 2066 + 2067 + if (!((pmc->mss_enable >> (emi_num / 2)) & 0x1)) 2068 + continue; 2069 + } 2070 + 2177 2071 /* Create sysfs only for enabled LLT blocks */ 2178 2072 if (strstr(pmc->block_name[i], "llt_miss")) { 2179 2073 unsigned int llt_num; ··· 2202 2072 continue; 2203 2073 2204 2074 if (!((pmc->llt_enable >> llt_num) & 0x1)) 2075 + continue; 2076 + } 2077 + 2078 + /* Create sysfs only for enabled APT blocks */ 2079 + if (strstr(pmc->block_name[i], "apt")) { 2080 + unsigned int apt_num; 2081 + 2082 + if (sscanf(pmc->block_name[i], "apt%u", &apt_num) != 1) 2083 + continue; 2084 + 2085 + if (!((pmc->apt_enable >> apt_num) & 0x1)) 2205 2086 continue; 2206 2087 } 2207 2088 ··· 2312 2171 return -EFAULT; 2313 2172 2314 2173 if (device_property_read_u32(dev, "tile_num", &pmc->tile_count)) { 2174 + if (device_property_read_u8(dev, "apt_enable", &pmc->apt_enable)) { 2175 + dev_warn(dev, "Number of APTs undefined, ignoring blocks\n"); 2176 + pmc->apt_enable = 0; 2177 + } 2315 2178 if (device_property_read_u8(dev, "llt_enable", &pmc->llt_enable)) { 2316 - dev_err(dev, "Number of tiles/LLTs undefined\n"); 2317 - return -EINVAL; 2179 + dev_warn(dev, "Number of LLTs undefined, ignoring blocks\n"); 2180 + pmc->llt_enable = 0; 2318 2181 } 2319 2182 if (device_property_read_u8(dev, "mss_enable", &pmc->mss_enable)) { 2320 - dev_err(dev, "Number of tiles/MSSs undefined\n"); 2321 - return -EINVAL; 2183 + dev_warn(dev, "Number of MSSs undefined, ignoring blocks\n"); 2184 + pmc->mss_enable = 0; 2322 2185 } 2323 2186 } 2324 2187
+613
drivers/platform/mellanox/mlxreg-dpu.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Nvidia Data Processor Unit platform driver 4 + * 5 + * Copyright (C) 2025 Nvidia Technologies Ltd. 6 + */ 7 + 8 + #include <linux/device.h> 9 + #include <linux/dev_printk.h> 10 + #include <linux/i2c.h> 11 + #include <linux/module.h> 12 + #include <linux/platform_data/mlxcpld.h> 13 + #include <linux/platform_data/mlxreg.h> 14 + #include <linux/platform_device.h> 15 + #include <linux/regmap.h> 16 + 17 + /* I2C bus IO offsets */ 18 + #define MLXREG_DPU_REG_FPGA1_VER_OFFSET 0x2400 19 + #define MLXREG_DPU_REG_FPGA1_PN_OFFSET 0x2404 20 + #define MLXREG_DPU_REG_FPGA1_PN1_OFFSET 0x2405 21 + #define MLXREG_DPU_REG_PG_OFFSET 0x2414 22 + #define MLXREG_DPU_REG_PG_EVENT_OFFSET 0x2415 23 + #define MLXREG_DPU_REG_PG_MASK_OFFSET 0x2416 24 + #define MLXREG_DPU_REG_RESET_GP1_OFFSET 0x2417 25 + #define MLXREG_DPU_REG_RST_CAUSE1_OFFSET 0x241e 26 + #define MLXREG_DPU_REG_GP0_RO_OFFSET 0x242b 27 + #define MLXREG_DPU_REG_GP0_OFFSET 0x242e 28 + #define MLXREG_DPU_REG_GP1_OFFSET 0x242c 29 + #define MLXREG_DPU_REG_GP4_OFFSET 0x2438 30 + #define MLXREG_DPU_REG_AGGRCO_OFFSET 0x2442 31 + #define MLXREG_DPU_REG_AGGRCO_MASK_OFFSET 0x2443 32 + #define MLXREG_DPU_REG_HEALTH_OFFSET 0x244d 33 + #define MLXREG_DPU_REG_HEALTH_EVENT_OFFSET 0x244e 34 + #define MLXREG_DPU_REG_HEALTH_MASK_OFFSET 0x244f 35 + #define MLXREG_DPU_REG_FPGA1_MVER_OFFSET 0x24de 36 + #define MLXREG_DPU_REG_CONFIG3_OFFSET 0x24fd 37 + #define MLXREG_DPU_REG_MAX 0x3fff 38 + 39 + /* Power Good event masks. */ 40 + #define MLXREG_DPU_PG_VDDIO_MASK BIT(0) 41 + #define MLXREG_DPU_PG_VDD_CPU_MASK BIT(1) 42 + #define MLXREG_DPU_PG_VDD_MASK BIT(2) 43 + #define MLXREG_DPU_PG_1V8_MASK BIT(3) 44 + #define MLXREG_DPU_PG_COMPARATOR_MASK BIT(4) 45 + #define MLXREG_DPU_PG_VDDQ_MASK BIT(5) 46 + #define MLXREG_DPU_PG_HVDD_MASK BIT(6) 47 + #define MLXREG_DPU_PG_DVDD_MASK BIT(7) 48 + #define MLXREG_DPU_PG_MASK (MLXREG_DPU_PG_DVDD_MASK | \ 49 + MLXREG_DPU_PG_HVDD_MASK | \ 50 + MLXREG_DPU_PG_VDDQ_MASK | \ 51 + MLXREG_DPU_PG_COMPARATOR_MASK | \ 52 + MLXREG_DPU_PG_1V8_MASK | \ 53 + MLXREG_DPU_PG_VDD_CPU_MASK | \ 54 + MLXREG_DPU_PG_VDD_MASK | \ 55 + MLXREG_DPU_PG_VDDIO_MASK) 56 + 57 + /* Health event masks. */ 58 + #define MLXREG_DPU_HLTH_THERMAL_TRIP_MASK BIT(0) 59 + #define MLXREG_DPU_HLTH_UFM_UPGRADE_DONE_MASK BIT(1) 60 + #define MLXREG_DPU_HLTH_VDDQ_HOT_ALERT_MASK BIT(2) 61 + #define MLXREG_DPU_HLTH_VDD_CPU_HOT_ALERT_MASK BIT(3) 62 + #define MLXREG_DPU_HLTH_VDDQ_ALERT_MASK BIT(4) 63 + #define MLXREG_DPU_HLTH_VDD_CPU_ALERT_MASK BIT(5) 64 + #define MLXREG_DPU_HEALTH_MASK (MLXREG_DPU_HLTH_UFM_UPGRADE_DONE_MASK | \ 65 + MLXREG_DPU_HLTH_VDDQ_HOT_ALERT_MASK | \ 66 + MLXREG_DPU_HLTH_VDD_CPU_HOT_ALERT_MASK | \ 67 + MLXREG_DPU_HLTH_VDDQ_ALERT_MASK | \ 68 + MLXREG_DPU_HLTH_VDD_CPU_ALERT_MASK | \ 69 + MLXREG_DPU_HLTH_THERMAL_TRIP_MASK) 70 + 71 + /* Hotplug aggregation masks. */ 72 + #define MLXREG_DPU_HEALTH_AGGR_MASK BIT(0) 73 + #define MLXREG_DPU_PG_AGGR_MASK BIT(1) 74 + #define MLXREG_DPU_AGGR_MASK (MLXREG_DPU_HEALTH_AGGR_MASK | \ 75 + MLXREG_DPU_PG_AGGR_MASK) 76 + 77 + /* Voltage regulator firmware update status mask. */ 78 + #define MLXREG_DPU_VOLTREG_UPD_MASK GENMASK(5, 4) 79 + 80 + #define MLXREG_DPU_NR_NONE (-1) 81 + 82 + /* 83 + * enum mlxreg_dpu_type - Data Processor Unit types 84 + * 85 + * @MLXREG_DPU_BF3: DPU equipped with BF3 SoC; 86 + */ 87 + enum mlxreg_dpu_type { 88 + MLXREG_DPU_BF3 = 0x0050, 89 + }; 90 + 91 + /* Default register access data. */ 92 + static struct mlxreg_core_data mlxreg_dpu_io_data[] = { 93 + { 94 + .label = "fpga1_version", 95 + .reg = MLXREG_DPU_REG_FPGA1_VER_OFFSET, 96 + .bit = GENMASK(7, 0), 97 + .mode = 0444, 98 + }, 99 + { 100 + .label = "fpga1_pn", 101 + .reg = MLXREG_DPU_REG_FPGA1_PN_OFFSET, 102 + .bit = GENMASK(15, 0), 103 + .mode = 0444, 104 + .regnum = 2, 105 + }, 106 + { 107 + .label = "fpga1_version_min", 108 + .reg = MLXREG_DPU_REG_FPGA1_MVER_OFFSET, 109 + .bit = GENMASK(7, 0), 110 + .mode = 0444, 111 + }, 112 + { 113 + .label = "perst_rst", 114 + .reg = MLXREG_DPU_REG_RESET_GP1_OFFSET, 115 + .mask = GENMASK(7, 0) & ~BIT(0), 116 + .mode = 0644, 117 + }, 118 + { 119 + .label = "usbphy_rst", 120 + .reg = MLXREG_DPU_REG_RESET_GP1_OFFSET, 121 + .mask = GENMASK(7, 0) & ~BIT(1), 122 + .mode = 0644, 123 + }, 124 + { 125 + .label = "phy_rst", 126 + .reg = MLXREG_DPU_REG_RESET_GP1_OFFSET, 127 + .mask = GENMASK(7, 0) & ~BIT(2), 128 + .mode = 0644, 129 + }, 130 + { 131 + .label = "tpm_rst", 132 + .reg = MLXREG_DPU_REG_RESET_GP1_OFFSET, 133 + .mask = GENMASK(7, 0) & ~BIT(6), 134 + .mode = 0644, 135 + }, 136 + { 137 + .label = "reset_from_main_board", 138 + .reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET, 139 + .mask = GENMASK(7, 0) & ~BIT(1), 140 + .mode = 0444, 141 + }, 142 + { 143 + .label = "reset_aux_pwr_or_reload", 144 + .reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET, 145 + .mask = GENMASK(7, 0) & ~BIT(2), 146 + .mode = 0444, 147 + }, 148 + { 149 + .label = "reset_comex_pwr_fail", 150 + .reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET, 151 + .mask = GENMASK(7, 0) & ~BIT(3), 152 + .mode = 0444, 153 + }, 154 + { 155 + .label = "reset_dpu_thermal", 156 + .reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET, 157 + .mask = GENMASK(7, 0) & ~BIT(6), 158 + .mode = 0444, 159 + }, 160 + { 161 + .label = "reset_pwr_off", 162 + .reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET, 163 + .mask = GENMASK(7, 0) & ~BIT(7), 164 + .mode = 0444, 165 + }, 166 + { 167 + .label = "dpu_id", 168 + .reg = MLXREG_DPU_REG_GP0_RO_OFFSET, 169 + .bit = GENMASK(3, 0), 170 + .mode = 0444, 171 + }, 172 + { 173 + .label = "voltreg_update_status", 174 + .reg = MLXREG_DPU_REG_GP0_RO_OFFSET, 175 + .mask = MLXREG_DPU_VOLTREG_UPD_MASK, 176 + .bit = 5, 177 + .mode = 0444, 178 + }, 179 + { 180 + .label = "boot_progress", 181 + .reg = MLXREG_DPU_REG_GP1_OFFSET, 182 + .mask = GENMASK(3, 0), 183 + .mode = 0444, 184 + }, 185 + { 186 + .label = "ufm_upgrade", 187 + .reg = MLXREG_DPU_REG_GP4_OFFSET, 188 + .mask = GENMASK(7, 0) & ~BIT(1), 189 + .mode = 0644, 190 + }, 191 + }; 192 + 193 + static struct mlxreg_core_platform_data mlxreg_dpu_default_regs_io_data = { 194 + .data = mlxreg_dpu_io_data, 195 + .counter = ARRAY_SIZE(mlxreg_dpu_io_data), 196 + }; 197 + 198 + /* Default hotplug data. */ 199 + static struct mlxreg_core_data mlxreg_dpu_power_events_items_data[] = { 200 + { 201 + .label = "pg_vddio", 202 + .reg = MLXREG_DPU_REG_PG_OFFSET, 203 + .mask = MLXREG_DPU_PG_VDDIO_MASK, 204 + .hpdev.nr = MLXREG_DPU_NR_NONE, 205 + }, 206 + { 207 + .label = "pg_vdd_cpu", 208 + .reg = MLXREG_DPU_REG_PG_OFFSET, 209 + .mask = MLXREG_DPU_PG_VDD_CPU_MASK, 210 + .hpdev.nr = MLXREG_DPU_NR_NONE, 211 + }, 212 + { 213 + .label = "pg_vdd", 214 + .reg = MLXREG_DPU_REG_PG_OFFSET, 215 + .mask = MLXREG_DPU_PG_VDD_MASK, 216 + .hpdev.nr = MLXREG_DPU_NR_NONE, 217 + }, 218 + { 219 + .label = "pg_1v8", 220 + .reg = MLXREG_DPU_REG_PG_OFFSET, 221 + .mask = MLXREG_DPU_PG_1V8_MASK, 222 + .hpdev.nr = MLXREG_DPU_NR_NONE, 223 + }, 224 + { 225 + .label = "pg_comparator", 226 + .reg = MLXREG_DPU_REG_PG_OFFSET, 227 + .mask = MLXREG_DPU_PG_COMPARATOR_MASK, 228 + .hpdev.nr = MLXREG_DPU_NR_NONE, 229 + }, 230 + { 231 + .label = "pg_vddq", 232 + .reg = MLXREG_DPU_REG_PG_OFFSET, 233 + .mask = MLXREG_DPU_PG_VDDQ_MASK, 234 + .hpdev.nr = MLXREG_DPU_NR_NONE, 235 + }, 236 + { 237 + .label = "pg_hvdd", 238 + .reg = MLXREG_DPU_REG_PG_OFFSET, 239 + .mask = MLXREG_DPU_PG_HVDD_MASK, 240 + .hpdev.nr = MLXREG_DPU_NR_NONE, 241 + }, 242 + { 243 + .label = "pg_dvdd", 244 + .reg = MLXREG_DPU_REG_PG_OFFSET, 245 + .mask = MLXREG_DPU_PG_DVDD_MASK, 246 + .hpdev.nr = MLXREG_DPU_NR_NONE, 247 + }, 248 + }; 249 + 250 + static struct mlxreg_core_data mlxreg_dpu_health_events_items_data[] = { 251 + { 252 + .label = "thermal_trip", 253 + .reg = MLXREG_DPU_REG_HEALTH_OFFSET, 254 + .mask = MLXREG_DPU_HLTH_THERMAL_TRIP_MASK, 255 + .hpdev.nr = MLXREG_DPU_NR_NONE, 256 + }, 257 + { 258 + .label = "ufm_upgrade_done", 259 + .reg = MLXREG_DPU_REG_HEALTH_OFFSET, 260 + .mask = MLXREG_DPU_HLTH_UFM_UPGRADE_DONE_MASK, 261 + .hpdev.nr = MLXREG_DPU_NR_NONE, 262 + }, 263 + { 264 + .label = "vddq_hot_alert", 265 + .reg = MLXREG_DPU_REG_HEALTH_OFFSET, 266 + .mask = MLXREG_DPU_HLTH_VDDQ_HOT_ALERT_MASK, 267 + .hpdev.nr = MLXREG_DPU_NR_NONE, 268 + }, 269 + { 270 + .label = "vdd_cpu_hot_alert", 271 + .reg = MLXREG_DPU_REG_HEALTH_OFFSET, 272 + .mask = MLXREG_DPU_HLTH_VDD_CPU_HOT_ALERT_MASK, 273 + .hpdev.nr = MLXREG_DPU_NR_NONE, 274 + }, 275 + { 276 + .label = "vddq_alert", 277 + .reg = MLXREG_DPU_REG_HEALTH_OFFSET, 278 + .mask = MLXREG_DPU_HLTH_VDDQ_ALERT_MASK, 279 + .hpdev.nr = MLXREG_DPU_NR_NONE, 280 + }, 281 + { 282 + .label = "vdd_cpu_alert", 283 + .reg = MLXREG_DPU_REG_HEALTH_OFFSET, 284 + .mask = MLXREG_DPU_HLTH_VDD_CPU_ALERT_MASK, 285 + .hpdev.nr = MLXREG_DPU_NR_NONE, 286 + }, 287 + }; 288 + 289 + static struct mlxreg_core_item mlxreg_dpu_hotplug_items[] = { 290 + { 291 + .data = mlxreg_dpu_power_events_items_data, 292 + .aggr_mask = MLXREG_DPU_PG_AGGR_MASK, 293 + .reg = MLXREG_DPU_REG_PG_OFFSET, 294 + .mask = MLXREG_DPU_PG_MASK, 295 + .count = ARRAY_SIZE(mlxreg_dpu_power_events_items_data), 296 + .health = false, 297 + .inversed = 0, 298 + }, 299 + { 300 + .data = mlxreg_dpu_health_events_items_data, 301 + .aggr_mask = MLXREG_DPU_HEALTH_AGGR_MASK, 302 + .reg = MLXREG_DPU_REG_HEALTH_OFFSET, 303 + .mask = MLXREG_DPU_HEALTH_MASK, 304 + .count = ARRAY_SIZE(mlxreg_dpu_health_events_items_data), 305 + .health = false, 306 + .inversed = 0, 307 + }, 308 + }; 309 + 310 + static 311 + struct mlxreg_core_hotplug_platform_data mlxreg_dpu_default_hotplug_data = { 312 + .items = mlxreg_dpu_hotplug_items, 313 + .count = ARRAY_SIZE(mlxreg_dpu_hotplug_items), 314 + .cell = MLXREG_DPU_REG_AGGRCO_OFFSET, 315 + .mask = MLXREG_DPU_AGGR_MASK, 316 + }; 317 + 318 + /** 319 + * struct mlxreg_dpu - device private data 320 + * @dev: platform device 321 + * @data: platform core data 322 + * @io_data: register access platform data 323 + * @io_regs: register access device 324 + * @hotplug_data: hotplug platform data 325 + * @hotplug: hotplug device 326 + */ 327 + struct mlxreg_dpu { 328 + struct device *dev; 329 + struct mlxreg_core_data *data; 330 + struct mlxreg_core_platform_data *io_data; 331 + struct platform_device *io_regs; 332 + struct mlxreg_core_hotplug_platform_data *hotplug_data; 333 + struct platform_device *hotplug; 334 + }; 335 + 336 + static bool mlxreg_dpu_writeable_reg(struct device *dev, unsigned int reg) 337 + { 338 + switch (reg) { 339 + case MLXREG_DPU_REG_PG_EVENT_OFFSET: 340 + case MLXREG_DPU_REG_PG_MASK_OFFSET: 341 + case MLXREG_DPU_REG_RESET_GP1_OFFSET: 342 + case MLXREG_DPU_REG_GP0_OFFSET: 343 + case MLXREG_DPU_REG_GP1_OFFSET: 344 + case MLXREG_DPU_REG_GP4_OFFSET: 345 + case MLXREG_DPU_REG_AGGRCO_OFFSET: 346 + case MLXREG_DPU_REG_AGGRCO_MASK_OFFSET: 347 + case MLXREG_DPU_REG_HEALTH_EVENT_OFFSET: 348 + case MLXREG_DPU_REG_HEALTH_MASK_OFFSET: 349 + return true; 350 + } 351 + return false; 352 + } 353 + 354 + static bool mlxreg_dpu_readable_reg(struct device *dev, unsigned int reg) 355 + { 356 + switch (reg) { 357 + case MLXREG_DPU_REG_FPGA1_VER_OFFSET: 358 + case MLXREG_DPU_REG_FPGA1_PN_OFFSET: 359 + case MLXREG_DPU_REG_FPGA1_PN1_OFFSET: 360 + case MLXREG_DPU_REG_PG_OFFSET: 361 + case MLXREG_DPU_REG_PG_EVENT_OFFSET: 362 + case MLXREG_DPU_REG_PG_MASK_OFFSET: 363 + case MLXREG_DPU_REG_RESET_GP1_OFFSET: 364 + case MLXREG_DPU_REG_RST_CAUSE1_OFFSET: 365 + case MLXREG_DPU_REG_GP0_RO_OFFSET: 366 + case MLXREG_DPU_REG_GP0_OFFSET: 367 + case MLXREG_DPU_REG_GP1_OFFSET: 368 + case MLXREG_DPU_REG_GP4_OFFSET: 369 + case MLXREG_DPU_REG_AGGRCO_OFFSET: 370 + case MLXREG_DPU_REG_AGGRCO_MASK_OFFSET: 371 + case MLXREG_DPU_REG_HEALTH_OFFSET: 372 + case MLXREG_DPU_REG_HEALTH_EVENT_OFFSET: 373 + case MLXREG_DPU_REG_HEALTH_MASK_OFFSET: 374 + case MLXREG_DPU_REG_FPGA1_MVER_OFFSET: 375 + case MLXREG_DPU_REG_CONFIG3_OFFSET: 376 + return true; 377 + } 378 + return false; 379 + } 380 + 381 + static bool mlxreg_dpu_volatile_reg(struct device *dev, unsigned int reg) 382 + { 383 + switch (reg) { 384 + case MLXREG_DPU_REG_FPGA1_VER_OFFSET: 385 + case MLXREG_DPU_REG_FPGA1_PN_OFFSET: 386 + case MLXREG_DPU_REG_FPGA1_PN1_OFFSET: 387 + case MLXREG_DPU_REG_PG_OFFSET: 388 + case MLXREG_DPU_REG_PG_EVENT_OFFSET: 389 + case MLXREG_DPU_REG_PG_MASK_OFFSET: 390 + case MLXREG_DPU_REG_RESET_GP1_OFFSET: 391 + case MLXREG_DPU_REG_RST_CAUSE1_OFFSET: 392 + case MLXREG_DPU_REG_GP0_RO_OFFSET: 393 + case MLXREG_DPU_REG_GP0_OFFSET: 394 + case MLXREG_DPU_REG_GP1_OFFSET: 395 + case MLXREG_DPU_REG_GP4_OFFSET: 396 + case MLXREG_DPU_REG_AGGRCO_OFFSET: 397 + case MLXREG_DPU_REG_AGGRCO_MASK_OFFSET: 398 + case MLXREG_DPU_REG_HEALTH_OFFSET: 399 + case MLXREG_DPU_REG_HEALTH_EVENT_OFFSET: 400 + case MLXREG_DPU_REG_HEALTH_MASK_OFFSET: 401 + case MLXREG_DPU_REG_FPGA1_MVER_OFFSET: 402 + case MLXREG_DPU_REG_CONFIG3_OFFSET: 403 + return true; 404 + } 405 + return false; 406 + } 407 + 408 + /* Configuration for the register map of a device with 2 bytes address space. */ 409 + static const struct regmap_config mlxreg_dpu_regmap_conf = { 410 + .reg_bits = 16, 411 + .val_bits = 8, 412 + .max_register = MLXREG_DPU_REG_MAX, 413 + .cache_type = REGCACHE_FLAT, 414 + .writeable_reg = mlxreg_dpu_writeable_reg, 415 + .readable_reg = mlxreg_dpu_readable_reg, 416 + .volatile_reg = mlxreg_dpu_volatile_reg, 417 + }; 418 + 419 + static int 420 + mlxreg_dpu_copy_hotplug_data(struct device *dev, struct mlxreg_dpu *mlxreg_dpu, 421 + const struct mlxreg_core_hotplug_platform_data *hotplug_data) 422 + { 423 + struct mlxreg_core_item *item; 424 + int i; 425 + 426 + mlxreg_dpu->hotplug_data = devm_kmemdup(dev, hotplug_data, 427 + sizeof(*mlxreg_dpu->hotplug_data), GFP_KERNEL); 428 + if (!mlxreg_dpu->hotplug_data) 429 + return -ENOMEM; 430 + 431 + mlxreg_dpu->hotplug_data->items = devm_kmemdup(dev, hotplug_data->items, 432 + mlxreg_dpu->hotplug_data->count * 433 + sizeof(*mlxreg_dpu->hotplug_data->items), 434 + GFP_KERNEL); 435 + if (!mlxreg_dpu->hotplug_data->items) 436 + return -ENOMEM; 437 + 438 + item = mlxreg_dpu->hotplug_data->items; 439 + for (i = 0; i < hotplug_data->count; i++, item++) { 440 + item->data = devm_kmemdup(dev, hotplug_data->items[i].data, 441 + hotplug_data->items[i].count * sizeof(*item->data), 442 + GFP_KERNEL); 443 + if (!item->data) 444 + return -ENOMEM; 445 + } 446 + 447 + return 0; 448 + } 449 + 450 + static int mlxreg_dpu_config_init(struct mlxreg_dpu *mlxreg_dpu, void *regmap, 451 + struct mlxreg_core_data *data, int irq) 452 + { 453 + struct device *dev = &data->hpdev.client->dev; 454 + u32 regval; 455 + int err; 456 + 457 + /* Validate DPU type. */ 458 + err = regmap_read(regmap, MLXREG_DPU_REG_CONFIG3_OFFSET, &regval); 459 + if (err) 460 + return err; 461 + 462 + switch (regval) { 463 + case MLXREG_DPU_BF3: 464 + /* Copy platform specific hotplug data. */ 465 + err = mlxreg_dpu_copy_hotplug_data(dev, mlxreg_dpu, 466 + &mlxreg_dpu_default_hotplug_data); 467 + if (err) 468 + return err; 469 + 470 + mlxreg_dpu->io_data = &mlxreg_dpu_default_regs_io_data; 471 + 472 + break; 473 + default: 474 + return -ENODEV; 475 + } 476 + 477 + /* Register IO access driver. */ 478 + if (mlxreg_dpu->io_data) { 479 + mlxreg_dpu->io_data->regmap = regmap; 480 + mlxreg_dpu->io_regs = 481 + platform_device_register_resndata(dev, "mlxreg-io", 482 + data->slot, NULL, 0, 483 + mlxreg_dpu->io_data, 484 + sizeof(*mlxreg_dpu->io_data)); 485 + if (IS_ERR(mlxreg_dpu->io_regs)) { 486 + dev_err(dev, "Failed to create regio for client %s at bus %d at addr 0x%02x\n", 487 + data->hpdev.brdinfo->type, data->hpdev.nr, 488 + data->hpdev.brdinfo->addr); 489 + return PTR_ERR(mlxreg_dpu->io_regs); 490 + } 491 + } 492 + 493 + /* Register hotplug driver. */ 494 + if (mlxreg_dpu->hotplug_data && irq) { 495 + mlxreg_dpu->hotplug_data->regmap = regmap; 496 + mlxreg_dpu->hotplug_data->irq = irq; 497 + mlxreg_dpu->hotplug = 498 + platform_device_register_resndata(dev, "mlxreg-hotplug", 499 + data->slot, NULL, 0, 500 + mlxreg_dpu->hotplug_data, 501 + sizeof(*mlxreg_dpu->hotplug_data)); 502 + if (IS_ERR(mlxreg_dpu->hotplug)) { 503 + err = PTR_ERR(mlxreg_dpu->hotplug); 504 + goto fail_register_hotplug; 505 + } 506 + } 507 + 508 + return 0; 509 + 510 + fail_register_hotplug: 511 + platform_device_unregister(mlxreg_dpu->io_regs); 512 + 513 + return err; 514 + } 515 + 516 + static void mlxreg_dpu_config_exit(struct mlxreg_dpu *mlxreg_dpu) 517 + { 518 + platform_device_unregister(mlxreg_dpu->hotplug); 519 + platform_device_unregister(mlxreg_dpu->io_regs); 520 + } 521 + 522 + static int mlxreg_dpu_probe(struct platform_device *pdev) 523 + { 524 + struct mlxreg_core_data *data; 525 + struct mlxreg_dpu *mlxreg_dpu; 526 + void *regmap; 527 + int err; 528 + 529 + data = dev_get_platdata(&pdev->dev); 530 + if (!data || !data->hpdev.brdinfo) 531 + return -EINVAL; 532 + 533 + data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr); 534 + if (!data->hpdev.adapter) 535 + return -EPROBE_DEFER; 536 + 537 + mlxreg_dpu = devm_kzalloc(&pdev->dev, sizeof(*mlxreg_dpu), GFP_KERNEL); 538 + if (!mlxreg_dpu) { 539 + err = -ENOMEM; 540 + goto alloc_fail; 541 + } 542 + 543 + /* Create device at the top of DPU I2C tree. */ 544 + data->hpdev.client = i2c_new_client_device(data->hpdev.adapter, 545 + data->hpdev.brdinfo); 546 + if (IS_ERR(data->hpdev.client)) { 547 + dev_err(&pdev->dev, "Failed to create client %s at bus %d at addr 0x%02x\n", 548 + data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr); 549 + err = PTR_ERR(data->hpdev.client); 550 + goto i2c_new_device_fail; 551 + } 552 + 553 + regmap = devm_regmap_init_i2c(data->hpdev.client, &mlxreg_dpu_regmap_conf); 554 + if (IS_ERR(regmap)) { 555 + dev_err(&pdev->dev, "Failed to create regmap for client %s at bus %d at addr 0x%02x\n", 556 + data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr); 557 + err = PTR_ERR(regmap); 558 + goto devm_regmap_init_i2c_fail; 559 + } 560 + 561 + /* Sync registers with hardware. */ 562 + regcache_mark_dirty(regmap); 563 + err = regcache_sync(regmap); 564 + if (err) { 565 + dev_err(&pdev->dev, "Failed to sync regmap for client %s at bus %d at addr 0x%02x\n", 566 + data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr); 567 + goto regcache_sync_fail; 568 + } 569 + 570 + mlxreg_dpu->data = data; 571 + mlxreg_dpu->dev = &pdev->dev; 572 + platform_set_drvdata(pdev, mlxreg_dpu); 573 + 574 + err = mlxreg_dpu_config_init(mlxreg_dpu, regmap, data, data->hpdev.brdinfo->irq); 575 + if (err) 576 + goto mlxreg_dpu_config_init_fail; 577 + 578 + return err; 579 + 580 + mlxreg_dpu_config_init_fail: 581 + regcache_sync_fail: 582 + devm_regmap_init_i2c_fail: 583 + i2c_unregister_device(data->hpdev.client); 584 + i2c_new_device_fail: 585 + alloc_fail: 586 + i2c_put_adapter(data->hpdev.adapter); 587 + return err; 588 + } 589 + 590 + static void mlxreg_dpu_remove(struct platform_device *pdev) 591 + { 592 + struct mlxreg_core_data *data = dev_get_platdata(&pdev->dev); 593 + struct mlxreg_dpu *mlxreg_dpu = platform_get_drvdata(pdev); 594 + 595 + mlxreg_dpu_config_exit(mlxreg_dpu); 596 + i2c_unregister_device(data->hpdev.client); 597 + i2c_put_adapter(data->hpdev.adapter); 598 + } 599 + 600 + static struct platform_driver mlxreg_dpu_driver = { 601 + .probe = mlxreg_dpu_probe, 602 + .remove = mlxreg_dpu_remove, 603 + .driver = { 604 + .name = "mlxreg-dpu", 605 + }, 606 + }; 607 + 608 + module_platform_driver(mlxreg_dpu_driver); 609 + 610 + MODULE_AUTHOR("Vadim Pasternak <vadimp@nvidia.com>"); 611 + MODULE_DESCRIPTION("Nvidia Data Processor Unit platform driver"); 612 + MODULE_LICENSE("Dual BSD/GPL"); 613 + MODULE_ALIAS("platform:mlxreg-dpu");
+4 -4
drivers/platform/mellanox/mlxreg-hotplug.c
··· 262 262 item = pdata->items; 263 263 264 264 /* Go over all kinds of items - psu, pwr, fan. */ 265 - for (i = 0; i < pdata->counter; i++, item++) { 265 + for (i = 0; i < pdata->count; i++, item++) { 266 266 if (item->capability) { 267 267 /* 268 268 * Read group capability register to get actual number ··· 541 541 goto unmask_event; 542 542 543 543 /* Handle topology and health configuration changes. */ 544 - for (i = 0; i < pdata->counter; i++, item++) { 544 + for (i = 0; i < pdata->count; i++, item++) { 545 545 if (aggr_asserted & item->aggr_mask) { 546 546 if (item->health) 547 547 mlxreg_hotplug_health_work_helper(priv, item); ··· 590 590 pdata = dev_get_platdata(&priv->pdev->dev); 591 591 item = pdata->items; 592 592 593 - for (i = 0; i < pdata->counter; i++, item++) { 593 + for (i = 0; i < pdata->count; i++, item++) { 594 594 /* Clear group presense event. */ 595 595 ret = regmap_write(priv->regmap, item->reg + 596 596 MLXREG_HOTPLUG_EVENT_OFF, 0); ··· 674 674 0); 675 675 676 676 /* Clear topology configurations. */ 677 - for (i = 0; i < pdata->counter; i++, item++) { 677 + for (i = 0; i < pdata->count; i++, item++) { 678 678 data = item->data; 679 679 /* Mask group presense event. */ 680 680 regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF,
+108 -4
drivers/platform/mellanox/nvsw-sn2201.c
··· 6 6 */ 7 7 8 8 #include <linux/device.h> 9 + #include <linux/dmi.h> 9 10 #include <linux/i2c.h> 10 11 #include <linux/interrupt.h> 11 12 #include <linux/irq.h> ··· 105 104 | NVSW_SN2201_CPLD_AGGR_PSU_MASK_DEF \ 106 105 | NVSW_SN2201_CPLD_AGGR_PWR_MASK_DEF \ 107 106 | NVSW_SN2201_CPLD_AGGR_FAN_MASK_DEF) 107 + #define NVSW_SN2201_CPLD_AGGR_BUSBAR_MASK_DEF \ 108 + (NVSW_SN2201_CPLD_AGGR_ASIC_MASK_DEF \ 109 + | NVSW_SN2201_CPLD_AGGR_FAN_MASK_DEF) 108 110 109 111 #define NVSW_SN2201_CPLD_ASIC_MASK GENMASK(3, 1) 110 112 #define NVSW_SN2201_CPLD_PSU_MASK GENMASK(1, 0) ··· 136 132 * @cpld_devs: I2C devices for cpld; 137 133 * @cpld_devs_num: number of I2C devices for cpld; 138 134 * @main_mux_deferred_nr: I2C adapter number must be exist prior creating devices execution; 135 + * @ext_pwr_source: true if system powered by external power supply; false - by internal; 139 136 */ 140 137 struct nvsw_sn2201 { 141 138 struct device *dev; ··· 157 152 struct mlxreg_hotplug_device *cpld_devs; 158 153 int cpld_devs_num; 159 154 int main_mux_deferred_nr; 155 + bool ext_pwr_source; 160 156 }; 161 157 162 158 static bool nvsw_sn2201_writeable_reg(struct device *dev, unsigned int reg) ··· 523 517 static 524 518 struct mlxreg_core_hotplug_platform_data nvsw_sn2201_hotplug = { 525 519 .items = nvsw_sn2201_items, 526 - .counter = ARRAY_SIZE(nvsw_sn2201_items), 520 + .count = ARRAY_SIZE(nvsw_sn2201_items), 527 521 .cell = NVSW_SN2201_SYS_INT_STATUS_OFFSET, 528 522 .mask = NVSW_SN2201_CPLD_AGGR_MASK_DEF, 523 + }; 524 + 525 + static struct mlxreg_core_item nvsw_sn2201_busbar_items[] = { 526 + { 527 + .data = nvsw_sn2201_fan_items_data, 528 + .aggr_mask = NVSW_SN2201_CPLD_AGGR_FAN_MASK_DEF, 529 + .reg = NVSW_SN2201_FAN_PRSNT_STATUS_OFFSET, 530 + .mask = NVSW_SN2201_CPLD_FAN_MASK, 531 + .count = ARRAY_SIZE(nvsw_sn2201_fan_items_data), 532 + .inversed = 1, 533 + .health = false, 534 + }, 535 + { 536 + .data = nvsw_sn2201_sys_items_data, 537 + .aggr_mask = NVSW_SN2201_CPLD_AGGR_ASIC_MASK_DEF, 538 + .reg = NVSW_SN2201_ASIC_STATUS_OFFSET, 539 + .mask = NVSW_SN2201_CPLD_ASIC_MASK, 540 + .count = ARRAY_SIZE(nvsw_sn2201_sys_items_data), 541 + .inversed = 1, 542 + .health = false, 543 + }, 544 + }; 545 + 546 + static 547 + struct mlxreg_core_hotplug_platform_data nvsw_sn2201_busbar_hotplug = { 548 + .items = nvsw_sn2201_busbar_items, 549 + .count = ARRAY_SIZE(nvsw_sn2201_busbar_items), 550 + .cell = NVSW_SN2201_SYS_INT_STATUS_OFFSET, 551 + .mask = NVSW_SN2201_CPLD_AGGR_BUSBAR_MASK_DEF, 529 552 }; 530 553 531 554 /* SN2201 static devices. */ ··· 591 556 }, 592 557 { 593 558 I2C_BOARD_INFO("pmbus", 0x40), 559 + }, 560 + { 561 + I2C_BOARD_INFO("lm5066i", 0x15), 594 562 }, 595 563 }; 596 564 ··· 642 604 { 643 605 .brdinfo = &nvsw_sn2201_static_devices[10], 644 606 .nr = NVSW_SN2201_MAIN_MUX_CH7_NR, 607 + }, 608 + }; 609 + 610 + /* SN2201 default busbar static board info. */ 611 + static struct mlxreg_hotplug_device nvsw_sn2201_busbar_static_brdinfo[] = { 612 + { 613 + .brdinfo = &nvsw_sn2201_static_devices[0], 614 + .nr = NVSW_SN2201_MAIN_NR, 615 + }, 616 + { 617 + .brdinfo = &nvsw_sn2201_static_devices[1], 618 + .nr = NVSW_SN2201_MAIN_MUX_CH0_NR, 619 + }, 620 + { 621 + .brdinfo = &nvsw_sn2201_static_devices[2], 622 + .nr = NVSW_SN2201_MAIN_MUX_CH0_NR, 623 + }, 624 + { 625 + .brdinfo = &nvsw_sn2201_static_devices[3], 626 + .nr = NVSW_SN2201_MAIN_MUX_CH0_NR, 627 + }, 628 + { 629 + .brdinfo = &nvsw_sn2201_static_devices[4], 630 + .nr = NVSW_SN2201_MAIN_MUX_CH3_NR, 631 + }, 632 + { 633 + .brdinfo = &nvsw_sn2201_static_devices[5], 634 + .nr = NVSW_SN2201_MAIN_MUX_CH5_NR, 635 + }, 636 + { 637 + .brdinfo = &nvsw_sn2201_static_devices[6], 638 + .nr = NVSW_SN2201_MAIN_MUX_CH5_NR, 639 + }, 640 + { 641 + .brdinfo = &nvsw_sn2201_static_devices[7], 642 + .nr = NVSW_SN2201_MAIN_MUX_CH5_NR, 643 + }, 644 + { 645 + .brdinfo = &nvsw_sn2201_static_devices[8], 646 + .nr = NVSW_SN2201_MAIN_MUX_CH6_NR, 647 + }, 648 + { 649 + .brdinfo = &nvsw_sn2201_static_devices[9], 650 + .nr = NVSW_SN2201_MAIN_MUX_CH6_NR, 651 + }, 652 + { 653 + .brdinfo = &nvsw_sn2201_static_devices[10], 654 + .nr = NVSW_SN2201_MAIN_MUX_CH7_NR, 655 + }, 656 + { 657 + .brdinfo = &nvsw_sn2201_static_devices[11], 658 + .nr = NVSW_SN2201_MAIN_MUX_CH1_NR, 645 659 }, 646 660 }; 647 661 ··· 1071 981 nvsw_sn2201->io_data = &nvsw_sn2201_regs_io; 1072 982 nvsw_sn2201->led_data = &nvsw_sn2201_led; 1073 983 nvsw_sn2201->wd_data = &nvsw_sn2201_wd; 1074 - nvsw_sn2201->hotplug_data = &nvsw_sn2201_hotplug; 984 + if (nvsw_sn2201->ext_pwr_source) 985 + nvsw_sn2201->hotplug_data = &nvsw_sn2201_busbar_hotplug; 986 + else 987 + nvsw_sn2201->hotplug_data = &nvsw_sn2201_hotplug; 1075 988 1076 989 /* Register IO access driver. */ 1077 990 if (nvsw_sn2201->io_data) { ··· 1291 1198 static int nvsw_sn2201_probe(struct platform_device *pdev) 1292 1199 { 1293 1200 struct nvsw_sn2201 *nvsw_sn2201; 1201 + const char *sku; 1294 1202 int ret; 1295 1203 1296 1204 nvsw_sn2201 = devm_kzalloc(&pdev->dev, sizeof(*nvsw_sn2201), GFP_KERNEL); 1297 1205 if (!nvsw_sn2201) 1298 1206 return -ENOMEM; 1207 + 1208 + /* Validate system powering type - only HI168 SKU supports external power. */ 1209 + sku = dmi_get_system_info(DMI_PRODUCT_SKU); 1210 + if (sku && !strcmp(sku, "HI168")) 1211 + nvsw_sn2201->ext_pwr_source = true; 1299 1212 1300 1213 nvsw_sn2201->dev = &pdev->dev; 1301 1214 platform_set_drvdata(pdev, nvsw_sn2201); ··· 1313 1214 nvsw_sn2201->main_mux_deferred_nr = NVSW_SN2201_MAIN_MUX_DEFER_NR; 1314 1215 nvsw_sn2201->main_mux_devs = nvsw_sn2201_main_mux_brdinfo; 1315 1216 nvsw_sn2201->cpld_devs = nvsw_sn2201_cpld_brdinfo; 1316 - nvsw_sn2201->sn2201_devs = nvsw_sn2201_static_brdinfo; 1317 - nvsw_sn2201->sn2201_devs_num = ARRAY_SIZE(nvsw_sn2201_static_brdinfo); 1217 + if (nvsw_sn2201->ext_pwr_source) { 1218 + nvsw_sn2201->sn2201_devs = nvsw_sn2201_busbar_static_brdinfo; 1219 + nvsw_sn2201->sn2201_devs_num = ARRAY_SIZE(nvsw_sn2201_busbar_static_brdinfo); 1220 + } else { 1221 + nvsw_sn2201->sn2201_devs = nvsw_sn2201_static_brdinfo; 1222 + nvsw_sn2201->sn2201_devs_num = ARRAY_SIZE(nvsw_sn2201_static_brdinfo); 1223 + } 1318 1224 1319 1225 return nvsw_sn2201_config_pre_init(nvsw_sn2201); 1320 1226 }
+1 -1
drivers/platform/surface/Kconfig
··· 6 6 menuconfig SURFACE_PLATFORMS 7 7 bool "Microsoft Surface Platform-Specific Device Drivers" 8 8 depends on ARM64 || X86 || COMPILE_TEST 9 - default y 9 + default y if ARM64 || X86 10 10 help 11 11 Say Y here to get to see options for platform-specific device drivers 12 12 for Microsoft Surface devices. This option alone does not add any
+40
drivers/platform/x86/Kconfig
··· 779 779 To compile this driver as a module, choose M here: the module 780 780 will be called pcengines-apuv2. 781 781 782 + config PORTWELL_EC 783 + tristate "Portwell Embedded Controller driver" 784 + depends on X86 && HAS_IOPORT && WATCHDOG && GPIOLIB 785 + select WATCHDOG_CORE 786 + help 787 + This driver provides support for the GPIO pins and watchdog timer 788 + embedded in Portwell's EC. 789 + 790 + Theoretically, this driver should work on multiple Portwell platforms, 791 + but it has only been tested on the Portwell NANO-6064 board. 792 + If you encounter any issues on other boards, please report them. 793 + 794 + To compile this driver as a module, choose M here: the module 795 + will be called portwell-ec. 796 + 782 797 config BARCO_P50_GPIO 783 798 tristate "Barco P50 GPIO driver for identify LED/button" 784 799 depends on GPIOLIB ··· 1090 1075 To compile this driver as a module, choose M here: the module 1091 1076 will be called lenovo-wmi-camera. 1092 1077 1078 + config DASHARO_ACPI 1079 + tristate "Dasharo ACPI Platform Driver" 1080 + depends on ACPI 1081 + depends on HWMON 1082 + help 1083 + This driver provides HWMON support for devices running Dasharo 1084 + firmware. 1085 + 1086 + If you have a device with Dasharo firmware, choose Y or M here. 1087 + 1093 1088 source "drivers/platform/x86/x86-android-tablets/Kconfig" 1094 1089 1095 1090 config FW_ATTR_CLASS ··· 1225 1200 1226 1201 To compile this driver as a module, choose M here: the module 1227 1202 will be called sel3350-platform. 1203 + 1204 + config OXP_EC 1205 + tristate "OneXPlayer EC platform control" 1206 + depends on ACPI_EC 1207 + depends on ACPI_BATTERY 1208 + depends on HWMON 1209 + depends on X86 1210 + help 1211 + Enables support for the platform EC of OneXPlayer and AOKZOE 1212 + handheld devices. This includes fan speed, fan controls, and 1213 + disabling the default TDP behavior of the device. Due to legacy 1214 + reasons, this driver also provides hwmon functionality to Ayaneo 1215 + devices and the OrangePi Neo. 1216 + 1217 + source "drivers/platform/x86/tuxedo/Kconfig" 1228 1218 1229 1219 endif # X86_PLATFORM_DEVICES 1230 1220
+12
drivers/platform/x86/Makefile
··· 92 92 # PC Engines 93 93 obj-$(CONFIG_PCENGINES_APU2) += pcengines-apuv2.o 94 94 95 + # Portwell 96 + obj-$(CONFIG_PORTWELL_EC) += portwell-ec.o 97 + 95 98 # Barco 96 99 obj-$(CONFIG_BARCO_P50_GPIO) += barco-p50-gpio.o 97 100 ··· 114 111 115 112 # Inspur 116 113 obj-$(CONFIG_INSPUR_PLATFORM_PROFILE) += inspur_platform_profile.o 114 + 115 + # Dasharo 116 + obj-$(CONFIG_DASHARO_ACPI) += dasharo-acpi.o 117 117 118 118 # Laptop drivers 119 119 obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o ··· 155 149 # Silicom 156 150 obj-$(CONFIG_SILICOM_PLATFORM) += silicom-platform.o 157 151 152 + # TUXEDO 153 + obj-y += tuxedo/ 154 + 158 155 # Winmate 159 156 obj-$(CONFIG_WINMATE_FM07_KEYS) += winmate-fm07-keys.o 160 157 161 158 # SEL 162 159 obj-$(CONFIG_SEL3350_PLATFORM) += sel3350-platform.o 160 + 161 + # OneXPlayer 162 + obj-$(CONFIG_OXP_EC) += oxpec.o
+2 -2
drivers/platform/x86/acerhdf.c
··· 271 271 * this struct is used to instruct thermal layer to use bang_bang instead of 272 272 * default governor for acerhdf 273 273 */ 274 - static struct thermal_zone_params acerhdf_zone_params = { 274 + static const struct thermal_zone_params acerhdf_zone_params = { 275 275 .governor_name = "bang_bang", 276 276 }; 277 277 ··· 426 426 } 427 427 428 428 /* bind callback functions to thermalzone */ 429 - static struct thermal_zone_device_ops acerhdf_dev_ops = { 429 + static const struct thermal_zone_device_ops acerhdf_dev_ops = { 430 430 .should_bind = acerhdf_should_bind, 431 431 .get_temp = acerhdf_get_ec_temp, 432 432 .change_mode = acerhdf_change_mode,
+11
drivers/platform/x86/amd/Kconfig
··· 32 32 33 33 This mechanism will only be activated on platforms that advertise a 34 34 need for it. 35 + 36 + config AMD_ISP_PLATFORM 37 + tristate "AMD ISP4 platform driver" 38 + depends on I2C && X86_64 && ACPI 39 + help 40 + Platform driver for AMD platforms containing image signal processor 41 + gen 4. Provides camera sensor module board information to allow 42 + sensor and V4L drivers to work properly. 43 + 44 + This driver can also be built as a module. If so, the module 45 + will be called amd_isp4.
+1
drivers/platform/x86/amd/Makefile
··· 10 10 obj-$(CONFIG_AMD_HSMP) += hsmp/ 11 11 obj-$(CONFIG_AMD_PMF) += pmf/ 12 12 obj-$(CONFIG_AMD_WBRF) += wbrf.o 13 + obj-$(CONFIG_AMD_ISP_PLATFORM) += amd_isp4.o
+311
drivers/platform/x86/amd/amd_isp4.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * AMD ISP platform driver for sensor i2-client instantiation 4 + * 5 + * Copyright 2025 Advanced Micro Devices, Inc. 6 + */ 7 + 8 + #include <linux/err.h> 9 + #include <linux/i2c.h> 10 + #include <linux/module.h> 11 + #include <linux/mutex.h> 12 + #include <linux/platform_device.h> 13 + #include <linux/property.h> 14 + #include <linux/string.h> 15 + #include <linux/types.h> 16 + #include <linux/units.h> 17 + 18 + #define AMDISP_OV05C10_I2C_ADDR 0x10 19 + #define AMDISP_OV05C10_HID "OMNI5C10" 20 + #define AMDISP_OV05C10_REMOTE_EP_NAME "ov05c10_isp_4_1_1" 21 + #define AMD_ISP_PLAT_DRV_NAME "amd-isp4" 22 + 23 + /* 24 + * AMD ISP platform info definition to initialize sensor 25 + * specific platform configuration to prepare the amdisp 26 + * platform. 27 + */ 28 + struct amdisp_platform_info { 29 + struct i2c_board_info board_info; 30 + const struct software_node **swnodes; 31 + }; 32 + 33 + /* 34 + * AMD ISP platform definition to configure the device properties 35 + * missing in the ACPI table. 36 + */ 37 + struct amdisp_platform { 38 + const struct amdisp_platform_info *pinfo; 39 + struct i2c_board_info board_info; 40 + struct notifier_block i2c_nb; 41 + struct i2c_client *i2c_dev; 42 + struct mutex lock; /* protects i2c client creation */ 43 + }; 44 + 45 + /* Top-level OV05C10 camera node property table */ 46 + static const struct property_entry ov05c10_camera_props[] = { 47 + PROPERTY_ENTRY_U32("clock-frequency", 24 * HZ_PER_MHZ), 48 + { } 49 + }; 50 + 51 + /* Root AMD ISP OV05C10 camera node definition */ 52 + static const struct software_node camera_node = { 53 + .name = AMDISP_OV05C10_HID, 54 + .properties = ov05c10_camera_props, 55 + }; 56 + 57 + /* 58 + * AMD ISP OV05C10 Ports node definition. No properties defined for 59 + * ports node for OV05C10. 60 + */ 61 + static const struct software_node ports = { 62 + .name = "ports", 63 + .parent = &camera_node, 64 + }; 65 + 66 + /* 67 + * AMD ISP OV05C10 Port node definition. No properties defined for 68 + * port node for OV05C10. 69 + */ 70 + static const struct software_node port_node = { 71 + .name = "port@", 72 + .parent = &ports, 73 + }; 74 + 75 + /* 76 + * Remote endpoint AMD ISP node definition. No properties defined for 77 + * remote endpoint node for OV05C10. 78 + */ 79 + static const struct software_node remote_ep_isp_node = { 80 + .name = AMDISP_OV05C10_REMOTE_EP_NAME, 81 + }; 82 + 83 + /* 84 + * Remote endpoint reference for isp node included in the 85 + * OV05C10 endpoint. 86 + */ 87 + static const struct software_node_ref_args ov05c10_refs[] = { 88 + SOFTWARE_NODE_REFERENCE(&remote_ep_isp_node), 89 + }; 90 + 91 + /* OV05C10 supports one single link frequency */ 92 + static const u64 ov05c10_link_freqs[] = { 93 + 925 * HZ_PER_MHZ, 94 + }; 95 + 96 + /* OV05C10 supports only 2-lane configuration */ 97 + static const u32 ov05c10_data_lanes[] = { 98 + 1, 99 + 2, 100 + }; 101 + 102 + /* OV05C10 endpoint node properties table */ 103 + static const struct property_entry ov05c10_endpoint_props[] = { 104 + PROPERTY_ENTRY_U32("bus-type", 4), 105 + PROPERTY_ENTRY_U32_ARRAY_LEN("data-lanes", ov05c10_data_lanes, 106 + ARRAY_SIZE(ov05c10_data_lanes)), 107 + PROPERTY_ENTRY_U64_ARRAY_LEN("link-frequencies", ov05c10_link_freqs, 108 + ARRAY_SIZE(ov05c10_link_freqs)), 109 + PROPERTY_ENTRY_REF_ARRAY("remote-endpoint", ov05c10_refs), 110 + { } 111 + }; 112 + 113 + /* AMD ISP endpoint node definition */ 114 + static const struct software_node endpoint_node = { 115 + .name = "endpoint", 116 + .parent = &port_node, 117 + .properties = ov05c10_endpoint_props, 118 + }; 119 + 120 + /* 121 + * AMD ISP swnode graph uses 5 nodes and also its relationship is 122 + * fixed to align with the structure that v4l2 expects for successful 123 + * endpoint fwnode parsing. 124 + * 125 + * It is only the node property_entries that will vary for each platform 126 + * supporting different sensor modules. 127 + */ 128 + static const struct software_node *ov05c10_nodes[] = { 129 + &camera_node, 130 + &ports, 131 + &port_node, 132 + &endpoint_node, 133 + &remote_ep_isp_node, 134 + NULL 135 + }; 136 + 137 + /* OV05C10 specific AMD ISP platform configuration */ 138 + static const struct amdisp_platform_info ov05c10_platform_config = { 139 + .board_info = { 140 + .dev_name = "ov05c10", 141 + I2C_BOARD_INFO("ov05c10", AMDISP_OV05C10_I2C_ADDR), 142 + }, 143 + .swnodes = ov05c10_nodes, 144 + }; 145 + 146 + static const struct acpi_device_id amdisp_sensor_ids[] = { 147 + { AMDISP_OV05C10_HID, (kernel_ulong_t)&ov05c10_platform_config }, 148 + { } 149 + }; 150 + MODULE_DEVICE_TABLE(acpi, amdisp_sensor_ids); 151 + 152 + static inline bool is_isp_i2c_adapter(struct i2c_adapter *adap) 153 + { 154 + return !strcmp(adap->owner->name, "i2c_designware_amdisp"); 155 + } 156 + 157 + static void instantiate_isp_i2c_client(struct amdisp_platform *isp4_platform, 158 + struct i2c_adapter *adap) 159 + { 160 + struct i2c_board_info *info = &isp4_platform->board_info; 161 + struct i2c_client *i2c_dev; 162 + 163 + guard(mutex)(&isp4_platform->lock); 164 + 165 + if (isp4_platform->i2c_dev) 166 + return; 167 + 168 + i2c_dev = i2c_new_client_device(adap, info); 169 + if (IS_ERR(i2c_dev)) { 170 + dev_err(&adap->dev, "error %pe registering isp i2c_client\n", i2c_dev); 171 + return; 172 + } 173 + isp4_platform->i2c_dev = i2c_dev; 174 + } 175 + 176 + static int isp_i2c_bus_notify(struct notifier_block *nb, 177 + unsigned long action, void *data) 178 + { 179 + struct amdisp_platform *isp4_platform = 180 + container_of(nb, struct amdisp_platform, i2c_nb); 181 + struct device *dev = data; 182 + struct i2c_client *client; 183 + struct i2c_adapter *adap; 184 + 185 + switch (action) { 186 + case BUS_NOTIFY_ADD_DEVICE: 187 + adap = i2c_verify_adapter(dev); 188 + if (!adap) 189 + break; 190 + if (is_isp_i2c_adapter(adap)) 191 + instantiate_isp_i2c_client(isp4_platform, adap); 192 + break; 193 + case BUS_NOTIFY_REMOVED_DEVICE: 194 + client = i2c_verify_client(dev); 195 + if (!client) 196 + break; 197 + 198 + scoped_guard(mutex, &isp4_platform->lock) { 199 + if (isp4_platform->i2c_dev == client) { 200 + dev_dbg(&client->adapter->dev, "amdisp i2c_client removed\n"); 201 + isp4_platform->i2c_dev = NULL; 202 + } 203 + } 204 + break; 205 + default: 206 + break; 207 + } 208 + 209 + return NOTIFY_DONE; 210 + } 211 + 212 + static struct amdisp_platform *prepare_amdisp_platform(struct device *dev, 213 + const struct amdisp_platform_info *src) 214 + { 215 + struct amdisp_platform *isp4_platform; 216 + int ret; 217 + 218 + isp4_platform = devm_kzalloc(dev, sizeof(*isp4_platform), GFP_KERNEL); 219 + if (!isp4_platform) 220 + return ERR_PTR(-ENOMEM); 221 + 222 + ret = devm_mutex_init(dev, &isp4_platform->lock); 223 + if (ret) 224 + return ERR_PTR(ret); 225 + 226 + isp4_platform->board_info.dev_name = src->board_info.dev_name; 227 + strscpy(isp4_platform->board_info.type, src->board_info.type); 228 + isp4_platform->board_info.addr = src->board_info.addr; 229 + isp4_platform->pinfo = src; 230 + 231 + ret = software_node_register_node_group(src->swnodes); 232 + if (ret) 233 + return ERR_PTR(ret); 234 + 235 + isp4_platform->board_info.swnode = src->swnodes[0]; 236 + 237 + return isp4_platform; 238 + } 239 + 240 + static int try_to_instantiate_i2c_client(struct device *dev, void *data) 241 + { 242 + struct i2c_adapter *adap = i2c_verify_adapter(dev); 243 + struct amdisp_platform *isp4_platform = data; 244 + 245 + if (!isp4_platform || !adap) 246 + return 0; 247 + if (!adap->owner) 248 + return 0; 249 + 250 + if (is_isp_i2c_adapter(adap)) 251 + instantiate_isp_i2c_client(isp4_platform, adap); 252 + 253 + return 0; 254 + } 255 + 256 + static int amd_isp_probe(struct platform_device *pdev) 257 + { 258 + const struct amdisp_platform_info *pinfo; 259 + struct amdisp_platform *isp4_platform; 260 + int ret; 261 + 262 + pinfo = device_get_match_data(&pdev->dev); 263 + if (!pinfo) 264 + return dev_err_probe(&pdev->dev, -EINVAL, 265 + "failed to get valid ACPI data\n"); 266 + 267 + isp4_platform = prepare_amdisp_platform(&pdev->dev, pinfo); 268 + if (IS_ERR(isp4_platform)) 269 + return dev_err_probe(&pdev->dev, PTR_ERR(isp4_platform), 270 + "failed to prepare AMD ISP platform fwnode\n"); 271 + 272 + isp4_platform->i2c_nb.notifier_call = isp_i2c_bus_notify; 273 + ret = bus_register_notifier(&i2c_bus_type, &isp4_platform->i2c_nb); 274 + if (ret) 275 + goto error_unregister_sw_node; 276 + 277 + /* check if adapter is already registered and create i2c client instance */ 278 + i2c_for_each_dev(isp4_platform, try_to_instantiate_i2c_client); 279 + 280 + platform_set_drvdata(pdev, isp4_platform); 281 + return 0; 282 + 283 + error_unregister_sw_node: 284 + software_node_unregister_node_group(isp4_platform->pinfo->swnodes); 285 + return ret; 286 + } 287 + 288 + static void amd_isp_remove(struct platform_device *pdev) 289 + { 290 + struct amdisp_platform *isp4_platform = platform_get_drvdata(pdev); 291 + 292 + bus_unregister_notifier(&i2c_bus_type, &isp4_platform->i2c_nb); 293 + i2c_unregister_device(isp4_platform->i2c_dev); 294 + software_node_unregister_node_group(isp4_platform->pinfo->swnodes); 295 + } 296 + 297 + static struct platform_driver amd_isp_platform_driver = { 298 + .driver = { 299 + .name = AMD_ISP_PLAT_DRV_NAME, 300 + .acpi_match_table = amdisp_sensor_ids, 301 + }, 302 + .probe = amd_isp_probe, 303 + .remove = amd_isp_remove, 304 + }; 305 + 306 + module_platform_driver(amd_isp_platform_driver); 307 + 308 + MODULE_AUTHOR("Benjamin Chan <benjamin.chan@amd.com>"); 309 + MODULE_AUTHOR("Pratap Nirujogi <pratap.nirujogi@amd.com>"); 310 + MODULE_DESCRIPTION("AMD ISP4 Platform Driver"); 311 + MODULE_LICENSE("GPL");
+2
drivers/platform/x86/amd/hsmp/Kconfig
··· 12 12 config AMD_HSMP_ACPI 13 13 tristate "AMD HSMP ACPI device driver" 14 14 depends on ACPI 15 + depends on HWMON || !HWMON 15 16 select AMD_HSMP 16 17 help 17 18 Host System Management Port (HSMP) interface is a mailbox interface ··· 30 29 31 30 config AMD_HSMP_PLAT 32 31 tristate "AMD HSMP platform device driver" 32 + depends on HWMON || !HWMON 33 33 select AMD_HSMP 34 34 help 35 35 Host System Management Port (HSMP) interface is a mailbox interface
+1
drivers/platform/x86/amd/hsmp/Makefile
··· 6 6 7 7 obj-$(CONFIG_AMD_HSMP) += hsmp_common.o 8 8 hsmp_common-y := hsmp.o 9 + hsmp_common-$(CONFIG_HWMON) += hwmon.o 9 10 obj-$(CONFIG_AMD_HSMP_PLAT) += amd_hsmp.o 10 11 amd_hsmp-y := plat.o 11 12 obj-$(CONFIG_AMD_HSMP_ACPI) += hsmp_acpi.o
+266 -1
drivers/platform/x86/amd/hsmp/acpi.c
··· 12 12 #include <asm/amd/hsmp.h> 13 13 14 14 #include <linux/acpi.h> 15 + #include <linux/array_size.h> 16 + #include <linux/bits.h> 17 + #include <linux/bitfield.h> 15 18 #include <linux/device.h> 16 19 #include <linux/dev_printk.h> 17 20 #include <linux/ioport.h> ··· 31 28 #include "hsmp.h" 32 29 33 30 #define DRIVER_NAME "hsmp_acpi" 34 - #define DRIVER_VERSION "2.3" 35 31 36 32 /* These are the strings specified in ACPI table */ 37 33 #define MSG_IDOFF_STR "MsgIdOffset" ··· 38 36 #define MSG_RESPOFF_STR "MsgRspOffset" 39 37 40 38 static struct hsmp_plat_device *hsmp_pdev; 39 + 40 + struct hsmp_sys_attr { 41 + struct device_attribute dattr; 42 + u32 msg_id; 43 + }; 41 44 42 45 static int amd_hsmp_acpi_rdwr(struct hsmp_socket *sock, u32 offset, 43 46 u32 *value, bool write) ··· 251 244 return 0; 252 245 } 253 246 247 + static umode_t hsmp_is_sock_dev_attr_visible(struct kobject *kobj, 248 + struct attribute *attr, int id) 249 + { 250 + return attr->mode; 251 + } 252 + 253 + #define to_hsmp_sys_attr(_attr) container_of(_attr, struct hsmp_sys_attr, dattr) 254 + 255 + static ssize_t hsmp_msg_resp32_show(struct device *dev, struct device_attribute *attr, 256 + char *buf) 257 + { 258 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 259 + struct hsmp_socket *sock = dev_get_drvdata(dev); 260 + u32 data; 261 + int ret; 262 + 263 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1); 264 + if (ret) 265 + return ret; 266 + 267 + return sysfs_emit(buf, "%u\n", data); 268 + } 269 + 270 + #define DDR_MAX_BW_MASK GENMASK(31, 20) 271 + #define DDR_UTIL_BW_MASK GENMASK(19, 8) 272 + #define DDR_UTIL_BW_PERC_MASK GENMASK(7, 0) 273 + #define FW_VER_MAJOR_MASK GENMASK(23, 16) 274 + #define FW_VER_MINOR_MASK GENMASK(15, 8) 275 + #define FW_VER_DEBUG_MASK GENMASK(7, 0) 276 + #define FMAX_MASK GENMASK(31, 16) 277 + #define FMIN_MASK GENMASK(15, 0) 278 + #define FREQ_LIMIT_MASK GENMASK(31, 16) 279 + #define FREQ_SRC_IND_MASK GENMASK(15, 0) 280 + 281 + static ssize_t hsmp_ddr_max_bw_show(struct device *dev, struct device_attribute *attr, 282 + char *buf) 283 + { 284 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 285 + struct hsmp_socket *sock = dev_get_drvdata(dev); 286 + u32 data; 287 + int ret; 288 + 289 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1); 290 + if (ret) 291 + return ret; 292 + 293 + return sysfs_emit(buf, "%lu\n", FIELD_GET(DDR_MAX_BW_MASK, data)); 294 + } 295 + 296 + static ssize_t hsmp_ddr_util_bw_show(struct device *dev, struct device_attribute *attr, 297 + char *buf) 298 + { 299 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 300 + struct hsmp_socket *sock = dev_get_drvdata(dev); 301 + u32 data; 302 + int ret; 303 + 304 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1); 305 + if (ret) 306 + return ret; 307 + 308 + return sysfs_emit(buf, "%lu\n", FIELD_GET(DDR_UTIL_BW_MASK, data)); 309 + } 310 + 311 + static ssize_t hsmp_ddr_util_bw_perc_show(struct device *dev, struct device_attribute *attr, 312 + char *buf) 313 + { 314 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 315 + struct hsmp_socket *sock = dev_get_drvdata(dev); 316 + u32 data; 317 + int ret; 318 + 319 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1); 320 + if (ret) 321 + return ret; 322 + 323 + return sysfs_emit(buf, "%lu\n", FIELD_GET(DDR_UTIL_BW_PERC_MASK, data)); 324 + } 325 + 326 + static ssize_t hsmp_msg_fw_ver_show(struct device *dev, struct device_attribute *attr, 327 + char *buf) 328 + { 329 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 330 + struct hsmp_socket *sock = dev_get_drvdata(dev); 331 + u32 data; 332 + int ret; 333 + 334 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1); 335 + if (ret) 336 + return ret; 337 + 338 + return sysfs_emit(buf, "%lu.%lu.%lu\n", 339 + FIELD_GET(FW_VER_MAJOR_MASK, data), 340 + FIELD_GET(FW_VER_MINOR_MASK, data), 341 + FIELD_GET(FW_VER_DEBUG_MASK, data)); 342 + } 343 + 344 + static ssize_t hsmp_fclk_show(struct device *dev, struct device_attribute *attr, 345 + char *buf) 346 + { 347 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 348 + struct hsmp_socket *sock = dev_get_drvdata(dev); 349 + u32 data[2]; 350 + int ret; 351 + 352 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, data, 2); 353 + if (ret) 354 + return ret; 355 + 356 + return sysfs_emit(buf, "%u\n", data[0]); 357 + } 358 + 359 + static ssize_t hsmp_mclk_show(struct device *dev, struct device_attribute *attr, 360 + char *buf) 361 + { 362 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 363 + struct hsmp_socket *sock = dev_get_drvdata(dev); 364 + u32 data[2]; 365 + int ret; 366 + 367 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, data, 2); 368 + if (ret) 369 + return ret; 370 + 371 + return sysfs_emit(buf, "%u\n", data[1]); 372 + } 373 + 374 + static ssize_t hsmp_clk_fmax_show(struct device *dev, struct device_attribute *attr, 375 + char *buf) 376 + { 377 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 378 + struct hsmp_socket *sock = dev_get_drvdata(dev); 379 + u32 data; 380 + int ret; 381 + 382 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1); 383 + if (ret) 384 + return ret; 385 + 386 + return sysfs_emit(buf, "%lu\n", FIELD_GET(FMAX_MASK, data)); 387 + } 388 + 389 + static ssize_t hsmp_clk_fmin_show(struct device *dev, struct device_attribute *attr, 390 + char *buf) 391 + { 392 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 393 + struct hsmp_socket *sock = dev_get_drvdata(dev); 394 + u32 data; 395 + int ret; 396 + 397 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1); 398 + if (ret) 399 + return ret; 400 + 401 + return sysfs_emit(buf, "%lu\n", FIELD_GET(FMIN_MASK, data)); 402 + } 403 + 404 + static ssize_t hsmp_freq_limit_show(struct device *dev, struct device_attribute *attr, 405 + char *buf) 406 + { 407 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 408 + struct hsmp_socket *sock = dev_get_drvdata(dev); 409 + u32 data; 410 + int ret; 411 + 412 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1); 413 + if (ret) 414 + return ret; 415 + 416 + return sysfs_emit(buf, "%lu\n", FIELD_GET(FREQ_LIMIT_MASK, data)); 417 + } 418 + 419 + static const char * const freqlimit_srcnames[] = { 420 + "cHTC-Active", 421 + "PROCHOT", 422 + "TDC limit", 423 + "PPT Limit", 424 + "OPN Max", 425 + "Reliability Limit", 426 + "APML Agent", 427 + "HSMP Agent", 428 + }; 429 + 430 + static ssize_t hsmp_freq_limit_source_show(struct device *dev, struct device_attribute *attr, 431 + char *buf) 432 + { 433 + struct hsmp_sys_attr *hattr = to_hsmp_sys_attr(attr); 434 + struct hsmp_socket *sock = dev_get_drvdata(dev); 435 + unsigned int index; 436 + int len = 0; 437 + u16 src_ind; 438 + u32 data; 439 + int ret; 440 + 441 + ret = hsmp_msg_get_nargs(sock->sock_ind, hattr->msg_id, &data, 1); 442 + if (ret) 443 + return ret; 444 + 445 + src_ind = FIELD_GET(FREQ_SRC_IND_MASK, data); 446 + for (index = 0; index < ARRAY_SIZE(freqlimit_srcnames); index++) { 447 + if (!src_ind) 448 + break; 449 + if (src_ind & 1) 450 + len += sysfs_emit_at(buf, len, "%s\n", freqlimit_srcnames[index]); 451 + src_ind >>= 1; 452 + } 453 + return len; 454 + } 455 + 254 456 static int init_acpi(struct device *dev) 255 457 { 256 458 u16 sock_ind; ··· 498 282 dev_err(dev, "Failed to init metric table\n"); 499 283 } 500 284 285 + ret = hsmp_create_sensor(dev, sock_ind); 286 + if (ret) 287 + dev_err(dev, "Failed to register HSMP sensors with hwmon\n"); 288 + 289 + dev_set_drvdata(dev, &hsmp_pdev->sock[sock_ind]); 290 + 501 291 return ret; 502 292 } 503 293 ··· 518 296 NULL 519 297 }; 520 298 299 + #define HSMP_DEV_ATTR(_name, _msg_id, _show, _mode) \ 300 + static struct hsmp_sys_attr hattr_##_name = { \ 301 + .dattr = __ATTR(_name, _mode, _show, NULL), \ 302 + .msg_id = _msg_id, \ 303 + } 304 + 305 + HSMP_DEV_ATTR(c0_residency_input, HSMP_GET_C0_PERCENT, hsmp_msg_resp32_show, 0444); 306 + HSMP_DEV_ATTR(prochot_status, HSMP_GET_PROC_HOT, hsmp_msg_resp32_show, 0444); 307 + HSMP_DEV_ATTR(smu_fw_version, HSMP_GET_SMU_VER, hsmp_msg_fw_ver_show, 0444); 308 + HSMP_DEV_ATTR(protocol_version, HSMP_GET_PROTO_VER, hsmp_msg_resp32_show, 0444); 309 + HSMP_DEV_ATTR(cclk_freq_limit_input, HSMP_GET_CCLK_THROTTLE_LIMIT, hsmp_msg_resp32_show, 0444); 310 + HSMP_DEV_ATTR(ddr_max_bw, HSMP_GET_DDR_BANDWIDTH, hsmp_ddr_max_bw_show, 0444); 311 + HSMP_DEV_ATTR(ddr_utilised_bw_input, HSMP_GET_DDR_BANDWIDTH, hsmp_ddr_util_bw_show, 0444); 312 + HSMP_DEV_ATTR(ddr_utilised_bw_perc_input, HSMP_GET_DDR_BANDWIDTH, hsmp_ddr_util_bw_perc_show, 0444); 313 + HSMP_DEV_ATTR(fclk_input, HSMP_GET_FCLK_MCLK, hsmp_fclk_show, 0444); 314 + HSMP_DEV_ATTR(mclk_input, HSMP_GET_FCLK_MCLK, hsmp_mclk_show, 0444); 315 + HSMP_DEV_ATTR(clk_fmax, HSMP_GET_SOCKET_FMAX_FMIN, hsmp_clk_fmax_show, 0444); 316 + HSMP_DEV_ATTR(clk_fmin, HSMP_GET_SOCKET_FMAX_FMIN, hsmp_clk_fmin_show, 0444); 317 + HSMP_DEV_ATTR(pwr_current_active_freq_limit, HSMP_GET_SOCKET_FREQ_LIMIT, 318 + hsmp_freq_limit_show, 0444); 319 + HSMP_DEV_ATTR(pwr_current_active_freq_limit_source, HSMP_GET_SOCKET_FREQ_LIMIT, 320 + hsmp_freq_limit_source_show, 0444); 321 + 322 + static struct attribute *hsmp_dev_attr_list[] = { 323 + &hattr_c0_residency_input.dattr.attr, 324 + &hattr_prochot_status.dattr.attr, 325 + &hattr_smu_fw_version.dattr.attr, 326 + &hattr_protocol_version.dattr.attr, 327 + &hattr_cclk_freq_limit_input.dattr.attr, 328 + &hattr_ddr_max_bw.dattr.attr, 329 + &hattr_ddr_utilised_bw_input.dattr.attr, 330 + &hattr_ddr_utilised_bw_perc_input.dattr.attr, 331 + &hattr_fclk_input.dattr.attr, 332 + &hattr_mclk_input.dattr.attr, 333 + &hattr_clk_fmax.dattr.attr, 334 + &hattr_clk_fmin.dattr.attr, 335 + &hattr_pwr_current_active_freq_limit.dattr.attr, 336 + &hattr_pwr_current_active_freq_limit_source.dattr.attr, 337 + NULL 338 + }; 339 + 521 340 static const struct attribute_group hsmp_attr_grp = { 522 341 .bin_attrs_new = hsmp_attr_list, 342 + .attrs = hsmp_dev_attr_list, 523 343 .is_bin_visible = hsmp_is_sock_attr_visible, 344 + .is_visible = hsmp_is_sock_dev_attr_visible, 524 345 }; 525 346 526 347 static const struct attribute_group *hsmp_groups[] = {
+23 -2
drivers/platform/x86/amd/hsmp/hsmp.c
··· 32 32 #define HSMP_WR true 33 33 #define HSMP_RD false 34 34 35 - #define DRIVER_VERSION "2.4" 36 - 37 35 /* 38 36 * When same message numbers are used for both GET and SET operation, 39 37 * bit:31 indicates whether its SET or GET operation. ··· 227 229 return ret; 228 230 } 229 231 EXPORT_SYMBOL_NS_GPL(hsmp_send_message, "AMD_HSMP"); 232 + 233 + int hsmp_msg_get_nargs(u16 sock_ind, u32 msg_id, u32 *data, u8 num_args) 234 + { 235 + struct hsmp_message msg = {}; 236 + unsigned int i; 237 + int ret; 238 + 239 + if (!data) 240 + return -EINVAL; 241 + msg.msg_id = msg_id; 242 + msg.sock_ind = sock_ind; 243 + msg.response_sz = num_args; 244 + 245 + ret = hsmp_send_message(&msg); 246 + if (ret) 247 + return ret; 248 + 249 + for (i = 0; i < num_args; i++) 250 + data[i] = msg.args[i]; 251 + 252 + return 0; 253 + } 254 + EXPORT_SYMBOL_NS_GPL(hsmp_msg_get_nargs, "AMD_HSMP"); 230 255 231 256 int hsmp_test(u16 sock_ind, u32 value) 232 257 {
+9
drivers/platform/x86/amd/hsmp/hsmp.h
··· 12 12 13 13 #include <linux/compiler_types.h> 14 14 #include <linux/device.h> 15 + #include <linux/hwmon.h> 15 16 #include <linux/miscdevice.h> 16 17 #include <linux/pci.h> 17 18 #include <linux/semaphore.h> ··· 25 24 #define HSMP_CDEV_NAME "hsmp_cdev" 26 25 #define HSMP_DEVNODE_NAME "hsmp" 27 26 #define ACPI_HSMP_DEVICE_HID "AMDI0097" 27 + 28 + #define DRIVER_VERSION "2.5" 28 29 29 30 struct hsmp_mbaddr_info { 30 31 u32 base_addr; ··· 64 61 int hsmp_get_tbl_dram_base(u16 sock_ind); 65 62 ssize_t hsmp_metric_tbl_read(struct hsmp_socket *sock, char *buf, size_t size); 66 63 struct hsmp_plat_device *get_hsmp_pdev(void); 64 + #if IS_REACHABLE(CONFIG_HWMON) 65 + int hsmp_create_sensor(struct device *dev, u16 sock_ind); 66 + #else 67 + static inline int hsmp_create_sensor(struct device *dev, u16 sock_ind) { return 0; } 68 + #endif 69 + int hsmp_msg_get_nargs(u16 sock_ind, u32 msg_id, u32 *data, u8 num_args); 67 70 #endif /* HSMP_H */
+121
drivers/platform/x86/amd/hsmp/hwmon.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * AMD HSMP hwmon support 4 + * Copyright (c) 2025, AMD. 5 + * All Rights Reserved. 6 + * 7 + * This file provides hwmon implementation for HSMP interface. 8 + */ 9 + 10 + #include <asm/amd/hsmp.h> 11 + 12 + #include <linux/device.h> 13 + #include <linux/err.h> 14 + #include <linux/hwmon.h> 15 + #include <linux/types.h> 16 + #include <linux/units.h> 17 + 18 + #include "hsmp.h" 19 + 20 + #define HSMP_HWMON_NAME "amd_hsmp_hwmon" 21 + 22 + static int hsmp_hwmon_write(struct device *dev, enum hwmon_sensor_types type, 23 + u32 attr, int channel, long val) 24 + { 25 + u16 sock_ind = (uintptr_t)dev_get_drvdata(dev); 26 + struct hsmp_message msg = {}; 27 + 28 + if (type != hwmon_power) 29 + return -EOPNOTSUPP; 30 + 31 + if (attr != hwmon_power_cap) 32 + return -EOPNOTSUPP; 33 + 34 + msg.num_args = 1; 35 + msg.args[0] = val / MICROWATT_PER_MILLIWATT; 36 + msg.msg_id = HSMP_SET_SOCKET_POWER_LIMIT; 37 + msg.sock_ind = sock_ind; 38 + return hsmp_send_message(&msg); 39 + } 40 + 41 + static int hsmp_hwmon_read(struct device *dev, 42 + enum hwmon_sensor_types type, 43 + u32 attr, int channel, long *val) 44 + { 45 + u16 sock_ind = (uintptr_t)dev_get_drvdata(dev); 46 + struct hsmp_message msg = {}; 47 + int ret; 48 + 49 + if (type != hwmon_power) 50 + return -EOPNOTSUPP; 51 + 52 + msg.sock_ind = sock_ind; 53 + msg.response_sz = 1; 54 + 55 + switch (attr) { 56 + case hwmon_power_input: 57 + msg.msg_id = HSMP_GET_SOCKET_POWER; 58 + break; 59 + case hwmon_power_cap: 60 + msg.msg_id = HSMP_GET_SOCKET_POWER_LIMIT; 61 + break; 62 + case hwmon_power_cap_max: 63 + msg.msg_id = HSMP_GET_SOCKET_POWER_LIMIT_MAX; 64 + break; 65 + default: 66 + return -EOPNOTSUPP; 67 + } 68 + 69 + ret = hsmp_send_message(&msg); 70 + if (!ret) 71 + *val = msg.args[0] * MICROWATT_PER_MILLIWATT; 72 + 73 + return ret; 74 + } 75 + 76 + static umode_t hsmp_hwmon_is_visble(const void *data, 77 + enum hwmon_sensor_types type, 78 + u32 attr, int channel) 79 + { 80 + if (type != hwmon_power) 81 + return 0; 82 + 83 + switch (attr) { 84 + case hwmon_power_input: 85 + return 0444; 86 + case hwmon_power_cap: 87 + return 0644; 88 + case hwmon_power_cap_max: 89 + return 0444; 90 + default: 91 + return 0; 92 + } 93 + } 94 + 95 + static const struct hwmon_ops hsmp_hwmon_ops = { 96 + .read = hsmp_hwmon_read, 97 + .is_visible = hsmp_hwmon_is_visble, 98 + .write = hsmp_hwmon_write, 99 + }; 100 + 101 + static const struct hwmon_channel_info * const hsmp_info[] = { 102 + HWMON_CHANNEL_INFO(power, HWMON_P_INPUT | HWMON_P_CAP | HWMON_P_CAP_MAX), 103 + NULL 104 + }; 105 + 106 + static const struct hwmon_chip_info hsmp_chip_info = { 107 + .ops = &hsmp_hwmon_ops, 108 + .info = hsmp_info, 109 + }; 110 + 111 + int hsmp_create_sensor(struct device *dev, u16 sock_ind) 112 + { 113 + struct device *hwmon_dev; 114 + 115 + hwmon_dev = devm_hwmon_device_register_with_info(dev, HSMP_HWMON_NAME, 116 + (void *)(uintptr_t)sock_ind, 117 + &hsmp_chip_info, 118 + NULL); 119 + return PTR_ERR_OR_ZERO(hwmon_dev); 120 + } 121 + EXPORT_SYMBOL_NS(hsmp_create_sensor, "AMD_HSMP");
+5 -1
drivers/platform/x86/amd/hsmp/plat.c
··· 24 24 #include "hsmp.h" 25 25 26 26 #define DRIVER_NAME "amd_hsmp" 27 - #define DRIVER_VERSION "2.3" 28 27 29 28 /* 30 29 * To access specific HSMP mailbox register, s/w writes the SMN address of HSMP mailbox ··· 189 190 if (ret) 190 191 dev_err(dev, "Failed to init metric table\n"); 191 192 } 193 + 194 + /* Register with hwmon interface for reporting power */ 195 + ret = hsmp_create_sensor(dev, i); 196 + if (ret) 197 + dev_err(dev, "Failed to register HSMP sensors with hwmon\n"); 192 198 } 193 199 194 200 return 0;
+109 -39
drivers/platform/x86/asus-wmi.c
··· 142 142 #define ASUS_MINI_LED_2024_STRONG 0x01 143 143 #define ASUS_MINI_LED_2024_OFF 0x02 144 144 145 - /* Controls the power state of the USB0 hub on ROG Ally which input is on */ 146 145 #define ASUS_USB0_PWR_EC0_CSEE "\\_SB.PCI0.SBRG.EC0.CSEE" 147 - /* 300ms so far seems to produce a reliable result on AC and battery */ 148 - #define ASUS_USB0_PWR_EC0_CSEE_WAIT 1500 146 + /* 147 + * The period required to wait after screen off/on/s2idle.check in MS. 148 + * Time here greatly impacts the wake behaviour. Used in suspend/wake. 149 + */ 150 + #define ASUS_USB0_PWR_EC0_CSEE_WAIT 600 151 + #define ASUS_USB0_PWR_EC0_CSEE_OFF 0xB7 152 + #define ASUS_USB0_PWR_EC0_CSEE_ON 0xB8 149 153 150 154 static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL }; 151 155 152 156 static int throttle_thermal_policy_write(struct asus_wmi *); 153 157 154 - static const struct dmi_system_id asus_ally_mcu_quirk[] = { 158 + static const struct dmi_system_id asus_rog_ally_device[] = { 155 159 { 156 160 .matches = { 157 161 DMI_MATCH(DMI_BOARD_NAME, "RC71L"), ··· 278 274 u32 tablet_switch_dev_id; 279 275 bool tablet_switch_inverted; 280 276 281 - /* The ROG Ally device requires the MCU USB device be disconnected before suspend */ 282 - bool ally_mcu_usb_switch; 283 - 284 277 enum fan_type fan_type; 285 278 enum fan_type gpu_fan_type; 286 279 enum fan_type mid_fan_type; ··· 336 335 337 336 struct asus_wmi_driver *driver; 338 337 }; 338 + 339 + /* Global to allow setting externally without requiring driver data */ 340 + static enum asus_ally_mcu_hack use_ally_mcu_hack = ASUS_WMI_ALLY_MCU_HACK_INIT; 339 341 340 342 /* WMI ************************************************************************/ 341 343 ··· 554 550 return 0; 555 551 } 556 552 557 - static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, 553 + int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, 558 554 u32 *retval) 559 555 { 560 556 return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id, ··· 1348 1344 static DEVICE_ATTR_RW(nv_temp_target); 1349 1345 1350 1346 /* Ally MCU Powersave ********************************************************/ 1347 + 1348 + /* 1349 + * The HID driver needs to check MCU version and set this to false if the MCU FW 1350 + * version is >= the minimum requirements. New FW do not need the hacks. 1351 + */ 1352 + void set_ally_mcu_hack(enum asus_ally_mcu_hack status) 1353 + { 1354 + use_ally_mcu_hack = status; 1355 + pr_debug("%s Ally MCU suspend quirk\n", 1356 + status == ASUS_WMI_ALLY_MCU_HACK_ENABLED ? "Enabled" : "Disabled"); 1357 + } 1358 + EXPORT_SYMBOL_NS_GPL(set_ally_mcu_hack, "ASUS_WMI"); 1359 + 1360 + /* 1361 + * mcu_powersave should be enabled always, as it is fixed in MCU FW versions: 1362 + * - v313 for Ally X 1363 + * - v319 for Ally 1 1364 + * The HID driver checks MCU versions and so should set this if requirements match 1365 + */ 1366 + void set_ally_mcu_powersave(bool enabled) 1367 + { 1368 + int result, err; 1369 + 1370 + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MCU_POWERSAVE, enabled, &result); 1371 + if (err) { 1372 + pr_warn("Failed to set MCU powersave: %d\n", err); 1373 + return; 1374 + } 1375 + if (result > 1) { 1376 + pr_warn("Failed to set MCU powersave (result): 0x%x\n", result); 1377 + return; 1378 + } 1379 + 1380 + pr_debug("%s MCU Powersave\n", 1381 + enabled ? "Enabled" : "Disabled"); 1382 + } 1383 + EXPORT_SYMBOL_NS_GPL(set_ally_mcu_powersave, "ASUS_WMI"); 1384 + 1351 1385 static ssize_t mcu_powersave_show(struct device *dev, 1352 1386 struct device_attribute *attr, char *buf) 1353 1387 { ··· 4754 4712 if (err) 4755 4713 goto fail_platform; 4756 4714 4715 + if (use_ally_mcu_hack == ASUS_WMI_ALLY_MCU_HACK_INIT) { 4716 + if (acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE) 4717 + && dmi_check_system(asus_rog_ally_device)) 4718 + use_ally_mcu_hack = ASUS_WMI_ALLY_MCU_HACK_ENABLED; 4719 + if (dmi_match(DMI_BOARD_NAME, "RC71")) { 4720 + /* 4721 + * These steps ensure the device is in a valid good state, this is 4722 + * especially important for the Ally 1 after a reboot. 4723 + */ 4724 + acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, 4725 + ASUS_USB0_PWR_EC0_CSEE_ON); 4726 + msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT); 4727 + } 4728 + } 4729 + 4757 4730 /* ensure defaults for tunables */ 4758 4731 asus->ppt_pl2_sppt = 5; 4759 4732 asus->ppt_pl1_spl = 5; ··· 4782 4725 asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU); 4783 4726 asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE); 4784 4727 asus->oobe_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_OOBE); 4785 - asus->ally_mcu_usb_switch = acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE) 4786 - && dmi_check_system(asus_ally_mcu_quirk); 4787 4728 4788 4729 if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE)) 4789 4730 asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE; ··· 4968 4913 return 0; 4969 4914 } 4970 4915 4971 - static int asus_hotk_resume_early(struct device *device) 4972 - { 4973 - struct asus_wmi *asus = dev_get_drvdata(device); 4974 - 4975 - if (asus->ally_mcu_usb_switch) { 4976 - /* sleep required to prevent USB0 being yanked then reappearing rapidly */ 4977 - if (ACPI_FAILURE(acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, 0xB8))) 4978 - dev_err(device, "ROG Ally MCU failed to connect USB dev\n"); 4979 - else 4980 - msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT); 4981 - } 4982 - return 0; 4983 - } 4984 - 4985 - static int asus_hotk_prepare(struct device *device) 4986 - { 4987 - struct asus_wmi *asus = dev_get_drvdata(device); 4988 - 4989 - if (asus->ally_mcu_usb_switch) { 4990 - /* sleep required to ensure USB0 is disabled before sleep continues */ 4991 - if (ACPI_FAILURE(acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, 0xB7))) 4992 - dev_err(device, "ROG Ally MCU failed to disconnect USB dev\n"); 4993 - else 4994 - msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT); 4995 - } 4996 - return 0; 4997 - } 4998 - 4999 4916 static int asus_hotk_restore(struct device *device) 5000 4917 { 5001 4918 struct asus_wmi *asus = dev_get_drvdata(device); ··· 5015 4988 return 0; 5016 4989 } 5017 4990 4991 + static int asus_hotk_prepare(struct device *device) 4992 + { 4993 + if (use_ally_mcu_hack == ASUS_WMI_ALLY_MCU_HACK_ENABLED) { 4994 + acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, 4995 + ASUS_USB0_PWR_EC0_CSEE_OFF); 4996 + msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT); 4997 + } 4998 + return 0; 4999 + } 5000 + 5001 + #if defined(CONFIG_SUSPEND) 5002 + static void asus_ally_s2idle_restore(void) 5003 + { 5004 + if (use_ally_mcu_hack == ASUS_WMI_ALLY_MCU_HACK_ENABLED) { 5005 + acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, 5006 + ASUS_USB0_PWR_EC0_CSEE_ON); 5007 + msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT); 5008 + } 5009 + } 5010 + 5011 + /* Use only for Ally devices due to the wake_on_ac */ 5012 + static struct acpi_s2idle_dev_ops asus_ally_s2idle_dev_ops = { 5013 + .restore = asus_ally_s2idle_restore, 5014 + }; 5015 + 5016 + static void asus_s2idle_check_register(void) 5017 + { 5018 + if (acpi_register_lps0_dev(&asus_ally_s2idle_dev_ops)) 5019 + pr_warn("failed to register LPS0 sleep handler in asus-wmi\n"); 5020 + } 5021 + 5022 + static void asus_s2idle_check_unregister(void) 5023 + { 5024 + acpi_unregister_lps0_dev(&asus_ally_s2idle_dev_ops); 5025 + } 5026 + #else 5027 + static void asus_s2idle_check_register(void) {} 5028 + static void asus_s2idle_check_unregister(void) {} 5029 + #endif /* CONFIG_SUSPEND */ 5030 + 5018 5031 static const struct dev_pm_ops asus_pm_ops = { 5019 5032 .thaw = asus_hotk_thaw, 5020 5033 .restore = asus_hotk_restore, 5021 5034 .resume = asus_hotk_resume, 5022 - .resume_early = asus_hotk_resume_early, 5023 5035 .prepare = asus_hotk_prepare, 5024 5036 }; 5025 5037 ··· 5085 5019 if (ret) 5086 5020 return ret; 5087 5021 } 5022 + 5023 + asus_s2idle_check_register(); 5088 5024 5089 5025 return asus_wmi_add(pdev); 5090 5026 } ··· 5120 5052 5121 5053 void asus_wmi_unregister_driver(struct asus_wmi_driver *driver) 5122 5054 { 5055 + asus_s2idle_check_unregister(); 5056 + 5123 5057 platform_device_unregister(driver->platform_device); 5124 5058 platform_driver_unregister(&driver->platform_driver); 5125 5059 used = false;
+7 -3
drivers/platform/x86/barco-p50-gpio.c
··· 268 268 return ret; 269 269 } 270 270 271 - static void p50_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) 271 + static int p50_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) 272 272 { 273 273 struct p50_gpio *p50 = gpiochip_get_data(gc); 274 + int ret; 274 275 275 276 mutex_lock(&p50->lock); 276 277 277 - p50_send_mbox_cmd(p50, P50_MBOX_CMD_WRITE_GPIO, gpio_params[offset], value); 278 + ret = p50_send_mbox_cmd(p50, P50_MBOX_CMD_WRITE_GPIO, 279 + gpio_params[offset], value); 278 280 279 281 mutex_unlock(&p50->lock); 282 + 283 + return ret; 280 284 } 281 285 282 286 static int p50_gpio_probe(struct platform_device *pdev) ··· 316 312 p50->gc.base = -1; 317 313 p50->gc.get_direction = p50_gpio_get_direction; 318 314 p50->gc.get = p50_gpio_get; 319 - p50->gc.set = p50_gpio_set; 315 + p50->gc.set_rv = p50_gpio_set; 320 316 321 317 322 318 /* reset mbox */
+360
drivers/platform/x86/dasharo-acpi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Dasharo ACPI Driver 4 + */ 5 + 6 + #include <linux/acpi.h> 7 + #include <linux/array_size.h> 8 + #include <linux/hwmon.h> 9 + #include <linux/module.h> 10 + #include <linux/platform_device.h> 11 + #include <linux/types.h> 12 + #include <linux/units.h> 13 + 14 + enum dasharo_feature { 15 + DASHARO_FEATURE_TEMPERATURE = 0, 16 + DASHARO_FEATURE_FAN_PWM, 17 + DASHARO_FEATURE_FAN_TACH, 18 + DASHARO_FEATURE_MAX 19 + }; 20 + 21 + enum dasharo_temperature { 22 + DASHARO_TEMPERATURE_CPU_PACKAGE = 0, 23 + DASHARO_TEMPERATURE_CPU_CORE, 24 + DASHARO_TEMPERATURE_GPU, 25 + DASHARO_TEMPERATURE_BOARD, 26 + DASHARO_TEMPERATURE_CHASSIS, 27 + DASHARO_TEMPERATURE_MAX 28 + }; 29 + 30 + enum dasharo_fan { 31 + DASHARO_FAN_CPU = 0, 32 + DASHARO_FAN_GPU, 33 + DASHARO_FAN_CHASSIS, 34 + DASHARO_FAN_MAX 35 + }; 36 + 37 + #define MAX_GROUPS_PER_FEAT 8 38 + 39 + static const char * const dasharo_group_names[DASHARO_FEATURE_MAX][MAX_GROUPS_PER_FEAT] = { 40 + [DASHARO_FEATURE_TEMPERATURE] = { 41 + [DASHARO_TEMPERATURE_CPU_PACKAGE] = "CPU Package", 42 + [DASHARO_TEMPERATURE_CPU_CORE] = "CPU Core", 43 + [DASHARO_TEMPERATURE_GPU] = "GPU", 44 + [DASHARO_TEMPERATURE_BOARD] = "Board", 45 + [DASHARO_TEMPERATURE_CHASSIS] = "Chassis", 46 + }, 47 + [DASHARO_FEATURE_FAN_PWM] = { 48 + [DASHARO_FAN_CPU] = "CPU", 49 + [DASHARO_FAN_GPU] = "GPU", 50 + [DASHARO_FAN_CHASSIS] = "Chassis", 51 + }, 52 + [DASHARO_FEATURE_FAN_TACH] = { 53 + [DASHARO_FAN_CPU] = "CPU", 54 + [DASHARO_FAN_GPU] = "GPU", 55 + [DASHARO_FAN_CHASSIS] = "Chassis", 56 + }, 57 + }; 58 + 59 + struct dasharo_capability { 60 + unsigned int group; 61 + unsigned int index; 62 + char name[16]; 63 + }; 64 + 65 + #define MAX_CAPS_PER_FEAT 24 66 + 67 + struct dasharo_data { 68 + struct platform_device *pdev; 69 + int caps_found[DASHARO_FEATURE_MAX]; 70 + struct dasharo_capability capabilities[DASHARO_FEATURE_MAX][MAX_CAPS_PER_FEAT]; 71 + }; 72 + 73 + static int dasharo_get_feature_cap_count(struct dasharo_data *data, enum dasharo_feature feat, int cap) 74 + { 75 + struct acpi_object_list obj_list; 76 + union acpi_object obj[2]; 77 + acpi_handle handle; 78 + acpi_status status; 79 + u64 count; 80 + 81 + obj[0].type = ACPI_TYPE_INTEGER; 82 + obj[0].integer.value = feat; 83 + obj[1].type = ACPI_TYPE_INTEGER; 84 + obj[1].integer.value = cap; 85 + obj_list.count = 2; 86 + obj_list.pointer = &obj[0]; 87 + 88 + handle = ACPI_HANDLE(&data->pdev->dev); 89 + status = acpi_evaluate_integer(handle, "GFCP", &obj_list, &count); 90 + if (ACPI_FAILURE(status)) 91 + return -ENODEV; 92 + 93 + return count; 94 + } 95 + 96 + static int dasharo_read_channel(struct dasharo_data *data, char *method, enum dasharo_feature feat, int channel, long *value) 97 + { 98 + struct acpi_object_list obj_list; 99 + union acpi_object obj[2]; 100 + acpi_handle handle; 101 + acpi_status status; 102 + u64 val; 103 + 104 + if (feat >= ARRAY_SIZE(data->capabilities)) 105 + return -EINVAL; 106 + 107 + if (channel >= data->caps_found[feat]) 108 + return -EINVAL; 109 + 110 + obj[0].type = ACPI_TYPE_INTEGER; 111 + obj[0].integer.value = data->capabilities[feat][channel].group; 112 + obj[1].type = ACPI_TYPE_INTEGER; 113 + obj[1].integer.value = data->capabilities[feat][channel].index; 114 + obj_list.count = 2; 115 + obj_list.pointer = &obj[0]; 116 + 117 + handle = ACPI_HANDLE(&data->pdev->dev); 118 + status = acpi_evaluate_integer(handle, method, &obj_list, &val); 119 + if (ACPI_FAILURE(status)) 120 + return -ENODEV; 121 + 122 + *value = val; 123 + return 0; 124 + } 125 + 126 + static int dasharo_hwmon_read(struct device *dev, enum hwmon_sensor_types type, 127 + u32 attr, int channel, long *val) 128 + { 129 + struct dasharo_data *data = dev_get_drvdata(dev); 130 + long value; 131 + int ret; 132 + 133 + switch (type) { 134 + case hwmon_temp: 135 + ret = dasharo_read_channel(data, "GTMP", DASHARO_FEATURE_TEMPERATURE, channel, &value); 136 + if (!ret) 137 + *val = value * MILLIDEGREE_PER_DEGREE; 138 + break; 139 + case hwmon_fan: 140 + ret = dasharo_read_channel(data, "GFTH", DASHARO_FEATURE_FAN_TACH, channel, &value); 141 + if (!ret) 142 + *val = value; 143 + break; 144 + case hwmon_pwm: 145 + ret = dasharo_read_channel(data, "GFDC", DASHARO_FEATURE_FAN_PWM, channel, &value); 146 + if (!ret) 147 + *val = value; 148 + break; 149 + default: 150 + return -ENODEV; 151 + break; 152 + } 153 + 154 + return ret; 155 + } 156 + 157 + static int dasharo_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type, 158 + u32 attr, int channel, const char **str) 159 + { 160 + struct dasharo_data *data = dev_get_drvdata(dev); 161 + 162 + switch (type) { 163 + case hwmon_temp: 164 + if (channel >= data->caps_found[DASHARO_FEATURE_TEMPERATURE]) 165 + return -EINVAL; 166 + 167 + *str = data->capabilities[DASHARO_FEATURE_TEMPERATURE][channel].name; 168 + break; 169 + case hwmon_fan: 170 + if (channel >= data->caps_found[DASHARO_FEATURE_FAN_TACH]) 171 + return -EINVAL; 172 + 173 + *str = data->capabilities[DASHARO_FEATURE_FAN_TACH][channel].name; 174 + break; 175 + default: 176 + return -EOPNOTSUPP; 177 + } 178 + 179 + return 0; 180 + } 181 + 182 + static umode_t dasharo_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type, 183 + u32 attr, int channel) 184 + { 185 + const struct dasharo_data *data = drvdata; 186 + 187 + switch (type) { 188 + case hwmon_temp: 189 + if (channel < data->caps_found[DASHARO_FEATURE_TEMPERATURE]) 190 + return 0444; 191 + break; 192 + case hwmon_pwm: 193 + if (channel < data->caps_found[DASHARO_FEATURE_FAN_PWM]) 194 + return 0444; 195 + break; 196 + case hwmon_fan: 197 + if (channel < data->caps_found[DASHARO_FEATURE_FAN_TACH]) 198 + return 0444; 199 + break; 200 + default: 201 + break; 202 + } 203 + 204 + return 0; 205 + } 206 + 207 + static const struct hwmon_ops dasharo_hwmon_ops = { 208 + .is_visible = dasharo_hwmon_is_visible, 209 + .read_string = dasharo_hwmon_read_string, 210 + .read = dasharo_hwmon_read, 211 + }; 212 + 213 + // Max 24 capabilities per feature 214 + static const struct hwmon_channel_info * const dasharo_hwmon_info[] = { 215 + HWMON_CHANNEL_INFO(fan, 216 + HWMON_F_INPUT | HWMON_F_LABEL, 217 + HWMON_F_INPUT | HWMON_F_LABEL, 218 + HWMON_F_INPUT | HWMON_F_LABEL, 219 + HWMON_F_INPUT | HWMON_F_LABEL, 220 + HWMON_F_INPUT | HWMON_F_LABEL, 221 + HWMON_F_INPUT | HWMON_F_LABEL, 222 + HWMON_F_INPUT | HWMON_F_LABEL, 223 + HWMON_F_INPUT | HWMON_F_LABEL, 224 + HWMON_F_INPUT | HWMON_F_LABEL, 225 + HWMON_F_INPUT | HWMON_F_LABEL, 226 + HWMON_F_INPUT | HWMON_F_LABEL, 227 + HWMON_F_INPUT | HWMON_F_LABEL, 228 + HWMON_F_INPUT | HWMON_F_LABEL, 229 + HWMON_F_INPUT | HWMON_F_LABEL, 230 + HWMON_F_INPUT | HWMON_F_LABEL, 231 + HWMON_F_INPUT | HWMON_F_LABEL, 232 + HWMON_F_INPUT | HWMON_F_LABEL, 233 + HWMON_F_INPUT | HWMON_F_LABEL, 234 + HWMON_F_INPUT | HWMON_F_LABEL, 235 + HWMON_F_INPUT | HWMON_F_LABEL, 236 + HWMON_F_INPUT | HWMON_F_LABEL, 237 + HWMON_F_INPUT | HWMON_F_LABEL, 238 + HWMON_F_INPUT | HWMON_F_LABEL, 239 + HWMON_F_INPUT | HWMON_F_LABEL), 240 + HWMON_CHANNEL_INFO(temp, 241 + HWMON_T_INPUT | HWMON_T_LABEL, 242 + HWMON_T_INPUT | HWMON_T_LABEL, 243 + HWMON_T_INPUT | HWMON_T_LABEL, 244 + HWMON_T_INPUT | HWMON_T_LABEL, 245 + HWMON_T_INPUT | HWMON_T_LABEL, 246 + HWMON_T_INPUT | HWMON_T_LABEL, 247 + HWMON_T_INPUT | HWMON_T_LABEL, 248 + HWMON_T_INPUT | HWMON_T_LABEL, 249 + HWMON_T_INPUT | HWMON_T_LABEL, 250 + HWMON_T_INPUT | HWMON_T_LABEL, 251 + HWMON_T_INPUT | HWMON_T_LABEL, 252 + HWMON_T_INPUT | HWMON_T_LABEL, 253 + HWMON_T_INPUT | HWMON_T_LABEL, 254 + HWMON_T_INPUT | HWMON_T_LABEL, 255 + HWMON_T_INPUT | HWMON_T_LABEL, 256 + HWMON_T_INPUT | HWMON_T_LABEL, 257 + HWMON_T_INPUT | HWMON_T_LABEL, 258 + HWMON_T_INPUT | HWMON_T_LABEL, 259 + HWMON_T_INPUT | HWMON_T_LABEL, 260 + HWMON_T_INPUT | HWMON_T_LABEL, 261 + HWMON_T_INPUT | HWMON_T_LABEL, 262 + HWMON_T_INPUT | HWMON_T_LABEL, 263 + HWMON_T_INPUT | HWMON_T_LABEL, 264 + HWMON_T_INPUT | HWMON_T_LABEL), 265 + HWMON_CHANNEL_INFO(pwm, 266 + HWMON_PWM_INPUT, 267 + HWMON_PWM_INPUT, 268 + HWMON_PWM_INPUT, 269 + HWMON_PWM_INPUT, 270 + HWMON_PWM_INPUT, 271 + HWMON_PWM_INPUT, 272 + HWMON_PWM_INPUT, 273 + HWMON_PWM_INPUT, 274 + HWMON_PWM_INPUT, 275 + HWMON_PWM_INPUT, 276 + HWMON_PWM_INPUT, 277 + HWMON_PWM_INPUT, 278 + HWMON_PWM_INPUT, 279 + HWMON_PWM_INPUT, 280 + HWMON_PWM_INPUT, 281 + HWMON_PWM_INPUT, 282 + HWMON_PWM_INPUT, 283 + HWMON_PWM_INPUT, 284 + HWMON_PWM_INPUT, 285 + HWMON_PWM_INPUT, 286 + HWMON_PWM_INPUT, 287 + HWMON_PWM_INPUT, 288 + HWMON_PWM_INPUT, 289 + HWMON_PWM_INPUT), 290 + NULL 291 + }; 292 + 293 + static const struct hwmon_chip_info dasharo_hwmon_chip_info = { 294 + .ops = &dasharo_hwmon_ops, 295 + .info = dasharo_hwmon_info, 296 + }; 297 + 298 + static void dasharo_fill_feature_caps(struct dasharo_data *data, enum dasharo_feature feat) 299 + { 300 + struct dasharo_capability *cap; 301 + int cap_count = 0; 302 + int count; 303 + 304 + for (int group = 0; group < MAX_GROUPS_PER_FEAT; ++group) { 305 + count = dasharo_get_feature_cap_count(data, feat, group); 306 + if (count <= 0) 307 + continue; 308 + 309 + for (unsigned int i = 0; i < count; ++i) { 310 + if (cap_count >= ARRAY_SIZE(data->capabilities[feat])) 311 + break; 312 + 313 + cap = &data->capabilities[feat][cap_count]; 314 + cap->group = group; 315 + cap->index = i; 316 + scnprintf(cap->name, sizeof(cap->name), "%s %d", 317 + dasharo_group_names[feat][group], i); 318 + cap_count++; 319 + } 320 + } 321 + data->caps_found[feat] = cap_count; 322 + } 323 + 324 + static int dasharo_probe(struct platform_device *pdev) 325 + { 326 + struct dasharo_data *data; 327 + struct device *hwmon; 328 + 329 + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 330 + if (!data) 331 + return -ENOMEM; 332 + data->pdev = pdev; 333 + 334 + for (unsigned int i = 0; i < DASHARO_FEATURE_MAX; ++i) 335 + dasharo_fill_feature_caps(data, i); 336 + 337 + hwmon = devm_hwmon_device_register_with_info(&pdev->dev, "dasharo_acpi", data, 338 + &dasharo_hwmon_chip_info, NULL); 339 + 340 + return PTR_ERR_OR_ZERO(hwmon); 341 + } 342 + 343 + static const struct acpi_device_id dasharo_device_ids[] = { 344 + {"DSHR0001", 0}, 345 + {} 346 + }; 347 + MODULE_DEVICE_TABLE(acpi, dasharo_device_ids); 348 + 349 + static struct platform_driver dasharo_driver = { 350 + .driver = { 351 + .name = "dasharo-acpi", 352 + .acpi_match_table = dasharo_device_ids, 353 + }, 354 + .probe = dasharo_probe, 355 + }; 356 + module_platform_driver(dasharo_driver); 357 + 358 + MODULE_DESCRIPTION("Dasharo ACPI Driver"); 359 + MODULE_AUTHOR("Michał Kopeć <michal.kopec@3mdeb.com>"); 360 + MODULE_LICENSE("GPL");
+2 -1
drivers/platform/x86/dell/Kconfig
··· 22 22 depends on DMI 23 23 depends on LEDS_CLASS 24 24 depends on NEW_LEDS 25 + depends on HWMON 25 26 help 26 27 This is a driver for controlling Alienware WMI driven features. 27 28 ··· 172 171 173 172 config DELL_SMO8800 174 173 tristate "Dell Latitude freefall driver (ACPI SMO88XX)" 175 - default m 174 + default m if ACPI 176 175 depends on I2C 177 176 depends on ACPI || COMPILE_TEST 178 177 help
+982 -137
drivers/platform/x86/dell/alienware-wmi-wmax.c
··· 8 8 9 9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 10 11 + #include <linux/array_size.h> 11 12 #include <linux/bitfield.h> 13 + #include <linux/bitmap.h> 12 14 #include <linux/bits.h> 15 + #include <linux/debugfs.h> 13 16 #include <linux/dmi.h> 17 + #include <linux/hwmon.h> 18 + #include <linux/hwmon-sysfs.h> 19 + #include <linux/kstrtox.h> 20 + #include <linux/minmax.h> 14 21 #include <linux/moduleparam.h> 15 22 #include <linux/platform_profile.h> 23 + #include <linux/pm.h> 24 + #include <linux/seq_file.h> 25 + #include <linux/units.h> 16 26 #include <linux/wmi.h> 17 27 #include "alienware-wmi.h" 18 28 ··· 34 24 #define WMAX_METHOD_DEEP_SLEEP_STATUS 0x0C 35 25 #define WMAX_METHOD_BRIGHTNESS 0x3 36 26 #define WMAX_METHOD_ZONE_CONTROL 0x4 37 - #define WMAX_METHOD_THERMAL_INFORMATION 0x14 38 - #define WMAX_METHOD_THERMAL_CONTROL 0x15 39 - #define WMAX_METHOD_GAME_SHIFT_STATUS 0x25 40 27 41 - #define WMAX_THERMAL_MODE_GMODE 0xAB 28 + #define AWCC_METHOD_GET_FAN_SENSORS 0x13 29 + #define AWCC_METHOD_THERMAL_INFORMATION 0x14 30 + #define AWCC_METHOD_THERMAL_CONTROL 0x15 31 + #define AWCC_METHOD_FWUP_GPIO_CONTROL 0x20 32 + #define AWCC_METHOD_READ_TOTAL_GPIOS 0x21 33 + #define AWCC_METHOD_READ_GPIO_STATUS 0x22 34 + #define AWCC_METHOD_GAME_SHIFT_STATUS 0x25 42 35 43 - #define WMAX_FAILURE_CODE 0xFFFFFFFF 44 - #define WMAX_THERMAL_TABLE_MASK GENMASK(7, 4) 45 - #define WMAX_THERMAL_MODE_MASK GENMASK(3, 0) 46 - #define WMAX_SENSOR_ID_MASK BIT(8) 36 + #define AWCC_FAILURE_CODE 0xFFFFFFFF 37 + #define AWCC_FAILURE_CODE_2 0xFFFFFFFE 38 + 39 + #define AWCC_SENSOR_ID_FLAG BIT(8) 40 + #define AWCC_THERMAL_MODE_MASK GENMASK(3, 0) 41 + #define AWCC_THERMAL_TABLE_MASK GENMASK(7, 4) 42 + #define AWCC_RESOURCE_ID_MASK GENMASK(7, 0) 43 + 44 + /* Arbitrary limit based on supported models */ 45 + #define AWCC_MAX_RES_COUNT 16 46 + #define AWCC_ID_BITMAP_SIZE (U8_MAX + 1) 47 + #define AWCC_ID_BITMAP_LONGS BITS_TO_LONGS(AWCC_ID_BITMAP_SIZE) 48 + 49 + static bool force_hwmon; 50 + module_param_unsafe(force_hwmon, bool, 0); 51 + MODULE_PARM_DESC(force_hwmon, "Force probing for HWMON support without checking if the WMI backend is available"); 47 52 48 53 static bool force_platform_profile; 49 54 module_param_unsafe(force_platform_profile, bool, 0); ··· 69 44 MODULE_PARM_DESC(force_gmode, "Forces G-Mode when performance profile is selected"); 70 45 71 46 struct awcc_quirks { 47 + bool hwmon; 72 48 bool pprof; 73 49 bool gmode; 74 50 }; 75 51 76 52 static struct awcc_quirks g_series_quirks = { 53 + .hwmon = true, 77 54 .pprof = true, 78 55 .gmode = true, 79 56 }; 80 57 81 58 static struct awcc_quirks generic_quirks = { 59 + .hwmon = true, 82 60 .pprof = true, 83 61 .gmode = false, 84 62 }; ··· 235 207 }, 236 208 }; 237 209 238 - enum WMAX_THERMAL_INFORMATION_OPERATIONS { 239 - WMAX_OPERATION_SYS_DESCRIPTION = 0x02, 240 - WMAX_OPERATION_LIST_IDS = 0x03, 241 - WMAX_OPERATION_CURRENT_PROFILE = 0x0B, 210 + enum AWCC_GET_FAN_SENSORS_OPERATIONS { 211 + AWCC_OP_GET_TOTAL_FAN_TEMPS = 0x01, 212 + AWCC_OP_GET_FAN_TEMP_ID = 0x02, 242 213 }; 243 214 244 - enum WMAX_THERMAL_CONTROL_OPERATIONS { 245 - WMAX_OPERATION_ACTIVATE_PROFILE = 0x01, 215 + enum AWCC_THERMAL_INFORMATION_OPERATIONS { 216 + AWCC_OP_GET_SYSTEM_DESCRIPTION = 0x02, 217 + AWCC_OP_GET_RESOURCE_ID = 0x03, 218 + AWCC_OP_GET_TEMPERATURE = 0x04, 219 + AWCC_OP_GET_FAN_RPM = 0x05, 220 + AWCC_OP_GET_FAN_MIN_RPM = 0x08, 221 + AWCC_OP_GET_FAN_MAX_RPM = 0x09, 222 + AWCC_OP_GET_CURRENT_PROFILE = 0x0B, 223 + AWCC_OP_GET_FAN_BOOST = 0x0C, 246 224 }; 247 225 248 - enum WMAX_GAME_SHIFT_STATUS_OPERATIONS { 249 - WMAX_OPERATION_TOGGLE_GAME_SHIFT = 0x01, 250 - WMAX_OPERATION_GET_GAME_SHIFT_STATUS = 0x02, 226 + enum AWCC_THERMAL_CONTROL_OPERATIONS { 227 + AWCC_OP_ACTIVATE_PROFILE = 0x01, 228 + AWCC_OP_SET_FAN_BOOST = 0x02, 251 229 }; 252 230 253 - enum WMAX_THERMAL_TABLES { 254 - WMAX_THERMAL_TABLE_BASIC = 0x90, 255 - WMAX_THERMAL_TABLE_USTT = 0xA0, 231 + enum AWCC_GAME_SHIFT_STATUS_OPERATIONS { 232 + AWCC_OP_TOGGLE_GAME_SHIFT = 0x01, 233 + AWCC_OP_GET_GAME_SHIFT_STATUS = 0x02, 256 234 }; 257 235 258 - enum wmax_thermal_mode { 259 - THERMAL_MODE_USTT_BALANCED, 260 - THERMAL_MODE_USTT_BALANCED_PERFORMANCE, 261 - THERMAL_MODE_USTT_COOL, 262 - THERMAL_MODE_USTT_QUIET, 263 - THERMAL_MODE_USTT_PERFORMANCE, 264 - THERMAL_MODE_USTT_LOW_POWER, 265 - THERMAL_MODE_BASIC_QUIET, 266 - THERMAL_MODE_BASIC_BALANCED, 267 - THERMAL_MODE_BASIC_BALANCED_PERFORMANCE, 268 - THERMAL_MODE_BASIC_PERFORMANCE, 269 - THERMAL_MODE_LAST, 236 + enum AWCC_THERMAL_TABLES { 237 + AWCC_THERMAL_TABLE_LEGACY = 0x9, 238 + AWCC_THERMAL_TABLE_USTT = 0xA, 239 + }; 240 + 241 + enum AWCC_SPECIAL_THERMAL_CODES { 242 + AWCC_SPECIAL_PROFILE_CUSTOM = 0x00, 243 + AWCC_SPECIAL_PROFILE_GMODE = 0xAB, 244 + }; 245 + 246 + enum AWCC_TEMP_SENSOR_TYPES { 247 + AWCC_TEMP_SENSOR_CPU = 0x01, 248 + AWCC_TEMP_SENSOR_GPU = 0x06, 249 + }; 250 + 251 + enum awcc_thermal_profile { 252 + AWCC_PROFILE_USTT_BALANCED, 253 + AWCC_PROFILE_USTT_BALANCED_PERFORMANCE, 254 + AWCC_PROFILE_USTT_COOL, 255 + AWCC_PROFILE_USTT_QUIET, 256 + AWCC_PROFILE_USTT_PERFORMANCE, 257 + AWCC_PROFILE_USTT_LOW_POWER, 258 + AWCC_PROFILE_LEGACY_QUIET, 259 + AWCC_PROFILE_LEGACY_BALANCED, 260 + AWCC_PROFILE_LEGACY_BALANCED_PERFORMANCE, 261 + AWCC_PROFILE_LEGACY_PERFORMANCE, 262 + AWCC_PROFILE_LAST, 270 263 }; 271 264 272 265 struct wmax_led_args { ··· 312 263 u8 arg3; 313 264 }; 314 265 315 - struct awcc_priv { 316 - struct wmi_device *wdev; 317 - struct device *ppdev; 318 - enum wmax_thermal_mode supported_thermal_profiles[PLATFORM_PROFILE_LAST]; 266 + struct awcc_fan_data { 267 + unsigned long auto_channels_temp; 268 + const char *label; 269 + u32 min_rpm; 270 + u32 max_rpm; 271 + u8 suspend_cache; 272 + u8 id; 319 273 }; 320 274 321 - static const enum platform_profile_option wmax_mode_to_platform_profile[THERMAL_MODE_LAST] = { 322 - [THERMAL_MODE_USTT_BALANCED] = PLATFORM_PROFILE_BALANCED, 323 - [THERMAL_MODE_USTT_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE, 324 - [THERMAL_MODE_USTT_COOL] = PLATFORM_PROFILE_COOL, 325 - [THERMAL_MODE_USTT_QUIET] = PLATFORM_PROFILE_QUIET, 326 - [THERMAL_MODE_USTT_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE, 327 - [THERMAL_MODE_USTT_LOW_POWER] = PLATFORM_PROFILE_LOW_POWER, 328 - [THERMAL_MODE_BASIC_QUIET] = PLATFORM_PROFILE_QUIET, 329 - [THERMAL_MODE_BASIC_BALANCED] = PLATFORM_PROFILE_BALANCED, 330 - [THERMAL_MODE_BASIC_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE, 331 - [THERMAL_MODE_BASIC_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE, 275 + struct awcc_priv { 276 + struct wmi_device *wdev; 277 + union { 278 + u32 system_description; 279 + struct { 280 + u8 fan_count; 281 + u8 temp_count; 282 + u8 unknown_count; 283 + u8 profile_count; 284 + }; 285 + u8 res_count[4]; 286 + }; 287 + 288 + struct device *ppdev; 289 + u8 supported_profiles[PLATFORM_PROFILE_LAST]; 290 + 291 + struct device *hwdev; 292 + struct awcc_fan_data **fan_data; 293 + unsigned long temp_sensors[AWCC_ID_BITMAP_LONGS]; 294 + 295 + u32 gpio_count; 296 + }; 297 + 298 + static const enum platform_profile_option awcc_mode_to_platform_profile[AWCC_PROFILE_LAST] = { 299 + [AWCC_PROFILE_USTT_BALANCED] = PLATFORM_PROFILE_BALANCED, 300 + [AWCC_PROFILE_USTT_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE, 301 + [AWCC_PROFILE_USTT_COOL] = PLATFORM_PROFILE_COOL, 302 + [AWCC_PROFILE_USTT_QUIET] = PLATFORM_PROFILE_QUIET, 303 + [AWCC_PROFILE_USTT_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE, 304 + [AWCC_PROFILE_USTT_LOW_POWER] = PLATFORM_PROFILE_LOW_POWER, 305 + [AWCC_PROFILE_LEGACY_QUIET] = PLATFORM_PROFILE_QUIET, 306 + [AWCC_PROFILE_LEGACY_BALANCED] = PLATFORM_PROFILE_BALANCED, 307 + [AWCC_PROFILE_LEGACY_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE, 308 + [AWCC_PROFILE_LEGACY_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE, 332 309 }; 333 310 334 311 static struct awcc_quirks *awcc; ··· 572 497 }; 573 498 574 499 /* 575 - * Thermal Profile control 576 - * - Provides thermal profile control through the Platform Profile API 500 + * AWCC Helpers 577 501 */ 578 - static bool is_wmax_thermal_code(u32 code) 502 + static bool is_awcc_thermal_profile_id(u8 code) 579 503 { 580 - if (code & WMAX_SENSOR_ID_MASK) 504 + u8 table = FIELD_GET(AWCC_THERMAL_TABLE_MASK, code); 505 + u8 mode = FIELD_GET(AWCC_THERMAL_MODE_MASK, code); 506 + 507 + if (mode >= AWCC_PROFILE_LAST) 581 508 return false; 582 509 583 - if ((code & WMAX_THERMAL_MODE_MASK) >= THERMAL_MODE_LAST) 584 - return false; 585 - 586 - if ((code & WMAX_THERMAL_TABLE_MASK) == WMAX_THERMAL_TABLE_BASIC && 587 - (code & WMAX_THERMAL_MODE_MASK) >= THERMAL_MODE_BASIC_QUIET) 510 + if (table == AWCC_THERMAL_TABLE_LEGACY && mode >= AWCC_PROFILE_LEGACY_QUIET) 588 511 return true; 589 512 590 - if ((code & WMAX_THERMAL_TABLE_MASK) == WMAX_THERMAL_TABLE_USTT && 591 - (code & WMAX_THERMAL_MODE_MASK) <= THERMAL_MODE_USTT_LOW_POWER) 513 + if (table == AWCC_THERMAL_TABLE_USTT && mode <= AWCC_PROFILE_USTT_LOW_POWER) 592 514 return true; 593 515 594 516 return false; 595 517 } 596 518 597 - static int wmax_thermal_information(struct wmi_device *wdev, u8 operation, 598 - u8 arg, u32 *out_data) 519 + static int awcc_wmi_command(struct wmi_device *wdev, u32 method_id, 520 + struct wmax_u32_args *args, u32 *out) 599 521 { 600 - struct wmax_u32_args in_args = { 522 + int ret; 523 + 524 + ret = alienware_wmi_command(wdev, method_id, args, sizeof(*args), out); 525 + if (ret) 526 + return ret; 527 + 528 + if (*out == AWCC_FAILURE_CODE || *out == AWCC_FAILURE_CODE_2) 529 + return -EBADRQC; 530 + 531 + return 0; 532 + } 533 + 534 + static int awcc_get_fan_sensors(struct wmi_device *wdev, u8 operation, 535 + u8 fan_id, u8 index, u32 *out) 536 + { 537 + struct wmax_u32_args args = { 538 + .operation = operation, 539 + .arg1 = fan_id, 540 + .arg2 = index, 541 + .arg3 = 0, 542 + }; 543 + 544 + return awcc_wmi_command(wdev, AWCC_METHOD_GET_FAN_SENSORS, &args, out); 545 + } 546 + 547 + static int awcc_thermal_information(struct wmi_device *wdev, u8 operation, u8 arg, 548 + u32 *out) 549 + { 550 + struct wmax_u32_args args = { 601 551 .operation = operation, 602 552 .arg1 = arg, 603 553 .arg2 = 0, 604 554 .arg3 = 0, 605 555 }; 606 - int ret; 607 556 608 - ret = alienware_wmi_command(wdev, WMAX_METHOD_THERMAL_INFORMATION, 609 - &in_args, sizeof(in_args), out_data); 610 - if (ret < 0) 611 - return ret; 612 - 613 - if (*out_data == WMAX_FAILURE_CODE) 614 - return -EBADRQC; 615 - 616 - return 0; 557 + return awcc_wmi_command(wdev, AWCC_METHOD_THERMAL_INFORMATION, &args, out); 617 558 } 618 559 619 - static int wmax_thermal_control(struct wmi_device *wdev, u8 profile) 560 + static int awcc_fwup_gpio_control(struct wmi_device *wdev, u8 pin, u8 status) 620 561 { 621 - struct wmax_u32_args in_args = { 622 - .operation = WMAX_OPERATION_ACTIVATE_PROFILE, 623 - .arg1 = profile, 562 + struct wmax_u32_args args = { 563 + .operation = pin, 564 + .arg1 = status, 624 565 .arg2 = 0, 625 566 .arg3 = 0, 626 567 }; 627 - u32 out_data; 628 - int ret; 568 + u32 out; 629 569 630 - ret = alienware_wmi_command(wdev, WMAX_METHOD_THERMAL_CONTROL, 631 - &in_args, sizeof(in_args), &out_data); 632 - if (ret) 633 - return ret; 634 - 635 - if (out_data == WMAX_FAILURE_CODE) 636 - return -EBADRQC; 637 - 638 - return 0; 570 + return awcc_wmi_command(wdev, AWCC_METHOD_FWUP_GPIO_CONTROL, &args, &out); 639 571 } 640 572 641 - static int wmax_game_shift_status(struct wmi_device *wdev, u8 operation, 642 - u32 *out_data) 573 + static int awcc_read_total_gpios(struct wmi_device *wdev, u32 *count) 643 574 { 644 - struct wmax_u32_args in_args = { 575 + struct wmax_u32_args args = {}; 576 + 577 + return awcc_wmi_command(wdev, AWCC_METHOD_READ_TOTAL_GPIOS, &args, count); 578 + } 579 + 580 + static int awcc_read_gpio_status(struct wmi_device *wdev, u8 pin, u32 *status) 581 + { 582 + struct wmax_u32_args args = { 583 + .operation = pin, 584 + .arg1 = 0, 585 + .arg2 = 0, 586 + .arg3 = 0, 587 + }; 588 + 589 + return awcc_wmi_command(wdev, AWCC_METHOD_READ_GPIO_STATUS, &args, status); 590 + } 591 + 592 + static int awcc_game_shift_status(struct wmi_device *wdev, u8 operation, 593 + u32 *out) 594 + { 595 + struct wmax_u32_args args = { 645 596 .operation = operation, 646 597 .arg1 = 0, 647 598 .arg2 = 0, 648 599 .arg3 = 0, 649 600 }; 601 + 602 + return awcc_wmi_command(wdev, AWCC_METHOD_GAME_SHIFT_STATUS, &args, out); 603 + } 604 + 605 + /** 606 + * awcc_op_get_resource_id - Get the resource ID at a given index 607 + * @wdev: AWCC WMI device 608 + * @index: Index 609 + * @out: Value returned by the WMI call 610 + * 611 + * Get the resource ID at a given @index. Resource IDs are listed in the 612 + * following order: 613 + * 614 + * - Fan IDs 615 + * - Sensor IDs 616 + * - Unknown IDs 617 + * - Thermal Profile IDs 618 + * 619 + * The total number of IDs of a given type can be obtained with 620 + * AWCC_OP_GET_SYSTEM_DESCRIPTION. 621 + * 622 + * Return: 0 on success, -errno on failure 623 + */ 624 + static int awcc_op_get_resource_id(struct wmi_device *wdev, u8 index, u8 *out) 625 + { 626 + struct wmax_u32_args args = { 627 + .operation = AWCC_OP_GET_RESOURCE_ID, 628 + .arg1 = index, 629 + .arg2 = 0, 630 + .arg3 = 0, 631 + }; 632 + u32 out_data; 650 633 int ret; 651 634 652 - ret = alienware_wmi_command(wdev, WMAX_METHOD_GAME_SHIFT_STATUS, 653 - &in_args, sizeof(in_args), out_data); 654 - if (ret < 0) 635 + ret = awcc_wmi_command(wdev, AWCC_METHOD_THERMAL_INFORMATION, &args, &out_data); 636 + if (ret) 655 637 return ret; 656 638 657 - if (*out_data == WMAX_FAILURE_CODE) 658 - return -EOPNOTSUPP; 639 + *out = FIELD_GET(AWCC_RESOURCE_ID_MASK, out_data); 659 640 660 641 return 0; 661 642 } 662 643 663 - static int thermal_profile_get(struct device *dev, 664 - enum platform_profile_option *profile) 644 + static int awcc_op_get_fan_rpm(struct wmi_device *wdev, u8 fan_id, u32 *out) 645 + { 646 + struct wmax_u32_args args = { 647 + .operation = AWCC_OP_GET_FAN_RPM, 648 + .arg1 = fan_id, 649 + .arg2 = 0, 650 + .arg3 = 0, 651 + }; 652 + 653 + return awcc_wmi_command(wdev, AWCC_METHOD_THERMAL_INFORMATION, &args, out); 654 + } 655 + 656 + static int awcc_op_get_temperature(struct wmi_device *wdev, u8 temp_id, u32 *out) 657 + { 658 + struct wmax_u32_args args = { 659 + .operation = AWCC_OP_GET_TEMPERATURE, 660 + .arg1 = temp_id, 661 + .arg2 = 0, 662 + .arg3 = 0, 663 + }; 664 + 665 + return awcc_wmi_command(wdev, AWCC_METHOD_THERMAL_INFORMATION, &args, out); 666 + } 667 + 668 + static int awcc_op_get_fan_boost(struct wmi_device *wdev, u8 fan_id, u32 *out) 669 + { 670 + struct wmax_u32_args args = { 671 + .operation = AWCC_OP_GET_FAN_BOOST, 672 + .arg1 = fan_id, 673 + .arg2 = 0, 674 + .arg3 = 0, 675 + }; 676 + 677 + return awcc_wmi_command(wdev, AWCC_METHOD_THERMAL_INFORMATION, &args, out); 678 + } 679 + 680 + static int awcc_op_get_current_profile(struct wmi_device *wdev, u32 *out) 681 + { 682 + struct wmax_u32_args args = { 683 + .operation = AWCC_OP_GET_CURRENT_PROFILE, 684 + .arg1 = 0, 685 + .arg2 = 0, 686 + .arg3 = 0, 687 + }; 688 + 689 + return awcc_wmi_command(wdev, AWCC_METHOD_THERMAL_INFORMATION, &args, out); 690 + } 691 + 692 + static int awcc_op_activate_profile(struct wmi_device *wdev, u8 profile) 693 + { 694 + struct wmax_u32_args args = { 695 + .operation = AWCC_OP_ACTIVATE_PROFILE, 696 + .arg1 = profile, 697 + .arg2 = 0, 698 + .arg3 = 0, 699 + }; 700 + u32 out; 701 + 702 + return awcc_wmi_command(wdev, AWCC_METHOD_THERMAL_CONTROL, &args, &out); 703 + } 704 + 705 + static int awcc_op_set_fan_boost(struct wmi_device *wdev, u8 fan_id, u8 boost) 706 + { 707 + struct wmax_u32_args args = { 708 + .operation = AWCC_OP_SET_FAN_BOOST, 709 + .arg1 = fan_id, 710 + .arg2 = boost, 711 + .arg3 = 0, 712 + }; 713 + u32 out; 714 + 715 + return awcc_wmi_command(wdev, AWCC_METHOD_THERMAL_CONTROL, &args, &out); 716 + } 717 + 718 + /* 719 + * HWMON 720 + * - Provides temperature and fan speed monitoring as well as manual fan 721 + * control 722 + */ 723 + static umode_t awcc_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type, 724 + u32 attr, int channel) 725 + { 726 + const struct awcc_priv *priv = drvdata; 727 + unsigned int temp_count; 728 + 729 + switch (type) { 730 + case hwmon_temp: 731 + temp_count = bitmap_weight(priv->temp_sensors, AWCC_ID_BITMAP_SIZE); 732 + 733 + return channel < temp_count ? 0444 : 0; 734 + case hwmon_fan: 735 + return channel < priv->fan_count ? 0444 : 0; 736 + case hwmon_pwm: 737 + return channel < priv->fan_count ? 0444 : 0; 738 + default: 739 + return 0; 740 + } 741 + } 742 + 743 + static int awcc_hwmon_read(struct device *dev, enum hwmon_sensor_types type, 744 + u32 attr, int channel, long *val) 745 + { 746 + struct awcc_priv *priv = dev_get_drvdata(dev); 747 + const struct awcc_fan_data *fan; 748 + u32 state; 749 + int ret; 750 + u8 temp; 751 + 752 + switch (type) { 753 + case hwmon_temp: 754 + temp = find_nth_bit(priv->temp_sensors, AWCC_ID_BITMAP_SIZE, channel); 755 + 756 + switch (attr) { 757 + case hwmon_temp_input: 758 + ret = awcc_op_get_temperature(priv->wdev, temp, &state); 759 + if (ret) 760 + return ret; 761 + 762 + *val = state * MILLIDEGREE_PER_DEGREE; 763 + break; 764 + default: 765 + return -EOPNOTSUPP; 766 + } 767 + 768 + break; 769 + case hwmon_fan: 770 + fan = priv->fan_data[channel]; 771 + 772 + switch (attr) { 773 + case hwmon_fan_input: 774 + ret = awcc_op_get_fan_rpm(priv->wdev, fan->id, &state); 775 + if (ret) 776 + return ret; 777 + 778 + *val = state; 779 + break; 780 + case hwmon_fan_min: 781 + *val = fan->min_rpm; 782 + break; 783 + case hwmon_fan_max: 784 + *val = fan->max_rpm; 785 + break; 786 + default: 787 + return -EOPNOTSUPP; 788 + } 789 + 790 + break; 791 + case hwmon_pwm: 792 + fan = priv->fan_data[channel]; 793 + 794 + switch (attr) { 795 + case hwmon_pwm_auto_channels_temp: 796 + *val = fan->auto_channels_temp; 797 + break; 798 + default: 799 + return -EOPNOTSUPP; 800 + } 801 + 802 + break; 803 + default: 804 + return -EOPNOTSUPP; 805 + } 806 + 807 + return 0; 808 + } 809 + 810 + static int awcc_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type, 811 + u32 attr, int channel, const char **str) 812 + { 813 + struct awcc_priv *priv = dev_get_drvdata(dev); 814 + u8 temp; 815 + 816 + switch (type) { 817 + case hwmon_temp: 818 + temp = find_nth_bit(priv->temp_sensors, AWCC_ID_BITMAP_SIZE, channel); 819 + 820 + switch (temp) { 821 + case AWCC_TEMP_SENSOR_CPU: 822 + *str = "CPU"; 823 + break; 824 + case AWCC_TEMP_SENSOR_GPU: 825 + *str = "GPU"; 826 + break; 827 + default: 828 + *str = "Unknown"; 829 + break; 830 + } 831 + 832 + break; 833 + case hwmon_fan: 834 + *str = priv->fan_data[channel]->label; 835 + break; 836 + default: 837 + return -EOPNOTSUPP; 838 + } 839 + 840 + return 0; 841 + } 842 + 843 + static const struct hwmon_ops awcc_hwmon_ops = { 844 + .is_visible = awcc_hwmon_is_visible, 845 + .read = awcc_hwmon_read, 846 + .read_string = awcc_hwmon_read_string, 847 + }; 848 + 849 + static const struct hwmon_channel_info * const awcc_hwmon_info[] = { 850 + HWMON_CHANNEL_INFO(temp, 851 + HWMON_T_LABEL | HWMON_T_INPUT, 852 + HWMON_T_LABEL | HWMON_T_INPUT, 853 + HWMON_T_LABEL | HWMON_T_INPUT, 854 + HWMON_T_LABEL | HWMON_T_INPUT, 855 + HWMON_T_LABEL | HWMON_T_INPUT, 856 + HWMON_T_LABEL | HWMON_T_INPUT 857 + ), 858 + HWMON_CHANNEL_INFO(fan, 859 + HWMON_F_LABEL | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_MAX, 860 + HWMON_F_LABEL | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_MAX, 861 + HWMON_F_LABEL | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_MAX, 862 + HWMON_F_LABEL | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_MAX, 863 + HWMON_F_LABEL | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_MAX, 864 + HWMON_F_LABEL | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_MAX 865 + ), 866 + HWMON_CHANNEL_INFO(pwm, 867 + HWMON_PWM_AUTO_CHANNELS_TEMP, 868 + HWMON_PWM_AUTO_CHANNELS_TEMP, 869 + HWMON_PWM_AUTO_CHANNELS_TEMP, 870 + HWMON_PWM_AUTO_CHANNELS_TEMP, 871 + HWMON_PWM_AUTO_CHANNELS_TEMP, 872 + HWMON_PWM_AUTO_CHANNELS_TEMP 873 + ), 874 + NULL 875 + }; 876 + 877 + static const struct hwmon_chip_info awcc_hwmon_chip_info = { 878 + .ops = &awcc_hwmon_ops, 879 + .info = awcc_hwmon_info, 880 + }; 881 + 882 + static ssize_t fan_boost_show(struct device *dev, struct device_attribute *attr, 883 + char *buf) 884 + { 885 + struct awcc_priv *priv = dev_get_drvdata(dev); 886 + int index = to_sensor_dev_attr(attr)->index; 887 + struct awcc_fan_data *fan = priv->fan_data[index]; 888 + u32 boost; 889 + int ret; 890 + 891 + ret = awcc_op_get_fan_boost(priv->wdev, fan->id, &boost); 892 + if (ret) 893 + return ret; 894 + 895 + return sysfs_emit(buf, "%u\n", boost); 896 + } 897 + 898 + static ssize_t fan_boost_store(struct device *dev, struct device_attribute *attr, 899 + const char *buf, size_t count) 900 + { 901 + struct awcc_priv *priv = dev_get_drvdata(dev); 902 + int index = to_sensor_dev_attr(attr)->index; 903 + struct awcc_fan_data *fan = priv->fan_data[index]; 904 + unsigned long val; 905 + int ret; 906 + 907 + ret = kstrtoul(buf, 0, &val); 908 + if (ret) 909 + return ret; 910 + 911 + ret = awcc_op_set_fan_boost(priv->wdev, fan->id, clamp_val(val, 0, 255)); 912 + 913 + return ret ? ret : count; 914 + } 915 + 916 + static SENSOR_DEVICE_ATTR_RW(fan1_boost, fan_boost, 0); 917 + static SENSOR_DEVICE_ATTR_RW(fan2_boost, fan_boost, 1); 918 + static SENSOR_DEVICE_ATTR_RW(fan3_boost, fan_boost, 2); 919 + static SENSOR_DEVICE_ATTR_RW(fan4_boost, fan_boost, 3); 920 + static SENSOR_DEVICE_ATTR_RW(fan5_boost, fan_boost, 4); 921 + static SENSOR_DEVICE_ATTR_RW(fan6_boost, fan_boost, 5); 922 + 923 + static umode_t fan_boost_attr_visible(struct kobject *kobj, struct attribute *attr, int n) 924 + { 925 + struct awcc_priv *priv = dev_get_drvdata(kobj_to_dev(kobj)); 926 + 927 + return n < priv->fan_count ? attr->mode : 0; 928 + } 929 + 930 + static bool fan_boost_group_visible(struct kobject *kobj) 931 + { 932 + return true; 933 + } 934 + 935 + DEFINE_SYSFS_GROUP_VISIBLE(fan_boost); 936 + 937 + static struct attribute *fan_boost_attrs[] = { 938 + &sensor_dev_attr_fan1_boost.dev_attr.attr, 939 + &sensor_dev_attr_fan2_boost.dev_attr.attr, 940 + &sensor_dev_attr_fan3_boost.dev_attr.attr, 941 + &sensor_dev_attr_fan4_boost.dev_attr.attr, 942 + &sensor_dev_attr_fan5_boost.dev_attr.attr, 943 + &sensor_dev_attr_fan6_boost.dev_attr.attr, 944 + NULL 945 + }; 946 + 947 + static const struct attribute_group fan_boost_group = { 948 + .attrs = fan_boost_attrs, 949 + .is_visible = SYSFS_GROUP_VISIBLE(fan_boost), 950 + }; 951 + 952 + static const struct attribute_group *awcc_hwmon_groups[] = { 953 + &fan_boost_group, 954 + NULL 955 + }; 956 + 957 + static int awcc_hwmon_temps_init(struct wmi_device *wdev) 958 + { 959 + struct awcc_priv *priv = dev_get_drvdata(&wdev->dev); 960 + unsigned int i; 961 + int ret; 962 + u8 id; 963 + 964 + for (i = 0; i < priv->temp_count; i++) { 965 + /* 966 + * Temperature sensors IDs are listed after the fan IDs at 967 + * offset `fan_count` 968 + */ 969 + ret = awcc_op_get_resource_id(wdev, i + priv->fan_count, &id); 970 + if (ret) 971 + return ret; 972 + 973 + __set_bit(id, priv->temp_sensors); 974 + } 975 + 976 + return 0; 977 + } 978 + 979 + static char *awcc_get_fan_label(unsigned long *fan_temps) 980 + { 981 + unsigned int temp_count = bitmap_weight(fan_temps, AWCC_ID_BITMAP_SIZE); 982 + char *label; 983 + u8 temp_id; 984 + 985 + switch (temp_count) { 986 + case 0: 987 + label = "Independent Fan"; 988 + break; 989 + case 1: 990 + temp_id = find_first_bit(fan_temps, AWCC_ID_BITMAP_SIZE); 991 + 992 + switch (temp_id) { 993 + case AWCC_TEMP_SENSOR_CPU: 994 + label = "Processor Fan"; 995 + break; 996 + case AWCC_TEMP_SENSOR_GPU: 997 + label = "Video Fan"; 998 + break; 999 + default: 1000 + label = "Unknown Fan"; 1001 + break; 1002 + } 1003 + 1004 + break; 1005 + default: 1006 + label = "Shared Fan"; 1007 + break; 1008 + } 1009 + 1010 + return label; 1011 + } 1012 + 1013 + static int awcc_hwmon_fans_init(struct wmi_device *wdev) 1014 + { 1015 + struct awcc_priv *priv = dev_get_drvdata(&wdev->dev); 1016 + unsigned long fan_temps[AWCC_ID_BITMAP_LONGS]; 1017 + unsigned long gather[AWCC_ID_BITMAP_LONGS]; 1018 + u32 min_rpm, max_rpm, temp_count, temp_id; 1019 + struct awcc_fan_data *fan_data; 1020 + unsigned int i, j; 1021 + int ret; 1022 + u8 id; 1023 + 1024 + for (i = 0; i < priv->fan_count; i++) { 1025 + fan_data = devm_kzalloc(&wdev->dev, sizeof(*fan_data), GFP_KERNEL); 1026 + if (!fan_data) 1027 + return -ENOMEM; 1028 + 1029 + /* 1030 + * Fan IDs are listed first at offset 0 1031 + */ 1032 + ret = awcc_op_get_resource_id(wdev, i, &id); 1033 + if (ret) 1034 + return ret; 1035 + 1036 + ret = awcc_thermal_information(wdev, AWCC_OP_GET_FAN_MIN_RPM, id, 1037 + &min_rpm); 1038 + if (ret) 1039 + return ret; 1040 + 1041 + ret = awcc_thermal_information(wdev, AWCC_OP_GET_FAN_MAX_RPM, id, 1042 + &max_rpm); 1043 + if (ret) 1044 + return ret; 1045 + 1046 + ret = awcc_get_fan_sensors(wdev, AWCC_OP_GET_TOTAL_FAN_TEMPS, id, 1047 + 0, &temp_count); 1048 + if (ret) 1049 + return ret; 1050 + 1051 + bitmap_zero(fan_temps, AWCC_ID_BITMAP_SIZE); 1052 + 1053 + for (j = 0; j < temp_count; j++) { 1054 + ret = awcc_get_fan_sensors(wdev, AWCC_OP_GET_FAN_TEMP_ID, 1055 + id, j, &temp_id); 1056 + if (ret) 1057 + break; 1058 + 1059 + temp_id = FIELD_GET(AWCC_RESOURCE_ID_MASK, temp_id); 1060 + __set_bit(temp_id, fan_temps); 1061 + } 1062 + 1063 + fan_data->id = id; 1064 + fan_data->min_rpm = min_rpm; 1065 + fan_data->max_rpm = max_rpm; 1066 + fan_data->label = awcc_get_fan_label(fan_temps); 1067 + bitmap_gather(gather, fan_temps, priv->temp_sensors, AWCC_ID_BITMAP_SIZE); 1068 + bitmap_copy(&fan_data->auto_channels_temp, gather, BITS_PER_LONG); 1069 + priv->fan_data[i] = fan_data; 1070 + } 1071 + 1072 + return 0; 1073 + } 1074 + 1075 + static int awcc_hwmon_init(struct wmi_device *wdev) 1076 + { 1077 + struct awcc_priv *priv = dev_get_drvdata(&wdev->dev); 1078 + int ret; 1079 + 1080 + priv->fan_data = devm_kcalloc(&wdev->dev, priv->fan_count, 1081 + sizeof(*priv->fan_data), GFP_KERNEL); 1082 + if (!priv->fan_data) 1083 + return -ENOMEM; 1084 + 1085 + ret = awcc_hwmon_temps_init(wdev); 1086 + if (ret) 1087 + return ret; 1088 + 1089 + ret = awcc_hwmon_fans_init(wdev); 1090 + if (ret) 1091 + return ret; 1092 + 1093 + priv->hwdev = devm_hwmon_device_register_with_info(&wdev->dev, "alienware_wmi", 1094 + priv, &awcc_hwmon_chip_info, 1095 + awcc_hwmon_groups); 1096 + 1097 + return PTR_ERR_OR_ZERO(priv->hwdev); 1098 + } 1099 + 1100 + static void awcc_hwmon_suspend(struct device *dev) 1101 + { 1102 + struct awcc_priv *priv = dev_get_drvdata(dev); 1103 + struct awcc_fan_data *fan; 1104 + unsigned int i; 1105 + u32 boost; 1106 + int ret; 1107 + 1108 + for (i = 0; i < priv->fan_count; i++) { 1109 + fan = priv->fan_data[i]; 1110 + 1111 + ret = awcc_thermal_information(priv->wdev, AWCC_OP_GET_FAN_BOOST, 1112 + fan->id, &boost); 1113 + if (ret) 1114 + dev_err(dev, "Failed to store Fan %u boost while suspending\n", i); 1115 + 1116 + fan->suspend_cache = ret ? 0 : clamp_val(boost, 0, 255); 1117 + 1118 + awcc_op_set_fan_boost(priv->wdev, fan->id, 0); 1119 + if (ret) 1120 + dev_err(dev, "Failed to set Fan %u boost to 0 while suspending\n", i); 1121 + } 1122 + } 1123 + 1124 + static void awcc_hwmon_resume(struct device *dev) 1125 + { 1126 + struct awcc_priv *priv = dev_get_drvdata(dev); 1127 + struct awcc_fan_data *fan; 1128 + unsigned int i; 1129 + int ret; 1130 + 1131 + for (i = 0; i < priv->fan_count; i++) { 1132 + fan = priv->fan_data[i]; 1133 + 1134 + if (!fan->suspend_cache) 1135 + continue; 1136 + 1137 + ret = awcc_op_set_fan_boost(priv->wdev, fan->id, fan->suspend_cache); 1138 + if (ret) 1139 + dev_err(dev, "Failed to restore Fan %u boost while resuming\n", i); 1140 + } 1141 + } 1142 + 1143 + /* 1144 + * Thermal Profile control 1145 + * - Provides thermal profile control through the Platform Profile API 1146 + */ 1147 + static int awcc_platform_profile_get(struct device *dev, 1148 + enum platform_profile_option *profile) 665 1149 { 666 1150 struct awcc_priv *priv = dev_get_drvdata(dev); 667 1151 u32 out_data; 668 1152 int ret; 669 1153 670 - ret = wmax_thermal_information(priv->wdev, WMAX_OPERATION_CURRENT_PROFILE, 671 - 0, &out_data); 672 - 673 - if (ret < 0) 1154 + ret = awcc_op_get_current_profile(priv->wdev, &out_data); 1155 + if (ret) 674 1156 return ret; 675 1157 676 - if (out_data == WMAX_THERMAL_MODE_GMODE) { 1158 + switch (out_data) { 1159 + case AWCC_SPECIAL_PROFILE_CUSTOM: 1160 + *profile = PLATFORM_PROFILE_CUSTOM; 1161 + return 0; 1162 + case AWCC_SPECIAL_PROFILE_GMODE: 677 1163 *profile = PLATFORM_PROFILE_PERFORMANCE; 678 1164 return 0; 1165 + default: 1166 + break; 679 1167 } 680 1168 681 - if (!is_wmax_thermal_code(out_data)) 1169 + if (!is_awcc_thermal_profile_id(out_data)) 682 1170 return -ENODATA; 683 1171 684 - out_data &= WMAX_THERMAL_MODE_MASK; 685 - *profile = wmax_mode_to_platform_profile[out_data]; 1172 + out_data = FIELD_GET(AWCC_THERMAL_MODE_MASK, out_data); 1173 + *profile = awcc_mode_to_platform_profile[out_data]; 686 1174 687 1175 return 0; 688 1176 } 689 1177 690 - static int thermal_profile_set(struct device *dev, 691 - enum platform_profile_option profile) 1178 + static int awcc_platform_profile_set(struct device *dev, 1179 + enum platform_profile_option profile) 692 1180 { 693 1181 struct awcc_priv *priv = dev_get_drvdata(dev); 694 1182 ··· 1259 621 u32 gmode_status; 1260 622 int ret; 1261 623 1262 - ret = wmax_game_shift_status(priv->wdev, 1263 - WMAX_OPERATION_GET_GAME_SHIFT_STATUS, 624 + ret = awcc_game_shift_status(priv->wdev, 625 + AWCC_OP_GET_GAME_SHIFT_STATUS, 1264 626 &gmode_status); 1265 627 1266 628 if (ret < 0) ··· 1268 630 1269 631 if ((profile == PLATFORM_PROFILE_PERFORMANCE && !gmode_status) || 1270 632 (profile != PLATFORM_PROFILE_PERFORMANCE && gmode_status)) { 1271 - ret = wmax_game_shift_status(priv->wdev, 1272 - WMAX_OPERATION_TOGGLE_GAME_SHIFT, 633 + ret = awcc_game_shift_status(priv->wdev, 634 + AWCC_OP_TOGGLE_GAME_SHIFT, 1273 635 &gmode_status); 1274 636 1275 637 if (ret < 0) ··· 1277 639 } 1278 640 } 1279 641 1280 - return wmax_thermal_control(priv->wdev, 1281 - priv->supported_thermal_profiles[profile]); 642 + return awcc_op_activate_profile(priv->wdev, priv->supported_profiles[profile]); 1282 643 } 1283 644 1284 - static int thermal_profile_probe(void *drvdata, unsigned long *choices) 645 + static int awcc_platform_profile_probe(void *drvdata, unsigned long *choices) 1285 646 { 1286 647 enum platform_profile_option profile; 1287 648 struct awcc_priv *priv = drvdata; 1288 - enum wmax_thermal_mode mode; 1289 - u8 sys_desc[4]; 1290 - u32 first_mode; 1291 - u32 out_data; 649 + enum awcc_thermal_profile mode; 650 + u8 id, offset = 0; 1292 651 int ret; 1293 652 1294 - ret = wmax_thermal_information(priv->wdev, WMAX_OPERATION_SYS_DESCRIPTION, 1295 - 0, (u32 *) &sys_desc); 1296 - if (ret < 0) 1297 - return ret; 653 + /* 654 + * Thermal profile IDs are listed last at offset 655 + * fan_count + temp_count + unknown_count 656 + */ 657 + for (unsigned int i = 0; i < ARRAY_SIZE(priv->res_count) - 1; i++) 658 + offset += priv->res_count[i]; 1298 659 1299 - first_mode = sys_desc[0] + sys_desc[1]; 1300 - 1301 - for (u32 i = 0; i < sys_desc[3]; i++) { 1302 - ret = wmax_thermal_information(priv->wdev, WMAX_OPERATION_LIST_IDS, 1303 - i + first_mode, &out_data); 660 + for (unsigned int i = 0; i < priv->profile_count; i++) { 661 + ret = awcc_op_get_resource_id(priv->wdev, i + offset, &id); 662 + /* 663 + * Some devices report an incorrect number of thermal profiles 664 + * so the resource ID list may end prematurely 665 + */ 1304 666 if (ret == -EBADRQC) 1305 667 break; 1306 668 if (ret) 1307 669 return ret; 1308 670 1309 - if (!is_wmax_thermal_code(out_data)) 671 + if (!is_awcc_thermal_profile_id(id)) { 672 + dev_dbg(&priv->wdev->dev, "Unmapped thermal profile ID 0x%02x\n", id); 1310 673 continue; 674 + } 1311 675 1312 - mode = out_data & WMAX_THERMAL_MODE_MASK; 1313 - profile = wmax_mode_to_platform_profile[mode]; 1314 - priv->supported_thermal_profiles[profile] = out_data; 676 + mode = FIELD_GET(AWCC_THERMAL_MODE_MASK, id); 677 + profile = awcc_mode_to_platform_profile[mode]; 678 + priv->supported_profiles[profile] = id; 1315 679 1316 - set_bit(profile, choices); 680 + __set_bit(profile, choices); 1317 681 } 1318 682 1319 683 if (bitmap_empty(choices, PLATFORM_PROFILE_LAST)) 1320 684 return -ENODEV; 1321 685 1322 686 if (awcc->gmode) { 1323 - priv->supported_thermal_profiles[PLATFORM_PROFILE_PERFORMANCE] = 1324 - WMAX_THERMAL_MODE_GMODE; 687 + priv->supported_profiles[PLATFORM_PROFILE_PERFORMANCE] = 688 + AWCC_SPECIAL_PROFILE_GMODE; 1325 689 1326 - set_bit(PLATFORM_PROFILE_PERFORMANCE, choices); 690 + __set_bit(PLATFORM_PROFILE_PERFORMANCE, choices); 1327 691 } 692 + 693 + /* Every model supports the "custom" profile */ 694 + priv->supported_profiles[PLATFORM_PROFILE_CUSTOM] = 695 + AWCC_SPECIAL_PROFILE_CUSTOM; 696 + 697 + __set_bit(PLATFORM_PROFILE_CUSTOM, choices); 1328 698 1329 699 return 0; 1330 700 } 1331 701 1332 702 static const struct platform_profile_ops awcc_platform_profile_ops = { 1333 - .probe = thermal_profile_probe, 1334 - .profile_get = thermal_profile_get, 1335 - .profile_set = thermal_profile_set, 703 + .probe = awcc_platform_profile_probe, 704 + .profile_get = awcc_platform_profile_get, 705 + .profile_set = awcc_platform_profile_set, 1336 706 }; 1337 707 1338 708 static int awcc_platform_profile_init(struct wmi_device *wdev) ··· 1353 707 return PTR_ERR_OR_ZERO(priv->ppdev); 1354 708 } 1355 709 710 + /* 711 + * DebugFS 712 + */ 713 + static int awcc_debugfs_system_description_read(struct seq_file *seq, void *data) 714 + { 715 + struct device *dev = seq->private; 716 + struct awcc_priv *priv = dev_get_drvdata(dev); 717 + 718 + seq_printf(seq, "0x%08x\n", priv->system_description); 719 + 720 + return 0; 721 + } 722 + 723 + static int awcc_debugfs_hwmon_data_read(struct seq_file *seq, void *data) 724 + { 725 + struct device *dev = seq->private; 726 + struct awcc_priv *priv = dev_get_drvdata(dev); 727 + const struct awcc_fan_data *fan; 728 + unsigned int bit; 729 + 730 + seq_printf(seq, "Number of fans: %u\n", priv->fan_count); 731 + seq_printf(seq, "Number of temperature sensors: %u\n\n", priv->temp_count); 732 + 733 + for (u32 i = 0; i < priv->fan_count; i++) { 734 + fan = priv->fan_data[i]; 735 + 736 + seq_printf(seq, "Fan %u:\n", i); 737 + seq_printf(seq, " ID: 0x%02x\n", fan->id); 738 + seq_printf(seq, " Related temperature sensors bitmap: %lu\n", 739 + fan->auto_channels_temp); 740 + } 741 + 742 + seq_puts(seq, "\nTemperature sensor IDs:\n"); 743 + for_each_set_bit(bit, priv->temp_sensors, AWCC_ID_BITMAP_SIZE) 744 + seq_printf(seq, " 0x%02x\n", bit); 745 + 746 + return 0; 747 + } 748 + 749 + static int awcc_debugfs_pprof_data_read(struct seq_file *seq, void *data) 750 + { 751 + struct device *dev = seq->private; 752 + struct awcc_priv *priv = dev_get_drvdata(dev); 753 + 754 + seq_printf(seq, "Number of thermal profiles: %u\n\n", priv->profile_count); 755 + 756 + for (u32 i = 0; i < PLATFORM_PROFILE_LAST; i++) { 757 + if (!priv->supported_profiles[i]) 758 + continue; 759 + 760 + seq_printf(seq, "Platform profile %u:\n", i); 761 + seq_printf(seq, " ID: 0x%02x\n", priv->supported_profiles[i]); 762 + } 763 + 764 + return 0; 765 + } 766 + 767 + static int awcc_gpio_pin_show(struct seq_file *seq, void *data) 768 + { 769 + unsigned long pin = debugfs_get_aux_num(seq->file); 770 + struct wmi_device *wdev = seq->private; 771 + u32 status; 772 + int ret; 773 + 774 + ret = awcc_read_gpio_status(wdev, pin, &status); 775 + if (ret) 776 + return ret; 777 + 778 + seq_printf(seq, "%u\n", status); 779 + 780 + return 0; 781 + } 782 + 783 + static ssize_t awcc_gpio_pin_write(struct file *file, const char __user *buf, 784 + size_t count, loff_t *ppos) 785 + { 786 + unsigned long pin = debugfs_get_aux_num(file); 787 + struct seq_file *seq = file->private_data; 788 + struct wmi_device *wdev = seq->private; 789 + bool status; 790 + int ret; 791 + 792 + if (!ppos || *ppos) 793 + return -EINVAL; 794 + 795 + ret = kstrtobool_from_user(buf, count, &status); 796 + if (ret) 797 + return ret; 798 + 799 + ret = awcc_fwup_gpio_control(wdev, pin, status); 800 + if (ret) 801 + return ret; 802 + 803 + return count; 804 + } 805 + 806 + DEFINE_SHOW_STORE_ATTRIBUTE(awcc_gpio_pin); 807 + 808 + static void awcc_debugfs_remove(void *data) 809 + { 810 + struct dentry *root = data; 811 + 812 + debugfs_remove(root); 813 + } 814 + 815 + static void awcc_debugfs_init(struct wmi_device *wdev) 816 + { 817 + struct awcc_priv *priv = dev_get_drvdata(&wdev->dev); 818 + struct dentry *root, *gpio_ctl; 819 + u32 gpio_count; 820 + char name[64]; 821 + int ret; 822 + 823 + scnprintf(name, sizeof(name), "%s-%s", "alienware-wmi", dev_name(&wdev->dev)); 824 + root = debugfs_create_dir(name, NULL); 825 + 826 + debugfs_create_devm_seqfile(&wdev->dev, "system_description", root, 827 + awcc_debugfs_system_description_read); 828 + 829 + if (awcc->hwmon) 830 + debugfs_create_devm_seqfile(&wdev->dev, "hwmon_data", root, 831 + awcc_debugfs_hwmon_data_read); 832 + 833 + if (awcc->pprof) 834 + debugfs_create_devm_seqfile(&wdev->dev, "pprof_data", root, 835 + awcc_debugfs_pprof_data_read); 836 + 837 + ret = awcc_read_total_gpios(wdev, &gpio_count); 838 + if (ret) { 839 + dev_dbg(&wdev->dev, "Failed to get total GPIO Pin count\n"); 840 + goto out_add_action; 841 + } else if (gpio_count > AWCC_MAX_RES_COUNT) { 842 + dev_dbg(&wdev->dev, "Reported GPIO Pin count may be incorrect: %u\n", gpio_count); 843 + goto out_add_action; 844 + } 845 + 846 + gpio_ctl = debugfs_create_dir("gpio_ctl", root); 847 + 848 + priv->gpio_count = gpio_count; 849 + debugfs_create_u32("total_gpios", 0444, gpio_ctl, &priv->gpio_count); 850 + 851 + for (unsigned int i = 0; i < gpio_count; i++) { 852 + scnprintf(name, sizeof(name), "pin%u", i); 853 + debugfs_create_file_aux_num(name, 0644, gpio_ctl, wdev, i, 854 + &awcc_gpio_pin_fops); 855 + } 856 + 857 + out_add_action: 858 + devm_add_action_or_reset(&wdev->dev, awcc_debugfs_remove, root); 859 + } 860 + 1356 861 static int alienware_awcc_setup(struct wmi_device *wdev) 1357 862 { 1358 863 struct awcc_priv *priv; ··· 1513 716 if (!priv) 1514 717 return -ENOMEM; 1515 718 719 + ret = awcc_thermal_information(wdev, AWCC_OP_GET_SYSTEM_DESCRIPTION, 720 + 0, &priv->system_description); 721 + if (ret < 0) 722 + return ret; 723 + 724 + /* Sanity check */ 725 + for (unsigned int i = 0; i < ARRAY_SIZE(priv->res_count); i++) { 726 + if (priv->res_count[i] > AWCC_MAX_RES_COUNT) { 727 + dev_err(&wdev->dev, "Malformed system description: 0x%08x\n", 728 + priv->system_description); 729 + return -ENXIO; 730 + } 731 + } 732 + 1516 733 priv->wdev = wdev; 1517 734 dev_set_drvdata(&wdev->dev, priv); 735 + 736 + if (awcc->hwmon) { 737 + ret = awcc_hwmon_init(wdev); 738 + if (ret) 739 + return ret; 740 + } 1518 741 1519 742 if (awcc->pprof) { 1520 743 ret = awcc_platform_profile_init(wdev); 1521 744 if (ret) 1522 745 return ret; 1523 746 } 747 + 748 + awcc_debugfs_init(wdev); 1524 749 1525 750 return 0; 1526 751 } ··· 1594 775 return ret; 1595 776 } 1596 777 778 + static int wmax_wmi_suspend(struct device *dev) 779 + { 780 + if (awcc->hwmon) 781 + awcc_hwmon_suspend(dev); 782 + 783 + return 0; 784 + } 785 + 786 + static int wmax_wmi_resume(struct device *dev) 787 + { 788 + if (awcc->hwmon) 789 + awcc_hwmon_resume(dev); 790 + 791 + return 0; 792 + } 793 + 794 + static DEFINE_SIMPLE_DEV_PM_OPS(wmax_wmi_pm_ops, wmax_wmi_suspend, wmax_wmi_resume); 795 + 1597 796 static const struct wmi_device_id alienware_wmax_device_id_table[] = { 1598 797 { WMAX_CONTROL_GUID, NULL }, 1599 798 { }, ··· 1622 785 .driver = { 1623 786 .name = "alienware-wmi-wmax", 1624 787 .probe_type = PROBE_PREFER_ASYNCHRONOUS, 788 + .pm = pm_sleep_ptr(&wmax_wmi_pm_ops), 1625 789 }, 1626 790 .id_table = alienware_wmax_device_id_table, 1627 791 .probe = wmax_wmi_probe, ··· 1636 798 id = dmi_first_match(awcc_dmi_table); 1637 799 if (id) 1638 800 awcc = id->driver_data; 801 + 802 + if (force_hwmon) { 803 + if (!awcc) 804 + awcc = &empty_quirks; 805 + 806 + awcc->hwmon = true; 807 + } 1639 808 1640 809 if (force_platform_profile) { 1641 810 if (!awcc)
+19 -48
drivers/platform/x86/dell/dell-pc.c
··· 11 11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 12 12 13 13 #include <linux/bitfield.h> 14 + #include <linux/bitops.h> 14 15 #include <linux/bits.h> 16 + #include <linux/device/faux.h> 15 17 #include <linux/dmi.h> 16 18 #include <linux/err.h> 17 19 #include <linux/init.h> 18 20 #include <linux/kernel.h> 19 21 #include <linux/module.h> 20 22 #include <linux/platform_profile.h> 21 - #include <linux/platform_device.h> 22 23 #include <linux/slab.h> 23 24 24 25 #include "dell-smbios.h" 25 26 26 - static struct platform_device *platform_device; 27 + static struct faux_device *dell_pc_fdev; 27 28 static int supported_modes; 28 29 29 30 static const struct dmi_system_id dell_device_table[] __initconst = { ··· 147 146 148 147 dell_fill_request(&buffer, 0x0, 0, 0, 0); 149 148 ret = dell_send_request(&buffer, CLASS_INFO, SELECT_THERMAL_MANAGEMENT); 150 - /* Thermal function not supported */ 151 - if (ret == -ENXIO) { 152 - *supported_bits = 0; 153 - return 0; 154 - } 155 149 if (ret) 156 150 return ret; 157 151 *supported_bits = FIELD_GET(DELL_THERMAL_SUPPORTED, buffer.output[1]); ··· 229 233 static int thermal_platform_profile_probe(void *drvdata, unsigned long *choices) 230 234 { 231 235 if (supported_modes & DELL_QUIET) 232 - set_bit(PLATFORM_PROFILE_QUIET, choices); 236 + __set_bit(PLATFORM_PROFILE_QUIET, choices); 233 237 if (supported_modes & DELL_COOL_BOTTOM) 234 - set_bit(PLATFORM_PROFILE_COOL, choices); 238 + __set_bit(PLATFORM_PROFILE_COOL, choices); 235 239 if (supported_modes & DELL_BALANCED) 236 - set_bit(PLATFORM_PROFILE_BALANCED, choices); 240 + __set_bit(PLATFORM_PROFILE_BALANCED, choices); 237 241 if (supported_modes & DELL_PERFORMANCE) 238 - set_bit(PLATFORM_PROFILE_PERFORMANCE, choices); 242 + __set_bit(PLATFORM_PROFILE_PERFORMANCE, choices); 239 243 240 244 return 0; 241 245 } ··· 246 250 .profile_set = thermal_platform_profile_set, 247 251 }; 248 252 249 - static int thermal_init(void) 253 + static int dell_pc_faux_probe(struct faux_device *fdev) 250 254 { 251 255 struct device *ppdev; 252 256 int ret; 253 257 254 - /* If thermal commands are not supported, exit without error */ 255 258 if (!dell_smbios_class_is_supported(CLASS_INFO)) 256 - return 0; 259 + return -ENODEV; 257 260 258 - /* If thermal modes are not supported, exit without error */ 259 261 ret = thermal_get_supported_modes(&supported_modes); 260 262 if (ret < 0) 261 263 return ret; 262 - if (!supported_modes) 263 - return 0; 264 264 265 - platform_device = platform_device_register_simple("dell-pc", PLATFORM_DEVID_NONE, NULL, 0); 266 - if (IS_ERR(platform_device)) 267 - return PTR_ERR(platform_device); 265 + ppdev = devm_platform_profile_register(&fdev->dev, "dell-pc", NULL, 266 + &dell_pc_platform_profile_ops); 268 267 269 - ppdev = devm_platform_profile_register(&platform_device->dev, "dell-pc", 270 - NULL, &dell_pc_platform_profile_ops); 271 - if (IS_ERR(ppdev)) { 272 - ret = PTR_ERR(ppdev); 273 - goto cleanup_platform_device; 274 - } 275 - 276 - return 0; 277 - 278 - cleanup_platform_device: 279 - platform_device_unregister(platform_device); 280 - 281 - return ret; 268 + return PTR_ERR_OR_ZERO(ppdev); 282 269 } 283 270 284 - static void thermal_cleanup(void) 285 - { 286 - platform_device_unregister(platform_device); 287 - } 271 + static const struct faux_device_ops dell_pc_faux_ops = { 272 + .probe = dell_pc_faux_probe, 273 + }; 288 274 289 275 static int __init dell_init(void) 290 276 { 291 - int ret; 292 - 293 277 if (!dmi_check_system(dell_device_table)) 294 278 return -ENODEV; 295 279 296 - /* Do not fail module if thermal modes not supported, just skip */ 297 - ret = thermal_init(); 298 - if (ret) 299 - goto fail_thermal; 280 + dell_pc_fdev = faux_device_create("dell-pc", NULL, &dell_pc_faux_ops); 281 + if (!dell_pc_fdev) 282 + return -ENODEV; 300 283 301 284 return 0; 302 - 303 - fail_thermal: 304 - thermal_cleanup(); 305 - return ret; 306 285 } 307 286 308 287 static void __exit dell_exit(void) 309 288 { 310 - thermal_cleanup(); 289 + faux_device_destroy(dell_pc_fdev); 311 290 } 312 291 313 292 module_init(dell_init);
+233 -13
drivers/platform/x86/dell/dell-wmi-ddv.c
··· 8 8 #define pr_format(fmt) KBUILD_MODNAME ": " fmt 9 9 10 10 #include <linux/acpi.h> 11 + #include <linux/bitfield.h> 11 12 #include <linux/debugfs.h> 12 13 #include <linux/device.h> 13 14 #include <linux/device/driver.h> ··· 39 38 #define DELL_DDV_SUPPORTED_VERSION_MIN 2 40 39 #define DELL_DDV_SUPPORTED_VERSION_MAX 3 41 40 #define DELL_DDV_GUID "8A42EA14-4F2A-FD45-6422-0087F7A7E608" 41 + 42 + /* Battery indices 1, 2 and 3 */ 43 + #define DELL_DDV_NUM_BATTERIES 3 44 + 45 + #define SBS_MANUFACTURE_YEAR_MASK GENMASK(15, 9) 46 + #define SBS_MANUFACTURE_MONTH_MASK GENMASK(8, 5) 47 + #define SBS_MANUFACTURE_DAY_MASK GENMASK(4, 0) 48 + 49 + #define MA_FAILURE_MODE_MASK GENMASK(11, 8) 50 + #define MA_FAILURE_MODE_PERMANENT 0x9 51 + #define MA_FAILURE_MODE_OVERHEAT 0xA 52 + #define MA_FAILURE_MODE_OVERCURRENT 0xB 53 + 54 + #define MA_PERMANENT_FAILURE_CODE_MASK GENMASK(13, 12) 55 + #define MA_PERMANENT_FAILURE_FUSE_BLOWN 0x0 56 + #define MA_PERMANENT_FAILURE_CELL_IMBALANCE 0x1 57 + #define MA_PERMANENT_FAILURE_OVERVOLTAGE 0x2 58 + #define MA_PERMANENT_FAILURE_FET_FAILURE 0x3 59 + 60 + #define MA_OVERHEAT_FAILURE_CODE_MASK GENMASK(15, 12) 61 + #define MA_OVERHEAT_FAILURE_START 0x5 62 + #define MA_OVERHEAT_FAILURE_CHARGING 0x7 63 + #define MA_OVERHEAT_FAILURE_DISCHARGING 0x8 64 + 65 + #define MA_OVERCURRENT_FAILURE_CODE_MASK GENMASK(15, 12) 66 + #define MA_OVERCURRENT_FAILURE_CHARGING 0x6 67 + #define MA_OVERCURRENT_FAILURE_DISCHARGING 0xB 42 68 43 69 #define DELL_EPPID_LENGTH 20 44 70 #define DELL_EPPID_EXT_LENGTH 23 ··· 133 105 struct dell_wmi_ddv_data { 134 106 struct acpi_battery_hook hook; 135 107 struct device_attribute eppid_attr; 108 + struct mutex translation_cache_lock; /* Protects the translation cache */ 109 + struct power_supply *translation_cache[DELL_DDV_NUM_BATTERIES]; 136 110 struct dell_wmi_ddv_sensors fans; 137 111 struct dell_wmi_ddv_sensors temps; 138 112 struct wmi_device *wdev; ··· 669 639 return ret; 670 640 } 671 641 672 - static int dell_wmi_ddv_battery_index(struct acpi_device *acpi_dev, u32 *index) 642 + static int dell_wmi_ddv_battery_translate(struct dell_wmi_ddv_data *data, 643 + struct power_supply *battery, u32 *index) 673 644 { 674 - const char *uid_str; 645 + u32 serial_dec, serial_hex, serial; 646 + union power_supply_propval val; 647 + int ret; 675 648 676 - uid_str = acpi_device_uid(acpi_dev); 677 - if (!uid_str) 678 - return -ENODEV; 649 + guard(mutex)(&data->translation_cache_lock); 679 650 680 - return kstrtou32(uid_str, 10, index); 651 + for (int i = 0; i < ARRAY_SIZE(data->translation_cache); i++) { 652 + if (data->translation_cache[i] == battery) { 653 + dev_dbg(&data->wdev->dev, "Translation cache hit for battery index %u\n", 654 + i + 1); 655 + *index = i + 1; 656 + return 0; 657 + } 658 + } 659 + 660 + dev_dbg(&data->wdev->dev, "Translation cache miss\n"); 661 + 662 + /* Perform a translation between a ACPI battery and a battery index */ 663 + 664 + ret = power_supply_get_property(battery, POWER_SUPPLY_PROP_SERIAL_NUMBER, &val); 665 + if (ret < 0) 666 + return ret; 667 + 668 + /* 669 + * Some devices display the serial number of the ACPI battery (string!) as a decimal 670 + * number while other devices display it as a hexadecimal number. Because of this we 671 + * have to check both cases. 672 + */ 673 + ret = kstrtou32(val.strval, 16, &serial_hex); 674 + if (ret < 0) 675 + return ret; /* Should never fail */ 676 + 677 + ret = kstrtou32(val.strval, 10, &serial_dec); 678 + if (ret < 0) 679 + serial_dec = 0; /* Can fail, thus we only mark serial_dec as invalid */ 680 + 681 + for (int i = 0; i < ARRAY_SIZE(data->translation_cache); i++) { 682 + ret = dell_wmi_ddv_query_integer(data->wdev, DELL_DDV_BATTERY_SERIAL_NUMBER, i + 1, 683 + &serial); 684 + if (ret < 0) 685 + return ret; 686 + 687 + /* A serial number of 0 signals that this index is not associated with a battery */ 688 + if (!serial) 689 + continue; 690 + 691 + if (serial == serial_dec || serial == serial_hex) { 692 + dev_dbg(&data->wdev->dev, "Translation cache update for battery index %u\n", 693 + i + 1); 694 + data->translation_cache[i] = battery; 695 + *index = i + 1; 696 + return 0; 697 + } 698 + } 699 + 700 + return -ENODEV; 701 + } 702 + 703 + static void dell_wmi_battery_invalidate(struct dell_wmi_ddv_data *data, 704 + struct power_supply *battery) 705 + { 706 + guard(mutex)(&data->translation_cache_lock); 707 + 708 + for (int i = 0; i < ARRAY_SIZE(data->translation_cache); i++) { 709 + if (data->translation_cache[i] == battery) { 710 + data->translation_cache[i] = NULL; 711 + return; 712 + } 713 + } 681 714 } 682 715 683 716 static ssize_t eppid_show(struct device *dev, struct device_attribute *attr, char *buf) ··· 750 657 u32 index; 751 658 int ret; 752 659 753 - ret = dell_wmi_ddv_battery_index(to_acpi_device(dev->parent), &index); 660 + ret = dell_wmi_ddv_battery_translate(data, to_power_supply(dev), &index); 754 661 if (ret < 0) 755 662 return ret; 756 663 ··· 769 676 return ret; 770 677 } 771 678 679 + static int dell_wmi_ddv_get_health(struct dell_wmi_ddv_data *data, u32 index, 680 + union power_supply_propval *val) 681 + { 682 + u32 value, code; 683 + int ret; 684 + 685 + ret = dell_wmi_ddv_query_integer(data->wdev, DELL_DDV_BATTERY_MANUFACTURER_ACCESS, index, 686 + &value); 687 + if (ret < 0) 688 + return ret; 689 + 690 + switch (FIELD_GET(MA_FAILURE_MODE_MASK, value)) { 691 + case MA_FAILURE_MODE_PERMANENT: 692 + code = FIELD_GET(MA_PERMANENT_FAILURE_CODE_MASK, value); 693 + switch (code) { 694 + case MA_PERMANENT_FAILURE_FUSE_BLOWN: 695 + val->intval = POWER_SUPPLY_HEALTH_BLOWN_FUSE; 696 + return 0; 697 + case MA_PERMANENT_FAILURE_CELL_IMBALANCE: 698 + val->intval = POWER_SUPPLY_HEALTH_CELL_IMBALANCE; 699 + return 0; 700 + case MA_PERMANENT_FAILURE_OVERVOLTAGE: 701 + val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 702 + return 0; 703 + case MA_PERMANENT_FAILURE_FET_FAILURE: 704 + val->intval = POWER_SUPPLY_HEALTH_DEAD; 705 + return 0; 706 + default: 707 + dev_notice_once(&data->wdev->dev, "Unknown permanent failure code %u\n", 708 + code); 709 + val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 710 + return 0; 711 + } 712 + case MA_FAILURE_MODE_OVERHEAT: 713 + code = FIELD_GET(MA_OVERHEAT_FAILURE_CODE_MASK, value); 714 + switch (code) { 715 + case MA_OVERHEAT_FAILURE_START: 716 + case MA_OVERHEAT_FAILURE_CHARGING: 717 + case MA_OVERHEAT_FAILURE_DISCHARGING: 718 + val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; 719 + return 0; 720 + default: 721 + dev_notice_once(&data->wdev->dev, "Unknown overheat failure code %u\n", 722 + code); 723 + val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 724 + return 0; 725 + } 726 + case MA_FAILURE_MODE_OVERCURRENT: 727 + code = FIELD_GET(MA_OVERCURRENT_FAILURE_CODE_MASK, value); 728 + switch (code) { 729 + case MA_OVERCURRENT_FAILURE_CHARGING: 730 + case MA_OVERCURRENT_FAILURE_DISCHARGING: 731 + val->intval = POWER_SUPPLY_HEALTH_OVERCURRENT; 732 + return 0; 733 + default: 734 + dev_notice_once(&data->wdev->dev, "Unknown overcurrent failure code %u\n", 735 + code); 736 + val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 737 + return 0; 738 + } 739 + default: 740 + val->intval = POWER_SUPPLY_HEALTH_GOOD; 741 + return 0; 742 + } 743 + } 744 + 745 + static int dell_wmi_ddv_get_manufacture_date(struct dell_wmi_ddv_data *data, u32 index, 746 + enum power_supply_property psp, 747 + union power_supply_propval *val) 748 + { 749 + u16 year, month, day; 750 + u32 value; 751 + int ret; 752 + 753 + ret = dell_wmi_ddv_query_integer(data->wdev, DELL_DDV_BATTERY_MANUFACTURE_DATE, 754 + index, &value); 755 + if (ret < 0) 756 + return ret; 757 + if (value > U16_MAX) 758 + return -ENXIO; 759 + 760 + /* 761 + * Some devices report a invalid manufacture date value 762 + * like 0.0.1980. Because of this we have to check the 763 + * whole value before exposing parts of it to user space. 764 + */ 765 + year = FIELD_GET(SBS_MANUFACTURE_YEAR_MASK, value) + 1980; 766 + month = FIELD_GET(SBS_MANUFACTURE_MONTH_MASK, value); 767 + if (month < 1 || month > 12) 768 + return -ENODATA; 769 + 770 + day = FIELD_GET(SBS_MANUFACTURE_DAY_MASK, value); 771 + if (day < 1 || day > 31) 772 + return -ENODATA; 773 + 774 + switch (psp) { 775 + case POWER_SUPPLY_PROP_MANUFACTURE_YEAR: 776 + val->intval = year; 777 + return 0; 778 + case POWER_SUPPLY_PROP_MANUFACTURE_MONTH: 779 + val->intval = month; 780 + return 0; 781 + case POWER_SUPPLY_PROP_MANUFACTURE_DAY: 782 + val->intval = day; 783 + return 0; 784 + default: 785 + return -EINVAL; 786 + } 787 + } 788 + 772 789 static int dell_wmi_ddv_get_property(struct power_supply *psy, const struct power_supply_ext *ext, 773 790 void *drvdata, enum power_supply_property psp, 774 791 union power_supply_propval *val) ··· 887 684 u32 index, value; 888 685 int ret; 889 686 890 - ret = dell_wmi_ddv_battery_index(to_acpi_device(psy->dev.parent), &index); 687 + ret = dell_wmi_ddv_battery_translate(data, psy, &index); 891 688 if (ret < 0) 892 689 return ret; 893 690 894 691 switch (psp) { 692 + case POWER_SUPPLY_PROP_HEALTH: 693 + return dell_wmi_ddv_get_health(data, index, val); 895 694 case POWER_SUPPLY_PROP_TEMP: 896 695 ret = dell_wmi_ddv_query_integer(data->wdev, DELL_DDV_BATTERY_TEMPERATURE, index, 897 696 &value); ··· 905 700 */ 906 701 val->intval = value - 2732; 907 702 return 0; 703 + case POWER_SUPPLY_PROP_MANUFACTURE_YEAR: 704 + case POWER_SUPPLY_PROP_MANUFACTURE_MONTH: 705 + case POWER_SUPPLY_PROP_MANUFACTURE_DAY: 706 + return dell_wmi_ddv_get_manufacture_date(data, index, psp, val); 908 707 default: 909 708 return -EINVAL; 910 709 } 911 710 } 912 711 913 712 static const enum power_supply_property dell_wmi_ddv_properties[] = { 713 + POWER_SUPPLY_PROP_HEALTH, 914 714 POWER_SUPPLY_PROP_TEMP, 715 + POWER_SUPPLY_PROP_MANUFACTURE_YEAR, 716 + POWER_SUPPLY_PROP_MANUFACTURE_MONTH, 717 + POWER_SUPPLY_PROP_MANUFACTURE_DAY, 915 718 }; 916 719 917 720 static const struct power_supply_ext dell_wmi_ddv_extension = { ··· 932 719 static int dell_wmi_ddv_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook) 933 720 { 934 721 struct dell_wmi_ddv_data *data = container_of(hook, struct dell_wmi_ddv_data, hook); 935 - u32 index; 936 722 int ret; 937 723 938 - /* Return 0 instead of error to avoid being unloaded */ 939 - ret = dell_wmi_ddv_battery_index(to_acpi_device(battery->dev.parent), &index); 940 - if (ret < 0) 941 - return 0; 724 + /* 725 + * We cannot do the battery matching here since the battery might be absent, preventing 726 + * us from reading the serial number. 727 + */ 942 728 943 729 ret = device_create_file(&battery->dev, &data->eppid_attr); 944 730 if (ret < 0) ··· 961 749 device_remove_file(&battery->dev, &data->eppid_attr); 962 750 power_supply_unregister_extension(battery, &dell_wmi_ddv_extension); 963 751 752 + dell_wmi_battery_invalidate(data, battery); 753 + 964 754 return 0; 965 755 } 966 756 967 757 static int dell_wmi_ddv_battery_add(struct dell_wmi_ddv_data *data) 968 758 { 759 + int ret; 760 + 761 + ret = devm_mutex_init(&data->wdev->dev, &data->translation_cache_lock); 762 + if (ret < 0) 763 + return ret; 764 + 969 765 data->hook.name = "Dell DDV Battery Extension"; 970 766 data->hook.add_battery = dell_wmi_ddv_add_battery; 971 767 data->hook.remove_battery = dell_wmi_ddv_remove_battery;
+2 -2
drivers/platform/x86/eeepc-laptop.c
··· 1370 1370 if (!eeepc) 1371 1371 return -ENOMEM; 1372 1372 eeepc->handle = device->handle; 1373 - strcpy(acpi_device_name(device), EEEPC_ACPI_DEVICE_NAME); 1374 - strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS); 1373 + strscpy(acpi_device_name(device), EEEPC_ACPI_DEVICE_NAME); 1374 + strscpy(acpi_device_class(device), EEEPC_ACPI_CLASS); 1375 1375 device->driver_data = eeepc; 1376 1376 eeepc->device = device; 1377 1377
+4 -3
drivers/platform/x86/intel/int0002_vgpio.c
··· 65 65 return 0; 66 66 } 67 67 68 - static void int0002_gpio_set(struct gpio_chip *chip, unsigned int offset, 69 - int value) 68 + static int int0002_gpio_set(struct gpio_chip *chip, unsigned int offset, 69 + int value) 70 70 { 71 + return 0; 71 72 } 72 73 73 74 static int int0002_gpio_direction_output(struct gpio_chip *chip, ··· 193 192 chip->parent = dev; 194 193 chip->owner = THIS_MODULE; 195 194 chip->get = int0002_gpio_get; 196 - chip->set = int0002_gpio_set; 195 + chip->set_rv = int0002_gpio_set; 197 196 chip->direction_input = int0002_gpio_get; 198 197 chip->direction_output = int0002_gpio_direction_output; 199 198 chip->base = -1;
+2 -1
drivers/platform/x86/intel/int3472/Makefile
··· 1 1 obj-$(CONFIG_INTEL_SKL_INT3472) += intel_skl_int3472_discrete.o \ 2 2 intel_skl_int3472_tps68470.o \ 3 3 intel_skl_int3472_common.o 4 - intel_skl_int3472_discrete-y := discrete.o clk_and_regulator.o led.o 4 + intel_skl_int3472_discrete-y := discrete.o discrete_quirks.o \ 5 + clk_and_regulator.o led.o 5 6 intel_skl_int3472_tps68470-y := tps68470.o tps68470_board_data.o 6 7 7 8 intel_skl_int3472_common-y += common.o
+59 -114
drivers/platform/x86/intel/int3472/clk_and_regulator.c
··· 5 5 #include <linux/clkdev.h> 6 6 #include <linux/clk-provider.h> 7 7 #include <linux/device.h> 8 - #include <linux/dmi.h> 9 8 #include <linux/gpio/consumer.h> 9 + #include <linux/platform_data/x86/int3472.h> 10 10 #include <linux/regulator/driver.h> 11 11 #include <linux/slab.h> 12 - 13 - #include "common.h" 14 12 15 13 /* 16 14 * 82c0d13a-78c5-4244-9bb1-eb8b539a8d11 ··· 116 118 .recalc_rate = skl_int3472_clk_recalc_rate, 117 119 }; 118 120 119 - int skl_int3472_register_dsm_clock(struct int3472_discrete_device *int3472) 121 + static int skl_int3472_register_clock(struct int3472_discrete_device *int3472) 120 122 { 121 123 struct acpi_device *adev = int3472->adev; 122 124 struct clk_init_data init = { ··· 124 126 .flags = CLK_GET_RATE_NOCACHE, 125 127 }; 126 128 int ret; 127 - 128 - if (int3472->clock.cl) 129 - return 0; /* A GPIO controlled clk has already been registered */ 130 - 131 - if (!acpi_check_dsm(adev->handle, &img_clk_guid, 0, BIT(1))) 132 - return 0; /* DSM clock control is not available */ 133 129 134 130 init.name = kasprintf(GFP_KERNEL, "%s-clk", acpi_dev_name(adev)); 135 131 if (!init.name) ··· 153 161 return ret; 154 162 } 155 163 164 + int skl_int3472_register_dsm_clock(struct int3472_discrete_device *int3472) 165 + { 166 + if (int3472->clock.cl) 167 + return 0; /* A GPIO controlled clk has already been registered */ 168 + 169 + if (!acpi_check_dsm(int3472->adev->handle, &img_clk_guid, 0, BIT(1))) 170 + return 0; /* DSM clock control is not available */ 171 + 172 + return skl_int3472_register_clock(int3472); 173 + } 174 + 156 175 int skl_int3472_register_gpio_clock(struct int3472_discrete_device *int3472, 157 176 struct gpio_desc *gpio) 158 177 { 159 - struct clk_init_data init = { 160 - .ops = &skl_int3472_clock_ops, 161 - .flags = CLK_GET_RATE_NOCACHE, 162 - }; 163 - int ret; 164 - 165 178 if (int3472->clock.cl) 166 179 return -EBUSY; 167 180 168 181 int3472->clock.ena_gpio = gpio; 169 182 170 - init.name = kasprintf(GFP_KERNEL, "%s-clk", 171 - acpi_dev_name(int3472->adev)); 172 - if (!init.name) 173 - return -ENOMEM; 174 - 175 - int3472->clock.frequency = skl_int3472_get_clk_frequency(int3472); 176 - 177 - int3472->clock.clk_hw.init = &init; 178 - int3472->clock.clk = clk_register(&int3472->adev->dev, 179 - &int3472->clock.clk_hw); 180 - if (IS_ERR(int3472->clock.clk)) { 181 - ret = PTR_ERR(int3472->clock.clk); 182 - goto out_free_init_name; 183 - } 184 - 185 - int3472->clock.cl = clkdev_create(int3472->clock.clk, NULL, 186 - int3472->sensor_name); 187 - if (!int3472->clock.cl) { 188 - ret = -ENOMEM; 189 - goto err_unregister_clk; 190 - } 191 - 192 - kfree(init.name); 193 - return 0; 194 - 195 - err_unregister_clk: 196 - clk_unregister(int3472->clock.clk); 197 - out_free_init_name: 198 - kfree(init.name); 199 - 200 - return ret; 183 + return skl_int3472_register_clock(int3472); 201 184 } 202 185 203 186 void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472) ··· 182 215 183 216 clkdev_drop(int3472->clock.cl); 184 217 clk_unregister(int3472->clock.clk); 218 + gpiod_put(int3472->clock.ena_gpio); 185 219 } 186 220 187 - /* 188 - * The INT3472 device is going to be the only supplier of a regulator for 189 - * the sensor device. But unlike the clk framework the regulator framework 190 - * does not allow matching by consumer-device-name only. 191 - * 192 - * Ideally all sensor drivers would use "avdd" as supply-id. But for drivers 193 - * where this cannot be changed because another supply-id is already used in 194 - * e.g. DeviceTree files an alias for the other supply-id can be added here. 195 - * 196 - * Do not forget to update GPIO_REGULATOR_SUPPLY_MAP_COUNT when changing this. 197 - */ 198 - static const char * const skl_int3472_regulator_map_supplies[] = { 199 - "avdd", 200 - "AVDD", 201 - }; 202 - 203 - static_assert(ARRAY_SIZE(skl_int3472_regulator_map_supplies) == 204 - GPIO_REGULATOR_SUPPLY_MAP_COUNT); 205 - 206 - /* 207 - * On some models there is a single GPIO regulator which is shared between 208 - * sensors and only listed in the ACPI resources of one sensor. 209 - * This DMI table contains the name of the second sensor. This is used to add 210 - * entries for the second sensor to the supply_map. 211 - */ 212 - static const struct dmi_system_id skl_int3472_regulator_second_sensor[] = { 213 - { 214 - /* Lenovo Miix 510-12IKB */ 215 - .matches = { 216 - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 217 - DMI_MATCH(DMI_PRODUCT_VERSION, "MIIX 510-12IKB"), 218 - }, 219 - .driver_data = "i2c-OVTI2680:00", 220 - }, 221 - { } 222 - }; 223 - 224 221 int skl_int3472_register_regulator(struct int3472_discrete_device *int3472, 225 - struct gpio_desc *gpio) 222 + struct gpio_desc *gpio, 223 + unsigned int enable_time, 224 + const char *supply_name, 225 + const char *second_sensor) 226 226 { 227 227 struct regulator_init_data init_data = { }; 228 + struct int3472_gpio_regulator *regulator; 228 229 struct regulator_config cfg = { }; 229 - const char *second_sensor = NULL; 230 - const struct dmi_system_id *id; 231 230 int i, j; 232 231 233 - id = dmi_first_match(skl_int3472_regulator_second_sensor); 234 - if (id) 235 - second_sensor = id->driver_data; 232 + if (int3472->n_regulator_gpios >= INT3472_MAX_REGULATORS) { 233 + dev_err(int3472->dev, "Too many regulators mapped\n"); 234 + return -EINVAL; 235 + } 236 236 237 - for (i = 0, j = 0; i < ARRAY_SIZE(skl_int3472_regulator_map_supplies); i++) { 238 - int3472->regulator.supply_map[j].supply = skl_int3472_regulator_map_supplies[i]; 239 - int3472->regulator.supply_map[j].dev_name = int3472->sensor_name; 237 + if (strlen(supply_name) >= GPIO_SUPPLY_NAME_LENGTH) { 238 + dev_err(int3472->dev, "supply-name '%s' length too long\n", supply_name); 239 + return -E2BIG; 240 + } 241 + 242 + regulator = &int3472->regulators[int3472->n_regulator_gpios]; 243 + string_upper(regulator->supply_name_upper, supply_name); 244 + 245 + /* The below code assume that map-count is 2 (upper- and lower-case) */ 246 + static_assert(GPIO_REGULATOR_SUPPLY_MAP_COUNT == 2); 247 + 248 + for (i = 0, j = 0; i < GPIO_REGULATOR_SUPPLY_MAP_COUNT; i++) { 249 + const char *supply = i ? regulator->supply_name_upper : supply_name; 250 + 251 + regulator->supply_map[j].supply = supply; 252 + regulator->supply_map[j].dev_name = int3472->sensor_name; 240 253 j++; 241 254 242 255 if (second_sensor) { 243 - int3472->regulator.supply_map[j].supply = 244 - skl_int3472_regulator_map_supplies[i]; 245 - int3472->regulator.supply_map[j].dev_name = second_sensor; 256 + regulator->supply_map[j].supply = supply; 257 + regulator->supply_map[j].dev_name = second_sensor; 246 258 j++; 247 259 } 248 260 } 249 261 250 262 init_data.constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS; 251 - init_data.consumer_supplies = int3472->regulator.supply_map; 263 + init_data.consumer_supplies = regulator->supply_map; 252 264 init_data.num_consumer_supplies = j; 253 265 254 - snprintf(int3472->regulator.regulator_name, 255 - sizeof(int3472->regulator.regulator_name), "%s-regulator", 256 - acpi_dev_name(int3472->adev)); 257 - snprintf(int3472->regulator.supply_name, 258 - GPIO_REGULATOR_SUPPLY_NAME_LENGTH, "supply-0"); 266 + snprintf(regulator->regulator_name, sizeof(regulator->regulator_name), "%s-%s", 267 + acpi_dev_name(int3472->adev), supply_name); 259 268 260 - int3472->regulator.rdesc = INT3472_REGULATOR( 261 - int3472->regulator.regulator_name, 262 - int3472->regulator.supply_name, 263 - &int3472_gpio_regulator_ops); 264 - 265 - int3472->regulator.gpio = gpio; 269 + regulator->rdesc = INT3472_REGULATOR(regulator->regulator_name, 270 + &int3472_gpio_regulator_ops, 271 + enable_time, GPIO_REGULATOR_OFF_ON_DELAY); 266 272 267 273 cfg.dev = &int3472->adev->dev; 268 274 cfg.init_data = &init_data; 269 - cfg.ena_gpiod = int3472->regulator.gpio; 275 + cfg.ena_gpiod = gpio; 270 276 271 - int3472->regulator.rdev = regulator_register(int3472->dev, 272 - &int3472->regulator.rdesc, 273 - &cfg); 277 + regulator->rdev = regulator_register(int3472->dev, &regulator->rdesc, &cfg); 278 + if (IS_ERR(regulator->rdev)) 279 + return PTR_ERR(regulator->rdev); 274 280 275 - return PTR_ERR_OR_ZERO(int3472->regulator.rdev); 281 + int3472->regulators[int3472->n_regulator_gpios].ena_gpio = gpio; 282 + int3472->n_regulator_gpios++; 283 + return 0; 276 284 } 277 285 278 286 void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472) 279 287 { 280 - regulator_unregister(int3472->regulator.rdev); 288 + for (int i = 0; i < int3472->n_regulator_gpios; i++) { 289 + regulator_unregister(int3472->regulators[i].rdev); 290 + gpiod_put(int3472->regulators[i].ena_gpio); 291 + } 281 292 }
+4 -5
drivers/platform/x86/intel/int3472/common.c
··· 2 2 /* Author: Dan Scally <djrscally@gmail.com> */ 3 3 4 4 #include <linux/acpi.h> 5 + #include <linux/platform_data/x86/int3472.h> 5 6 #include <linux/slab.h> 6 - 7 - #include "common.h" 8 7 9 8 union acpi_object *skl_int3472_get_acpi_buffer(struct acpi_device *adev, char *id) 10 9 { ··· 28 29 29 30 return obj; 30 31 } 31 - EXPORT_SYMBOL_GPL(skl_int3472_get_acpi_buffer); 32 + EXPORT_SYMBOL_NS_GPL(skl_int3472_get_acpi_buffer, "INTEL_INT3472"); 32 33 33 34 int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb) 34 35 { ··· 52 53 kfree(obj); 53 54 return ret; 54 55 } 55 - EXPORT_SYMBOL_GPL(skl_int3472_fill_cldb); 56 + EXPORT_SYMBOL_NS_GPL(skl_int3472_fill_cldb, "INTEL_INT3472"); 56 57 57 58 /* sensor_adev_ret may be NULL, name_ret must not be NULL */ 58 59 int skl_int3472_get_sensor_adev_and_name(struct device *dev, ··· 83 84 84 85 return ret; 85 86 } 86 - EXPORT_SYMBOL_GPL(skl_int3472_get_sensor_adev_and_name); 87 + EXPORT_SYMBOL_NS_GPL(skl_int3472_get_sensor_adev_and_name, "INTEL_INT3472"); 87 88 88 89 MODULE_DESCRIPTION("Intel SkyLake INT3472 ACPI Device Driver library"); 89 90 MODULE_AUTHOR("Daniel Scally <djrscally@gmail.com>");
+54 -19
drivers/platform/x86/intel/int3472/common.h include/linux/platform_data/x86/int3472.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 - /* Author: Dan Scally <djrscally@gmail.com> */ 2 + /* 3 + * Intel INT3472 ACPI camera sensor power-management support 4 + * 5 + * Author: Dan Scally <djrscally@gmail.com> 6 + */ 3 7 4 - #ifndef _INTEL_SKL_INT3472_H 5 - #define _INTEL_SKL_INT3472_H 8 + #ifndef __PLATFORM_DATA_X86_INT3472_H 9 + #define __PLATFORM_DATA_X86_INT3472_H 6 10 7 11 #include <linux/clk-provider.h> 8 12 #include <linux/gpio/machine.h> ··· 26 22 #define INT3472_GPIO_TYPE_POWER_ENABLE 0x0b 27 23 #define INT3472_GPIO_TYPE_CLK_ENABLE 0x0c 28 24 #define INT3472_GPIO_TYPE_PRIVACY_LED 0x0d 25 + #define INT3472_GPIO_TYPE_HANDSHAKE 0x12 29 26 30 27 #define INT3472_PDEV_MAX_NAME_LEN 23 31 28 #define INT3472_MAX_SENSOR_GPIOS 3 29 + #define INT3472_MAX_REGULATORS 3 32 30 33 - #define GPIO_REGULATOR_NAME_LENGTH 21 34 - #define GPIO_REGULATOR_SUPPLY_NAME_LENGTH 9 31 + /* E.g. "avdd\0" */ 32 + #define GPIO_SUPPLY_NAME_LENGTH 5 33 + /* 12 chars for acpi_dev_name() + "-", e.g. "ABCD1234:00-" */ 34 + #define GPIO_REGULATOR_NAME_LENGTH (12 + GPIO_SUPPLY_NAME_LENGTH) 35 + /* lower- and upper-case mapping */ 35 36 #define GPIO_REGULATOR_SUPPLY_MAP_COUNT 2 37 + /* 38 + * Ensure the GPIO is driven low/high for at least 2 ms before changing. 39 + * 40 + * 2 ms has been chosen because it is the minimum time ovXXXX sensors need to 41 + * have their reset line driven logical high to properly register a reset. 42 + */ 43 + #define GPIO_REGULATOR_ENABLE_TIME (2 * USEC_PER_MSEC) 44 + #define GPIO_REGULATOR_OFF_ON_DELAY (2 * USEC_PER_MSEC) 36 45 37 46 #define INT3472_LED_MAX_NAME_LEN 32 38 47 39 48 #define CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET 86 40 49 41 - #define INT3472_REGULATOR(_name, _supply, _ops) \ 50 + #define INT3472_REGULATOR(_name, _ops, _enable_time, _off_on_delay) \ 42 51 (const struct regulator_desc) { \ 43 52 .name = _name, \ 44 - .supply_name = _supply, \ 45 53 .type = REGULATOR_VOLTAGE, \ 46 54 .ops = _ops, \ 47 55 .owner = THIS_MODULE, \ 56 + .enable_time = _enable_time, \ 57 + .off_on_delay = _off_on_delay, \ 48 58 } 49 59 50 60 #define to_int3472_clk(hw) \ ··· 68 50 container_of(clk, struct int3472_discrete_device, clock) 69 51 70 52 struct acpi_device; 53 + struct dmi_system_id; 71 54 struct i2c_client; 72 55 struct platform_device; 73 56 ··· 89 70 u8 reserved2[17]; 90 71 }; 91 72 73 + struct int3472_discrete_quirks { 74 + /* For models where AVDD GPIO is shared between sensors */ 75 + const char *avdd_second_sensor; 76 + }; 77 + 78 + struct int3472_gpio_regulator { 79 + /* SUPPLY_MAP_COUNT * 2 to make room for second sensor mappings */ 80 + struct regulator_consumer_supply supply_map[GPIO_REGULATOR_SUPPLY_MAP_COUNT * 2]; 81 + char supply_name_upper[GPIO_SUPPLY_NAME_LENGTH]; 82 + char regulator_name[GPIO_REGULATOR_NAME_LENGTH]; 83 + struct gpio_desc *ena_gpio; 84 + struct regulator_dev *rdev; 85 + struct regulator_desc rdesc; 86 + }; 87 + 92 88 struct int3472_discrete_device { 93 89 struct acpi_device *adev; 94 90 struct device *dev; 95 91 struct acpi_device *sensor; 96 92 const char *sensor_name; 97 93 98 - const struct int3472_sensor_config *sensor_config; 99 - 100 - struct int3472_gpio_regulator { 101 - /* SUPPLY_MAP_COUNT * 2 to make room for second sensor mappings */ 102 - struct regulator_consumer_supply supply_map[GPIO_REGULATOR_SUPPLY_MAP_COUNT * 2]; 103 - char regulator_name[GPIO_REGULATOR_NAME_LENGTH]; 104 - char supply_name[GPIO_REGULATOR_SUPPLY_NAME_LENGTH]; 105 - struct gpio_desc *gpio; 106 - struct regulator_dev *rdev; 107 - struct regulator_desc rdesc; 108 - } regulator; 94 + struct int3472_gpio_regulator regulators[INT3472_MAX_REGULATORS]; 109 95 110 96 struct int3472_clock { 111 97 struct clk *clk; ··· 128 104 struct gpio_desc *gpio; 129 105 } pled; 130 106 107 + struct int3472_discrete_quirks quirks; 108 + 131 109 unsigned int ngpios; /* how many GPIOs have we seen */ 132 110 unsigned int n_sensor_gpios; /* how many have we mapped to sensor */ 111 + unsigned int n_regulator_gpios; /* how many have we mapped to a regulator */ 133 112 struct gpiod_lookup_table gpios; 134 113 }; 114 + 115 + extern const struct dmi_system_id skl_int3472_discrete_quirks[]; 135 116 136 117 union acpi_object *skl_int3472_get_acpi_buffer(struct acpi_device *adev, 137 118 char *id); ··· 145 116 struct acpi_device **sensor_adev_ret, 146 117 const char **name_ret); 147 118 119 + int int3472_discrete_parse_crs(struct int3472_discrete_device *int3472); 120 + void int3472_discrete_cleanup(struct int3472_discrete_device *int3472); 121 + 148 122 int skl_int3472_register_gpio_clock(struct int3472_discrete_device *int3472, 149 123 struct gpio_desc *gpio); 150 124 int skl_int3472_register_dsm_clock(struct int3472_discrete_device *int3472); 151 125 void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472); 152 126 153 127 int skl_int3472_register_regulator(struct int3472_discrete_device *int3472, 154 - struct gpio_desc *gpio); 128 + struct gpio_desc *gpio, 129 + unsigned int enable_time, 130 + const char *supply_name, 131 + const char *second_sensor); 155 132 void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472); 156 133 157 134 int skl_int3472_register_pled(struct int3472_discrete_device *int3472, struct gpio_desc *gpio);
+56 -13
drivers/platform/x86/intel/int3472/discrete.c
··· 5 5 #include <linux/array_size.h> 6 6 #include <linux/bitfield.h> 7 7 #include <linux/device.h> 8 + #include <linux/dmi.h> 8 9 #include <linux/gpio/consumer.h> 9 10 #include <linux/gpio/machine.h> 10 11 #include <linux/i2c.h> 11 12 #include <linux/kernel.h> 12 13 #include <linux/module.h> 13 14 #include <linux/overflow.h> 15 + #include <linux/platform_data/x86/int3472.h> 14 16 #include <linux/platform_device.h> 15 17 #include <linux/string_choices.h> 16 18 #include <linux/uuid.h> 17 - 18 - #include "common.h" 19 19 20 20 /* 21 21 * 79234640-9e10-4fea-a5c1-b5aa8b19756f ··· 117 117 return ERR_PTR(ret); 118 118 119 119 gpiod_add_lookup_table(lookup); 120 - desc = devm_gpiod_get(int3472->dev, con_id, GPIOD_OUT_LOW); 120 + desc = gpiod_get(int3472->dev, con_id, GPIOD_OUT_LOW); 121 121 gpiod_remove_lookup_table(lookup); 122 122 123 123 return desc; ··· 142 142 }; 143 143 144 144 static const struct int3472_gpio_map int3472_gpio_map[] = { 145 + /* mt9m114 designs declare a powerdown pin which controls the regulators */ 146 + { "INT33F0", INT3472_GPIO_TYPE_POWERDOWN, INT3472_GPIO_TYPE_POWER_ENABLE, false, "vdd" }, 147 + /* ov7251 driver / DT-bindings expect "enable" as con_id for reset */ 145 148 { "INT347E", INT3472_GPIO_TYPE_RESET, INT3472_GPIO_TYPE_RESET, false, "enable" }, 146 149 }; 147 150 148 - static void int3472_get_con_id_and_polarity(struct acpi_device *adev, u8 *type, 151 + static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3472, u8 *type, 149 152 const char **con_id, unsigned long *gpio_flags) 150 153 { 154 + struct acpi_device *adev = int3472->sensor; 151 155 unsigned int i; 152 156 153 157 for (i = 0; i < ARRAY_SIZE(int3472_gpio_map); i++) { ··· 165 161 166 162 if (!acpi_dev_hid_uid_match(adev, int3472_gpio_map[i].hid, NULL)) 167 163 continue; 164 + 165 + dev_dbg(int3472->dev, "mapping type 0x%02x pin to 0x%02x %s\n", 166 + *type, int3472_gpio_map[i].type_to, int3472_gpio_map[i].con_id); 168 167 169 168 *type = int3472_gpio_map[i].type_to; 170 169 *gpio_flags = int3472_gpio_map[i].polarity_low ? ··· 194 187 *gpio_flags = GPIO_ACTIVE_HIGH; 195 188 break; 196 189 case INT3472_GPIO_TYPE_POWER_ENABLE: 197 - *con_id = "power-enable"; 190 + *con_id = "avdd"; 191 + *gpio_flags = GPIO_ACTIVE_HIGH; 192 + break; 193 + case INT3472_GPIO_TYPE_HANDSHAKE: 194 + *con_id = "dvdd"; 198 195 *gpio_flags = GPIO_ACTIVE_HIGH; 199 196 break; 200 197 default: ··· 273 262 274 263 type = FIELD_GET(INT3472_GPIO_DSM_TYPE, obj->integer.value); 275 264 276 - int3472_get_con_id_and_polarity(int3472->sensor, &type, &con_id, &gpio_flags); 265 + int3472_get_con_id_and_polarity(int3472, &type, &con_id, &gpio_flags); 277 266 278 267 pin = FIELD_GET(INT3472_GPIO_DSM_PIN, obj->integer.value); 279 268 /* Pin field is not really used under Windows and wraps around at 8 bits */ ··· 300 289 case INT3472_GPIO_TYPE_CLK_ENABLE: 301 290 case INT3472_GPIO_TYPE_PRIVACY_LED: 302 291 case INT3472_GPIO_TYPE_POWER_ENABLE: 292 + case INT3472_GPIO_TYPE_HANDSHAKE: 303 293 gpio = skl_int3472_gpiod_get_from_temp_lookup(int3472, agpio, con_id, gpio_flags); 304 294 if (IS_ERR(gpio)) { 305 295 ret = PTR_ERR(gpio); ··· 322 310 323 311 break; 324 312 case INT3472_GPIO_TYPE_POWER_ENABLE: 325 - ret = skl_int3472_register_regulator(int3472, gpio); 313 + ret = skl_int3472_register_regulator(int3472, gpio, 314 + GPIO_REGULATOR_ENABLE_TIME, 315 + con_id, 316 + int3472->quirks.avdd_second_sensor); 326 317 if (ret) 327 - err_msg = "Failed to map regulator to sensor\n"; 318 + err_msg = "Failed to map power-enable to sensor\n"; 319 + 320 + break; 321 + case INT3472_GPIO_TYPE_HANDSHAKE: 322 + /* Setups using a handshake pin need 25 ms enable delay */ 323 + ret = skl_int3472_register_regulator(int3472, gpio, 324 + 25 * USEC_PER_MSEC, 325 + con_id, NULL); 326 + if (ret) 327 + err_msg = "Failed to map handshake to sensor\n"; 328 328 329 329 break; 330 330 default: /* Never reached */ 331 331 ret = -EINVAL; 332 332 break; 333 333 } 334 + 335 + if (ret) 336 + gpiod_put(gpio); 337 + 334 338 break; 335 339 default: 336 340 dev_warn(int3472->dev, ··· 366 338 return 1; 367 339 } 368 340 369 - static int skl_int3472_parse_crs(struct int3472_discrete_device *int3472) 341 + int int3472_discrete_parse_crs(struct int3472_discrete_device *int3472) 370 342 { 371 343 LIST_HEAD(resource_list); 372 344 int ret; ··· 391 363 392 364 return 0; 393 365 } 366 + EXPORT_SYMBOL_NS_GPL(int3472_discrete_parse_crs, "INTEL_INT3472_DISCRETE"); 394 367 395 - static void skl_int3472_discrete_remove(struct platform_device *pdev) 368 + void int3472_discrete_cleanup(struct int3472_discrete_device *int3472) 396 369 { 397 - struct int3472_discrete_device *int3472 = platform_get_drvdata(pdev); 398 - 399 370 gpiod_remove_lookup_table(&int3472->gpios); 400 371 401 372 skl_int3472_unregister_clock(int3472); 402 373 skl_int3472_unregister_pled(int3472); 403 374 skl_int3472_unregister_regulator(int3472); 404 375 } 376 + EXPORT_SYMBOL_NS_GPL(int3472_discrete_cleanup, "INTEL_INT3472_DISCRETE"); 377 + 378 + static void skl_int3472_discrete_remove(struct platform_device *pdev) 379 + { 380 + int3472_discrete_cleanup(platform_get_drvdata(pdev)); 381 + } 405 382 406 383 static int skl_int3472_discrete_probe(struct platform_device *pdev) 407 384 { 408 385 struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); 386 + const struct int3472_discrete_quirks *quirks = NULL; 409 387 struct int3472_discrete_device *int3472; 388 + const struct dmi_system_id *id; 410 389 struct int3472_cldb cldb; 411 390 int ret; 412 391 413 392 if (!adev) 414 393 return -ENODEV; 394 + 395 + id = dmi_first_match(skl_int3472_discrete_quirks); 396 + if (id) 397 + quirks = id->driver_data; 415 398 416 399 ret = skl_int3472_fill_cldb(adev, &cldb); 417 400 if (ret) { ··· 447 408 platform_set_drvdata(pdev, int3472); 448 409 int3472->clock.imgclk_index = cldb.clock_source; 449 410 411 + if (quirks) 412 + int3472->quirks = *quirks; 413 + 450 414 ret = skl_int3472_get_sensor_adev_and_name(&pdev->dev, &int3472->sensor, 451 415 &int3472->sensor_name); 452 416 if (ret) ··· 461 419 */ 462 420 INIT_LIST_HEAD(&int3472->gpios.list); 463 421 464 - ret = skl_int3472_parse_crs(int3472); 422 + ret = int3472_discrete_parse_crs(int3472); 465 423 if (ret) { 466 424 skl_int3472_discrete_remove(pdev); 467 425 return ret; ··· 490 448 MODULE_DESCRIPTION("Intel SkyLake INT3472 ACPI Discrete Device Driver"); 491 449 MODULE_AUTHOR("Daniel Scally <djrscally@gmail.com>"); 492 450 MODULE_LICENSE("GPL v2"); 451 + MODULE_IMPORT_NS("INTEL_INT3472");
+21
drivers/platform/x86/intel/int3472/discrete_quirks.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Author: Hans de Goede <hansg@kernel.org> */ 3 + 4 + #include <linux/dmi.h> 5 + #include <linux/platform_data/x86/int3472.h> 6 + 7 + static const struct int3472_discrete_quirks lenovo_miix_510_quirks = { 8 + .avdd_second_sensor = "i2c-OVTI2680:00", 9 + }; 10 + 11 + const struct dmi_system_id skl_int3472_discrete_quirks[] = { 12 + { 13 + /* Lenovo Miix 510-12IKB */ 14 + .matches = { 15 + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 16 + DMI_MATCH(DMI_PRODUCT_VERSION, "MIIX 510-12IKB"), 17 + }, 18 + .driver_data = (void *)&lenovo_miix_510_quirks, 19 + }, 20 + { } 21 + };
+2 -1
drivers/platform/x86/intel/int3472/led.c
··· 4 4 #include <linux/acpi.h> 5 5 #include <linux/gpio/consumer.h> 6 6 #include <linux/leds.h> 7 - #include "common.h" 7 + #include <linux/platform_data/x86/int3472.h> 8 8 9 9 static int int3472_pled_set(struct led_classdev *led_cdev, 10 10 enum led_brightness brightness) ··· 56 56 57 57 led_remove_lookup(&int3472->pled.lookup); 58 58 led_classdev_unregister(&int3472->pled.classdev); 59 + gpiod_put(int3472->pled.gpio); 59 60 }
+2 -1
drivers/platform/x86/intel/int3472/tps68470.c
··· 8 8 #include <linux/mfd/tps68470.h> 9 9 #include <linux/platform_device.h> 10 10 #include <linux/platform_data/tps68470.h> 11 + #include <linux/platform_data/x86/int3472.h> 11 12 #include <linux/regmap.h> 12 13 #include <linux/string.h> 13 14 14 - #include "common.h" 15 15 #include "tps68470.h" 16 16 17 17 #define DESIGNED_FOR_CHROMEOS 1 ··· 261 261 MODULE_DESCRIPTION("Intel SkyLake INT3472 ACPI TPS68470 Device Driver"); 262 262 MODULE_AUTHOR("Daniel Scally <djrscally@gmail.com>"); 263 263 MODULE_LICENSE("GPL v2"); 264 + MODULE_IMPORT_NS("INTEL_INT3472"); 264 265 MODULE_SOFTDEP("pre: clk-tps68470 tps68470-regulator");
+4
drivers/platform/x86/intel/pmc/Kconfig
··· 8 8 depends on PCI 9 9 depends on ACPI 10 10 depends on INTEL_PMT_TELEMETRY 11 + select INTEL_PMC_SSRAM_TELEMETRY 11 12 help 12 13 The Intel Platform Controller Hub for Intel Core SoCs provides access 13 14 to Power Management Controller registers via various interfaces. This ··· 25 24 - SLPS0 Debug registers (Cannonlake/Icelake PCH) 26 25 - Low Power Mode registers (Tigerlake and beyond) 27 26 - PMC quirks as needed to enable SLPS0/S0ix 27 + 28 + config INTEL_PMC_SSRAM_TELEMETRY 29 + tristate
+6 -2
drivers/platform/x86/intel/pmc/Makefile
··· 3 3 # Intel x86 Platform-Specific Drivers 4 4 # 5 5 6 - intel_pmc_core-y := core.o core_ssram.o spt.o cnp.o \ 7 - icl.o tgl.o adl.o mtl.o arl.o lnl.o ptl.o 6 + intel_pmc_core-y := core.o spt.o cnp.o icl.o \ 7 + tgl.o adl.o mtl.o arl.o lnl.o ptl.o 8 8 obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o 9 9 intel_pmc_core_pltdrv-y := pltdrv.o 10 10 obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core_pltdrv.o 11 + 12 + # Intel PMC SSRAM driver 13 + intel_pmc_ssram_telemetry-y += ssram_telemetry.o 14 + obj-$(CONFIG_INTEL_PMC_SSRAM_TELEMETRY) += intel_pmc_ssram_telemetry.o
+4 -9
drivers/platform/x86/intel/pmc/arl.c
··· 10 10 11 11 #include <linux/pci.h> 12 12 #include "core.h" 13 - #include "../pmt/telemetry.h" 14 13 15 14 /* PMC SSRAM PMT Telemetry GUID */ 16 15 #define IOEP_LPM_REQ_GUID 0x5077612 ··· 650 651 .etr3_offset = ETR3_OFFSET, 651 652 }; 652 653 653 - #define PMC_DEVID_SOCM 0x777f 654 - #define PMC_DEVID_SOCS 0xae7f 655 - #define PMC_DEVID_IOEP 0x7ecf 656 - #define PMC_DEVID_PCHS 0x7f27 657 654 static struct pmc_info arl_pmc_info_list[] = { 658 655 { 659 656 .guid = IOEP_LPM_REQ_GUID, 660 - .devid = PMC_DEVID_IOEP, 657 + .devid = PMC_DEVID_ARL_IOEP, 661 658 .map = &mtl_ioep_reg_map, 662 659 }, 663 660 { 664 661 .guid = SOCS_LPM_REQ_GUID, 665 - .devid = PMC_DEVID_SOCS, 662 + .devid = PMC_DEVID_ARL_SOCS, 666 663 .map = &arl_socs_reg_map, 667 664 }, 668 665 { 669 666 .guid = PCHS_LPM_REQ_GUID, 670 - .devid = PMC_DEVID_PCHS, 667 + .devid = PMC_DEVID_ARL_PCHS, 671 668 .map = &arl_pchs_reg_map, 672 669 }, 673 670 { 674 671 .guid = SOCM_LPM_REQ_GUID, 675 - .devid = PMC_DEVID_SOCM, 672 + .devid = PMC_DEVID_ARL_SOCM, 676 673 .map = &mtl_socm_reg_map, 677 674 }, 678 675 {}
+227 -13
drivers/platform/x86/intel/pmc/core.c
··· 29 29 #include <asm/tsc.h> 30 30 31 31 #include "core.h" 32 + #include "ssram_telemetry.h" 32 33 #include "../pmt/telemetry.h" 33 34 34 35 /* Maximum number of modes supported by platfoms that has low power mode capability */ ··· 1346 1345 } 1347 1346 } 1348 1347 1348 + static u32 pmc_core_find_guid(struct pmc_info *list, const struct pmc_reg_map *map) 1349 + { 1350 + for (; list->map; ++list) 1351 + if (list->map == map) 1352 + return list->guid; 1353 + 1354 + return 0; 1355 + } 1356 + 1357 + /* 1358 + * This function retrieves low power mode requirement data from PMC Low 1359 + * Power Mode (LPM) table. 1360 + * 1361 + * In telemetry space, the LPM table contains a 4 byte header followed 1362 + * by 8 consecutive mode blocks (one for each LPM mode). Each block 1363 + * has a 4 byte header followed by a set of registers that describe the 1364 + * IP state requirements for the given mode. The IP mapping is platform 1365 + * specific but the same for each block, making for easy analysis. 1366 + * Platforms only use a subset of the space to track the requirements 1367 + * for their IPs. Callers provide the requirement registers they use as 1368 + * a list of indices. Each requirement register is associated with an 1369 + * IP map that's maintained by the caller. 1370 + * 1371 + * Header 1372 + * +----+----------------------------+----------------------------+ 1373 + * | 0 | REVISION | ENABLED MODES | 1374 + * +----+--------------+-------------+-------------+--------------+ 1375 + * 1376 + * Low Power Mode 0 Block 1377 + * +----+--------------+-------------+-------------+--------------+ 1378 + * | 1 | SUB ID | SIZE | MAJOR | MINOR | 1379 + * +----+--------------+-------------+-------------+--------------+ 1380 + * | 2 | LPM0 Requirements 0 | 1381 + * +----+---------------------------------------------------------+ 1382 + * | | ... | 1383 + * +----+---------------------------------------------------------+ 1384 + * | 29 | LPM0 Requirements 27 | 1385 + * +----+---------------------------------------------------------+ 1386 + * 1387 + * ... 1388 + * 1389 + * Low Power Mode 7 Block 1390 + * +----+--------------+-------------+-------------+--------------+ 1391 + * | | SUB ID | SIZE | MAJOR | MINOR | 1392 + * +----+--------------+-------------+-------------+--------------+ 1393 + * | 60 | LPM7 Requirements 0 | 1394 + * +----+---------------------------------------------------------+ 1395 + * | | ... | 1396 + * +----+---------------------------------------------------------+ 1397 + * | 87 | LPM7 Requirements 27 | 1398 + * +----+---------------------------------------------------------+ 1399 + * 1400 + */ 1401 + static int pmc_core_get_lpm_req(struct pmc_dev *pmcdev, struct pmc *pmc, struct pci_dev *pcidev) 1402 + { 1403 + struct telem_endpoint *ep; 1404 + const u8 *lpm_indices; 1405 + int num_maps, mode_offset = 0; 1406 + int ret, mode; 1407 + int lpm_size; 1408 + u32 guid; 1409 + 1410 + lpm_indices = pmc->map->lpm_reg_index; 1411 + num_maps = pmc->map->lpm_num_maps; 1412 + lpm_size = LPM_MAX_NUM_MODES * num_maps; 1413 + 1414 + guid = pmc_core_find_guid(pmcdev->regmap_list, pmc->map); 1415 + if (!guid) 1416 + return -ENXIO; 1417 + 1418 + ep = pmt_telem_find_and_register_endpoint(pcidev, guid, 0); 1419 + if (IS_ERR(ep)) { 1420 + dev_dbg(&pmcdev->pdev->dev, "couldn't get telem endpoint %pe", ep); 1421 + return -EPROBE_DEFER; 1422 + } 1423 + 1424 + pmc->lpm_req_regs = devm_kzalloc(&pmcdev->pdev->dev, 1425 + lpm_size * sizeof(u32), 1426 + GFP_KERNEL); 1427 + if (!pmc->lpm_req_regs) { 1428 + ret = -ENOMEM; 1429 + goto unregister_ep; 1430 + } 1431 + 1432 + mode_offset = LPM_HEADER_OFFSET + LPM_MODE_OFFSET; 1433 + pmc_for_each_mode(mode, pmcdev) { 1434 + u32 *req_offset = pmc->lpm_req_regs + (mode * num_maps); 1435 + int m; 1436 + 1437 + for (m = 0; m < num_maps; m++) { 1438 + u8 sample_id = lpm_indices[m] + mode_offset; 1439 + 1440 + ret = pmt_telem_read32(ep, sample_id, req_offset, 1); 1441 + if (ret) { 1442 + dev_err(&pmcdev->pdev->dev, 1443 + "couldn't read Low Power Mode requirements: %d\n", ret); 1444 + goto unregister_ep; 1445 + } 1446 + ++req_offset; 1447 + } 1448 + mode_offset += LPM_REG_COUNT + LPM_MODE_OFFSET; 1449 + } 1450 + 1451 + unregister_ep: 1452 + pmt_telem_unregister_endpoint(ep); 1453 + 1454 + return ret; 1455 + } 1456 + 1457 + static int pmc_core_ssram_get_lpm_reqs(struct pmc_dev *pmcdev, int func) 1458 + { 1459 + struct pci_dev *pcidev __free(pci_dev_put) = NULL; 1460 + unsigned int i; 1461 + int ret; 1462 + 1463 + pcidev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(20, func)); 1464 + if (!pcidev) 1465 + return -ENODEV; 1466 + 1467 + for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { 1468 + if (!pmcdev->pmcs[i]) 1469 + continue; 1470 + 1471 + ret = pmc_core_get_lpm_req(pmcdev, pmcdev->pmcs[i], pcidev); 1472 + if (ret) 1473 + return ret; 1474 + } 1475 + 1476 + return 0; 1477 + } 1478 + 1479 + static const struct pmc_reg_map *pmc_core_find_regmap(struct pmc_info *list, u16 devid) 1480 + { 1481 + for (; list->map; ++list) 1482 + if (devid == list->devid) 1483 + return list->map; 1484 + 1485 + return NULL; 1486 + } 1487 + 1488 + static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_index) 1489 + 1490 + { 1491 + struct pmc_ssram_telemetry pmc_ssram_telemetry; 1492 + const struct pmc_reg_map *map; 1493 + struct pmc *pmc; 1494 + int ret; 1495 + 1496 + ret = pmc_ssram_telemetry_get_pmc_info(pmc_index, &pmc_ssram_telemetry); 1497 + if (ret) 1498 + return ret; 1499 + 1500 + map = pmc_core_find_regmap(pmcdev->regmap_list, pmc_ssram_telemetry.devid); 1501 + if (!map) 1502 + return -ENODEV; 1503 + 1504 + pmc = pmcdev->pmcs[pmc_index]; 1505 + /* Memory for primary PMC has been allocated */ 1506 + if (!pmc) { 1507 + pmc = devm_kzalloc(&pmcdev->pdev->dev, sizeof(*pmc), GFP_KERNEL); 1508 + if (!pmc) 1509 + return -ENOMEM; 1510 + } 1511 + 1512 + pmc->map = map; 1513 + pmc->base_addr = pmc_ssram_telemetry.base_addr; 1514 + pmc->regbase = ioremap(pmc->base_addr, pmc->map->regmap_length); 1515 + 1516 + if (!pmc->regbase) { 1517 + devm_kfree(&pmcdev->pdev->dev, pmc); 1518 + return -ENOMEM; 1519 + } 1520 + 1521 + pmcdev->pmcs[pmc_index] = pmc; 1522 + 1523 + return 0; 1524 + } 1525 + 1526 + static int pmc_core_ssram_get_reg_base(struct pmc_dev *pmcdev) 1527 + { 1528 + int ret; 1529 + 1530 + ret = pmc_core_pmc_add(pmcdev, PMC_IDX_MAIN); 1531 + if (ret) 1532 + return ret; 1533 + 1534 + pmc_core_pmc_add(pmcdev, PMC_IDX_IOE); 1535 + pmc_core_pmc_add(pmcdev, PMC_IDX_PCH); 1536 + 1537 + return 0; 1538 + } 1539 + 1349 1540 /* 1350 1541 * When supported, ssram init is used to achieve all available PMCs. 1351 1542 * If ssram init fails, this function uses legacy method to at least get the ··· 1555 1362 ssram = pmc_dev_info->regmap_list != NULL; 1556 1363 if (ssram) { 1557 1364 pmcdev->regmap_list = pmc_dev_info->regmap_list; 1558 - ret = pmc_core_ssram_init(pmcdev, pmc_dev_info->pci_func); 1365 + ret = pmc_core_ssram_get_reg_base(pmcdev); 1366 + /* 1367 + * EAGAIN error code indicates Intel PMC SSRAM Telemetry driver 1368 + * has not finished probe and PMC info is not available yet. Try 1369 + * again later. 1370 + */ 1371 + if (ret == -EAGAIN) 1372 + return -EPROBE_DEFER; 1373 + 1559 1374 if (ret) { 1560 1375 dev_warn(&pmcdev->pdev->dev, 1561 - "ssram init failed, %d, using legacy init\n", ret); 1376 + "Failed to get PMC info from SSRAM, %d, using legacy init\n", ret); 1562 1377 ssram = false; 1563 1378 } 1564 1379 } ··· 1582 1381 if (pmc_dev_info->dmu_guid) 1583 1382 pmc_core_punit_pmt_init(pmcdev, pmc_dev_info->dmu_guid); 1584 1383 1585 - if (ssram) 1586 - return pmc_core_ssram_get_lpm_reqs(pmcdev); 1384 + if (ssram) { 1385 + ret = pmc_core_ssram_get_lpm_reqs(pmcdev, pmc_dev_info->pci_func); 1386 + if (ret) 1387 + goto unmap_regbase; 1388 + } 1587 1389 1588 1390 return 0; 1391 + 1392 + unmap_regbase: 1393 + for (unsigned int i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { 1394 + struct pmc *pmc = pmcdev->pmcs[i]; 1395 + 1396 + if (pmc && pmc->regbase) 1397 + iounmap(pmc->regbase); 1398 + } 1399 + 1400 + if (pmcdev->punit_ep) 1401 + pmt_telem_unregister_endpoint(pmcdev->punit_ep); 1402 + 1403 + return ret; 1589 1404 } 1590 1405 1591 1406 static const struct x86_cpu_id intel_pmc_core_ids[] = { ··· 1688 1471 for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { 1689 1472 struct pmc *pmc = pmcdev->pmcs[i]; 1690 1473 1691 - if (pmc) 1474 + if (pmc && pmc->regbase) 1692 1475 iounmap(pmc->regbase); 1693 - } 1694 - 1695 - if (pmcdev->ssram_pcidev) { 1696 - pci_dev_put(pmcdev->ssram_pcidev); 1697 - pci_disable_device(pmcdev->ssram_pcidev); 1698 1476 } 1699 1477 1700 1478 if (pmcdev->punit_ep) 1701 1479 pmt_telem_unregister_endpoint(pmcdev->punit_ep); 1702 1480 1703 1481 platform_set_drvdata(pdev, NULL); 1704 - mutex_destroy(&pmcdev->lock); 1705 1482 } 1706 1483 1707 1484 static int pmc_core_probe(struct platform_device *pdev) ··· 1740 1529 if (!pmcdev->pkgc_res_cnt) 1741 1530 return -ENOMEM; 1742 1531 1743 - mutex_init(&pmcdev->lock); 1532 + ret = devm_mutex_init(&pdev->dev, &pmcdev->lock); 1533 + if (ret) 1534 + return ret; 1744 1535 1745 1536 if (pmc_dev_info->init) 1746 1537 ret = pmc_dev_info->init(pmcdev, pmc_dev_info); ··· 1750 1537 ret = generic_core_init(pmcdev, pmc_dev_info); 1751 1538 1752 1539 if (ret) { 1753 - pmc_core_clean_structure(pdev); 1540 + platform_set_drvdata(pdev, NULL); 1754 1541 return ret; 1755 1542 } 1756 1543 ··· 1932 1719 1933 1720 module_platform_driver(pmc_core_driver); 1934 1721 1722 + MODULE_IMPORT_NS("INTEL_PMT_TELEMETRY"); 1935 1723 MODULE_LICENSE("GPL v2"); 1936 1724 MODULE_DESCRIPTION("Intel PMC Core Driver");
+17 -5
drivers/platform/x86/intel/pmc/core.h
··· 24 24 #define MAX_NUM_PMC 3 25 25 #define S0IX_BLK_SIZE 4 26 26 27 + /* PCH query */ 28 + #define LPM_HEADER_OFFSET 1 29 + #define LPM_REG_COUNT 28 30 + #define LPM_MODE_OFFSET 1 31 + 27 32 /* Sunrise Point Power Management Controller PCI Device ID */ 28 33 #define SPT_PMC_PCI_DEVICE_ID 0x9d21 29 34 #define SPT_PMC_BASE_ADDR_OFFSET 0x48 ··· 298 293 #define PTL_PMC_LTR_CUR_PLT 0x1C2C 299 294 #define PTL_PCD_PMC_MMIO_REG_LEN 0x31A8 300 295 296 + /* SSRAM PMC Device ID */ 297 + /* ARL */ 298 + #define PMC_DEVID_ARL_SOCM 0x777f 299 + #define PMC_DEVID_ARL_SOCS 0xae7f 300 + #define PMC_DEVID_ARL_IOEP 0x7ecf 301 + #define PMC_DEVID_ARL_PCHS 0x7f27 302 + 303 + /* MTL */ 304 + #define PMC_DEVID_MTL_SOCM 0x7e7f 305 + #define PMC_DEVID_MTL_IOEP 0x7ecf 306 + #define PMC_DEVID_MTL_IOEM 0x7ebf 307 + 301 308 extern const char *pmc_lpm_modes[]; 302 309 303 310 struct pmc_bit_map { ··· 413 396 * struct pmc_dev - pmc device structure 414 397 * @devs: pointer to an array of pmc pointers 415 398 * @pdev: pointer to platform_device struct 416 - * @ssram_pcidev: pointer to pci device struct for the PMC SSRAM 417 399 * @crystal_freq: crystal frequency from cpuid 418 400 * @dbgfs_dir: path to debugfs interface 419 401 * @pmc_xram_read_bit: flag to indicate whether PMC XRAM shadow registers ··· 432 416 struct pmc *pmcs[MAX_NUM_PMC]; 433 417 struct dentry *dbgfs_dir; 434 418 struct platform_device *pdev; 435 - struct pci_dev *ssram_pcidev; 436 419 unsigned int crystal_freq; 437 420 int pmc_xram_read_bit; 438 421 struct mutex lock; /* generic mutex lock for PMC Core */ ··· 500 485 extern const struct pmc_reg_map mtl_ioep_reg_map; 501 486 502 487 void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev); 503 - int pmc_core_ssram_get_lpm_reqs(struct pmc_dev *pmcdev); 504 488 int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore); 505 489 506 490 int pmc_core_resume_common(struct pmc_dev *pmcdev); ··· 507 493 void pmc_core_get_low_power_modes(struct pmc_dev *pmcdev); 508 494 void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 guid); 509 495 void pmc_core_set_device_d3(unsigned int device); 510 - 511 - int pmc_core_ssram_init(struct pmc_dev *pmcdev, int func); 512 496 513 497 int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info); 514 498
-332
drivers/platform/x86/intel/pmc/core_ssram.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - /* 3 - * This file contains functions to handle discovery of PMC metrics located 4 - * in the PMC SSRAM PCI device. 5 - * 6 - * Copyright (c) 2023, Intel Corporation. 7 - * All Rights Reserved. 8 - * 9 - */ 10 - 11 - #include <linux/cleanup.h> 12 - #include <linux/intel_vsec.h> 13 - #include <linux/pci.h> 14 - #include <linux/io-64-nonatomic-lo-hi.h> 15 - 16 - #include "core.h" 17 - #include "../pmt/telemetry.h" 18 - 19 - #define SSRAM_HDR_SIZE 0x100 20 - #define SSRAM_PWRM_OFFSET 0x14 21 - #define SSRAM_DVSEC_OFFSET 0x1C 22 - #define SSRAM_DVSEC_SIZE 0x10 23 - #define SSRAM_PCH_OFFSET 0x60 24 - #define SSRAM_IOE_OFFSET 0x68 25 - #define SSRAM_DEVID_OFFSET 0x70 26 - 27 - /* PCH query */ 28 - #define LPM_HEADER_OFFSET 1 29 - #define LPM_REG_COUNT 28 30 - #define LPM_MODE_OFFSET 1 31 - 32 - DEFINE_FREE(pmc_core_iounmap, void __iomem *, if (_T) iounmap(_T)) 33 - 34 - static u32 pmc_core_find_guid(struct pmc_info *list, const struct pmc_reg_map *map) 35 - { 36 - for (; list->map; ++list) 37 - if (list->map == map) 38 - return list->guid; 39 - 40 - return 0; 41 - } 42 - 43 - static int pmc_core_get_lpm_req(struct pmc_dev *pmcdev, struct pmc *pmc) 44 - { 45 - struct telem_endpoint *ep; 46 - const u8 *lpm_indices; 47 - int num_maps, mode_offset = 0; 48 - int ret, mode; 49 - int lpm_size; 50 - u32 guid; 51 - 52 - lpm_indices = pmc->map->lpm_reg_index; 53 - num_maps = pmc->map->lpm_num_maps; 54 - lpm_size = LPM_MAX_NUM_MODES * num_maps; 55 - 56 - guid = pmc_core_find_guid(pmcdev->regmap_list, pmc->map); 57 - if (!guid) 58 - return -ENXIO; 59 - 60 - ep = pmt_telem_find_and_register_endpoint(pmcdev->ssram_pcidev, guid, 0); 61 - if (IS_ERR(ep)) { 62 - dev_dbg(&pmcdev->pdev->dev, "couldn't get telem endpoint %ld", 63 - PTR_ERR(ep)); 64 - return -EPROBE_DEFER; 65 - } 66 - 67 - pmc->lpm_req_regs = devm_kzalloc(&pmcdev->pdev->dev, 68 - lpm_size * sizeof(u32), 69 - GFP_KERNEL); 70 - if (!pmc->lpm_req_regs) { 71 - ret = -ENOMEM; 72 - goto unregister_ep; 73 - } 74 - 75 - /* 76 - * PMC Low Power Mode (LPM) table 77 - * 78 - * In telemetry space, the LPM table contains a 4 byte header followed 79 - * by 8 consecutive mode blocks (one for each LPM mode). Each block 80 - * has a 4 byte header followed by a set of registers that describe the 81 - * IP state requirements for the given mode. The IP mapping is platform 82 - * specific but the same for each block, making for easy analysis. 83 - * Platforms only use a subset of the space to track the requirements 84 - * for their IPs. Callers provide the requirement registers they use as 85 - * a list of indices. Each requirement register is associated with an 86 - * IP map that's maintained by the caller. 87 - * 88 - * Header 89 - * +----+----------------------------+----------------------------+ 90 - * | 0 | REVISION | ENABLED MODES | 91 - * +----+--------------+-------------+-------------+--------------+ 92 - * 93 - * Low Power Mode 0 Block 94 - * +----+--------------+-------------+-------------+--------------+ 95 - * | 1 | SUB ID | SIZE | MAJOR | MINOR | 96 - * +----+--------------+-------------+-------------+--------------+ 97 - * | 2 | LPM0 Requirements 0 | 98 - * +----+---------------------------------------------------------+ 99 - * | | ... | 100 - * +----+---------------------------------------------------------+ 101 - * | 29 | LPM0 Requirements 27 | 102 - * +----+---------------------------------------------------------+ 103 - * 104 - * ... 105 - * 106 - * Low Power Mode 7 Block 107 - * +----+--------------+-------------+-------------+--------------+ 108 - * | | SUB ID | SIZE | MAJOR | MINOR | 109 - * +----+--------------+-------------+-------------+--------------+ 110 - * | 60 | LPM7 Requirements 0 | 111 - * +----+---------------------------------------------------------+ 112 - * | | ... | 113 - * +----+---------------------------------------------------------+ 114 - * | 87 | LPM7 Requirements 27 | 115 - * +----+---------------------------------------------------------+ 116 - * 117 - */ 118 - mode_offset = LPM_HEADER_OFFSET + LPM_MODE_OFFSET; 119 - pmc_for_each_mode(mode, pmcdev) { 120 - u32 *req_offset = pmc->lpm_req_regs + (mode * num_maps); 121 - int m; 122 - 123 - for (m = 0; m < num_maps; m++) { 124 - u8 sample_id = lpm_indices[m] + mode_offset; 125 - 126 - ret = pmt_telem_read32(ep, sample_id, req_offset, 1); 127 - if (ret) { 128 - dev_err(&pmcdev->pdev->dev, 129 - "couldn't read Low Power Mode requirements: %d\n", ret); 130 - devm_kfree(&pmcdev->pdev->dev, pmc->lpm_req_regs); 131 - goto unregister_ep; 132 - } 133 - ++req_offset; 134 - } 135 - mode_offset += LPM_REG_COUNT + LPM_MODE_OFFSET; 136 - } 137 - 138 - unregister_ep: 139 - pmt_telem_unregister_endpoint(ep); 140 - 141 - return ret; 142 - } 143 - 144 - int pmc_core_ssram_get_lpm_reqs(struct pmc_dev *pmcdev) 145 - { 146 - int ret, i; 147 - 148 - if (!pmcdev->ssram_pcidev) 149 - return -ENODEV; 150 - 151 - for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); ++i) { 152 - if (!pmcdev->pmcs[i]) 153 - continue; 154 - 155 - ret = pmc_core_get_lpm_req(pmcdev, pmcdev->pmcs[i]); 156 - if (ret) 157 - return ret; 158 - } 159 - 160 - return 0; 161 - } 162 - 163 - static void 164 - pmc_add_pmt(struct pmc_dev *pmcdev, u64 ssram_base, void __iomem *ssram) 165 - { 166 - struct pci_dev *pcidev = pmcdev->ssram_pcidev; 167 - struct intel_vsec_platform_info info = {}; 168 - struct intel_vsec_header *headers[2] = {}; 169 - struct intel_vsec_header header; 170 - void __iomem *dvsec; 171 - u32 dvsec_offset; 172 - u32 table, hdr; 173 - 174 - ssram = ioremap(ssram_base, SSRAM_HDR_SIZE); 175 - if (!ssram) 176 - return; 177 - 178 - dvsec_offset = readl(ssram + SSRAM_DVSEC_OFFSET); 179 - iounmap(ssram); 180 - 181 - dvsec = ioremap(ssram_base + dvsec_offset, SSRAM_DVSEC_SIZE); 182 - if (!dvsec) 183 - return; 184 - 185 - hdr = readl(dvsec + PCI_DVSEC_HEADER1); 186 - header.id = readw(dvsec + PCI_DVSEC_HEADER2); 187 - header.rev = PCI_DVSEC_HEADER1_REV(hdr); 188 - header.length = PCI_DVSEC_HEADER1_LEN(hdr); 189 - header.num_entries = readb(dvsec + INTEL_DVSEC_ENTRIES); 190 - header.entry_size = readb(dvsec + INTEL_DVSEC_SIZE); 191 - 192 - table = readl(dvsec + INTEL_DVSEC_TABLE); 193 - header.tbir = INTEL_DVSEC_TABLE_BAR(table); 194 - header.offset = INTEL_DVSEC_TABLE_OFFSET(table); 195 - iounmap(dvsec); 196 - 197 - headers[0] = &header; 198 - info.caps = VSEC_CAP_TELEMETRY; 199 - info.headers = headers; 200 - info.base_addr = ssram_base; 201 - info.parent = &pmcdev->pdev->dev; 202 - 203 - intel_vsec_register(pcidev, &info); 204 - } 205 - 206 - static const struct pmc_reg_map *pmc_core_find_regmap(struct pmc_info *list, u16 devid) 207 - { 208 - for (; list->map; ++list) 209 - if (devid == list->devid) 210 - return list->map; 211 - 212 - return NULL; 213 - } 214 - 215 - static inline u64 get_base(void __iomem *addr, u32 offset) 216 - { 217 - return lo_hi_readq(addr + offset) & GENMASK_ULL(63, 3); 218 - } 219 - 220 - static int 221 - pmc_core_pmc_add(struct pmc_dev *pmcdev, u64 pwrm_base, 222 - const struct pmc_reg_map *reg_map, int pmc_index) 223 - { 224 - struct pmc *pmc = pmcdev->pmcs[pmc_index]; 225 - 226 - if (!pwrm_base) 227 - return -ENODEV; 228 - 229 - /* Memory for primary PMC has been allocated in core.c */ 230 - if (!pmc) { 231 - pmc = devm_kzalloc(&pmcdev->pdev->dev, sizeof(*pmc), GFP_KERNEL); 232 - if (!pmc) 233 - return -ENOMEM; 234 - } 235 - 236 - pmc->map = reg_map; 237 - pmc->base_addr = pwrm_base; 238 - pmc->regbase = ioremap(pmc->base_addr, pmc->map->regmap_length); 239 - 240 - if (!pmc->regbase) { 241 - devm_kfree(&pmcdev->pdev->dev, pmc); 242 - return -ENOMEM; 243 - } 244 - 245 - pmcdev->pmcs[pmc_index] = pmc; 246 - 247 - return 0; 248 - } 249 - 250 - static int 251 - pmc_core_ssram_get_pmc(struct pmc_dev *pmcdev, int pmc_idx, u32 offset) 252 - { 253 - struct pci_dev *ssram_pcidev = pmcdev->ssram_pcidev; 254 - void __iomem __free(pmc_core_iounmap) *tmp_ssram = NULL; 255 - void __iomem __free(pmc_core_iounmap) *ssram = NULL; 256 - const struct pmc_reg_map *map; 257 - u64 ssram_base, pwrm_base; 258 - u16 devid; 259 - 260 - if (!pmcdev->regmap_list) 261 - return -ENOENT; 262 - 263 - ssram_base = ssram_pcidev->resource[0].start; 264 - tmp_ssram = ioremap(ssram_base, SSRAM_HDR_SIZE); 265 - if (!tmp_ssram) 266 - return -ENOMEM; 267 - 268 - if (pmc_idx != PMC_IDX_MAIN) { 269 - /* 270 - * The secondary PMC BARS (which are behind hidden PCI devices) 271 - * are read from fixed offsets in MMIO of the primary PMC BAR. 272 - * If a device is not present, the value will be 0. 273 - */ 274 - ssram_base = get_base(tmp_ssram, offset); 275 - if (!ssram_base) 276 - return 0; 277 - 278 - ssram = ioremap(ssram_base, SSRAM_HDR_SIZE); 279 - if (!ssram) 280 - return -ENOMEM; 281 - 282 - } else { 283 - ssram = no_free_ptr(tmp_ssram); 284 - } 285 - 286 - pwrm_base = get_base(ssram, SSRAM_PWRM_OFFSET); 287 - devid = readw(ssram + SSRAM_DEVID_OFFSET); 288 - 289 - /* Find and register and PMC telemetry entries */ 290 - pmc_add_pmt(pmcdev, ssram_base, ssram); 291 - 292 - map = pmc_core_find_regmap(pmcdev->regmap_list, devid); 293 - if (!map) 294 - return -ENODEV; 295 - 296 - return pmc_core_pmc_add(pmcdev, pwrm_base, map, pmc_idx); 297 - } 298 - 299 - int pmc_core_ssram_init(struct pmc_dev *pmcdev, int func) 300 - { 301 - struct pci_dev *pcidev; 302 - int ret; 303 - 304 - pcidev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(20, func)); 305 - if (!pcidev) 306 - return -ENODEV; 307 - 308 - ret = pcim_enable_device(pcidev); 309 - if (ret) 310 - goto release_dev; 311 - 312 - pmcdev->ssram_pcidev = pcidev; 313 - 314 - ret = pmc_core_ssram_get_pmc(pmcdev, PMC_IDX_MAIN, 0); 315 - if (ret) 316 - goto disable_dev; 317 - 318 - pmc_core_ssram_get_pmc(pmcdev, PMC_IDX_IOE, SSRAM_IOE_OFFSET); 319 - pmc_core_ssram_get_pmc(pmcdev, PMC_IDX_PCH, SSRAM_PCH_OFFSET); 320 - 321 - return 0; 322 - 323 - disable_dev: 324 - pmcdev->ssram_pcidev = NULL; 325 - pci_disable_device(pcidev); 326 - release_dev: 327 - pci_dev_put(pcidev); 328 - 329 - return ret; 330 - } 331 - MODULE_IMPORT_NS("INTEL_VSEC"); 332 - MODULE_IMPORT_NS("INTEL_PMT_TELEMETRY");
+3 -7
drivers/platform/x86/intel/pmc/mtl.c
··· 10 10 11 11 #include <linux/pci.h> 12 12 #include "core.h" 13 - #include "../pmt/telemetry.h" 14 13 15 14 /* PMC SSRAM PMT Telemetry GUIDS */ 16 15 #define SOCP_LPM_REQ_GUID 0x2625030 ··· 946 947 .lpm_reg_index = MTL_LPM_REG_INDEX, 947 948 }; 948 949 949 - #define PMC_DEVID_SOCM 0x7e7f 950 - #define PMC_DEVID_IOEP 0x7ecf 951 - #define PMC_DEVID_IOEM 0x7ebf 952 950 static struct pmc_info mtl_pmc_info_list[] = { 953 951 { 954 952 .guid = SOCP_LPM_REQ_GUID, 955 - .devid = PMC_DEVID_SOCM, 953 + .devid = PMC_DEVID_MTL_SOCM, 956 954 .map = &mtl_socm_reg_map, 957 955 }, 958 956 { 959 957 .guid = IOEP_LPM_REQ_GUID, 960 - .devid = PMC_DEVID_IOEP, 958 + .devid = PMC_DEVID_MTL_IOEP, 961 959 .map = &mtl_ioep_reg_map, 962 960 }, 963 961 { 964 962 .guid = IOEM_LPM_REQ_GUID, 965 - .devid = PMC_DEVID_IOEM, 963 + .devid = PMC_DEVID_MTL_IOEM, 966 964 .map = &mtl_ioem_reg_map 967 965 }, 968 966 {}
+204
drivers/platform/x86/intel/pmc/ssram_telemetry.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Intel PMC SSRAM TELEMETRY PCI Driver 4 + * 5 + * Copyright (c) 2023, Intel Corporation. 6 + */ 7 + 8 + #include <linux/cleanup.h> 9 + #include <linux/intel_vsec.h> 10 + #include <linux/pci.h> 11 + #include <linux/types.h> 12 + #include <linux/io-64-nonatomic-lo-hi.h> 13 + 14 + #include "core.h" 15 + #include "ssram_telemetry.h" 16 + 17 + #define SSRAM_HDR_SIZE 0x100 18 + #define SSRAM_PWRM_OFFSET 0x14 19 + #define SSRAM_DVSEC_OFFSET 0x1C 20 + #define SSRAM_DVSEC_SIZE 0x10 21 + #define SSRAM_PCH_OFFSET 0x60 22 + #define SSRAM_IOE_OFFSET 0x68 23 + #define SSRAM_DEVID_OFFSET 0x70 24 + 25 + DEFINE_FREE(pmc_ssram_telemetry_iounmap, void __iomem *, if (_T) iounmap(_T)) 26 + 27 + static struct pmc_ssram_telemetry *pmc_ssram_telems; 28 + static bool device_probed; 29 + 30 + static int 31 + pmc_ssram_telemetry_add_pmt(struct pci_dev *pcidev, u64 ssram_base, void __iomem *ssram) 32 + { 33 + struct intel_vsec_platform_info info = {}; 34 + struct intel_vsec_header *headers[2] = {}; 35 + struct intel_vsec_header header; 36 + void __iomem *dvsec; 37 + u32 dvsec_offset; 38 + u32 table, hdr; 39 + 40 + dvsec_offset = readl(ssram + SSRAM_DVSEC_OFFSET); 41 + dvsec = ioremap(ssram_base + dvsec_offset, SSRAM_DVSEC_SIZE); 42 + if (!dvsec) 43 + return -ENOMEM; 44 + 45 + hdr = readl(dvsec + PCI_DVSEC_HEADER1); 46 + header.id = readw(dvsec + PCI_DVSEC_HEADER2); 47 + header.rev = PCI_DVSEC_HEADER1_REV(hdr); 48 + header.length = PCI_DVSEC_HEADER1_LEN(hdr); 49 + header.num_entries = readb(dvsec + INTEL_DVSEC_ENTRIES); 50 + header.entry_size = readb(dvsec + INTEL_DVSEC_SIZE); 51 + 52 + table = readl(dvsec + INTEL_DVSEC_TABLE); 53 + header.tbir = INTEL_DVSEC_TABLE_BAR(table); 54 + header.offset = INTEL_DVSEC_TABLE_OFFSET(table); 55 + iounmap(dvsec); 56 + 57 + headers[0] = &header; 58 + info.caps = VSEC_CAP_TELEMETRY; 59 + info.headers = headers; 60 + info.base_addr = ssram_base; 61 + info.parent = &pcidev->dev; 62 + 63 + return intel_vsec_register(pcidev, &info); 64 + } 65 + 66 + static inline u64 get_base(void __iomem *addr, u32 offset) 67 + { 68 + return lo_hi_readq(addr + offset) & GENMASK_ULL(63, 3); 69 + } 70 + 71 + static int 72 + pmc_ssram_telemetry_get_pmc(struct pci_dev *pcidev, unsigned int pmc_idx, u32 offset) 73 + { 74 + void __iomem __free(pmc_ssram_telemetry_iounmap) *tmp_ssram = NULL; 75 + void __iomem __free(pmc_ssram_telemetry_iounmap) *ssram = NULL; 76 + u64 ssram_base, pwrm_base; 77 + u16 devid; 78 + 79 + ssram_base = pci_resource_start(pcidev, 0); 80 + tmp_ssram = ioremap(ssram_base, SSRAM_HDR_SIZE); 81 + if (!tmp_ssram) 82 + return -ENOMEM; 83 + 84 + if (pmc_idx != PMC_IDX_MAIN) { 85 + /* 86 + * The secondary PMC BARS (which are behind hidden PCI devices) 87 + * are read from fixed offsets in MMIO of the primary PMC BAR. 88 + * If a device is not present, the value will be 0. 89 + */ 90 + ssram_base = get_base(tmp_ssram, offset); 91 + if (!ssram_base) 92 + return 0; 93 + 94 + ssram = ioremap(ssram_base, SSRAM_HDR_SIZE); 95 + if (!ssram) 96 + return -ENOMEM; 97 + 98 + } else { 99 + ssram = no_free_ptr(tmp_ssram); 100 + } 101 + 102 + pwrm_base = get_base(ssram, SSRAM_PWRM_OFFSET); 103 + devid = readw(ssram + SSRAM_DEVID_OFFSET); 104 + 105 + pmc_ssram_telems[pmc_idx].devid = devid; 106 + pmc_ssram_telems[pmc_idx].base_addr = pwrm_base; 107 + 108 + /* Find and register and PMC telemetry entries */ 109 + return pmc_ssram_telemetry_add_pmt(pcidev, ssram_base, ssram); 110 + } 111 + 112 + /** 113 + * pmc_ssram_telemetry_get_pmc_info() - Get a PMC devid and base_addr information 114 + * @pmc_idx: Index of the PMC 115 + * @pmc_ssram_telemetry: pmc_ssram_telemetry structure to store the PMC information 116 + * 117 + * Return: 118 + * * 0 - Success 119 + * * -EAGAIN - Probe function has not finished yet. Try again. 120 + * * -EINVAL - Invalid pmc_idx 121 + * * -ENODEV - PMC device is not available 122 + */ 123 + int pmc_ssram_telemetry_get_pmc_info(unsigned int pmc_idx, 124 + struct pmc_ssram_telemetry *pmc_ssram_telemetry) 125 + { 126 + /* 127 + * PMCs are discovered in probe function. If this function is called before 128 + * probe function complete, the result would be invalid. Use device_probed 129 + * variable to avoid this case. Return -EAGAIN to inform the consumer to call 130 + * again later. 131 + */ 132 + if (!device_probed) 133 + return -EAGAIN; 134 + 135 + /* 136 + * Memory barrier is used to ensure the correct read order between 137 + * device_probed variable and PMC info. 138 + */ 139 + smp_rmb(); 140 + if (pmc_idx >= MAX_NUM_PMC) 141 + return -EINVAL; 142 + 143 + if (!pmc_ssram_telems || !pmc_ssram_telems[pmc_idx].devid) 144 + return -ENODEV; 145 + 146 + pmc_ssram_telemetry->devid = pmc_ssram_telems[pmc_idx].devid; 147 + pmc_ssram_telemetry->base_addr = pmc_ssram_telems[pmc_idx].base_addr; 148 + return 0; 149 + } 150 + EXPORT_SYMBOL_GPL(pmc_ssram_telemetry_get_pmc_info); 151 + 152 + static int intel_pmc_ssram_telemetry_probe(struct pci_dev *pcidev, const struct pci_device_id *id) 153 + { 154 + int ret; 155 + 156 + pmc_ssram_telems = devm_kzalloc(&pcidev->dev, sizeof(*pmc_ssram_telems) * MAX_NUM_PMC, 157 + GFP_KERNEL); 158 + if (!pmc_ssram_telems) { 159 + ret = -ENOMEM; 160 + goto probe_finish; 161 + } 162 + 163 + ret = pcim_enable_device(pcidev); 164 + if (ret) { 165 + dev_dbg(&pcidev->dev, "failed to enable PMC SSRAM device\n"); 166 + goto probe_finish; 167 + } 168 + 169 + ret = pmc_ssram_telemetry_get_pmc(pcidev, PMC_IDX_MAIN, 0); 170 + if (ret) 171 + goto probe_finish; 172 + 173 + pmc_ssram_telemetry_get_pmc(pcidev, PMC_IDX_IOE, SSRAM_IOE_OFFSET); 174 + pmc_ssram_telemetry_get_pmc(pcidev, PMC_IDX_PCH, SSRAM_PCH_OFFSET); 175 + 176 + probe_finish: 177 + /* 178 + * Memory barrier is used to ensure the correct write order between PMC info 179 + * and device_probed variable. 180 + */ 181 + smp_wmb(); 182 + device_probed = true; 183 + return ret; 184 + } 185 + 186 + static const struct pci_device_id intel_pmc_ssram_telemetry_pci_ids[] = { 187 + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_MTL_SOCM) }, 188 + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_ARL_SOCS) }, 189 + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_ARL_SOCM) }, 190 + { } 191 + }; 192 + MODULE_DEVICE_TABLE(pci, intel_pmc_ssram_telemetry_pci_ids); 193 + 194 + static struct pci_driver intel_pmc_ssram_telemetry_driver = { 195 + .name = "intel_pmc_ssram_telemetry", 196 + .id_table = intel_pmc_ssram_telemetry_pci_ids, 197 + .probe = intel_pmc_ssram_telemetry_probe, 198 + }; 199 + module_pci_driver(intel_pmc_ssram_telemetry_driver); 200 + 201 + MODULE_IMPORT_NS("INTEL_VSEC"); 202 + MODULE_AUTHOR("Xi Pardee <xi.pardee@intel.com>"); 203 + MODULE_DESCRIPTION("Intel PMC SSRAM Telemetry driver"); 204 + MODULE_LICENSE("GPL");
+24
drivers/platform/x86/intel/pmc/ssram_telemetry.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Intel PMC SSRAM Telemetry PCI Driver Header File 4 + * 5 + * Copyright (c) 2024, Intel Corporation. 6 + */ 7 + 8 + #ifndef PMC_SSRAM_H 9 + #define PMC_SSRAM_H 10 + 11 + /** 12 + * struct pmc_ssram_telemetry - Structure to keep pmc info in ssram device 13 + * @devid: device id of the pmc device 14 + * @base_addr: contains PWRM base address 15 + */ 16 + struct pmc_ssram_telemetry { 17 + u16 devid; 18 + u64 base_addr; 19 + }; 20 + 21 + int pmc_ssram_telemetry_get_pmc_info(unsigned int pmc_idx, 22 + struct pmc_ssram_telemetry *pmc_ssram_telemetry); 23 + 24 + #endif /* PMC_SSRAM_H */
-21
drivers/platform/x86/intel/speed_select_if/isst_if_common.c
··· 199 199 } 200 200 EXPORT_SYMBOL_GPL(isst_resume_common); 201 201 202 - static void isst_restore_msr_local(int cpu) 203 - { 204 - struct isst_cmd *sst_cmd; 205 - int i; 206 - 207 - mutex_lock(&isst_hash_lock); 208 - for (i = 0; i < ARRAY_SIZE(punit_msr_white_list); ++i) { 209 - if (!punit_msr_white_list[i]) 210 - break; 211 - 212 - hash_for_each_possible(isst_hash, sst_cmd, hnode, 213 - punit_msr_white_list[i]) { 214 - if (!sst_cmd->mbox_cmd_type && sst_cmd->cpu == cpu) 215 - wrmsrq_safe(sst_cmd->cmd, sst_cmd->data); 216 - } 217 - } 218 - mutex_unlock(&isst_hash_lock); 219 - } 220 - 221 202 /** 222 203 * isst_if_mbox_cmd_invalid() - Check invalid mailbox commands 223 204 * @cmd: Pointer to the command structure to verify. ··· 415 434 416 435 set_punit_id: 417 436 isst_cpu_info[cpu].punit_cpu_id = data; 418 - 419 - isst_restore_msr_local(cpu); 420 437 421 438 return 0; 422 439 }
+101 -2
drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c
··· 35 35 36 36 /* Supported SST hardware version by this driver */ 37 37 #define ISST_MAJOR_VERSION 0 38 - #define ISST_MINOR_VERSION 1 38 + #define ISST_MINOR_VERSION 2 39 39 40 40 /* 41 41 * Used to indicate if value read from MMIO needs to get multiplied ··· 381 381 return -ENODEV; 382 382 } 383 383 384 - if (TPMI_MINOR_VERSION(pd_info->sst_header.interface_version) != ISST_MINOR_VERSION) 384 + if (TPMI_MINOR_VERSION(pd_info->sst_header.interface_version) > ISST_MINOR_VERSION) 385 385 dev_info(dev, "SST: Ignore: Unsupported minor version:%lx\n", 386 386 TPMI_MINOR_VERSION(pd_info->sst_header.interface_version)); 387 387 ··· 1017 1017 1018 1018 #define SST_PP_INFO_10_OFFSET 80 1019 1019 #define SST_PP_INFO_11_OFFSET 88 1020 + #define SST_PP_INFO_12_OFFSET 96 1020 1021 1021 1022 #define SST_PP_P1_SSE_START 0 1022 1023 #define SST_PP_P1_SSE_WIDTH 8 ··· 1069 1068 1070 1069 #define SST_PP_CORE_RATIO_PM_FABRIC_START 48 1071 1070 #define SST_PP_CORE_RATIO_PM_FABRIC_WIDTH 8 1071 + 1072 + #define SST_PP_CORE_RATIO_P0_FABRIC_1_START 0 1073 + #define SST_PP_CORE_RATIO_P0_FABRIC_1_WIDTH 8 1074 + 1075 + #define SST_PP_CORE_RATIO_P1_FABRIC_1_START 8 1076 + #define SST_PP_CORE_RATIO_P1_FABRIC_1_WIDTH 8 1077 + 1078 + #define SST_PP_CORE_RATIO_PM_FABRIC_1_START 16 1079 + #define SST_PP_CORE_RATIO_PM_FABRIC_1_WIDTH 8 1072 1080 1073 1081 static int isst_if_get_perf_level_info(void __user *argp) 1074 1082 { ··· 1173 1163 SST_PP_CORE_RATIO_PM_FABRIC_WIDTH, SST_MUL_FACTOR_FREQ) 1174 1164 1175 1165 if (copy_to_user(argp, &perf_level, sizeof(perf_level))) 1166 + return -EFAULT; 1167 + 1168 + return 0; 1169 + } 1170 + 1171 + static int isst_if_get_perf_level_fabric_info(void __user *argp) 1172 + { 1173 + struct isst_perf_level_fabric_info perf_level_fabric; 1174 + struct tpmi_per_power_domain_info *power_domain_info; 1175 + int start = SST_PP_CORE_RATIO_P0_FABRIC_START; 1176 + int width = SST_PP_CORE_RATIO_P0_FABRIC_WIDTH; 1177 + int offset = SST_PP_INFO_11_OFFSET; 1178 + int i; 1179 + 1180 + if (copy_from_user(&perf_level_fabric, argp, sizeof(perf_level_fabric))) 1181 + return -EFAULT; 1182 + 1183 + power_domain_info = get_instance(perf_level_fabric.socket_id, 1184 + perf_level_fabric.power_domain_id); 1185 + if (!power_domain_info) 1186 + return -EINVAL; 1187 + 1188 + if (perf_level_fabric.level > power_domain_info->max_level) 1189 + return -EINVAL; 1190 + 1191 + if (power_domain_info->pp_header.feature_rev < 2) 1192 + return -EINVAL; 1193 + 1194 + if (!(power_domain_info->pp_header.level_en_mask & BIT(perf_level_fabric.level))) 1195 + return -EINVAL; 1196 + 1197 + /* For revision 2, maximum number of fabrics is 2 */ 1198 + perf_level_fabric.max_fabrics = 2; 1199 + 1200 + for (i = 0; i < perf_level_fabric.max_fabrics; i++) { 1201 + _read_pp_level_info("p0_fabric_freq_mhz", perf_level_fabric.p0_fabric_freq_mhz[i], 1202 + perf_level_fabric.level, offset, start, width, 1203 + SST_MUL_FACTOR_FREQ) 1204 + start += width; 1205 + 1206 + _read_pp_level_info("p1_fabric_freq_mhz", perf_level_fabric.p1_fabric_freq_mhz[i], 1207 + perf_level_fabric.level, offset, start, width, 1208 + SST_MUL_FACTOR_FREQ) 1209 + start += width; 1210 + 1211 + _read_pp_level_info("pm_fabric_freq_mhz", perf_level_fabric.pm_fabric_freq_mhz[i], 1212 + perf_level_fabric.level, offset, start, width, 1213 + SST_MUL_FACTOR_FREQ) 1214 + offset = SST_PP_INFO_12_OFFSET; 1215 + start = SST_PP_CORE_RATIO_P0_FABRIC_1_START; 1216 + } 1217 + 1218 + if (copy_to_user(argp, &perf_level_fabric, sizeof(perf_level_fabric))) 1176 1219 return -EFAULT; 1177 1220 1178 1221 return 0; ··· 1392 1329 #define SST_TF_INFO_0_OFFSET 0 1393 1330 #define SST_TF_INFO_1_OFFSET 8 1394 1331 #define SST_TF_INFO_2_OFFSET 16 1332 + #define SST_TF_INFO_8_OFFSET 64 1333 + #define SST_TF_INFO_8_BUCKETS 3 1395 1334 1396 1335 #define SST_TF_MAX_LP_CLIP_RATIOS TRL_MAX_LEVELS 1336 + 1337 + #define SST_TF_FEATURE_REV_START 4 1338 + #define SST_TF_FEATURE_REV_WIDTH 8 1397 1339 1398 1340 #define SST_TF_LP_CLIP_RATIO_0_START 16 1399 1341 #define SST_TF_LP_CLIP_RATIO_0_WIDTH 8 ··· 1409 1341 #define SST_TF_NUM_CORE_0_START 0 1410 1342 #define SST_TF_NUM_CORE_0_WIDTH 8 1411 1343 1344 + #define SST_TF_NUM_MOD_0_START 0 1345 + #define SST_TF_NUM_MOD_0_WIDTH 16 1346 + 1412 1347 static int isst_if_get_turbo_freq_info(void __user *argp) 1413 1348 { 1414 1349 static struct isst_turbo_freq_info turbo_freq; 1415 1350 struct tpmi_per_power_domain_info *power_domain_info; 1351 + u8 feature_rev; 1416 1352 int i, j; 1417 1353 1418 1354 if (copy_from_user(&turbo_freq, argp, sizeof(turbo_freq))) ··· 1432 1360 turbo_freq.max_buckets = TRL_MAX_BUCKETS; 1433 1361 turbo_freq.max_trl_levels = TRL_MAX_LEVELS; 1434 1362 turbo_freq.max_clip_freqs = SST_TF_MAX_LP_CLIP_RATIOS; 1363 + 1364 + _read_tf_level_info("feature_rev", feature_rev, turbo_freq.level, 1365 + SST_TF_INFO_0_OFFSET, SST_TF_FEATURE_REV_START, 1366 + SST_TF_FEATURE_REV_WIDTH, SST_MUL_FACTOR_NONE); 1435 1367 1436 1368 for (i = 0; i < turbo_freq.max_clip_freqs; ++i) 1437 1369 _read_tf_level_info("lp_clip*", turbo_freq.lp_clip_freq_mhz[i], ··· 1453 1377 SST_MUL_FACTOR_FREQ) 1454 1378 } 1455 1379 1380 + if (feature_rev >= 2) { 1381 + bool has_tf_info_8 = false; 1382 + 1383 + for (i = 0; i < SST_TF_INFO_8_BUCKETS; ++i) { 1384 + _read_tf_level_info("bucket_*_mod_count", turbo_freq.bucket_core_counts[i], 1385 + turbo_freq.level, SST_TF_INFO_8_OFFSET, 1386 + SST_TF_NUM_MOD_0_WIDTH * i, SST_TF_NUM_MOD_0_WIDTH, 1387 + SST_MUL_FACTOR_NONE) 1388 + 1389 + if (turbo_freq.bucket_core_counts[i]) 1390 + has_tf_info_8 = true; 1391 + } 1392 + 1393 + if (has_tf_info_8) 1394 + goto done_core_count; 1395 + } 1396 + 1456 1397 for (i = 0; i < TRL_MAX_BUCKETS; ++i) 1457 1398 _read_tf_level_info("bucket_*_core_count", turbo_freq.bucket_core_counts[i], 1458 1399 turbo_freq.level, SST_TF_INFO_1_OFFSET, 1459 1400 SST_TF_NUM_CORE_0_WIDTH * i, SST_TF_NUM_CORE_0_WIDTH, 1460 1401 SST_MUL_FACTOR_NONE) 1402 + 1403 + 1404 + done_core_count: 1461 1405 1462 1406 if (copy_to_user(argp, &turbo_freq, sizeof(turbo_freq))) 1463 1407 return -EFAULT; ··· 1516 1420 break; 1517 1421 case ISST_IF_GET_PERF_LEVEL_INFO: 1518 1422 ret = isst_if_get_perf_level_info(argp); 1423 + break; 1424 + case ISST_IF_GET_PERF_LEVEL_FABRIC_INFO: 1425 + ret = isst_if_get_perf_level_fabric_info(argp); 1519 1426 break; 1520 1427 case ISST_IF_GET_PERF_LEVEL_CPU_MASK: 1521 1428 ret = isst_if_get_perf_level_mask(argp);
+30 -4
drivers/platform/x86/intel/tpmi_power_domains.c
··· 74 74 75 75 static cpumask_t *tpmi_power_domain_mask; 76 76 77 + static u16 *domain_die_map; 78 + 77 79 /* Lock to protect tpmi_power_domain_mask and tpmi_cpu_hash */ 78 80 static DEFINE_MUTEX(tpmi_lock); 79 81 ··· 154 152 } 155 153 EXPORT_SYMBOL_NS_GPL(tpmi_get_power_domain_mask, "INTEL_TPMI_POWER_DOMAIN"); 156 154 155 + int tpmi_get_linux_die_id(int pkg_id, int domain_id) 156 + { 157 + if (pkg_id >= topology_max_packages() || domain_id >= MAX_POWER_DOMAINS) 158 + return -EINVAL; 159 + 160 + return domain_die_map[pkg_id * MAX_POWER_DOMAINS + domain_id]; 161 + } 162 + EXPORT_SYMBOL_NS_GPL(tpmi_get_linux_die_id, "INTEL_TPMI_POWER_DOMAIN"); 163 + 157 164 static int tpmi_get_logical_id(unsigned int cpu, struct tpmi_cpu_info *info) 158 165 { 159 166 u64 data; ··· 200 189 cpumask_set_cpu(cpu, &tpmi_power_domain_mask[index]); 201 190 hash_add(tpmi_cpu_hash, &info->hnode, info->punit_core_id); 202 191 192 + domain_die_map[info->pkg_id * MAX_POWER_DOMAINS + info->punit_domain_id] = 193 + topology_die_id(cpu); 194 + 203 195 return 0; 204 196 } 205 197 ··· 226 212 if (!tpmi_power_domain_mask) 227 213 return -ENOMEM; 228 214 215 + domain_die_map = kcalloc(size_mul(topology_max_packages(), MAX_POWER_DOMAINS), 216 + sizeof(*domain_die_map), GFP_KERNEL); 217 + if (!domain_die_map) 218 + goto free_domain_mask; 219 + 229 220 ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, 230 221 "platform/x86/tpmi_power_domains:online", 231 222 tpmi_cpu_online, NULL); 232 - if (ret < 0) { 233 - kfree(tpmi_power_domain_mask); 234 - return ret; 235 - } 223 + if (ret < 0) 224 + goto free_domain_map; 236 225 237 226 tpmi_hp_state = ret; 238 227 239 228 return 0; 229 + 230 + free_domain_map: 231 + kfree(domain_die_map); 232 + 233 + free_domain_mask: 234 + kfree(tpmi_power_domain_mask); 235 + 236 + return ret; 240 237 } 241 238 module_init(tpmi_init) 242 239 ··· 255 230 { 256 231 cpuhp_remove_state(tpmi_hp_state); 257 232 kfree(tpmi_power_domain_mask); 233 + kfree(domain_die_map); 258 234 } 259 235 module_exit(tpmi_exit) 260 236
+1
drivers/platform/x86/intel/tpmi_power_domains.h
··· 14 14 int tpmi_get_punit_core_number(int cpu_no); 15 15 int tpmi_get_power_domain_id(int cpu_no); 16 16 cpumask_t *tpmi_get_power_domain_mask(int cpu_no); 17 + int tpmi_get_linux_die_id(int pkg_id, int domain_id); 17 18 18 19 #endif
+34
drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
··· 43 43 return sprintf(buf, "%u\n", data->package_id); 44 44 } 45 45 46 + #define MAX_UNCORE_AGENT_TYPES 4 47 + 48 + /* The order follows AGENT_TYPE_* defines */ 49 + static const char *agent_name[MAX_UNCORE_AGENT_TYPES] = {"core", "cache", "memory", "io"}; 50 + 51 + static ssize_t show_agent_types(struct kobject *kobj, struct kobj_attribute *attr, char *buf) 52 + { 53 + struct uncore_data *data = container_of(attr, struct uncore_data, agent_types_kobj_attr); 54 + unsigned long agent_mask = data->agent_type_mask; 55 + int agent, length = 0; 56 + 57 + for_each_set_bit(agent, &agent_mask, MAX_UNCORE_AGENT_TYPES) { 58 + if (length) 59 + length += sysfs_emit_at(buf, length, " "); 60 + 61 + length += sysfs_emit_at(buf, length, agent_name[agent]); 62 + } 63 + 64 + length += sysfs_emit_at(buf, length, "\n"); 65 + 66 + return length; 67 + } 68 + 46 69 static ssize_t show_attr(struct uncore_data *data, char *buf, enum uncore_index index) 47 70 { 48 71 unsigned int value; ··· 143 120 UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE); 144 121 show_uncore_attr(elc_floor_freq_khz, UNCORE_INDEX_EFF_LAT_CTRL_FREQ); 145 122 123 + show_uncore_attr(die_id, UNCORE_INDEX_DIE_ID); 124 + 146 125 #define show_uncore_data(member_name) \ 147 126 static ssize_t show_##member_name(struct kobject *kobj, \ 148 127 struct kobj_attribute *attr, char *buf)\ ··· 204 179 data->uncore_attrs[index++] = &data->fabric_cluster_id_kobj_attr.attr; 205 180 init_attribute_root_ro(package_id); 206 181 data->uncore_attrs[index++] = &data->package_id_kobj_attr.attr; 182 + if (data->agent_type_mask) { 183 + init_attribute_ro(agent_types); 184 + data->uncore_attrs[index++] = &data->agent_types_kobj_attr.attr; 185 + } 186 + if (topology_max_dies_per_package() > 1 && 187 + data->agent_type_mask & AGENT_TYPE_CORE) { 188 + init_attribute_ro(die_id); 189 + data->uncore_attrs[index++] = &data->die_id_kobj_attr.attr; 190 + } 207 191 } 208 192 209 193 data->uncore_attrs[index++] = &data->max_freq_khz_kobj_attr.attr;
+19 -1
drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h
··· 11 11 12 12 #include <linux/device.h> 13 13 14 + /* 15 + * Define uncore agents, which are under uncore frequency control. 16 + * Defined in the same order as specified in the TPMI UFS Specifications. 17 + * It is possible that there are common uncore frequency control to more than 18 + * one hardware agents. So, these defines are used as a bit mask. 19 + */ 20 + 21 + #define AGENT_TYPE_CORE 0x01 22 + #define AGENT_TYPE_CACHE 0x02 23 + #define AGENT_TYPE_MEMORY 0x04 24 + #define AGENT_TYPE_IO 0x08 25 + 14 26 /** 15 27 * struct uncore_data - Encapsulate all uncore data 16 28 * @stored_uncore_data: Last user changed MSR 620 value, which will be restored ··· 37 25 * @cluster_id: cluster id in a domain 38 26 * @instance_id: Unique instance id to append to directory name 39 27 * @name: Sysfs entry name for this instance 28 + * @agent_type_mask: Bit mask of all hardware agents for this domain 40 29 * @uncore_attr_group: Attribute group storage 41 30 * @max_freq_khz_kobj_attr: Storage for kobject attribute max_freq_khz 42 31 * @mix_freq_khz_kobj_attr: Storage for kobject attribute min_freq_khz ··· 54 41 * @elc_high_threshold_enable_kobj_attr: 55 42 Storage for kobject attribute elc_high_threshold_enable 56 43 * @elc_floor_freq_khz_kobj_attr: Storage for kobject attribute elc_floor_freq_khz 44 + * @agent_types_kobj_attr: Storage for kobject attribute agent_type 57 45 * @uncore_attrs: Attribute storage for group creation 58 46 * 59 47 * This structure is used to encapsulate all data related to uncore sysfs ··· 72 58 int cluster_id; 73 59 int instance_id; 74 60 char name[32]; 61 + u16 agent_type_mask; 75 62 76 63 struct attribute_group uncore_attr_group; 77 64 struct kobj_attribute max_freq_khz_kobj_attr; ··· 87 72 struct kobj_attribute elc_high_threshold_percent_kobj_attr; 88 73 struct kobj_attribute elc_high_threshold_enable_kobj_attr; 89 74 struct kobj_attribute elc_floor_freq_khz_kobj_attr; 90 - struct attribute *uncore_attrs[13]; 75 + struct kobj_attribute agent_types_kobj_attr; 76 + struct kobj_attribute die_id_kobj_attr; 77 + struct attribute *uncore_attrs[15]; 91 78 }; 92 79 93 80 #define UNCORE_DOMAIN_ID_INVALID -1 ··· 102 85 UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD, 103 86 UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE, 104 87 UNCORE_INDEX_EFF_LAT_CTRL_FREQ, 88 + UNCORE_INDEX_DIE_ID, 105 89 }; 106 90 107 91 int uncore_freq_common_init(int (*read)(struct uncore_data *data, unsigned int *value,
+49
drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c
··· 26 26 #include <linux/module.h> 27 27 #include <linux/intel_tpmi.h> 28 28 29 + #include "../tpmi_power_domains.h" 29 30 #include "uncore-frequency-common.h" 30 31 31 32 #define UNCORE_MAJOR_VERSION 0 ··· 50 49 bool root_domain; 51 50 bool elc_supported; 52 51 u8 __iomem *cluster_base; 52 + u16 cdie_id; 53 53 struct uncore_data uncore_data; 54 54 struct tpmi_uncore_struct *uncore_root; 55 55 }; ··· 349 347 return 0; 350 348 } 351 349 350 + /* 351 + * Agent types as per the TPMI UFS Specification for UFS_STATUS 352 + * Agent Type - Core Bit: 23 353 + * Agent Type - Cache Bit: 24 354 + * Agent Type - Memory Bit: 25 355 + * Agent Type - IO Bit: 26 356 + */ 357 + 358 + #define UNCORE_AGENT_TYPES GENMASK_ULL(26, 23) 359 + 360 + /* Helper function to read agent type over MMIO and set the agent type mask */ 361 + static void uncore_set_agent_type(struct tpmi_uncore_cluster_info *cluster_info) 362 + { 363 + u64 status; 364 + 365 + status = readq((u8 __iomem *)cluster_info->cluster_base + UNCORE_STATUS_INDEX); 366 + cluster_info->uncore_data.agent_type_mask = FIELD_GET(UNCORE_AGENT_TYPES, status); 367 + } 368 + 352 369 /* Callback for sysfs read for TPMI uncore values. Called under mutex locks. */ 353 370 static int uncore_read(struct uncore_data *data, unsigned int *value, enum uncore_index index) 354 371 { 372 + struct tpmi_uncore_cluster_info *cluster_info; 373 + int ret; 374 + 355 375 switch (index) { 356 376 case UNCORE_INDEX_MIN_FREQ: 357 377 case UNCORE_INDEX_MAX_FREQ: ··· 387 363 case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE: 388 364 case UNCORE_INDEX_EFF_LAT_CTRL_FREQ: 389 365 return read_eff_lat_ctrl(data, value, index); 366 + 367 + case UNCORE_INDEX_DIE_ID: 368 + cluster_info = container_of(data, struct tpmi_uncore_cluster_info, uncore_data); 369 + ret = tpmi_get_linux_die_id(cluster_info->uncore_data.package_id, 370 + cluster_info->cdie_id); 371 + if (ret < 0) 372 + return ret; 373 + 374 + *value = ret; 375 + return 0; 390 376 391 377 default: 392 378 break; ··· 445 411 uncore_freq_remove_die_entry(&cluster_info->uncore_data); 446 412 } 447 413 } 414 + } 415 + 416 + static void set_cdie_id(int domain_id, struct tpmi_uncore_cluster_info *cluster_info, 417 + struct intel_tpmi_plat_info *plat_info) 418 + { 419 + 420 + cluster_info->cdie_id = domain_id; 421 + 422 + if (plat_info->cdie_mask && cluster_info->uncore_data.agent_type_mask & AGENT_TYPE_CORE) 423 + cluster_info->cdie_id = domain_id + ffs(plat_info->cdie_mask) - 1; 448 424 } 449 425 450 426 #define UNCORE_VERSION_MASK GENMASK_ULL(7, 0) ··· 596 552 597 553 cluster_info->cluster_base = pd_info->uncore_base + mask; 598 554 555 + uncore_set_agent_type(cluster_info); 556 + 599 557 cluster_info->uncore_data.package_id = pkg; 600 558 /* There are no dies like Cascade Lake */ 601 559 cluster_info->uncore_data.die_id = 0; 602 560 cluster_info->uncore_data.domain_id = i; 603 561 cluster_info->uncore_data.cluster_id = j; 562 + 563 + set_cdie_id(i, cluster_info, plat_info); 604 564 605 565 cluster_info->uncore_root = tpmi_uncore; 606 566 ··· 679 631 680 632 MODULE_IMPORT_NS("INTEL_TPMI"); 681 633 MODULE_IMPORT_NS("INTEL_UNCORE_FREQUENCY"); 634 + MODULE_IMPORT_NS("INTEL_TPMI_POWER_DOMAIN"); 682 635 MODULE_DESCRIPTION("Intel TPMI UFS Driver"); 683 636 MODULE_LICENSE("GPL");
+6 -3
drivers/platform/x86/intel/vsec.c
··· 332 332 return have_devices; 333 333 } 334 334 335 - void intel_vsec_register(struct pci_dev *pdev, 335 + int intel_vsec_register(struct pci_dev *pdev, 336 336 struct intel_vsec_platform_info *info) 337 337 { 338 338 if (!pdev || !info || !info->headers) 339 - return; 339 + return -EINVAL; 340 340 341 - intel_vsec_walk_header(pdev, info); 341 + if (!intel_vsec_walk_header(pdev, info)) 342 + return -ENODEV; 343 + else 344 + return 0; 342 345 } 343 346 EXPORT_SYMBOL_NS_GPL(intel_vsec_register, "INTEL_VSEC"); 344 347
+1054
drivers/platform/x86/oxpec.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Platform driver for OneXPlayer and AOKZOE devices. For the time being, 4 + * it also exposes fan controls for AYANEO, and OrangePi Handhelds via 5 + * hwmon sysfs. 6 + * 7 + * Fan control is provided via pwm interface in the range [0-255]. 8 + * Old AMD boards use [0-100] as range in the EC, the written value is 9 + * scaled to accommodate for that. Newer boards like the mini PRO and 10 + * AOKZOE are not scaled but have the same EC layout. Newer models 11 + * like the 2 and X1 are [0-184] and are scaled to 0-255. OrangePi 12 + * are [1-244] and scaled to 0-255. 13 + * 14 + * Copyright (C) 2022 Joaquín I. Aramendía <samsagax@gmail.com> 15 + * Copyright (C) 2024 Derek J. Clark <derekjohn.clark@gmail.com> 16 + * Copyright (C) 2025 Antheas Kapenekakis <lkml@antheas.dev> 17 + */ 18 + 19 + #include <linux/acpi.h> 20 + #include <linux/dmi.h> 21 + #include <linux/hwmon.h> 22 + #include <linux/init.h> 23 + #include <linux/kernel.h> 24 + #include <linux/module.h> 25 + #include <linux/platform_device.h> 26 + #include <linux/processor.h> 27 + #include <acpi/battery.h> 28 + 29 + /* Handle ACPI lock mechanism */ 30 + static u32 oxp_mutex; 31 + 32 + #define ACPI_LOCK_DELAY_MS 500 33 + 34 + static bool lock_global_acpi_lock(void) 35 + { 36 + return ACPI_SUCCESS(acpi_acquire_global_lock(ACPI_LOCK_DELAY_MS, &oxp_mutex)); 37 + } 38 + 39 + static bool unlock_global_acpi_lock(void) 40 + { 41 + return ACPI_SUCCESS(acpi_release_global_lock(oxp_mutex)); 42 + } 43 + 44 + enum oxp_board { 45 + aok_zoe_a1 = 1, 46 + aya_neo_2, 47 + aya_neo_air, 48 + aya_neo_air_1s, 49 + aya_neo_air_plus_mendo, 50 + aya_neo_air_pro, 51 + aya_neo_flip, 52 + aya_neo_geek, 53 + aya_neo_kun, 54 + orange_pi_neo, 55 + oxp_2, 56 + oxp_fly, 57 + oxp_mini_amd, 58 + oxp_mini_amd_a07, 59 + oxp_mini_amd_pro, 60 + oxp_x1, 61 + oxp_g1, 62 + }; 63 + 64 + static enum oxp_board board; 65 + static struct device *oxp_dev; 66 + 67 + /* Fan reading and PWM */ 68 + #define OXP_SENSOR_FAN_REG 0x76 /* Fan reading is 2 registers long */ 69 + #define OXP_2_SENSOR_FAN_REG 0x58 /* Fan reading is 2 registers long */ 70 + #define OXP_SENSOR_PWM_ENABLE_REG 0x4A /* PWM enable is 1 register long */ 71 + #define OXP_SENSOR_PWM_REG 0x4B /* PWM reading is 1 register long */ 72 + #define PWM_MODE_AUTO 0x00 73 + #define PWM_MODE_MANUAL 0x01 74 + 75 + /* OrangePi fan reading and PWM */ 76 + #define ORANGEPI_SENSOR_FAN_REG 0x78 /* Fan reading is 2 registers long */ 77 + #define ORANGEPI_SENSOR_PWM_ENABLE_REG 0x40 /* PWM enable is 1 register long */ 78 + #define ORANGEPI_SENSOR_PWM_REG 0x38 /* PWM reading is 1 register long */ 79 + 80 + /* Turbo button takeover function 81 + * Different boards have different values and EC registers 82 + * for the same function 83 + */ 84 + #define OXP_TURBO_SWITCH_REG 0xF1 /* Mini Pro, OneXFly, AOKZOE */ 85 + #define OXP_2_TURBO_SWITCH_REG 0xEB /* OXP2 and X1 */ 86 + #define OXP_MINI_TURBO_SWITCH_REG 0x1E /* Mini AO7 */ 87 + 88 + #define OXP_MINI_TURBO_TAKE_VAL 0x01 /* Mini AO7 */ 89 + #define OXP_TURBO_TAKE_VAL 0x40 /* All other models */ 90 + 91 + /* X1 Turbo LED */ 92 + #define OXP_X1_TURBO_LED_REG 0x57 93 + 94 + #define OXP_X1_TURBO_LED_OFF 0x01 95 + #define OXP_X1_TURBO_LED_ON 0x02 96 + 97 + /* Battery extension settings */ 98 + #define EC_CHARGE_CONTROL_BEHAVIOURS (BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) | \ 99 + BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE) | \ 100 + BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE)) 101 + 102 + #define OXP_X1_CHARGE_LIMIT_REG 0xA3 /* X1 charge limit (%) */ 103 + #define OXP_X1_CHARGE_INHIBIT_REG 0xA4 /* X1 bypass charging */ 104 + 105 + #define OXP_X1_CHARGE_INHIBIT_MASK_AWAKE 0x01 106 + /* X1 Mask is 0x0A, F1Pro is 0x02 but the extra bit on the X1 does nothing. */ 107 + #define OXP_X1_CHARGE_INHIBIT_MASK_OFF 0x02 108 + #define OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS (OXP_X1_CHARGE_INHIBIT_MASK_AWAKE | \ 109 + OXP_X1_CHARGE_INHIBIT_MASK_OFF) 110 + 111 + static const struct dmi_system_id dmi_table[] = { 112 + { 113 + .matches = { 114 + DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"), 115 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 AR07"), 116 + }, 117 + .driver_data = (void *)aok_zoe_a1, 118 + }, 119 + { 120 + .matches = { 121 + DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"), 122 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 Pro"), 123 + }, 124 + .driver_data = (void *)aok_zoe_a1, 125 + }, 126 + { 127 + .matches = { 128 + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 129 + DMI_MATCH(DMI_BOARD_NAME, "AYANEO 2"), 130 + }, 131 + .driver_data = (void *)aya_neo_2, 132 + }, 133 + { 134 + .matches = { 135 + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 136 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"), 137 + }, 138 + .driver_data = (void *)aya_neo_air, 139 + }, 140 + { 141 + .matches = { 142 + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 143 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR 1S"), 144 + }, 145 + .driver_data = (void *)aya_neo_air_1s, 146 + }, 147 + { 148 + .matches = { 149 + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 150 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AB05-Mendocino"), 151 + }, 152 + .driver_data = (void *)aya_neo_air_plus_mendo, 153 + }, 154 + { 155 + .matches = { 156 + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 157 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"), 158 + }, 159 + .driver_data = (void *)aya_neo_air_pro, 160 + }, 161 + { 162 + .matches = { 163 + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 164 + DMI_MATCH(DMI_BOARD_NAME, "FLIP"), 165 + }, 166 + .driver_data = (void *)aya_neo_flip, 167 + }, 168 + { 169 + .matches = { 170 + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 171 + DMI_MATCH(DMI_BOARD_NAME, "GEEK"), 172 + }, 173 + .driver_data = (void *)aya_neo_geek, 174 + }, 175 + { 176 + .matches = { 177 + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 178 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "KUN"), 179 + }, 180 + .driver_data = (void *)aya_neo_kun, 181 + }, 182 + { 183 + .matches = { 184 + DMI_MATCH(DMI_BOARD_VENDOR, "OrangePi"), 185 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "NEO-01"), 186 + }, 187 + .driver_data = (void *)orange_pi_neo, 188 + }, 189 + { 190 + .matches = { 191 + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 192 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONE XPLAYER"), 193 + }, 194 + .driver_data = (void *)oxp_mini_amd, 195 + }, 196 + { 197 + .matches = { 198 + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 199 + DMI_MATCH(DMI_BOARD_NAME, "ONEXPLAYER 2"), 200 + }, 201 + .driver_data = (void *)oxp_2, 202 + }, 203 + { 204 + .matches = { 205 + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 206 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1"), 207 + }, 208 + .driver_data = (void *)oxp_fly, 209 + }, 210 + { 211 + .matches = { 212 + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 213 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1 EVA-01"), 214 + }, 215 + .driver_data = (void *)oxp_fly, 216 + }, 217 + { 218 + .matches = { 219 + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 220 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1 OLED"), 221 + }, 222 + .driver_data = (void *)oxp_fly, 223 + }, 224 + { 225 + .matches = { 226 + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 227 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1L"), 228 + }, 229 + .driver_data = (void *)oxp_fly, 230 + }, 231 + { 232 + .matches = { 233 + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 234 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1Pro"), 235 + }, 236 + .driver_data = (void *)oxp_fly, 237 + }, 238 + { 239 + .matches = { 240 + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 241 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1 EVA-02"), 242 + }, 243 + .driver_data = (void *)oxp_fly, 244 + }, 245 + { 246 + .matches = { 247 + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 248 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER G1 A"), 249 + }, 250 + .driver_data = (void *)oxp_g1, 251 + }, 252 + { 253 + .matches = { 254 + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 255 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER G1 i"), 256 + }, 257 + .driver_data = (void *)oxp_g1, 258 + }, 259 + { 260 + .matches = { 261 + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 262 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER mini A07"), 263 + }, 264 + .driver_data = (void *)oxp_mini_amd_a07, 265 + }, 266 + { 267 + .matches = { 268 + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 269 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER Mini Pro"), 270 + }, 271 + .driver_data = (void *)oxp_mini_amd_pro, 272 + }, 273 + { 274 + .matches = { 275 + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 276 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1 A"), 277 + }, 278 + .driver_data = (void *)oxp_x1, 279 + }, 280 + { 281 + .matches = { 282 + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 283 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1 i"), 284 + }, 285 + .driver_data = (void *)oxp_x1, 286 + }, 287 + { 288 + .matches = { 289 + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 290 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1 mini"), 291 + }, 292 + .driver_data = (void *)oxp_x1, 293 + }, 294 + { 295 + .matches = { 296 + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 297 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1Pro"), 298 + }, 299 + .driver_data = (void *)oxp_x1, 300 + }, 301 + {}, 302 + }; 303 + 304 + /* Helper functions to handle EC read/write */ 305 + static int read_from_ec(u8 reg, int size, long *val) 306 + { 307 + u8 buffer; 308 + int ret; 309 + int i; 310 + 311 + if (!lock_global_acpi_lock()) 312 + return -EBUSY; 313 + 314 + *val = 0; 315 + for (i = 0; i < size; i++) { 316 + ret = ec_read(reg + i, &buffer); 317 + if (ret) 318 + return ret; 319 + *val <<= i * 8; 320 + *val += buffer; 321 + } 322 + 323 + if (!unlock_global_acpi_lock()) 324 + return -EBUSY; 325 + 326 + return 0; 327 + } 328 + 329 + static int write_to_ec(u8 reg, u8 value) 330 + { 331 + int ret; 332 + 333 + if (!lock_global_acpi_lock()) 334 + return -EBUSY; 335 + 336 + ret = ec_write(reg, value); 337 + 338 + if (!unlock_global_acpi_lock()) 339 + return -EBUSY; 340 + 341 + return ret; 342 + } 343 + 344 + /* Callbacks for turbo toggle attribute */ 345 + static umode_t tt_toggle_is_visible(struct kobject *kobj, 346 + struct attribute *attr, int n) 347 + { 348 + switch (board) { 349 + case aok_zoe_a1: 350 + case oxp_2: 351 + case oxp_fly: 352 + case oxp_mini_amd_a07: 353 + case oxp_mini_amd_pro: 354 + case oxp_x1: 355 + case oxp_g1: 356 + return attr->mode; 357 + default: 358 + break; 359 + } 360 + return 0; 361 + } 362 + 363 + static ssize_t tt_toggle_store(struct device *dev, 364 + struct device_attribute *attr, const char *buf, 365 + size_t count) 366 + { 367 + u8 reg, mask, val; 368 + long raw_val; 369 + bool enable; 370 + int ret; 371 + 372 + ret = kstrtobool(buf, &enable); 373 + if (ret) 374 + return ret; 375 + 376 + switch (board) { 377 + case oxp_mini_amd_a07: 378 + reg = OXP_MINI_TURBO_SWITCH_REG; 379 + mask = OXP_MINI_TURBO_TAKE_VAL; 380 + break; 381 + case aok_zoe_a1: 382 + case oxp_fly: 383 + case oxp_mini_amd_pro: 384 + reg = OXP_TURBO_SWITCH_REG; 385 + mask = OXP_TURBO_TAKE_VAL; 386 + break; 387 + case oxp_2: 388 + case oxp_x1: 389 + case oxp_g1: 390 + reg = OXP_2_TURBO_SWITCH_REG; 391 + mask = OXP_TURBO_TAKE_VAL; 392 + break; 393 + default: 394 + return -EINVAL; 395 + } 396 + 397 + ret = read_from_ec(reg, 1, &raw_val); 398 + if (ret) 399 + return ret; 400 + 401 + val = raw_val; 402 + if (enable) 403 + val |= mask; 404 + else 405 + val &= ~mask; 406 + 407 + ret = write_to_ec(reg, val); 408 + if (ret) 409 + return ret; 410 + 411 + return count; 412 + } 413 + 414 + static ssize_t tt_toggle_show(struct device *dev, 415 + struct device_attribute *attr, char *buf) 416 + { 417 + u8 reg, mask; 418 + int retval; 419 + long val; 420 + 421 + switch (board) { 422 + case oxp_mini_amd_a07: 423 + reg = OXP_MINI_TURBO_SWITCH_REG; 424 + mask = OXP_MINI_TURBO_TAKE_VAL; 425 + break; 426 + case aok_zoe_a1: 427 + case oxp_fly: 428 + case oxp_mini_amd_pro: 429 + reg = OXP_TURBO_SWITCH_REG; 430 + mask = OXP_TURBO_TAKE_VAL; 431 + break; 432 + case oxp_2: 433 + case oxp_x1: 434 + case oxp_g1: 435 + reg = OXP_2_TURBO_SWITCH_REG; 436 + mask = OXP_TURBO_TAKE_VAL; 437 + break; 438 + default: 439 + return -EINVAL; 440 + } 441 + 442 + retval = read_from_ec(reg, 1, &val); 443 + if (retval) 444 + return retval; 445 + 446 + return sysfs_emit(buf, "%d\n", (val & mask) == mask); 447 + } 448 + 449 + static DEVICE_ATTR_RW(tt_toggle); 450 + 451 + /* Callbacks for turbo LED attribute */ 452 + static umode_t tt_led_is_visible(struct kobject *kobj, 453 + struct attribute *attr, int n) 454 + { 455 + switch (board) { 456 + case oxp_x1: 457 + return attr->mode; 458 + default: 459 + break; 460 + } 461 + return 0; 462 + } 463 + 464 + static ssize_t tt_led_store(struct device *dev, 465 + struct device_attribute *attr, const char *buf, 466 + size_t count) 467 + { 468 + u8 reg, val; 469 + bool value; 470 + int ret; 471 + 472 + ret = kstrtobool(buf, &value); 473 + if (ret) 474 + return ret; 475 + 476 + switch (board) { 477 + case oxp_x1: 478 + reg = OXP_X1_TURBO_LED_REG; 479 + val = value ? OXP_X1_TURBO_LED_ON : OXP_X1_TURBO_LED_OFF; 480 + break; 481 + default: 482 + return -EINVAL; 483 + } 484 + 485 + ret = write_to_ec(reg, val); 486 + if (ret) 487 + return ret; 488 + 489 + return count; 490 + } 491 + 492 + static ssize_t tt_led_show(struct device *dev, 493 + struct device_attribute *attr, char *buf) 494 + { 495 + long enval; 496 + long val; 497 + int ret; 498 + u8 reg; 499 + 500 + switch (board) { 501 + case oxp_x1: 502 + reg = OXP_X1_TURBO_LED_REG; 503 + enval = OXP_X1_TURBO_LED_ON; 504 + break; 505 + default: 506 + return -EINVAL; 507 + } 508 + 509 + ret = read_from_ec(reg, 1, &val); 510 + if (ret) 511 + return ret; 512 + 513 + return sysfs_emit(buf, "%d\n", val == enval); 514 + } 515 + 516 + static DEVICE_ATTR_RW(tt_led); 517 + 518 + /* Callbacks for charge behaviour attributes */ 519 + static bool oxp_psy_ext_supported(void) 520 + { 521 + switch (board) { 522 + case oxp_x1: 523 + case oxp_g1: 524 + case oxp_fly: 525 + return true; 526 + default: 527 + break; 528 + } 529 + return false; 530 + } 531 + 532 + static int oxp_psy_ext_get_prop(struct power_supply *psy, 533 + const struct power_supply_ext *ext, 534 + void *data, 535 + enum power_supply_property psp, 536 + union power_supply_propval *val) 537 + { 538 + long raw_val; 539 + int ret; 540 + 541 + switch (psp) { 542 + case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: 543 + ret = read_from_ec(OXP_X1_CHARGE_LIMIT_REG, 1, &raw_val); 544 + if (ret) 545 + return ret; 546 + if (raw_val < 0 || raw_val > 100) 547 + return -EINVAL; 548 + val->intval = raw_val; 549 + return 0; 550 + case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: 551 + ret = read_from_ec(OXP_X1_CHARGE_INHIBIT_REG, 1, &raw_val); 552 + if (ret) 553 + return ret; 554 + if ((raw_val & OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS) == 555 + OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS) 556 + val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE; 557 + else if ((raw_val & OXP_X1_CHARGE_INHIBIT_MASK_AWAKE) == 558 + OXP_X1_CHARGE_INHIBIT_MASK_AWAKE) 559 + val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE; 560 + else 561 + val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO; 562 + return 0; 563 + default: 564 + return -EINVAL; 565 + } 566 + } 567 + 568 + static int oxp_psy_ext_set_prop(struct power_supply *psy, 569 + const struct power_supply_ext *ext, 570 + void *data, 571 + enum power_supply_property psp, 572 + const union power_supply_propval *val) 573 + { 574 + long raw_val; 575 + 576 + switch (psp) { 577 + case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: 578 + if (val->intval < 0 || val->intval > 100) 579 + return -EINVAL; 580 + return write_to_ec(OXP_X1_CHARGE_LIMIT_REG, val->intval); 581 + case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: 582 + switch (val->intval) { 583 + case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO: 584 + raw_val = 0; 585 + break; 586 + case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE: 587 + raw_val = OXP_X1_CHARGE_INHIBIT_MASK_AWAKE; 588 + break; 589 + case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE: 590 + raw_val = OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS; 591 + break; 592 + default: 593 + return -EINVAL; 594 + } 595 + 596 + return write_to_ec(OXP_X1_CHARGE_INHIBIT_REG, raw_val); 597 + default: 598 + return -EINVAL; 599 + } 600 + } 601 + 602 + static int oxp_psy_prop_is_writeable(struct power_supply *psy, 603 + const struct power_supply_ext *ext, 604 + void *data, 605 + enum power_supply_property psp) 606 + { 607 + return true; 608 + } 609 + 610 + static const enum power_supply_property oxp_psy_ext_props[] = { 611 + POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR, 612 + POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD, 613 + }; 614 + 615 + static const struct power_supply_ext oxp_psy_ext = { 616 + .name = "oxp-charge-control", 617 + .properties = oxp_psy_ext_props, 618 + .num_properties = ARRAY_SIZE(oxp_psy_ext_props), 619 + .charge_behaviours = EC_CHARGE_CONTROL_BEHAVIOURS, 620 + .get_property = oxp_psy_ext_get_prop, 621 + .set_property = oxp_psy_ext_set_prop, 622 + .property_is_writeable = oxp_psy_prop_is_writeable, 623 + }; 624 + 625 + static int oxp_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook) 626 + { 627 + return power_supply_register_extension(battery, &oxp_psy_ext, oxp_dev, NULL); 628 + } 629 + 630 + static int oxp_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook) 631 + { 632 + power_supply_unregister_extension(battery, &oxp_psy_ext); 633 + return 0; 634 + } 635 + 636 + static struct acpi_battery_hook battery_hook = { 637 + .add_battery = oxp_add_battery, 638 + .remove_battery = oxp_remove_battery, 639 + .name = "OneXPlayer Battery", 640 + }; 641 + 642 + /* PWM enable/disable functions */ 643 + static int oxp_pwm_enable(void) 644 + { 645 + switch (board) { 646 + case orange_pi_neo: 647 + return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL); 648 + case aok_zoe_a1: 649 + case aya_neo_2: 650 + case aya_neo_air: 651 + case aya_neo_air_plus_mendo: 652 + case aya_neo_air_pro: 653 + case aya_neo_flip: 654 + case aya_neo_geek: 655 + case aya_neo_kun: 656 + case oxp_2: 657 + case oxp_fly: 658 + case oxp_mini_amd: 659 + case oxp_mini_amd_a07: 660 + case oxp_mini_amd_pro: 661 + case oxp_x1: 662 + case oxp_g1: 663 + return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL); 664 + default: 665 + return -EINVAL; 666 + } 667 + } 668 + 669 + static int oxp_pwm_disable(void) 670 + { 671 + switch (board) { 672 + case orange_pi_neo: 673 + return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO); 674 + case aok_zoe_a1: 675 + case aya_neo_2: 676 + case aya_neo_air: 677 + case aya_neo_air_1s: 678 + case aya_neo_air_plus_mendo: 679 + case aya_neo_air_pro: 680 + case aya_neo_flip: 681 + case aya_neo_geek: 682 + case aya_neo_kun: 683 + case oxp_2: 684 + case oxp_fly: 685 + case oxp_mini_amd: 686 + case oxp_mini_amd_a07: 687 + case oxp_mini_amd_pro: 688 + case oxp_x1: 689 + case oxp_g1: 690 + return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO); 691 + default: 692 + return -EINVAL; 693 + } 694 + } 695 + 696 + static int oxp_pwm_read(long *val) 697 + { 698 + switch (board) { 699 + case orange_pi_neo: 700 + return read_from_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, 1, val); 701 + case aok_zoe_a1: 702 + case aya_neo_2: 703 + case aya_neo_air: 704 + case aya_neo_air_1s: 705 + case aya_neo_air_plus_mendo: 706 + case aya_neo_air_pro: 707 + case aya_neo_flip: 708 + case aya_neo_geek: 709 + case aya_neo_kun: 710 + case oxp_2: 711 + case oxp_fly: 712 + case oxp_mini_amd: 713 + case oxp_mini_amd_a07: 714 + case oxp_mini_amd_pro: 715 + case oxp_x1: 716 + case oxp_g1: 717 + return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val); 718 + default: 719 + return -EOPNOTSUPP; 720 + } 721 + } 722 + 723 + /* Callbacks for hwmon interface */ 724 + static umode_t oxp_ec_hwmon_is_visible(const void *drvdata, 725 + enum hwmon_sensor_types type, u32 attr, int channel) 726 + { 727 + switch (type) { 728 + case hwmon_fan: 729 + return 0444; 730 + case hwmon_pwm: 731 + return 0644; 732 + default: 733 + return 0; 734 + } 735 + } 736 + 737 + /* Fan speed read function */ 738 + static int oxp_pwm_fan_speed(long *val) 739 + { 740 + switch (board) { 741 + case orange_pi_neo: 742 + return read_from_ec(ORANGEPI_SENSOR_FAN_REG, 2, val); 743 + case oxp_2: 744 + case oxp_x1: 745 + case oxp_g1: 746 + return read_from_ec(OXP_2_SENSOR_FAN_REG, 2, val); 747 + case aok_zoe_a1: 748 + case aya_neo_2: 749 + case aya_neo_air: 750 + case aya_neo_air_1s: 751 + case aya_neo_air_plus_mendo: 752 + case aya_neo_air_pro: 753 + case aya_neo_flip: 754 + case aya_neo_geek: 755 + case aya_neo_kun: 756 + case oxp_fly: 757 + case oxp_mini_amd: 758 + case oxp_mini_amd_a07: 759 + case oxp_mini_amd_pro: 760 + return read_from_ec(OXP_SENSOR_FAN_REG, 2, val); 761 + default: 762 + return -EOPNOTSUPP; 763 + } 764 + } 765 + 766 + /* PWM input read/write functions */ 767 + static int oxp_pwm_input_write(long val) 768 + { 769 + if (val < 0 || val > 255) 770 + return -EINVAL; 771 + 772 + switch (board) { 773 + case orange_pi_neo: 774 + /* scale to range [1-244] */ 775 + val = ((val - 1) * 243 / 254) + 1; 776 + return write_to_ec(ORANGEPI_SENSOR_PWM_REG, val); 777 + case oxp_2: 778 + case oxp_x1: 779 + case oxp_g1: 780 + /* scale to range [0-184] */ 781 + val = (val * 184) / 255; 782 + return write_to_ec(OXP_SENSOR_PWM_REG, val); 783 + case aya_neo_2: 784 + case aya_neo_air: 785 + case aya_neo_air_1s: 786 + case aya_neo_air_plus_mendo: 787 + case aya_neo_air_pro: 788 + case aya_neo_flip: 789 + case aya_neo_geek: 790 + case aya_neo_kun: 791 + case oxp_mini_amd: 792 + case oxp_mini_amd_a07: 793 + /* scale to range [0-100] */ 794 + val = (val * 100) / 255; 795 + return write_to_ec(OXP_SENSOR_PWM_REG, val); 796 + case aok_zoe_a1: 797 + case oxp_fly: 798 + case oxp_mini_amd_pro: 799 + return write_to_ec(OXP_SENSOR_PWM_REG, val); 800 + default: 801 + return -EOPNOTSUPP; 802 + } 803 + } 804 + 805 + static int oxp_pwm_input_read(long *val) 806 + { 807 + int ret; 808 + 809 + switch (board) { 810 + case orange_pi_neo: 811 + ret = read_from_ec(ORANGEPI_SENSOR_PWM_REG, 1, val); 812 + if (ret) 813 + return ret; 814 + /* scale from range [1-244] */ 815 + *val = ((*val - 1) * 254 / 243) + 1; 816 + break; 817 + case oxp_2: 818 + case oxp_x1: 819 + case oxp_g1: 820 + ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val); 821 + if (ret) 822 + return ret; 823 + /* scale from range [0-184] */ 824 + *val = (*val * 255) / 184; 825 + break; 826 + case aya_neo_2: 827 + case aya_neo_air: 828 + case aya_neo_air_1s: 829 + case aya_neo_air_plus_mendo: 830 + case aya_neo_air_pro: 831 + case aya_neo_flip: 832 + case aya_neo_geek: 833 + case aya_neo_kun: 834 + case oxp_mini_amd: 835 + case oxp_mini_amd_a07: 836 + ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val); 837 + if (ret) 838 + return ret; 839 + /* scale from range [0-100] */ 840 + *val = (*val * 255) / 100; 841 + break; 842 + case aok_zoe_a1: 843 + case oxp_fly: 844 + case oxp_mini_amd_pro: 845 + default: 846 + ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val); 847 + if (ret) 848 + return ret; 849 + break; 850 + } 851 + return 0; 852 + } 853 + 854 + static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type, 855 + u32 attr, int channel, long *val) 856 + { 857 + int ret; 858 + 859 + switch (type) { 860 + case hwmon_fan: 861 + switch (attr) { 862 + case hwmon_fan_input: 863 + return oxp_pwm_fan_speed(val); 864 + default: 865 + break; 866 + } 867 + break; 868 + case hwmon_pwm: 869 + switch (attr) { 870 + case hwmon_pwm_input: 871 + return oxp_pwm_input_read(val); 872 + case hwmon_pwm_enable: 873 + ret = oxp_pwm_read(val); 874 + if (ret) 875 + return ret; 876 + 877 + /* Check for auto and return 2 */ 878 + if (!*val) { 879 + *val = 2; 880 + return 0; 881 + } 882 + 883 + /* Return 0 if at full fan speed, 1 otherwise */ 884 + ret = oxp_pwm_fan_speed(val); 885 + if (ret) 886 + return ret; 887 + 888 + if (*val == 255) 889 + *val = 0; 890 + else 891 + *val = 1; 892 + 893 + return 0; 894 + default: 895 + break; 896 + } 897 + break; 898 + default: 899 + break; 900 + } 901 + return -EOPNOTSUPP; 902 + } 903 + 904 + static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type, 905 + u32 attr, int channel, long val) 906 + { 907 + int ret; 908 + 909 + switch (type) { 910 + case hwmon_pwm: 911 + switch (attr) { 912 + case hwmon_pwm_enable: 913 + if (val == 1) 914 + return oxp_pwm_enable(); 915 + else if (val == 2) 916 + return oxp_pwm_disable(); 917 + else if (val != 0) 918 + return -EINVAL; 919 + 920 + /* Enable PWM and set to max speed */ 921 + ret = oxp_pwm_enable(); 922 + if (ret) 923 + return ret; 924 + return oxp_pwm_input_write(255); 925 + case hwmon_pwm_input: 926 + return oxp_pwm_input_write(val); 927 + default: 928 + break; 929 + } 930 + break; 931 + default: 932 + break; 933 + } 934 + return -EOPNOTSUPP; 935 + } 936 + 937 + /* Known sensors in the OXP EC controllers */ 938 + static const struct hwmon_channel_info * const oxp_platform_sensors[] = { 939 + HWMON_CHANNEL_INFO(fan, 940 + HWMON_F_INPUT), 941 + HWMON_CHANNEL_INFO(pwm, 942 + HWMON_PWM_INPUT | HWMON_PWM_ENABLE), 943 + NULL, 944 + }; 945 + 946 + static struct attribute *oxp_tt_toggle_attrs[] = { 947 + &dev_attr_tt_toggle.attr, 948 + NULL 949 + }; 950 + 951 + static const struct attribute_group oxp_tt_toggle_attribute_group = { 952 + .is_visible = tt_toggle_is_visible, 953 + .attrs = oxp_tt_toggle_attrs, 954 + }; 955 + 956 + static struct attribute *oxp_tt_led_attrs[] = { 957 + &dev_attr_tt_led.attr, 958 + NULL 959 + }; 960 + 961 + static const struct attribute_group oxp_tt_led_attribute_group = { 962 + .is_visible = tt_led_is_visible, 963 + .attrs = oxp_tt_led_attrs, 964 + }; 965 + 966 + static const struct attribute_group *oxp_ec_groups[] = { 967 + &oxp_tt_toggle_attribute_group, 968 + &oxp_tt_led_attribute_group, 969 + NULL 970 + }; 971 + 972 + static const struct hwmon_ops oxp_ec_hwmon_ops = { 973 + .is_visible = oxp_ec_hwmon_is_visible, 974 + .read = oxp_platform_read, 975 + .write = oxp_platform_write, 976 + }; 977 + 978 + static const struct hwmon_chip_info oxp_ec_chip_info = { 979 + .ops = &oxp_ec_hwmon_ops, 980 + .info = oxp_platform_sensors, 981 + }; 982 + 983 + /* Initialization logic */ 984 + static int oxp_platform_probe(struct platform_device *pdev) 985 + { 986 + struct device *dev = &pdev->dev; 987 + struct device *hwdev; 988 + int ret; 989 + 990 + oxp_dev = dev; 991 + hwdev = devm_hwmon_device_register_with_info(dev, "oxp_ec", NULL, 992 + &oxp_ec_chip_info, NULL); 993 + 994 + if (IS_ERR(hwdev)) 995 + return PTR_ERR(hwdev); 996 + 997 + if (oxp_psy_ext_supported()) { 998 + ret = devm_battery_hook_register(dev, &battery_hook); 999 + if (ret) 1000 + return ret; 1001 + } 1002 + 1003 + return 0; 1004 + } 1005 + 1006 + static struct platform_driver oxp_platform_driver = { 1007 + .driver = { 1008 + .name = "oxp-platform", 1009 + .dev_groups = oxp_ec_groups, 1010 + }, 1011 + .probe = oxp_platform_probe, 1012 + }; 1013 + 1014 + static struct platform_device *oxp_platform_device; 1015 + 1016 + static int __init oxp_platform_init(void) 1017 + { 1018 + const struct dmi_system_id *dmi_entry; 1019 + 1020 + dmi_entry = dmi_first_match(dmi_table); 1021 + if (!dmi_entry) 1022 + return -ENODEV; 1023 + 1024 + board = (enum oxp_board)(unsigned long)dmi_entry->driver_data; 1025 + 1026 + /* 1027 + * Have to check for AMD processor here because DMI strings are the same 1028 + * between Intel and AMD boards on older OneXPlayer devices, the only way 1029 + * to tell them apart is the CPU. Old Intel boards have an unsupported EC. 1030 + */ 1031 + if (board == oxp_mini_amd && boot_cpu_data.x86_vendor != X86_VENDOR_AMD) 1032 + return -ENODEV; 1033 + 1034 + oxp_platform_device = 1035 + platform_create_bundle(&oxp_platform_driver, 1036 + oxp_platform_probe, NULL, 0, NULL, 0); 1037 + 1038 + return PTR_ERR_OR_ZERO(oxp_platform_device); 1039 + } 1040 + 1041 + static void __exit oxp_platform_exit(void) 1042 + { 1043 + platform_device_unregister(oxp_platform_device); 1044 + platform_driver_unregister(&oxp_platform_driver); 1045 + } 1046 + 1047 + MODULE_DEVICE_TABLE(dmi, dmi_table); 1048 + 1049 + module_init(oxp_platform_init); 1050 + module_exit(oxp_platform_exit); 1051 + 1052 + MODULE_AUTHOR("Joaquín Ignacio Aramendía <samsagax@gmail.com>"); 1053 + MODULE_DESCRIPTION("Platform driver that handles EC sensors of OneXPlayer devices"); 1054 + MODULE_LICENSE("GPL");
+2 -2
drivers/platform/x86/panasonic-laptop.c
··· 1033 1033 pcc->handle = device->handle; 1034 1034 pcc->num_sifr = num_sifr; 1035 1035 device->driver_data = pcc; 1036 - strcpy(acpi_device_name(device), ACPI_PCC_DEVICE_NAME); 1037 - strcpy(acpi_device_class(device), ACPI_PCC_CLASS); 1036 + strscpy(acpi_device_name(device), ACPI_PCC_DEVICE_NAME); 1037 + strscpy(acpi_device_class(device), ACPI_PCC_CLASS); 1038 1038 1039 1039 result = acpi_pcc_init_input(pcc); 1040 1040 if (result) {
+291
drivers/platform/x86/portwell-ec.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * portwell-ec.c: Portwell embedded controller driver. 4 + * 5 + * Tested on: 6 + * - Portwell NANO-6064 7 + * 8 + * This driver provides support for GPIO and Watchdog Timer 9 + * functionalities of the Portwell boards with ITE embedded controller (EC). 10 + * The EC is accessed through I/O ports and provides: 11 + * - 8 GPIO pins for control and monitoring 12 + * - Hardware watchdog with 1-15300 second timeout range 13 + * 14 + * It integrates with the Linux GPIO and Watchdog subsystems, allowing 15 + * userspace interaction with EC GPIO pins and watchdog control, 16 + * ensuring system stability and configurability. 17 + * 18 + * (C) Copyright 2025 Portwell, Inc. 19 + * Author: Yen-Chi Huang (jesse.huang@portwell.com.tw) 20 + */ 21 + 22 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 23 + 24 + #include <linux/acpi.h> 25 + #include <linux/bitfield.h> 26 + #include <linux/dmi.h> 27 + #include <linux/gpio/driver.h> 28 + #include <linux/init.h> 29 + #include <linux/io.h> 30 + #include <linux/ioport.h> 31 + #include <linux/module.h> 32 + #include <linux/platform_device.h> 33 + #include <linux/sizes.h> 34 + #include <linux/string.h> 35 + #include <linux/watchdog.h> 36 + 37 + #define PORTWELL_EC_IOSPACE 0xe300 38 + #define PORTWELL_EC_IOSPACE_LEN SZ_256 39 + 40 + #define PORTWELL_GPIO_PINS 8 41 + #define PORTWELL_GPIO_DIR_REG 0x2b 42 + #define PORTWELL_GPIO_VAL_REG 0x2c 43 + 44 + #define PORTWELL_WDT_EC_CONFIG_ADDR 0x06 45 + #define PORTWELL_WDT_CONFIG_ENABLE 0x1 46 + #define PORTWELL_WDT_CONFIG_DISABLE 0x0 47 + #define PORTWELL_WDT_EC_COUNT_MIN_ADDR 0x07 48 + #define PORTWELL_WDT_EC_COUNT_SEC_ADDR 0x08 49 + #define PORTWELL_WDT_EC_MAX_COUNT_SECOND (255 * 60) 50 + 51 + #define PORTWELL_EC_FW_VENDOR_ADDRESS 0x4d 52 + #define PORTWELL_EC_FW_VENDOR_LENGTH 3 53 + #define PORTWELL_EC_FW_VENDOR_NAME "PWG" 54 + 55 + static bool force; 56 + module_param(force, bool, 0444); 57 + MODULE_PARM_DESC(force, "Force loading EC driver without checking DMI boardname"); 58 + 59 + static const struct dmi_system_id pwec_dmi_table[] = { 60 + { 61 + .ident = "NANO-6064 series", 62 + .matches = { 63 + DMI_MATCH(DMI_BOARD_NAME, "NANO-6064"), 64 + }, 65 + }, 66 + { } 67 + }; 68 + MODULE_DEVICE_TABLE(dmi, pwec_dmi_table); 69 + 70 + /* Functions for access EC via IOSPACE */ 71 + 72 + static void pwec_write(u8 index, u8 data) 73 + { 74 + outb(data, PORTWELL_EC_IOSPACE + index); 75 + } 76 + 77 + static u8 pwec_read(u8 address) 78 + { 79 + return inb(PORTWELL_EC_IOSPACE + address); 80 + } 81 + 82 + /* GPIO functions */ 83 + 84 + static int pwec_gpio_get(struct gpio_chip *chip, unsigned int offset) 85 + { 86 + return pwec_read(PORTWELL_GPIO_VAL_REG) & BIT(offset) ? 1 : 0; 87 + } 88 + 89 + static int pwec_gpio_set_rv(struct gpio_chip *chip, unsigned int offset, int val) 90 + { 91 + u8 tmp = pwec_read(PORTWELL_GPIO_VAL_REG); 92 + 93 + if (val) 94 + tmp |= BIT(offset); 95 + else 96 + tmp &= ~BIT(offset); 97 + pwec_write(PORTWELL_GPIO_VAL_REG, tmp); 98 + 99 + return 0; 100 + } 101 + 102 + static int pwec_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) 103 + { 104 + u8 direction = pwec_read(PORTWELL_GPIO_DIR_REG) & BIT(offset); 105 + 106 + if (direction) 107 + return GPIO_LINE_DIRECTION_IN; 108 + 109 + return GPIO_LINE_DIRECTION_OUT; 110 + } 111 + 112 + /* 113 + * Changing direction causes issues on some boards, 114 + * so direction_input and direction_output are disabled for now. 115 + */ 116 + 117 + static int pwec_gpio_direction_input(struct gpio_chip *gc, unsigned int offset) 118 + { 119 + return -EOPNOTSUPP; 120 + } 121 + 122 + static int pwec_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, int value) 123 + { 124 + return -EOPNOTSUPP; 125 + } 126 + 127 + static struct gpio_chip pwec_gpio_chip = { 128 + .label = "portwell-ec-gpio", 129 + .get_direction = pwec_gpio_get_direction, 130 + .direction_input = pwec_gpio_direction_input, 131 + .direction_output = pwec_gpio_direction_output, 132 + .get = pwec_gpio_get, 133 + .set_rv = pwec_gpio_set_rv, 134 + .base = -1, 135 + .ngpio = PORTWELL_GPIO_PINS, 136 + }; 137 + 138 + /* Watchdog functions */ 139 + 140 + static void pwec_wdt_write_timeout(unsigned int timeout) 141 + { 142 + pwec_write(PORTWELL_WDT_EC_COUNT_MIN_ADDR, timeout / 60); 143 + pwec_write(PORTWELL_WDT_EC_COUNT_SEC_ADDR, timeout % 60); 144 + } 145 + 146 + static int pwec_wdt_trigger(struct watchdog_device *wdd) 147 + { 148 + pwec_wdt_write_timeout(wdd->timeout); 149 + pwec_write(PORTWELL_WDT_EC_CONFIG_ADDR, PORTWELL_WDT_CONFIG_ENABLE); 150 + 151 + return 0; 152 + } 153 + 154 + static int pwec_wdt_start(struct watchdog_device *wdd) 155 + { 156 + return pwec_wdt_trigger(wdd); 157 + } 158 + 159 + static int pwec_wdt_stop(struct watchdog_device *wdd) 160 + { 161 + pwec_write(PORTWELL_WDT_EC_CONFIG_ADDR, PORTWELL_WDT_CONFIG_DISABLE); 162 + return 0; 163 + } 164 + 165 + static int pwec_wdt_set_timeout(struct watchdog_device *wdd, unsigned int timeout) 166 + { 167 + wdd->timeout = timeout; 168 + pwec_wdt_write_timeout(wdd->timeout); 169 + 170 + return 0; 171 + } 172 + 173 + /* Ensure consistent min/sec read in case of second rollover. */ 174 + static unsigned int pwec_wdt_get_timeleft(struct watchdog_device *wdd) 175 + { 176 + u8 sec, min, old_min; 177 + 178 + do { 179 + old_min = pwec_read(PORTWELL_WDT_EC_COUNT_MIN_ADDR); 180 + sec = pwec_read(PORTWELL_WDT_EC_COUNT_SEC_ADDR); 181 + min = pwec_read(PORTWELL_WDT_EC_COUNT_MIN_ADDR); 182 + } while (min != old_min); 183 + 184 + return min * 60 + sec; 185 + } 186 + 187 + static const struct watchdog_ops pwec_wdt_ops = { 188 + .owner = THIS_MODULE, 189 + .start = pwec_wdt_start, 190 + .stop = pwec_wdt_stop, 191 + .ping = pwec_wdt_trigger, 192 + .set_timeout = pwec_wdt_set_timeout, 193 + .get_timeleft = pwec_wdt_get_timeleft, 194 + }; 195 + 196 + static struct watchdog_device ec_wdt_dev = { 197 + .info = &(struct watchdog_info){ 198 + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 199 + .identity = "Portwell EC watchdog", 200 + }, 201 + .ops = &pwec_wdt_ops, 202 + .timeout = 60, 203 + .min_timeout = 1, 204 + .max_timeout = PORTWELL_WDT_EC_MAX_COUNT_SECOND, 205 + }; 206 + 207 + static int pwec_firmware_vendor_check(void) 208 + { 209 + u8 buf[PORTWELL_EC_FW_VENDOR_LENGTH + 1]; 210 + u8 i; 211 + 212 + for (i = 0; i < PORTWELL_EC_FW_VENDOR_LENGTH; i++) 213 + buf[i] = pwec_read(PORTWELL_EC_FW_VENDOR_ADDRESS + i); 214 + buf[PORTWELL_EC_FW_VENDOR_LENGTH] = '\0'; 215 + 216 + return !strcmp(PORTWELL_EC_FW_VENDOR_NAME, buf) ? 0 : -ENODEV; 217 + } 218 + 219 + static int pwec_probe(struct platform_device *pdev) 220 + { 221 + int ret; 222 + 223 + if (!devm_request_region(&pdev->dev, PORTWELL_EC_IOSPACE, 224 + PORTWELL_EC_IOSPACE_LEN, dev_name(&pdev->dev))) { 225 + dev_err(&pdev->dev, "failed to get IO region\n"); 226 + return -EBUSY; 227 + } 228 + 229 + ret = pwec_firmware_vendor_check(); 230 + if (ret < 0) 231 + return ret; 232 + 233 + ret = devm_gpiochip_add_data(&pdev->dev, &pwec_gpio_chip, NULL); 234 + if (ret < 0) { 235 + dev_err(&pdev->dev, "failed to register Portwell EC GPIO\n"); 236 + return ret; 237 + } 238 + 239 + ret = devm_watchdog_register_device(&pdev->dev, &ec_wdt_dev); 240 + if (ret < 0) { 241 + dev_err(&pdev->dev, "failed to register Portwell EC Watchdog\n"); 242 + return ret; 243 + } 244 + 245 + return 0; 246 + } 247 + 248 + static struct platform_driver pwec_driver = { 249 + .driver = { 250 + .name = "portwell-ec", 251 + }, 252 + .probe = pwec_probe, 253 + }; 254 + 255 + static struct platform_device *pwec_dev; 256 + 257 + static int __init pwec_init(void) 258 + { 259 + int ret; 260 + 261 + if (!dmi_check_system(pwec_dmi_table)) { 262 + if (!force) 263 + return -ENODEV; 264 + pr_warn("force load portwell-ec without DMI check\n"); 265 + } 266 + 267 + ret = platform_driver_register(&pwec_driver); 268 + if (ret) 269 + return ret; 270 + 271 + pwec_dev = platform_device_register_simple("portwell-ec", -1, NULL, 0); 272 + if (IS_ERR(pwec_dev)) { 273 + platform_driver_unregister(&pwec_driver); 274 + return PTR_ERR(pwec_dev); 275 + } 276 + 277 + return 0; 278 + } 279 + 280 + static void __exit pwec_exit(void) 281 + { 282 + platform_device_unregister(pwec_dev); 283 + platform_driver_unregister(&pwec_driver); 284 + } 285 + 286 + module_init(pwec_init); 287 + module_exit(pwec_exit); 288 + 289 + MODULE_AUTHOR("Yen-Chi Huang <jesse.huang@portwell.com.tw>"); 290 + MODULE_DESCRIPTION("Portwell EC Driver"); 291 + MODULE_LICENSE("GPL");
+6 -5
drivers/platform/x86/silicom-platform.c
··· 245 245 return direction == GPIO_LINE_DIRECTION_IN ? 0 : -EINVAL; 246 246 } 247 247 248 - static void silicom_gpio_set(struct gpio_chip *gc, 249 - unsigned int offset, 250 - int value) 248 + static int silicom_gpio_set(struct gpio_chip *gc, unsigned int offset, 249 + int value) 251 250 { 252 251 int direction = silicom_gpio_get_direction(gc, offset); 253 252 u8 *channels = gpiochip_get_data(gc); 254 253 int channel = channels[offset]; 255 254 256 255 if (direction == GPIO_LINE_DIRECTION_IN) 257 - return; 256 + return -EPERM; 258 257 259 258 silicom_mec_port_set(channel, !value); 259 + 260 + return 0; 260 261 } 261 262 262 263 static int silicom_gpio_direction_output(struct gpio_chip *gc, ··· 470 469 .direction_input = silicom_gpio_direction_input, 471 470 .direction_output = silicom_gpio_direction_output, 472 471 .get = silicom_gpio_get, 473 - .set = silicom_gpio_set, 472 + .set_rv = silicom_gpio_set, 474 473 .base = -1, 475 474 .ngpio = ARRAY_SIZE(plat_0222_gpio_channels), 476 475 .names = plat_0222_gpio_names,
+5 -170
drivers/platform/x86/sony-laptop.c
··· 48 48 #include <linux/acpi.h> 49 49 #include <linux/slab.h> 50 50 #include <linux/sonypi.h> 51 - #include <linux/sony-laptop.h> 52 51 #include <linux/rfkill.h> 53 52 #ifdef CONFIG_SONYPI_COMPAT 54 53 #include <linux/poll.h> ··· 3156 3157 struct sony_nc_value *item; 3157 3158 3158 3159 sony_nc_acpi_device = device; 3159 - strcpy(acpi_device_class(device), "sony/hotkey"); 3160 + strscpy(acpi_device_class(device), "sony/hotkey"); 3160 3161 3161 3162 sony_nc_acpi_handle = device->handle; 3162 3163 ··· 3326 3327 }; 3327 3328 3328 3329 struct sony_pic_irq { 3329 - struct acpi_resource_irq irq; 3330 3330 struct list_head list; 3331 + 3332 + /* Must be last --ends in a flexible-array member. */ 3333 + struct acpi_resource_irq irq; 3331 3334 }; 3332 3335 3333 3336 struct sonypi_eventtypes { ··· 3620 3619 return v1; 3621 3620 } 3622 3621 3623 - static u8 sony_pic_call3(u8 dev, u8 fn, u8 v) 3624 - { 3625 - u8 v1; 3626 - 3627 - wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); 3628 - outb(dev, spic_dev.cur_ioport->io1.minimum + 4); 3629 - wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); 3630 - outb(fn, spic_dev.cur_ioport->io1.minimum); 3631 - wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); 3632 - outb(v, spic_dev.cur_ioport->io1.minimum); 3633 - v1 = inb_p(spic_dev.cur_ioport->io1.minimum); 3634 - dprintk("sony_pic_call3(0x%.2x - 0x%.2x - 0x%.2x): 0x%.4x\n", 3635 - dev, fn, v, v1); 3636 - return v1; 3637 - } 3638 - 3639 3622 /* 3640 3623 * minidrivers for SPIC models 3641 3624 */ ··· 3706 3721 dev->model == SONYPI_DEVICE_TYPE1 ? 1 : 3707 3722 dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3); 3708 3723 } 3709 - 3710 - /* camera tests and poweron/poweroff */ 3711 - #define SONYPI_CAMERA_PICTURE 5 3712 - #define SONYPI_CAMERA_CONTROL 0x10 3713 - 3714 - #define SONYPI_CAMERA_BRIGHTNESS 0 3715 - #define SONYPI_CAMERA_CONTRAST 1 3716 - #define SONYPI_CAMERA_HUE 2 3717 - #define SONYPI_CAMERA_COLOR 3 3718 - #define SONYPI_CAMERA_SHARPNESS 4 3719 - 3720 - #define SONYPI_CAMERA_EXPOSURE_MASK 0xC 3721 - #define SONYPI_CAMERA_WHITE_BALANCE_MASK 0x3 3722 - #define SONYPI_CAMERA_PICTURE_MODE_MASK 0x30 3723 - #define SONYPI_CAMERA_MUTE_MASK 0x40 3724 - 3725 - /* the rest don't need a loop until not 0xff */ 3726 - #define SONYPI_CAMERA_AGC 6 3727 - #define SONYPI_CAMERA_AGC_MASK 0x30 3728 - #define SONYPI_CAMERA_SHUTTER_MASK 0x7 3729 - 3730 - #define SONYPI_CAMERA_SHUTDOWN_REQUEST 7 3731 - #define SONYPI_CAMERA_CONTROL 0x10 3732 - 3733 - #define SONYPI_CAMERA_STATUS 7 3734 - #define SONYPI_CAMERA_STATUS_READY 0x2 3735 - #define SONYPI_CAMERA_STATUS_POSITION 0x4 3736 - 3737 - #define SONYPI_DIRECTION_BACKWARDS 0x4 3738 - 3739 - #define SONYPI_CAMERA_REVISION 8 3740 - #define SONYPI_CAMERA_ROMVERSION 9 3741 - 3742 - static int __sony_pic_camera_ready(void) 3743 - { 3744 - u8 v; 3745 - 3746 - v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS); 3747 - return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY)); 3748 - } 3749 - 3750 - static int __sony_pic_camera_off(void) 3751 - { 3752 - if (!camera) { 3753 - pr_warn("camera control not enabled\n"); 3754 - return -ENODEV; 3755 - } 3756 - 3757 - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, 3758 - SONYPI_CAMERA_MUTE_MASK), 3759 - ITERATIONS_SHORT); 3760 - 3761 - if (spic_dev.camera_power) { 3762 - sony_pic_call2(0x91, 0); 3763 - spic_dev.camera_power = 0; 3764 - } 3765 - return 0; 3766 - } 3767 - 3768 - static int __sony_pic_camera_on(void) 3769 - { 3770 - int i, j, x; 3771 - 3772 - if (!camera) { 3773 - pr_warn("camera control not enabled\n"); 3774 - return -ENODEV; 3775 - } 3776 - 3777 - if (spic_dev.camera_power) 3778 - return 0; 3779 - 3780 - for (j = 5; j > 0; j--) { 3781 - 3782 - for (x = 0; x < 100 && sony_pic_call2(0x91, 0x1); x++) 3783 - msleep(10); 3784 - sony_pic_call1(0x93); 3785 - 3786 - for (i = 400; i > 0; i--) { 3787 - if (__sony_pic_camera_ready()) 3788 - break; 3789 - msleep(10); 3790 - } 3791 - if (i) 3792 - break; 3793 - } 3794 - 3795 - if (j == 0) { 3796 - pr_warn("failed to power on camera\n"); 3797 - return -ENODEV; 3798 - } 3799 - 3800 - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL, 3801 - 0x5a), 3802 - ITERATIONS_SHORT); 3803 - 3804 - spic_dev.camera_power = 1; 3805 - return 0; 3806 - } 3807 - 3808 - /* External camera command (exported to the motion eye v4l driver) */ 3809 - int sony_pic_camera_command(int command, u8 value) 3810 - { 3811 - if (!camera) 3812 - return -EIO; 3813 - 3814 - mutex_lock(&spic_dev.lock); 3815 - 3816 - switch (command) { 3817 - case SONY_PIC_COMMAND_SETCAMERA: 3818 - if (value) 3819 - __sony_pic_camera_on(); 3820 - else 3821 - __sony_pic_camera_off(); 3822 - break; 3823 - case SONY_PIC_COMMAND_SETCAMERABRIGHTNESS: 3824 - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_BRIGHTNESS, value), 3825 - ITERATIONS_SHORT); 3826 - break; 3827 - case SONY_PIC_COMMAND_SETCAMERACONTRAST: 3828 - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTRAST, value), 3829 - ITERATIONS_SHORT); 3830 - break; 3831 - case SONY_PIC_COMMAND_SETCAMERAHUE: 3832 - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_HUE, value), 3833 - ITERATIONS_SHORT); 3834 - break; 3835 - case SONY_PIC_COMMAND_SETCAMERACOLOR: 3836 - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_COLOR, value), 3837 - ITERATIONS_SHORT); 3838 - break; 3839 - case SONY_PIC_COMMAND_SETCAMERASHARPNESS: 3840 - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_SHARPNESS, value), 3841 - ITERATIONS_SHORT); 3842 - break; 3843 - case SONY_PIC_COMMAND_SETCAMERAPICTURE: 3844 - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, value), 3845 - ITERATIONS_SHORT); 3846 - break; 3847 - case SONY_PIC_COMMAND_SETCAMERAAGC: 3848 - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_AGC, value), 3849 - ITERATIONS_SHORT); 3850 - break; 3851 - default: 3852 - pr_err("sony_pic_camera_command invalid: %d\n", command); 3853 - break; 3854 - } 3855 - mutex_unlock(&spic_dev.lock); 3856 - return 0; 3857 - } 3858 - EXPORT_SYMBOL(sony_pic_camera_command); 3859 3724 3860 3725 /* gprs/edge modem (SZ460N and SZ210P), thanks to Joshua Wise */ 3861 3726 static void __sony_pic_set_wwanpower(u8 state) ··· 4512 4677 struct sony_pic_irq *irq, *tmp_irq; 4513 4678 4514 4679 spic_dev.acpi_dev = device; 4515 - strcpy(acpi_device_class(device), "sony/hotkey"); 4680 + strscpy(acpi_device_class(device), "sony/hotkey"); 4516 4681 sony_pic_detect_device_type(&spic_dev); 4517 4682 mutex_init(&spic_dev.lock); 4518 4683
+45 -4
drivers/platform/x86/thinkpad_acpi.c
··· 182 182 * directly in the sparse-keymap. 183 183 */ 184 184 TP_HKEY_EV_AMT_TOGGLE = 0x131a, /* Toggle AMT on/off */ 185 + TP_HKEY_EV_CAMERASHUTTER_TOGGLE = 0x131b, /* Toggle Camera Shutter */ 185 186 TP_HKEY_EV_DOUBLETAP_TOGGLE = 0x131c, /* Toggle trackpoint doubletap on/off */ 186 187 TP_HKEY_EV_PROFILE_TOGGLE = 0x131f, /* Toggle platform profile in 2024 systems */ 187 188 TP_HKEY_EV_PROFILE_TOGGLE2 = 0x1401, /* Toggle platform profile in 2025 + systems */ ··· 838 837 } 839 838 840 839 ibm->acpi->device->driver_data = ibm; 841 - sprintf(acpi_device_class(ibm->acpi->device), "%s/%s", 842 - TPACPI_ACPI_EVENT_PREFIX, 843 - ibm->name); 840 + scnprintf(acpi_device_class(ibm->acpi->device), 841 + sizeof(acpi_device_class(ibm->acpi->device)), 842 + "%s/%s", TPACPI_ACPI_EVENT_PREFIX, ibm->name); 844 843 845 844 status = acpi_install_notify_handler(*ibm->acpi->handle, 846 845 ibm->acpi->type, dispatch_acpi_notify, ibm); ··· 2252 2251 } 2253 2252 } 2254 2253 2254 + #define GCES_NO_SHUTTER_DEVICE BIT(31) 2255 + 2256 + static int get_camera_shutter(void) 2257 + { 2258 + acpi_handle gces_handle; 2259 + int output; 2260 + 2261 + if (ACPI_FAILURE(acpi_get_handle(hkey_handle, "GCES", &gces_handle))) 2262 + return -ENODEV; 2263 + 2264 + if (!acpi_evalf(gces_handle, &output, NULL, "dd", 0)) 2265 + return -EIO; 2266 + 2267 + if (output & GCES_NO_SHUTTER_DEVICE) 2268 + return -ENODEV; 2269 + 2270 + return output; 2271 + } 2272 + 2255 2273 static bool tpacpi_input_send_key(const u32 hkey, bool *send_acpi_ev) 2256 2274 { 2257 2275 bool known_ev; ··· 3324 3304 const struct key_entry *keymap; 3325 3305 bool radiosw_state = false; 3326 3306 bool tabletsw_state = false; 3327 - int hkeyv, res, status; 3307 + int hkeyv, res, status, camera_shutter_state; 3328 3308 3329 3309 vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, 3330 3310 "initializing hotkey subdriver\n"); ··· 3487 3467 res = sparse_keymap_setup(tpacpi_inputdev, keymap, NULL); 3488 3468 if (res) 3489 3469 return res; 3470 + 3471 + camera_shutter_state = get_camera_shutter(); 3472 + if (camera_shutter_state >= 0) { 3473 + input_set_capability(tpacpi_inputdev, EV_SW, SW_CAMERA_LENS_COVER); 3474 + input_report_switch(tpacpi_inputdev, SW_CAMERA_LENS_COVER, camera_shutter_state); 3475 + } 3490 3476 3491 3477 if (tp_features.hotkey_wlsw) { 3492 3478 input_set_capability(tpacpi_inputdev, EV_SW, SW_RFKILL_ALL); ··· 11192 11166 */ 11193 11167 static bool tpacpi_driver_event(const unsigned int hkey_event) 11194 11168 { 11169 + int camera_shutter_state; 11170 + 11195 11171 switch (hkey_event) { 11196 11172 case TP_HKEY_EV_BRGHT_UP: 11197 11173 case TP_HKEY_EV_BRGHT_DOWN: ··· 11269 11241 else 11270 11242 dytc_control_amt(!dytc_amt_active); 11271 11243 11244 + return true; 11245 + case TP_HKEY_EV_CAMERASHUTTER_TOGGLE: 11246 + camera_shutter_state = get_camera_shutter(); 11247 + if (camera_shutter_state < 0) { 11248 + pr_err("Error retrieving camera shutter state after shutter event\n"); 11249 + return true; 11250 + } 11251 + mutex_lock(&tpacpi_inputdev_send_mutex); 11252 + 11253 + input_report_switch(tpacpi_inputdev, SW_CAMERA_LENS_COVER, camera_shutter_state); 11254 + input_sync(tpacpi_inputdev); 11255 + 11256 + mutex_unlock(&tpacpi_inputdev_send_mutex); 11272 11257 return true; 11273 11258 case TP_HKEY_EV_DOUBLETAP_TOGGLE: 11274 11259 tp_features.trackpoint_doubletap = !tp_features.trackpoint_doubletap;
+2 -2
drivers/platform/x86/topstar-laptop.c
··· 296 296 if (!topstar) 297 297 return -ENOMEM; 298 298 299 - strcpy(acpi_device_name(device), "Topstar TPSACPI"); 300 - strcpy(acpi_device_class(device), TOPSTAR_LAPTOP_CLASS); 299 + strscpy(acpi_device_name(device), "Topstar TPSACPI"); 300 + strscpy(acpi_device_class(device), TOPSTAR_LAPTOP_CLASS); 301 301 device->driver_data = topstar; 302 302 topstar->device = device; 303 303
+8
drivers/platform/x86/tuxedo/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-or-later 2 + # 3 + # Copyright (C) 2024-2025 Werner Sembach wse@tuxedocomputers.com 4 + # 5 + # TUXEDO X86 Platform Specific Drivers 6 + # 7 + 8 + source "drivers/platform/x86/tuxedo/nb04/Kconfig"
+8
drivers/platform/x86/tuxedo/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0-or-later 2 + # 3 + # Copyright (C) 2024-2025 Werner Sembach wse@tuxedocomputers.com 4 + # 5 + # TUXEDO X86 Platform Specific Drivers 6 + # 7 + 8 + obj-y += nb04/
+17
drivers/platform/x86/tuxedo/nb04/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-or-later 2 + # 3 + # Copyright (C) 2024-2025 Werner Sembach wse@tuxedocomputers.com 4 + # 5 + # TUXEDO X86 Platform Specific Drivers 6 + # 7 + 8 + config TUXEDO_NB04_WMI_AB 9 + tristate "TUXEDO NB04 WMI AB Platform Driver" 10 + depends on ACPI_WMI 11 + depends on HID 12 + help 13 + This driver implements the WMI AB device found on TUXEDO notebooks 14 + with board vendor NB04. This enables keyboard backlight control via a 15 + virtual HID LampArray device. 16 + 17 + When compiled as a module it will be called tuxedo_nb04_wmi_ab.
+10
drivers/platform/x86/tuxedo/nb04/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0-or-later 2 + # 3 + # Copyright (C) 2024-2025 Werner Sembach wse@tuxedocomputers.com 4 + # 5 + # TUXEDO X86 Platform Specific Drivers 6 + # 7 + 8 + tuxedo_nb04_wmi_ab-y := wmi_ab.o 9 + tuxedo_nb04_wmi_ab-y += wmi_util.o 10 + obj-$(CONFIG_TUXEDO_NB04_WMI_AB) += tuxedo_nb04_wmi_ab.o
+923
drivers/platform/x86/tuxedo/nb04/wmi_ab.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * This driver implements the WMI AB device found on TUXEDO notebooks with board 4 + * vendor NB04. 5 + * 6 + * Copyright (C) 2024-2025 Werner Sembach <wse@tuxedocomputers.com> 7 + */ 8 + 9 + #include <linux/dmi.h> 10 + #include <linux/hid.h> 11 + #include <linux/minmax.h> 12 + #include <linux/module.h> 13 + #include <linux/wmi.h> 14 + 15 + #include "wmi_util.h" 16 + 17 + static const struct wmi_device_id tuxedo_nb04_wmi_ab_device_ids[] = { 18 + { .guid_string = "80C9BAA6-AC48-4538-9234-9F81A55E7C85" }, 19 + { } 20 + }; 21 + MODULE_DEVICE_TABLE(wmi, tuxedo_nb04_wmi_ab_device_ids); 22 + 23 + enum { 24 + LAMP_ARRAY_ATTRIBUTES_REPORT_ID = 0x01, 25 + LAMP_ATTRIBUTES_REQUEST_REPORT_ID = 0x02, 26 + LAMP_ATTRIBUTES_RESPONSE_REPORT_ID = 0x03, 27 + LAMP_MULTI_UPDATE_REPORT_ID = 0x04, 28 + LAMP_RANGE_UPDATE_REPORT_ID = 0x05, 29 + LAMP_ARRAY_CONTROL_REPORT_ID = 0x06, 30 + }; 31 + 32 + static u8 tux_report_descriptor[327] = { 33 + 0x05, 0x59, // Usage Page (Lighting and Illumination) 34 + 0x09, 0x01, // Usage (Lamp Array) 35 + 0xa1, 0x01, // Collection (Application) 36 + 0x85, LAMP_ARRAY_ATTRIBUTES_REPORT_ID, // Report ID (1) 37 + 0x09, 0x02, // Usage (Lamp Array Attributes Report) 38 + 0xa1, 0x02, // Collection (Logical) 39 + 0x09, 0x03, // Usage (Lamp Count) 40 + 0x15, 0x00, // Logical Minimum (0) 41 + 0x27, 0xff, 0xff, 0x00, 0x00, // Logical Maximum (65535) 42 + 0x75, 0x10, // Report Size (16) 43 + 0x95, 0x01, // Report Count (1) 44 + 0xb1, 0x03, // Feature (Cnst,Var,Abs) 45 + 0x09, 0x04, // Usage (Bounding Box Width In Micrometers) 46 + 0x09, 0x05, // Usage (Bounding Box Height In Micrometers) 47 + 0x09, 0x06, // Usage (Bounding Box Depth In Micrometers) 48 + 0x09, 0x07, // Usage (Lamp Array Kind) 49 + 0x09, 0x08, // Usage (Min Update Interval In Microseconds) 50 + 0x15, 0x00, // Logical Minimum (0) 51 + 0x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 52 + 0x75, 0x20, // Report Size (32) 53 + 0x95, 0x05, // Report Count (5) 54 + 0xb1, 0x03, // Feature (Cnst,Var,Abs) 55 + 0xc0, // End Collection 56 + 0x85, LAMP_ATTRIBUTES_REQUEST_REPORT_ID, // Report ID (2) 57 + 0x09, 0x20, // Usage (Lamp Attributes Request Report) 58 + 0xa1, 0x02, // Collection (Logical) 59 + 0x09, 0x21, // Usage (Lamp Id) 60 + 0x15, 0x00, // Logical Minimum (0) 61 + 0x27, 0xff, 0xff, 0x00, 0x00, // Logical Maximum (65535) 62 + 0x75, 0x10, // Report Size (16) 63 + 0x95, 0x01, // Report Count (1) 64 + 0xb1, 0x02, // Feature (Data,Var,Abs) 65 + 0xc0, // End Collection 66 + 0x85, LAMP_ATTRIBUTES_RESPONSE_REPORT_ID, // Report ID (3) 67 + 0x09, 0x22, // Usage (Lamp Attributes Response Report) 68 + 0xa1, 0x02, // Collection (Logical) 69 + 0x09, 0x21, // Usage (Lamp Id) 70 + 0x15, 0x00, // Logical Minimum (0) 71 + 0x27, 0xff, 0xff, 0x00, 0x00, // Logical Maximum (65535) 72 + 0x75, 0x10, // Report Size (16) 73 + 0x95, 0x01, // Report Count (1) 74 + 0xb1, 0x02, // Feature (Data,Var,Abs) 75 + 0x09, 0x23, // Usage (Position X In Micrometers) 76 + 0x09, 0x24, // Usage (Position Y In Micrometers) 77 + 0x09, 0x25, // Usage (Position Z In Micrometers) 78 + 0x09, 0x27, // Usage (Update Latency In Microseconds) 79 + 0x09, 0x26, // Usage (Lamp Purposes) 80 + 0x15, 0x00, // Logical Minimum (0) 81 + 0x27, 0xff, 0xff, 0xff, 0x7f, // Logical Maximum (2147483647) 82 + 0x75, 0x20, // Report Size (32) 83 + 0x95, 0x05, // Report Count (5) 84 + 0xb1, 0x02, // Feature (Data,Var,Abs) 85 + 0x09, 0x28, // Usage (Red Level Count) 86 + 0x09, 0x29, // Usage (Green Level Count) 87 + 0x09, 0x2a, // Usage (Blue Level Count) 88 + 0x09, 0x2b, // Usage (Intensity Level Count) 89 + 0x09, 0x2c, // Usage (Is Programmable) 90 + 0x09, 0x2d, // Usage (Input Binding) 91 + 0x15, 0x00, // Logical Minimum (0) 92 + 0x26, 0xff, 0x00, // Logical Maximum (255) 93 + 0x75, 0x08, // Report Size (8) 94 + 0x95, 0x06, // Report Count (6) 95 + 0xb1, 0x02, // Feature (Data,Var,Abs) 96 + 0xc0, // End Collection 97 + 0x85, LAMP_MULTI_UPDATE_REPORT_ID, // Report ID (4) 98 + 0x09, 0x50, // Usage (Lamp Multi Update Report) 99 + 0xa1, 0x02, // Collection (Logical) 100 + 0x09, 0x03, // Usage (Lamp Count) 101 + 0x09, 0x55, // Usage (Lamp Update Flags) 102 + 0x15, 0x00, // Logical Minimum (0) 103 + 0x25, 0x08, // Logical Maximum (8) 104 + 0x75, 0x08, // Report Size (8) 105 + 0x95, 0x02, // Report Count (2) 106 + 0xb1, 0x02, // Feature (Data,Var,Abs) 107 + 0x09, 0x21, // Usage (Lamp Id) 108 + 0x15, 0x00, // Logical Minimum (0) 109 + 0x27, 0xff, 0xff, 0x00, 0x00, // Logical Maximum (65535) 110 + 0x75, 0x10, // Report Size (16) 111 + 0x95, 0x08, // Report Count (8) 112 + 0xb1, 0x02, // Feature (Data,Var,Abs) 113 + 0x09, 0x51, // Usage (Red Update Channel) 114 + 0x09, 0x52, // Usage (Green Update Channel) 115 + 0x09, 0x53, // Usage (Blue Update Channel) 116 + 0x09, 0x54, // Usage (Intensity Update Channel) 117 + 0x09, 0x51, // Usage (Red Update Channel) 118 + 0x09, 0x52, // Usage (Green Update Channel) 119 + 0x09, 0x53, // Usage (Blue Update Channel) 120 + 0x09, 0x54, // Usage (Intensity Update Channel) 121 + 0x09, 0x51, // Usage (Red Update Channel) 122 + 0x09, 0x52, // Usage (Green Update Channel) 123 + 0x09, 0x53, // Usage (Blue Update Channel) 124 + 0x09, 0x54, // Usage (Intensity Update Channel) 125 + 0x09, 0x51, // Usage (Red Update Channel) 126 + 0x09, 0x52, // Usage (Green Update Channel) 127 + 0x09, 0x53, // Usage (Blue Update Channel) 128 + 0x09, 0x54, // Usage (Intensity Update Channel) 129 + 0x09, 0x51, // Usage (Red Update Channel) 130 + 0x09, 0x52, // Usage (Green Update Channel) 131 + 0x09, 0x53, // Usage (Blue Update Channel) 132 + 0x09, 0x54, // Usage (Intensity Update Channel) 133 + 0x09, 0x51, // Usage (Red Update Channel) 134 + 0x09, 0x52, // Usage (Green Update Channel) 135 + 0x09, 0x53, // Usage (Blue Update Channel) 136 + 0x09, 0x54, // Usage (Intensity Update Channel) 137 + 0x09, 0x51, // Usage (Red Update Channel) 138 + 0x09, 0x52, // Usage (Green Update Channel) 139 + 0x09, 0x53, // Usage (Blue Update Channel) 140 + 0x09, 0x54, // Usage (Intensity Update Channel) 141 + 0x09, 0x51, // Usage (Red Update Channel) 142 + 0x09, 0x52, // Usage (Green Update Channel) 143 + 0x09, 0x53, // Usage (Blue Update Channel) 144 + 0x09, 0x54, // Usage (Intensity Update Channel) 145 + 0x15, 0x00, // Logical Minimum (0) 146 + 0x26, 0xff, 0x00, // Logical Maximum (255) 147 + 0x75, 0x08, // Report Size (8) 148 + 0x95, 0x20, // Report Count (32) 149 + 0xb1, 0x02, // Feature (Data,Var,Abs) 150 + 0xc0, // End Collection 151 + 0x85, LAMP_RANGE_UPDATE_REPORT_ID, // Report ID (5) 152 + 0x09, 0x60, // Usage (Lamp Range Update Report) 153 + 0xa1, 0x02, // Collection (Logical) 154 + 0x09, 0x55, // Usage (Lamp Update Flags) 155 + 0x15, 0x00, // Logical Minimum (0) 156 + 0x25, 0x08, // Logical Maximum (8) 157 + 0x75, 0x08, // Report Size (8) 158 + 0x95, 0x01, // Report Count (1) 159 + 0xb1, 0x02, // Feature (Data,Var,Abs) 160 + 0x09, 0x61, // Usage (Lamp Id Start) 161 + 0x09, 0x62, // Usage (Lamp Id End) 162 + 0x15, 0x00, // Logical Minimum (0) 163 + 0x27, 0xff, 0xff, 0x00, 0x00, // Logical Maximum (65535) 164 + 0x75, 0x10, // Report Size (16) 165 + 0x95, 0x02, // Report Count (2) 166 + 0xb1, 0x02, // Feature (Data,Var,Abs) 167 + 0x09, 0x51, // Usage (Red Update Channel) 168 + 0x09, 0x52, // Usage (Green Update Channel) 169 + 0x09, 0x53, // Usage (Blue Update Channel) 170 + 0x09, 0x54, // Usage (Intensity Update Channel) 171 + 0x15, 0x00, // Logical Minimum (0) 172 + 0x26, 0xff, 0x00, // Logical Maximum (255) 173 + 0x75, 0x08, // Report Size (8) 174 + 0x95, 0x04, // Report Count (4) 175 + 0xb1, 0x02, // Feature (Data,Var,Abs) 176 + 0xc0, // End Collection 177 + 0x85, LAMP_ARRAY_CONTROL_REPORT_ID, // Report ID (6) 178 + 0x09, 0x70, // Usage (Lamp Array Control Report) 179 + 0xa1, 0x02, // Collection (Logical) 180 + 0x09, 0x71, // Usage (Autonomous Mode) 181 + 0x15, 0x00, // Logical Minimum (0) 182 + 0x25, 0x01, // Logical Maximum (1) 183 + 0x75, 0x08, // Report Size (8) 184 + 0x95, 0x01, // Report Count (1) 185 + 0xb1, 0x02, // Feature (Data,Var,Abs) 186 + 0xc0, // End Collection 187 + 0xc0 // End Collection 188 + }; 189 + 190 + struct tux_kbl_map_entry_t { 191 + u8 code; 192 + struct { 193 + u32 x; 194 + u32 y; 195 + u32 z; 196 + } pos; 197 + }; 198 + 199 + static const struct tux_kbl_map_entry_t sirius_16_ansii_kbl_map[] = { 200 + { 0x29, { 25000, 53000, 5000 } }, 201 + { 0x3a, { 41700, 53000, 5000 } }, 202 + { 0x3b, { 58400, 53000, 5000 } }, 203 + { 0x3c, { 75100, 53000, 5000 } }, 204 + { 0x3d, { 91800, 53000, 5000 } }, 205 + { 0x3e, { 108500, 53000, 5000 } }, 206 + { 0x3f, { 125200, 53000, 5000 } }, 207 + { 0x40, { 141900, 53000, 5000 } }, 208 + { 0x41, { 158600, 53000, 5000 } }, 209 + { 0x42, { 175300, 53000, 5000 } }, 210 + { 0x43, { 192000, 53000, 5000 } }, 211 + { 0x44, { 208700, 53000, 5000 } }, 212 + { 0x45, { 225400, 53000, 5000 } }, 213 + { 0xf1, { 242100, 53000, 5000 } }, 214 + { 0x46, { 258800, 53000, 5000 } }, 215 + { 0x4c, { 275500, 53000, 5000 } }, 216 + { 0x4a, { 294500, 53000, 5000 } }, 217 + { 0x4d, { 311200, 53000, 5000 } }, 218 + { 0x4b, { 327900, 53000, 5000 } }, 219 + { 0x4e, { 344600, 53000, 5000 } }, 220 + { 0x35, { 24500, 67500, 5250 } }, 221 + { 0x1e, { 42500, 67500, 5250 } }, 222 + { 0x1f, { 61000, 67500, 5250 } }, 223 + { 0x20, { 79500, 67500, 5250 } }, 224 + { 0x21, { 98000, 67500, 5250 } }, 225 + { 0x22, { 116500, 67500, 5250 } }, 226 + { 0x23, { 135000, 67500, 5250 } }, 227 + { 0x24, { 153500, 67500, 5250 } }, 228 + { 0x25, { 172000, 67500, 5250 } }, 229 + { 0x26, { 190500, 67500, 5250 } }, 230 + { 0x27, { 209000, 67500, 5250 } }, 231 + { 0x2d, { 227500, 67500, 5250 } }, 232 + { 0x2e, { 246000, 67500, 5250 } }, 233 + { 0x2a, { 269500, 67500, 5250 } }, 234 + { 0x53, { 294500, 67500, 5250 } }, 235 + { 0x55, { 311200, 67500, 5250 } }, 236 + { 0x54, { 327900, 67500, 5250 } }, 237 + { 0x56, { 344600, 67500, 5250 } }, 238 + { 0x2b, { 31000, 85500, 5500 } }, 239 + { 0x14, { 51500, 85500, 5500 } }, 240 + { 0x1a, { 70000, 85500, 5500 } }, 241 + { 0x08, { 88500, 85500, 5500 } }, 242 + { 0x15, { 107000, 85500, 5500 } }, 243 + { 0x17, { 125500, 85500, 5500 } }, 244 + { 0x1c, { 144000, 85500, 5500 } }, 245 + { 0x18, { 162500, 85500, 5500 } }, 246 + { 0x0c, { 181000, 85500, 5500 } }, 247 + { 0x12, { 199500, 85500, 5500 } }, 248 + { 0x13, { 218000, 85500, 5500 } }, 249 + { 0x2f, { 236500, 85500, 5500 } }, 250 + { 0x30, { 255000, 85500, 5500 } }, 251 + { 0x31, { 273500, 85500, 5500 } }, 252 + { 0x5f, { 294500, 85500, 5500 } }, 253 + { 0x60, { 311200, 85500, 5500 } }, 254 + { 0x61, { 327900, 85500, 5500 } }, 255 + { 0x39, { 33000, 103500, 5750 } }, 256 + { 0x04, { 57000, 103500, 5750 } }, 257 + { 0x16, { 75500, 103500, 5750 } }, 258 + { 0x07, { 94000, 103500, 5750 } }, 259 + { 0x09, { 112500, 103500, 5750 } }, 260 + { 0x0a, { 131000, 103500, 5750 } }, 261 + { 0x0b, { 149500, 103500, 5750 } }, 262 + { 0x0d, { 168000, 103500, 5750 } }, 263 + { 0x0e, { 186500, 103500, 5750 } }, 264 + { 0x0f, { 205000, 103500, 5750 } }, 265 + { 0x33, { 223500, 103500, 5750 } }, 266 + { 0x34, { 242000, 103500, 5750 } }, 267 + { 0x28, { 267500, 103500, 5750 } }, 268 + { 0x5c, { 294500, 103500, 5750 } }, 269 + { 0x5d, { 311200, 103500, 5750 } }, 270 + { 0x5e, { 327900, 103500, 5750 } }, 271 + { 0x57, { 344600, 94500, 5625 } }, 272 + { 0xe1, { 37000, 121500, 6000 } }, 273 + { 0x1d, { 66000, 121500, 6000 } }, 274 + { 0x1b, { 84500, 121500, 6000 } }, 275 + { 0x06, { 103000, 121500, 6000 } }, 276 + { 0x19, { 121500, 121500, 6000 } }, 277 + { 0x05, { 140000, 121500, 6000 } }, 278 + { 0x11, { 158500, 121500, 6000 } }, 279 + { 0x10, { 177000, 121500, 6000 } }, 280 + { 0x36, { 195500, 121500, 6000 } }, 281 + { 0x37, { 214000, 121500, 6000 } }, 282 + { 0x38, { 232500, 121500, 6000 } }, 283 + { 0xe5, { 251500, 121500, 6000 } }, 284 + { 0x52, { 273500, 129000, 6125 } }, 285 + { 0x59, { 294500, 121500, 6000 } }, 286 + { 0x5a, { 311200, 121500, 6000 } }, 287 + { 0x5b, { 327900, 121500, 6000 } }, 288 + { 0xe0, { 28000, 139500, 6250 } }, 289 + { 0xfe, { 47500, 139500, 6250 } }, 290 + { 0xe3, { 66000, 139500, 6250 } }, 291 + { 0xe2, { 84500, 139500, 6250 } }, 292 + { 0x2c, { 140000, 139500, 6250 } }, 293 + { 0xe6, { 195500, 139500, 6250 } }, 294 + { 0x65, { 214000, 139500, 6250 } }, 295 + { 0xe4, { 234000, 139500, 6250 } }, 296 + { 0x50, { 255000, 147000, 6375 } }, 297 + { 0x51, { 273500, 147000, 6375 } }, 298 + { 0x4f, { 292000, 147000, 6375 } }, 299 + { 0x62, { 311200, 139500, 6250 } }, 300 + { 0x63, { 327900, 139500, 6250 } }, 301 + { 0x58, { 344600, 130500, 6125 } }, 302 + }; 303 + 304 + static const struct tux_kbl_map_entry_t sirius_16_iso_kbl_map[] = { 305 + { 0x29, { 25000, 53000, 5000 } }, 306 + { 0x3a, { 41700, 53000, 5000 } }, 307 + { 0x3b, { 58400, 53000, 5000 } }, 308 + { 0x3c, { 75100, 53000, 5000 } }, 309 + { 0x3d, { 91800, 53000, 5000 } }, 310 + { 0x3e, { 108500, 53000, 5000 } }, 311 + { 0x3f, { 125200, 53000, 5000 } }, 312 + { 0x40, { 141900, 53000, 5000 } }, 313 + { 0x41, { 158600, 53000, 5000 } }, 314 + { 0x42, { 175300, 53000, 5000 } }, 315 + { 0x43, { 192000, 53000, 5000 } }, 316 + { 0x44, { 208700, 53000, 5000 } }, 317 + { 0x45, { 225400, 53000, 5000 } }, 318 + { 0xf1, { 242100, 53000, 5000 } }, 319 + { 0x46, { 258800, 53000, 5000 } }, 320 + { 0x4c, { 275500, 53000, 5000 } }, 321 + { 0x4a, { 294500, 53000, 5000 } }, 322 + { 0x4d, { 311200, 53000, 5000 } }, 323 + { 0x4b, { 327900, 53000, 5000 } }, 324 + { 0x4e, { 344600, 53000, 5000 } }, 325 + { 0x35, { 24500, 67500, 5250 } }, 326 + { 0x1e, { 42500, 67500, 5250 } }, 327 + { 0x1f, { 61000, 67500, 5250 } }, 328 + { 0x20, { 79500, 67500, 5250 } }, 329 + { 0x21, { 98000, 67500, 5250 } }, 330 + { 0x22, { 116500, 67500, 5250 } }, 331 + { 0x23, { 135000, 67500, 5250 } }, 332 + { 0x24, { 153500, 67500, 5250 } }, 333 + { 0x25, { 172000, 67500, 5250 } }, 334 + { 0x26, { 190500, 67500, 5250 } }, 335 + { 0x27, { 209000, 67500, 5250 } }, 336 + { 0x2d, { 227500, 67500, 5250 } }, 337 + { 0x2e, { 246000, 67500, 5250 } }, 338 + { 0x2a, { 269500, 67500, 5250 } }, 339 + { 0x53, { 294500, 67500, 5250 } }, 340 + { 0x55, { 311200, 67500, 5250 } }, 341 + { 0x54, { 327900, 67500, 5250 } }, 342 + { 0x56, { 344600, 67500, 5250 } }, 343 + { 0x2b, { 31000, 85500, 5500 } }, 344 + { 0x14, { 51500, 85500, 5500 } }, 345 + { 0x1a, { 70000, 85500, 5500 } }, 346 + { 0x08, { 88500, 85500, 5500 } }, 347 + { 0x15, { 107000, 85500, 5500 } }, 348 + { 0x17, { 125500, 85500, 5500 } }, 349 + { 0x1c, { 144000, 85500, 5500 } }, 350 + { 0x18, { 162500, 85500, 5500 } }, 351 + { 0x0c, { 181000, 85500, 5500 } }, 352 + { 0x12, { 199500, 85500, 5500 } }, 353 + { 0x13, { 218000, 85500, 5500 } }, 354 + { 0x2f, { 234500, 85500, 5500 } }, 355 + { 0x30, { 251000, 85500, 5500 } }, 356 + { 0x5f, { 294500, 85500, 5500 } }, 357 + { 0x60, { 311200, 85500, 5500 } }, 358 + { 0x61, { 327900, 85500, 5500 } }, 359 + { 0x39, { 33000, 103500, 5750 } }, 360 + { 0x04, { 57000, 103500, 5750 } }, 361 + { 0x16, { 75500, 103500, 5750 } }, 362 + { 0x07, { 94000, 103500, 5750 } }, 363 + { 0x09, { 112500, 103500, 5750 } }, 364 + { 0x0a, { 131000, 103500, 5750 } }, 365 + { 0x0b, { 149500, 103500, 5750 } }, 366 + { 0x0d, { 168000, 103500, 5750 } }, 367 + { 0x0e, { 186500, 103500, 5750 } }, 368 + { 0x0f, { 205000, 103500, 5750 } }, 369 + { 0x33, { 223500, 103500, 5750 } }, 370 + { 0x34, { 240000, 103500, 5750 } }, 371 + { 0x32, { 256500, 103500, 5750 } }, 372 + { 0x28, { 271500, 94500, 5750 } }, 373 + { 0x5c, { 294500, 103500, 5750 } }, 374 + { 0x5d, { 311200, 103500, 5750 } }, 375 + { 0x5e, { 327900, 103500, 5750 } }, 376 + { 0x57, { 344600, 94500, 5625 } }, 377 + { 0xe1, { 28000, 121500, 6000 } }, 378 + { 0x64, { 47500, 121500, 6000 } }, 379 + { 0x1d, { 66000, 121500, 6000 } }, 380 + { 0x1b, { 84500, 121500, 6000 } }, 381 + { 0x06, { 103000, 121500, 6000 } }, 382 + { 0x19, { 121500, 121500, 6000 } }, 383 + { 0x05, { 140000, 121500, 6000 } }, 384 + { 0x11, { 158500, 121500, 6000 } }, 385 + { 0x10, { 177000, 121500, 6000 } }, 386 + { 0x36, { 195500, 121500, 6000 } }, 387 + { 0x37, { 214000, 121500, 6000 } }, 388 + { 0x38, { 232500, 121500, 6000 } }, 389 + { 0xe5, { 251500, 121500, 6000 } }, 390 + { 0x52, { 273500, 129000, 6125 } }, 391 + { 0x59, { 294500, 121500, 6000 } }, 392 + { 0x5a, { 311200, 121500, 6000 } }, 393 + { 0x5b, { 327900, 121500, 6000 } }, 394 + { 0xe0, { 28000, 139500, 6250 } }, 395 + { 0xfe, { 47500, 139500, 6250 } }, 396 + { 0xe3, { 66000, 139500, 6250 } }, 397 + { 0xe2, { 84500, 139500, 6250 } }, 398 + { 0x2c, { 140000, 139500, 6250 } }, 399 + { 0xe6, { 195500, 139500, 6250 } }, 400 + { 0x65, { 214000, 139500, 6250 } }, 401 + { 0xe4, { 234000, 139500, 6250 } }, 402 + { 0x50, { 255000, 147000, 6375 } }, 403 + { 0x51, { 273500, 147000, 6375 } }, 404 + { 0x4f, { 292000, 147000, 6375 } }, 405 + { 0x62, { 311200, 139500, 6250 } }, 406 + { 0x63, { 327900, 139500, 6250 } }, 407 + { 0x58, { 344600, 130500, 6125 } }, 408 + }; 409 + 410 + struct tux_driver_data_t { 411 + struct hid_device *hdev; 412 + }; 413 + 414 + struct tux_hdev_driver_data_t { 415 + u8 lamp_count; 416 + const struct tux_kbl_map_entry_t *kbl_map; 417 + u8 next_lamp_id; 418 + union tux_wmi_xx_496in_80out_in_t next_kbl_set_multiple_keys_in; 419 + }; 420 + 421 + static int tux_ll_start(struct hid_device *hdev) 422 + { 423 + struct wmi_device *wdev = to_wmi_device(hdev->dev.parent); 424 + struct tux_hdev_driver_data_t *driver_data; 425 + union tux_wmi_xx_8in_80out_out_t out; 426 + union tux_wmi_xx_8in_80out_in_t in; 427 + u8 keyboard_type; 428 + int ret; 429 + 430 + driver_data = devm_kzalloc(&hdev->dev, sizeof(*driver_data), GFP_KERNEL); 431 + if (!driver_data) 432 + return -ENOMEM; 433 + 434 + in.get_device_status_in.device_type = TUX_GET_DEVICE_STATUS_DEVICE_ID_KEYBOARD; 435 + ret = tux_wmi_xx_8in_80out(wdev, TUX_GET_DEVICE_STATUS, &in, &out); 436 + if (ret) 437 + return ret; 438 + 439 + keyboard_type = out.get_device_status_out.keyboard_physical_layout; 440 + if (keyboard_type == TUX_GET_DEVICE_STATUS_KEYBOARD_LAYOUT_ANSII) { 441 + driver_data->lamp_count = ARRAY_SIZE(sirius_16_ansii_kbl_map); 442 + driver_data->kbl_map = sirius_16_ansii_kbl_map; 443 + } else if (keyboard_type == TUX_GET_DEVICE_STATUS_KEYBOARD_LAYOUT_ISO) { 444 + driver_data->lamp_count = ARRAY_SIZE(sirius_16_iso_kbl_map); 445 + driver_data->kbl_map = sirius_16_iso_kbl_map; 446 + } else { 447 + return -EINVAL; 448 + } 449 + driver_data->next_lamp_id = 0; 450 + 451 + dev_set_drvdata(&hdev->dev, driver_data); 452 + 453 + return ret; 454 + } 455 + 456 + static void tux_ll_stop(struct hid_device *hdev __always_unused) 457 + { 458 + } 459 + 460 + static int tux_ll_open(struct hid_device *hdev __always_unused) 461 + { 462 + return 0; 463 + } 464 + 465 + static void tux_ll_close(struct hid_device *hdev __always_unused) 466 + { 467 + } 468 + 469 + static int tux_ll_parse(struct hid_device *hdev) 470 + { 471 + return hid_parse_report(hdev, tux_report_descriptor, 472 + sizeof(tux_report_descriptor)); 473 + } 474 + 475 + struct __packed lamp_array_attributes_report_t { 476 + const u8 report_id; 477 + u16 lamp_count; 478 + u32 bounding_box_width_in_micrometers; 479 + u32 bounding_box_height_in_micrometers; 480 + u32 bounding_box_depth_in_micrometers; 481 + u32 lamp_array_kind; 482 + u32 min_update_interval_in_microseconds; 483 + }; 484 + 485 + static int handle_lamp_array_attributes_report(struct hid_device *hdev, 486 + struct lamp_array_attributes_report_t *rep) 487 + { 488 + struct tux_hdev_driver_data_t *driver_data = dev_get_drvdata(&hdev->dev); 489 + 490 + rep->lamp_count = driver_data->lamp_count; 491 + rep->bounding_box_width_in_micrometers = 368000; 492 + rep->bounding_box_height_in_micrometers = 266000; 493 + rep->bounding_box_depth_in_micrometers = 30000; 494 + /* 495 + * LampArrayKindKeyboard, see "26.2.1 LampArrayKind Values" of 496 + * "HID Usage Tables v1.5" 497 + */ 498 + rep->lamp_array_kind = 1; 499 + // Some guessed value for interval microseconds 500 + rep->min_update_interval_in_microseconds = 500; 501 + 502 + return sizeof(*rep); 503 + } 504 + 505 + struct __packed lamp_attributes_request_report_t { 506 + const u8 report_id; 507 + u16 lamp_id; 508 + }; 509 + 510 + static int handle_lamp_attributes_request_report(struct hid_device *hdev, 511 + struct lamp_attributes_request_report_t *rep) 512 + { 513 + struct tux_hdev_driver_data_t *driver_data = dev_get_drvdata(&hdev->dev); 514 + 515 + if (rep->lamp_id < driver_data->lamp_count) 516 + driver_data->next_lamp_id = rep->lamp_id; 517 + else 518 + driver_data->next_lamp_id = 0; 519 + 520 + return sizeof(*rep); 521 + } 522 + 523 + struct __packed lamp_attributes_response_report_t { 524 + const u8 report_id; 525 + u16 lamp_id; 526 + u32 position_x_in_micrometers; 527 + u32 position_y_in_micrometers; 528 + u32 position_z_in_micrometers; 529 + u32 update_latency_in_microseconds; 530 + u32 lamp_purpose; 531 + u8 red_level_count; 532 + u8 green_level_count; 533 + u8 blue_level_count; 534 + u8 intensity_level_count; 535 + u8 is_programmable; 536 + u8 input_binding; 537 + }; 538 + 539 + static int handle_lamp_attributes_response_report(struct hid_device *hdev, 540 + struct lamp_attributes_response_report_t *rep) 541 + { 542 + struct tux_hdev_driver_data_t *driver_data = dev_get_drvdata(&hdev->dev); 543 + u16 lamp_id = driver_data->next_lamp_id; 544 + 545 + rep->lamp_id = lamp_id; 546 + // Some guessed value for latency microseconds 547 + rep->update_latency_in_microseconds = 100; 548 + /* 549 + * LampPurposeControl, see "26.3.1 LampPurposes Flags" of 550 + * "HID Usage Tables v1.5" 551 + */ 552 + rep->lamp_purpose = 1; 553 + rep->red_level_count = 0xff; 554 + rep->green_level_count = 0xff; 555 + rep->blue_level_count = 0xff; 556 + rep->intensity_level_count = 0xff; 557 + rep->is_programmable = 1; 558 + 559 + if (driver_data->kbl_map[lamp_id].code <= 0xe8) { 560 + rep->input_binding = driver_data->kbl_map[lamp_id].code; 561 + } else { 562 + /* 563 + * Everything bigger is reserved/undefined, see 564 + * "10 Keyboard/Keypad Page (0x07)" of "HID Usage Tables v1.5" 565 + * and should return 0, see "26.8.3 Lamp Attributes" of the same 566 + * document. 567 + */ 568 + rep->input_binding = 0; 569 + } 570 + rep->position_x_in_micrometers = driver_data->kbl_map[lamp_id].pos.x; 571 + rep->position_y_in_micrometers = driver_data->kbl_map[lamp_id].pos.y; 572 + rep->position_z_in_micrometers = driver_data->kbl_map[lamp_id].pos.z; 573 + 574 + driver_data->next_lamp_id = (driver_data->next_lamp_id + 1) % driver_data->lamp_count; 575 + 576 + return sizeof(*rep); 577 + } 578 + 579 + #define LAMP_UPDATE_FLAGS_LAMP_UPDATE_COMPLETE BIT(0) 580 + 581 + struct __packed lamp_rgbi_tuple_t { 582 + u8 red; 583 + u8 green; 584 + u8 blue; 585 + u8 intensity; 586 + }; 587 + 588 + #define LAMP_MULTI_UPDATE_REPORT_LAMP_COUNT_MAX 8 589 + 590 + struct __packed lamp_multi_update_report_t { 591 + const u8 report_id; 592 + u8 lamp_count; 593 + u8 lamp_update_flags; 594 + u16 lamp_id[LAMP_MULTI_UPDATE_REPORT_LAMP_COUNT_MAX]; 595 + struct lamp_rgbi_tuple_t update_channels[LAMP_MULTI_UPDATE_REPORT_LAMP_COUNT_MAX]; 596 + }; 597 + 598 + static int handle_lamp_multi_update_report(struct hid_device *hdev, 599 + struct lamp_multi_update_report_t *rep) 600 + { 601 + struct tux_hdev_driver_data_t *driver_data = dev_get_drvdata(&hdev->dev); 602 + union tux_wmi_xx_496in_80out_in_t *next = &driver_data->next_kbl_set_multiple_keys_in; 603 + struct tux_kbl_set_multiple_keys_in_rgb_config_t *rgb_configs_j; 604 + struct wmi_device *wdev = to_wmi_device(hdev->dev.parent); 605 + union tux_wmi_xx_496in_80out_out_t out; 606 + u8 key_id, key_id_j, intensity_i, red_i, green_i, blue_i; 607 + int ret; 608 + 609 + /* 610 + * Catching misformatted lamp_multi_update_report and fail silently 611 + * according to "HID Usage Tables v1.5" 612 + */ 613 + for (unsigned int i = 0; i < rep->lamp_count; ++i) { 614 + if (rep->lamp_id[i] > driver_data->lamp_count) { 615 + hid_dbg(hdev, "Out of bounds lamp_id in lamp_multi_update_report. Skipping whole report!\n"); 616 + return sizeof(*rep); 617 + } 618 + 619 + for (unsigned int j = i + 1; j < rep->lamp_count; ++j) { 620 + if (rep->lamp_id[i] == rep->lamp_id[j]) { 621 + hid_dbg(hdev, "Duplicate lamp_id in lamp_multi_update_report. Skipping whole report!\n"); 622 + return sizeof(*rep); 623 + } 624 + } 625 + } 626 + 627 + for (unsigned int i = 0; i < rep->lamp_count; ++i) { 628 + key_id = driver_data->kbl_map[rep->lamp_id[i]].code; 629 + 630 + for (unsigned int j = 0; 631 + j < TUX_KBL_SET_MULTIPLE_KEYS_LIGHTING_SETTINGS_COUNT_MAX; 632 + ++j) { 633 + rgb_configs_j = &next->kbl_set_multiple_keys_in.rgb_configs[j]; 634 + key_id_j = rgb_configs_j->key_id; 635 + if (key_id_j != 0x00 && key_id_j != key_id) 636 + continue; 637 + 638 + if (key_id_j == 0x00) 639 + next->kbl_set_multiple_keys_in.rgb_configs_cnt = 640 + j + 1; 641 + rgb_configs_j->key_id = key_id; 642 + /* 643 + * While this driver respects update_channel.intensity 644 + * according to "HID Usage Tables v1.5" also on RGB 645 + * leds, the Microsoft MacroPad reference implementation 646 + * (https://github.com/microsoft/RP2040MacropadHidSample 647 + * 1d6c3ad) does not and ignores it. If it turns out 648 + * that Windows writes intensity = 0 for RGB leds 649 + * instead of intensity = 255, this driver should also 650 + * ignore the update_channel.intensity. 651 + */ 652 + intensity_i = rep->update_channels[i].intensity; 653 + red_i = rep->update_channels[i].red; 654 + green_i = rep->update_channels[i].green; 655 + blue_i = rep->update_channels[i].blue; 656 + rgb_configs_j->red = red_i * intensity_i / 0xff; 657 + rgb_configs_j->green = green_i * intensity_i / 0xff; 658 + rgb_configs_j->blue = blue_i * intensity_i / 0xff; 659 + 660 + break; 661 + } 662 + } 663 + 664 + if (rep->lamp_update_flags & LAMP_UPDATE_FLAGS_LAMP_UPDATE_COMPLETE) { 665 + ret = tux_wmi_xx_496in_80out(wdev, TUX_KBL_SET_MULTIPLE_KEYS, 666 + next, &out); 667 + memset(next, 0, sizeof(*next)); 668 + if (ret) 669 + return ret; 670 + } 671 + 672 + return sizeof(*rep); 673 + } 674 + 675 + struct __packed lamp_range_update_report_t { 676 + const u8 report_id; 677 + u8 lamp_update_flags; 678 + u16 lamp_id_start; 679 + u16 lamp_id_end; 680 + struct lamp_rgbi_tuple_t update_channel; 681 + }; 682 + 683 + static int handle_lamp_range_update_report(struct hid_device *hdev, 684 + struct lamp_range_update_report_t *rep) 685 + { 686 + struct tux_hdev_driver_data_t *driver_data = dev_get_drvdata(&hdev->dev); 687 + struct lamp_multi_update_report_t lamp_multi_update_report = { 688 + .report_id = LAMP_MULTI_UPDATE_REPORT_ID, 689 + }; 690 + struct lamp_rgbi_tuple_t *update_channels_j; 691 + int ret; 692 + 693 + /* 694 + * Catching misformatted lamp_range_update_report and fail silently 695 + * according to "HID Usage Tables v1.5" 696 + */ 697 + if (rep->lamp_id_start > rep->lamp_id_end) { 698 + hid_dbg(hdev, "lamp_id_start > lamp_id_end in lamp_range_update_report. Skipping whole report!\n"); 699 + return sizeof(*rep); 700 + } 701 + 702 + if (rep->lamp_id_end > driver_data->lamp_count - 1) { 703 + hid_dbg(hdev, "Out of bounds lamp_id_end in lamp_range_update_report. Skipping whole report!\n"); 704 + return sizeof(*rep); 705 + } 706 + 707 + /* 708 + * Break handle_lamp_range_update_report call down to multiple 709 + * handle_lamp_multi_update_report calls to easily ensure that mixing 710 + * handle_lamp_range_update_report and handle_lamp_multi_update_report 711 + * does not break things. 712 + */ 713 + for (unsigned int i = rep->lamp_id_start; i < rep->lamp_id_end + 1; 714 + i = i + LAMP_MULTI_UPDATE_REPORT_LAMP_COUNT_MAX) { 715 + lamp_multi_update_report.lamp_count = 716 + min(rep->lamp_id_end + 1 - i, 717 + LAMP_MULTI_UPDATE_REPORT_LAMP_COUNT_MAX); 718 + lamp_multi_update_report.lamp_update_flags = 719 + i + LAMP_MULTI_UPDATE_REPORT_LAMP_COUNT_MAX >= 720 + rep->lamp_id_end + 1 ? 721 + LAMP_UPDATE_FLAGS_LAMP_UPDATE_COMPLETE : 0; 722 + 723 + for (unsigned int j = 0; j < lamp_multi_update_report.lamp_count; ++j) { 724 + lamp_multi_update_report.lamp_id[j] = i + j; 725 + update_channels_j = 726 + &lamp_multi_update_report.update_channels[j]; 727 + update_channels_j->red = rep->update_channel.red; 728 + update_channels_j->green = rep->update_channel.green; 729 + update_channels_j->blue = rep->update_channel.blue; 730 + update_channels_j->intensity = rep->update_channel.intensity; 731 + } 732 + 733 + ret = handle_lamp_multi_update_report(hdev, &lamp_multi_update_report); 734 + if (ret < 0) 735 + return ret; 736 + if (ret != sizeof(lamp_multi_update_report)) 737 + return -EIO; 738 + } 739 + 740 + return sizeof(*rep); 741 + } 742 + 743 + struct __packed lamp_array_control_report_t { 744 + const u8 report_id; 745 + u8 autonomous_mode; 746 + }; 747 + 748 + static int handle_lamp_array_control_report(struct hid_device *hdev __always_unused, 749 + struct lamp_array_control_report_t *rep) 750 + { 751 + /* 752 + * The keyboards firmware doesn't have any built in controls and the 753 + * built in effects are not implemented so this is a NOOP. 754 + * According to the HID Documentation (HID Usage Tables v1.5) this 755 + * function is optional and can be removed from the HID Report 756 + * Descriptor, but it should first be confirmed that userspace respects 757 + * this possibility too. The Microsoft MacroPad reference implementation 758 + * (https://github.com/microsoft/RP2040MacropadHidSample 1d6c3ad) 759 + * already deviates from the spec at another point, see 760 + * handle_lamp_*_update_report. 761 + */ 762 + 763 + return sizeof(*rep); 764 + } 765 + 766 + static int tux_ll_raw_request(struct hid_device *hdev, u8 reportnum, u8 *buf, 767 + size_t len, unsigned char rtype, int reqtype) 768 + { 769 + if (rtype != HID_FEATURE_REPORT) 770 + return -EINVAL; 771 + 772 + switch (reqtype) { 773 + case HID_REQ_GET_REPORT: 774 + switch (reportnum) { 775 + case LAMP_ARRAY_ATTRIBUTES_REPORT_ID: 776 + if (len != sizeof(struct lamp_array_attributes_report_t)) 777 + return -EINVAL; 778 + return handle_lamp_array_attributes_report(hdev, 779 + (struct lamp_array_attributes_report_t *)buf); 780 + case LAMP_ATTRIBUTES_RESPONSE_REPORT_ID: 781 + if (len != sizeof(struct lamp_attributes_response_report_t)) 782 + return -EINVAL; 783 + return handle_lamp_attributes_response_report(hdev, 784 + (struct lamp_attributes_response_report_t *)buf); 785 + } 786 + break; 787 + case HID_REQ_SET_REPORT: 788 + switch (reportnum) { 789 + case LAMP_ATTRIBUTES_REQUEST_REPORT_ID: 790 + if (len != sizeof(struct lamp_attributes_request_report_t)) 791 + return -EINVAL; 792 + return handle_lamp_attributes_request_report(hdev, 793 + (struct lamp_attributes_request_report_t *)buf); 794 + case LAMP_MULTI_UPDATE_REPORT_ID: 795 + if (len != sizeof(struct lamp_multi_update_report_t)) 796 + return -EINVAL; 797 + return handle_lamp_multi_update_report(hdev, 798 + (struct lamp_multi_update_report_t *)buf); 799 + case LAMP_RANGE_UPDATE_REPORT_ID: 800 + if (len != sizeof(struct lamp_range_update_report_t)) 801 + return -EINVAL; 802 + return handle_lamp_range_update_report(hdev, 803 + (struct lamp_range_update_report_t *)buf); 804 + case LAMP_ARRAY_CONTROL_REPORT_ID: 805 + if (len != sizeof(struct lamp_array_control_report_t)) 806 + return -EINVAL; 807 + return handle_lamp_array_control_report(hdev, 808 + (struct lamp_array_control_report_t *)buf); 809 + } 810 + break; 811 + } 812 + 813 + return -EINVAL; 814 + } 815 + 816 + static const struct hid_ll_driver tux_ll_driver = { 817 + .start = &tux_ll_start, 818 + .stop = &tux_ll_stop, 819 + .open = &tux_ll_open, 820 + .close = &tux_ll_close, 821 + .parse = &tux_ll_parse, 822 + .raw_request = &tux_ll_raw_request, 823 + }; 824 + 825 + static int tux_virt_lamparray_add_device(struct wmi_device *wdev, 826 + struct hid_device **hdev_out) 827 + { 828 + struct hid_device *hdev; 829 + int ret; 830 + 831 + dev_dbg(&wdev->dev, "Adding TUXEDO NB04 Virtual LampArray device.\n"); 832 + 833 + hdev = hid_allocate_device(); 834 + if (IS_ERR(hdev)) 835 + return PTR_ERR(hdev); 836 + *hdev_out = hdev; 837 + 838 + strscpy(hdev->name, "TUXEDO NB04 RGB Lighting", sizeof(hdev->name)); 839 + 840 + hdev->ll_driver = &tux_ll_driver; 841 + hdev->bus = BUS_VIRTUAL; 842 + hdev->vendor = 0x21ba; 843 + hdev->product = 0x0400; 844 + hdev->dev.parent = &wdev->dev; 845 + 846 + ret = hid_add_device(hdev); 847 + if (ret) 848 + hid_destroy_device(hdev); 849 + return ret; 850 + } 851 + 852 + static int tux_probe(struct wmi_device *wdev, const void *context __always_unused) 853 + { 854 + struct tux_driver_data_t *driver_data; 855 + 856 + driver_data = devm_kzalloc(&wdev->dev, sizeof(*driver_data), GFP_KERNEL); 857 + if (!driver_data) 858 + return -ENOMEM; 859 + 860 + dev_set_drvdata(&wdev->dev, driver_data); 861 + 862 + return tux_virt_lamparray_add_device(wdev, &driver_data->hdev); 863 + } 864 + 865 + static void tux_remove(struct wmi_device *wdev) 866 + { 867 + struct tux_driver_data_t *driver_data = dev_get_drvdata(&wdev->dev); 868 + 869 + hid_destroy_device(driver_data->hdev); 870 + } 871 + 872 + static struct wmi_driver tuxedo_nb04_wmi_tux_driver = { 873 + .driver = { 874 + .name = "tuxedo_nb04_wmi_ab", 875 + .probe_type = PROBE_PREFER_ASYNCHRONOUS, 876 + }, 877 + .id_table = tuxedo_nb04_wmi_ab_device_ids, 878 + .probe = tux_probe, 879 + .remove = tux_remove, 880 + .no_singleton = true, 881 + }; 882 + 883 + /* 884 + * We don't know if the WMI API is stable and how unique the GUID is for this 885 + * ODM. To be on the safe side we therefore only run this driver on tested 886 + * devices defined by this list. 887 + */ 888 + static const struct dmi_system_id tested_devices_dmi_table[] __initconst = { 889 + { 890 + // TUXEDO Sirius 16 Gen1 891 + .matches = { 892 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TUXEDO"), 893 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "APX958"), 894 + }, 895 + }, 896 + { 897 + // TUXEDO Sirius 16 Gen2 898 + .matches = { 899 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TUXEDO"), 900 + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AHP958"), 901 + }, 902 + }, 903 + { } 904 + }; 905 + 906 + static int __init tuxedo_nb04_wmi_tux_init(void) 907 + { 908 + if (!dmi_check_system(tested_devices_dmi_table)) 909 + return -ENODEV; 910 + 911 + return wmi_driver_register(&tuxedo_nb04_wmi_tux_driver); 912 + } 913 + module_init(tuxedo_nb04_wmi_tux_init); 914 + 915 + static void __exit tuxedo_nb04_wmi_tux_exit(void) 916 + { 917 + return wmi_driver_unregister(&tuxedo_nb04_wmi_tux_driver); 918 + } 919 + module_exit(tuxedo_nb04_wmi_tux_exit); 920 + 921 + MODULE_DESCRIPTION("Virtual HID LampArray interface for TUXEDO NB04 devices"); 922 + MODULE_AUTHOR("Werner Sembach <wse@tuxedocomputers.com>"); 923 + MODULE_LICENSE("GPL");
+91
drivers/platform/x86/tuxedo/nb04/wmi_util.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * This code gives functions to avoid code duplication while interacting with 4 + * the TUXEDO NB04 wmi interfaces. 5 + * 6 + * Copyright (C) 2024-2025 Werner Sembach <wse@tuxedocomputers.com> 7 + */ 8 + 9 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 + 11 + #include <linux/cleanup.h> 12 + #include <linux/wmi.h> 13 + 14 + #include "wmi_util.h" 15 + 16 + static int __wmi_method_acpi_object_out(struct wmi_device *wdev, 17 + u32 wmi_method_id, 18 + u8 *in, 19 + acpi_size in_len, 20 + union acpi_object **out) 21 + { 22 + struct acpi_buffer acpi_buffer_in = { in_len, in }; 23 + struct acpi_buffer acpi_buffer_out = { ACPI_ALLOCATE_BUFFER, NULL }; 24 + 25 + dev_dbg(&wdev->dev, "Evaluate WMI method: %u in:\n", wmi_method_id); 26 + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, in, in_len); 27 + 28 + acpi_status status = wmidev_evaluate_method(wdev, 0, wmi_method_id, 29 + &acpi_buffer_in, 30 + &acpi_buffer_out); 31 + if (ACPI_FAILURE(status)) { 32 + dev_err(&wdev->dev, "Failed to evaluate WMI method.\n"); 33 + return -EIO; 34 + } 35 + if (!acpi_buffer_out.pointer) { 36 + dev_err(&wdev->dev, "Unexpected empty out buffer.\n"); 37 + return -ENODATA; 38 + } 39 + 40 + *out = acpi_buffer_out.pointer; 41 + 42 + return 0; 43 + } 44 + 45 + static int __wmi_method_buffer_out(struct wmi_device *wdev, 46 + u32 wmi_method_id, 47 + u8 *in, 48 + acpi_size in_len, 49 + u8 *out, 50 + acpi_size out_len) 51 + { 52 + int ret; 53 + 54 + union acpi_object *acpi_object_out __free(kfree) = NULL; 55 + 56 + ret = __wmi_method_acpi_object_out(wdev, wmi_method_id, 57 + in, in_len, 58 + &acpi_object_out); 59 + if (ret) 60 + return ret; 61 + 62 + if (acpi_object_out->type != ACPI_TYPE_BUFFER) { 63 + dev_err(&wdev->dev, "Unexpected out buffer type. Expected: %u Got: %u\n", 64 + ACPI_TYPE_BUFFER, acpi_object_out->type); 65 + return -EIO; 66 + } 67 + if (acpi_object_out->buffer.length < out_len) { 68 + dev_err(&wdev->dev, "Unexpected out buffer length.\n"); 69 + return -EIO; 70 + } 71 + 72 + memcpy(out, acpi_object_out->buffer.pointer, out_len); 73 + 74 + return 0; 75 + } 76 + 77 + int tux_wmi_xx_8in_80out(struct wmi_device *wdev, 78 + enum tux_wmi_xx_8in_80out_methods method, 79 + union tux_wmi_xx_8in_80out_in_t *in, 80 + union tux_wmi_xx_8in_80out_out_t *out) 81 + { 82 + return __wmi_method_buffer_out(wdev, method, in->raw, 8, out->raw, 80); 83 + } 84 + 85 + int tux_wmi_xx_496in_80out(struct wmi_device *wdev, 86 + enum tux_wmi_xx_496in_80out_methods method, 87 + union tux_wmi_xx_496in_80out_in_t *in, 88 + union tux_wmi_xx_496in_80out_out_t *out) 89 + { 90 + return __wmi_method_buffer_out(wdev, method, in->raw, 496, out->raw, 80); 91 + }
+109
drivers/platform/x86/tuxedo/nb04/wmi_util.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* 3 + * This code gives functions to avoid code duplication while interacting with 4 + * the TUXEDO NB04 wmi interfaces. 5 + * 6 + * Copyright (C) 2024-2025 Werner Sembach <wse@tuxedocomputers.com> 7 + */ 8 + 9 + #ifndef TUXEDO_NB04_WMI_UTIL_H 10 + #define TUXEDO_NB04_WMI_UTIL_H 11 + 12 + #include <linux/wmi.h> 13 + 14 + #define TUX_GET_DEVICE_STATUS_DEVICE_ID_TOUCHPAD 1 15 + #define TUX_GET_DEVICE_STATUS_DEVICE_ID_KEYBOARD 2 16 + #define TUX_GET_DEVICE_STATUS_DEVICE_ID_APP_PAGES 3 17 + 18 + #define TUX_GET_DEVICE_STATUS_KBL_TYPE_NONE 0 19 + #define TUX_GET_DEVICE_STATUS_KBL_TYPE_PER_KEY 1 20 + #define TUX_GET_DEVICE_STATUS_KBL_TYPE_FOUR_ZONE 2 21 + #define TUX_GET_DEVICE_STATUS_KBL_TYPE_WHITE_ONLY 3 22 + 23 + #define TUX_GET_DEVICE_STATUS_KEYBOARD_LAYOUT_ANSII 0 24 + #define TUX_GET_DEVICE_STATUS_KEYBOARD_LAYOUT_ISO 1 25 + 26 + #define TUX_GET_DEVICE_STATUS_COLOR_ID_RED 1 27 + #define TUX_GET_DEVICE_STATUS_COLOR_ID_GREEN 2 28 + #define TUX_GET_DEVICE_STATUS_COLOR_ID_YELLOW 3 29 + #define TUX_GET_DEVICE_STATUS_COLOR_ID_BLUE 4 30 + #define TUX_GET_DEVICE_STATUS_COLOR_ID_PURPLE 5 31 + #define TUX_GET_DEVICE_STATUS_COLOR_ID_INDIGO 6 32 + #define TUX_GET_DEVICE_STATUS_COLOR_ID_WHITE 7 33 + 34 + #define TUX_GET_DEVICE_STATUS_APP_PAGES_DASHBOARD BIT(0) 35 + #define TUX_GET_DEVICE_STATUS_APP_PAGES_SYSTEMINFOS BIT(1) 36 + #define TUX_GET_DEVICE_STATUS_APP_PAGES_KBL BIT(2) 37 + #define TUX_GET_DEVICE_STATUS_APP_PAGES_HOTKEYS BIT(3) 38 + 39 + union tux_wmi_xx_8in_80out_in_t { 40 + u8 raw[8]; 41 + struct __packed { 42 + u8 device_type; 43 + u8 reserved[7]; 44 + } get_device_status_in; 45 + }; 46 + 47 + union tux_wmi_xx_8in_80out_out_t { 48 + u8 raw[80]; 49 + struct __packed { 50 + u16 return_status; 51 + u8 device_enabled; 52 + u8 kbl_type; 53 + u8 kbl_side_bar_supported; 54 + u8 keyboard_physical_layout; 55 + u8 app_pages; 56 + u8 per_key_kbl_default_color; 57 + u8 four_zone_kbl_default_color_1; 58 + u8 four_zone_kbl_default_color_2; 59 + u8 four_zone_kbl_default_color_3; 60 + u8 four_zone_kbl_default_color_4; 61 + u8 light_bar_kbl_default_color; 62 + u8 reserved_0[1]; 63 + u16 dedicated_gpu_id; 64 + u8 reserved_1[64]; 65 + } get_device_status_out; 66 + }; 67 + 68 + enum tux_wmi_xx_8in_80out_methods { 69 + TUX_GET_DEVICE_STATUS = 2, 70 + }; 71 + 72 + #define TUX_KBL_SET_MULTIPLE_KEYS_LIGHTING_SETTINGS_COUNT_MAX 120 73 + 74 + union tux_wmi_xx_496in_80out_in_t { 75 + u8 raw[496]; 76 + struct __packed { 77 + u8 reserved[15]; 78 + u8 rgb_configs_cnt; 79 + struct tux_kbl_set_multiple_keys_in_rgb_config_t { 80 + u8 key_id; 81 + u8 red; 82 + u8 green; 83 + u8 blue; 84 + } rgb_configs[TUX_KBL_SET_MULTIPLE_KEYS_LIGHTING_SETTINGS_COUNT_MAX]; 85 + } kbl_set_multiple_keys_in; 86 + }; 87 + 88 + union tux_wmi_xx_496in_80out_out_t { 89 + u8 raw[80]; 90 + struct __packed { 91 + u8 return_value; 92 + u8 reserved[79]; 93 + } kbl_set_multiple_keys_out; 94 + }; 95 + 96 + enum tux_wmi_xx_496in_80out_methods { 97 + TUX_KBL_SET_MULTIPLE_KEYS = 6, 98 + }; 99 + 100 + int tux_wmi_xx_8in_80out(struct wmi_device *wdev, 101 + enum tux_wmi_xx_8in_80out_methods method, 102 + union tux_wmi_xx_8in_80out_in_t *in, 103 + union tux_wmi_xx_8in_80out_out_t *out); 104 + int tux_wmi_xx_496in_80out(struct wmi_device *wdev, 105 + enum tux_wmi_xx_496in_80out_methods method, 106 + union tux_wmi_xx_496in_80out_in_t *in, 107 + union tux_wmi_xx_496in_80out_out_t *out); 108 + 109 + #endif
+3 -7
drivers/platform/x86/xo15-ebook.c
··· 84 84 const struct acpi_device_id *id; 85 85 struct ebook_switch *button; 86 86 struct input_dev *input; 87 - char *name, *class; 88 87 int error; 89 88 90 89 button = kzalloc(sizeof(struct ebook_switch), GFP_KERNEL); ··· 98 99 goto err_free_button; 99 100 } 100 101 101 - name = acpi_device_name(device); 102 - class = acpi_device_class(device); 103 - 104 102 id = acpi_match_acpi_device(ebook_device_ids, device); 105 103 if (!id) { 106 104 dev_err(&device->dev, "Unsupported hid\n"); ··· 105 109 goto err_free_input; 106 110 } 107 111 108 - strcpy(name, XO15_EBOOK_DEVICE_NAME); 109 - sprintf(class, "%s/%s", XO15_EBOOK_CLASS, XO15_EBOOK_SUBCLASS); 112 + strscpy(acpi_device_name(device), XO15_EBOOK_DEVICE_NAME); 113 + strscpy(acpi_device_class(device), XO15_EBOOK_CLASS "/" XO15_EBOOK_SUBCLASS); 110 114 111 115 snprintf(button->phys, sizeof(button->phys), "%s/button/input0", id->id); 112 116 113 - input->name = name; 117 + input->name = acpi_device_name(device); 114 118 input->phys = button->phys; 115 119 input->id.bustype = BUS_HOST; 116 120 input->dev.parent = &device->dev;
+6 -3
drivers/power/supply/power_supply_sysfs.c
··· 110 110 [POWER_SUPPLY_HEALTH_COOL] = "Cool", 111 111 [POWER_SUPPLY_HEALTH_HOT] = "Hot", 112 112 [POWER_SUPPLY_HEALTH_NO_BATTERY] = "No battery", 113 + [POWER_SUPPLY_HEALTH_BLOWN_FUSE] = "Blown fuse", 114 + [POWER_SUPPLY_HEALTH_CELL_IMBALANCE] = "Cell imbalance", 113 115 }; 114 116 115 117 static const char * const POWER_SUPPLY_TECHNOLOGY_TEXT[] = { ··· 140 138 }; 141 139 142 140 static const char * const POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT[] = { 143 - [POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO] = "auto", 144 - [POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE] = "inhibit-charge", 145 - [POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE] = "force-discharge", 141 + [POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO] = "auto", 142 + [POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE] = "inhibit-charge", 143 + [POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE] = "inhibit-charge-awake", 144 + [POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE] = "force-discharge", 146 145 }; 147 146 148 147 static struct power_supply_attr power_supply_attrs[] __ro_after_init = {
+1
drivers/power/supply/test_power.c
··· 228 228 .property_is_writeable = test_power_battery_property_is_writeable, 229 229 .charge_behaviours = BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) 230 230 | BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE) 231 + | BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE) 231 232 | BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE), 232 233 .charge_types = BIT(POWER_SUPPLY_CHARGE_TYPE_STANDARD) 233 234 | BIT(POWER_SUPPLY_CHARGE_TYPE_LONGLIFE)
+3 -2
include/linux/intel_vsec.h
··· 139 139 } 140 140 141 141 #if IS_ENABLED(CONFIG_INTEL_VSEC) 142 - void intel_vsec_register(struct pci_dev *pdev, 142 + int intel_vsec_register(struct pci_dev *pdev, 143 143 struct intel_vsec_platform_info *info); 144 144 #else 145 - static inline void intel_vsec_register(struct pci_dev *pdev, 145 + static inline int intel_vsec_register(struct pci_dev *pdev, 146 146 struct intel_vsec_platform_info *info) 147 147 { 148 + return -ENODEV; 148 149 } 149 150 #endif 150 151 #endif
+2 -2
include/linux/platform_data/mlxreg.h
··· 209 209 * @items: same type components with the hotplug capability; 210 210 * @irq: platform interrupt number; 211 211 * @regmap: register map of parent device; 212 - * @counter: number of the components with the hotplug capability; 212 + * @count: number of the components with the hotplug capability; 213 213 * @cell: location of top aggregation interrupt register; 214 214 * @mask: top aggregation interrupt common mask; 215 215 * @cell_low: location of low aggregation interrupt register; ··· 224 224 struct mlxreg_core_item *items; 225 225 int irq; 226 226 void *regmap; 227 - int counter; 227 + int count; 228 228 u32 cell; 229 229 u32 mask; 230 230 u32 cell_low;
+19
include/linux/platform_data/x86/asus-wmi.h
··· 157 157 #define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00 158 158 #define ASUS_WMI_DSTS_LIGHTBAR_MASK 0x0000000F 159 159 160 + enum asus_ally_mcu_hack { 161 + ASUS_WMI_ALLY_MCU_HACK_INIT, 162 + ASUS_WMI_ALLY_MCU_HACK_ENABLED, 163 + ASUS_WMI_ALLY_MCU_HACK_DISABLED, 164 + }; 165 + 160 166 #if IS_REACHABLE(CONFIG_ASUS_WMI) 167 + void set_ally_mcu_hack(enum asus_ally_mcu_hack status); 168 + void set_ally_mcu_powersave(bool enabled); 169 + int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval); 161 170 int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval); 162 171 #else 172 + static inline void set_ally_mcu_hack(enum asus_ally_mcu_hack status) 173 + { 174 + } 175 + static inline void set_ally_mcu_powersave(bool enabled) 176 + { 177 + } 178 + static inline int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval) 179 + { 180 + return -ENODEV; 181 + } 163 182 static inline int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, 164 183 u32 *retval) 165 184 {
+3
include/linux/power_supply.h
··· 71 71 POWER_SUPPLY_HEALTH_COOL, 72 72 POWER_SUPPLY_HEALTH_HOT, 73 73 POWER_SUPPLY_HEALTH_NO_BATTERY, 74 + POWER_SUPPLY_HEALTH_BLOWN_FUSE, 75 + POWER_SUPPLY_HEALTH_CELL_IMBALANCE, 74 76 }; 75 77 76 78 enum { ··· 214 212 enum power_supply_charge_behaviour { 215 213 POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO = 0, 216 214 POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE, 215 + POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE, 217 216 POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE, 218 217 }; 219 218
-39
include/linux/sony-laptop.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - #ifndef _SONYLAPTOP_H_ 3 - #define _SONYLAPTOP_H_ 4 - 5 - #include <linux/types.h> 6 - 7 - #ifdef __KERNEL__ 8 - 9 - /* used only for communication between v4l and sony-laptop */ 10 - 11 - #define SONY_PIC_COMMAND_GETCAMERA 1 /* obsolete */ 12 - #define SONY_PIC_COMMAND_SETCAMERA 2 13 - #define SONY_PIC_COMMAND_GETCAMERABRIGHTNESS 3 /* obsolete */ 14 - #define SONY_PIC_COMMAND_SETCAMERABRIGHTNESS 4 15 - #define SONY_PIC_COMMAND_GETCAMERACONTRAST 5 /* obsolete */ 16 - #define SONY_PIC_COMMAND_SETCAMERACONTRAST 6 17 - #define SONY_PIC_COMMAND_GETCAMERAHUE 7 /* obsolete */ 18 - #define SONY_PIC_COMMAND_SETCAMERAHUE 8 19 - #define SONY_PIC_COMMAND_GETCAMERACOLOR 9 /* obsolete */ 20 - #define SONY_PIC_COMMAND_SETCAMERACOLOR 10 21 - #define SONY_PIC_COMMAND_GETCAMERASHARPNESS 11 /* obsolete */ 22 - #define SONY_PIC_COMMAND_SETCAMERASHARPNESS 12 23 - #define SONY_PIC_COMMAND_GETCAMERAPICTURE 13 /* obsolete */ 24 - #define SONY_PIC_COMMAND_SETCAMERAPICTURE 14 25 - #define SONY_PIC_COMMAND_GETCAMERAAGC 15 /* obsolete */ 26 - #define SONY_PIC_COMMAND_SETCAMERAAGC 16 27 - #define SONY_PIC_COMMAND_GETCAMERADIRECTION 17 /* obsolete */ 28 - #define SONY_PIC_COMMAND_GETCAMERAROMVERSION 18 /* obsolete */ 29 - #define SONY_PIC_COMMAND_GETCAMERAREVISION 19 /* obsolete */ 30 - 31 - #if IS_ENABLED(CONFIG_SONY_LAPTOP) 32 - int sony_pic_camera_command(int command, u8 value); 33 - #else 34 - static inline int sony_pic_camera_command(int command, u8 value) { return 0; } 35 - #endif 36 - 37 - #endif /* __KERNEL__ */ 38 - 39 - #endif /* _SONYLAPTOP_H_ */
+26
include/uapi/linux/isst_if.h
··· 375 375 __u16 trl_freq_mhz[TRL_MAX_LEVELS][TRL_MAX_BUCKETS]; 376 376 }; 377 377 378 + #define MAX_FABRIC_COUNT 8 379 + 380 + /** 381 + * struct isst_perf_level_fabric_info - Structure to get SST-PP fabric details 382 + * @socket_id: Socket/package id 383 + * @power_domain_id: Power Domain id 384 + * @level: SST-PP level for which caller wants to get information 385 + * @max_fabrics: Count of fabrics in resonse 386 + * @p0_fabric_freq_mhz: Fabric (Uncore) maximum frequency 387 + * @p1_fabric_freq_mhz: Fabric (Uncore) TDP frequency 388 + * @pm_fabric_freq_mhz: Fabric (Uncore) minimum frequency 389 + * 390 + * Structure used to get information on frequencies for fabrics. 391 + */ 392 + struct isst_perf_level_fabric_info { 393 + __u8 socket_id; 394 + __u8 power_domain_id; 395 + __u16 level; 396 + __u16 max_fabrics; 397 + __u16 p0_fabric_freq_mhz[MAX_FABRIC_COUNT]; 398 + __u16 p1_fabric_freq_mhz[MAX_FABRIC_COUNT]; 399 + __u16 pm_fabric_freq_mhz[MAX_FABRIC_COUNT]; 400 + }; 401 + 378 402 /** 379 403 * struct isst_perf_level_cpu_mask - Structure to get SST-PP level CPU mask 380 404 * @socket_id: Socket/package id ··· 495 471 #define ISST_IF_GET_BASE_FREQ_INFO _IOR(ISST_IF_MAGIC, 14, struct isst_base_freq_info *) 496 472 #define ISST_IF_GET_BASE_FREQ_CPU_MASK _IOR(ISST_IF_MAGIC, 15, struct isst_perf_level_cpu_mask *) 497 473 #define ISST_IF_GET_TURBO_FREQ_INFO _IOR(ISST_IF_MAGIC, 16, struct isst_turbo_freq_info *) 474 + #define ISST_IF_GET_PERF_LEVEL_FABRIC_INFO _IOR(ISST_IF_MAGIC, 17,\ 475 + struct isst_perf_level_fabric_info *) 498 476 499 477 #endif
+13 -2
tools/power/x86/intel-speed-select/isst-config.c
··· 16 16 int arg; 17 17 }; 18 18 19 - static const char *version_str = "v1.22"; 19 + static const char *version_str = "v1.23"; 20 20 21 21 static const int supported_api_ver = 3; 22 22 static struct isst_if_platform_info isst_platform_info; ··· 26 26 27 27 static int cpu_model; 28 28 static int cpu_stepping; 29 + static int extended_family; 29 30 30 31 #define MAX_CPUS_IN_ONE_REQ 512 31 32 static short max_target_cpus; ··· 144 143 return 0; 145 144 } 146 145 146 + static int is_dmr_plus_platform(void) 147 + { 148 + if (extended_family == 0x04) 149 + return 1; 150 + 151 + return 0; 152 + } 153 + 147 154 static int update_cpu_model(void) 148 155 { 149 156 unsigned int ebx, ecx, edx; ··· 159 150 160 151 __cpuid(1, fms, ebx, ecx, edx); 161 152 family = (fms >> 8) & 0xf; 153 + extended_family = (fms >> 20) & 0x0f; 162 154 cpu_model = (fms >> 4) & 0xf; 163 155 if (family == 6 || family == 0xf) 164 156 cpu_model += ((fms >> 16) & 0xf) << 4; ··· 1527 1517 usleep(2000); 1528 1518 1529 1519 /* Adjusting uncore freq */ 1530 - isst_adjust_uncore_freq(id, tdp_level, &ctdp_level); 1520 + if (!is_dmr_plus_platform()) 1521 + isst_adjust_uncore_freq(id, tdp_level, &ctdp_level); 1531 1522 1532 1523 fprintf(stderr, "Option is set to online/offline\n"); 1533 1524 ctdp_level.core_cpumask_size =
+12
tools/power/x86/intel-speed-select/isst-core-tpmi.c
··· 227 227 static int tpmi_get_tdp_info(struct isst_id *id, int config_index, 228 228 struct isst_pkg_ctdp_level_info *ctdp_level) 229 229 { 230 + struct isst_perf_level_fabric_info fabric_info; 230 231 struct isst_perf_level_data_info info; 231 232 int ret; 232 233 ··· 253 252 ctdp_level->uncore_p0 = info.p0_fabric_freq_mhz; 254 253 ctdp_level->uncore_p1 = info.p1_fabric_freq_mhz; 255 254 ctdp_level->uncore_pm = info.pm_fabric_freq_mhz; 255 + 256 + fabric_info.socket_id = id->pkg; 257 + fabric_info.power_domain_id = id->punit; 258 + fabric_info.level = config_index; 259 + 260 + ret = tpmi_process_ioctl(ISST_IF_GET_PERF_LEVEL_FABRIC_INFO, &fabric_info); 261 + if (ret != -1) { 262 + ctdp_level->uncore1_p0 = fabric_info.p0_fabric_freq_mhz[1]; 263 + ctdp_level->uncore1_p1 = fabric_info.p1_fabric_freq_mhz[1]; 264 + ctdp_level->uncore1_pm = fabric_info.pm_fabric_freq_mhz[1]; 265 + } 256 266 257 267 debug_printf 258 268 ("cpu:%d ctdp:%d CONFIG_TDP_GET_TDP_INFO tdp_ratio:%d pkg_tdp:%d ctdp_level->t_proc_hot:%d\n",
+20
tools/power/x86/intel-speed-select/isst-display.c
··· 460 460 format_and_print(outf, level + 2, header, value); 461 461 } 462 462 463 + if (ctdp_level->uncore1_p1) { 464 + snprintf(header, sizeof(header), "uncore-1-frequency-base(MHz)"); 465 + snprintf(value, sizeof(value), "%d", 466 + ctdp_level->uncore1_p1 * isst_get_disp_freq_multiplier()); 467 + format_and_print(outf, level + 2, header, value); 468 + } 469 + if (ctdp_level->uncore1_pm) { 470 + snprintf(header, sizeof(header), "uncore-1-frequency-min(MHz)"); 471 + snprintf(value, sizeof(value), "%d", 472 + ctdp_level->uncore1_pm * isst_get_disp_freq_multiplier()); 473 + format_and_print(outf, level + 2, header, value); 474 + } 475 + 476 + if (ctdp_level->uncore1_p0) { 477 + snprintf(header, sizeof(header), "uncore-1-frequency-max(MHz)"); 478 + snprintf(value, sizeof(value), "%d", 479 + ctdp_level->uncore1_p0 * isst_get_disp_freq_multiplier()); 480 + format_and_print(outf, level + 2, header, value); 481 + } 482 + 463 483 if (ctdp_level->mem_freq) { 464 484 snprintf(header, sizeof(header), "max-mem-frequency(MHz)"); 465 485 snprintf(value, sizeof(value), "%d",
+3
tools/power/x86/intel-speed-select/isst.h
··· 147 147 int uncore_p0; 148 148 int uncore_p1; 149 149 int uncore_pm; 150 + int uncore1_p0; 151 + int uncore1_p1; 152 + int uncore1_pm; 150 153 int sse_p1; 151 154 int avx2_p1; 152 155 int avx512_p1;