Merge tag 'platform-drivers-x86-v6.1-1' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 5 Oct 2022 17:38:24 +0000 (10:38 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 5 Oct 2022 17:38:24 +0000 (10:38 -0700)
Pull x86 platform driver updates from Hans de Goede:

 - AMD Platform Management Framework (PMF) driver with AMT and QnQF
   support

 - AMD PMC: Improved logging for debugging s2idle issues

 - Big refactor of the ACPI/x86 backlight handling, ensuring that we
   only register 1 /sys/class/backlight device per LCD panel

 - Microsoft Surface:
    - Surface Laptop Go 2 support
    - Surface Pro 8 HID sensor support

 - Asus WMI:
    - Lots of cleanups
    - Support for TUF RGB keyboard backlight control
    - Add support for ROG X13 tablet mode

 - Siemens Simatic: IPC227G and IPC427G support

 - Toshiba ACPI laptop driver: Fan hwmon and battery ECO mode support

 - tools/power/x86/intel-speed-select: Various improvements

 - Various cleanups

 - Various small bugfixes

* tag 'platform-drivers-x86-v6.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (153 commits)
  platform/x86: use PLATFORM_DEVID_NONE instead of -1
  platform/x86/amd: pmc: Dump idle mask during "check" stage instead
  platform/x86/intel/wmi: thunderbolt: Use dev_groups callback
  platform/x86/amd: pmc: remove CONFIG_DEBUG_FS checks
  platform/surface: Split memcpy() of struct ssam_event flexible array
  platform/x86: compal-laptop: Get rid of a few forward declarations
  platform/x86: intel-uncore-freq: Use sysfs_emit() to instead of scnprintf()
  platform/x86: dell-smbios-base: Use sysfs_emit()
  platform/x86/amd/pmf: Remove unused power_delta instances
  platform/x86/amd/pmf: install notify handler after acpi init
  Documentation/ABI/testing/sysfs-amd-pmf: Add ABI doc for AMD PMF
  platform/x86/amd/pmf: Add sysfs to toggle CnQF
  platform/x86/amd/pmf: Add support for CnQF
  platform/x86/amd: pmc: Fix build without debugfs
  platform/x86: hp-wmi: Support touchpad on/off
  platform/x86: int3472/discrete: Drop a forward declaration
  platform/x86: toshiba_acpi: change turn_on_panel_on_resume to static
  platform/x86: wmi: Drop forward declaration of static functions
  platform/x86: toshiba_acpi: Remove duplicate include
  platform/x86: msi-laptop: Change DMI match / alias strings to fix module autoloading
  ...

102 files changed:
Documentation/ABI/testing/sysfs-amd-pmc [new file with mode: 0644]
Documentation/ABI/testing/sysfs-amd-pmf [new file with mode: 0644]
Documentation/ABI/testing/sysfs-class-power
Documentation/ABI/testing/sysfs-platform-asus-wmi
Documentation/gpu/todo.rst
MAINTAINERS
drivers/acpi/Kconfig
drivers/acpi/acpi_video.c
drivers/acpi/sleep.h
drivers/acpi/video_detect.c
drivers/acpi/x86/s2idle.c
drivers/gpio/Kconfig
drivers/gpio/gpio-f7188x.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/gma500/Kconfig
drivers/gpu/drm/i915/Kconfig
drivers/gpu/drm/i915/display/intel_acpi.c
drivers/gpu/drm/i915/display/intel_acpi.h
drivers/gpu/drm/i915/display/intel_backlight.c
drivers/gpu/drm/i915/display/intel_display.c
drivers/gpu/drm/nouveau/nouveau_acpi.c
drivers/gpu/drm/nouveau/nouveau_acpi.h
drivers/gpu/drm/nouveau/nouveau_backlight.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_legacy_encoders.c
drivers/leds/simple/simatic-ipc-leds-gpio.c
drivers/platform/mellanox/mlxreg-lc.c
drivers/platform/surface/surface3_power.c
drivers/platform/surface/surface_acpi_notify.c
drivers/platform/x86/Kconfig
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/acerhdf.c
drivers/platform/x86/amd/Kconfig
drivers/platform/x86/amd/Makefile
drivers/platform/x86/amd/hsmp.c
drivers/platform/x86/amd/pmc.c
drivers/platform/x86/amd/pmf/Kconfig [new file with mode: 0644]
drivers/platform/x86/amd/pmf/Makefile [new file with mode: 0644]
drivers/platform/x86/amd/pmf/acpi.c [new file with mode: 0644]
drivers/platform/x86/amd/pmf/auto-mode.c [new file with mode: 0644]
drivers/platform/x86/amd/pmf/cnqf.c [new file with mode: 0644]
drivers/platform/x86/amd/pmf/core.c [new file with mode: 0644]
drivers/platform/x86/amd/pmf/pmf.h [new file with mode: 0644]
drivers/platform/x86/amd/pmf/sps.c [new file with mode: 0644]
drivers/platform/x86/amilo-rfkill.c
drivers/platform/x86/apple-gmux.c
drivers/platform/x86/asus-laptop.c
drivers/platform/x86/asus-nb-wmi.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/asus-wmi.h
drivers/platform/x86/compal-laptop.c
drivers/platform/x86/dell/alienware-wmi.c
drivers/platform/x86/dell/dcdbas.c
drivers/platform/x86/dell/dell-laptop.c
drivers/platform/x86/dell/dell-smbios-base.c
drivers/platform/x86/dell/dell-wmi-base.c
drivers/platform/x86/dell/dell-wmi-privacy.c
drivers/platform/x86/dell/dell-wmi-sysman/sysman.c
drivers/platform/x86/dell/dell_rbu.c
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/eeepc-wmi.c
drivers/platform/x86/fujitsu-laptop.c
drivers/platform/x86/hdaps.c
drivers/platform/x86/hp-wmi.c
drivers/platform/x86/huawei-wmi.c
drivers/platform/x86/intel/chtwc_int33fe.c
drivers/platform/x86/intel/int3472/discrete.c
drivers/platform/x86/intel/oaktrail.c
drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
drivers/platform/x86/intel/wmi/thunderbolt.c
drivers/platform/x86/mlx-platform.c
drivers/platform/x86/msi-laptop.c
drivers/platform/x86/nvidia-wmi-ec-backlight.c
drivers/platform/x86/panasonic-laptop.c
drivers/platform/x86/pmc_atom.c
drivers/platform/x86/samsung-laptop.c
drivers/platform/x86/simatic-ipc.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/tc1100-wmi.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/topstar-laptop.c
drivers/platform/x86/toshiba_acpi.c
drivers/platform/x86/winmate-fm07-keys.c
drivers/platform/x86/wmi.c
include/acpi/video.h
include/linux/acpi.h
include/linux/platform_data/x86/asus-wmi.h
include/linux/platform_data/x86/nvidia-wmi-ec-backlight.h [new file with mode: 0644]
include/linux/platform_data/x86/pmc_atom.h
include/linux/platform_data/x86/simatic-ipc-base.h
include/linux/platform_data/x86/simatic-ipc.h
include/linux/suspend.h
kernel/power/suspend.c
tools/power/x86/intel-speed-select/hfi-events.c
tools/power/x86/intel-speed-select/isst-config.c
tools/power/x86/intel-speed-select/isst-core.c
tools/power/x86/intel-speed-select/isst-daemon.c
tools/power/x86/intel-speed-select/isst-display.c
tools/power/x86/intel-speed-select/isst.h

diff --git a/Documentation/ABI/testing/sysfs-amd-pmc b/Documentation/ABI/testing/sysfs-amd-pmc
new file mode 100644 (file)
index 0000000..c421b72
--- /dev/null
@@ -0,0 +1,13 @@
+What:          /sys/bus/platform/drivers/amd_pmc/*/smu_fw_version
+Date:          October 2022
+Contact:       Mario Limonciello <mario.limonciello@amd.com>
+Description:   Reading this file reports the version of the firmware loaded to
+               System Management Unit (SMU) contained in AMD CPUs and
+               APUs.
+
+What:          /sys/bus/platform/drivers/amd_pmc/*/smu_program
+Date:          October 2022
+Contact:       Mario Limonciello <mario.limonciello@amd.com>
+Description:   Reading this file reports the program corresponding to the SMU
+               firmware version.  The program field is used to disambiguate two
+               APU/CPU models that can share the same firmware binary.
diff --git a/Documentation/ABI/testing/sysfs-amd-pmf b/Documentation/ABI/testing/sysfs-amd-pmf
new file mode 100644 (file)
index 0000000..7fc0e1c
--- /dev/null
@@ -0,0 +1,13 @@
+What:          /sys/devices/platform/*/cnqf_enable
+Date:          September 2022
+Contact:       Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+Description:   Reading this file tells if the AMD Platform Management(PMF)
+               Cool n Quiet Framework(CnQF) feature is enabled or not.
+
+               This feature is not enabled by default and gets only turned on
+               if OEM BIOS passes a "flag" to PMF ACPI function (index 11 or 12)
+               or in case the user writes "on".
+
+               To turn off CnQF user can write "off" to the sysfs node.
+               Note: Systems that support auto mode will not have this sysfs file
+               available.
index a9ce63c..e434fc5 100644 (file)
@@ -364,7 +364,10 @@ Date:              April 2019
 Contact:       linux-pm@vger.kernel.org
 Description:
                Represents a battery percentage level, above which charging will
-               stop.
+               stop. Not all hardware is capable of setting this to an arbitrary
+               percentage. Drivers will round written values to the nearest
+               supported value. Reading back the value will show the actual
+               threshold set by the driver.
 
                Access: Read, Write
 
index 0488573..a77a004 100644 (file)
@@ -57,3 +57,44 @@ Description:
                        * 0 - default,
                        * 1 - overboost,
                        * 2 - silent
+
+What:          /sys/devices/platform/<platform>/gpu_mux_mode
+Date:          Aug 2022
+KernelVersion: 6.1
+Contact:       "Luke Jones" <luke@ljones.dev>
+Description:
+               Switch the GPU hardware MUX mode. Laptops with this feature can
+               can be toggled to boot with only the dGPU (discrete mode) or in
+               standard Optimus/Hybrid mode. On switch a reboot is required:
+
+                       * 0 - Discrete GPU,
+                       * 1 - Optimus/Hybrid,
+
+What:          /sys/devices/platform/<platform>/dgpu_disable
+Date:          Aug 2022
+KernelVersion: 5.17
+Contact:       "Luke Jones" <luke@ljones.dev>
+Description:
+               Disable discrete GPU:
+                       * 0 - Enable dGPU,
+                       * 1 - Disable dGPU
+
+What:          /sys/devices/platform/<platform>/egpu_enable
+Date:          Aug 2022
+KernelVersion: 5.17
+Contact:       "Luke Jones" <luke@ljones.dev>
+Description:
+               Enable the external GPU paired with ROG X-Flow laptops.
+               Toggling this setting will also trigger ACPI to disable the dGPU:
+
+                       * 0 - Disable,
+                       * 1 - Enable
+
+What:          /sys/devices/platform/<platform>/panel_od
+Date:          Aug 2022
+KernelVersion: 5.17
+Contact:       "Luke Jones" <luke@ljones.dev>
+Description:
+               Enable an LCD response-time boost to reduce or remove ghosting:
+                       * 0 - Disable,
+                       * 1 - Enable
index 513b20c..7ff8955 100644 (file)
@@ -715,6 +715,74 @@ Contact: Sam Ravnborg
 
 Level: Advanced
 
+Brightness handling on devices with multiple internal panels
+============================================================
+
+On x86/ACPI devices there can be multiple backlight firmware interfaces:
+(ACPI) video, vendor specific and others. As well as direct/native (PWM)
+register programming by the KMS driver.
+
+To deal with this backlight drivers used on x86/ACPI call
+acpi_video_get_backlight_type() which has heuristics (+quirks) to select
+which backlight interface to use; and backlight drivers which do not match
+the returned type will not register themselves, so that only one backlight
+device gets registered (in a single GPU setup, see below).
+
+At the moment this more or less assumes that there will only
+be 1 (internal) panel on a system.
+
+On systems with 2 panels this may be a problem, depending on
+what interface acpi_video_get_backlight_type() selects:
+
+1. native: in this case the KMS driver is expected to know which backlight
+   device belongs to which output so everything should just work.
+2. video: this does support controlling multiple backlights, but some work
+   will need to be done to get the output <-> backlight device mapping
+
+The above assumes both panels will require the same backlight interface type.
+Things will break on systems with multiple panels where the 2 panels need
+a different type of control. E.g. one panel needs ACPI video backlight control,
+where as the other is using native backlight control. Currently in this case
+only one of the 2 required backlight devices will get registered, based on
+the acpi_video_get_backlight_type() return value.
+
+If this (theoretical) case ever shows up, then supporting this will need some
+work. A possible solution here would be to pass a device and connector-name
+to acpi_video_get_backlight_type() so that it can deal with this.
+
+Note in a way we already have a case where userspace sees 2 panels,
+in dual GPU laptop setups with a mux. On those systems we may see
+either 2 native backlight devices; or 2 native backlight devices.
+
+Userspace already has code to deal with this by detecting if the related
+panel is active (iow which way the mux between the GPU and the panels
+points) and then uses that backlight device. Userspace here very much
+assumes a single panel though. It picks only 1 of the 2 backlight devices
+and then only uses that one.
+
+Note that all userspace code (that I know off) is currently hardcoded
+to assume a single panel.
+
+Before the recent changes to not register multiple (e.g. video + native)
+/sys/class/backlight devices for a single panel (on a single GPU laptop),
+userspace would see multiple backlight devices all controlling the same
+backlight.
+
+To deal with this userspace had to always picks one preferred device under
+/sys/class/backlight and will ignore the others. So to support brightness
+control on multiple panels userspace will need to be updated too.
+
+There are plans to allow brightness control through the KMS API by adding
+a "display brightness" property to drm_connector objects for panels. This
+solves a number of issues with the /sys/class/backlight API, including not
+being able to map a sysfs backlight device to a specific connector. Any
+userspace changes to add support for brightness control on devices with
+multiple panels really should build on top of this new KMS property.
+
+Contact: Hans de Goede
+
+Level: Advanced
+
 Outside DRM
 ===========
 
index 756e1f5..5028318 100644 (file)
@@ -1027,6 +1027,13 @@ L:       platform-driver-x86@vger.kernel.org
 S:     Maintained
 F:     drivers/platform/x86/amd/pmc.c
 
+AMD PMF DRIVER
+M:     Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+L:     platform-driver-x86@vger.kernel.org
+S:     Maintained
+F:     Documentation/ABI/testing/sysfs-amd-pmf
+F:     drivers/platform/x86/amd/pmf/
+
 AMD HSMP DRIVER
 M:     Naveen Krishna Chatradhi <naveenkrishna.chatradhi@amd.com>
 R:     Carlos Bilbao <carlos.bilbao@amd.com>
@@ -14542,6 +14549,7 @@ M:      Daniel Dadap <ddadap@nvidia.com>
 L:     platform-driver-x86@vger.kernel.org
 S:     Supported
 F:     drivers/platform/x86/nvidia-wmi-ec-backlight.c
+F:     include/linux/platform_data/x86/nvidia-wmi-ec-backlight.h
 
 NVM EXPRESS DRIVER
 M:     Keith Busch <kbusch@kernel.org>
index bc9ddd2..473241b 100644 (file)
@@ -209,6 +209,7 @@ config ACPI_VIDEO
        tristate "Video"
        depends on BACKLIGHT_CLASS_DEVICE
        depends on INPUT
+       depends on ACPI_WMI || !X86
        select THERMAL
        help
          This driver implements the ACPI Extensions For Display Adapters
index 6d209ea..3295364 100644 (file)
@@ -47,9 +47,6 @@ module_param(brightness_switch_enabled, bool, 0644);
 static bool allow_duplicates;
 module_param(allow_duplicates, bool, 0644);
 
-static int disable_backlight_sysfs_if = -1;
-module_param(disable_backlight_sysfs_if, int, 0444);
-
 #define REPORT_OUTPUT_KEY_EVENTS               0x01
 #define REPORT_BRIGHTNESS_KEY_EVENTS           0x02
 static int report_key_events = -1;
@@ -73,6 +70,16 @@ module_param(device_id_scheme, bool, 0444);
 static int only_lcd = -1;
 module_param(only_lcd, int, 0444);
 
+/*
+ * Display probing is known to take up to 5 seconds, so delay the fallback
+ * backlight registration by 5 seconds + 3 seconds for some extra margin.
+ */
+static int register_backlight_delay = 8;
+module_param(register_backlight_delay, int, 0444);
+MODULE_PARM_DESC(register_backlight_delay,
+       "Delay in seconds before doing fallback (non GPU driver triggered) "
+       "backlight registration, set to 0 to disable.");
+
 static bool may_report_brightness_keys;
 static int register_count;
 static DEFINE_MUTEX(register_count_mutex);
@@ -81,7 +88,9 @@ static LIST_HEAD(video_bus_head);
 static int acpi_video_bus_add(struct acpi_device *device);
 static int acpi_video_bus_remove(struct acpi_device *device);
 static void acpi_video_bus_notify(struct acpi_device *device, u32 event);
-void acpi_video_detect_exit(void);
+static void acpi_video_bus_register_backlight_work(struct work_struct *ignored);
+static DECLARE_DELAYED_WORK(video_bus_register_backlight_work,
+                           acpi_video_bus_register_backlight_work);
 
 /*
  * Indices in the _BCL method response: the first two items are special,
@@ -382,14 +391,6 @@ static int video_set_bqc_offset(const struct dmi_system_id *d)
        return 0;
 }
 
-static int video_disable_backlight_sysfs_if(
-       const struct dmi_system_id *d)
-{
-       if (disable_backlight_sysfs_if == -1)
-               disable_backlight_sysfs_if = 1;
-       return 0;
-}
-
 static int video_set_device_id_scheme(const struct dmi_system_id *d)
 {
        device_id_scheme = true;
@@ -463,56 +464,6 @@ static const struct dmi_system_id video_dmi_table[] = {
        },
 
        /*
-        * Some machines have a broken acpi-video interface for brightness
-        * control, but still need an acpi_video_device_lcd_set_level() call
-        * on resume to turn the backlight power on.  We Enable backlight
-        * control on these systems, but do not register a backlight sysfs
-        * as brightness control does not work.
-        */
-       {
-        /* https://bugzilla.kernel.org/show_bug.cgi?id=21012 */
-        .callback = video_disable_backlight_sysfs_if,
-        .ident = "Toshiba Portege R700",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R700"),
-               },
-       },
-       {
-        /* https://bugs.freedesktop.org/show_bug.cgi?id=82634 */
-        .callback = video_disable_backlight_sysfs_if,
-        .ident = "Toshiba Portege R830",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R830"),
-               },
-       },
-       {
-        /* https://bugzilla.kernel.org/show_bug.cgi?id=21012 */
-        .callback = video_disable_backlight_sysfs_if,
-        .ident = "Toshiba Satellite R830",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE R830"),
-               },
-       },
-       {
-        .callback = video_disable_backlight_sysfs_if,
-        .ident = "Toshiba Satellite Z830",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE Z830"),
-               },
-       },
-       {
-        .callback = video_disable_backlight_sysfs_if,
-        .ident = "Toshiba Portege Z830",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE Z830"),
-               },
-       },
-       /*
         * Some machine's _DOD IDs don't have bit 31(Device ID Scheme) set
         * but the IDs actually follow the Device ID Scheme.
         */
@@ -1774,9 +1725,6 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
        if (result)
                return;
 
-       if (disable_backlight_sysfs_if > 0)
-               return;
-
        name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
        if (!name)
                return;
@@ -1875,8 +1823,6 @@ static int acpi_video_bus_register_backlight(struct acpi_video_bus *video)
        if (video->backlight_registered)
                return 0;
 
-       acpi_video_run_bcl_for_osi(video);
-
        if (acpi_video_get_backlight_type() != acpi_backlight_video)
                return 0;
 
@@ -2102,7 +2048,11 @@ static int acpi_video_bus_add(struct acpi_device *device)
        list_add_tail(&video->entry, &video_bus_head);
        mutex_unlock(&video_list_lock);
 
-       acpi_video_bus_register_backlight(video);
+       /*
+        * The userspace visible backlight_device gets registered separately
+        * from acpi_video_register_backlight().
+        */
+       acpi_video_run_bcl_for_osi(video);
        acpi_video_bus_add_notify_handler(video);
 
        return 0;
@@ -2127,20 +2077,25 @@ static int acpi_video_bus_remove(struct acpi_device *device)
 
        video = acpi_driver_data(device);
 
-       acpi_video_bus_remove_notify_handler(video);
-       acpi_video_bus_unregister_backlight(video);
-       acpi_video_bus_put_devices(video);
-
        mutex_lock(&video_list_lock);
        list_del(&video->entry);
        mutex_unlock(&video_list_lock);
 
+       acpi_video_bus_remove_notify_handler(video);
+       acpi_video_bus_unregister_backlight(video);
+       acpi_video_bus_put_devices(video);
+
        kfree(video->attached_array);
        kfree(video);
 
        return 0;
 }
 
+static void acpi_video_bus_register_backlight_work(struct work_struct *ignored)
+{
+       acpi_video_register_backlight();
+}
+
 static int __init is_i740(struct pci_dev *dev)
 {
        if (dev->device == 0x00D1)
@@ -2251,6 +2206,18 @@ int acpi_video_register(void)
         */
        register_count = 1;
 
+       /*
+        * acpi_video_bus_add() skips registering the userspace visible
+        * backlight_device. The intend is for this to be registered by the
+        * drm/kms driver calling acpi_video_register_backlight() *after* it is
+        * done setting up its own native backlight device. The delayed work
+        * ensures that acpi_video_register_backlight() always gets called
+        * eventually, in case there is no drm/kms driver or it is disabled.
+        */
+       if (register_backlight_delay)
+               schedule_delayed_work(&video_bus_register_backlight_work,
+                                     register_backlight_delay * HZ);
+
 leave:
        mutex_unlock(&register_count_mutex);
        return ret;
@@ -2261,6 +2228,7 @@ void acpi_video_unregister(void)
 {
        mutex_lock(&register_count_mutex);
        if (register_count) {
+               cancel_delayed_work_sync(&video_bus_register_backlight_work);
                acpi_bus_unregister_driver(&acpi_video_bus);
                register_count = 0;
                may_report_brightness_keys = false;
@@ -2269,19 +2237,16 @@ void acpi_video_unregister(void)
 }
 EXPORT_SYMBOL(acpi_video_unregister);
 
-void acpi_video_unregister_backlight(void)
+void acpi_video_register_backlight(void)
 {
        struct acpi_video_bus *video;
 
-       mutex_lock(&register_count_mutex);
-       if (register_count) {
-               mutex_lock(&video_list_lock);
-               list_for_each_entry(video, &video_bus_head, entry)
-                       acpi_video_bus_unregister_backlight(video);
-               mutex_unlock(&video_list_lock);
-       }
-       mutex_unlock(&register_count_mutex);
+       mutex_lock(&video_list_lock);
+       list_for_each_entry(video, &video_bus_head, entry)
+               acpi_video_bus_register_backlight(video);
+       mutex_unlock(&video_list_lock);
 }
+EXPORT_SYMBOL(acpi_video_register_backlight);
 
 bool acpi_video_handles_brightness_key_presses(void)
 {
@@ -2318,7 +2283,6 @@ static int __init acpi_video_init(void)
 
 static void __exit acpi_video_exit(void)
 {
-       acpi_video_detect_exit();
        acpi_video_unregister();
 }
 
index 7fe41ee..d960a23 100644 (file)
@@ -18,6 +18,7 @@ static inline acpi_status acpi_set_waking_vector(u32 wakeup_address)
 extern int acpi_s2idle_begin(void);
 extern int acpi_s2idle_prepare(void);
 extern int acpi_s2idle_prepare_late(void);
+extern void acpi_s2idle_check(void);
 extern bool acpi_s2idle_wake(void);
 extern void acpi_s2idle_restore_early(void);
 extern void acpi_s2idle_restore(void);
index 5d7f380..0d9064a 100644 (file)
@@ -17,8 +17,9 @@
  * Otherwise vendor specific drivers like thinkpad_acpi, asus-laptop,
  * sony_acpi,... can take care about backlight brightness.
  *
- * Backlight drivers can use acpi_video_get_backlight_type() to determine
- * which driver should handle the backlight.
+ * Backlight drivers can use acpi_video_get_backlight_type() to determine which
+ * driver should handle the backlight. RAW/GPU-driver backlight drivers must
+ * use the acpi_video_backlight_use_native() helper for this.
  *
  * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m)
  * this file will not be compiled and acpi_video_get_backlight_type() will
 
 #include <linux/export.h>
 #include <linux/acpi.h>
+#include <linux/apple-gmux.h>
 #include <linux/backlight.h>
 #include <linux/dmi.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/platform_data/x86/nvidia-wmi-ec-backlight.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
 #include <acpi/video.h>
 
-void acpi_video_unregister_backlight(void);
-
-static bool backlight_notifier_registered;
-static struct notifier_block backlight_nb;
-static struct work_struct backlight_notify_work;
-
 static enum acpi_backlight_type acpi_backlight_cmdline = acpi_backlight_undef;
 static enum acpi_backlight_type acpi_backlight_dmi = acpi_backlight_undef;
 
@@ -78,6 +75,36 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
        return AE_OK;
 }
 
+/* This depends on ACPI_WMI which is X86 only */
+#ifdef CONFIG_X86
+static bool nvidia_wmi_ec_supported(void)
+{
+       struct wmi_brightness_args args = {
+               .mode = WMI_BRIGHTNESS_MODE_GET,
+               .val = 0,
+               .ret = 0,
+       };
+       struct acpi_buffer buf = { (acpi_size)sizeof(args), &args };
+       acpi_status status;
+
+       status = wmi_evaluate_method(WMI_BRIGHTNESS_GUID, 0,
+                                    WMI_BRIGHTNESS_METHOD_SOURCE, &buf, &buf);
+       if (ACPI_FAILURE(status))
+               return false;
+
+       /*
+        * If brightness is handled by the EC then nvidia-wmi-ec-backlight
+        * should be used, else the GPU driver(s) should be used.
+        */
+       return args.ret == WMI_BRIGHTNESS_SOURCE_EC;
+}
+#else
+static bool nvidia_wmi_ec_supported(void)
+{
+       return false;
+}
+#endif
+
 /* Force to use vendor driver when the ACPI device is known to be
  * buggy */
 static int video_detect_force_vendor(const struct dmi_system_id *d)
@@ -105,63 +132,143 @@ static int video_detect_force_none(const struct dmi_system_id *d)
 }
 
 static const struct dmi_system_id video_detect_dmi_table[] = {
-       /* On Samsung X360, the BIOS will set a flag (VDRV) if generic
-        * ACPI backlight device is used. This flag will definitively break
-        * the backlight interface (even the vendor interface) until next
-        * reboot. It's why we should prevent video.ko from being used here
-        * and we can't rely on a later call to acpi_video_unregister().
-        */
        {
+        /* https://bugzilla.redhat.com/show_bug.cgi?id=1128309 */
         .callback = video_detect_force_vendor,
-        /* X360 */
+        /* Acer KAV80 */
         .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
-               DMI_MATCH(DMI_BOARD_NAME, "X360"),
+               DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "KAV80"),
                },
        },
        {
-       .callback = video_detect_force_vendor,
-       /* Asus UL30VT */
-       .matches = {
+        .callback = video_detect_force_vendor,
+        /* Asus UL30VT */
+        .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
                DMI_MATCH(DMI_PRODUCT_NAME, "UL30VT"),
                },
        },
        {
-       .callback = video_detect_force_vendor,
-       /* Asus UL30A */
-       .matches = {
+        .callback = video_detect_force_vendor,
+        /* Asus UL30A */
+        .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
                DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"),
                },
        },
        {
-       .callback = video_detect_force_vendor,
-       /* GIGABYTE GB-BXBT-2807 */
-       .matches = {
+        .callback = video_detect_force_vendor,
+        /* Asus X55U */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "X55U"),
+               },
+       },
+       {
+        .callback = video_detect_force_vendor,
+        /* Asus X101CH */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "X101CH"),
+               },
+       },
+       {
+        .callback = video_detect_force_vendor,
+        /* Asus X401U */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "X401U"),
+               },
+       },
+       {
+        .callback = video_detect_force_vendor,
+        /* Asus X501U */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "X501U"),
+               },
+       },
+       {
+        .callback = video_detect_force_vendor,
+        /* Asus 1015CX */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "1015CX"),
+               },
+       },
+       {
+        .callback = video_detect_force_vendor,
+        /* GIGABYTE GB-BXBT-2807 */
+        .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
                DMI_MATCH(DMI_PRODUCT_NAME, "GB-BXBT-2807"),
                },
        },
        {
-       .callback = video_detect_force_vendor,
-       /* Sony VPCEH3U1E */
-       .matches = {
+        .callback = video_detect_force_vendor,
+        /* Samsung N150/N210/N220 */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
+               DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
+               },
+       },
+       {
+        .callback = video_detect_force_vendor,
+        /* Samsung NF110/NF210/NF310 */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
+               DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
+               },
+       },
+       {
+        .callback = video_detect_force_vendor,
+        /* Samsung NC210 */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "NC210/NC110"),
+               DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"),
+               },
+       },
+       {
+        .callback = video_detect_force_vendor,
+        /* Sony VPCEH3U1E */
+        .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
                DMI_MATCH(DMI_PRODUCT_NAME, "VPCEH3U1E"),
                },
        },
        {
-       .callback = video_detect_force_vendor,
-       /* Xiaomi Mi Pad 2 */
-       .matches = {
+        .callback = video_detect_force_vendor,
+        /* Xiaomi Mi Pad 2 */
+        .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Xiaomi Inc"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"),
                },
        },
 
        /*
+        * Toshiba models with Transflective display, these need to use
+        * the toshiba_acpi vendor driver for proper Transflective handling.
+        */
+       {
+        .callback = video_detect_force_vendor,
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R500"),
+               },
+       },
+       {
+        .callback = video_detect_force_vendor,
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R600"),
+               },
+       },
+
+       /*
         * These models have a working acpi_video backlight control, and using
         * native backlight causes a regression where backlight does not work
         * when userspace is not handling brightness key events. Disable
@@ -390,6 +497,41 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
                },
        },
        {
+        /* https://bugzilla.redhat.com/show_bug.cgi?id=1012674 */
+        .callback = video_detect_force_native,
+        /* Acer Aspire 5741 */
+        .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5741"),
+               },
+       },
+       {
+        /* https://bugzilla.kernel.org/show_bug.cgi?id=42993 */
+        .callback = video_detect_force_native,
+        /* Acer Aspire 5750 */
+        .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"),
+               },
+       },
+       {
+        /* https://bugzilla.kernel.org/show_bug.cgi?id=42833 */
+        .callback = video_detect_force_native,
+        /* Acer Extensa 5235 */
+        .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5235"),
+               },
+       },
+       {
+        .callback = video_detect_force_native,
+        /* Acer TravelMate 4750 */
+        .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"),
+               },
+       },
+       {
         /* https://bugzilla.kernel.org/show_bug.cgi?id=207835 */
         .callback = video_detect_force_native,
         /* Acer TravelMate 5735Z */
@@ -400,120 +542,109 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
                },
        },
        {
-       .callback = video_detect_force_native,
-       /* ASUSTeK COMPUTER INC. GA401 */
-       .matches = {
+        /* https://bugzilla.kernel.org/show_bug.cgi?id=36322 */
+        .callback = video_detect_force_native,
+        /* Acer TravelMate 5760 */
+        .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5760"),
+               },
+       },
+       {
+        .callback = video_detect_force_native,
+        /* ASUSTeK COMPUTER INC. GA401 */
+        .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                DMI_MATCH(DMI_PRODUCT_NAME, "GA401"),
                },
        },
        {
-       .callback = video_detect_force_native,
-       /* ASUSTeK COMPUTER INC. GA502 */
-       .matches = {
+        .callback = video_detect_force_native,
+        /* ASUSTeK COMPUTER INC. GA502 */
+        .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                DMI_MATCH(DMI_PRODUCT_NAME, "GA502"),
                },
        },
        {
-       .callback = video_detect_force_native,
-       /* ASUSTeK COMPUTER INC. GA503 */
-       .matches = {
+        .callback = video_detect_force_native,
+        /* ASUSTeK COMPUTER INC. GA503 */
+        .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
                DMI_MATCH(DMI_PRODUCT_NAME, "GA503"),
                },
        },
-       /*
-        * Clevo NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2 have both a
-        * working native and video interface. However the default detection
-        * mechanism first registers the video interface before unregistering
-        * it again and switching to the native interface during boot. This
-        * results in a dangling SBIOS request for backlight change for some
-        * reason, causing the backlight to switch to ~2% once per boot on the
-        * first power cord connect or disconnect event. Setting the native
-        * interface explicitly circumvents this buggy behaviour, by avoiding
-        * the unregistering process.
-        */
        {
-       .callback = video_detect_force_native,
-       .ident = "Clevo NL5xRU",
-       .matches = {
-               DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
+        .callback = video_detect_force_native,
+        /* Asus UX303UB */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "UX303UB"),
                },
        },
        {
-       .callback = video_detect_force_native,
-       .ident = "Clevo NL5xRU",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
-               DMI_MATCH(DMI_BOARD_NAME, "AURA1501"),
+        .callback = video_detect_force_native,
+        /* Samsung N150P */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "N150P"),
+               DMI_MATCH(DMI_BOARD_NAME, "N150P"),
                },
        },
        {
-       .callback = video_detect_force_native,
-       .ident = "Clevo NL5xRU",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
-               DMI_MATCH(DMI_BOARD_NAME, "EDUBOOK1502"),
+        .callback = video_detect_force_native,
+        /* Samsung N145P/N250P/N260P */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
+               DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
                },
        },
        {
-       .callback = video_detect_force_native,
-       .ident = "Clevo NL5xNU",
-       .matches = {
-               DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
+        .callback = video_detect_force_native,
+        /* Samsung N250P */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "N250P"),
+               DMI_MATCH(DMI_BOARD_NAME, "N250P"),
                },
        },
+
        /*
-        * The TongFang PF5PU1G, PF4NU1F, PF5NU1G, and PF5LUXG/TUXEDO BA15 Gen10,
-        * Pulse 14/15 Gen1, and Pulse 15 Gen2 have the same problem as the Clevo
-        * NL5xRU and NL5xNU/TUXEDO Aura 15 Gen1 and Gen2. See the description
-        * above.
+        * These Toshibas have a broken acpi-video interface for brightness
+        * control. They also have an issue where the panel is off after
+        * suspend until a special firmware call is made to turn it back
+        * on. This is handled by the toshiba_acpi kernel module, so that
+        * module must be enabled for these models to work correctly.
         */
        {
-       .callback = video_detect_force_native,
-       .ident = "TongFang PF5PU1G",
-       .matches = {
-               DMI_MATCH(DMI_BOARD_NAME, "PF5PU1G"),
-               },
-       },
-       {
-       .callback = video_detect_force_native,
-       .ident = "TongFang PF4NU1F",
-       .matches = {
-               DMI_MATCH(DMI_BOARD_NAME, "PF4NU1F"),
-               },
-       },
-       {
-       .callback = video_detect_force_native,
-       .ident = "TongFang PF4NU1F",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
-               DMI_MATCH(DMI_BOARD_NAME, "PULSE1401"),
-               },
-       },
-       {
-       .callback = video_detect_force_native,
-       .ident = "TongFang PF5NU1G",
-       .matches = {
-               DMI_MATCH(DMI_BOARD_NAME, "PF5NU1G"),
+        /* https://bugzilla.kernel.org/show_bug.cgi?id=21012 */
+        .callback = video_detect_force_native,
+        /* Toshiba Portégé R700 */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R700"),
                },
        },
        {
-       .callback = video_detect_force_native,
-       .ident = "TongFang PF5NU1G",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
-               DMI_MATCH(DMI_BOARD_NAME, "PULSE1501"),
+        /* Portégé: https://bugs.freedesktop.org/show_bug.cgi?id=82634 */
+        /* Satellite: https://bugzilla.kernel.org/show_bug.cgi?id=21012 */
+        .callback = video_detect_force_native,
+        /* Toshiba Satellite/Portégé R830 */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "R830"),
                },
        },
        {
-       .callback = video_detect_force_native,
-       .ident = "TongFang PF5LUXG",
-       .matches = {
-               DMI_MATCH(DMI_BOARD_NAME, "PF5LUXG"),
+        .callback = video_detect_force_native,
+        /* Toshiba Satellite/Portégé Z830 */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Z830"),
                },
        },
+
        /*
         * Desktops which falsely report a backlight and which our heuristics
         * for this do not catch.
@@ -537,43 +668,15 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        { },
 };
 
-/* This uses a workqueue to avoid various locking ordering issues */
-static void acpi_video_backlight_notify_work(struct work_struct *work)
-{
-       if (acpi_video_get_backlight_type() != acpi_backlight_video)
-               acpi_video_unregister_backlight();
-}
-
-static int acpi_video_backlight_notify(struct notifier_block *nb,
-                                      unsigned long val, void *bd)
-{
-       struct backlight_device *backlight = bd;
-
-       /* A raw bl registering may change video -> native */
-       if (backlight->props.type == BACKLIGHT_RAW &&
-           val == BACKLIGHT_REGISTERED)
-               schedule_work(&backlight_notify_work);
-
-       return NOTIFY_OK;
-}
-
 /*
  * Determine which type of backlight interface to use on this system,
  * First check cmdline, then dmi quirks, then do autodetect.
- *
- * The autodetect order is:
- * 1) Is the acpi-video backlight interface supported ->
- *  no, use a vendor interface
- * 2) Is this a win8 "ready" BIOS and do we have a native interface ->
- *  yes, use a native interface
- * 3) Else use the acpi-video interface
- *
- * Arguably the native on win8 check should be done first, but that would
- * be a behavior change, which may causes issues.
  */
-enum acpi_backlight_type acpi_video_get_backlight_type(void)
+static enum acpi_backlight_type __acpi_video_get_backlight_type(bool native)
 {
        static DEFINE_MUTEX(init_mutex);
+       static bool nvidia_wmi_ec_present;
+       static bool native_available;
        static bool init_done;
        static long video_caps;
 
@@ -585,48 +688,60 @@ enum acpi_backlight_type acpi_video_get_backlight_type(void)
                acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
                                    ACPI_UINT32_MAX, find_video, NULL,
                                    &video_caps, NULL);
-               INIT_WORK(&backlight_notify_work,
-                         acpi_video_backlight_notify_work);
-               backlight_nb.notifier_call = acpi_video_backlight_notify;
-               backlight_nb.priority = 0;
-               if (backlight_register_notifier(&backlight_nb) == 0)
-                       backlight_notifier_registered = true;
+               nvidia_wmi_ec_present = nvidia_wmi_ec_supported();
                init_done = true;
        }
+       if (native)
+               native_available = true;
        mutex_unlock(&init_mutex);
 
+       /*
+        * The below heuristics / detection steps are in order of descending
+        * presedence. The commandline takes presedence over anything else.
+        */
        if (acpi_backlight_cmdline != acpi_backlight_undef)
                return acpi_backlight_cmdline;
 
+       /* DMI quirks override any autodetection. */
        if (acpi_backlight_dmi != acpi_backlight_undef)
                return acpi_backlight_dmi;
 
-       if (!(video_caps & ACPI_VIDEO_BACKLIGHT))
-               return acpi_backlight_vendor;
+       /* Special cases such as nvidia_wmi_ec and apple gmux. */
+       if (nvidia_wmi_ec_present)
+               return acpi_backlight_nvidia_wmi_ec;
 
-       if (acpi_osi_is_win8() && backlight_device_get_by_type(BACKLIGHT_RAW))
-               return acpi_backlight_native;
+       if (apple_gmux_present())
+               return acpi_backlight_apple_gmux;
+
+       /* On systems with ACPI video use either native or ACPI video. */
+       if (video_caps & ACPI_VIDEO_BACKLIGHT) {
+               /*
+                * Windows 8 and newer no longer use the ACPI video interface,
+                * so it often does not work. If the ACPI tables are written
+                * for win8 and native brightness ctl is available, use that.
+                *
+                * The native check deliberately is inside the if acpi-video
+                * block on older devices without acpi-video support native
+                * is usually not the best choice.
+                */
+               if (acpi_osi_is_win8() && native_available)
+                       return acpi_backlight_native;
+               else
+                       return acpi_backlight_video;
+       }
 
-       return acpi_backlight_video;
+       /* No ACPI video (old hw), use vendor specific fw methods. */
+       return acpi_backlight_vendor;
 }
-EXPORT_SYMBOL(acpi_video_get_backlight_type);
 
-/*
- * Set the preferred backlight interface type based on DMI info.
- * This function allows DMI blacklists to be implemented by external
- * platform drivers instead of putting a big blacklist in video_detect.c
- */
-void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type)
+enum acpi_backlight_type acpi_video_get_backlight_type(void)
 {
-       acpi_backlight_dmi = type;
-       /* Remove acpi-video backlight interface if it is no longer desired */
-       if (acpi_video_get_backlight_type() != acpi_backlight_video)
-               acpi_video_unregister_backlight();
+       return __acpi_video_get_backlight_type(false);
 }
-EXPORT_SYMBOL(acpi_video_set_dmi_backlight_type);
+EXPORT_SYMBOL(acpi_video_get_backlight_type);
 
-void __exit acpi_video_detect_exit(void)
+bool acpi_video_backlight_use_native(void)
 {
-       if (backlight_notifier_registered)
-               backlight_unregister_notifier(&backlight_nb);
+       return __acpi_video_get_backlight_type(true) == acpi_backlight_native;
 }
+EXPORT_SYMBOL(acpi_video_backlight_use_native);
index 0155c1d..42f2490 100644 (file)
@@ -584,6 +584,19 @@ int acpi_s2idle_prepare_late(void)
        return 0;
 }
 
+void acpi_s2idle_check(void)
+{
+       struct acpi_s2idle_dev_ops *handler;
+
+       if (!lps0_device_handle || sleep_no_lps0)
+               return;
+
+       list_for_each_entry(handler, &lps0_s2idle_devops_head, list_node) {
+               if (handler->check)
+                       handler->check();
+       }
+}
+
 void acpi_s2idle_restore_early(void)
 {
        struct acpi_s2idle_dev_ops *handler;
@@ -625,6 +638,7 @@ static const struct platform_s2idle_ops acpi_s2idle_ops_lps0 = {
        .begin = acpi_s2idle_begin,
        .prepare = acpi_s2idle_prepare,
        .prepare_late = acpi_s2idle_prepare_late,
+       .check = acpi_s2idle_check,
        .wake = acpi_s2idle_wake,
        .restore_early = acpi_s2idle_restore_early,
        .restore = acpi_s2idle_restore,
index 0642f57..3f64345 100644 (file)
@@ -874,10 +874,11 @@ config GPIO_104_IDI_48
          module parameter.
 
 config GPIO_F7188X
-       tristate "F71869, F71869A, F71882FG, F71889F and F81866 GPIO support"
+       tristate "Fintek and Nuvoton Super-I/O GPIO support"
        help
          This option enables support for GPIOs found on Fintek Super-I/O
          chips F71869, F71869A, F71882FG, F71889F and F81866.
+         As well as Nuvoton Super-I/O chip NCT6116D.
 
          To compile this driver as a module, choose M here: the module will
          be called f7188x-gpio.
index 18a3147..9effa77 100644 (file)
@@ -1,12 +1,15 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * GPIO driver for Fintek Super-I/O F71869, F71869A, F71882, F71889 and F81866
+ * GPIO driver for Fintek and Nuvoton Super-I/O chips
  *
  * Copyright (C) 2010-2013 LaCie
  *
  * Author: Simon Guinot <simon.guinot@sequanux.org>
  */
 
+#define DRVNAME "gpio-f7188x"
+#define pr_fmt(fmt) DRVNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/gpio/driver.h>
 #include <linux/bitops.h>
 
-#define DRVNAME "gpio-f7188x"
-
 /*
  * Super-I/O registers
  */
 #define SIO_LDSEL              0x07    /* Logical device select */
 #define SIO_DEVID              0x20    /* Device ID (2 bytes) */
-#define SIO_DEVREV             0x22    /* Device revision */
-#define SIO_MANID              0x23    /* Fintek ID (2 bytes) */
 
-#define SIO_LD_GPIO            0x06    /* GPIO logical device */
 #define SIO_UNLOCK_KEY         0x87    /* Key to enable Super-I/O */
 #define SIO_LOCK_KEY           0xAA    /* Key to disable Super-I/O */
 
-#define SIO_FINTEK_ID          0x1934  /* Manufacturer ID */
+/*
+ * Fintek devices.
+ */
+#define SIO_FINTEK_DEVREV      0x22    /* Fintek Device revision */
+#define SIO_FINTEK_MANID       0x23    /* Fintek ID (2 bytes) */
+
+#define SIO_FINTEK_ID          0x1934  /* Manufacturer ID */
+
 #define SIO_F71869_ID          0x0814  /* F71869 chipset ID */
 #define SIO_F71869A_ID         0x1007  /* F71869A chipset ID */
 #define SIO_F71882_ID          0x0541  /* F71882 chipset ID */
 #define SIO_F71889_ID          0x0909  /* F71889 chipset ID */
 #define SIO_F71889A_ID         0x1005  /* F71889A chipset ID */
 #define SIO_F81866_ID          0x1010  /* F81866 chipset ID */
-#define SIO_F81804_ID          0x1502  /* F81804 chipset ID, same for f81966 */
+#define SIO_F81804_ID          0x1502  /* F81804 chipset ID, same for F81966 */
 #define SIO_F81865_ID          0x0704  /* F81865 chipset ID */
 
+#define SIO_LD_GPIO_FINTEK     0x06    /* GPIO logical device */
+
+/*
+ * Nuvoton devices.
+ */
+#define SIO_NCT6116D_ID                0xD283  /* NCT6116D chipset ID */
+
+#define SIO_LD_GPIO_NUVOTON    0x07    /* GPIO logical device */
+
 
 enum chips {
        f71869,
@@ -48,6 +62,7 @@ enum chips {
        f81866,
        f81804,
        f81865,
+       nct6116d,
 };
 
 static const char * const f7188x_names[] = {
@@ -59,10 +74,12 @@ static const char * const f7188x_names[] = {
        "f81866",
        "f81804",
        "f81865",
+       "nct6116d",
 };
 
 struct f7188x_sio {
        int addr;
+       int device;
        enum chips type;
 };
 
@@ -110,7 +127,7 @@ static inline int superio_enter(int base)
 {
        /* Don't step on other drivers' I/O space by accident. */
        if (!request_muxed_region(base, 2, DRVNAME)) {
-               pr_err(DRVNAME "I/O address 0x%04x already in use\n", base);
+               pr_err("I/O address 0x%04x already in use\n", base);
                return -EBUSY;
        }
 
@@ -146,10 +163,10 @@ static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value);
 static int f7188x_gpio_set_config(struct gpio_chip *chip, unsigned offset,
                                  unsigned long config);
 
-#define F7188X_GPIO_BANK(_base, _ngpio, _regbase)                      \
+#define F7188X_GPIO_BANK(_base, _ngpio, _regbase, _label)                      \
        {                                                               \
                .chip = {                                               \
-                       .label            = DRVNAME,                    \
+                       .label            = _label,                     \
                        .owner            = THIS_MODULE,                \
                        .get_direction    = f7188x_gpio_get_direction,  \
                        .direction_input  = f7188x_gpio_direction_in,   \
@@ -164,94 +181,108 @@ static int f7188x_gpio_set_config(struct gpio_chip *chip, unsigned offset,
                .regbase = _regbase,                                    \
        }
 
-#define gpio_dir(base) (base + 0)
-#define gpio_data_out(base) (base + 1)
-#define gpio_data_in(base) (base + 2)
+#define f7188x_gpio_dir(base) ((base) + 0)
+#define f7188x_gpio_data_out(base) ((base) + 1)
+#define f7188x_gpio_data_in(base) ((base) + 2)
 /* Output mode register (0:open drain 1:push-pull). */
-#define gpio_out_mode(base) (base + 3)
+#define f7188x_gpio_out_mode(base) ((base) + 3)
+
+#define f7188x_gpio_dir_invert(type)   ((type) == nct6116d)
+#define f7188x_gpio_data_single(type)  ((type) == nct6116d)
 
 static struct f7188x_gpio_bank f71869_gpio_bank[] = {
-       F7188X_GPIO_BANK(0, 6, 0xF0),
-       F7188X_GPIO_BANK(10, 8, 0xE0),
-       F7188X_GPIO_BANK(20, 8, 0xD0),
-       F7188X_GPIO_BANK(30, 8, 0xC0),
-       F7188X_GPIO_BANK(40, 8, 0xB0),
-       F7188X_GPIO_BANK(50, 5, 0xA0),
-       F7188X_GPIO_BANK(60, 6, 0x90),
+       F7188X_GPIO_BANK(0, 6, 0xF0, DRVNAME "-0"),
+       F7188X_GPIO_BANK(10, 8, 0xE0, DRVNAME "-1"),
+       F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"),
+       F7188X_GPIO_BANK(30, 8, 0xC0, DRVNAME "-3"),
+       F7188X_GPIO_BANK(40, 8, 0xB0, DRVNAME "-4"),
+       F7188X_GPIO_BANK(50, 5, 0xA0, DRVNAME "-5"),
+       F7188X_GPIO_BANK(60, 6, 0x90, DRVNAME "-6"),
 };
 
 static struct f7188x_gpio_bank f71869a_gpio_bank[] = {
-       F7188X_GPIO_BANK(0, 6, 0xF0),
-       F7188X_GPIO_BANK(10, 8, 0xE0),
-       F7188X_GPIO_BANK(20, 8, 0xD0),
-       F7188X_GPIO_BANK(30, 8, 0xC0),
-       F7188X_GPIO_BANK(40, 8, 0xB0),
-       F7188X_GPIO_BANK(50, 5, 0xA0),
-       F7188X_GPIO_BANK(60, 8, 0x90),
-       F7188X_GPIO_BANK(70, 8, 0x80),
+       F7188X_GPIO_BANK(0, 6, 0xF0, DRVNAME "-0"),
+       F7188X_GPIO_BANK(10, 8, 0xE0, DRVNAME "-1"),
+       F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"),
+       F7188X_GPIO_BANK(30, 8, 0xC0, DRVNAME "-3"),
+       F7188X_GPIO_BANK(40, 8, 0xB0, DRVNAME "-4"),
+       F7188X_GPIO_BANK(50, 5, 0xA0, DRVNAME "-5"),
+       F7188X_GPIO_BANK(60, 8, 0x90, DRVNAME "-6"),
+       F7188X_GPIO_BANK(70, 8, 0x80, DRVNAME "-7"),
 };
 
 static struct f7188x_gpio_bank f71882_gpio_bank[] = {
-       F7188X_GPIO_BANK(0, 8, 0xF0),
-       F7188X_GPIO_BANK(10, 8, 0xE0),
-       F7188X_GPIO_BANK(20, 8, 0xD0),
-       F7188X_GPIO_BANK(30, 4, 0xC0),
-       F7188X_GPIO_BANK(40, 4, 0xB0),
+       F7188X_GPIO_BANK(0, 8, 0xF0, DRVNAME "-0"),
+       F7188X_GPIO_BANK(10, 8, 0xE0, DRVNAME "-1"),
+       F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"),
+       F7188X_GPIO_BANK(30, 4, 0xC0, DRVNAME "-3"),
+       F7188X_GPIO_BANK(40, 4, 0xB0, DRVNAME "-4"),
 };
 
 static struct f7188x_gpio_bank f71889a_gpio_bank[] = {
-       F7188X_GPIO_BANK(0, 7, 0xF0),
-       F7188X_GPIO_BANK(10, 7, 0xE0),
-       F7188X_GPIO_BANK(20, 8, 0xD0),
-       F7188X_GPIO_BANK(30, 8, 0xC0),
-       F7188X_GPIO_BANK(40, 8, 0xB0),
-       F7188X_GPIO_BANK(50, 5, 0xA0),
-       F7188X_GPIO_BANK(60, 8, 0x90),
-       F7188X_GPIO_BANK(70, 8, 0x80),
+       F7188X_GPIO_BANK(0, 7, 0xF0, DRVNAME "-0"),
+       F7188X_GPIO_BANK(10, 7, 0xE0, DRVNAME "-1"),
+       F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"),
+       F7188X_GPIO_BANK(30, 8, 0xC0, DRVNAME "-3"),
+       F7188X_GPIO_BANK(40, 8, 0xB0, DRVNAME "-4"),
+       F7188X_GPIO_BANK(50, 5, 0xA0, DRVNAME "-5"),
+       F7188X_GPIO_BANK(60, 8, 0x90, DRVNAME "-6"),
+       F7188X_GPIO_BANK(70, 8, 0x80, DRVNAME "-7"),
 };
 
 static struct f7188x_gpio_bank f71889_gpio_bank[] = {
-       F7188X_GPIO_BANK(0, 7, 0xF0),
-       F7188X_GPIO_BANK(10, 7, 0xE0),
-       F7188X_GPIO_BANK(20, 8, 0xD0),
-       F7188X_GPIO_BANK(30, 8, 0xC0),
-       F7188X_GPIO_BANK(40, 8, 0xB0),
-       F7188X_GPIO_BANK(50, 5, 0xA0),
-       F7188X_GPIO_BANK(60, 8, 0x90),
-       F7188X_GPIO_BANK(70, 8, 0x80),
+       F7188X_GPIO_BANK(0, 7, 0xF0, DRVNAME "-0"),
+       F7188X_GPIO_BANK(10, 7, 0xE0, DRVNAME "-1"),
+       F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"),
+       F7188X_GPIO_BANK(30, 8, 0xC0, DRVNAME "-3"),
+       F7188X_GPIO_BANK(40, 8, 0xB0, DRVNAME "-4"),
+       F7188X_GPIO_BANK(50, 5, 0xA0, DRVNAME "-5"),
+       F7188X_GPIO_BANK(60, 8, 0x90, DRVNAME "-6"),
+       F7188X_GPIO_BANK(70, 8, 0x80, DRVNAME "-7"),
 };
 
 static struct f7188x_gpio_bank f81866_gpio_bank[] = {
-       F7188X_GPIO_BANK(0, 8, 0xF0),
-       F7188X_GPIO_BANK(10, 8, 0xE0),
-       F7188X_GPIO_BANK(20, 8, 0xD0),
-       F7188X_GPIO_BANK(30, 8, 0xC0),
-       F7188X_GPIO_BANK(40, 8, 0xB0),
-       F7188X_GPIO_BANK(50, 8, 0xA0),
-       F7188X_GPIO_BANK(60, 8, 0x90),
-       F7188X_GPIO_BANK(70, 8, 0x80),
-       F7188X_GPIO_BANK(80, 8, 0x88),
+       F7188X_GPIO_BANK(0, 8, 0xF0, DRVNAME "-0"),
+       F7188X_GPIO_BANK(10, 8, 0xE0, DRVNAME "-1"),
+       F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"),
+       F7188X_GPIO_BANK(30, 8, 0xC0, DRVNAME "-3"),
+       F7188X_GPIO_BANK(40, 8, 0xB0, DRVNAME "-4"),
+       F7188X_GPIO_BANK(50, 8, 0xA0, DRVNAME "-5"),
+       F7188X_GPIO_BANK(60, 8, 0x90, DRVNAME "-6"),
+       F7188X_GPIO_BANK(70, 8, 0x80, DRVNAME "-7"),
+       F7188X_GPIO_BANK(80, 8, 0x88, DRVNAME "-8"),
 };
 
 
 static struct f7188x_gpio_bank f81804_gpio_bank[] = {
-       F7188X_GPIO_BANK(0, 8, 0xF0),
-       F7188X_GPIO_BANK(10, 8, 0xE0),
-       F7188X_GPIO_BANK(20, 8, 0xD0),
-       F7188X_GPIO_BANK(50, 8, 0xA0),
-       F7188X_GPIO_BANK(60, 8, 0x90),
-       F7188X_GPIO_BANK(70, 8, 0x80),
-       F7188X_GPIO_BANK(90, 8, 0x98),
+       F7188X_GPIO_BANK(0, 8, 0xF0, DRVNAME "-0"),
+       F7188X_GPIO_BANK(10, 8, 0xE0, DRVNAME "-1"),
+       F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"),
+       F7188X_GPIO_BANK(50, 8, 0xA0, DRVNAME "-3"),
+       F7188X_GPIO_BANK(60, 8, 0x90, DRVNAME "-4"),
+       F7188X_GPIO_BANK(70, 8, 0x80, DRVNAME "-5"),
+       F7188X_GPIO_BANK(90, 8, 0x98, DRVNAME "-6"),
 };
 
 static struct f7188x_gpio_bank f81865_gpio_bank[] = {
-       F7188X_GPIO_BANK(0, 8, 0xF0),
-       F7188X_GPIO_BANK(10, 8, 0xE0),
-       F7188X_GPIO_BANK(20, 8, 0xD0),
-       F7188X_GPIO_BANK(30, 8, 0xC0),
-       F7188X_GPIO_BANK(40, 8, 0xB0),
-       F7188X_GPIO_BANK(50, 8, 0xA0),
-       F7188X_GPIO_BANK(60, 5, 0x90),
+       F7188X_GPIO_BANK(0, 8, 0xF0, DRVNAME "-0"),
+       F7188X_GPIO_BANK(10, 8, 0xE0, DRVNAME "-1"),
+       F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"),
+       F7188X_GPIO_BANK(30, 8, 0xC0, DRVNAME "-3"),
+       F7188X_GPIO_BANK(40, 8, 0xB0, DRVNAME "-4"),
+       F7188X_GPIO_BANK(50, 8, 0xA0, DRVNAME "-5"),
+       F7188X_GPIO_BANK(60, 5, 0x90, DRVNAME "-6"),
+};
+
+static struct f7188x_gpio_bank nct6116d_gpio_bank[] = {
+       F7188X_GPIO_BANK(0, 8, 0xE0, DRVNAME "-0"),
+       F7188X_GPIO_BANK(10, 8, 0xE4, DRVNAME "-1"),
+       F7188X_GPIO_BANK(20, 8, 0xE8, DRVNAME "-2"),
+       F7188X_GPIO_BANK(30, 8, 0xEC, DRVNAME "-3"),
+       F7188X_GPIO_BANK(40, 8, 0xF0, DRVNAME "-4"),
+       F7188X_GPIO_BANK(50, 8, 0xF4, DRVNAME "-5"),
+       F7188X_GPIO_BANK(60, 8, 0xF8, DRVNAME "-6"),
+       F7188X_GPIO_BANK(70, 1, 0xFC, DRVNAME "-7"),
 };
 
 static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
@@ -264,13 +295,16 @@ static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
        err = superio_enter(sio->addr);
        if (err)
                return err;
-       superio_select(sio->addr, SIO_LD_GPIO);
+       superio_select(sio->addr, sio->device);
 
-       dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
+       dir = superio_inb(sio->addr, f7188x_gpio_dir(bank->regbase));
 
        superio_exit(sio->addr);
 
-       if (dir & 1 << offset)
+       if (f7188x_gpio_dir_invert(sio->type))
+               dir = ~dir;
+
+       if (dir & BIT(offset))
                return GPIO_LINE_DIRECTION_OUT;
 
        return GPIO_LINE_DIRECTION_IN;
@@ -286,11 +320,15 @@ static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
        err = superio_enter(sio->addr);
        if (err)
                return err;
-       superio_select(sio->addr, SIO_LD_GPIO);
+       superio_select(sio->addr, sio->device);
 
-       dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
-       dir &= ~BIT(offset);
-       superio_outb(sio->addr, gpio_dir(bank->regbase), dir);
+       dir = superio_inb(sio->addr, f7188x_gpio_dir(bank->regbase));
+
+       if (f7188x_gpio_dir_invert(sio->type))
+               dir |= BIT(offset);
+       else
+               dir &= ~BIT(offset);
+       superio_outb(sio->addr, f7188x_gpio_dir(bank->regbase), dir);
 
        superio_exit(sio->addr);
 
@@ -307,14 +345,14 @@ static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset)
        err = superio_enter(sio->addr);
        if (err)
                return err;
-       superio_select(sio->addr, SIO_LD_GPIO);
+       superio_select(sio->addr, sio->device);
 
-       dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
+       dir = superio_inb(sio->addr, f7188x_gpio_dir(bank->regbase));
        dir = !!(dir & BIT(offset));
-       if (dir)
-               data = superio_inb(sio->addr, gpio_data_out(bank->regbase));
+       if (f7188x_gpio_data_single(sio->type) || dir)
+               data = superio_inb(sio->addr, f7188x_gpio_data_out(bank->regbase));
        else
-               data = superio_inb(sio->addr, gpio_data_in(bank->regbase));
+               data = superio_inb(sio->addr, f7188x_gpio_data_in(bank->regbase));
 
        superio_exit(sio->addr);
 
@@ -332,18 +370,21 @@ static int f7188x_gpio_direction_out(struct gpio_chip *chip,
        err = superio_enter(sio->addr);
        if (err)
                return err;
-       superio_select(sio->addr, SIO_LD_GPIO);
+       superio_select(sio->addr, sio->device);
 
-       data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase));
+       data_out = superio_inb(sio->addr, f7188x_gpio_data_out(bank->regbase));
        if (value)
                data_out |= BIT(offset);
        else
                data_out &= ~BIT(offset);
-       superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out);
+       superio_outb(sio->addr, f7188x_gpio_data_out(bank->regbase), data_out);
 
-       dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
-       dir |= BIT(offset);
-       superio_outb(sio->addr, gpio_dir(bank->regbase), dir);
+       dir = superio_inb(sio->addr, f7188x_gpio_dir(bank->regbase));
+       if (f7188x_gpio_dir_invert(sio->type))
+               dir &= ~BIT(offset);
+       else
+               dir |= BIT(offset);
+       superio_outb(sio->addr, f7188x_gpio_dir(bank->regbase), dir);
 
        superio_exit(sio->addr);
 
@@ -360,14 +401,14 @@ static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        err = superio_enter(sio->addr);
        if (err)
                return;
-       superio_select(sio->addr, SIO_LD_GPIO);
+       superio_select(sio->addr, sio->device);
 
-       data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase));
+       data_out = superio_inb(sio->addr, f7188x_gpio_data_out(bank->regbase));
        if (value)
                data_out |= BIT(offset);
        else
                data_out &= ~BIT(offset);
-       superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out);
+       superio_outb(sio->addr, f7188x_gpio_data_out(bank->regbase), data_out);
 
        superio_exit(sio->addr);
 }
@@ -388,14 +429,14 @@ static int f7188x_gpio_set_config(struct gpio_chip *chip, unsigned offset,
        err = superio_enter(sio->addr);
        if (err)
                return err;
-       superio_select(sio->addr, SIO_LD_GPIO);
+       superio_select(sio->addr, sio->device);
 
-       data = superio_inb(sio->addr, gpio_out_mode(bank->regbase));
+       data = superio_inb(sio->addr, f7188x_gpio_out_mode(bank->regbase));
        if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN)
                data &= ~BIT(offset);
        else
                data |= BIT(offset);
-       superio_outb(sio->addr, gpio_out_mode(bank->regbase), data);
+       superio_outb(sio->addr, f7188x_gpio_out_mode(bank->regbase), data);
 
        superio_exit(sio->addr);
        return 0;
@@ -449,6 +490,10 @@ static int f7188x_gpio_probe(struct platform_device *pdev)
                data->nr_bank = ARRAY_SIZE(f81865_gpio_bank);
                data->bank = f81865_gpio_bank;
                break;
+       case nct6116d:
+               data->nr_bank = ARRAY_SIZE(nct6116d_gpio_bank);
+               data->bank = nct6116d_gpio_bank;
+               break;
        default:
                return -ENODEV;
        }
@@ -479,18 +524,15 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio)
 {
        int err;
        u16 devid;
+       u16 manid;
 
        err = superio_enter(addr);
        if (err)
                return err;
 
        err = -ENODEV;
-       devid = superio_inw(addr, SIO_MANID);
-       if (devid != SIO_FINTEK_ID) {
-               pr_debug(DRVNAME ": Not a Fintek device at 0x%08x\n", addr);
-               goto err;
-       }
 
+       sio->device = SIO_LD_GPIO_FINTEK;
        devid = superio_inw(addr, SIO_DEVID);
        switch (devid) {
        case SIO_F71869_ID:
@@ -517,17 +559,30 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio)
        case SIO_F81865_ID:
                sio->type = f81865;
                break;
+       case SIO_NCT6116D_ID:
+               sio->device = SIO_LD_GPIO_NUVOTON;
+               sio->type = nct6116d;
+               break;
        default:
-               pr_info(DRVNAME ": Unsupported Fintek device 0x%04x\n", devid);
+               pr_info("Unsupported Fintek device 0x%04x\n", devid);
                goto err;
        }
+
+       /* double check manufacturer where possible */
+       if (sio->type != nct6116d) {
+               manid = superio_inw(addr, SIO_FINTEK_MANID);
+               if (manid != SIO_FINTEK_ID) {
+                       pr_debug("Not a Fintek device at 0x%08x\n", addr);
+                       goto err;
+               }
+       }
+
        sio->addr = addr;
        err = 0;
 
-       pr_info(DRVNAME ": Found %s at %#x, revision %d\n",
-               f7188x_names[sio->type],
-               (unsigned int) addr,
-               (int) superio_inb(addr, SIO_DEVREV));
+       pr_info("Found %s at %#x\n", f7188x_names[sio->type], (unsigned int)addr);
+       if (sio->type != nct6116d)
+               pr_info("   revision %d\n", superio_inb(addr, SIO_FINTEK_DEVREV));
 
 err:
        superio_exit(addr);
@@ -548,13 +603,13 @@ f7188x_gpio_device_add(const struct f7188x_sio *sio)
        err = platform_device_add_data(f7188x_gpio_pdev,
                                       sio, sizeof(*sio));
        if (err) {
-               pr_err(DRVNAME "Platform data allocation failed\n");
+               pr_err("Platform data allocation failed\n");
                goto err;
        }
 
        err = platform_device_add(f7188x_gpio_pdev);
        if (err) {
-               pr_err(DRVNAME "Device addition failed\n");
+               pr_err("Device addition failed\n");
                goto err;
        }
 
index 6c2256e..8cafe63 100644 (file)
@@ -248,6 +248,13 @@ config DRM_RADEON
        select HWMON
        select BACKLIGHT_CLASS_DEVICE
        select INTERVAL_TREE
+       # radeon depends on ACPI_VIDEO when ACPI is enabled, for select to work
+       # ACPI_VIDEO's dependencies must also be selected.
+       select INPUT if ACPI
+       select ACPI_VIDEO if ACPI
+       # On x86 ACPI_VIDEO also needs ACPI_WMI
+       select X86_PLATFORM_DEVICES if ACPI && X86
+       select ACPI_WMI if ACPI && X86
        help
          Choose this option if you have an ATI Radeon graphics card.  There
          are both PCI and AGP versions.  You don't need to choose this to
@@ -273,6 +280,13 @@ config DRM_AMDGPU
        select BACKLIGHT_CLASS_DEVICE
        select INTERVAL_TREE
        select DRM_BUDDY
+       # amdgpu depends on ACPI_VIDEO when ACPI is enabled, for select to work
+       # ACPI_VIDEO's dependencies must also be selected.
+       select INPUT if ACPI
+       select ACPI_VIDEO if ACPI
+       # On x86 ACPI_VIDEO also needs ACPI_WMI
+       select X86_PLATFORM_DEVICES if ACPI && X86
+       select ACPI_WMI if ACPI && X86
        help
          Choose this option if you have a recent AMD Radeon graphics card.
 
index fa7421a..6be9ac2 100644 (file)
@@ -26,6 +26,8 @@
 
 #include <linux/pci.h>
 
+#include <acpi/video.h>
+
 #include <drm/drm_crtc_helper.h>
 #include <drm/amdgpu_drm.h>
 #include "amdgpu.h"
@@ -182,7 +184,12 @@ void amdgpu_atombios_encoder_init_backlight(struct amdgpu_encoder *amdgpu_encode
                return;
 
        if (!(adev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
-               return;
+               goto register_acpi_backlight;
+
+       if (!acpi_video_backlight_use_native()) {
+               drm_info(dev, "Skipping amdgpu atom DIG backlight registration\n");
+               goto register_acpi_backlight;
+       }
 
        pdata = kmalloc(sizeof(struct amdgpu_backlight_privdata), GFP_KERNEL);
        if (!pdata) {
@@ -218,6 +225,11 @@ void amdgpu_atombios_encoder_init_backlight(struct amdgpu_encoder *amdgpu_encode
 error:
        kfree(pdata);
        return;
+
+register_acpi_backlight:
+       /* Try registering an ACPI video backlight device instead. */
+       acpi_video_register_backlight();
+       return;
 }
 
 void
index 1efe7fa..a0cd836 100644 (file)
@@ -89,6 +89,8 @@
 #include <drm/drm_audio_component.h>
 #include <drm/drm_gem_atomic_helper.h>
 
+#include <acpi/video.h>
+
 #include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
 
 #include "dcn/dcn_1_0_offset.h"
@@ -4058,6 +4060,13 @@ amdgpu_dm_register_backlight_device(struct amdgpu_display_manager *dm)
        amdgpu_dm_update_backlight_caps(dm, dm->num_of_edps);
        dm->brightness[dm->num_of_edps] = AMDGPU_MAX_BL_LEVEL;
 
+       if (!acpi_video_backlight_use_native()) {
+               drm_info(adev_to_drm(dm->adev), "Skipping amdgpu DM backlight registration\n");
+               /* Try registering an ACPI video backlight device instead. */
+               acpi_video_register_backlight();
+               return;
+       }
+
        props.max_brightness = AMDGPU_MAX_BL_LEVEL;
        props.brightness = AMDGPU_MAX_BL_LEVEL;
        props.type = BACKLIGHT_RAW;
index 0cff202..807b989 100644 (file)
@@ -7,6 +7,8 @@ config DRM_GMA500
        select ACPI_VIDEO if ACPI
        select BACKLIGHT_CLASS_DEVICE if ACPI
        select INPUT if ACPI
+       select X86_PLATFORM_DEVICES if ACPI
+       select ACPI_WMI if ACPI
        help
          Say yes for an experimental 2D KMS framebuffer driver for the
          Intel GMA500 (Poulsbo), Intel GMA600 (Moorestown/Oak Trail) and
index 7ae3b7d..3efce05 100644 (file)
@@ -23,6 +23,8 @@ config DRM_I915
        # but for select to work, need to select ACPI_VIDEO's dependencies, ick
        select BACKLIGHT_CLASS_DEVICE if ACPI
        select INPUT if ACPI
+       select X86_PLATFORM_DEVICES if ACPI
+       select ACPI_WMI if ACPI
        select ACPI_VIDEO if ACPI
        select ACPI_BUTTON if ACPI
        select SYNC_FILE
index e784300..9df78e7 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/pci.h>
 #include <linux/acpi.h>
+#include <acpi/video.h>
 
 #include "i915_drv.h"
 #include "intel_acpi.h"
@@ -331,3 +332,29 @@ void intel_acpi_assign_connector_fwnodes(struct drm_i915_private *i915)
         */
        fwnode_handle_put(fwnode);
 }
+
+void intel_acpi_video_register(struct drm_i915_private *i915)
+{
+       struct drm_connector_list_iter conn_iter;
+       struct drm_connector *connector;
+
+       acpi_video_register();
+
+       /*
+        * If i915 is driving an internal panel without registering its native
+        * backlight handler try to register the acpi_video backlight.
+        * For panels not driven by i915 another GPU driver may still register
+        * a native backlight later and acpi_video_register_backlight() should
+        * only be called after any native backlights have been registered.
+        */
+       drm_connector_list_iter_begin(&i915->drm, &conn_iter);
+       drm_for_each_connector_iter(connector, &conn_iter) {
+               struct intel_panel *panel = &to_intel_connector(connector)->panel;
+
+               if (panel->backlight.funcs && !panel->backlight.device) {
+                       acpi_video_register_backlight();
+                       break;
+               }
+       }
+       drm_connector_list_iter_end(&conn_iter);
+}
index 4a760a2..6a00074 100644 (file)
@@ -14,6 +14,7 @@ void intel_unregister_dsm_handler(void);
 void intel_dsm_get_bios_data_funcs_supported(struct drm_i915_private *i915);
 void intel_acpi_device_id_update(struct drm_i915_private *i915);
 void intel_acpi_assign_connector_fwnodes(struct drm_i915_private *i915);
+void intel_acpi_video_register(struct drm_i915_private *i915);
 #else
 static inline void intel_register_dsm_handler(void) { return; }
 static inline void intel_unregister_dsm_handler(void) { return; }
@@ -23,6 +24,8 @@ static inline
 void intel_acpi_device_id_update(struct drm_i915_private *i915) { return; }
 static inline
 void intel_acpi_assign_connector_fwnodes(struct drm_i915_private *i915) { return; }
+static inline
+void intel_acpi_video_register(struct drm_i915_private *i915) { return; }
 #endif /* CONFIG_ACPI */
 
 #endif /* __INTEL_ACPI_H__ */
index f5e1d69..ae1cdb6 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/pwm.h>
 #include <linux/string_helpers.h>
 
+#include <acpi/video.h>
+
 #include "intel_backlight.h"
 #include "intel_connector.h"
 #include "intel_de.h"
@@ -951,6 +953,11 @@ int intel_backlight_device_register(struct intel_connector *connector)
 
        WARN_ON(panel->backlight.max == 0);
 
+       if (!acpi_video_backlight_use_native()) {
+               drm_info(&i915->drm, "Skipping intel_backlight registration\n");
+               return 0;
+       }
+
        memset(&props, 0, sizeof(props));
        props.type = BACKLIGHT_RAW;
 
index fc5d948..6a1c15e 100644 (file)
@@ -9084,7 +9084,7 @@ void intel_display_driver_register(struct drm_i915_private *i915)
 
        /* Must be done after probing outputs */
        intel_opregion_register(i915);
-       acpi_video_register();
+       intel_acpi_video_register(i915);
 
        intel_audio_init(i915);
 
index 6140db7..8cf096f 100644 (file)
@@ -386,3 +386,13 @@ nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
 
        return kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
 }
+
+bool nouveau_acpi_video_backlight_use_native(void)
+{
+       return acpi_video_backlight_use_native();
+}
+
+void nouveau_acpi_video_register_backlight(void)
+{
+       acpi_video_register_backlight();
+}
index 330f9b8..e39dd8b 100644 (file)
@@ -11,6 +11,8 @@ void nouveau_register_dsm_handler(void);
 void nouveau_unregister_dsm_handler(void);
 void nouveau_switcheroo_optimus_dsm(void);
 void *nouveau_acpi_edid(struct drm_device *, struct drm_connector *);
+bool nouveau_acpi_video_backlight_use_native(void);
+void nouveau_acpi_video_register_backlight(void);
 #else
 static inline bool nouveau_is_optimus(void) { return false; };
 static inline bool nouveau_is_v1_dsm(void) { return false; };
@@ -18,6 +20,8 @@ static inline void nouveau_register_dsm_handler(void) {}
 static inline void nouveau_unregister_dsm_handler(void) {}
 static inline void nouveau_switcheroo_optimus_dsm(void) {}
 static inline void *nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) { return NULL; }
+static inline bool nouveau_acpi_video_backlight_use_native(void) { return true; }
+static inline void nouveau_acpi_video_register_backlight(void) {}
 #endif
 
 #endif
index a2141d3..a614582 100644 (file)
@@ -38,6 +38,7 @@
 #include "nouveau_reg.h"
 #include "nouveau_encoder.h"
 #include "nouveau_connector.h"
+#include "nouveau_acpi.h"
 
 static struct ida bl_ida;
 #define BL_NAME_SIZE 15 // 12 for name + 2 for digits + 1 for '\0'
@@ -405,6 +406,11 @@ nouveau_backlight_init(struct drm_connector *connector)
                goto fail_alloc;
        }
 
+       if (!nouveau_acpi_video_backlight_use_native()) {
+               NV_INFO(drm, "Skipping nv_backlight registration\n");
+               goto fail_alloc;
+       }
+
        if (!nouveau_get_backlight_name(backlight_name, bl)) {
                NV_ERROR(drm, "Failed to retrieve a unique name for the backlight interface\n");
                goto fail_alloc;
@@ -430,6 +436,13 @@ nouveau_backlight_init(struct drm_connector *connector)
 
 fail_alloc:
        kfree(bl);
+       /*
+        * If we get here we have an internal panel, but no nv_backlight,
+        * try registering an ACPI video backlight device instead.
+        */
+       if (ret == 0)
+               nouveau_acpi_video_register_backlight();
+
        return ret;
 }
 
index c93040e..2b01ede 100644 (file)
@@ -32,6 +32,8 @@
 #include <drm/drm_file.h>
 #include <drm/radeon_drm.h>
 
+#include <acpi/video.h>
+
 #include "atom.h"
 #include "radeon_atombios.h"
 #include "radeon.h"
@@ -209,6 +211,11 @@ void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder,
        if (!(rdev->mode_info.firmware_flags & ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU))
                return;
 
+       if (!acpi_video_backlight_use_native()) {
+               drm_info(dev, "Skipping radeon atom DIG backlight registration\n");
+               return;
+       }
+
        pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL);
        if (!pdata) {
                DRM_ERROR("Memory allocation failed\n");
index 46549d5..c1cbebb 100644 (file)
@@ -30,6 +30,8 @@
 #include <drm/drm_device.h>
 #include <drm/radeon_drm.h>
 
+#include <acpi/video.h>
+
 #include "radeon.h"
 #include "radeon_atombios.h"
 #include "radeon_legacy_encoders.h"
@@ -167,7 +169,7 @@ static void radeon_encoder_add_backlight(struct radeon_encoder *radeon_encoder,
                return;
 
        if (radeon_backlight == 0) {
-               return;
+               use_bl = false;
        } else if (radeon_backlight == 1) {
                use_bl = true;
        } else if (radeon_backlight == -1) {
@@ -193,6 +195,13 @@ static void radeon_encoder_add_backlight(struct radeon_encoder *radeon_encoder,
                else
                        radeon_legacy_backlight_init(radeon_encoder, connector);
        }
+
+       /*
+        * If there is no native backlight device (which may happen even when
+        * use_bl==true) try registering an ACPI video backlight device instead.
+        */
+       if (!rdev->mode_info.bl_encoder)
+               acpi_video_register_backlight();
 }
 
 void
index 1a66fb9..0cd32c6 100644 (file)
@@ -33,6 +33,8 @@
 #include <drm/drm_util.h>
 #include <drm/radeon_drm.h>
 
+#include <acpi/video.h>
+
 #include "radeon.h"
 #include "radeon_asic.h"
 #include "radeon_legacy_encoders.h"
@@ -387,6 +389,11 @@ void radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder,
                return;
 #endif
 
+       if (!acpi_video_backlight_use_native()) {
+               drm_info(dev, "Skipping radeon legacy LVDS backlight registration\n");
+               return;
+       }
+
        pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL);
        if (!pdata) {
                DRM_ERROR("Memory allocation failed\n");
index 4c9e663..b9eeb87 100644 (file)
 #include <linux/leds.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/platform_data/x86/simatic-ipc-base.h>
 
-static struct gpiod_lookup_table simatic_ipc_led_gpio_table = {
+static struct gpiod_lookup_table *simatic_ipc_led_gpio_table;
+
+static struct gpiod_lookup_table simatic_ipc_led_gpio_table_127e = {
        .dev_id = "leds-gpio",
        .table = {
-               GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 51, NULL, 0, GPIO_ACTIVE_LOW),
                GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 52, NULL, 1, GPIO_ACTIVE_LOW),
                GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 53, NULL, 2, GPIO_ACTIVE_LOW),
                GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 57, NULL, 3, GPIO_ACTIVE_LOW),
                GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 58, NULL, 4, GPIO_ACTIVE_LOW),
                GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 60, NULL, 5, GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 51, NULL, 0, GPIO_ACTIVE_LOW),
                GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 56, NULL, 6, GPIO_ACTIVE_LOW),
                GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 59, NULL, 7, GPIO_ACTIVE_HIGH),
        },
 };
 
+static struct gpiod_lookup_table simatic_ipc_led_gpio_table_227g = {
+       .dev_id = "leds-gpio",
+       .table = {
+               GPIO_LOOKUP_IDX("gpio-f7188x-2", 0, NULL, 0, GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP_IDX("gpio-f7188x-2", 1, NULL, 1, GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP_IDX("gpio-f7188x-2", 2, NULL, 2, GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP_IDX("gpio-f7188x-2", 3, NULL, 3, GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP_IDX("gpio-f7188x-2", 4, NULL, 4, GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP_IDX("gpio-f7188x-2", 5, NULL, 5, GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP_IDX("gpio-f7188x-3", 6, NULL, 6, GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP_IDX("gpio-f7188x-3", 7, NULL, 7, GPIO_ACTIVE_HIGH),
+       }
+};
+
 static const struct gpio_led simatic_ipc_gpio_leds[] = {
-       { .name = "green:" LED_FUNCTION_STATUS "-3" },
        { .name = "red:" LED_FUNCTION_STATUS "-1" },
        { .name = "green:" LED_FUNCTION_STATUS "-1" },
        { .name = "red:" LED_FUNCTION_STATUS "-2" },
        { .name = "green:" LED_FUNCTION_STATUS "-2" },
        { .name = "red:" LED_FUNCTION_STATUS "-3" },
+       { .name = "green:" LED_FUNCTION_STATUS "-3" },
 };
 
 static const struct gpio_led_platform_data simatic_ipc_gpio_leds_pdata = {
@@ -46,7 +63,7 @@ static struct platform_device *simatic_leds_pdev;
 
 static int simatic_ipc_leds_gpio_remove(struct platform_device *pdev)
 {
-       gpiod_remove_lookup_table(&simatic_ipc_led_gpio_table);
+       gpiod_remove_lookup_table(simatic_ipc_led_gpio_table);
        platform_device_unregister(simatic_leds_pdev);
 
        return 0;
@@ -54,10 +71,25 @@ static int simatic_ipc_leds_gpio_remove(struct platform_device *pdev)
 
 static int simatic_ipc_leds_gpio_probe(struct platform_device *pdev)
 {
+       const struct simatic_ipc_platform *plat = pdev->dev.platform_data;
        struct gpio_desc *gpiod;
        int err;
 
-       gpiod_add_lookup_table(&simatic_ipc_led_gpio_table);
+       switch (plat->devmode) {
+       case SIMATIC_IPC_DEVICE_127E:
+               simatic_ipc_led_gpio_table = &simatic_ipc_led_gpio_table_127e;
+               break;
+       case SIMATIC_IPC_DEVICE_227G:
+               if (!IS_ENABLED(CONFIG_GPIO_F7188X))
+                       return -ENODEV;
+               request_module("gpio-f7188x");
+               simatic_ipc_led_gpio_table = &simatic_ipc_led_gpio_table_227g;
+               break;
+       default:
+               return -ENODEV;
+       }
+
+       gpiod_add_lookup_table(simatic_ipc_led_gpio_table);
        simatic_leds_pdev = platform_device_register_resndata(NULL,
                "leds-gpio", PLATFORM_DEVID_NONE, NULL, 0,
                &simatic_ipc_gpio_leds_pdata,
index 1e071df..8d83383 100644 (file)
@@ -564,10 +564,8 @@ static int mlxreg_lc_event_handler(void *handle, enum mlxreg_hotplug_kind kind,
                 mlxreg_lc->data->slot, mlxreg_lc->state, kind, action);
 
        mutex_lock(&mlxreg_lc->lock);
-       if (!(mlxreg_lc->state & MLXREG_LC_INITIALIZED)) {
-               mutex_unlock(&mlxreg_lc->lock);
-               return 0;
-       }
+       if (!(mlxreg_lc->state & MLXREG_LC_INITIALIZED))
+               goto mlxreg_lc_non_initialzed_exit;
 
        switch (kind) {
        case MLXREG_HOTPLUG_LC_SYNCED:
@@ -594,8 +592,8 @@ static int mlxreg_lc_event_handler(void *handle, enum mlxreg_hotplug_kind kind,
                                /* In case line card is configured - enable it. */
                                if (mlxreg_lc->state & MLXREG_LC_CONFIGURED)
                                        err = mlxreg_lc_enable_disable(mlxreg_lc, 1);
-                               mutex_unlock(&mlxreg_lc->lock);
-                               return err;
+
+                               goto mlxreg_lc_enable_disable_exit;
                        }
                        err = mlxreg_lc_create_static_devices(mlxreg_lc, mlxreg_lc->main_devs,
                                                              mlxreg_lc->main_devs_num);
@@ -627,8 +625,10 @@ static int mlxreg_lc_event_handler(void *handle, enum mlxreg_hotplug_kind kind,
                break;
        }
 
+mlxreg_lc_enable_disable_exit:
 mlxreg_lc_power_on_off_fail:
 mlxreg_lc_create_static_devices_fail:
+mlxreg_lc_non_initialzed_exit:
        mutex_unlock(&mlxreg_lc->lock);
 
        return err;
index 3b20ddd..73961a2 100644 (file)
@@ -519,7 +519,7 @@ static int mshw0011_probe(struct i2c_client *client)
        i2c_set_clientdata(client, data);
 
        memset(&board_info, 0, sizeof(board_info));
-       strlcpy(board_info.type, "MSHW0011-bat0", I2C_NAME_SIZE);
+       strscpy(board_info.type, "MSHW0011-bat0", I2C_NAME_SIZE);
 
        bat0 = i2c_acpi_new_device(dev, 1, &board_info);
        if (IS_ERR(bat0))
index 44e3179..50500e5 100644 (file)
@@ -355,7 +355,8 @@ static u32 san_evt_bat_nf(struct ssam_event_notifier *nf,
        INIT_DELAYED_WORK(&work->work, san_evt_bat_workfn);
        work->dev = d->dev;
 
-       memcpy(&work->event, event, sizeof(struct ssam_event) + event->length);
+       work->event = *event;
+       memcpy(work->event.data, event->data, event->length);
 
        queue_delayed_work(san_wq, &work->work, delay);
        return SSAM_NOTIF_HANDLED;
index f2f98e9..f5312f5 100644 (file)
@@ -93,6 +93,7 @@ config PEAQ_WMI
 
 config NVIDIA_WMI_EC_BACKLIGHT
        tristate "EC Backlight Driver for Hybrid Graphics Notebook Systems"
+       depends on ACPI_VIDEO
        depends on ACPI_WMI
        depends on BACKLIGHT_CLASS_DEVICE
        help
@@ -790,6 +791,7 @@ config SAMSUNG_Q10
 config ACPI_TOSHIBA
        tristate "Toshiba Laptop Extras"
        depends on ACPI
+       depends on ACPI_BATTERY
        depends on ACPI_WMI
        select LEDS_CLASS
        select NEW_LEDS
@@ -797,6 +799,7 @@ config ACPI_TOSHIBA
        depends on INPUT
        depends on SERIO_I8042 || SERIO_I8042 = n
        depends on ACPI_VIDEO || ACPI_VIDEO = n
+       depends on HWMON || HWMON = n
        depends on RFKILL || RFKILL = n
        depends on IIO
        select INPUT_SPARSEKMAP
index f1259d8..18224f9 100644 (file)
@@ -650,69 +650,6 @@ static const struct dmi_system_id non_acer_quirks[] __initconst = {
        {}
 };
 
-static int __init
-video_set_backlight_video_vendor(const struct dmi_system_id *d)
-{
-       interface->capability &= ~ACER_CAP_BRIGHTNESS;
-       pr_info("Brightness must be controlled by generic video driver\n");
-       return 0;
-}
-
-static const struct dmi_system_id video_vendor_dmi_table[] __initconst = {
-       {
-               .callback = video_set_backlight_video_vendor,
-               .ident = "Acer TravelMate 4750",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"),
-               },
-       },
-       {
-               .callback = video_set_backlight_video_vendor,
-               .ident = "Acer Extensa 5235",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5235"),
-               },
-       },
-       {
-               .callback = video_set_backlight_video_vendor,
-               .ident = "Acer TravelMate 5760",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5760"),
-               },
-       },
-       {
-               .callback = video_set_backlight_video_vendor,
-               .ident = "Acer Aspire 5750",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"),
-               },
-       },
-       {
-               .callback = video_set_backlight_video_vendor,
-               .ident = "Acer Aspire 5741",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5741"),
-               },
-       },
-       {
-               /*
-                * Note no video_set_backlight_video_vendor, we must use the
-                * acer interface, as there is no native backlight interface.
-                */
-               .ident = "Acer KAV80",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "KAV80"),
-               },
-       },
-       {}
-};
-
 /* Find which quirks are needed for a particular vendor/ model pair */
 static void __init find_quirks(void)
 {
@@ -2484,9 +2421,6 @@ static int __init acer_wmi_init(void)
 
        set_quirks();
 
-       if (dmi_check_system(video_vendor_dmi_table))
-               acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
-
        if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
                interface->capability &= ~ACER_CAP_BRIGHTNESS;
 
@@ -2529,7 +2463,7 @@ static int __init acer_wmi_init(void)
                goto error_platform_register;
        }
 
-       acer_platform_device = platform_device_alloc("acer-wmi", -1);
+       acer_platform_device = platform_device_alloc("acer-wmi", PLATFORM_DEVID_NONE);
        if (!acer_platform_device) {
                err = -ENOMEM;
                goto error_device_alloc;
index 3463629..d2c0fc3 100644 (file)
@@ -676,7 +676,7 @@ static int __init acerhdf_register_platform(void)
        if (err)
                return err;
 
-       acerhdf_dev = platform_device_alloc("acerhdf", -1);
+       acerhdf_dev = platform_device_alloc("acerhdf", PLATFORM_DEVID_NONE);
        if (!acerhdf_dev) {
                err = -ENOMEM;
                goto err_device_alloc;
index c0d0a3c..a825af8 100644 (file)
@@ -3,6 +3,8 @@
 # AMD x86 Platform Specific Drivers
 #
 
+source "drivers/platform/x86/amd/pmf/Kconfig"
+
 config AMD_PMC
        tristate "AMD SoC PMC driver"
        depends on ACPI && PCI && RTC_CLASS
index a03fbb0..2c22919 100644 (file)
@@ -8,3 +8,4 @@ amd-pmc-y                       := pmc.o
 obj-$(CONFIG_AMD_PMC)          += amd-pmc.o
 amd_hsmp-y                     := hsmp.o
 obj-$(CONFIG_AMD_HSMP)         += amd_hsmp.o
+obj-$(CONFIG_AMD_PMF)          += pmf/
index a0c54b8..521c6a2 100644 (file)
@@ -392,7 +392,7 @@ static int __init hsmp_plt_init(void)
        if (ret)
                return ret;
 
-       amd_hsmp_platdev = platform_device_alloc(DRIVER_NAME, -1);
+       amd_hsmp_platdev = platform_device_alloc(DRIVER_NAME, PLATFORM_DEVID_NONE);
        if (!amd_hsmp_platdev) {
                ret = -ENOMEM;
                goto drv_unregister;
index 700eb19..ce859b3 100644 (file)
@@ -39,7 +39,9 @@
 #define AMD_PMC_STB_INDEX_ADDRESS      0xF8
 #define AMD_PMC_STB_INDEX_DATA         0xFC
 #define AMD_PMC_STB_PMI_0              0x03E30600
-#define AMD_PMC_STB_PREDEF             0xC6000001
+#define AMD_PMC_STB_S2IDLE_PREPARE     0xC6000001
+#define AMD_PMC_STB_S2IDLE_RESTORE     0xC6000002
+#define AMD_PMC_STB_S2IDLE_CHECK       0xC6000003
 
 /* STB S2D(Spill to DRAM) has different message port offset */
 #define STB_SPILL_TO_DRAM              0xBE
@@ -151,9 +153,7 @@ struct amd_pmc_dev {
        struct device *dev;
        struct pci_dev *rdev;
        struct mutex lock; /* generic mutex lock */
-#if IS_ENABLED(CONFIG_DEBUG_FS)
        struct dentry *dbgfs_dir;
-#endif /* CONFIG_DEBUG_FS */
 };
 
 static bool enable_stb;
@@ -369,7 +369,64 @@ static void amd_pmc_validate_deepest(struct amd_pmc_dev *pdev)
 }
 #endif
 
-#ifdef CONFIG_DEBUG_FS
+static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev)
+{
+       int rc;
+       u32 val;
+
+       rc = amd_pmc_send_cmd(dev, 0, &val, SMU_MSG_GETSMUVERSION, 1);
+       if (rc)
+               return rc;
+
+       dev->smu_program = (val >> 24) & GENMASK(7, 0);
+       dev->major = (val >> 16) & GENMASK(7, 0);
+       dev->minor = (val >> 8) & GENMASK(7, 0);
+       dev->rev = (val >> 0) & GENMASK(7, 0);
+
+       dev_dbg(dev->dev, "SMU program %u version is %u.%u.%u\n",
+               dev->smu_program, dev->major, dev->minor, dev->rev);
+
+       return 0;
+}
+
+static ssize_t smu_fw_version_show(struct device *d, struct device_attribute *attr,
+                                  char *buf)
+{
+       struct amd_pmc_dev *dev = dev_get_drvdata(d);
+
+       if (!dev->major) {
+               int rc = amd_pmc_get_smu_version(dev);
+
+               if (rc)
+                       return rc;
+       }
+       return sysfs_emit(buf, "%u.%u.%u\n", dev->major, dev->minor, dev->rev);
+}
+
+static ssize_t smu_program_show(struct device *d, struct device_attribute *attr,
+                                  char *buf)
+{
+       struct amd_pmc_dev *dev = dev_get_drvdata(d);
+
+       if (!dev->major) {
+               int rc = amd_pmc_get_smu_version(dev);
+
+               if (rc)
+                       return rc;
+       }
+       return sysfs_emit(buf, "%u\n", dev->smu_program);
+}
+
+static DEVICE_ATTR_RO(smu_fw_version);
+static DEVICE_ATTR_RO(smu_program);
+
+static struct attribute *pmc_attrs[] = {
+       &dev_attr_smu_fw_version.attr,
+       &dev_attr_smu_program.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(pmc);
+
 static int smu_fw_info_show(struct seq_file *s, void *unused)
 {
        struct amd_pmc_dev *dev = s->private;
@@ -435,26 +492,6 @@ static int s0ix_stats_show(struct seq_file *s, void *unused)
 }
 DEFINE_SHOW_ATTRIBUTE(s0ix_stats);
 
-static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev)
-{
-       int rc;
-       u32 val;
-
-       rc = amd_pmc_send_cmd(dev, 0, &val, SMU_MSG_GETSMUVERSION, 1);
-       if (rc)
-               return rc;
-
-       dev->smu_program = (val >> 24) & GENMASK(7, 0);
-       dev->major = (val >> 16) & GENMASK(7, 0);
-       dev->minor = (val >> 8) & GENMASK(7, 0);
-       dev->rev = (val >> 0) & GENMASK(7, 0);
-
-       dev_dbg(dev->dev, "SMU program %u version is %u.%u.%u\n",
-               dev->smu_program, dev->major, dev->minor, dev->rev);
-
-       return 0;
-}
-
 static int amd_pmc_idlemask_show(struct seq_file *s, void *unused)
 {
        struct amd_pmc_dev *dev = s->private;
@@ -504,15 +541,6 @@ static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev)
                                            &amd_pmc_stb_debugfs_fops);
        }
 }
-#else
-static inline void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev)
-{
-}
-
-static inline void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev)
-{
-}
-#endif /* CONFIG_DEBUG_FS */
 
 static void amd_pmc_dump_registers(struct amd_pmc_dev *dev)
 {
@@ -691,8 +719,6 @@ static void amd_pmc_s2idle_prepare(void)
                }
        }
 
-       /* Dump the IdleMask before we send hint to SMU */
-       amd_pmc_idlemask_read(pdev, pdev->dev, NULL);
        msg = amd_pmc_get_os_hint(pdev);
        rc = amd_pmc_send_cmd(pdev, arg, NULL, msg, 0);
        if (rc) {
@@ -700,11 +726,22 @@ static void amd_pmc_s2idle_prepare(void)
                return;
        }
 
-       if (enable_stb) {
-               rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_PREDEF);
-               if (rc)
-                       dev_err(pdev->dev, "error writing to STB: %d\n", rc);
-       }
+       rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_S2IDLE_PREPARE);
+       if (rc)
+               dev_err(pdev->dev, "error writing to STB: %d\n", rc);
+}
+
+static void amd_pmc_s2idle_check(void)
+{
+       struct amd_pmc_dev *pdev = &pmc;
+       int rc;
+
+       /* Dump the IdleMask before we add to the STB */
+       amd_pmc_idlemask_read(pdev, pdev->dev, NULL);
+
+       rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_S2IDLE_CHECK);
+       if (rc)
+               dev_err(pdev->dev, "error writing to STB: %d\n", rc);
 }
 
 static void amd_pmc_s2idle_restore(void)
@@ -721,15 +758,9 @@ static void amd_pmc_s2idle_restore(void)
        /* Let SMU know that we are looking for stats */
        amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_DUMP_DATA, 0);
 
-       /* Dump the IdleMask to see the blockers */
-       amd_pmc_idlemask_read(pdev, pdev->dev, NULL);
-
-       /* Write data incremented by 1 to distinguish in stb_read */
-       if (enable_stb) {
-               rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_PREDEF + 1);
-               if (rc)
-                       dev_err(pdev->dev, "error writing to STB: %d\n", rc);
-       }
+       rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_S2IDLE_RESTORE);
+       if (rc)
+               dev_err(pdev->dev, "error writing to STB: %d\n", rc);
 
        /* Notify on failed entry */
        amd_pmc_validate_deepest(pdev);
@@ -737,6 +768,7 @@ static void amd_pmc_s2idle_restore(void)
 
 static struct acpi_s2idle_dev_ops amd_pmc_s2idle_dev_ops = {
        .prepare = amd_pmc_s2idle_prepare,
+       .check = amd_pmc_s2idle_check,
        .restore = amd_pmc_s2idle_restore,
 };
 #endif
@@ -935,6 +967,7 @@ static struct platform_driver amd_pmc_driver = {
        .driver = {
                .name = "amd_pmc",
                .acpi_match_table = amd_pmc_acpi_ids,
+               .dev_groups = pmc_groups,
        },
        .probe = amd_pmc_probe,
        .remove = amd_pmc_remove,
diff --git a/drivers/platform/x86/amd/pmf/Kconfig b/drivers/platform/x86/amd/pmf/Kconfig
new file mode 100644 (file)
index 0000000..c375498
--- /dev/null
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# AMD PMF Driver
+#
+
+config AMD_PMF
+       tristate "AMD Platform Management Framework"
+       depends on ACPI && PCI
+       select ACPI_PLATFORM_PROFILE
+       help
+         This driver provides support for the AMD Platform Management Framework.
+         The goal is to enhance end user experience by making AMD PCs smarter,
+         quiter, power efficient by adapting to user behavior and environment.
+
+         To compile this driver as a module, choose M here: the module will
+         be called amd_pmf.
diff --git a/drivers/platform/x86/amd/pmf/Makefile b/drivers/platform/x86/amd/pmf/Makefile
new file mode 100644 (file)
index 0000000..fdededf
--- /dev/null
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for linux/drivers/platform/x86/amd/pmf
+# AMD Platform Management Framework
+#
+
+obj-$(CONFIG_AMD_PMF) += amd-pmf.o
+amd-pmf-objs := core.o acpi.o sps.o \
+               auto-mode.o cnqf.o
diff --git a/drivers/platform/x86/amd/pmf/acpi.c b/drivers/platform/x86/amd/pmf/acpi.c
new file mode 100644 (file)
index 0000000..081e84e
--- /dev/null
@@ -0,0 +1,304 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AMD Platform Management Framework Driver
+ *
+ * Copyright (c) 2022, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+ */
+
+#include <linux/acpi.h>
+#include "pmf.h"
+
+#define APMF_CQL_NOTIFICATION  2
+#define APMF_AMT_NOTIFICATION  3
+
+static union acpi_object *apmf_if_call(struct amd_pmf_dev *pdev, int fn, struct acpi_buffer *param)
+{
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       acpi_handle ahandle = ACPI_HANDLE(pdev->dev);
+       struct acpi_object_list apmf_if_arg_list;
+       union acpi_object apmf_if_args[2];
+       acpi_status status;
+
+       apmf_if_arg_list.count = 2;
+       apmf_if_arg_list.pointer = &apmf_if_args[0];
+
+       apmf_if_args[0].type = ACPI_TYPE_INTEGER;
+       apmf_if_args[0].integer.value = fn;
+
+       if (param) {
+               apmf_if_args[1].type = ACPI_TYPE_BUFFER;
+               apmf_if_args[1].buffer.length = param->length;
+               apmf_if_args[1].buffer.pointer = param->pointer;
+       } else {
+               apmf_if_args[1].type = ACPI_TYPE_INTEGER;
+               apmf_if_args[1].integer.value = 0;
+       }
+
+       status = acpi_evaluate_object(ahandle, "APMF", &apmf_if_arg_list, &buffer);
+       if (ACPI_FAILURE(status)) {
+               dev_err(pdev->dev, "APMF method:%d call failed\n", fn);
+               kfree(buffer.pointer);
+               return NULL;
+       }
+
+       return buffer.pointer;
+}
+
+static int apmf_if_call_store_buffer(struct amd_pmf_dev *pdev, int fn, void *dest, size_t out_sz)
+{
+       union acpi_object *info;
+       size_t size;
+       int err = 0;
+
+       info = apmf_if_call(pdev, fn, NULL);
+       if (!info)
+               return -EIO;
+
+       if (info->type != ACPI_TYPE_BUFFER) {
+               dev_err(pdev->dev, "object is not a buffer\n");
+               err = -EINVAL;
+               goto out;
+       }
+
+       if (info->buffer.length < 2) {
+               dev_err(pdev->dev, "buffer too small\n");
+               err = -EINVAL;
+               goto out;
+       }
+
+       size = *(u16 *)info->buffer.pointer;
+       if (info->buffer.length < size) {
+               dev_err(pdev->dev, "buffer smaller then headersize %u < %zu\n",
+                       info->buffer.length, size);
+               err = -EINVAL;
+               goto out;
+       }
+
+       if (size < out_sz) {
+               dev_err(pdev->dev, "buffer too small %zu\n", size);
+               err = -EINVAL;
+               goto out;
+       }
+
+       memcpy(dest, info->buffer.pointer, out_sz);
+
+out:
+       kfree(info);
+       return err;
+}
+
+int is_apmf_func_supported(struct amd_pmf_dev *pdev, unsigned long index)
+{
+       /* If bit-n is set, that indicates function n+1 is supported */
+       return !!(pdev->supported_func & BIT(index - 1));
+}
+
+int apmf_get_static_slider_granular(struct amd_pmf_dev *pdev,
+                                   struct apmf_static_slider_granular_output *data)
+{
+       if (!is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR))
+               return -EINVAL;
+
+       return apmf_if_call_store_buffer(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR,
+                                                                        data, sizeof(*data));
+}
+
+static void apmf_sbios_heartbeat_notify(struct work_struct *work)
+{
+       struct amd_pmf_dev *dev = container_of(work, struct amd_pmf_dev, heart_beat.work);
+       union acpi_object *info;
+
+       dev_dbg(dev->dev, "Sending heartbeat to SBIOS\n");
+       info = apmf_if_call(dev, APMF_FUNC_SBIOS_HEARTBEAT, NULL);
+       if (!info)
+               goto out;
+
+       schedule_delayed_work(&dev->heart_beat, msecs_to_jiffies(dev->hb_interval * 1000));
+
+out:
+       kfree(info);
+}
+
+int apmf_update_fan_idx(struct amd_pmf_dev *pdev, bool manual, u32 idx)
+{
+       union acpi_object *info;
+       struct apmf_fan_idx args;
+       struct acpi_buffer params;
+       int err = 0;
+
+       args.size = sizeof(args);
+       args.fan_ctl_mode = manual;
+       args.fan_ctl_idx = idx;
+
+       params.length = sizeof(args);
+       params.pointer = (void *)&args;
+
+       info = apmf_if_call(pdev, APMF_FUNC_SET_FAN_IDX, &params);
+       if (!info) {
+               err = -EIO;
+               goto out;
+       }
+
+out:
+       kfree(info);
+       return err;
+}
+
+int apmf_get_auto_mode_def(struct amd_pmf_dev *pdev, struct apmf_auto_mode *data)
+{
+       return apmf_if_call_store_buffer(pdev, APMF_FUNC_AUTO_MODE, data, sizeof(*data));
+}
+
+int apmf_get_sbios_requests(struct amd_pmf_dev *pdev, struct apmf_sbios_req *req)
+{
+       return apmf_if_call_store_buffer(pdev, APMF_FUNC_SBIOS_REQUESTS,
+                                                                        req, sizeof(*req));
+}
+
+static void apmf_event_handler(acpi_handle handle, u32 event, void *data)
+{
+       struct amd_pmf_dev *pmf_dev = data;
+       struct apmf_sbios_req req;
+       int ret;
+
+       mutex_lock(&pmf_dev->update_mutex);
+       ret = apmf_get_sbios_requests(pmf_dev, &req);
+       if (ret) {
+               dev_err(pmf_dev->dev, "Failed to get SBIOS requests:%d\n", ret);
+               goto out;
+       }
+
+       if (req.pending_req & BIT(APMF_AMT_NOTIFICATION)) {
+               dev_dbg(pmf_dev->dev, "AMT is supported and notifications %s\n",
+                       req.amt_event ? "Enabled" : "Disabled");
+               pmf_dev->amt_enabled = !!req.amt_event;
+
+               if (pmf_dev->amt_enabled)
+                       amd_pmf_handle_amt(pmf_dev);
+               else
+                       amd_pmf_reset_amt(pmf_dev);
+       }
+
+       if (req.pending_req & BIT(APMF_CQL_NOTIFICATION)) {
+               dev_dbg(pmf_dev->dev, "CQL is supported and notifications %s\n",
+                       req.cql_event ? "Enabled" : "Disabled");
+
+               /* update the target mode information */
+               if (pmf_dev->amt_enabled)
+                       amd_pmf_update_2_cql(pmf_dev, req.cql_event);
+       }
+out:
+       mutex_unlock(&pmf_dev->update_mutex);
+}
+
+static int apmf_if_verify_interface(struct amd_pmf_dev *pdev)
+{
+       struct apmf_verify_interface output;
+       int err;
+
+       err = apmf_if_call_store_buffer(pdev, APMF_FUNC_VERIFY_INTERFACE, &output, sizeof(output));
+       if (err)
+               return err;
+
+       pdev->supported_func = output.supported_functions;
+       dev_dbg(pdev->dev, "supported functions:0x%x notifications:0x%x\n",
+               output.supported_functions, output.notification_mask);
+
+       return 0;
+}
+
+static int apmf_get_system_params(struct amd_pmf_dev *dev)
+{
+       struct apmf_system_params params;
+       int err;
+
+       if (!is_apmf_func_supported(dev, APMF_FUNC_GET_SYS_PARAMS))
+               return -EINVAL;
+
+       err = apmf_if_call_store_buffer(dev, APMF_FUNC_GET_SYS_PARAMS, &params, sizeof(params));
+       if (err)
+               return err;
+
+       dev_dbg(dev->dev, "system params mask:0x%x flags:0x%x cmd_code:0x%x heartbeat:%d\n",
+               params.valid_mask,
+               params.flags,
+               params.command_code,
+               params.heartbeat_int);
+       params.flags = params.flags & params.valid_mask;
+       dev->hb_interval = params.heartbeat_int;
+
+       return 0;
+}
+
+int apmf_get_dyn_slider_def_ac(struct amd_pmf_dev *pdev, struct apmf_dyn_slider_output *data)
+{
+       return apmf_if_call_store_buffer(pdev, APMF_FUNC_DYN_SLIDER_AC, data, sizeof(*data));
+}
+
+int apmf_get_dyn_slider_def_dc(struct amd_pmf_dev *pdev, struct apmf_dyn_slider_output *data)
+{
+       return apmf_if_call_store_buffer(pdev, APMF_FUNC_DYN_SLIDER_DC, data, sizeof(*data));
+}
+
+int apmf_install_handler(struct amd_pmf_dev *pmf_dev)
+{
+       acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev);
+       acpi_status status;
+
+       /* Install the APMF Notify handler */
+       if (is_apmf_func_supported(pmf_dev, APMF_FUNC_AUTO_MODE) &&
+           is_apmf_func_supported(pmf_dev, APMF_FUNC_SBIOS_REQUESTS)) {
+               status = acpi_install_notify_handler(ahandle, ACPI_ALL_NOTIFY,
+                                                    apmf_event_handler, pmf_dev);
+               if (ACPI_FAILURE(status)) {
+                       dev_err(pmf_dev->dev, "failed to install notify handler\n");
+                       return -ENODEV;
+               }
+
+               /* Call the handler once manually to catch up with possibly missed notifies. */
+               apmf_event_handler(ahandle, 0, pmf_dev);
+       }
+
+       return 0;
+}
+
+void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev)
+{
+       acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev);
+
+       if (pmf_dev->hb_interval)
+               cancel_delayed_work_sync(&pmf_dev->heart_beat);
+
+       if (is_apmf_func_supported(pmf_dev, APMF_FUNC_AUTO_MODE) &&
+           is_apmf_func_supported(pmf_dev, APMF_FUNC_SBIOS_REQUESTS))
+               acpi_remove_notify_handler(ahandle, ACPI_ALL_NOTIFY, apmf_event_handler);
+}
+
+int apmf_acpi_init(struct amd_pmf_dev *pmf_dev)
+{
+       int ret;
+
+       ret = apmf_if_verify_interface(pmf_dev);
+       if (ret) {
+               dev_err(pmf_dev->dev, "APMF verify interface failed :%d\n", ret);
+               goto out;
+       }
+
+       ret = apmf_get_system_params(pmf_dev);
+       if (ret) {
+               dev_err(pmf_dev->dev, "APMF apmf_get_system_params failed :%d\n", ret);
+               goto out;
+       }
+
+       if (pmf_dev->hb_interval) {
+               /* send heartbeats only if the interval is not zero */
+               INIT_DELAYED_WORK(&pmf_dev->heart_beat, apmf_sbios_heartbeat_notify);
+               schedule_delayed_work(&pmf_dev->heart_beat, 0);
+       }
+
+out:
+       return ret;
+}
diff --git a/drivers/platform/x86/amd/pmf/auto-mode.c b/drivers/platform/x86/amd/pmf/auto-mode.c
new file mode 100644 (file)
index 0000000..644af42
--- /dev/null
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AMD Platform Management Framework Driver
+ *
+ * Copyright (c) 2022, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+ */
+
+#include <linux/acpi.h>
+#include <linux/workqueue.h>
+#include "pmf.h"
+
+static struct auto_mode_mode_config config_store;
+static const char *state_as_str(unsigned int state);
+
+static void amd_pmf_set_automode(struct amd_pmf_dev *dev, int idx,
+                                struct auto_mode_mode_config *table)
+{
+       struct power_table_control *pwr_ctrl = &config_store.mode_set[idx].power_control;
+
+       amd_pmf_send_cmd(dev, SET_SPL, false, pwr_ctrl->spl, NULL);
+       amd_pmf_send_cmd(dev, SET_FPPT, false, pwr_ctrl->fppt, NULL);
+       amd_pmf_send_cmd(dev, SET_SPPT, false, pwr_ctrl->sppt, NULL);
+       amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pwr_ctrl->sppt_apu_only, NULL);
+       amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pwr_ctrl->stt_min, NULL);
+       amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
+                        pwr_ctrl->stt_skin_temp[STT_TEMP_APU], NULL);
+       amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
+                        pwr_ctrl->stt_skin_temp[STT_TEMP_HS2], NULL);
+
+       if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX))
+               apmf_update_fan_idx(dev, config_store.mode_set[idx].fan_control.manual,
+                                   config_store.mode_set[idx].fan_control.fan_id);
+}
+
+static int amd_pmf_get_moving_avg(struct amd_pmf_dev *pdev, int socket_power)
+{
+       int i, total = 0;
+
+       if (pdev->socket_power_history_idx == -1) {
+               for (i = 0; i < AVG_SAMPLE_SIZE; i++)
+                       pdev->socket_power_history[i] = socket_power;
+       }
+
+       pdev->socket_power_history_idx = (pdev->socket_power_history_idx + 1) % AVG_SAMPLE_SIZE;
+       pdev->socket_power_history[pdev->socket_power_history_idx] = socket_power;
+
+       for (i = 0; i < AVG_SAMPLE_SIZE; i++)
+               total += pdev->socket_power_history[i];
+
+       return total / AVG_SAMPLE_SIZE;
+}
+
+void amd_pmf_trans_automode(struct amd_pmf_dev *dev, int socket_power, ktime_t time_elapsed_ms)
+{
+       int avg_power = 0;
+       bool update = false;
+       int i, j;
+
+       /* Get the average moving average computed by auto mode algorithm */
+       avg_power = amd_pmf_get_moving_avg(dev, socket_power);
+
+       for (i = 0; i < AUTO_TRANSITION_MAX; i++) {
+               if ((config_store.transition[i].shifting_up && avg_power >=
+                    config_store.transition[i].power_threshold) ||
+                   (!config_store.transition[i].shifting_up && avg_power <=
+                    config_store.transition[i].power_threshold)) {
+                       if (config_store.transition[i].timer <
+                           config_store.transition[i].time_constant)
+                               config_store.transition[i].timer += time_elapsed_ms;
+               } else {
+                       config_store.transition[i].timer = 0;
+               }
+
+               if (config_store.transition[i].timer >=
+                   config_store.transition[i].time_constant &&
+                   !config_store.transition[i].applied) {
+                       config_store.transition[i].applied = true;
+                       update = true;
+               } else if (config_store.transition[i].timer <=
+                          config_store.transition[i].time_constant &&
+                          config_store.transition[i].applied) {
+                       config_store.transition[i].applied = false;
+                       update = true;
+               }
+       }
+
+       dev_dbg(dev->dev, "[AUTO_MODE] avg power: %u mW mode: %s\n", avg_power,
+               state_as_str(config_store.current_mode));
+
+       if (update) {
+               for (j = 0; j < AUTO_TRANSITION_MAX; j++) {
+                       /* Apply the mode with highest priority indentified */
+                       if (config_store.transition[j].applied) {
+                               if (config_store.current_mode !=
+                                   config_store.transition[j].target_mode) {
+                                       config_store.current_mode =
+                                                       config_store.transition[j].target_mode;
+                                       dev_dbg(dev->dev, "[AUTO_MODE] moving to mode:%s\n",
+                                               state_as_str(config_store.current_mode));
+                                       amd_pmf_set_automode(dev, config_store.current_mode, NULL);
+                               }
+                               break;
+                       }
+               }
+       }
+}
+
+void amd_pmf_update_2_cql(struct amd_pmf_dev *dev, bool is_cql_event)
+{
+       int mode = config_store.current_mode;
+
+       config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].target_mode =
+                                  is_cql_event ? AUTO_PERFORMANCE_ON_LAP : AUTO_PERFORMANCE;
+
+       if ((mode == AUTO_PERFORMANCE || mode == AUTO_PERFORMANCE_ON_LAP) &&
+           mode != config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].target_mode) {
+               mode = config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].target_mode;
+               amd_pmf_set_automode(dev, mode, NULL);
+       }
+       dev_dbg(dev->dev, "updated CQL thermals\n");
+}
+
+static void amd_pmf_get_power_threshold(void)
+{
+       config_store.transition[AUTO_TRANSITION_TO_QUIET].power_threshold =
+                               config_store.mode_set[AUTO_BALANCE].power_floor -
+                               config_store.transition[AUTO_TRANSITION_TO_QUIET].power_delta;
+
+       config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].power_threshold =
+                               config_store.mode_set[AUTO_BALANCE].power_floor -
+                               config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].power_delta;
+
+       config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].power_threshold =
+                       config_store.mode_set[AUTO_QUIET].power_floor -
+                       config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].power_delta;
+
+       config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].power_threshold =
+               config_store.mode_set[AUTO_PERFORMANCE].power_floor -
+               config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].power_delta;
+}
+
+static const char *state_as_str(unsigned int state)
+{
+       switch (state) {
+       case AUTO_QUIET:
+               return "QUIET";
+       case AUTO_BALANCE:
+               return "BALANCED";
+       case AUTO_PERFORMANCE_ON_LAP:
+               return "ON_LAP";
+       case AUTO_PERFORMANCE:
+               return "PERFORMANCE";
+       default:
+               return "Unknown Auto Mode State";
+       }
+}
+
+static void amd_pmf_load_defaults_auto_mode(struct amd_pmf_dev *dev)
+{
+       struct apmf_auto_mode output;
+       struct power_table_control *pwr_ctrl;
+       int i;
+
+       apmf_get_auto_mode_def(dev, &output);
+       /* time constant */
+       config_store.transition[AUTO_TRANSITION_TO_QUIET].time_constant =
+                                                               output.balanced_to_quiet;
+       config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].time_constant =
+                                                               output.balanced_to_perf;
+       config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].time_constant =
+                                                               output.quiet_to_balanced;
+       config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].time_constant =
+                                                               output.perf_to_balanced;
+
+       /* power floor */
+       config_store.mode_set[AUTO_QUIET].power_floor = output.pfloor_quiet;
+       config_store.mode_set[AUTO_BALANCE].power_floor = output.pfloor_balanced;
+       config_store.mode_set[AUTO_PERFORMANCE].power_floor = output.pfloor_perf;
+       config_store.mode_set[AUTO_PERFORMANCE_ON_LAP].power_floor = output.pfloor_perf;
+
+       /* Power delta for mode change */
+       config_store.transition[AUTO_TRANSITION_TO_QUIET].power_delta =
+                                                               output.pd_balanced_to_quiet;
+       config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].power_delta =
+                                                               output.pd_balanced_to_perf;
+       config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].power_delta =
+                                                               output.pd_quiet_to_balanced;
+       config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].power_delta =
+                                                               output.pd_perf_to_balanced;
+
+       /* Power threshold */
+       amd_pmf_get_power_threshold();
+
+       /* skin temperature limits */
+       pwr_ctrl = &config_store.mode_set[AUTO_QUIET].power_control;
+       pwr_ctrl->spl = output.spl_quiet;
+       pwr_ctrl->sppt = output.sppt_quiet;
+       pwr_ctrl->fppt = output.fppt_quiet;
+       pwr_ctrl->sppt_apu_only = output.sppt_apu_only_quiet;
+       pwr_ctrl->stt_min = output.stt_min_limit_quiet;
+       pwr_ctrl->stt_skin_temp[STT_TEMP_APU] = output.stt_apu_quiet;
+       pwr_ctrl->stt_skin_temp[STT_TEMP_HS2] = output.stt_hs2_quiet;
+
+       pwr_ctrl = &config_store.mode_set[AUTO_BALANCE].power_control;
+       pwr_ctrl->spl = output.spl_balanced;
+       pwr_ctrl->sppt = output.sppt_balanced;
+       pwr_ctrl->fppt = output.fppt_balanced;
+       pwr_ctrl->sppt_apu_only = output.sppt_apu_only_balanced;
+       pwr_ctrl->stt_min = output.stt_min_limit_balanced;
+       pwr_ctrl->stt_skin_temp[STT_TEMP_APU] = output.stt_apu_balanced;
+       pwr_ctrl->stt_skin_temp[STT_TEMP_HS2] = output.stt_hs2_balanced;
+
+       pwr_ctrl = &config_store.mode_set[AUTO_PERFORMANCE].power_control;
+       pwr_ctrl->spl = output.spl_perf;
+       pwr_ctrl->sppt = output.sppt_perf;
+       pwr_ctrl->fppt = output.fppt_perf;
+       pwr_ctrl->sppt_apu_only = output.sppt_apu_only_perf;
+       pwr_ctrl->stt_min = output.stt_min_limit_perf;
+       pwr_ctrl->stt_skin_temp[STT_TEMP_APU] = output.stt_apu_perf;
+       pwr_ctrl->stt_skin_temp[STT_TEMP_HS2] = output.stt_hs2_perf;
+
+       pwr_ctrl = &config_store.mode_set[AUTO_PERFORMANCE_ON_LAP].power_control;
+       pwr_ctrl->spl = output.spl_perf_on_lap;
+       pwr_ctrl->sppt = output.sppt_perf_on_lap;
+       pwr_ctrl->fppt = output.fppt_perf_on_lap;
+       pwr_ctrl->sppt_apu_only = output.sppt_apu_only_perf_on_lap;
+       pwr_ctrl->stt_min = output.stt_min_limit_perf_on_lap;
+       pwr_ctrl->stt_skin_temp[STT_TEMP_APU] = output.stt_apu_perf_on_lap;
+       pwr_ctrl->stt_skin_temp[STT_TEMP_HS2] = output.stt_hs2_perf_on_lap;
+
+       /* Fan ID */
+       config_store.mode_set[AUTO_QUIET].fan_control.fan_id = output.fan_id_quiet;
+       config_store.mode_set[AUTO_BALANCE].fan_control.fan_id = output.fan_id_balanced;
+       config_store.mode_set[AUTO_PERFORMANCE].fan_control.fan_id = output.fan_id_perf;
+       config_store.mode_set[AUTO_PERFORMANCE_ON_LAP].fan_control.fan_id =
+                                                                       output.fan_id_perf;
+
+       config_store.transition[AUTO_TRANSITION_TO_QUIET].target_mode = AUTO_QUIET;
+       config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].target_mode =
+                                                               AUTO_PERFORMANCE;
+       config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].target_mode =
+                                                                       AUTO_BALANCE;
+       config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].target_mode =
+                                                                       AUTO_BALANCE;
+
+       config_store.transition[AUTO_TRANSITION_TO_QUIET].shifting_up = false;
+       config_store.transition[AUTO_TRANSITION_TO_PERFORMANCE].shifting_up = true;
+       config_store.transition[AUTO_TRANSITION_FROM_QUIET_TO_BALANCE].shifting_up = true;
+       config_store.transition[AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE].shifting_up =
+                                                                               false;
+
+       for (i = 0 ; i < AUTO_MODE_MAX ; i++) {
+               if (config_store.mode_set[i].fan_control.fan_id == FAN_INDEX_AUTO)
+                       config_store.mode_set[i].fan_control.manual = false;
+               else
+                       config_store.mode_set[i].fan_control.manual = true;
+       }
+
+       /* set to initial default values */
+       config_store.current_mode = AUTO_BALANCE;
+       dev->socket_power_history_idx = -1;
+}
+
+int amd_pmf_reset_amt(struct amd_pmf_dev *dev)
+{
+       /*
+        * OEM BIOS implementation guide says that if the auto mode is enabled
+        * the platform_profile registration shall be done by the OEM driver.
+        * There could be cases where both static slider and auto mode BIOS
+        * functions are enabled, in that case enable static slider updates
+        * only if it advertised as supported.
+        */
+
+       if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) {
+               int mode = amd_pmf_get_pprof_modes(dev);
+
+               if (mode < 0)
+                       return mode;
+
+               dev_dbg(dev->dev, "resetting AMT thermals\n");
+               amd_pmf_update_slider(dev, SLIDER_OP_SET, mode, NULL);
+       }
+       return 0;
+}
+
+void amd_pmf_handle_amt(struct amd_pmf_dev *dev)
+{
+       amd_pmf_set_automode(dev, config_store.current_mode, NULL);
+}
+
+void amd_pmf_deinit_auto_mode(struct amd_pmf_dev *dev)
+{
+       cancel_delayed_work_sync(&dev->work_buffer);
+}
+
+void amd_pmf_init_auto_mode(struct amd_pmf_dev *dev)
+{
+       amd_pmf_load_defaults_auto_mode(dev);
+       /* update the thermal limits for Automode */
+       amd_pmf_set_automode(dev, config_store.current_mode, NULL);
+       amd_pmf_init_metrics_table(dev);
+}
diff --git a/drivers/platform/x86/amd/pmf/cnqf.c b/drivers/platform/x86/amd/pmf/cnqf.c
new file mode 100644 (file)
index 0000000..668c7c0
--- /dev/null
@@ -0,0 +1,395 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AMD Platform Management Framework Driver
+ *
+ * Copyright (c) 2022, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+ */
+
+#include <linux/workqueue.h>
+#include "pmf.h"
+
+static struct cnqf_config config_store;
+
+static int amd_pmf_set_cnqf(struct amd_pmf_dev *dev, int src, int idx,
+                           struct cnqf_config *table)
+{
+       struct power_table_control *pc;
+
+       pc = &config_store.mode_set[src][idx].power_control;
+
+       amd_pmf_send_cmd(dev, SET_SPL, false, pc->spl, NULL);
+       amd_pmf_send_cmd(dev, SET_FPPT, false, pc->fppt, NULL);
+       amd_pmf_send_cmd(dev, SET_SPPT, false, pc->sppt, NULL);
+       amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false, pc->sppt_apu_only, NULL);
+       amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false, pc->stt_min, NULL);
+       amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false, pc->stt_skin_temp[STT_TEMP_APU],
+                        NULL);
+       amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false, pc->stt_skin_temp[STT_TEMP_HS2],
+                        NULL);
+
+       if (is_apmf_func_supported(dev, APMF_FUNC_SET_FAN_IDX))
+               apmf_update_fan_idx(dev,
+                                   config_store.mode_set[src][idx].fan_control.manual,
+                                   config_store.mode_set[src][idx].fan_control.fan_id);
+
+       return 0;
+}
+
+static void amd_pmf_update_power_threshold(int src)
+{
+       struct cnqf_mode_settings *ts;
+       struct cnqf_tran_params *tp;
+
+       tp = &config_store.trans_param[src][CNQF_TRANSITION_TO_QUIET];
+       ts = &config_store.mode_set[src][CNQF_MODE_BALANCE];
+       tp->power_threshold = ts->power_floor;
+
+       tp = &config_store.trans_param[src][CNQF_TRANSITION_TO_TURBO];
+       ts = &config_store.mode_set[src][CNQF_MODE_PERFORMANCE];
+       tp->power_threshold = ts->power_floor;
+
+       tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE];
+       ts = &config_store.mode_set[src][CNQF_MODE_BALANCE];
+       tp->power_threshold = ts->power_floor;
+
+       tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE];
+       ts = &config_store.mode_set[src][CNQF_MODE_PERFORMANCE];
+       tp->power_threshold = ts->power_floor;
+
+       tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_QUIET_TO_BALANCE];
+       ts = &config_store.mode_set[src][CNQF_MODE_QUIET];
+       tp->power_threshold = ts->power_floor;
+
+       tp = &config_store.trans_param[src][CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE];
+       ts = &config_store.mode_set[src][CNQF_MODE_TURBO];
+       tp->power_threshold = ts->power_floor;
+}
+
+static const char *state_as_str(unsigned int state)
+{
+       switch (state) {
+       case CNQF_MODE_QUIET:
+               return "QUIET";
+       case CNQF_MODE_BALANCE:
+               return "BALANCED";
+       case CNQF_MODE_TURBO:
+               return "TURBO";
+       case CNQF_MODE_PERFORMANCE:
+               return "PERFORMANCE";
+       default:
+               return "Unknown CnQF mode";
+       }
+}
+
+static int amd_pmf_cnqf_get_power_source(struct amd_pmf_dev *dev)
+{
+       if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC) &&
+           is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC))
+               return amd_pmf_get_power_source();
+       else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC))
+               return POWER_SOURCE_DC;
+       else
+               return POWER_SOURCE_AC;
+}
+
+int amd_pmf_trans_cnqf(struct amd_pmf_dev *dev, int socket_power, ktime_t time_lapsed_ms)
+{
+       struct cnqf_tran_params *tp;
+       int src, i, j;
+       u32 avg_power = 0;
+
+       src = amd_pmf_cnqf_get_power_source(dev);
+
+       if (dev->current_profile == PLATFORM_PROFILE_BALANCED) {
+               amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL);
+       } else {
+               /*
+                * Return from here if the platform_profile is not balanced
+                * so that preference is given to user mode selection, rather
+                * than enforcing CnQF to run all the time (if enabled)
+                */
+               return -EINVAL;
+       }
+
+       for (i = 0; i < CNQF_TRANSITION_MAX; i++) {
+               config_store.trans_param[src][i].timer += time_lapsed_ms;
+               config_store.trans_param[src][i].total_power += socket_power;
+               config_store.trans_param[src][i].count++;
+
+               tp = &config_store.trans_param[src][i];
+               if (tp->timer >= tp->time_constant && tp->count) {
+                       avg_power = tp->total_power / tp->count;
+
+                       /* Reset the indices */
+                       tp->timer = 0;
+                       tp->total_power = 0;
+                       tp->count = 0;
+
+                       if ((tp->shifting_up && avg_power >= tp->power_threshold) ||
+                           (!tp->shifting_up && avg_power <= tp->power_threshold)) {
+                               tp->priority = true;
+                       } else {
+                               tp->priority = false;
+                       }
+               }
+       }
+
+       dev_dbg(dev->dev, "[CNQF] Avg power: %u mW socket power: %u mW mode:%s\n",
+               avg_power, socket_power, state_as_str(config_store.current_mode));
+
+       for (j = 0; j < CNQF_TRANSITION_MAX; j++) {
+               /* apply the highest priority */
+               if (config_store.trans_param[src][j].priority) {
+                       if (config_store.current_mode !=
+                           config_store.trans_param[src][j].target_mode) {
+                               config_store.current_mode =
+                                               config_store.trans_param[src][j].target_mode;
+                               dev_dbg(dev->dev, "Moving to Mode :%s\n",
+                                       state_as_str(config_store.current_mode));
+                               amd_pmf_set_cnqf(dev, src,
+                                                config_store.current_mode, NULL);
+                       }
+                       break;
+               }
+       }
+       return 0;
+}
+
+static void amd_pmf_update_trans_data(int idx, struct apmf_dyn_slider_output out)
+{
+       struct cnqf_tran_params *tp;
+
+       tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_QUIET];
+       tp->time_constant = out.t_balanced_to_quiet;
+       tp->target_mode = CNQF_MODE_QUIET;
+       tp->shifting_up = false;
+
+       tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE];
+       tp->time_constant = out.t_balanced_to_perf;
+       tp->target_mode = CNQF_MODE_PERFORMANCE;
+       tp->shifting_up = true;
+
+       tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_QUIET_TO_BALANCE];
+       tp->time_constant = out.t_quiet_to_balanced;
+       tp->target_mode = CNQF_MODE_BALANCE;
+       tp->shifting_up = true;
+
+       tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE];
+       tp->time_constant = out.t_perf_to_balanced;
+       tp->target_mode = CNQF_MODE_BALANCE;
+       tp->shifting_up = false;
+
+       tp = &config_store.trans_param[idx][CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE];
+       tp->time_constant = out.t_turbo_to_perf;
+       tp->target_mode = CNQF_MODE_PERFORMANCE;
+       tp->shifting_up = false;
+
+       tp = &config_store.trans_param[idx][CNQF_TRANSITION_TO_TURBO];
+       tp->time_constant = out.t_perf_to_turbo;
+       tp->target_mode = CNQF_MODE_TURBO;
+       tp->shifting_up = true;
+}
+
+static void amd_pmf_update_mode_set(int idx, struct apmf_dyn_slider_output out)
+{
+       struct cnqf_mode_settings *ms;
+
+       /* Quiet Mode */
+       ms = &config_store.mode_set[idx][CNQF_MODE_QUIET];
+       ms->power_floor = out.ps[APMF_CNQF_QUIET].pfloor;
+       ms->power_control.fppt = out.ps[APMF_CNQF_QUIET].fppt;
+       ms->power_control.sppt = out.ps[APMF_CNQF_QUIET].sppt;
+       ms->power_control.sppt_apu_only = out.ps[APMF_CNQF_QUIET].sppt_apu_only;
+       ms->power_control.spl = out.ps[APMF_CNQF_QUIET].spl;
+       ms->power_control.stt_min = out.ps[APMF_CNQF_QUIET].stt_min_limit;
+       ms->power_control.stt_skin_temp[STT_TEMP_APU] =
+               out.ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_APU];
+       ms->power_control.stt_skin_temp[STT_TEMP_HS2] =
+               out.ps[APMF_CNQF_QUIET].stt_skintemp[STT_TEMP_HS2];
+       ms->fan_control.fan_id = out.ps[APMF_CNQF_QUIET].fan_id;
+
+       /* Balance Mode */
+       ms = &config_store.mode_set[idx][CNQF_MODE_BALANCE];
+       ms->power_floor = out.ps[APMF_CNQF_BALANCE].pfloor;
+       ms->power_control.fppt = out.ps[APMF_CNQF_BALANCE].fppt;
+       ms->power_control.sppt = out.ps[APMF_CNQF_BALANCE].sppt;
+       ms->power_control.sppt_apu_only = out.ps[APMF_CNQF_BALANCE].sppt_apu_only;
+       ms->power_control.spl = out.ps[APMF_CNQF_BALANCE].spl;
+       ms->power_control.stt_min = out.ps[APMF_CNQF_BALANCE].stt_min_limit;
+       ms->power_control.stt_skin_temp[STT_TEMP_APU] =
+               out.ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_APU];
+       ms->power_control.stt_skin_temp[STT_TEMP_HS2] =
+               out.ps[APMF_CNQF_BALANCE].stt_skintemp[STT_TEMP_HS2];
+       ms->fan_control.fan_id = out.ps[APMF_CNQF_BALANCE].fan_id;
+
+       /* Performance Mode */
+       ms = &config_store.mode_set[idx][CNQF_MODE_PERFORMANCE];
+       ms->power_floor = out.ps[APMF_CNQF_PERFORMANCE].pfloor;
+       ms->power_control.fppt = out.ps[APMF_CNQF_PERFORMANCE].fppt;
+       ms->power_control.sppt = out.ps[APMF_CNQF_PERFORMANCE].sppt;
+       ms->power_control.sppt_apu_only = out.ps[APMF_CNQF_PERFORMANCE].sppt_apu_only;
+       ms->power_control.spl = out.ps[APMF_CNQF_PERFORMANCE].spl;
+       ms->power_control.stt_min = out.ps[APMF_CNQF_PERFORMANCE].stt_min_limit;
+       ms->power_control.stt_skin_temp[STT_TEMP_APU] =
+               out.ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_APU];
+       ms->power_control.stt_skin_temp[STT_TEMP_HS2] =
+               out.ps[APMF_CNQF_PERFORMANCE].stt_skintemp[STT_TEMP_HS2];
+       ms->fan_control.fan_id = out.ps[APMF_CNQF_PERFORMANCE].fan_id;
+
+       /* Turbo Mode */
+       ms = &config_store.mode_set[idx][CNQF_MODE_TURBO];
+       ms->power_floor = out.ps[APMF_CNQF_TURBO].pfloor;
+       ms->power_control.fppt = out.ps[APMF_CNQF_TURBO].fppt;
+       ms->power_control.sppt = out.ps[APMF_CNQF_TURBO].sppt;
+       ms->power_control.sppt_apu_only = out.ps[APMF_CNQF_TURBO].sppt_apu_only;
+       ms->power_control.spl = out.ps[APMF_CNQF_TURBO].spl;
+       ms->power_control.stt_min = out.ps[APMF_CNQF_TURBO].stt_min_limit;
+       ms->power_control.stt_skin_temp[STT_TEMP_APU] =
+               out.ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_APU];
+       ms->power_control.stt_skin_temp[STT_TEMP_HS2] =
+               out.ps[APMF_CNQF_TURBO].stt_skintemp[STT_TEMP_HS2];
+       ms->fan_control.fan_id = out.ps[APMF_CNQF_TURBO].fan_id;
+}
+
+static int amd_pmf_check_flags(struct amd_pmf_dev *dev)
+{
+       struct apmf_dyn_slider_output out = {};
+
+       if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC))
+               apmf_get_dyn_slider_def_ac(dev, &out);
+       else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC))
+               apmf_get_dyn_slider_def_dc(dev, &out);
+
+       return out.flags;
+}
+
+static int amd_pmf_load_defaults_cnqf(struct amd_pmf_dev *dev)
+{
+       struct apmf_dyn_slider_output out;
+       int i, j, ret;
+
+       for (i = 0; i < POWER_SOURCE_MAX; i++) {
+               if (!is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC + i))
+                       continue;
+
+               if (i == POWER_SOURCE_AC)
+                       ret = apmf_get_dyn_slider_def_ac(dev, &out);
+               else
+                       ret = apmf_get_dyn_slider_def_dc(dev, &out);
+               if (ret) {
+                       dev_err(dev->dev, "APMF apmf_get_dyn_slider_def_dc failed :%d\n", ret);
+                       return ret;
+               }
+
+               amd_pmf_update_mode_set(i, out);
+               amd_pmf_update_trans_data(i, out);
+               amd_pmf_update_power_threshold(i);
+
+               for (j = 0; j < CNQF_MODE_MAX; j++) {
+                       if (config_store.mode_set[i][j].fan_control.fan_id == FAN_INDEX_AUTO)
+                               config_store.mode_set[i][j].fan_control.manual = false;
+                       else
+                               config_store.mode_set[i][j].fan_control.manual = true;
+               }
+       }
+
+       /* set to initial default values */
+       config_store.current_mode = CNQF_MODE_BALANCE;
+
+       return 0;
+}
+
+static ssize_t cnqf_enable_store(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
+       int mode, result, src;
+       bool input;
+
+       mode = amd_pmf_get_pprof_modes(pdev);
+       if (mode < 0)
+               return mode;
+
+       result = kstrtobool(buf, &input);
+       if (result)
+               return result;
+
+       src = amd_pmf_cnqf_get_power_source(pdev);
+       pdev->cnqf_enabled = input;
+
+       if (pdev->cnqf_enabled && pdev->current_profile == PLATFORM_PROFILE_BALANCED) {
+               amd_pmf_set_cnqf(pdev, src, config_store.current_mode, NULL);
+       } else {
+               if (is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR))
+                       amd_pmf_update_slider(pdev, SLIDER_OP_SET, mode, NULL);
+       }
+
+       dev_dbg(pdev->dev, "Received CnQF %s\n", input ? "on" : "off");
+       return count;
+}
+
+static ssize_t cnqf_enable_show(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
+
+       return sysfs_emit(buf, "%s\n", pdev->cnqf_enabled ? "on" : "off");
+}
+
+static DEVICE_ATTR_RW(cnqf_enable);
+
+static umode_t cnqf_feature_is_visible(struct kobject *kobj,
+                                      struct attribute *attr, int n)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
+
+       return pdev->cnqf_supported ? attr->mode : 0;
+}
+
+static struct attribute *cnqf_feature_attrs[] = {
+       &dev_attr_cnqf_enable.attr,
+       NULL
+};
+
+const struct attribute_group cnqf_feature_attribute_group = {
+       .is_visible = cnqf_feature_is_visible,
+       .attrs = cnqf_feature_attrs,
+};
+
+void amd_pmf_deinit_cnqf(struct amd_pmf_dev *dev)
+{
+       cancel_delayed_work_sync(&dev->work_buffer);
+}
+
+int amd_pmf_init_cnqf(struct amd_pmf_dev *dev)
+{
+       int ret, src;
+
+       /*
+        * Note the caller of this function has already checked that both
+        * APMF_FUNC_DYN_SLIDER_AC and APMF_FUNC_DYN_SLIDER_DC are supported.
+        */
+
+       ret = amd_pmf_load_defaults_cnqf(dev);
+       if (ret < 0)
+               return ret;
+
+       amd_pmf_init_metrics_table(dev);
+
+       dev->cnqf_supported = true;
+       dev->cnqf_enabled = amd_pmf_check_flags(dev);
+
+       /* update the thermal for CnQF */
+       if (dev->cnqf_enabled && dev->current_profile == PLATFORM_PROFILE_BALANCED) {
+               src = amd_pmf_cnqf_get_power_source(dev);
+               amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL);
+       }
+
+       return 0;
+}
diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
new file mode 100644 (file)
index 0000000..a5f5a4b
--- /dev/null
@@ -0,0 +1,412 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AMD Platform Management Framework Driver
+ *
+ * Copyright (c) 2022, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+ */
+
+#include <linux/debugfs.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include "pmf.h"
+
+/* PMF-SMU communication registers */
+#define AMD_PMF_REGISTER_MESSAGE       0xA18
+#define AMD_PMF_REGISTER_RESPONSE      0xA78
+#define AMD_PMF_REGISTER_ARGUMENT      0xA58
+
+/* Base address of SMU for mapping physical address to virtual address */
+#define AMD_PMF_SMU_INDEX_ADDRESS      0xB8
+#define AMD_PMF_SMU_INDEX_DATA         0xBC
+#define AMD_PMF_MAPPING_SIZE           0x01000
+#define AMD_PMF_BASE_ADDR_OFFSET       0x10000
+#define AMD_PMF_BASE_ADDR_LO           0x13B102E8
+#define AMD_PMF_BASE_ADDR_HI           0x13B102EC
+#define AMD_PMF_BASE_ADDR_LO_MASK      GENMASK(15, 0)
+#define AMD_PMF_BASE_ADDR_HI_MASK      GENMASK(31, 20)
+
+/* SMU Response Codes */
+#define AMD_PMF_RESULT_OK                    0x01
+#define AMD_PMF_RESULT_CMD_REJECT_BUSY       0xFC
+#define AMD_PMF_RESULT_CMD_REJECT_PREREQ     0xFD
+#define AMD_PMF_RESULT_CMD_UNKNOWN           0xFE
+#define AMD_PMF_RESULT_FAILED                0xFF
+
+/* List of supported CPU ids */
+#define AMD_CPU_ID_RMB                 0x14b5
+#define AMD_CPU_ID_PS                  0x14e8
+
+#define PMF_MSG_DELAY_MIN_US           50
+#define RESPONSE_REGISTER_LOOP_MAX     20000
+
+#define DELAY_MIN_US   2000
+#define DELAY_MAX_US   3000
+
+/* override Metrics Table sample size time (in ms) */
+static int metrics_table_loop_ms = 1000;
+module_param(metrics_table_loop_ms, int, 0644);
+MODULE_PARM_DESC(metrics_table_loop_ms, "Metrics Table sample size time (default = 1000ms)");
+
+/* Force load on supported older platforms */
+static bool force_load;
+module_param(force_load, bool, 0444);
+MODULE_PARM_DESC(force_load, "Force load this driver on supported older platforms (experimental)");
+
+static int current_power_limits_show(struct seq_file *seq, void *unused)
+{
+       struct amd_pmf_dev *dev = seq->private;
+       struct amd_pmf_static_slider_granular table;
+       int mode, src = 0;
+
+       mode = amd_pmf_get_pprof_modes(dev);
+       if (mode < 0)
+               return mode;
+
+       src = amd_pmf_get_power_source();
+       amd_pmf_update_slider(dev, SLIDER_OP_GET, mode, &table);
+       seq_printf(seq, "spl:%u fppt:%u sppt:%u sppt_apu_only:%u stt_min:%u stt[APU]:%u stt[HS2]: %u\n",
+                  table.prop[src][mode].spl,
+                  table.prop[src][mode].fppt,
+                  table.prop[src][mode].sppt,
+                  table.prop[src][mode].sppt_apu_only,
+                  table.prop[src][mode].stt_min,
+                  table.prop[src][mode].stt_skin_temp[STT_TEMP_APU],
+                  table.prop[src][mode].stt_skin_temp[STT_TEMP_HS2]);
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(current_power_limits);
+
+static void amd_pmf_dbgfs_unregister(struct amd_pmf_dev *dev)
+{
+       debugfs_remove_recursive(dev->dbgfs_dir);
+}
+
+static void amd_pmf_dbgfs_register(struct amd_pmf_dev *dev)
+{
+       dev->dbgfs_dir = debugfs_create_dir("amd_pmf", NULL);
+       debugfs_create_file("current_power_limits", 0644, dev->dbgfs_dir, dev,
+                           &current_power_limits_fops);
+}
+
+int amd_pmf_get_power_source(void)
+{
+       if (power_supply_is_system_supplied() > 0)
+               return POWER_SOURCE_AC;
+       else
+               return POWER_SOURCE_DC;
+}
+
+static void amd_pmf_get_metrics(struct work_struct *work)
+{
+       struct amd_pmf_dev *dev = container_of(work, struct amd_pmf_dev, work_buffer.work);
+       ktime_t time_elapsed_ms;
+       int socket_power;
+
+       mutex_lock(&dev->update_mutex);
+       /* Transfer table contents */
+       memset(dev->buf, 0, sizeof(dev->m_table));
+       amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, 0, 7, NULL);
+       memcpy(&dev->m_table, dev->buf, sizeof(dev->m_table));
+
+       time_elapsed_ms = ktime_to_ms(ktime_get()) - dev->start_time;
+       /* Calculate the avg SoC power consumption */
+       socket_power = dev->m_table.apu_power + dev->m_table.dgpu_power;
+
+       if (dev->amt_enabled) {
+               /* Apply the Auto Mode transition */
+               amd_pmf_trans_automode(dev, socket_power, time_elapsed_ms);
+       }
+
+       if (dev->cnqf_enabled) {
+               /* Apply the CnQF transition */
+               amd_pmf_trans_cnqf(dev, socket_power, time_elapsed_ms);
+       }
+
+       dev->start_time = ktime_to_ms(ktime_get());
+       schedule_delayed_work(&dev->work_buffer, msecs_to_jiffies(metrics_table_loop_ms));
+       mutex_unlock(&dev->update_mutex);
+}
+
+static inline u32 amd_pmf_reg_read(struct amd_pmf_dev *dev, int reg_offset)
+{
+       return ioread32(dev->regbase + reg_offset);
+}
+
+static inline void amd_pmf_reg_write(struct amd_pmf_dev *dev, int reg_offset, u32 val)
+{
+       iowrite32(val, dev->regbase + reg_offset);
+}
+
+static void __maybe_unused amd_pmf_dump_registers(struct amd_pmf_dev *dev)
+{
+       u32 value;
+
+       value = amd_pmf_reg_read(dev, AMD_PMF_REGISTER_RESPONSE);
+       dev_dbg(dev->dev, "AMD_PMF_REGISTER_RESPONSE:%x\n", value);
+
+       value = amd_pmf_reg_read(dev, AMD_PMF_REGISTER_ARGUMENT);
+       dev_dbg(dev->dev, "AMD_PMF_REGISTER_ARGUMENT:%d\n", value);
+
+       value = amd_pmf_reg_read(dev, AMD_PMF_REGISTER_MESSAGE);
+       dev_dbg(dev->dev, "AMD_PMF_REGISTER_MESSAGE:%x\n", value);
+}
+
+int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 *data)
+{
+       int rc;
+       u32 val;
+
+       mutex_lock(&dev->lock);
+
+       /* Wait until we get a valid response */
+       rc = readx_poll_timeout(ioread32, dev->regbase + AMD_PMF_REGISTER_RESPONSE,
+                               val, val != 0, PMF_MSG_DELAY_MIN_US,
+                               PMF_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX);
+       if (rc) {
+               dev_err(dev->dev, "failed to talk to SMU\n");
+               goto out_unlock;
+       }
+
+       /* Write zero to response register */
+       amd_pmf_reg_write(dev, AMD_PMF_REGISTER_RESPONSE, 0);
+
+       /* Write argument into argument register */
+       amd_pmf_reg_write(dev, AMD_PMF_REGISTER_ARGUMENT, arg);
+
+       /* Write message ID to message ID register */
+       amd_pmf_reg_write(dev, AMD_PMF_REGISTER_MESSAGE, message);
+
+       /* Wait until we get a valid response */
+       rc = readx_poll_timeout(ioread32, dev->regbase + AMD_PMF_REGISTER_RESPONSE,
+                               val, val != 0, PMF_MSG_DELAY_MIN_US,
+                               PMF_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX);
+       if (rc) {
+               dev_err(dev->dev, "SMU response timed out\n");
+               goto out_unlock;
+       }
+
+       switch (val) {
+       case AMD_PMF_RESULT_OK:
+               if (get) {
+                       /* PMFW may take longer time to return back the data */
+                       usleep_range(DELAY_MIN_US, 10 * DELAY_MAX_US);
+                       *data = amd_pmf_reg_read(dev, AMD_PMF_REGISTER_ARGUMENT);
+               }
+               break;
+       case AMD_PMF_RESULT_CMD_REJECT_BUSY:
+               dev_err(dev->dev, "SMU not ready. err: 0x%x\n", val);
+               rc = -EBUSY;
+               goto out_unlock;
+       case AMD_PMF_RESULT_CMD_UNKNOWN:
+               dev_err(dev->dev, "SMU cmd unknown. err: 0x%x\n", val);
+               rc = -EINVAL;
+               goto out_unlock;
+       case AMD_PMF_RESULT_CMD_REJECT_PREREQ:
+       case AMD_PMF_RESULT_FAILED:
+       default:
+               dev_err(dev->dev, "SMU cmd failed. err: 0x%x\n", val);
+               rc = -EIO;
+               goto out_unlock;
+       }
+
+out_unlock:
+       mutex_unlock(&dev->lock);
+       amd_pmf_dump_registers(dev);
+       return rc;
+}
+
+static const struct pci_device_id pmf_pci_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RMB) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PS) },
+       { }
+};
+
+int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev)
+{
+       u64 phys_addr;
+       u32 hi, low;
+
+       INIT_DELAYED_WORK(&dev->work_buffer, amd_pmf_get_metrics);
+
+       /* Get Metrics Table Address */
+       dev->buf = kzalloc(sizeof(dev->m_table), GFP_KERNEL);
+       if (!dev->buf)
+               return -ENOMEM;
+
+       phys_addr = virt_to_phys(dev->buf);
+       hi = phys_addr >> 32;
+       low = phys_addr & GENMASK(31, 0);
+
+       amd_pmf_send_cmd(dev, SET_DRAM_ADDR_HIGH, 0, hi, NULL);
+       amd_pmf_send_cmd(dev, SET_DRAM_ADDR_LOW, 0, low, NULL);
+
+       /*
+        * Start collecting the metrics data after a small delay
+        * or else, we might end up getting stale values from PMFW.
+        */
+       schedule_delayed_work(&dev->work_buffer, msecs_to_jiffies(metrics_table_loop_ms * 3));
+
+       return 0;
+}
+
+static void amd_pmf_init_features(struct amd_pmf_dev *dev)
+{
+       int ret;
+
+       /* Enable Static Slider */
+       if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) {
+               amd_pmf_init_sps(dev);
+               dev_dbg(dev->dev, "SPS enabled and Platform Profiles registered\n");
+       }
+
+       /* Enable Auto Mode */
+       if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) {
+               amd_pmf_init_auto_mode(dev);
+               dev_dbg(dev->dev, "Auto Mode Init done\n");
+       } else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC) ||
+                         is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) {
+               /* Enable Cool n Quiet Framework (CnQF) */
+               ret = amd_pmf_init_cnqf(dev);
+               if (ret)
+                       dev_warn(dev->dev, "CnQF Init failed\n");
+       }
+}
+
+static void amd_pmf_deinit_features(struct amd_pmf_dev *dev)
+{
+       if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR))
+               amd_pmf_deinit_sps(dev);
+
+       if (is_apmf_func_supported(dev, APMF_FUNC_AUTO_MODE)) {
+               amd_pmf_deinit_auto_mode(dev);
+       } else if (is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_AC) ||
+                         is_apmf_func_supported(dev, APMF_FUNC_DYN_SLIDER_DC)) {
+               amd_pmf_deinit_cnqf(dev);
+       }
+}
+
+static const struct acpi_device_id amd_pmf_acpi_ids[] = {
+       {"AMDI0100", 0x100},
+       {"AMDI0102", 0},
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, amd_pmf_acpi_ids);
+
+static int amd_pmf_probe(struct platform_device *pdev)
+{
+       const struct acpi_device_id *id;
+       struct amd_pmf_dev *dev;
+       struct pci_dev *rdev;
+       u32 base_addr_lo;
+       u32 base_addr_hi;
+       u64 base_addr;
+       u32 val;
+       int err;
+
+       id = acpi_match_device(amd_pmf_acpi_ids, &pdev->dev);
+       if (!id)
+               return -ENODEV;
+
+       if (id->driver_data == 0x100 && !force_load)
+               return -ENODEV;
+
+       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       dev->dev = &pdev->dev;
+
+       rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
+       if (!rdev || !pci_match_id(pmf_pci_ids, rdev)) {
+               pci_dev_put(rdev);
+               return -ENODEV;
+       }
+
+       dev->cpu_id = rdev->device;
+       err = pci_write_config_dword(rdev, AMD_PMF_SMU_INDEX_ADDRESS, AMD_PMF_BASE_ADDR_LO);
+       if (err) {
+               dev_err(dev->dev, "error writing to 0x%x\n", AMD_PMF_SMU_INDEX_ADDRESS);
+               pci_dev_put(rdev);
+               return pcibios_err_to_errno(err);
+       }
+
+       err = pci_read_config_dword(rdev, AMD_PMF_SMU_INDEX_DATA, &val);
+       if (err) {
+               pci_dev_put(rdev);
+               return pcibios_err_to_errno(err);
+       }
+
+       base_addr_lo = val & AMD_PMF_BASE_ADDR_HI_MASK;
+
+       err = pci_write_config_dword(rdev, AMD_PMF_SMU_INDEX_ADDRESS, AMD_PMF_BASE_ADDR_HI);
+       if (err) {
+               dev_err(dev->dev, "error writing to 0x%x\n", AMD_PMF_SMU_INDEX_ADDRESS);
+               pci_dev_put(rdev);
+               return pcibios_err_to_errno(err);
+       }
+
+       err = pci_read_config_dword(rdev, AMD_PMF_SMU_INDEX_DATA, &val);
+       if (err) {
+               pci_dev_put(rdev);
+               return pcibios_err_to_errno(err);
+       }
+
+       base_addr_hi = val & AMD_PMF_BASE_ADDR_LO_MASK;
+       pci_dev_put(rdev);
+       base_addr = ((u64)base_addr_hi << 32 | base_addr_lo);
+
+       dev->regbase = devm_ioremap(dev->dev, base_addr + AMD_PMF_BASE_ADDR_OFFSET,
+                                   AMD_PMF_MAPPING_SIZE);
+       if (!dev->regbase)
+               return -ENOMEM;
+
+       apmf_acpi_init(dev);
+       platform_set_drvdata(pdev, dev);
+       amd_pmf_init_features(dev);
+       apmf_install_handler(dev);
+       amd_pmf_dbgfs_register(dev);
+
+       mutex_init(&dev->lock);
+       mutex_init(&dev->update_mutex);
+       dev_info(dev->dev, "registered PMF device successfully\n");
+
+       return 0;
+}
+
+static int amd_pmf_remove(struct platform_device *pdev)
+{
+       struct amd_pmf_dev *dev = platform_get_drvdata(pdev);
+
+       mutex_destroy(&dev->lock);
+       mutex_destroy(&dev->update_mutex);
+       amd_pmf_deinit_features(dev);
+       apmf_acpi_deinit(dev);
+       amd_pmf_dbgfs_unregister(dev);
+       kfree(dev->buf);
+       return 0;
+}
+
+static const struct attribute_group *amd_pmf_driver_groups[] = {
+       &cnqf_feature_attribute_group,
+       NULL,
+};
+
+static struct platform_driver amd_pmf_driver = {
+       .driver = {
+               .name = "amd-pmf",
+               .acpi_match_table = amd_pmf_acpi_ids,
+               .dev_groups = amd_pmf_driver_groups,
+       },
+       .probe = amd_pmf_probe,
+       .remove = amd_pmf_remove,
+};
+module_platform_driver(amd_pmf_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AMD Platform Management Framework Driver");
diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
new file mode 100644 (file)
index 0000000..84bbe2c
--- /dev/null
@@ -0,0 +1,417 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * AMD Platform Management Framework Driver
+ *
+ * Copyright (c) 2022, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+ */
+
+#ifndef PMF_H
+#define PMF_H
+
+#include <linux/acpi.h>
+#include <linux/platform_profile.h>
+
+/* APMF Functions */
+#define APMF_FUNC_VERIFY_INTERFACE                     0
+#define APMF_FUNC_GET_SYS_PARAMS                       1
+#define APMF_FUNC_SBIOS_REQUESTS                       2
+#define APMF_FUNC_SBIOS_HEARTBEAT                      4
+#define APMF_FUNC_AUTO_MODE                                    5
+#define APMF_FUNC_SET_FAN_IDX                          7
+#define APMF_FUNC_STATIC_SLIDER_GRANULAR       9
+#define APMF_FUNC_DYN_SLIDER_AC                                11
+#define APMF_FUNC_DYN_SLIDER_DC                                12
+
+/* Message Definitions */
+#define SET_SPL                                0x03 /* SPL: Sustained Power Limit */
+#define SET_SPPT                       0x05 /* SPPT: Slow Package Power Tracking */
+#define SET_FPPT                       0x07 /* FPPT: Fast Package Power Tracking */
+#define GET_SPL                                0x0B
+#define GET_SPPT                       0x0D
+#define GET_FPPT                       0x0F
+#define SET_DRAM_ADDR_HIGH     0x14
+#define SET_DRAM_ADDR_LOW      0x15
+#define SET_TRANSFER_TABLE     0x16
+#define SET_STT_MIN_LIMIT      0x18 /* STT: Skin Temperature Tracking */
+#define SET_STT_LIMIT_APU      0x19
+#define SET_STT_LIMIT_HS2      0x1A
+#define SET_SPPT_APU_ONLY      0x1D
+#define GET_SPPT_APU_ONLY      0x1E
+#define GET_STT_MIN_LIMIT      0x1F
+#define GET_STT_LIMIT_APU      0x20
+#define GET_STT_LIMIT_HS2      0x21
+
+/* Fan Index for Auto Mode */
+#define FAN_INDEX_AUTO         0xFFFFFFFF
+
+#define ARG_NONE 0
+#define AVG_SAMPLE_SIZE 3
+
+/* AMD PMF BIOS interfaces */
+struct apmf_verify_interface {
+       u16 size;
+       u16 version;
+       u32 notification_mask;
+       u32 supported_functions;
+} __packed;
+
+struct apmf_system_params {
+       u16 size;
+       u32 valid_mask;
+       u32 flags;
+       u8 command_code;
+       u32 heartbeat_int;
+} __packed;
+
+struct apmf_sbios_req {
+       u16 size;
+       u32 pending_req;
+       u8 rsd;
+       u8 cql_event;
+       u8 amt_event;
+       u32 fppt;
+       u32 sppt;
+       u32 fppt_apu_only;
+       u32 spl;
+       u32 stt_min_limit;
+       u8 skin_temp_apu;
+       u8 skin_temp_hs2;
+} __packed;
+
+struct apmf_fan_idx {
+       u16 size;
+       u8 fan_ctl_mode;
+       u32 fan_ctl_idx;
+} __packed;
+
+struct smu_pmf_metrics {
+       u16 gfxclk_freq; /* in MHz */
+       u16 socclk_freq; /* in MHz */
+       u16 vclk_freq; /* in MHz */
+       u16 dclk_freq; /* in MHz */
+       u16 memclk_freq; /* in MHz */
+       u16 spare;
+       u16 gfx_activity; /* in Centi */
+       u16 uvd_activity; /* in Centi */
+       u16 voltage[2]; /* in mV */
+       u16 currents[2]; /* in mA */
+       u16 power[2];/* in mW */
+       u16 core_freq[8]; /* in MHz */
+       u16 core_power[8]; /* in mW */
+       u16 core_temp[8]; /* in centi-Celsius */
+       u16 l3_freq; /* in MHz */
+       u16 l3_temp; /* in centi-Celsius */
+       u16 gfx_temp; /* in centi-Celsius */
+       u16 soc_temp; /* in centi-Celsius */
+       u16 throttler_status;
+       u16 current_socketpower; /* in mW */
+       u16 stapm_orig_limit; /* in W */
+       u16 stapm_cur_limit; /* in W */
+       u32 apu_power; /* in mW */
+       u32 dgpu_power; /* in mW */
+       u16 vdd_tdc_val; /* in mA */
+       u16 soc_tdc_val; /* in mA */
+       u16 vdd_edc_val; /* in mA */
+       u16 soc_edcv_al; /* in mA */
+       u16 infra_cpu_maxfreq; /* in MHz */
+       u16 infra_gfx_maxfreq; /* in MHz */
+       u16 skin_temp; /* in centi-Celsius */
+       u16 device_state;
+} __packed;
+
+enum amd_stt_skin_temp {
+       STT_TEMP_APU,
+       STT_TEMP_HS2,
+       STT_TEMP_COUNT,
+};
+
+enum amd_slider_op {
+       SLIDER_OP_GET,
+       SLIDER_OP_SET,
+};
+
+enum power_source {
+       POWER_SOURCE_AC,
+       POWER_SOURCE_DC,
+       POWER_SOURCE_MAX,
+};
+
+enum power_modes {
+       POWER_MODE_PERFORMANCE,
+       POWER_MODE_BALANCED_POWER,
+       POWER_MODE_POWER_SAVER,
+       POWER_MODE_MAX,
+};
+
+struct amd_pmf_dev {
+       void __iomem *regbase;
+       void __iomem *smu_virt_addr;
+       void *buf;
+       u32 base_addr;
+       u32 cpu_id;
+       struct device *dev;
+       struct mutex lock; /* protects the PMF interface */
+       u32 supported_func;
+       enum platform_profile_option current_profile;
+       struct platform_profile_handler pprof;
+       struct dentry *dbgfs_dir;
+       int hb_interval; /* SBIOS heartbeat interval */
+       struct delayed_work heart_beat;
+       struct smu_pmf_metrics m_table;
+       struct delayed_work work_buffer;
+       ktime_t start_time;
+       int socket_power_history[AVG_SAMPLE_SIZE];
+       int socket_power_history_idx;
+       bool amt_enabled;
+       struct mutex update_mutex; /* protects race between ACPI handler and metrics thread */
+       bool cnqf_enabled;
+       bool cnqf_supported;
+};
+
+struct apmf_sps_prop_granular {
+       u32 fppt;
+       u32 sppt;
+       u32 sppt_apu_only;
+       u32 spl;
+       u32 stt_min;
+       u8 stt_skin_temp[STT_TEMP_COUNT];
+       u32 fan_id;
+} __packed;
+
+/* Static Slider */
+struct apmf_static_slider_granular_output {
+       u16 size;
+       struct apmf_sps_prop_granular prop[POWER_SOURCE_MAX * POWER_MODE_MAX];
+} __packed;
+
+struct amd_pmf_static_slider_granular {
+       u16 size;
+       struct apmf_sps_prop_granular prop[POWER_SOURCE_MAX][POWER_MODE_MAX];
+};
+
+struct fan_table_control {
+       bool manual;
+       unsigned long fan_id;
+};
+
+struct power_table_control {
+       u32 spl;
+       u32 sppt;
+       u32 fppt;
+       u32 sppt_apu_only;
+       u32 stt_min;
+       u32 stt_skin_temp[STT_TEMP_COUNT];
+       u32 reserved[16];
+};
+
+/* Auto Mode Layer */
+enum auto_mode_transition_priority {
+       AUTO_TRANSITION_TO_PERFORMANCE, /* Any other mode to Performance Mode */
+       AUTO_TRANSITION_FROM_QUIET_TO_BALANCE, /* Quiet Mode to Balance Mode */
+       AUTO_TRANSITION_TO_QUIET, /* Any other mode to Quiet Mode */
+       AUTO_TRANSITION_FROM_PERFORMANCE_TO_BALANCE, /* Performance Mode to Balance Mode */
+       AUTO_TRANSITION_MAX,
+};
+
+enum auto_mode_mode {
+       AUTO_QUIET,
+       AUTO_BALANCE,
+       AUTO_PERFORMANCE_ON_LAP,
+       AUTO_PERFORMANCE,
+       AUTO_MODE_MAX,
+};
+
+struct auto_mode_trans_params {
+       u32 time_constant; /* minimum time required to switch to next mode */
+       u32 power_delta; /* delta power to shift mode */
+       u32 power_threshold;
+       u32 timer; /* elapsed time. if timer > TimeThreshold, it will move to next mode */
+       u32 applied;
+       enum auto_mode_mode target_mode;
+       u32 shifting_up;
+};
+
+struct auto_mode_mode_settings {
+       struct power_table_control power_control;
+       struct fan_table_control fan_control;
+       u32 power_floor;
+};
+
+struct auto_mode_mode_config {
+       struct auto_mode_trans_params transition[AUTO_TRANSITION_MAX];
+       struct auto_mode_mode_settings mode_set[AUTO_MODE_MAX];
+       enum auto_mode_mode current_mode;
+};
+
+struct apmf_auto_mode {
+       u16 size;
+       /* time constant */
+       u32 balanced_to_perf;
+       u32 perf_to_balanced;
+       u32 quiet_to_balanced;
+       u32 balanced_to_quiet;
+       /* power floor */
+       u32 pfloor_perf;
+       u32 pfloor_balanced;
+       u32 pfloor_quiet;
+       /* Power delta for mode change */
+       u32 pd_balanced_to_perf;
+       u32 pd_perf_to_balanced;
+       u32 pd_quiet_to_balanced;
+       u32 pd_balanced_to_quiet;
+       /* skin temperature limits */
+       u8 stt_apu_perf_on_lap; /* CQL ON */
+       u8 stt_hs2_perf_on_lap; /* CQL ON */
+       u8 stt_apu_perf;
+       u8 stt_hs2_perf;
+       u8 stt_apu_balanced;
+       u8 stt_hs2_balanced;
+       u8 stt_apu_quiet;
+       u8 stt_hs2_quiet;
+       u32 stt_min_limit_perf_on_lap; /* CQL ON */
+       u32 stt_min_limit_perf;
+       u32 stt_min_limit_balanced;
+       u32 stt_min_limit_quiet;
+       /* SPL based */
+       u32 fppt_perf_on_lap; /* CQL ON */
+       u32 sppt_perf_on_lap; /* CQL ON */
+       u32 spl_perf_on_lap; /* CQL ON */
+       u32 sppt_apu_only_perf_on_lap; /* CQL ON */
+       u32 fppt_perf;
+       u32 sppt_perf;
+       u32 spl_perf;
+       u32 sppt_apu_only_perf;
+       u32 fppt_balanced;
+       u32 sppt_balanced;
+       u32 spl_balanced;
+       u32 sppt_apu_only_balanced;
+       u32 fppt_quiet;
+       u32 sppt_quiet;
+       u32 spl_quiet;
+       u32 sppt_apu_only_quiet;
+       /* Fan ID */
+       u32 fan_id_perf;
+       u32 fan_id_balanced;
+       u32 fan_id_quiet;
+} __packed;
+
+/* CnQF Layer */
+enum cnqf_trans_priority {
+       CNQF_TRANSITION_TO_TURBO, /* Any other mode to Turbo Mode */
+       CNQF_TRANSITION_FROM_BALANCE_TO_PERFORMANCE, /* quiet/balance to Performance Mode */
+       CNQF_TRANSITION_FROM_QUIET_TO_BALANCE, /* Quiet Mode to Balance Mode */
+       CNQF_TRANSITION_TO_QUIET, /* Any other mode to Quiet Mode */
+       CNQF_TRANSITION_FROM_PERFORMANCE_TO_BALANCE, /* Performance/Turbo to Balance Mode */
+       CNQF_TRANSITION_FROM_TURBO_TO_PERFORMANCE, /* Turbo mode to Performance Mode */
+       CNQF_TRANSITION_MAX,
+};
+
+enum cnqf_mode {
+       CNQF_MODE_QUIET,
+       CNQF_MODE_BALANCE,
+       CNQF_MODE_PERFORMANCE,
+       CNQF_MODE_TURBO,
+       CNQF_MODE_MAX,
+};
+
+enum apmf_cnqf_pos {
+       APMF_CNQF_TURBO,
+       APMF_CNQF_PERFORMANCE,
+       APMF_CNQF_BALANCE,
+       APMF_CNQF_QUIET,
+       APMF_CNQF_MAX,
+};
+
+struct cnqf_mode_settings {
+       struct power_table_control power_control;
+       struct fan_table_control fan_control;
+       u32 power_floor;
+};
+
+struct cnqf_tran_params {
+       u32 time_constant; /* minimum time required to switch to next mode */
+       u32 power_threshold;
+       u32 timer; /* elapsed time. if timer > timethreshold, it will move to next mode */
+       u32 total_power;
+       u32 count;
+       bool priority;
+       bool shifting_up;
+       enum cnqf_mode target_mode;
+};
+
+struct cnqf_config {
+       struct cnqf_tran_params trans_param[POWER_SOURCE_MAX][CNQF_TRANSITION_MAX];
+       struct cnqf_mode_settings mode_set[POWER_SOURCE_MAX][CNQF_MODE_MAX];
+       struct power_table_control defaults;
+       enum cnqf_mode current_mode;
+       u32 power_src;
+       u32 avg_power;
+};
+
+struct apmf_cnqf_power_set {
+       u32 pfloor;
+       u32 fppt;
+       u32 sppt;
+       u32 sppt_apu_only;
+       u32 spl;
+       u32 stt_min_limit;
+       u8 stt_skintemp[STT_TEMP_COUNT];
+       u32 fan_id;
+} __packed;
+
+struct apmf_dyn_slider_output {
+       u16 size;
+       u16 flags;
+       u32 t_perf_to_turbo;
+       u32 t_balanced_to_perf;
+       u32 t_quiet_to_balanced;
+       u32 t_balanced_to_quiet;
+       u32 t_perf_to_balanced;
+       u32 t_turbo_to_perf;
+       struct apmf_cnqf_power_set ps[APMF_CNQF_MAX];
+} __packed;
+
+/* Core Layer */
+int apmf_acpi_init(struct amd_pmf_dev *pmf_dev);
+void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev);
+int is_apmf_func_supported(struct amd_pmf_dev *pdev, unsigned long index);
+int amd_pmf_send_cmd(struct amd_pmf_dev *dev, u8 message, bool get, u32 arg, u32 *data);
+int amd_pmf_init_metrics_table(struct amd_pmf_dev *dev);
+int amd_pmf_get_power_source(void);
+int apmf_install_handler(struct amd_pmf_dev *pmf_dev);
+
+/* SPS Layer */
+int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf);
+void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx,
+                          struct amd_pmf_static_slider_granular *table);
+int amd_pmf_init_sps(struct amd_pmf_dev *dev);
+void amd_pmf_deinit_sps(struct amd_pmf_dev *dev);
+int apmf_get_static_slider_granular(struct amd_pmf_dev *pdev,
+                                   struct apmf_static_slider_granular_output *output);
+
+
+int apmf_update_fan_idx(struct amd_pmf_dev *pdev, bool manual, u32 idx);
+
+/* Auto Mode Layer */
+int apmf_get_auto_mode_def(struct amd_pmf_dev *pdev, struct apmf_auto_mode *data);
+void amd_pmf_init_auto_mode(struct amd_pmf_dev *dev);
+void amd_pmf_deinit_auto_mode(struct amd_pmf_dev *dev);
+void amd_pmf_trans_automode(struct amd_pmf_dev *dev, int socket_power, ktime_t time_elapsed_ms);
+int apmf_get_sbios_requests(struct amd_pmf_dev *pdev, struct apmf_sbios_req *req);
+
+void amd_pmf_update_2_cql(struct amd_pmf_dev *dev, bool is_cql_event);
+int amd_pmf_reset_amt(struct amd_pmf_dev *dev);
+void amd_pmf_handle_amt(struct amd_pmf_dev *dev);
+
+/* CnQF Layer */
+int apmf_get_dyn_slider_def_ac(struct amd_pmf_dev *pdev, struct apmf_dyn_slider_output *data);
+int apmf_get_dyn_slider_def_dc(struct amd_pmf_dev *pdev, struct apmf_dyn_slider_output *data);
+int amd_pmf_init_cnqf(struct amd_pmf_dev *dev);
+void amd_pmf_deinit_cnqf(struct amd_pmf_dev *dev);
+int amd_pmf_trans_cnqf(struct amd_pmf_dev *dev, int socket_power, ktime_t time_lapsed_ms);
+extern const struct attribute_group cnqf_feature_attribute_group;
+
+#endif /* PMF_H */
diff --git a/drivers/platform/x86/amd/pmf/sps.c b/drivers/platform/x86/amd/pmf/sps.c
new file mode 100644 (file)
index 0000000..dba7e36
--- /dev/null
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AMD Platform Management Framework (PMF) Driver
+ *
+ * Copyright (c) 2022, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+ */
+
+#include "pmf.h"
+
+static struct amd_pmf_static_slider_granular config_store;
+
+static void amd_pmf_load_defaults_sps(struct amd_pmf_dev *dev)
+{
+       struct apmf_static_slider_granular_output output;
+       int i, j, idx = 0;
+
+       memset(&config_store, 0, sizeof(config_store));
+       apmf_get_static_slider_granular(dev, &output);
+
+       for (i = 0; i < POWER_SOURCE_MAX; i++) {
+               for (j = 0; j < POWER_MODE_MAX; j++) {
+                       config_store.prop[i][j].spl = output.prop[idx].spl;
+                       config_store.prop[i][j].sppt = output.prop[idx].sppt;
+                       config_store.prop[i][j].sppt_apu_only =
+                                               output.prop[idx].sppt_apu_only;
+                       config_store.prop[i][j].fppt = output.prop[idx].fppt;
+                       config_store.prop[i][j].stt_min = output.prop[idx].stt_min;
+                       config_store.prop[i][j].stt_skin_temp[STT_TEMP_APU] =
+                                       output.prop[idx].stt_skin_temp[STT_TEMP_APU];
+                       config_store.prop[i][j].stt_skin_temp[STT_TEMP_HS2] =
+                                       output.prop[idx].stt_skin_temp[STT_TEMP_HS2];
+                       config_store.prop[i][j].fan_id = output.prop[idx].fan_id;
+                       idx++;
+               }
+       }
+}
+
+void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx,
+                          struct amd_pmf_static_slider_granular *table)
+{
+       int src = amd_pmf_get_power_source();
+
+       if (op == SLIDER_OP_SET) {
+               amd_pmf_send_cmd(dev, SET_SPL, false, config_store.prop[src][idx].spl, NULL);
+               amd_pmf_send_cmd(dev, SET_FPPT, false, config_store.prop[src][idx].fppt, NULL);
+               amd_pmf_send_cmd(dev, SET_SPPT, false, config_store.prop[src][idx].sppt, NULL);
+               amd_pmf_send_cmd(dev, SET_SPPT_APU_ONLY, false,
+                                config_store.prop[src][idx].sppt_apu_only, NULL);
+               amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false,
+                                config_store.prop[src][idx].stt_min, NULL);
+               amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
+                                config_store.prop[src][idx].stt_skin_temp[STT_TEMP_APU], NULL);
+               amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
+                                config_store.prop[src][idx].stt_skin_temp[STT_TEMP_HS2], NULL);
+       } else if (op == SLIDER_OP_GET) {
+               amd_pmf_send_cmd(dev, GET_SPL, true, ARG_NONE, &table->prop[src][idx].spl);
+               amd_pmf_send_cmd(dev, GET_FPPT, true, ARG_NONE, &table->prop[src][idx].fppt);
+               amd_pmf_send_cmd(dev, GET_SPPT, true, ARG_NONE, &table->prop[src][idx].sppt);
+               amd_pmf_send_cmd(dev, GET_SPPT_APU_ONLY, true, ARG_NONE,
+                                &table->prop[src][idx].sppt_apu_only);
+               amd_pmf_send_cmd(dev, GET_STT_MIN_LIMIT, true, ARG_NONE,
+                                &table->prop[src][idx].stt_min);
+               amd_pmf_send_cmd(dev, GET_STT_LIMIT_APU, true, ARG_NONE,
+                                (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_APU]);
+               amd_pmf_send_cmd(dev, GET_STT_LIMIT_HS2, true, ARG_NONE,
+                                (u32 *)&table->prop[src][idx].stt_skin_temp[STT_TEMP_HS2]);
+       }
+}
+
+static int amd_pmf_profile_get(struct platform_profile_handler *pprof,
+                              enum platform_profile_option *profile)
+{
+       struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof);
+
+       *profile = pmf->current_profile;
+       return 0;
+}
+
+int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf)
+{
+       int mode;
+
+       switch (pmf->current_profile) {
+       case PLATFORM_PROFILE_PERFORMANCE:
+               mode = POWER_MODE_PERFORMANCE;
+               break;
+       case PLATFORM_PROFILE_BALANCED:
+               mode = POWER_MODE_BALANCED_POWER;
+               break;
+       case PLATFORM_PROFILE_LOW_POWER:
+               mode = POWER_MODE_POWER_SAVER;
+               break;
+       default:
+               dev_err(pmf->dev, "Unknown Platform Profile.\n");
+               return -EOPNOTSUPP;
+       }
+
+       return mode;
+}
+
+static int amd_pmf_profile_set(struct platform_profile_handler *pprof,
+                              enum platform_profile_option profile)
+{
+       struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof);
+       int mode;
+
+       pmf->current_profile = profile;
+       mode = amd_pmf_get_pprof_modes(pmf);
+       if (mode < 0)
+               return mode;
+
+       amd_pmf_update_slider(pmf, SLIDER_OP_SET, mode, NULL);
+       return 0;
+}
+
+int amd_pmf_init_sps(struct amd_pmf_dev *dev)
+{
+       int err;
+
+       dev->current_profile = PLATFORM_PROFILE_BALANCED;
+       amd_pmf_load_defaults_sps(dev);
+
+       dev->pprof.profile_get = amd_pmf_profile_get;
+       dev->pprof.profile_set = amd_pmf_profile_set;
+
+       /* Setup supported modes */
+       set_bit(PLATFORM_PROFILE_LOW_POWER, dev->pprof.choices);
+       set_bit(PLATFORM_PROFILE_BALANCED, dev->pprof.choices);
+       set_bit(PLATFORM_PROFILE_PERFORMANCE, dev->pprof.choices);
+
+       /* Create platform_profile structure and register */
+       err = platform_profile_register(&dev->pprof);
+       if (err)
+               dev_err(dev->dev, "Failed to register SPS support, this is most likely an SBIOS bug: %d\n",
+                       err);
+
+       return err;
+}
+
+void amd_pmf_deinit_sps(struct amd_pmf_dev *dev)
+{
+       platform_profile_remove();
+}
index 493e169..3e313c4 100644 (file)
@@ -150,7 +150,8 @@ static int __init amilo_rfkill_init(void)
        if (rc)
                return rc;
 
-       amilo_rfkill_pdev = platform_device_register_simple(KBUILD_MODNAME, -1,
+       amilo_rfkill_pdev = platform_device_register_simple(KBUILD_MODNAME,
+                                                           PLATFORM_DEVID_NONE,
                                                            NULL, 0);
        if (IS_ERR(amilo_rfkill_pdev)) {
                rc = PTR_ERR(amilo_rfkill_pdev);
index ffe98a1..ca33df7 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/vga_switcheroo.h>
-#include <acpi/video.h>
 #include <asm/io.h>
 
 /**
@@ -694,7 +693,6 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
         * backlight control and supports more levels than other options.
         * Disable the other backlight choices.
         */
-       acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
        apple_bl_unregister();
 
        gmux_data->power_state = VGA_SWITCHEROO_ON;
@@ -804,7 +802,6 @@ static void gmux_remove(struct pnp_dev *pnp)
        apple_gmux_data = NULL;
        kfree(gmux_data);
 
-       acpi_video_register();
        apple_bl_register();
 }
 
index 4d2d32b..47b2f8b 100644 (file)
@@ -1633,7 +1633,7 @@ static int asus_platform_init(struct asus_laptop *asus)
 {
        int result;
 
-       asus->platform_device = platform_device_alloc(ASUS_LAPTOP_FILE, -1);
+       asus->platform_device = platform_device_alloc(ASUS_LAPTOP_FILE, PLATFORM_DEVID_NONE);
        if (!asus->platform_device)
                return -ENOMEM;
        platform_set_drvdata(asus->platform_device, asus);
index 478dd30..613c45c 100644 (file)
@@ -43,7 +43,7 @@ MODULE_PARM_DESC(wapf, "WAPF value");
 
 static int tablet_mode_sw = -1;
 module_param(tablet_mode_sw, uint, 0444);
-MODULE_PARM_DESC(tablet_mode_sw, "Tablet mode detect: -1:auto 0:disable 1:kbd-dock 2:lid-flip");
+MODULE_PARM_DESC(tablet_mode_sw, "Tablet mode detect: -1:auto 0:disable 1:kbd-dock 2:lid-flip 3:lid-flip-rog");
 
 static struct quirk_entry *quirks;
 
@@ -79,12 +79,10 @@ static struct quirk_entry quirk_asus_q500a = {
 
 /*
  * For those machines that need software to control bt/wifi status
- * and can't adjust brightness through ACPI interface
  * and have duplicate events(ACPI and WMI) for display toggle
  */
 static struct quirk_entry quirk_asus_x55u = {
        .wapf = 4,
-       .wmi_backlight_power = true,
        .wmi_backlight_set_devstate = true,
        .no_display_toggle = true,
 };
@@ -99,11 +97,6 @@ static struct quirk_entry quirk_asus_x200ca = {
        .wmi_backlight_set_devstate = true,
 };
 
-static struct quirk_entry quirk_asus_ux303ub = {
-       .wmi_backlight_native = true,
-       .wmi_backlight_set_devstate = true,
-};
-
 static struct quirk_entry quirk_asus_x550lb = {
        .wmi_backlight_set_devstate = true,
        .xusb2pr = 0x01D9,
@@ -115,12 +108,17 @@ static struct quirk_entry quirk_asus_forceals = {
 };
 
 static struct quirk_entry quirk_asus_use_kbd_dock_devid = {
-       .use_kbd_dock_devid = true,
+       .tablet_switch_mode = asus_wmi_kbd_dock_devid,
 };
 
 static struct quirk_entry quirk_asus_use_lid_flip_devid = {
        .wmi_backlight_set_devstate = true,
-       .use_lid_flip_devid = true,
+       .tablet_switch_mode = asus_wmi_lid_flip_devid,
+};
+
+static struct quirk_entry quirk_asus_tablet_mode = {
+       .wmi_backlight_set_devstate = true,
+       .tablet_switch_mode = asus_wmi_lid_flip_rog_devid,
 };
 
 static int dmi_matched(const struct dmi_system_id *dmi)
@@ -147,11 +145,6 @@ static const struct dmi_system_id asus_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
                        DMI_MATCH(DMI_PRODUCT_NAME, "U32U"),
                },
-               /*
-                * Note this machine has a Brazos APU, and most Brazos Asus
-                * machines need quirk_asus_x55u / wmi_backlight_power but
-                * here acpi-video seems to work fine for backlight control.
-                */
                .driver_data = &quirk_asus_wapf4,
        },
        {
@@ -381,15 +374,6 @@ static const struct dmi_system_id asus_quirks[] = {
        },
        {
                .callback = dmi_matched,
-               .ident = "ASUSTeK COMPUTER INC. UX303UB",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "UX303UB"),
-               },
-               .driver_data = &quirk_asus_ux303ub,
-       },
-       {
-               .callback = dmi_matched,
                .ident = "ASUSTeK COMPUTER INC. UX330UAK",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
@@ -471,6 +455,15 @@ static const struct dmi_system_id asus_quirks[] = {
                },
                .driver_data = &quirk_asus_use_lid_flip_devid,
        },
+       {
+               .callback = dmi_matched,
+               .ident = "ASUS ROG FLOW X13",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "GV301Q"),
+               },
+               .driver_data = &quirk_asus_tablet_mode,
+       },
        {},
 };
 
@@ -490,20 +483,8 @@ static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver)
        else
                wapf = quirks->wapf;
 
-       switch (tablet_mode_sw) {
-       case 0:
-               quirks->use_kbd_dock_devid = false;
-               quirks->use_lid_flip_devid = false;
-               break;
-       case 1:
-               quirks->use_kbd_dock_devid = true;
-               quirks->use_lid_flip_devid = false;
-               break;
-       case 2:
-               quirks->use_kbd_dock_devid = false;
-               quirks->use_lid_flip_devid = true;
-               break;
-       }
+       if (tablet_mode_sw != -1)
+               quirks->tablet_switch_mode = tablet_mode_sw;
 
        if (quirks->i8042_filter) {
                ret = i8042_install_filter(quirks->i8042_filter);
@@ -575,12 +556,14 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
        { KE_KEY, 0xA5, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + HDMI */
        { KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */
        { KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */
+       { KE_KEY, 0xAE, { KEY_FN_F5 } }, /* Fn+F5 fan mode on 2020+ */
        { KE_KEY, 0xB3, { KEY_PROG4 } }, /* AURA */
        { KE_KEY, 0xB5, { KEY_CALC } },
        { KE_KEY, 0xC4, { KEY_KBDILLUMUP } },
        { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } },
        { KE_IGNORE, 0xC6, },  /* Ambient Light Sensor notification */
        { KE_KEY, 0xFA, { KEY_PROG2 } },           /* Lid flip action */
+       { KE_KEY, 0xBD, { KEY_PROG2 } },           /* Lid flip action on ROG xflow laptops */
        { KE_END, 0},
 };
 
index eec7d0e..6e8e093 100644 (file)
@@ -68,9 +68,11 @@ module_param(fnlock_default, bool, 0444);
 #define NOTIFY_KBD_FBM                 0x99
 #define NOTIFY_KBD_TTP                 0xae
 #define NOTIFY_LID_FLIP                        0xfa
+#define NOTIFY_LID_FLIP_ROG            0xbd
 
 #define ASUS_WMI_FNLOCK_BIOS_DISABLED  BIT(0)
 
+#define ASUS_GPU_FAN_DESC              "gpu_fan"
 #define ASUS_FAN_DESC                  "cpu_fan"
 #define ASUS_FAN_MFUN                  0x13
 #define ASUS_FAN_SFUN_READ             0x06
@@ -221,19 +223,25 @@ struct asus_wmi {
        struct asus_rfkill gps;
        struct asus_rfkill uwb;
 
+       int tablet_switch_event_code;
+       u32 tablet_switch_dev_id;
+
        enum fan_type fan_type;
+       enum fan_type gpu_fan_type;
        int fan_pwm_mode;
+       int gpu_fan_pwm_mode;
        int agfn_pwm;
 
        bool fan_boost_mode_available;
        u8 fan_boost_mode_mask;
        u8 fan_boost_mode;
 
-       bool egpu_enable_available; // 0 = enable
-       bool egpu_enable;
-
+       bool egpu_enable_available;
        bool dgpu_disable_available;
-       bool dgpu_disable;
+       bool gpu_mux_mode_available;
+
+       bool kbd_rgb_mode_available;
+       bool kbd_rgb_state_available;
 
        bool throttle_thermal_policy_available;
        u8 throttle_thermal_policy_mode;
@@ -249,7 +257,6 @@ struct asus_wmi {
        bool battery_rsoc_available;
 
        bool panel_overdrive_available;
-       bool panel_overdrive;
 
        struct hotplug_slot hotplug_slot;
        struct mutex hotplug_lock;
@@ -486,10 +493,28 @@ static bool asus_wmi_dev_is_present(struct asus_wmi *asus, u32 dev_id)
 }
 
 /* Input **********************************************************************/
+static void asus_wmi_tablet_sw_init(struct asus_wmi *asus, u32 dev_id, int event_code)
+{
+       struct device *dev = &asus->platform_device->dev;
+       int result;
+
+       result = asus_wmi_get_devstate_simple(asus, dev_id);
+       if (result >= 0) {
+               input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
+               input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
+               asus->tablet_switch_dev_id = dev_id;
+               asus->tablet_switch_event_code = event_code;
+       } else if (result == -ENODEV) {
+               dev_err(dev, "This device has tablet-mode-switch quirk but got ENODEV checking it. This is a bug.");
+       } else {
+               dev_err(dev, "Error checking for tablet-mode-switch: %d\n", result);
+       }
+}
 
 static int asus_wmi_input_init(struct asus_wmi *asus)
 {
-       int err, result;
+       struct device *dev = &asus->platform_device->dev;
+       int err;
 
        asus->inputdev = input_allocate_device();
        if (!asus->inputdev)
@@ -498,35 +523,25 @@ static int asus_wmi_input_init(struct asus_wmi *asus)
        asus->inputdev->name = asus->driver->input_name;
        asus->inputdev->phys = asus->driver->input_phys;
        asus->inputdev->id.bustype = BUS_HOST;
-       asus->inputdev->dev.parent = &asus->platform_device->dev;
+       asus->inputdev->dev.parent = dev;
        set_bit(EV_REP, asus->inputdev->evbit);
 
        err = sparse_keymap_setup(asus->inputdev, asus->driver->keymap, NULL);
        if (err)
                goto err_free_dev;
 
-       if (asus->driver->quirks->use_kbd_dock_devid) {
-               result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_KBD_DOCK);
-               if (result >= 0) {
-                       input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
-                       input_report_switch(asus->inputdev, SW_TABLET_MODE, !result);
-               } else if (result != -ENODEV) {
-                       pr_err("Error checking for keyboard-dock: %d\n", result);
-               }
-       }
-
-       if (asus->driver->quirks->use_lid_flip_devid) {
-               result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP);
-               if (result < 0)
-                       asus->driver->quirks->use_lid_flip_devid = 0;
-               if (result >= 0) {
-                       input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
-                       input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
-               } else if (result == -ENODEV) {
-                       pr_err("This device has lid_flip quirk but got ENODEV checking it. This is a bug.");
-               } else {
-                       pr_err("Error checking for lid-flip: %d\n", result);
-               }
+       switch (asus->driver->quirks->tablet_switch_mode) {
+       case asus_wmi_no_tablet_switch:
+               break;
+       case asus_wmi_kbd_dock_devid:
+               asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_KBD_DOCK, NOTIFY_KBD_DOCK_CHANGE);
+               break;
+       case asus_wmi_lid_flip_devid:
+               asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_LID_FLIP, NOTIFY_LID_FLIP);
+               break;
+       case asus_wmi_lid_flip_rog_devid:
+               asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_LID_FLIP_ROG, NOTIFY_LID_FLIP_ROG);
+               break;
        }
 
        err = input_register_device(asus->inputdev);
@@ -550,10 +565,14 @@ static void asus_wmi_input_exit(struct asus_wmi *asus)
 
 /* Tablet mode ****************************************************************/
 
-static void lid_flip_tablet_mode_get_state(struct asus_wmi *asus)
+static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus)
 {
-       int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_LID_FLIP);
+       int result;
+
+       if (!asus->tablet_switch_dev_id)
+               return;
 
+       result = asus_wmi_get_devstate_simple(asus, asus->tablet_switch_dev_id);
        if (result >= 0) {
                input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
                input_sync(asus->inputdev);
@@ -561,179 +580,267 @@ static void lid_flip_tablet_mode_get_state(struct asus_wmi *asus)
 }
 
 /* dGPU ********************************************************************/
-static int dgpu_disable_check_present(struct asus_wmi *asus)
+static ssize_t dgpu_disable_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
 {
-       u32 result;
-       int err;
-
-       asus->dgpu_disable_available = false;
-
-       err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_DGPU, &result);
-       if (err) {
-               if (err == -ENODEV)
-                       return 0;
-               return err;
-       }
+       struct asus_wmi *asus = dev_get_drvdata(dev);
+       int result;
 
-       if (result & ASUS_WMI_DSTS_PRESENCE_BIT) {
-               asus->dgpu_disable_available = true;
-               asus->dgpu_disable = result & ASUS_WMI_DSTS_STATUS_BIT;
-       }
+       result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_DGPU);
+       if (result < 0)
+               return result;
 
-       return 0;
+       return sysfs_emit(buf, "%d\n", result);
 }
 
-static int dgpu_disable_write(struct asus_wmi *asus)
+/*
+ * A user may be required to store the value twice, typcial store first, then
+ * rescan PCI bus to activate power, then store a second time to save correctly.
+ * The reason for this is that an extra code path in the ACPI is enabled when
+ * the device and bus are powered.
+ */
+static ssize_t dgpu_disable_store(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
 {
-       u32 retval;
-       u8 value;
-       int err;
+       int result, err;
+       u32 disable;
+
+       struct asus_wmi *asus = dev_get_drvdata(dev);
 
-       /* Don't rely on type conversion */
-       value = asus->dgpu_disable ? 1 : 0;
+       result = kstrtou32(buf, 10, &disable);
+       if (result)
+               return result;
+
+       if (disable > 1)
+               return -EINVAL;
 
-       err = asus_wmi_set_devstate(ASUS_WMI_DEVID_DGPU, value, &retval);
+       err = asus_wmi_set_devstate(ASUS_WMI_DEVID_DGPU, disable, &result);
        if (err) {
                pr_warn("Failed to set dgpu disable: %d\n", err);
                return err;
        }
 
-       if (retval > 1) {
-               pr_warn("Failed to set dgpu disable (retval): 0x%x\n", retval);
+       if (result > 1) {
+               pr_warn("Failed to set dgpu disable (result): 0x%x\n", result);
                return -EIO;
        }
 
        sysfs_notify(&asus->platform_device->dev.kobj, NULL, "dgpu_disable");
 
-       return 0;
+       return count;
 }
+static DEVICE_ATTR_RW(dgpu_disable);
 
-static ssize_t dgpu_disable_show(struct device *dev,
+/* eGPU ********************************************************************/
+static ssize_t egpu_enable_show(struct device *dev,
                                   struct device_attribute *attr, char *buf)
 {
        struct asus_wmi *asus = dev_get_drvdata(dev);
-       u8 mode = asus->dgpu_disable;
+       int result;
 
-       return sysfs_emit(buf, "%d\n", mode);
+       result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU);
+       if (result < 0)
+               return result;
+
+       return sysfs_emit(buf, "%d\n", result);
 }
 
-/*
- * A user may be required to store the value twice, typcial store first, then
- * rescan PCI bus to activate power, then store a second time to save correctly.
- * The reason for this is that an extra code path in the ACPI is enabled when
- * the device and bus are powered.
- */
-static ssize_t dgpu_disable_store(struct device *dev,
+/* The ACPI call to enable the eGPU also disables the internal dGPU */
+static ssize_t egpu_enable_store(struct device *dev,
                                    struct device_attribute *attr,
                                    const char *buf, size_t count)
 {
-       bool disable;
-       int result;
+       int result, err;
+       u32 enable;
 
        struct asus_wmi *asus = dev_get_drvdata(dev);
 
-       result = kstrtobool(buf, &disable);
-       if (result)
-               return result;
+       err = kstrtou32(buf, 10, &enable);
+       if (err)
+               return err;
 
-       asus->dgpu_disable = disable;
+       if (enable > 1)
+               return -EINVAL;
 
-       result = dgpu_disable_write(asus);
-       if (result)
-               return result;
+       err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, enable, &result);
+       if (err) {
+               pr_warn("Failed to set egpu disable: %d\n", err);
+               return err;
+       }
+
+       if (result > 1) {
+               pr_warn("Failed to set egpu disable (retval): 0x%x\n", result);
+               return -EIO;
+       }
+
+       sysfs_notify(&asus->platform_device->dev.kobj, NULL, "egpu_enable");
 
        return count;
 }
+static DEVICE_ATTR_RW(egpu_enable);
 
-static DEVICE_ATTR_RW(dgpu_disable);
+/* gpu mux switch *************************************************************/
+static ssize_t gpu_mux_mode_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct asus_wmi *asus = dev_get_drvdata(dev);
+       int result;
 
-/* eGPU ********************************************************************/
-static int egpu_enable_check_present(struct asus_wmi *asus)
+       result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPU_MUX);
+       if (result < 0)
+               return result;
+
+       return sysfs_emit(buf, "%d\n", result);
+}
+
+static ssize_t gpu_mux_mode_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
 {
-       u32 result;
-       int err;
+       struct asus_wmi *asus = dev_get_drvdata(dev);
+       int result, err;
+       u32 optimus;
 
-       asus->egpu_enable_available = false;
+       err = kstrtou32(buf, 10, &optimus);
+       if (err)
+               return err;
+
+       if (optimus > 1)
+               return -EINVAL;
 
-       err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_EGPU, &result);
+       err = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_MUX, optimus, &result);
        if (err) {
-               if (err == -ENODEV)
-                       return 0;
+               dev_err(dev, "Failed to set GPU MUX mode: %d\n", err);
                return err;
        }
-
-       if (result & ASUS_WMI_DSTS_PRESENCE_BIT) {
-               asus->egpu_enable_available = true;
-               asus->egpu_enable = result & ASUS_WMI_DSTS_STATUS_BIT;
+       /* !1 is considered a fail by ASUS */
+       if (result != 1) {
+               dev_warn(dev, "Failed to set GPU MUX mode (result): 0x%x\n", result);
+               return -EIO;
        }
 
-       return 0;
+       sysfs_notify(&asus->platform_device->dev.kobj, NULL, "gpu_mux_mode");
+
+       return count;
 }
+static DEVICE_ATTR_RW(gpu_mux_mode);
 
-static int egpu_enable_write(struct asus_wmi *asus)
+/* TUF Laptop Keyboard RGB Modes **********************************************/
+static ssize_t kbd_rgb_mode_store(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
 {
-       u32 retval;
-       u8 value;
+       u32 cmd, mode, r, g,  b,  speed;
        int err;
 
-       /* Don't rely on type conversion */
-       value = asus->egpu_enable ? 1 : 0;
+       if (sscanf(buf, "%d %d %d %d %d %d", &cmd, &mode, &r, &g, &b, &speed) != 6)
+               return -EINVAL;
 
-       err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, value, &retval);
+       cmd = !!cmd;
 
-       if (err) {
-               pr_warn("Failed to set egpu disable: %d\n", err);
-               return err;
-       }
+       /* These are the known usable modes across all TUF/ROG */
+       if (mode >= 12 || mode == 9)
+               mode = 10;
 
-       if (retval > 1) {
-               pr_warn("Failed to set egpu disable (retval): 0x%x\n", retval);
-               return -EIO;
+       switch (speed) {
+       case 0:
+               speed = 0xe1;
+               break;
+       case 1:
+               speed = 0xeb;
+               break;
+       case 2:
+               speed = 0xf5;
+               break;
+       default:
+               speed = 0xeb;
        }
 
-       sysfs_notify(&asus->platform_device->dev.kobj, NULL, "egpu_enable");
+       err = asus_wmi_evaluate_method3(ASUS_WMI_METHODID_DEVS, ASUS_WMI_DEVID_TUF_RGB_MODE,
+                       cmd | (mode << 8) | (r << 16) | (g << 24), b | (speed << 8), NULL);
+       if (err)
+               return err;
 
-       return 0;
+       return count;
 }
+static DEVICE_ATTR_WO(kbd_rgb_mode);
 
-static ssize_t egpu_enable_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
+static ssize_t kbd_rgb_mode_index_show(struct device *device,
+                                                struct device_attribute *attr,
+                                                char *buf)
 {
-       struct asus_wmi *asus = dev_get_drvdata(dev);
-       bool mode = asus->egpu_enable;
-
-       return sysfs_emit(buf, "%d\n", mode);
+       return sysfs_emit(buf, "%s\n", "cmd mode red green blue speed");
 }
+static DEVICE_ATTR_RO(kbd_rgb_mode_index);
 
-/* The ACPI call to enable the eGPU also disables the internal dGPU */
-static ssize_t egpu_enable_store(struct device *dev,
-                                   struct device_attribute *attr,
-                                   const char *buf, size_t count)
-{
-       bool enable;
-       int result;
-
-       struct asus_wmi *asus = dev_get_drvdata(dev);
+static struct attribute *kbd_rgb_mode_attrs[] = {
+       &dev_attr_kbd_rgb_mode.attr,
+       &dev_attr_kbd_rgb_mode_index.attr,
+       NULL,
+};
 
-       result = kstrtobool(buf, &enable);
-       if (result)
-               return result;
+static const struct attribute_group kbd_rgb_mode_group = {
+       .attrs = kbd_rgb_mode_attrs,
+};
 
-       asus->egpu_enable = enable;
+/* TUF Laptop Keyboard RGB State **********************************************/
+static ssize_t kbd_rgb_state_store(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       u32 flags, cmd, boot, awake, sleep, keyboard;
+       int err;
 
-       result = egpu_enable_write(asus);
-       if (result)
-               return result;
+       if (sscanf(buf, "%d %d %d %d %d", &cmd, &boot, &awake, &sleep, &keyboard) != 5)
+               return -EINVAL;
 
-       /* Ensure that the kernel status of dgpu is updated */
-       result = dgpu_disable_check_present(asus);
-       if (result)
-               return result;
+       if (cmd)
+               cmd = BIT(2);
+
+       flags = 0;
+       if (boot)
+               flags |= BIT(1);
+       if (awake)
+               flags |= BIT(3);
+       if (sleep)
+               flags |= BIT(5);
+       if (keyboard)
+               flags |= BIT(7);
+
+       /* 0xbd is the required default arg0 for the method. Nothing happens otherwise */
+       err = asus_wmi_evaluate_method3(ASUS_WMI_METHODID_DEVS,
+                       ASUS_WMI_DEVID_TUF_RGB_STATE, 0xbd | cmd << 8 | (flags << 16), 0, NULL);
+       if (err)
+               return err;
 
        return count;
 }
+static DEVICE_ATTR_WO(kbd_rgb_state);
 
-static DEVICE_ATTR_RW(egpu_enable);
+static ssize_t kbd_rgb_state_index_show(struct device *device,
+                                                struct device_attribute *attr,
+                                                char *buf)
+{
+       return sysfs_emit(buf, "%s\n", "cmd boot awake sleep keyboard");
+}
+static DEVICE_ATTR_RO(kbd_rgb_state_index);
+
+static struct attribute *kbd_rgb_state_attrs[] = {
+       &dev_attr_kbd_rgb_state.attr,
+       &dev_attr_kbd_rgb_state_index.attr,
+       NULL,
+};
+
+static const struct attribute_group kbd_rgb_state_group = {
+       .attrs = kbd_rgb_state_attrs,
+};
+
+static const struct attribute_group *kbd_rgb_mode_groups[] = {
+       NULL,
+       NULL,
+       NULL,
+};
 
 /* Battery ********************************************************************/
 
@@ -771,7 +878,7 @@ static ssize_t charge_control_end_threshold_show(struct device *device,
                                                 struct device_attribute *attr,
                                                 char *buf)
 {
-       return sprintf(buf, "%d\n", charge_end_threshold);
+       return sysfs_emit(buf, "%d\n", charge_end_threshold);
 }
 
 static DEVICE_ATTR_RW(charge_control_end_threshold);
@@ -1053,7 +1160,12 @@ static void asus_wmi_led_exit(struct asus_wmi *asus)
 
 static int asus_wmi_led_init(struct asus_wmi *asus)
 {
-       int rv = 0, led_val;
+       int rv = 0, num_rgb_groups = 0, led_val;
+
+       if (asus->kbd_rgb_mode_available)
+               kbd_rgb_mode_groups[num_rgb_groups++] = &kbd_rgb_mode_group;
+       if (asus->kbd_rgb_state_available)
+               kbd_rgb_mode_groups[num_rgb_groups++] = &kbd_rgb_state_group;
 
        asus->led_workqueue = create_singlethread_workqueue("led_workqueue");
        if (!asus->led_workqueue)
@@ -1081,6 +1193,9 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
                asus->kbd_led.brightness_get = kbd_led_get;
                asus->kbd_led.max_brightness = 3;
 
+               if (num_rgb_groups != 0)
+                       asus->kbd_led.groups = kbd_rgb_mode_groups;
+
                rv = led_classdev_register(&asus->platform_device->dev,
                                           &asus->kbd_led);
                if (rv)
@@ -1555,84 +1670,51 @@ exit:
 }
 
 /* Panel Overdrive ************************************************************/
-static int panel_od_check_present(struct asus_wmi *asus)
-{
-       u32 result;
-       int err;
-
-       asus->panel_overdrive_available = false;
-
-       err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_PANEL_OD, &result);
-       if (err) {
-               if (err == -ENODEV)
-                       return 0;
-               return err;
-       }
-
-       if (result & ASUS_WMI_DSTS_PRESENCE_BIT) {
-               asus->panel_overdrive_available = true;
-               asus->panel_overdrive = result & ASUS_WMI_DSTS_STATUS_BIT;
-       }
-
-       return 0;
-}
-
-static int panel_od_write(struct asus_wmi *asus)
-{
-       u32 retval;
-       u8 value;
-       int err;
-
-       /* Don't rely on type conversion */
-       value = asus->panel_overdrive ? 1 : 0;
-
-       err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PANEL_OD, value, &retval);
-
-       if (err) {
-               pr_warn("Failed to set panel overdrive: %d\n", err);
-               return err;
-       }
-
-       if (retval > 1) {
-               pr_warn("Failed to set panel overdrive (retval): 0x%x\n", retval);
-               return -EIO;
-       }
-
-       sysfs_notify(&asus->platform_device->dev.kobj, NULL, "panel_od");
-
-       return 0;
-}
-
 static ssize_t panel_od_show(struct device *dev,
                                   struct device_attribute *attr, char *buf)
 {
        struct asus_wmi *asus = dev_get_drvdata(dev);
+       int result;
+
+       result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_PANEL_OD);
+       if (result < 0)
+               return result;
 
-       return sysfs_emit(buf, "%d\n", asus->panel_overdrive);
+       return sysfs_emit(buf, "%d\n", result);
 }
 
 static ssize_t panel_od_store(struct device *dev,
                                    struct device_attribute *attr,
                                    const char *buf, size_t count)
 {
-       bool overdrive;
-       int result;
+       int result, err;
+       u32 overdrive;
 
        struct asus_wmi *asus = dev_get_drvdata(dev);
 
-       result = kstrtobool(buf, &overdrive);
+       result = kstrtou32(buf, 10, &overdrive);
        if (result)
                return result;
 
-       asus->panel_overdrive = overdrive;
-       result = panel_od_write(asus);
+       if (overdrive > 1)
+               return -EINVAL;
 
-       if (result)
-               return result;
+       err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PANEL_OD, overdrive, &result);
+
+       if (err) {
+               pr_warn("Failed to set panel overdrive: %d\n", err);
+               return err;
+       }
+
+       if (result > 1) {
+               pr_warn("Failed to set panel overdrive (result): 0x%x\n", result);
+               return -EIO;
+       }
+
+       sysfs_notify(&asus->platform_device->dev.kobj, NULL, "panel_od");
 
        return count;
 }
-
 static DEVICE_ATTR_RW(panel_od);
 
 /* Quirks *********************************************************************/
@@ -1782,6 +1864,18 @@ static int asus_fan_set_auto(struct asus_wmi *asus)
                return -ENXIO;
        }
 
+       /*
+        * Modern models like the G713 also have GPU fan control (this is not AGFN)
+        */
+       if (asus->gpu_fan_type == FAN_TYPE_SPEC83) {
+               status = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_FAN_CTRL,
+                                              0, &retval);
+               if (status)
+                       return status;
+
+               if (retval != 1)
+                       return -EIO;
+       }
 
        return 0;
 }
@@ -1819,7 +1913,7 @@ static ssize_t pwm1_show(struct device *dev,
                value = -1;
        }
 
-       return sprintf(buf, "%d\n", value);
+       return sysfs_emit(buf, "%d\n", value);
 }
 
 static ssize_t pwm1_store(struct device *dev,
@@ -1879,7 +1973,7 @@ static ssize_t fan1_input_show(struct device *dev,
                return -ENXIO;
        }
 
-       return sprintf(buf, "%d\n", value < 0 ? -1 : value*100);
+       return sysfs_emit(buf, "%d\n", value < 0 ? -1 : value * 100);
 }
 
 static ssize_t pwm1_enable_show(struct device *dev,
@@ -1897,7 +1991,7 @@ static ssize_t pwm1_enable_show(struct device *dev,
         * in practice on X532FL at least (the bit is always 0) and there's
         * also nothing in the DSDT to indicate that this behaviour exists.
         */
-       return sprintf(buf, "%d\n", asus->fan_pwm_mode);
+       return sysfs_emit(buf, "%d\n", asus->fan_pwm_mode);
 }
 
 static ssize_t pwm1_enable_store(struct device *dev,
@@ -1965,7 +2059,7 @@ static ssize_t fan1_label_show(struct device *dev,
                                          struct device_attribute *attr,
                                          char *buf)
 {
-       return sprintf(buf, "%s\n", ASUS_FAN_DESC);
+       return sysfs_emit(buf, "%s\n", ASUS_FAN_DESC);
 }
 
 static ssize_t asus_hwmon_temp1(struct device *dev,
@@ -1984,11 +2078,86 @@ static ssize_t asus_hwmon_temp1(struct device *dev,
                       deci_kelvin_to_millicelsius(value & 0xFFFF));
 }
 
+/* GPU fan on modern ROG laptops */
+static ssize_t fan2_input_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct asus_wmi *asus = dev_get_drvdata(dev);
+       int value;
+       int ret;
+
+       ret = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_GPU_FAN_CTRL, &value);
+       if (ret < 0)
+               return ret;
+
+       value &= 0xffff;
+
+       return sysfs_emit(buf, "%d\n", value * 100);
+}
+
+static ssize_t fan2_label_show(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf)
+{
+       return sysfs_emit(buf, "%s\n", ASUS_GPU_FAN_DESC);
+}
+
+static ssize_t pwm2_enable_show(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf)
+{
+       struct asus_wmi *asus = dev_get_drvdata(dev);
+
+       return sysfs_emit(buf, "%d\n", asus->gpu_fan_pwm_mode);
+}
+
+static ssize_t pwm2_enable_store(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       struct asus_wmi *asus = dev_get_drvdata(dev);
+       int state;
+       int value;
+       int ret;
+       u32 retval;
+
+       ret = kstrtouint(buf, 10, &state);
+       if (ret)
+               return ret;
+
+       switch (state) { /* standard documented hwmon values */
+       case ASUS_FAN_CTRL_FULLSPEED:
+               value = 1;
+               break;
+       case ASUS_FAN_CTRL_AUTO:
+               value = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_FAN_CTRL,
+                                   value, &retval);
+       if (ret)
+               return ret;
+
+       if (retval != 1)
+               return -EIO;
+
+       asus->gpu_fan_pwm_mode = state;
+       return count;
+}
+
 /* Fan1 */
 static DEVICE_ATTR_RW(pwm1);
 static DEVICE_ATTR_RW(pwm1_enable);
 static DEVICE_ATTR_RO(fan1_input);
 static DEVICE_ATTR_RO(fan1_label);
+/* Fan2 - GPU fan */
+static DEVICE_ATTR_RW(pwm2_enable);
+static DEVICE_ATTR_RO(fan2_input);
+static DEVICE_ATTR_RO(fan2_label);
 
 /* Temperature */
 static DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL);
@@ -1996,8 +2165,11 @@ static DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL);
 static struct attribute *hwmon_attributes[] = {
        &dev_attr_pwm1.attr,
        &dev_attr_pwm1_enable.attr,
+       &dev_attr_pwm2_enable.attr,
        &dev_attr_fan1_input.attr,
        &dev_attr_fan1_label.attr,
+       &dev_attr_fan2_input.attr,
+       &dev_attr_fan2_label.attr,
 
        &dev_attr_temp1_input.attr,
        NULL
@@ -2006,7 +2178,7 @@ static struct attribute *hwmon_attributes[] = {
 static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
                                          struct attribute *attr, int idx)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev = kobj_to_dev(kobj);
        struct asus_wmi *asus = dev_get_drvdata(dev->parent);
        u32 value = ASUS_WMI_UNSUPPORTED_METHOD;
 
@@ -2018,6 +2190,11 @@ static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
            || attr == &dev_attr_pwm1_enable.attr) {
                if (asus->fan_type == FAN_TYPE_NONE)
                        return 0;
+       } else if (attr == &dev_attr_fan2_input.attr
+           || attr == &dev_attr_fan2_label.attr
+           || attr == &dev_attr_pwm2_enable.attr) {
+               if (asus->gpu_fan_type == FAN_TYPE_NONE)
+                       return 0;
        } else if (attr == &dev_attr_temp1_input.attr) {
                int err = asus_wmi_get_devstate(asus,
                                                ASUS_WMI_DEVID_THERMAL_CTRL,
@@ -2060,6 +2237,7 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus)
 
 static int asus_wmi_fan_init(struct asus_wmi *asus)
 {
+       asus->gpu_fan_type = FAN_TYPE_NONE;
        asus->fan_type = FAN_TYPE_NONE;
        asus->agfn_pwm = -1;
 
@@ -2068,6 +2246,10 @@ static int asus_wmi_fan_init(struct asus_wmi *asus)
        else if (asus_wmi_has_agfn_fan(asus))
                asus->fan_type = FAN_TYPE_AGFN;
 
+       /*  Modern models like G713 also have GPU fan control */
+       if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_FAN_CTRL))
+               asus->gpu_fan_type = FAN_TYPE_SPEC83;
+
        if (asus->fan_type == FAN_TYPE_NONE)
                return -ENODEV;
 
@@ -2158,7 +2340,7 @@ static ssize_t fan_boost_mode_show(struct device *dev,
 {
        struct asus_wmi *asus = dev_get_drvdata(dev);
 
-       return scnprintf(buf, PAGE_SIZE, "%d\n", asus->fan_boost_mode);
+       return sysfs_emit(buf, "%d\n", asus->fan_boost_mode);
 }
 
 static ssize_t fan_boost_mode_store(struct device *dev,
@@ -2710,7 +2892,7 @@ static ssize_t throttle_thermal_policy_show(struct device *dev,
        struct asus_wmi *asus = dev_get_drvdata(dev);
        u8 mode = asus->throttle_thermal_policy_mode;
 
-       return scnprintf(buf, PAGE_SIZE, "%d\n", mode);
+       return sysfs_emit(buf, "%d\n", mode);
 }
 
 static ssize_t throttle_thermal_policy_store(struct device *dev,
@@ -3062,9 +3244,7 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
 {
        unsigned int key_value = 1;
        bool autorelease = 1;
-       int result, orig_code;
-
-       orig_code = code;
+       int orig_code = code;
 
        if (asus->driver->key_filter) {
                asus->driver->key_filter(asus->driver, &code, &key_value,
@@ -3107,30 +3287,18 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
                return;
        }
 
-       if (asus->driver->quirks->use_kbd_dock_devid && code == NOTIFY_KBD_DOCK_CHANGE) {
-               result = asus_wmi_get_devstate_simple(asus,
-                                                     ASUS_WMI_DEVID_KBD_DOCK);
-               if (result >= 0) {
-                       input_report_switch(asus->inputdev, SW_TABLET_MODE,
-                                           !result);
-                       input_sync(asus->inputdev);
-               }
-               return;
-       }
-
-       if (asus->driver->quirks->use_lid_flip_devid && code == NOTIFY_LID_FLIP) {
-               lid_flip_tablet_mode_get_state(asus);
+       if (code == asus->tablet_switch_event_code) {
+               asus_wmi_tablet_mode_get_state(asus);
                return;
        }
 
-       if (asus->fan_boost_mode_available && code == NOTIFY_KBD_FBM) {
-               fan_boost_mode_switch_next(asus);
+       if (code == NOTIFY_KBD_FBM || code == NOTIFY_KBD_TTP) {
+               if (asus->fan_boost_mode_available)
+                       fan_boost_mode_switch_next(asus);
+               if (asus->throttle_thermal_policy_available)
+                       throttle_thermal_policy_switch_next(asus);
                return;
-       }
 
-       if (asus->throttle_thermal_policy_available && code == NOTIFY_KBD_TTP) {
-               throttle_thermal_policy_switch_next(asus);
-               return;
        }
 
        if (is_display_toggle(code) && asus->driver->quirks->no_display_toggle)
@@ -3282,6 +3450,7 @@ static struct attribute *platform_attributes[] = {
        &dev_attr_touchpad.attr,
        &dev_attr_egpu_enable.attr,
        &dev_attr_dgpu_disable.attr,
+       &dev_attr_gpu_mux_mode.attr,
        &dev_attr_lid_resume.attr,
        &dev_attr_als_enable.attr,
        &dev_attr_fan_boost_mode.attr,
@@ -3293,7 +3462,7 @@ static struct attribute *platform_attributes[] = {
 static umode_t asus_sysfs_is_visible(struct kobject *kobj,
                                    struct attribute *attr, int idx)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev = kobj_to_dev(kobj);
        struct asus_wmi *asus = dev_get_drvdata(dev);
        bool ok = true;
        int devid = -1;
@@ -3312,6 +3481,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
                ok = asus->egpu_enable_available;
        else if (attr == &dev_attr_dgpu_disable.attr)
                ok = asus->dgpu_disable_available;
+       else if (attr == &dev_attr_gpu_mux_mode.attr)
+               ok = asus->gpu_mux_mode_available;
        else if (attr == &dev_attr_fan_boost_mode.attr)
                ok = asus->fan_boost_mode_available;
        else if (attr == &dev_attr_throttle_thermal_policy.attr)
@@ -3552,7 +3723,6 @@ static int asus_wmi_add(struct platform_device *pdev)
        struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver);
        struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv);
        struct asus_wmi *asus;
-       const char *chassis_type;
        acpi_status status;
        int err;
        u32 result;
@@ -3573,13 +3743,12 @@ static int asus_wmi_add(struct platform_device *pdev)
        if (err)
                goto fail_platform;
 
-       err = egpu_enable_check_present(asus);
-       if (err)
-               goto fail_egpu_enable;
-
-       err = dgpu_disable_check_present(asus);
-       if (err)
-               goto fail_dgpu_disable;
+       asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU);
+       asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU);
+       asus->gpu_mux_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX);
+       asus->kbd_rgb_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE);
+       asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE);
+       asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD);
 
        err = fan_boost_mode_check_present(asus);
        if (err)
@@ -3595,10 +3764,6 @@ static int asus_wmi_add(struct platform_device *pdev)
        if (err)
                goto fail_platform_profile_setup;
 
-       err = panel_od_check_present(asus);
-       if (err)
-               goto fail_panel_od;
-
        err = asus_wmi_sysfs_init(asus->platform_device);
        if (err)
                goto fail_sysfs;
@@ -3634,18 +3799,6 @@ static int asus_wmi_add(struct platform_device *pdev)
        if (asus->driver->quirks->wmi_force_als_set)
                asus_wmi_set_als();
 
-       /* Some Asus desktop boards export an acpi-video backlight interface,
-          stop this from showing up */
-       chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE);
-       if (chassis_type && !strcmp(chassis_type, "3"))
-               acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
-
-       if (asus->driver->quirks->wmi_backlight_power)
-               acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
-
-       if (asus->driver->quirks->wmi_backlight_native)
-               acpi_video_set_dmi_backlight_type(acpi_backlight_native);
-
        if (asus->driver->quirks->xusb2pr)
                asus_wmi_set_xusb2pr(asus);
 
@@ -3693,10 +3846,7 @@ fail_platform_profile_setup:
        if (asus->platform_profile_support)
                platform_profile_remove();
 fail_fan_boost_mode:
-fail_egpu_enable:
-fail_dgpu_disable:
 fail_platform:
-fail_panel_od:
        kfree(asus);
        return err;
 }
@@ -3755,9 +3905,7 @@ static int asus_hotk_resume(struct device *device)
        if (asus_wmi_has_fnlock_key(asus))
                asus_wmi_fnlock_update(asus);
 
-       if (asus->driver->quirks->use_lid_flip_devid)
-               lid_flip_tablet_mode_get_state(asus);
-
+       asus_wmi_tablet_mode_get_state(asus);
        return 0;
 }
 
@@ -3797,9 +3945,7 @@ static int asus_hotk_restore(struct device *device)
        if (asus_wmi_has_fnlock_key(asus))
                asus_wmi_fnlock_update(asus);
 
-       if (asus->driver->quirks->use_lid_flip_devid)
-               lid_flip_tablet_mode_get_state(asus);
-
+       asus_wmi_tablet_mode_get_state(asus);
        return 0;
 }
 
index b302415..6531699 100644 (file)
@@ -25,16 +25,20 @@ struct module;
 struct key_entry;
 struct asus_wmi;
 
+enum asus_wmi_tablet_switch_mode {
+       asus_wmi_no_tablet_switch,
+       asus_wmi_kbd_dock_devid,
+       asus_wmi_lid_flip_devid,
+       asus_wmi_lid_flip_rog_devid,
+};
+
 struct quirk_entry {
        bool hotplug_wireless;
        bool scalar_panel_brightness;
        bool store_backlight_power;
-       bool wmi_backlight_power;
-       bool wmi_backlight_native;
        bool wmi_backlight_set_devstate;
        bool wmi_force_als_set;
-       bool use_kbd_dock_devid;
-       bool use_lid_flip_devid;
+       enum asus_wmi_tablet_switch_mode tablet_switch_mode;
        int wapf;
        /*
         * For machines with AMD graphic chips, it will send out WMI event
index 0942f50..e10d2f6 100644 (file)
@@ -721,16 +721,6 @@ static struct attribute *compal_hwmon_attrs[] = {
 };
 ATTRIBUTE_GROUPS(compal_hwmon);
 
-static int compal_probe(struct platform_device *);
-static int compal_remove(struct platform_device *);
-static struct platform_driver compal_driver = {
-       .driver = {
-               .name = DRIVER_NAME,
-       },
-       .probe  = compal_probe,
-       .remove = compal_remove,
-};
-
 static enum power_supply_property compal_bat_properties[] = {
        POWER_SUPPLY_PROP_STATUS,
        POWER_SUPPLY_PROP_HEALTH,
@@ -965,6 +955,80 @@ err_wifi:
        return ret;
 }
 
+static int compal_probe(struct platform_device *pdev)
+{
+       int err;
+       struct compal_data *data;
+       struct device *hwmon_dev;
+       struct power_supply_config psy_cfg = {};
+
+       if (!extra_features)
+               return 0;
+
+       /* Fan control */
+       data = devm_kzalloc(&pdev->dev, sizeof(struct compal_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       initialize_fan_control_data(data);
+
+       err = sysfs_create_group(&pdev->dev.kobj, &compal_platform_attr_group);
+       if (err)
+               return err;
+
+       hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev,
+                                                          "compal", data,
+                                                          compal_hwmon_groups);
+       if (IS_ERR(hwmon_dev)) {
+               err = PTR_ERR(hwmon_dev);
+               goto remove;
+       }
+
+       /* Power supply */
+       initialize_power_supply_data(data);
+       psy_cfg.drv_data = data;
+       data->psy = power_supply_register(&compal_device->dev, &psy_bat_desc,
+                                         &psy_cfg);
+       if (IS_ERR(data->psy)) {
+               err = PTR_ERR(data->psy);
+               goto remove;
+       }
+
+       platform_set_drvdata(pdev, data);
+
+       return 0;
+
+remove:
+       sysfs_remove_group(&pdev->dev.kobj, &compal_platform_attr_group);
+       return err;
+}
+
+static int compal_remove(struct platform_device *pdev)
+{
+       struct compal_data *data;
+
+       if (!extra_features)
+               return 0;
+
+       pr_info("Unloading: resetting fan control to motherboard\n");
+       pwm_disable_control();
+
+       data = platform_get_drvdata(pdev);
+       power_supply_unregister(data->psy);
+
+       sysfs_remove_group(&pdev->dev.kobj, &compal_platform_attr_group);
+
+       return 0;
+}
+
+static struct platform_driver compal_driver = {
+       .driver = {
+               .name = DRIVER_NAME,
+       },
+       .probe  = compal_probe,
+       .remove = compal_remove,
+};
+
 static int __init compal_init(void)
 {
        int ret;
@@ -996,7 +1060,7 @@ static int __init compal_init(void)
        if (ret)
                goto err_backlight;
 
-       compal_device = platform_device_alloc(DRIVER_NAME, -1);
+       compal_device = platform_device_alloc(DRIVER_NAME, PLATFORM_DEVID_NONE);
        if (!compal_device) {
                ret = -ENOMEM;
                goto err_platform_driver;
@@ -1028,54 +1092,6 @@ err_backlight:
        return ret;
 }
 
-static int compal_probe(struct platform_device *pdev)
-{
-       int err;
-       struct compal_data *data;
-       struct device *hwmon_dev;
-       struct power_supply_config psy_cfg = {};
-
-       if (!extra_features)
-               return 0;
-
-       /* Fan control */
-       data = devm_kzalloc(&pdev->dev, sizeof(struct compal_data), GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       initialize_fan_control_data(data);
-
-       err = sysfs_create_group(&pdev->dev.kobj, &compal_platform_attr_group);
-       if (err)
-               return err;
-
-       hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev,
-                                                          "compal", data,
-                                                          compal_hwmon_groups);
-       if (IS_ERR(hwmon_dev)) {
-               err = PTR_ERR(hwmon_dev);
-               goto remove;
-       }
-
-       /* Power supply */
-       initialize_power_supply_data(data);
-       psy_cfg.drv_data = data;
-       data->psy = power_supply_register(&compal_device->dev, &psy_bat_desc,
-                                         &psy_cfg);
-       if (IS_ERR(data->psy)) {
-               err = PTR_ERR(data->psy);
-               goto remove;
-       }
-
-       platform_set_drvdata(pdev, data);
-
-       return 0;
-
-remove:
-       sysfs_remove_group(&pdev->dev.kobj, &compal_platform_attr_group);
-       return err;
-}
-
 static void __exit compal_cleanup(void)
 {
        platform_device_unregister(compal_device);
@@ -1089,25 +1105,6 @@ static void __exit compal_cleanup(void)
        pr_info("Driver unloaded\n");
 }
 
-static int compal_remove(struct platform_device *pdev)
-{
-       struct compal_data *data;
-
-       if (!extra_features)
-               return 0;
-
-       pr_info("Unloading: resetting fan control to motherboard\n");
-       pwm_disable_control();
-
-       data = platform_get_drvdata(pdev);
-       power_supply_unregister(data->psy);
-
-       sysfs_remove_group(&pdev->dev.kobj, &compal_platform_attr_group);
-
-       return 0;
-}
-
-
 module_init(compal_init);
 module_exit(compal_cleanup);
 
index f212482..a34e07e 100644 (file)
@@ -791,7 +791,7 @@ static int __init alienware_wmi_init(void)
        ret = platform_driver_register(&platform_driver);
        if (ret)
                goto fail_platform_driver;
-       platform_device = platform_device_alloc("alienware-wmi", -1);
+       platform_device = platform_device_alloc("alienware-wmi", PLATFORM_DEVID_NONE);
        if (!platform_device) {
                ret = -ENOMEM;
                goto fail_platform_device1;
index 42beafb..0ecb7b1 100644 (file)
@@ -716,7 +716,7 @@ static struct platform_driver dcdbas_driver = {
 
 static const struct platform_device_info dcdbas_dev_info __initconst = {
        .name           = DRIVER_NAME,
-       .id             = -1,
+       .id             = PLATFORM_DEVID_NONE,
        .dma_mask       = DMA_BIT_MASK(32),
 };
 
index 1321687..e92c3ad 100644 (file)
@@ -2193,7 +2193,7 @@ static int __init dell_init(void)
        ret = platform_driver_register(&platform_driver);
        if (ret)
                goto fail_platform_driver;
-       platform_device = platform_device_alloc("dell-laptop", -1);
+       platform_device = platform_device_alloc("dell-laptop", PLATFORM_DEVID_NONE);
        if (!platform_device) {
                ret = -ENOMEM;
                goto fail_platform_device1;
index fc086b6..e61bfaf 100644 (file)
@@ -441,7 +441,7 @@ static ssize_t location_show(struct device *dev,
 
        i = match_attribute(dev, attr);
        if (i > 0)
-               return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].location);
+               return sysfs_emit(buf, "%08x", da_tokens[i].location);
        return 0;
 }
 
@@ -455,7 +455,7 @@ static ssize_t value_show(struct device *dev,
 
        i = match_attribute(dev, attr);
        if (i > 0)
-               return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].value);
+               return sysfs_emit(buf, "%08x", da_tokens[i].value);
        return 0;
 }
 
index e07d3ba..0a259a2 100644 (file)
@@ -344,6 +344,9 @@ static const struct key_entry dell_wmi_keymap_type_0011[] = {
  * They are events with extended data
  */
 static const struct key_entry dell_wmi_keymap_type_0012[] = {
+       /* Backlight brightness change event */
+       { KE_IGNORE, 0x0003, { KEY_RESERVED } },
+
        /* Ultra-performance mode switch request */
        { KE_IGNORE, 0x000d, { KEY_RESERVED } },
 
index 074b7e6..c82b3d6 100644 (file)
@@ -174,15 +174,12 @@ static ssize_t dell_privacy_current_state_show(struct device *dev,
 static DEVICE_ATTR_RO(dell_privacy_supported_type);
 static DEVICE_ATTR_RO(dell_privacy_current_state);
 
-static struct attribute *privacy_attributes[] = {
+static struct attribute *privacy_attrs[] = {
        &dev_attr_dell_privacy_supported_type.attr,
        &dev_attr_dell_privacy_current_state.attr,
        NULL,
 };
-
-static const struct attribute_group privacy_attribute_group = {
-       .attrs = privacy_attributes
-};
+ATTRIBUTE_GROUPS(privacy);
 
 /*
  * Describes the Device State class exposed by BIOS which can be consumed by
@@ -342,10 +339,6 @@ static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context)
        if (ret)
                return ret;
 
-       ret = devm_device_add_group(&wdev->dev, &privacy_attribute_group);
-       if (ret)
-               return ret;
-
        if (priv->features_present & BIT(DELL_PRIVACY_TYPE_AUDIO)) {
                ret = dell_privacy_leds_setup(&priv->wdev->dev);
                if (ret)
@@ -374,6 +367,7 @@ static const struct wmi_device_id dell_wmi_privacy_wmi_id_table[] = {
 static struct wmi_driver dell_privacy_wmi_driver = {
        .driver = {
                .name = "dell-privacy",
+               .dev_groups = privacy_groups,
        },
        .probe = dell_privacy_wmi_probe,
        .remove = dell_privacy_wmi_remove,
index 636bdfa..0a6411a 100644 (file)
@@ -270,7 +270,7 @@ void strlcpy_attr(char *dest, char *src)
        size_t len = strlen(src) + 1;
 
        if (len > 1 && len <= MAX_BUFF)
-               strlcpy(dest, src, len);
+               strscpy(dest, src, len);
 
        /*len can be zero because any property not-applicable to attribute can
         * be empty so check only for too long buffers and log error
index e9f4b30..9f51e0f 100644 (file)
@@ -645,7 +645,7 @@ static int __init dcdrbu_init(void)
        spin_lock_init(&rbu_data.lock);
 
        init_packet_head();
-       rbu_device = platform_device_register_simple("dell_rbu", -1, NULL, 0);
+       rbu_device = platform_device_register_simple("dell_rbu", PLATFORM_DEVID_NONE, NULL, 0);
        if (IS_ERR(rbu_device)) {
                pr_err("platform_device_register_simple failed\n");
                return PTR_ERR(rbu_device);
index ba08c92..a388a28 100644 (file)
@@ -444,7 +444,7 @@ static int eeepc_platform_init(struct eeepc_laptop *eeepc)
 {
        int result;
 
-       eeepc->platform_device = platform_device_alloc(EEEPC_LAPTOP_FILE, -1);
+       eeepc->platform_device = platform_device_alloc(EEEPC_LAPTOP_FILE, PLATFORM_DEVID_NONE);
        if (!eeepc->platform_device)
                return -ENOMEM;
        platform_set_drvdata(eeepc->platform_device, eeepc);
index ce86d84..32d9f0b 100644 (file)
@@ -96,11 +96,6 @@ static struct quirk_entry quirk_asus_et2012_type3 = {
        .store_backlight_power = true,
 };
 
-static struct quirk_entry quirk_asus_x101ch = {
-       /* We need this when ACPI function doesn't do this well */
-       .wmi_backlight_power = true,
-};
-
 static struct quirk_entry *quirks;
 
 static void et2012_quirks(void)
@@ -151,25 +146,7 @@ static const struct dmi_system_id asus_quirks[] = {
                },
                .driver_data = &quirk_asus_unknown,
        },
-       {
-               .callback = dmi_matched,
-               .ident = "ASUSTeK Computer INC. X101CH",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X101CH"),
-               },
-               .driver_data = &quirk_asus_x101ch,
-       },
-       {
-               .callback = dmi_matched,
-               .ident = "ASUSTeK Computer INC. 1015CX",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "1015CX"),
-               },
-               .driver_data = &quirk_asus_x101ch,
-       },
-       {},
+       {}
 };
 
 static void eeepc_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code,
index 8092938..b543d11 100644 (file)
@@ -543,7 +543,7 @@ static int fujitsu_laptop_platform_add(struct acpi_device *device)
        struct fujitsu_laptop *priv = acpi_driver_data(device);
        int ret;
 
-       priv->pf_device = platform_device_alloc("fujitsu-laptop", -1);
+       priv->pf_device = platform_device_alloc("fujitsu-laptop", PLATFORM_DEVID_NONE);
        if (!priv->pf_device)
                return -ENOMEM;
 
index 9996485..f11f726 100644 (file)
@@ -547,7 +547,7 @@ static int __init hdaps_init(void)
        if (ret)
                goto out_region;
 
-       pdev = platform_device_register_simple("hdaps", -1, NULL, 0);
+       pdev = platform_device_register_simple("hdaps", PLATFORM_DEVID_NONE, NULL, 0);
        if (IS_ERR(pdev)) {
                ret = PTR_ERR(pdev);
                goto out_driver;
index bc7020e..627a6d0 100644 (file)
@@ -177,7 +177,8 @@ enum hp_thermal_profile_omen_v1 {
 enum hp_thermal_profile {
        HP_THERMAL_PROFILE_PERFORMANCE  = 0x00,
        HP_THERMAL_PROFILE_DEFAULT              = 0x01,
-       HP_THERMAL_PROFILE_COOL                 = 0x02
+       HP_THERMAL_PROFILE_COOL                 = 0x02,
+       HP_THERMAL_PROFILE_QUIET                = 0x03,
 };
 
 #define IS_HWBLOCKED(x) ((x & HPWMI_POWER_FW_OR_HW) != HPWMI_POWER_FW_OR_HW)
@@ -206,15 +207,17 @@ struct bios_rfkill2_state {
 };
 
 static const struct key_entry hp_wmi_keymap[] = {
-       { KE_KEY, 0x02,   { KEY_BRIGHTNESSUP } },
-       { KE_KEY, 0x03,   { KEY_BRIGHTNESSDOWN } },
-       { KE_KEY, 0x20e6, { KEY_PROG1 } },
-       { KE_KEY, 0x20e8, { KEY_MEDIA } },
-       { KE_KEY, 0x2142, { KEY_MEDIA } },
-       { KE_KEY, 0x213b, { KEY_INFO } },
-       { KE_KEY, 0x2169, { KEY_ROTATE_DISPLAY } },
-       { KE_KEY, 0x216a, { KEY_SETUP } },
-       { KE_KEY, 0x231b, { KEY_HELP } },
+       { KE_KEY, 0x02,    { KEY_BRIGHTNESSUP } },
+       { KE_KEY, 0x03,    { KEY_BRIGHTNESSDOWN } },
+       { KE_KEY, 0x20e6,  { KEY_PROG1 } },
+       { KE_KEY, 0x20e8,  { KEY_MEDIA } },
+       { KE_KEY, 0x2142,  { KEY_MEDIA } },
+       { KE_KEY, 0x213b,  { KEY_INFO } },
+       { KE_KEY, 0x2169,  { KEY_ROTATE_DISPLAY } },
+       { KE_KEY, 0x216a,  { KEY_SETUP } },
+       { KE_KEY, 0x21a9,  { KEY_TOUCHPAD_OFF } },
+       { KE_KEY, 0x121a9, { KEY_TOUCHPAD_ON } },
+       { KE_KEY, 0x231b,  { KEY_HELP } },
        { KE_END, 0 }
 };
 
@@ -1194,6 +1197,9 @@ static int hp_wmi_platform_profile_get(struct platform_profile_handler *pprof,
        case HP_THERMAL_PROFILE_COOL:
                *profile =  PLATFORM_PROFILE_COOL;
                break;
+       case HP_THERMAL_PROFILE_QUIET:
+               *profile = PLATFORM_PROFILE_QUIET;
+               break;
        default:
                return -EINVAL;
        }
@@ -1216,6 +1222,9 @@ static int hp_wmi_platform_profile_set(struct platform_profile_handler *pprof,
        case PLATFORM_PROFILE_COOL:
                tp =  HP_THERMAL_PROFILE_COOL;
                break;
+       case PLATFORM_PROFILE_QUIET:
+               tp = HP_THERMAL_PROFILE_QUIET;
+               break;
        default:
                return -EOPNOTSUPP;
        }
@@ -1263,6 +1272,8 @@ static int thermal_profile_setup(void)
 
                platform_profile_handler.profile_get = hp_wmi_platform_profile_get;
                platform_profile_handler.profile_set = hp_wmi_platform_profile_set;
+
+               set_bit(PLATFORM_PROFILE_QUIET, platform_profile_handler.choices);
        }
 
        set_bit(PLATFORM_PROFILE_COOL, platform_profile_handler.choices);
@@ -1508,7 +1519,7 @@ static int __init hp_wmi_init(void)
 
        if (bios_capable) {
                hp_wmi_platform_dev =
-                       platform_device_register_simple("hp-wmi", -1, NULL, 0);
+                       platform_device_register_simple("hp-wmi", PLATFORM_DEVID_NONE, NULL, 0);
                if (IS_ERR(hp_wmi_platform_dev)) {
                        err = PTR_ERR(hp_wmi_platform_dev);
                        goto err_destroy_input;
index eac3e6b..5873c26 100644 (file)
@@ -871,7 +871,7 @@ static __init int huawei_wmi_init(void)
        if (err)
                goto pdrv_err;
 
-       pdev = platform_device_register_simple("huawei-wmi", -1, NULL, 0);
+       pdev = platform_device_register_simple("huawei-wmi", PLATFORM_DEVID_NONE, NULL, 0);
        if (IS_ERR(pdev)) {
                err = PTR_ERR(pdev);
                goto pdev_err;
index c52ac23..2c9a7d5 100644 (file)
@@ -219,7 +219,7 @@ static int cht_int33fe_add_nodes(struct cht_int33fe_data *data)
 
        /*
         * Update node used in "usb-role-switch" property. Note that we
-        * rely on software_node_register_nodes() to use the original
+        * rely on software_node_register_node_group() to use the original
         * instance of properties instead of copying them.
         */
        fusb302_mux_refs[0].node = mux_ref_node;
@@ -270,7 +270,7 @@ cht_int33fe_register_max17047(struct device *dev, struct cht_int33fe_data *data)
        }
 
        memset(&board_info, 0, sizeof(board_info));
-       strlcpy(board_info.type, "max17047", I2C_NAME_SIZE);
+       strscpy(board_info.type, "max17047", I2C_NAME_SIZE);
        board_info.dev_name = "max17047";
        board_info.fwnode = fwnode;
        data->battery_fg = i2c_acpi_new_device(dev, 1, &board_info);
@@ -361,7 +361,7 @@ static int cht_int33fe_typec_probe(struct platform_device *pdev)
        }
 
        memset(&board_info, 0, sizeof(board_info));
-       strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE);
+       strscpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE);
        board_info.dev_name = "fusb302";
        board_info.fwnode = fwnode;
        board_info.irq = fusb302_irq;
@@ -381,7 +381,7 @@ static int cht_int33fe_typec_probe(struct platform_device *pdev)
        memset(&board_info, 0, sizeof(board_info));
        board_info.dev_name = "pi3usb30532";
        board_info.fwnode = fwnode;
-       strlcpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE);
+       strscpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE);
 
        data->pi3usb30532 = i2c_acpi_new_device(dev, 3, &board_info);
        if (IS_ERR(data->pi3usb30532)) {
index ed4c9d7..974a132 100644 (file)
@@ -331,7 +331,22 @@ static int skl_int3472_parse_crs(struct int3472_discrete_device *int3472)
        return 0;
 }
 
-static int skl_int3472_discrete_remove(struct platform_device *pdev);
+static int skl_int3472_discrete_remove(struct platform_device *pdev)
+{
+       struct int3472_discrete_device *int3472 = platform_get_drvdata(pdev);
+
+       gpiod_remove_lookup_table(&int3472->gpios);
+
+       if (int3472->clock.cl)
+               skl_int3472_unregister_clock(int3472);
+
+       gpiod_put(int3472->clock.ena_gpio);
+       gpiod_put(int3472->clock.led_gpio);
+
+       skl_int3472_unregister_regulator(int3472);
+
+       return 0;
+}
 
 static int skl_int3472_discrete_probe(struct platform_device *pdev)
 {
@@ -383,23 +398,6 @@ static int skl_int3472_discrete_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int skl_int3472_discrete_remove(struct platform_device *pdev)
-{
-       struct int3472_discrete_device *int3472 = platform_get_drvdata(pdev);
-
-       gpiod_remove_lookup_table(&int3472->gpios);
-
-       if (int3472->clock.cl)
-               skl_int3472_unregister_clock(int3472);
-
-       gpiod_put(int3472->clock.ena_gpio);
-       gpiod_put(int3472->clock.led_gpio);
-
-       skl_int3472_unregister_regulator(int3472);
-
-       return 0;
-}
-
 static const struct acpi_device_id int3472_device_id[] = {
        { "INT3472", 0 },
        { }
index 1a09a75..7c5c623 100644 (file)
@@ -317,7 +317,7 @@ static int __init oaktrail_init(void)
                goto err_driver_reg;
        }
 
-       oaktrail_device = platform_device_alloc(DRIVER_NAME, -1);
+       oaktrail_device = platform_device_alloc(DRIVER_NAME, PLATFORM_DEVID_NONE);
        if (!oaktrail_device) {
                pr_warn("Unable to allocate platform device\n");
                ret = -ENOMEM;
index 84eabd6..cb24de9 100644 (file)
@@ -113,7 +113,7 @@ show_uncore_perf_status(current_freq_khz);
                struct uncore_data *data = container_of(attr, struct uncore_data,\
                                                          member_name##_dev_attr);\
                                                                        \
-               return scnprintf(buf, PAGE_SIZE, "%u\n",                \
+               return sysfs_emit(buf, "%u\n",                          \
                                 data->member_name);                    \
        }                                                               \
 
index 4ae8706..fc333ff 100644 (file)
@@ -51,26 +51,7 @@ static struct attribute *tbt_attrs[] = {
        &dev_attr_force_power.attr,
        NULL
 };
-
-static const struct attribute_group tbt_attribute_group = {
-       .attrs = tbt_attrs,
-};
-
-static int intel_wmi_thunderbolt_probe(struct wmi_device *wdev,
-                                      const void *context)
-{
-       int ret;
-
-       ret = sysfs_create_group(&wdev->dev.kobj, &tbt_attribute_group);
-       kobject_uevent(&wdev->dev.kobj, KOBJ_CHANGE);
-       return ret;
-}
-
-static void intel_wmi_thunderbolt_remove(struct wmi_device *wdev)
-{
-       sysfs_remove_group(&wdev->dev.kobj, &tbt_attribute_group);
-       kobject_uevent(&wdev->dev.kobj, KOBJ_CHANGE);
-}
+ATTRIBUTE_GROUPS(tbt);
 
 static const struct wmi_device_id intel_wmi_thunderbolt_id_table[] = {
        { .guid_string = INTEL_WMI_THUNDERBOLT_GUID },
@@ -80,9 +61,8 @@ static const struct wmi_device_id intel_wmi_thunderbolt_id_table[] = {
 static struct wmi_driver intel_wmi_thunderbolt_driver = {
        .driver = {
                .name = "intel-wmi-thunderbolt",
+               .dev_groups = tbt_groups,
        },
-       .probe = intel_wmi_thunderbolt_probe,
-       .remove = intel_wmi_thunderbolt_remove,
        .id_table = intel_wmi_thunderbolt_id_table,
 };
 
index 5e072a0..2fac05a 100644 (file)
@@ -5181,7 +5181,7 @@ static int __init mlxplat_init(void)
        if (!dmi_check_system(mlxplat_dmi_table))
                return -ENODEV;
 
-       mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1,
+       mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, PLATFORM_DEVID_NONE,
                                        mlxplat_lpc_resources,
                                        ARRAY_SIZE(mlxplat_lpc_resources));
 
index 24ffc8e..6b18ec5 100644 (file)
@@ -53,8 +53,6 @@
 #include <linux/input/sparse-keymap.h>
 #include <acpi/video.h>
 
-#define MSI_DRIVER_VERSION "0.5"
-
 #define MSI_LCD_LEVEL_MAX 9
 
 #define MSI_EC_COMMAND_WIRELESS 0x10
@@ -592,15 +590,22 @@ static int dmi_check_cb(const struct dmi_system_id *dmi)
        return 1;
 }
 
+static unsigned long msi_work_delay(int msecs)
+{
+       if (quirks->ec_delay)
+               return msecs_to_jiffies(msecs);
+
+       return 0;
+}
+
 static const struct dmi_system_id msi_dmi_table[] __initconst = {
        {
                .ident = "MSI S270",
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD"),
+                       DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "MS-1013"),
                        DMI_MATCH(DMI_PRODUCT_VERSION, "0131"),
-                       DMI_MATCH(DMI_CHASSIS_VENDOR,
-                                 "MICRO-STAR INT'L CO.,LTD")
+                       DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR INT")
                },
                .driver_data = &quirk_old_ec_model,
                .callback = dmi_check_cb
@@ -633,8 +638,7 @@ static const struct dmi_system_id msi_dmi_table[] __initconst = {
                        DMI_MATCH(DMI_SYS_VENDOR, "NOTEBOOK"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "SAM2000"),
                        DMI_MATCH(DMI_PRODUCT_VERSION, "0131"),
-                       DMI_MATCH(DMI_CHASSIS_VENDOR,
-                                 "MICRO-STAR INT'L CO.,LTD")
+                       DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR INT")
                },
                .driver_data = &quirk_old_ec_model,
                .callback = dmi_check_cb
@@ -705,6 +709,7 @@ static const struct dmi_system_id msi_dmi_table[] __initconst = {
        },
        { }
 };
+MODULE_DEVICE_TABLE(dmi, msi_dmi_table);
 
 static int rfkill_bluetooth_set(void *data, bool blocked)
 {
@@ -785,7 +790,6 @@ static void msi_update_rfkill(struct work_struct *ignored)
                msi_rfkill_set_state(rfk_threeg, !threeg_s);
 }
 static DECLARE_DELAYED_WORK(msi_rfkill_dwork, msi_update_rfkill);
-static DECLARE_WORK(msi_rfkill_work, msi_update_rfkill);
 
 static void msi_send_touchpad_key(struct work_struct *ignored)
 {
@@ -801,7 +805,6 @@ static void msi_send_touchpad_key(struct work_struct *ignored)
                KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true);
 }
 static DECLARE_DELAYED_WORK(msi_touchpad_dwork, msi_send_touchpad_key);
-static DECLARE_WORK(msi_touchpad_work, msi_send_touchpad_key);
 
 static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
                                struct serio *port)
@@ -819,20 +822,12 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
                extended = false;
                switch (data) {
                case 0xE4:
-                       if (quirks->ec_delay) {
-                               schedule_delayed_work(&msi_touchpad_dwork,
-                                       round_jiffies_relative(0.5 * HZ));
-                       } else
-                               schedule_work(&msi_touchpad_work);
+                       schedule_delayed_work(&msi_touchpad_dwork, msi_work_delay(500));
                        break;
                case 0x54:
                case 0x62:
                case 0x76:
-                       if (quirks->ec_delay) {
-                               schedule_delayed_work(&msi_rfkill_dwork,
-                                       round_jiffies_relative(0.5 * HZ));
-                       } else
-                               schedule_work(&msi_rfkill_work);
+                       schedule_delayed_work(&msi_rfkill_dwork, msi_work_delay(500));
                        break;
                }
        }
@@ -899,12 +894,7 @@ static int rfkill_init(struct platform_device *sdev)
        }
 
        /* schedule to run rfkill state initial */
-       if (quirks->ec_delay) {
-               schedule_delayed_work(&msi_rfkill_init,
-                       round_jiffies_relative(1 * HZ));
-       } else
-               schedule_work(&msi_rfkill_work);
-
+       schedule_delayed_work(&msi_rfkill_init, msi_work_delay(1000));
        return 0;
 
 err_threeg:
@@ -921,8 +911,7 @@ err_bluetooth:
        return retval;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int msi_laptop_resume(struct device *device)
+static int msi_scm_disable_hw_fn_handling(void)
 {
        u8 data;
        int result;
@@ -942,6 +931,12 @@ static int msi_laptop_resume(struct device *device)
 
        return 0;
 }
+
+#ifdef CONFIG_PM_SLEEP
+static int msi_laptop_resume(struct device *device)
+{
+       return msi_scm_disable_hw_fn_handling();
+}
 #endif
 
 static int __init msi_laptop_input_setup(void)
@@ -974,7 +969,6 @@ err_free_dev:
 
 static int __init load_scm_model_init(struct platform_device *sdev)
 {
-       u8 data;
        int result;
 
        if (!quirks->ec_read_only) {
@@ -988,12 +982,7 @@ static int __init load_scm_model_init(struct platform_device *sdev)
        }
 
        /* disable hardware control by fn key */
-       result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data);
-       if (result < 0)
-               return result;
-
-       result = ec_write(MSI_STANDARD_EC_SCM_LOAD_ADDRESS,
-               data | MSI_STANDARD_EC_SCM_LOAD_MASK);
+       result = msi_scm_disable_hw_fn_handling();
        if (result < 0)
                return result;
 
@@ -1022,9 +1011,19 @@ fail_input:
        rfkill_cleanup();
 
 fail_rfkill:
-
        return result;
+}
+
+static void msi_scm_model_exit(void)
+{
+       if (!quirks->load_scm_model)
+               return;
 
+       i8042_remove_filter(msi_laptop_i8042_filter);
+       cancel_delayed_work_sync(&msi_touchpad_dwork);
+       input_unregister_device(msi_laptop_input_dev);
+       cancel_delayed_work_sync(&msi_rfkill_dwork);
+       rfkill_cleanup();
 }
 
 static int __init msi_init(void)
@@ -1048,8 +1047,7 @@ static int __init msi_init(void)
                return -EINVAL;
 
        /* Register backlight stuff */
-
-       if (quirks->old_ec_model ||
+       if (quirks->old_ec_model &&
            acpi_video_get_backlight_type() == acpi_backlight_vendor) {
                struct backlight_properties props;
                memset(&props, 0, sizeof(struct backlight_properties));
@@ -1068,7 +1066,7 @@ static int __init msi_init(void)
 
        /* Register platform stuff */
 
-       msipf_device = platform_device_alloc("msi-laptop-pf", -1);
+       msipf_device = platform_device_alloc("msi-laptop-pf", PLATFORM_DEVID_NONE);
        if (!msipf_device) {
                ret = -ENOMEM;
                goto fail_platform_driver;
@@ -1108,19 +1106,12 @@ static int __init msi_init(void)
                        set_auto_brightness(auto_brightness);
        }
 
-       pr_info("driver " MSI_DRIVER_VERSION " successfully loaded\n");
-
        return 0;
 
 fail_create_attr:
        sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
 fail_create_group:
-       if (quirks->load_scm_model) {
-               i8042_remove_filter(msi_laptop_i8042_filter);
-               cancel_delayed_work_sync(&msi_rfkill_dwork);
-               cancel_work_sync(&msi_rfkill_work);
-               rfkill_cleanup();
-       }
+       msi_scm_model_exit();
 fail_scm_model_init:
        platform_device_del(msipf_device);
 fail_device_add:
@@ -1135,14 +1126,7 @@ fail_backlight:
 
 static void __exit msi_cleanup(void)
 {
-       if (quirks->load_scm_model) {
-               i8042_remove_filter(msi_laptop_i8042_filter);
-               input_unregister_device(msi_laptop_input_dev);
-               cancel_delayed_work_sync(&msi_rfkill_dwork);
-               cancel_work_sync(&msi_rfkill_work);
-               rfkill_cleanup();
-       }
-
+       msi_scm_model_exit();
        sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
        if (!quirks->old_ec_model && threeg_exists)
                device_remove_file(&msipf_device->dev, &dev_attr_threeg);
@@ -1155,8 +1139,6 @@ static void __exit msi_cleanup(void)
                if (auto_brightness != 2)
                        set_auto_brightness(1);
        }
-
-       pr_info("driver unloaded\n");
 }
 
 module_init(msi_init);
@@ -1164,16 +1146,4 @@ module_exit(msi_cleanup);
 
 MODULE_AUTHOR("Lennart Poettering");
 MODULE_DESCRIPTION("MSI Laptop Support");
-MODULE_VERSION(MSI_DRIVER_VERSION);
 MODULE_LICENSE("GPL");
-
-MODULE_ALIAS("dmi:*:svnMICRO-STARINT'LCO.,LTD:pnMS-1013:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
-MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1058:pvr0581:rvnMSI:rnMS-1058:*:ct10:*");
-MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1412:*:rvnMSI:rnMS-1412:*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
-MODULE_ALIAS("dmi:*:svnNOTEBOOK:pnSAM2000:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
-MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N034:*");
-MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N051:*");
-MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N014:*");
-MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnCR620:*");
-MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnU270series:*");
-MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnU90/U100:*");
index 61e3719..baccdf6 100644 (file)
@@ -7,73 +7,10 @@
 #include <linux/backlight.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
+#include <linux/platform_data/x86/nvidia-wmi-ec-backlight.h>
 #include <linux/types.h>
 #include <linux/wmi.h>
-
-/**
- * enum wmi_brightness_method - WMI method IDs
- * @WMI_BRIGHTNESS_METHOD_LEVEL:  Get/Set EC brightness level status
- * @WMI_BRIGHTNESS_METHOD_SOURCE: Get/Set EC Brightness Source
- */
-enum wmi_brightness_method {
-       WMI_BRIGHTNESS_METHOD_LEVEL = 1,
-       WMI_BRIGHTNESS_METHOD_SOURCE = 2,
-       WMI_BRIGHTNESS_METHOD_MAX
-};
-
-/**
- * enum wmi_brightness_mode - Operation mode for WMI-wrapped method
- * @WMI_BRIGHTNESS_MODE_GET:            Get the current brightness level/source.
- * @WMI_BRIGHTNESS_MODE_SET:            Set the brightness level.
- * @WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL:  Get the maximum brightness level. This
- *                                      is only valid when the WMI method is
- *                                      %WMI_BRIGHTNESS_METHOD_LEVEL.
- */
-enum wmi_brightness_mode {
-       WMI_BRIGHTNESS_MODE_GET = 0,
-       WMI_BRIGHTNESS_MODE_SET = 1,
-       WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL = 2,
-       WMI_BRIGHTNESS_MODE_MAX
-};
-
-/**
- * enum wmi_brightness_source - Backlight brightness control source selection
- * @WMI_BRIGHTNESS_SOURCE_GPU: Backlight brightness is controlled by the GPU.
- * @WMI_BRIGHTNESS_SOURCE_EC:  Backlight brightness is controlled by the
- *                             system's Embedded Controller (EC).
- * @WMI_BRIGHTNESS_SOURCE_AUX: Backlight brightness is controlled over the
- *                             DisplayPort AUX channel.
- */
-enum wmi_brightness_source {
-       WMI_BRIGHTNESS_SOURCE_GPU = 1,
-       WMI_BRIGHTNESS_SOURCE_EC = 2,
-       WMI_BRIGHTNESS_SOURCE_AUX = 3,
-       WMI_BRIGHTNESS_SOURCE_MAX
-};
-
-/**
- * struct wmi_brightness_args - arguments for the WMI-wrapped ACPI method
- * @mode:    Pass in an &enum wmi_brightness_mode value to select between
- *           getting or setting a value.
- * @val:     In parameter for value to set when using %WMI_BRIGHTNESS_MODE_SET
- *           mode. Not used in conjunction with %WMI_BRIGHTNESS_MODE_GET or
- *           %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL mode.
- * @ret:     Out parameter returning retrieved value when operating in
- *           %WMI_BRIGHTNESS_MODE_GET or %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL
- *           mode. Not used in %WMI_BRIGHTNESS_MODE_SET mode.
- * @ignored: Padding; not used. The ACPI method expects a 24 byte params struct.
- *
- * This is the parameters structure for the WmiBrightnessNotify ACPI method as
- * wrapped by WMI. The value passed in to @val or returned by @ret will be a
- * brightness value when the WMI method ID is %WMI_BRIGHTNESS_METHOD_LEVEL, or
- * an &enum wmi_brightness_source value with %WMI_BRIGHTNESS_METHOD_SOURCE.
- */
-struct wmi_brightness_args {
-       u32 mode;
-       u32 val;
-       u32 ret;
-       u32 ignored[3];
-};
+#include <acpi/video.h>
 
 /**
  * wmi_brightness_notify() - helper function for calling WMI-wrapped ACPI method
@@ -151,19 +88,10 @@ static int nvidia_wmi_ec_backlight_probe(struct wmi_device *wdev, const void *ct
 {
        struct backlight_properties props = {};
        struct backlight_device *bdev;
-       u32 source;
        int ret;
 
-       ret = wmi_brightness_notify(wdev, WMI_BRIGHTNESS_METHOD_SOURCE,
-                                  WMI_BRIGHTNESS_MODE_GET, &source);
-       if (ret)
-               return ret;
-
-       /*
-        * This driver is only to be used when brightness control is handled
-        * by the EC; otherwise, the GPU driver(s) should control brightness.
-        */
-       if (source != WMI_BRIGHTNESS_SOURCE_EC)
+       /* drivers/acpi/video_detect.c also checks that SOURCE == EC */
+       if (acpi_video_get_backlight_type() != acpi_backlight_nvidia_wmi_ec)
                return -ENODEV;
 
        /*
@@ -191,8 +119,6 @@ static int nvidia_wmi_ec_backlight_probe(struct wmi_device *wdev, const void *ct
        return PTR_ERR_OR_ZERO(bdev);
 }
 
-#define WMI_BRIGHTNESS_GUID "603E9613-EF25-4338-A3D0-C46177516DB7"
-
 static const struct wmi_device_id nvidia_wmi_ec_backlight_id_table[] = {
        { .guid_string = WMI_BRIGHTNESS_GUID },
        { }
index d9a095d..ad3083f 100644 (file)
@@ -1034,7 +1034,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
        /* optical drive initialization */
        if (ACPI_SUCCESS(check_optd_present())) {
                pcc->platform = platform_device_register_simple("panasonic",
-                       -1, NULL, 0);
+                       PLATFORM_DEVID_NONE, NULL, 0);
                if (IS_ERR(pcc->platform)) {
                        result = PTR_ERR(pcc->platform);
                        goto out_backlight;
index 5c757c7..93a6414 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Intel Atom SOC Power Management Controller Driver
- * Copyright (c) 2014, Intel Corporation.
+ * Intel Atom SoC Power Management Controller Driver
+ * Copyright (c) 2014-2015,2017,2022 Intel Corporation.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -60,7 +60,7 @@ static const struct pmc_clk byt_clks[] = {
                .freq = 19200000,
                .parent_name = "xtal",
        },
-       {},
+       {}
 };
 
 static const struct pmc_clk cht_clks[] = {
@@ -69,7 +69,7 @@ static const struct pmc_clk cht_clks[] = {
                .freq = 19200000,
                .parent_name = NULL,
        },
-       {},
+       {}
 };
 
 static const struct pmc_bit_map d3_sts_0_map[] = {
@@ -105,7 +105,7 @@ static const struct pmc_bit_map d3_sts_0_map[] = {
        {"LPSS2_F5_I2C5",       BIT_LPSS2_F5_I2C5},
        {"LPSS2_F6_I2C6",       BIT_LPSS2_F6_I2C6},
        {"LPSS2_F7_I2C7",       BIT_LPSS2_F7_I2C7},
-       {},
+       {}
 };
 
 static struct pmc_bit_map byt_d3_sts_1_map[] = {
@@ -113,21 +113,21 @@ static struct pmc_bit_map byt_d3_sts_1_map[] = {
        {"OTG_SS_PHY",          BIT_OTG_SS_PHY},
        {"USH_SS_PHY",          BIT_USH_SS_PHY},
        {"DFX",                 BIT_DFX},
-       {},
+       {}
 };
 
 static struct pmc_bit_map cht_d3_sts_1_map[] = {
        {"SMB",                 BIT_SMB},
        {"GMM",                 BIT_STS_GMM},
        {"ISH",                 BIT_STS_ISH},
-       {},
+       {}
 };
 
 static struct pmc_bit_map cht_func_dis_2_map[] = {
        {"SMB",                 BIT_SMB},
        {"GMM",                 BIT_FD_GMM},
        {"ISH",                 BIT_FD_ISH},
-       {},
+       {}
 };
 
 static const struct pmc_bit_map byt_pss_map[] = {
@@ -149,7 +149,7 @@ static const struct pmc_bit_map byt_pss_map[] = {
        {"OTG_VCCA",            PMC_PSS_BIT_OTG_VCCA},
        {"USB",                 PMC_PSS_BIT_USB},
        {"USB_SUS",             PMC_PSS_BIT_USB_SUS},
-       {},
+       {}
 };
 
 static const struct pmc_bit_map cht_pss_map[] = {
@@ -172,7 +172,7 @@ static const struct pmc_bit_map cht_pss_map[] = {
        {"DFX_CLUSTER3",        PMC_PSS_BIT_CHT_DFX_CLUSTER3},
        {"DFX_CLUSTER4",        PMC_PSS_BIT_CHT_DFX_CLUSTER4},
        {"DFX_CLUSTER5",        PMC_PSS_BIT_CHT_DFX_CLUSTER5},
-       {},
+       {}
 };
 
 static const struct pmc_reg_map byt_reg_map = {
@@ -354,7 +354,7 @@ static bool pmc_clk_is_critical = true;
 
 static int dmi_callback(const struct dmi_system_id *d)
 {
-       pr_info("%s critclks quirk enabled\n", d->ident);
+       pr_info("%s: PMC critical clocks quirk enabled\n", d->ident);
 
        return 1;
 }
@@ -417,8 +417,7 @@ static const struct dmi_system_id critclk_systems[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"),
                },
        },
-
-       { /*sentinel*/ }
+       {}
 };
 
 static int pmc_setup_clks(struct pci_dev *pdev, void __iomem *pmc_regmap,
@@ -490,15 +489,11 @@ static int pmc_setup_dev(struct pci_dev *pdev, const struct pci_device_id *ent)
        return ret;
 }
 
-/*
- * Data for PCI driver interface
- *
- * used by pci_match_id() call below.
- */
+/* Data for PCI driver interface used by pci_match_id() call below */
 static const struct pci_device_id pmc_pci_ids[] = {
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_VLV_PMC), (kernel_ulong_t)&byt_data },
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_CHT_PMC), (kernel_ulong_t)&cht_data },
-       { 0, },
+       {}
 };
 
 static int __init pmc_atom_init(void)
@@ -506,8 +501,9 @@ static int __init pmc_atom_init(void)
        struct pci_dev *pdev = NULL;
        const struct pci_device_id *ent;
 
-       /* We look for our device - PCU PMC
-        * we assume that there is max. one device.
+       /*
+        * We look for our device - PCU PMC.
+        * We assume that there is maximum one device.
         *
         * We can't use plain pci_driver mechanism,
         * as the device is really a multiple function device,
@@ -519,7 +515,7 @@ static int __init pmc_atom_init(void)
                if (ent)
                        return pmc_setup_dev(pdev, ent);
        }
-       /* Device not found. */
+       /* Device not found */
        return -ENODEV;
 }
 
@@ -527,6 +523,6 @@ device_initcall(pmc_atom_init);
 
 /*
 MODULE_AUTHOR("Aubrey Li <aubrey.li@linux.intel.com>");
-MODULE_DESCRIPTION("Intel Atom SOC Power Management Controller Interface");
+MODULE_DESCRIPTION("Intel Atom SoC Power Management Controller Interface");
 MODULE_LICENSE("GPL v2");
 */
index c187dcd..b4aa8ba 100644 (file)
@@ -356,23 +356,13 @@ struct samsung_laptop {
 };
 
 struct samsung_quirks {
-       bool broken_acpi_video;
        bool four_kbd_backlight_levels;
        bool enable_kbd_backlight;
-       bool use_native_backlight;
        bool lid_handling;
 };
 
 static struct samsung_quirks samsung_unknown = {};
 
-static struct samsung_quirks samsung_broken_acpi_video = {
-       .broken_acpi_video = true,
-};
-
-static struct samsung_quirks samsung_use_native_backlight = {
-       .use_native_backlight = true,
-};
-
 static struct samsung_quirks samsung_np740u3e = {
        .four_kbd_backlight_levels = true,
        .enable_kbd_backlight = true,
@@ -1484,7 +1474,7 @@ static int __init samsung_platform_init(struct samsung_laptop *samsung)
 {
        struct platform_device *pdev;
 
-       pdev = platform_device_register_simple("samsung", -1, NULL, 0);
+       pdev = platform_device_register_simple("samsung", PLATFORM_DEVID_NONE, NULL, 0);
        if (IS_ERR(pdev))
                return PTR_ERR(pdev);
 
@@ -1542,76 +1532,6 @@ static const struct dmi_system_id samsung_dmi_table[] __initconst = {
        /* Specific DMI ids for laptop with quirks */
        {
         .callback = samsung_dmi_matched,
-        .ident = "N150P",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "N150P"),
-               DMI_MATCH(DMI_BOARD_NAME, "N150P"),
-               },
-        .driver_data = &samsung_use_native_backlight,
-       },
-       {
-        .callback = samsung_dmi_matched,
-        .ident = "N145P/N250P/N260P",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
-               DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
-               },
-        .driver_data = &samsung_use_native_backlight,
-       },
-       {
-        .callback = samsung_dmi_matched,
-        .ident = "N150/N210/N220",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
-               DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
-               },
-        .driver_data = &samsung_broken_acpi_video,
-       },
-       {
-        .callback = samsung_dmi_matched,
-        .ident = "NF110/NF210/NF310",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
-               DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
-               },
-        .driver_data = &samsung_broken_acpi_video,
-       },
-       {
-        .callback = samsung_dmi_matched,
-        .ident = "X360",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "X360"),
-               DMI_MATCH(DMI_BOARD_NAME, "X360"),
-               },
-        .driver_data = &samsung_broken_acpi_video,
-       },
-       {
-        .callback = samsung_dmi_matched,
-        .ident = "N250P",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "N250P"),
-               DMI_MATCH(DMI_BOARD_NAME, "N250P"),
-               },
-        .driver_data = &samsung_use_native_backlight,
-       },
-       {
-        .callback = samsung_dmi_matched,
-        .ident = "NC210",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "NC210/NC110"),
-               DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"),
-               },
-        .driver_data = &samsung_broken_acpi_video,
-       },
-       {
-        .callback = samsung_dmi_matched,
         .ident = "730U3E/740U3E",
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
@@ -1654,15 +1574,8 @@ static int __init samsung_init(void)
        samsung->handle_backlight = true;
        samsung->quirks = quirks;
 
-#ifdef CONFIG_ACPI
-       if (samsung->quirks->broken_acpi_video)
-               acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
-       if (samsung->quirks->use_native_backlight)
-               acpi_video_set_dmi_backlight_type(acpi_backlight_native);
-
        if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
                samsung->handle_backlight = false;
-#endif
 
        ret = samsung_platform_init(samsung);
        if (ret)
index ca3647b..ca76076 100644 (file)
@@ -41,10 +41,12 @@ static struct {
        {SIMATIC_IPC_IPC127E, SIMATIC_IPC_DEVICE_127E, SIMATIC_IPC_DEVICE_NONE},
        {SIMATIC_IPC_IPC227D, SIMATIC_IPC_DEVICE_227D, SIMATIC_IPC_DEVICE_NONE},
        {SIMATIC_IPC_IPC227E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_227E},
+       {SIMATIC_IPC_IPC227G, SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_227G},
        {SIMATIC_IPC_IPC277E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227E},
        {SIMATIC_IPC_IPC427D, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE},
        {SIMATIC_IPC_IPC427E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_427E},
        {SIMATIC_IPC_IPC477E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_427E},
+       {SIMATIC_IPC_IPC427G, SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_227G},
 };
 
 static int register_platform_devices(u32 station_id)
@@ -65,7 +67,8 @@ static int register_platform_devices(u32 station_id)
        }
 
        if (ledmode != SIMATIC_IPC_DEVICE_NONE) {
-               if (ledmode == SIMATIC_IPC_DEVICE_127E)
+               if (ledmode == SIMATIC_IPC_DEVICE_127E ||
+                   ledmode == SIMATIC_IPC_DEVICE_227G)
                        pdevname = KBUILD_MODNAME "_leds_gpio";
                platform_data.devmode = ledmode;
                ipc_led_platform_device =
@@ -80,6 +83,11 @@ static int register_platform_devices(u32 station_id)
                         ipc_led_platform_device->name);
        }
 
+       if (wdtmode == SIMATIC_IPC_DEVICE_227G) {
+               request_module("w83627hf_wdt");
+               return 0;
+       }
+
        if (wdtmode != SIMATIC_IPC_DEVICE_NONE) {
                platform_data.devmode = wdtmode;
                ipc_wdt_platform_device =
index 07ef05f..765fcab 100644 (file)
@@ -584,7 +584,7 @@ static int sony_pf_add(void)
        if (ret)
                goto out;
 
-       sony_pf_device = platform_device_alloc("sony-laptop", -1);
+       sony_pf_device = platform_device_alloc("sony-laptop", PLATFORM_DEVID_NONE);
        if (!sony_pf_device) {
                ret = -ENOMEM;
                goto out_platform_registered;
index 9072eb3..ded2621 100644 (file)
@@ -233,7 +233,7 @@ static int __init tc1100_init(void)
        if (!wmi_has_guid(GUID))
                return -ENODEV;
 
-       tc1100_device = platform_device_alloc("tc1100-wmi", -1);
+       tc1100_device = platform_device_alloc("tc1100-wmi", PLATFORM_DEVID_NONE);
        if (!tc1100_device)
                return -ENOMEM;
 
index 2dbb9fc..6a823b8 100644 (file)
@@ -7623,9 +7623,9 @@ static int __init volume_create_alsa_mixer(void)
        data = card->private_data;
        data->card = card;
 
-       strlcpy(card->driver, TPACPI_ALSA_DRVNAME,
+       strscpy(card->driver, TPACPI_ALSA_DRVNAME,
                sizeof(card->driver));
-       strlcpy(card->shortname, TPACPI_ALSA_SHRTNAME,
+       strscpy(card->shortname, TPACPI_ALSA_SHRTNAME,
                sizeof(card->shortname));
        snprintf(card->mixername, sizeof(card->mixername), "ThinkPad EC %s",
                 (thinkpad_id.ec_version_str) ?
@@ -11715,7 +11715,7 @@ static int __init thinkpad_acpi_module_init(void)
                tp_features.quirks = dmi_id->driver_data;
 
        /* Device initialization */
-       tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, -1,
+       tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, PLATFORM_DEVID_NONE,
                                                        NULL, 0);
        if (IS_ERR(tpacpi_pdev)) {
                ret = PTR_ERR(tpacpi_pdev);
@@ -11726,7 +11726,7 @@ static int __init thinkpad_acpi_module_init(void)
        }
        tpacpi_sensors_pdev = platform_device_register_simple(
                                                TPACPI_HWMON_DRVR_NAME,
-                                               -1, NULL, 0);
+                                               PLATFORM_DEVID_NONE, NULL, 0);
        if (IS_ERR(tpacpi_sensors_pdev)) {
                ret = PTR_ERR(tpacpi_sensors_pdev);
                tpacpi_sensors_pdev = NULL;
index f7761d9..6d18fbf 100644 (file)
@@ -192,7 +192,7 @@ static int topstar_platform_init(struct topstar_laptop *topstar)
 {
        int err;
 
-       topstar->platform = platform_device_alloc(TOPSTAR_LAPTOP_CLASS, -1);
+       topstar->platform = platform_device_alloc(TOPSTAR_LAPTOP_CLASS, PLATFORM_DEVID_NONE);
        if (!topstar->platform)
                return -ENOMEM;
 
index 0fc9e8b..160abd3 100644 (file)
@@ -23,6 +23,7 @@
 #define PROC_INTERFACE_VERSION 1
 
 #include <linux/compiler.h>
+#include <linux/dmi.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/workqueue.h>
 #include <linux/i8042.h>
 #include <linux/acpi.h>
-#include <linux/dmi.h>
 #include <linux/uaccess.h>
 #include <linux/miscdevice.h>
 #include <linux/rfkill.h>
+#include <linux/hwmon.h>
 #include <linux/iio/iio.h>
 #include <linux/toshiba.h>
+#include <acpi/battery.h>
 #include <acpi/video.h>
 
 MODULE_AUTHOR("John Belmonte");
 MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
 MODULE_LICENSE("GPL");
 
+static int turn_on_panel_on_resume = -1;
+module_param(turn_on_panel_on_resume, int, 0644);
+MODULE_PARM_DESC(turn_on_panel_on_resume,
+       "Call HCI_PANEL_POWER_ON on resume (-1 = auto, 0 = no, 1 = yes");
+
 #define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100"
 
 /* Scan code for Fn key on TOS1900 models */
@@ -100,18 +107,21 @@ MODULE_LICENSE("GPL");
 #define TOS_NOT_INSTALLED              0x8e00
 
 /* Registers */
+#define HCI_PANEL_POWER_ON             0x0002
 #define HCI_FAN                                0x0004
 #define HCI_TR_BACKLIGHT               0x0005
 #define HCI_SYSTEM_EVENT               0x0016
 #define HCI_VIDEO_OUT                  0x001c
 #define HCI_HOTKEY_EVENT               0x001e
 #define HCI_LCD_BRIGHTNESS             0x002a
+#define HCI_FAN_RPM                    0x0045
 #define HCI_WIRELESS                   0x0056
 #define HCI_ACCELEROMETER              0x006d
 #define HCI_COOLING_METHOD             0x007f
 #define HCI_KBD_ILLUMINATION           0x0095
 #define HCI_ECO_MODE                   0x0097
 #define HCI_ACCELEROMETER2             0x00a6
+#define HCI_BATTERY_CHARGE_MODE                0x00ba
 #define HCI_SYSTEM_INFO                        0xc000
 #define SCI_PANEL_POWER_ON             0x010d
 #define SCI_ILLUMINATION               0x014e
@@ -170,6 +180,9 @@ struct toshiba_acpi_dev {
        struct miscdevice miscdev;
        struct rfkill *wwan_rfk;
        struct iio_dev *indio_dev;
+#if IS_ENABLED(CONFIG_HWMON)
+       struct device *hwmon_device;
+#endif
 
        int force_fan;
        int last_key_event;
@@ -185,6 +198,7 @@ struct toshiba_acpi_dev {
        unsigned int illumination_supported:1;
        unsigned int video_supported:1;
        unsigned int fan_supported:1;
+       unsigned int fan_rpm_supported:1;
        unsigned int system_event_supported:1;
        unsigned int ntfy_supported:1;
        unsigned int info_supported:1;
@@ -201,6 +215,7 @@ struct toshiba_acpi_dev {
        unsigned int usb_three_supported:1;
        unsigned int wwan_supported:1;
        unsigned int cooling_method_supported:1;
+       unsigned int battery_charge_mode_supported:1;
        unsigned int sysfs_created:1;
        unsigned int special_functions;
 
@@ -272,14 +287,6 @@ static const struct key_entry toshiba_acpi_alt_keymap[] = {
 };
 
 /*
- * List of models which have a broken acpi-video backlight interface and thus
- * need to use the toshiba (vendor) interface instead.
- */
-static const struct dmi_system_id toshiba_vendor_backlight_dmi[] = {
-       {}
-};
-
-/*
  * Utility
  */
 
@@ -675,12 +682,15 @@ static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev)
                return;
        }
 
-       if (out[0] == TOS_INPUT_DATA_ERROR) {
+       if (out[0] == TOS_INPUT_DATA_ERROR || out[0] == TOS_NOT_SUPPORTED) {
                /*
                 * If we receive 0x8300 (Input Data Error), it means that the
                 * LED device is present, but that we just screwed the input
                 * parameters.
                 *
+                * On some laptops 0x8000 (Not supported) is also returned in
+                * this case, so we need to allow for that as well.
+                *
                 * Let's query the status of the LED to see if we really have a
                 * success response, indicating the actual presense of the LED,
                 * bail out otherwise.
@@ -1282,6 +1292,69 @@ static int toshiba_cooling_method_set(struct toshiba_acpi_dev *dev, u32 state)
        return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
 }
 
+/* Battery charge control */
+static void toshiba_battery_charge_mode_available(struct toshiba_acpi_dev *dev)
+{
+       u32 in[TCI_WORDS] = { HCI_GET, HCI_BATTERY_CHARGE_MODE, 0, 0, 0, 0 };
+       u32 out[TCI_WORDS];
+       acpi_status status;
+
+       dev->battery_charge_mode_supported = 0;
+
+       status = tci_raw(dev, in, out);
+       if (ACPI_FAILURE(status)) {
+               pr_err("ACPI call to get Battery Charge Mode failed\n");
+               return;
+       }
+
+       if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2)
+               return;
+
+       dev->battery_charge_mode_supported = 1;
+}
+
+static int toshiba_battery_charge_mode_get(struct toshiba_acpi_dev *dev, u32 *state)
+{
+       u32 in[TCI_WORDS] = { HCI_GET, HCI_BATTERY_CHARGE_MODE, 0, 0, 0, 0x1 };
+       u32 out[TCI_WORDS];
+       int retries = 3;
+
+       do {
+               acpi_status status = tci_raw(dev, in, out);
+
+               if (ACPI_FAILURE(status))
+                       pr_err("ACPI call to get Battery Charge Mode failed\n");
+               switch (out[0]) {
+               case TOS_SUCCESS:
+               case TOS_SUCCESS2:
+                       *state = out[2];
+                       return 0;
+               case TOS_NOT_SUPPORTED:
+                       return -ENODEV;
+               case TOS_DATA_NOT_AVAILABLE:
+                       retries--;
+                       break;
+               default:
+                       return -EIO;
+               }
+       } while (retries);
+
+       return -EIO;
+}
+
+static int toshiba_battery_charge_mode_set(struct toshiba_acpi_dev *dev, u32 state)
+{
+       u32 result = hci_write(dev, HCI_BATTERY_CHARGE_MODE, state);
+
+       if (result == TOS_FAILURE)
+               pr_err("ACPI call to set Battery Charge Mode failed\n");
+
+       if (result == TOS_NOT_SUPPORTED)
+               return -ENODEV;
+
+       return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
+}
+
 /* Transflective Backlight */
 static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status)
 {
@@ -1616,6 +1689,29 @@ static const struct proc_ops fan_proc_ops = {
        .proc_write     = fan_proc_write,
 };
 
+/* Fan RPM */
+static int get_fan_rpm(struct toshiba_acpi_dev *dev, u32 *rpm)
+{
+       u32 in[TCI_WORDS] = { HCI_GET, HCI_FAN_RPM, 0, 1, 0, 0 };
+       u32 out[TCI_WORDS];
+       acpi_status status = tci_raw(dev, in, out);
+
+       if (ACPI_FAILURE(status)) {
+               pr_err("ACPI call to get Fan speed failed\n");
+               return -EIO;
+       }
+
+       if (out[0] == TOS_NOT_SUPPORTED)
+               return -ENODEV;
+
+       if (out[0] == TOS_SUCCESS) {
+               *rpm = out[2];
+               return 0;
+       }
+
+       return -EIO;
+}
+
 static int keys_proc_show(struct seq_file *m, void *v)
 {
        struct toshiba_acpi_dev *dev = m->private;
@@ -2786,6 +2882,7 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
        dev->hotkey_dev->name = "Toshiba input device";
        dev->hotkey_dev->phys = "toshiba_acpi/input0";
        dev->hotkey_dev->id.bustype = BUS_HOST;
+       dev->hotkey_dev->dev.parent = &dev->acpi_dev->dev;
 
        if (dev->hotkey_event_type == HCI_SYSTEM_TYPE1 ||
            !dev->kbd_function_keys_supported)
@@ -2881,14 +2978,6 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
                return 0;
        }
 
-       /*
-        * Tell acpi-video-detect code to prefer vendor backlight on all
-        * systems with transflective backlight and on dmi matched systems.
-        */
-       if (dev->tr_backlight_supported ||
-           dmi_check_system(toshiba_vendor_backlight_dmi))
-               acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
-
        if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
                return 0;
 
@@ -2916,6 +3005,139 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
        return 0;
 }
 
+/* HWMON support for fan */
+#if IS_ENABLED(CONFIG_HWMON)
+static umode_t toshiba_acpi_hwmon_is_visible(const void *drvdata,
+                                            enum hwmon_sensor_types type,
+                                            u32 attr, int channel)
+{
+       return 0444;
+}
+
+static int toshiba_acpi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
+                                  u32 attr, int channel, long *val)
+{
+       /*
+        * There is only a single channel and single attribute (for the
+        * fan) at this point.
+        * This can be replaced with more advanced logic in the future,
+        * should the need arise.
+        */
+       if (type == hwmon_fan && channel == 0 && attr == hwmon_fan_input) {
+               u32 value;
+               int ret;
+
+               ret = get_fan_rpm(toshiba_acpi, &value);
+               if (ret)
+                       return ret;
+
+               *val = value;
+               return 0;
+       }
+       return -EOPNOTSUPP;
+}
+
+static const struct hwmon_channel_info *toshiba_acpi_hwmon_info[] = {
+       HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),
+       NULL
+};
+
+static const struct hwmon_ops toshiba_acpi_hwmon_ops = {
+       .is_visible = toshiba_acpi_hwmon_is_visible,
+       .read = toshiba_acpi_hwmon_read,
+};
+
+static const struct hwmon_chip_info toshiba_acpi_hwmon_chip_info = {
+       .ops = &toshiba_acpi_hwmon_ops,
+       .info = toshiba_acpi_hwmon_info,
+};
+#endif
+
+/* ACPI battery hooking */
+static ssize_t charge_control_end_threshold_show(struct device *device,
+                                                struct device_attribute *attr,
+                                                char *buf)
+{
+       u32 state;
+       int status;
+
+       if (toshiba_acpi == NULL) {
+               pr_err("Toshiba ACPI object invalid\n");
+               return -ENODEV;
+       }
+
+       status = toshiba_battery_charge_mode_get(toshiba_acpi, &state);
+
+       if (status != 0)
+               return status;
+
+       if (state == 1)
+               return sprintf(buf, "80\n");
+       else
+               return sprintf(buf, "100\n");
+}
+
+static ssize_t charge_control_end_threshold_store(struct device *dev,
+                                                 struct device_attribute *attr,
+                                                 const char *buf,
+                                                 size_t count)
+{
+       u32 value;
+       int rval;
+
+       if (toshiba_acpi == NULL) {
+               pr_err("Toshiba ACPI object invalid\n");
+               return -ENODEV;
+       }
+
+       rval = kstrtou32(buf, 10, &value);
+       if (rval)
+               return rval;
+
+       if (value < 1 || value > 100)
+               return -EINVAL;
+       rval = toshiba_battery_charge_mode_set(toshiba_acpi,
+                                              (value < 90) ? 1 : 0);
+       if (rval < 0)
+               return rval;
+       else
+               return count;
+}
+
+static DEVICE_ATTR_RW(charge_control_end_threshold);
+
+static struct attribute *toshiba_acpi_battery_attrs[] = {
+       &dev_attr_charge_control_end_threshold.attr,
+       NULL,
+};
+
+ATTRIBUTE_GROUPS(toshiba_acpi_battery);
+
+static int toshiba_acpi_battery_add(struct power_supply *battery)
+{
+       if (toshiba_acpi == NULL) {
+               pr_err("Init order issue\n");
+               return -ENODEV;
+       }
+       if (!toshiba_acpi->battery_charge_mode_supported)
+               return -ENODEV;
+       if (device_add_groups(&battery->dev, toshiba_acpi_battery_groups))
+               return -ENODEV;
+       return 0;
+}
+
+static int toshiba_acpi_battery_remove(struct power_supply *battery)
+{
+       device_remove_groups(&battery->dev, toshiba_acpi_battery_groups);
+       return 0;
+}
+
+static struct acpi_battery_hook battery_hook = {
+       .add_battery = toshiba_acpi_battery_add,
+       .remove_battery = toshiba_acpi_battery_remove,
+       .name = "Toshiba Battery Extension",
+};
+
 static void print_supported_features(struct toshiba_acpi_dev *dev)
 {
        pr_info("Supported laptop features:");
@@ -2928,6 +3150,8 @@ static void print_supported_features(struct toshiba_acpi_dev *dev)
                pr_cont(" video-out");
        if (dev->fan_supported)
                pr_cont(" fan");
+       if (dev->fan_rpm_supported)
+               pr_cont(" fan-rpm");
        if (dev->tr_backlight_supported)
                pr_cont(" transflective-backlight");
        if (dev->illumination_supported)
@@ -2956,6 +3180,8 @@ static void print_supported_features(struct toshiba_acpi_dev *dev)
                pr_cont(" wwan");
        if (dev->cooling_method_supported)
                pr_cont(" cooling-method");
+       if (dev->battery_charge_mode_supported)
+               pr_cont(" battery-charge-mode");
 
        pr_cont("\n");
 }
@@ -2968,6 +3194,11 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
 
        remove_toshiba_proc_entries(dev);
 
+#if IS_ENABLED(CONFIG_HWMON)
+       if (dev->hwmon_device)
+               hwmon_device_unregister(dev->hwmon_device);
+#endif
+
        if (dev->accelerometer_supported && dev->indio_dev) {
                iio_device_unregister(dev->indio_dev);
                iio_device_free(dev->indio_dev);
@@ -2996,6 +3227,9 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
                rfkill_destroy(dev->wwan_rfk);
        }
 
+       if (dev->battery_charge_mode_supported)
+               battery_hook_unregister(&battery_hook);
+
        if (toshiba_acpi)
                toshiba_acpi = NULL;
 
@@ -3015,6 +3249,43 @@ static const char *find_hci_method(acpi_handle handle)
        return NULL;
 }
 
+/*
+ * Some Toshibas have a broken acpi-video interface for brightness control,
+ * these are quirked in drivers/acpi/video_detect.c to use the GPU native
+ * (/sys/class/backlight/intel_backlight) instead.
+ * But these need a HCI_SET call to actually turn the panel back on at resume,
+ * without this call the screen stays black at resume.
+ * Either HCI_LCD_BRIGHTNESS (used by acpi_video's _BCM) or HCI_PANEL_POWER_ON
+ * works. toshiba_acpi_resume() uses HCI_PANEL_POWER_ON to avoid changing
+ * the configured brightness level.
+ */
+static const struct dmi_system_id turn_on_panel_on_resume_dmi_ids[] = {
+       {
+        /* Toshiba Portégé R700 */
+        /* https://bugzilla.kernel.org/show_bug.cgi?id=21012 */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R700"),
+               },
+       },
+       {
+        /* Toshiba Satellite/Portégé R830 */
+        /* Portégé: https://bugs.freedesktop.org/show_bug.cgi?id=82634 */
+        /* Satellite: https://bugzilla.kernel.org/show_bug.cgi?id=21012 */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "R830"),
+               },
+       },
+       {
+        /* Toshiba Satellite/Portégé Z830 */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Z830"),
+               },
+       },
+};
+
 static int toshiba_acpi_add(struct acpi_device *acpi_dev)
 {
        struct toshiba_acpi_dev *dev;
@@ -3157,12 +3428,32 @@ iio_error:
        ret = get_fan_status(dev, &dummy);
        dev->fan_supported = !ret;
 
+       ret = get_fan_rpm(dev, &dummy);
+       dev->fan_rpm_supported = !ret;
+
+#if IS_ENABLED(CONFIG_HWMON)
+       if (dev->fan_rpm_supported) {
+               dev->hwmon_device = hwmon_device_register_with_info(
+                       &dev->acpi_dev->dev, "toshiba_acpi_sensors", NULL,
+                       &toshiba_acpi_hwmon_chip_info, NULL);
+               if (IS_ERR(dev->hwmon_device)) {
+                       dev->hwmon_device = NULL;
+                       pr_warn("unable to register hwmon device, skipping\n");
+               }
+       }
+#endif
+
+       if (turn_on_panel_on_resume == -1)
+               turn_on_panel_on_resume = dmi_check_system(turn_on_panel_on_resume_dmi_ids);
+
        toshiba_wwan_available(dev);
        if (dev->wwan_supported)
                toshiba_acpi_setup_wwan_rfkill(dev);
 
        toshiba_cooling_method_available(dev);
 
+       toshiba_battery_charge_mode_available(dev);
+
        print_supported_features(dev);
 
        ret = sysfs_create_group(&dev->acpi_dev->dev.kobj,
@@ -3177,6 +3468,13 @@ iio_error:
 
        toshiba_acpi = dev;
 
+       /*
+        * As the battery hook relies on the static variable toshiba_acpi being
+        * set, this must be done after toshiba_acpi is assigned.
+        */
+       if (dev->battery_charge_mode_supported)
+               battery_hook_register(&battery_hook);
+
        return 0;
 
 error:
@@ -3273,6 +3571,9 @@ static int toshiba_acpi_resume(struct device *device)
                        rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch);
        }
 
+       if (turn_on_panel_on_resume)
+               hci_write(dev, HCI_PANEL_POWER_ON, 1);
+
        return 0;
 }
 #endif
index 2c90c5c..465ffad 100644 (file)
@@ -161,7 +161,7 @@ static int __init fm07keys_init(void)
                return ret;
        }
 
-       dev = platform_device_register_simple(DRV_NAME, -1, NULL, 0);
+       dev = platform_device_register_simple(DRV_NAME, PLATFORM_DEVID_NONE, NULL, 0);
        if (IS_ERR(dev)) {
                ret = PTR_ERR(dev);
                pr_err("fm07keys: failed to allocate device, err = %d\n", ret);
index aed293b..223550a 100644 (file)
@@ -95,9 +95,6 @@ module_param(debug_dump_wdg, bool, 0444);
 MODULE_PARM_DESC(debug_dump_wdg,
                 "Dump available WMI interfaces [0/1]");
 
-static int acpi_wmi_remove(struct platform_device *device);
-static int acpi_wmi_probe(struct platform_device *device);
-
 static const struct acpi_device_id wmi_device_ids[] = {
        {"PNP0C14", 0},
        {"pnp0c14", 0},
@@ -105,13 +102,10 @@ static const struct acpi_device_id wmi_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, wmi_device_ids);
 
-static struct platform_driver acpi_wmi_driver = {
-       .driver = {
-               .name = "acpi-wmi",
-               .acpi_match_table = wmi_device_ids,
-       },
-       .probe = acpi_wmi_probe,
-       .remove = acpi_wmi_remove,
+/* allow duplicate GUIDs as these device drivers use struct wmi_driver */
+static const char * const allow_duplicates[] = {
+       "05901221-D566-11D1-B2F0-00A0C9062910", /* wmi-bmof */
+       NULL
 };
 
 /*
@@ -1073,6 +1067,23 @@ static const struct device_type wmi_type_data = {
        .release = wmi_dev_release,
 };
 
+/*
+ * _WDG is a static list that is only parsed at startup,
+ * so it's safe to count entries without extra protection.
+ */
+static int guid_count(const guid_t *guid)
+{
+       struct wmi_block *wblock;
+       int count = 0;
+
+       list_for_each_entry(wblock, &wmi_block_list, list) {
+               if (guid_equal(&wblock->gblock.guid, guid))
+                       count++;
+       }
+
+       return count;
+}
+
 static int wmi_create_device(struct device *wmi_bus_dev,
                             struct wmi_block *wblock,
                             struct acpi_device *device)
@@ -1080,6 +1091,7 @@ static int wmi_create_device(struct device *wmi_bus_dev,
        struct acpi_device_info *info;
        char method[WMI_ACPI_METHOD_NAME_SIZE];
        int result;
+       uint count;
 
        if (wblock->gblock.flags & ACPI_WMI_EVENT) {
                wblock->dev.dev.type = &wmi_type_event;
@@ -1134,7 +1146,11 @@ static int wmi_create_device(struct device *wmi_bus_dev,
        wblock->dev.dev.bus = &wmi_bus_type;
        wblock->dev.dev.parent = wmi_bus_dev;
 
-       dev_set_name(&wblock->dev.dev, "%pUL", &wblock->gblock.guid);
+       count = guid_count(&wblock->gblock.guid);
+       if (count)
+               dev_set_name(&wblock->dev.dev, "%pUL-%d", &wblock->gblock.guid, count);
+       else
+               dev_set_name(&wblock->dev.dev, "%pUL", &wblock->gblock.guid);
 
        device_initialize(&wblock->dev.dev);
 
@@ -1154,11 +1170,20 @@ static void wmi_free_devices(struct acpi_device *device)
        }
 }
 
-static bool guid_already_parsed(struct acpi_device *device, const guid_t *guid)
+static bool guid_already_parsed_for_legacy(struct acpi_device *device, const guid_t *guid)
 {
        struct wmi_block *wblock;
 
        list_for_each_entry(wblock, &wmi_block_list, list) {
+               /* skip warning and register if we know the driver will use struct wmi_driver */
+               for (int i = 0; allow_duplicates[i] != NULL; i++) {
+                       guid_t tmp;
+
+                       if (guid_parse(allow_duplicates[i], &tmp))
+                               continue;
+                       if (guid_equal(&tmp, guid))
+                               return false;
+               }
                if (guid_equal(&wblock->gblock.guid, guid)) {
                        /*
                         * Because we historically didn't track the relationship
@@ -1208,13 +1233,7 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device)
                if (debug_dump_wdg)
                        wmi_dump_wdg(&gblock[i]);
 
-               /*
-                * Some WMI devices, like those for nVidia hooks, have a
-                * duplicate GUID. It's not clear what we should do in this
-                * case yet, so for now, we'll just ignore the duplicate
-                * for device creation.
-                */
-               if (guid_already_parsed(device, &gblock[i].guid))
+               if (guid_already_parsed_for_legacy(device, &gblock[i].guid))
                        continue;
 
                wblock = kzalloc(sizeof(*wblock), GFP_KERNEL);
@@ -1449,6 +1468,15 @@ void wmi_driver_unregister(struct wmi_driver *driver)
 }
 EXPORT_SYMBOL(wmi_driver_unregister);
 
+static struct platform_driver acpi_wmi_driver = {
+       .driver = {
+               .name = "acpi-wmi",
+               .acpi_match_table = wmi_device_ids,
+       },
+       .probe = acpi_wmi_probe,
+       .remove = acpi_wmi_remove,
+};
+
 static int __init acpi_wmi_init(void)
 {
        int error;
index db8548f..a275c35 100644 (file)
@@ -48,15 +48,18 @@ enum acpi_backlight_type {
        acpi_backlight_video,
        acpi_backlight_vendor,
        acpi_backlight_native,
+       acpi_backlight_nvidia_wmi_ec,
+       acpi_backlight_apple_gmux,
 };
 
 #if IS_ENABLED(CONFIG_ACPI_VIDEO)
 extern int acpi_video_register(void);
 extern void acpi_video_unregister(void);
+extern void acpi_video_register_backlight(void);
 extern int acpi_video_get_edid(struct acpi_device *device, int type,
                               int device_id, void **edid);
 extern enum acpi_backlight_type acpi_video_get_backlight_type(void);
-extern void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type);
+extern bool acpi_video_backlight_use_native(void);
 /*
  * Note: The value returned by acpi_video_handles_brightness_key_presses()
  * may change over time and should not be cached.
@@ -68,6 +71,7 @@ extern int acpi_video_get_levels(struct acpi_device *device,
 #else
 static inline int acpi_video_register(void) { return -ENODEV; }
 static inline void acpi_video_unregister(void) { return; }
+static inline void acpi_video_register_backlight(void) { return; }
 static inline int acpi_video_get_edid(struct acpi_device *device, int type,
                                      int device_id, void **edid)
 {
@@ -77,8 +81,9 @@ static inline enum acpi_backlight_type acpi_video_get_backlight_type(void)
 {
        return acpi_backlight_vendor;
 }
-static inline void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type)
+static inline bool acpi_video_backlight_use_native(void)
 {
+       return true;
 }
 static inline bool acpi_video_handles_brightness_key_presses(void)
 {
index 2f9193b..729cff1 100644 (file)
@@ -1083,6 +1083,7 @@ acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state,
 struct acpi_s2idle_dev_ops {
        struct list_head list_node;
        void (*prepare)(void);
+       void (*check)(void);
        void (*restore)(void);
 };
 int acpi_register_lps0_dev(struct acpi_s2idle_dev_ops *arg);
index 98f2b2f..28234dc 100644 (file)
@@ -65,6 +65,7 @@
 #define ASUS_WMI_DEVID_PANEL_OD                0x00050019
 #define ASUS_WMI_DEVID_CAMERA          0x00060013
 #define ASUS_WMI_DEVID_LID_FLIP                0x00060062
+#define ASUS_WMI_DEVID_LID_FLIP_ROG    0x00060077
 
 /* Storage */
 #define ASUS_WMI_DEVID_CARDREADER      0x00080013
@@ -78,6 +79,7 @@
 #define ASUS_WMI_DEVID_THERMAL_CTRL    0x00110011
 #define ASUS_WMI_DEVID_FAN_CTRL                0x00110012 /* deprecated */
 #define ASUS_WMI_DEVID_CPU_FAN_CTRL    0x00110013
+#define ASUS_WMI_DEVID_GPU_FAN_CTRL    0x00110014
 #define ASUS_WMI_DEVID_CPU_FAN_CURVE   0x00110024
 #define ASUS_WMI_DEVID_GPU_FAN_CURVE   0x00110025
 
 /* dgpu on/off */
 #define ASUS_WMI_DEVID_DGPU            0x00090020
 
+/* gpu mux switch, 0 = dGPU, 1 = Optimus */
+#define ASUS_WMI_DEVID_GPU_MUX         0x00090016
+
+/* TUF laptop RGB modes/colours */
+#define ASUS_WMI_DEVID_TUF_RGB_MODE    0x00100056
+
+/* TUF laptop RGB power/state */
+#define ASUS_WMI_DEVID_TUF_RGB_STATE   0x00100057
+
 /* DSTS masks */
 #define ASUS_WMI_DSTS_STATUS_BIT       0x00000001
 #define ASUS_WMI_DSTS_UNKNOWN_BIT      0x00000002
diff --git a/include/linux/platform_data/x86/nvidia-wmi-ec-backlight.h b/include/linux/platform_data/x86/nvidia-wmi-ec-backlight.h
new file mode 100644 (file)
index 0000000..23d6013
--- /dev/null
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020, NVIDIA CORPORATION.  All rights reserved.
+ */
+
+#ifndef __PLATFORM_DATA_X86_NVIDIA_WMI_EC_BACKLIGHT_H
+#define __PLATFORM_DATA_X86_NVIDIA_WMI_EC_BACKLIGHT_H
+
+#define WMI_BRIGHTNESS_GUID "603E9613-EF25-4338-A3D0-C46177516DB7"
+
+/**
+ * enum wmi_brightness_method - WMI method IDs
+ * @WMI_BRIGHTNESS_METHOD_LEVEL:  Get/Set EC brightness level status
+ * @WMI_BRIGHTNESS_METHOD_SOURCE: Get/Set EC Brightness Source
+ */
+enum wmi_brightness_method {
+       WMI_BRIGHTNESS_METHOD_LEVEL = 1,
+       WMI_BRIGHTNESS_METHOD_SOURCE = 2,
+       WMI_BRIGHTNESS_METHOD_MAX
+};
+
+/**
+ * enum wmi_brightness_mode - Operation mode for WMI-wrapped method
+ * @WMI_BRIGHTNESS_MODE_GET:            Get the current brightness level/source.
+ * @WMI_BRIGHTNESS_MODE_SET:            Set the brightness level.
+ * @WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL:  Get the maximum brightness level. This
+ *                                      is only valid when the WMI method is
+ *                                      %WMI_BRIGHTNESS_METHOD_LEVEL.
+ */
+enum wmi_brightness_mode {
+       WMI_BRIGHTNESS_MODE_GET = 0,
+       WMI_BRIGHTNESS_MODE_SET = 1,
+       WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL = 2,
+       WMI_BRIGHTNESS_MODE_MAX
+};
+
+/**
+ * enum wmi_brightness_source - Backlight brightness control source selection
+ * @WMI_BRIGHTNESS_SOURCE_GPU: Backlight brightness is controlled by the GPU.
+ * @WMI_BRIGHTNESS_SOURCE_EC:  Backlight brightness is controlled by the
+ *                             system's Embedded Controller (EC).
+ * @WMI_BRIGHTNESS_SOURCE_AUX: Backlight brightness is controlled over the
+ *                             DisplayPort AUX channel.
+ */
+enum wmi_brightness_source {
+       WMI_BRIGHTNESS_SOURCE_GPU = 1,
+       WMI_BRIGHTNESS_SOURCE_EC = 2,
+       WMI_BRIGHTNESS_SOURCE_AUX = 3,
+       WMI_BRIGHTNESS_SOURCE_MAX
+};
+
+/**
+ * struct wmi_brightness_args - arguments for the WMI-wrapped ACPI method
+ * @mode:    Pass in an &enum wmi_brightness_mode value to select between
+ *           getting or setting a value.
+ * @val:     In parameter for value to set when using %WMI_BRIGHTNESS_MODE_SET
+ *           mode. Not used in conjunction with %WMI_BRIGHTNESS_MODE_GET or
+ *           %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL mode.
+ * @ret:     Out parameter returning retrieved value when operating in
+ *           %WMI_BRIGHTNESS_MODE_GET or %WMI_BRIGHTNESS_MODE_GET_MAX_LEVEL
+ *           mode. Not used in %WMI_BRIGHTNESS_MODE_SET mode.
+ * @ignored: Padding; not used. The ACPI method expects a 24 byte params struct.
+ *
+ * This is the parameters structure for the WmiBrightnessNotify ACPI method as
+ * wrapped by WMI. The value passed in to @val or returned by @ret will be a
+ * brightness value when the WMI method ID is %WMI_BRIGHTNESS_METHOD_LEVEL, or
+ * an &enum wmi_brightness_source value with %WMI_BRIGHTNESS_METHOD_SOURCE.
+ */
+struct wmi_brightness_args {
+       u32 mode;
+       u32 val;
+       u32 ret;
+       u32 ignored[3];
+};
+
+#endif
index dd81f51..b8a701c 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Intel Atom SOC Power Management Controller Header File
- * Copyright (c) 2014, Intel Corporation.
+ * Intel Atom SoC Power Management Controller Header File
+ * Copyright (c) 2014-2015,2022 Intel Corporation.
  */
 
 #ifndef PMC_ATOM_H
index 39fefd4..57d6a10 100644 (file)
@@ -19,6 +19,7 @@
 #define SIMATIC_IPC_DEVICE_427E 2
 #define SIMATIC_IPC_DEVICE_127E 3
 #define SIMATIC_IPC_DEVICE_227E 4
+#define SIMATIC_IPC_DEVICE_227G 5
 
 struct simatic_ipc_platform {
        u8      devmode;
index f3b76b3..632320e 100644 (file)
@@ -31,6 +31,8 @@ enum simatic_ipc_station_ids {
        SIMATIC_IPC_IPC427E = 0x00000A01,
        SIMATIC_IPC_IPC477E = 0x00000A02,
        SIMATIC_IPC_IPC127E = 0x00000D01,
+       SIMATIC_IPC_IPC227G = 0x00000F01,
+       SIMATIC_IPC_IPC427G = 0x00001001,
 };
 
 static inline u32 simatic_ipc_get_station_id(u8 *data, int max_len)
index 23a253d..be77372 100644 (file)
@@ -191,6 +191,7 @@ struct platform_s2idle_ops {
        int (*begin)(void);
        int (*prepare)(void);
        int (*prepare_late)(void);
+       void (*check)(void);
        bool (*wake)(void);
        void (*restore_early)(void);
        void (*restore)(void);
index 8270759..c6272d4 100644 (file)
@@ -136,6 +136,9 @@ static void s2idle_loop(void)
                        break;
                }
 
+               if (s2idle_ops && s2idle_ops->check)
+                       s2idle_ops->check();
+
                s2idle_enter();
        }
 
index f0ed697..be96e90 100644 (file)
@@ -181,7 +181,10 @@ struct perf_cap {
 
 static void process_hfi_event(struct perf_cap *perf_cap)
 {
-       process_level_change(perf_cap->cpu);
+       struct isst_id id;
+
+       set_isst_id(&id, perf_cap->cpu);
+       process_level_change(&id);
 }
 
 static int handle_event(struct nl_msg *n, void *arg)
index 9d35614..a160bad 100644 (file)
@@ -15,7 +15,7 @@ struct process_cmd_struct {
        int arg;
 };
 
-static const char *version_str = "v1.12";
+static const char *version_str = "v1.13";
 
 static const int supported_api_ver = 1;
 static struct isst_if_platform_info isst_platform_info;
@@ -63,6 +63,7 @@ struct _cpu_map {
        unsigned short die_id;
        unsigned short punit_cpu;
        unsigned short punit_cpu_core;
+       unsigned short initialized;
 };
 struct _cpu_map *cpu_map;
 
@@ -298,10 +299,16 @@ static void store_cpu_topology(void)
        fclose(fp);
 }
 
-int get_physical_package_id(int cpu)
+static int get_physical_package_id(int cpu)
 {
        int ret;
 
+       if (cpu < 0)
+               return -1;
+
+       if (cpu_map && cpu_map[cpu].initialized)
+               return cpu_map[cpu].pkg_id;
+
        ret = parse_int_file(0,
                        "/sys/devices/system/cpu/cpu%d/topology/physical_package_id",
                        cpu);
@@ -316,10 +323,16 @@ int get_physical_package_id(int cpu)
        return ret;
 }
 
-int get_physical_core_id(int cpu)
+static int get_physical_core_id(int cpu)
 {
        int ret;
 
+       if (cpu < 0)
+               return -1;
+
+       if (cpu_map && cpu_map[cpu].initialized)
+               return cpu_map[cpu].core_id;
+
        ret = parse_int_file(0,
                        "/sys/devices/system/cpu/cpu%d/topology/core_id",
                        cpu);
@@ -334,10 +347,16 @@ int get_physical_core_id(int cpu)
        return ret;
 }
 
-int get_physical_die_id(int cpu)
+static int get_physical_die_id(int cpu)
 {
        int ret;
 
+       if (cpu < 0)
+               return -1;
+
+       if (cpu_map && cpu_map[cpu].initialized)
+               return cpu_map[cpu].die_id;
+
        ret = parse_int_file(0,
                        "/sys/devices/system/cpu/cpu%d/topology/die_id",
                        cpu);
@@ -359,6 +378,31 @@ int get_physical_die_id(int cpu)
        return ret;
 }
 
+void set_isst_id(struct isst_id *id, int cpu)
+{
+       id->cpu = cpu;
+
+       id->pkg = get_physical_package_id(cpu);
+       if (id < 0 || id->pkg >= MAX_PACKAGE_COUNT)
+               id->pkg = -1;
+
+       id->die = get_physical_die_id(cpu);
+       if (id < 0 || id->die >= MAX_DIE_PER_PACKAGE)
+               id->die = -1;
+}
+
+int is_cpu_in_power_domain(int cpu, struct isst_id *id)
+{
+       struct isst_id tid;
+
+       set_isst_id(&tid, cpu);
+
+       if (id->pkg == tid.pkg && id->die == tid.die)
+               return 1;
+
+       return 0;
+}
+
 int get_cpufreq_base_freq(int cpu)
 {
        return parse_int_file(0, "/sys/devices/system/cpu/cpu%d/cpufreq/base_frequency", cpu);
@@ -410,13 +454,14 @@ static void force_all_cpus_online(void)
        unlink("/var/run/isst_cpu_topology.dat");
 }
 
-void for_each_online_package_in_set(void (*callback)(int, void *, void *,
+void for_each_online_package_in_set(void (*callback)(struct isst_id *, void *, void *,
                                                     void *, void *),
                                    void *arg1, void *arg2, void *arg3,
                                    void *arg4)
 {
        int max_packages[MAX_PACKAGE_COUNT * MAX_PACKAGE_COUNT];
        int pkg_index = 0, i;
+       struct isst_id id;
 
        memset(max_packages, 0xff, sizeof(max_packages));
        for (i = 0; i < topo_max_cpus; ++i) {
@@ -450,18 +495,20 @@ void for_each_online_package_in_set(void (*callback)(int, void *, void *,
                        }
                }
 
+               set_isst_id(&id, i);
                if (!skip && online && callback) {
-                       callback(i, arg1, arg2, arg3, arg4);
+                       callback(&id, arg1, arg2, arg3, arg4);
                        max_packages[pkg_index++] = pkg_id;
                }
        }
 }
 
 static void for_each_online_target_cpu_in_set(
-       void (*callback)(int, void *, void *, void *, void *), void *arg1,
+       void (*callback)(struct isst_id *, void *, void *, void *, void *), void *arg1,
        void *arg2, void *arg3, void *arg4)
 {
        int i, found = 0;
+       struct isst_id id;
 
        for (i = 0; i < topo_max_cpus; ++i) {
                int online;
@@ -475,8 +522,9 @@ static void for_each_online_target_cpu_in_set(
                        online =
                                1; /* online entry for CPU 0 needs some special configs */
 
+               set_isst_id(&id, i);
                if (online && callback) {
-                       callback(i, arg1, arg2, arg3, arg4);
+                       callback(&id, arg1, arg2, arg3, arg4);
                        found = 1;
                }
        }
@@ -536,47 +584,8 @@ void free_cpu_set(cpu_set_t *cpu_set)
 }
 
 static int cpu_cnt[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE];
-static long long core_mask[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE];
-static void set_cpu_present_cpu_mask(void)
-{
-       size_t size;
-       DIR *dir;
-       int i;
 
-       size = alloc_cpu_set(&present_cpumask);
-       present_cpumask_size = size;
-       for (i = 0; i < topo_max_cpus; ++i) {
-               char buffer[256];
-
-               snprintf(buffer, sizeof(buffer),
-                        "/sys/devices/system/cpu/cpu%d", i);
-               dir = opendir(buffer);
-               if (dir) {
-                       int pkg_id, die_id;
-
-                       CPU_SET_S(i, size, present_cpumask);
-                       die_id = get_physical_die_id(i);
-                       if (die_id < 0)
-                               die_id = 0;
-
-                       pkg_id = get_physical_package_id(i);
-                       if (pkg_id < 0) {
-                               fprintf(stderr, "Failed to get package id, CPU %d may be offline\n", i);
-                               continue;
-                       }
-                       if (pkg_id < MAX_PACKAGE_COUNT &&
-                           die_id < MAX_DIE_PER_PACKAGE) {
-                               int core_id = get_physical_core_id(i);
-
-                               cpu_cnt[pkg_id][die_id]++;
-                               core_mask[pkg_id][die_id] |= (1ULL << core_id);
-                       }
-               }
-               closedir(dir);
-       }
-}
-
-int get_max_punit_core_id(int pkg_id, int die_id)
+int get_max_punit_core_id(struct isst_id *id)
 {
        int max_id = 0;
        int i;
@@ -586,60 +595,74 @@ int get_max_punit_core_id(int pkg_id, int die_id)
                if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
                        continue;
 
-               if (cpu_map[i].pkg_id == pkg_id &&
-                       cpu_map[i].die_id == die_id &&
-                       cpu_map[i].punit_cpu_core > max_id)
+               if (is_cpu_in_power_domain(i, id) &&
+                   cpu_map[i].punit_cpu_core > max_id)
                        max_id = cpu_map[i].punit_cpu_core;
        }
 
        return max_id;
 }
 
-int get_cpu_count(int pkg_id, int die_id)
+int get_cpu_count(struct isst_id *id)
 {
-       if (pkg_id < MAX_PACKAGE_COUNT && die_id < MAX_DIE_PER_PACKAGE)
-               return cpu_cnt[pkg_id][die_id];
-
-       return 0;
-}
-
-static void set_cpu_target_cpu_mask(void)
-{
-       size_t size;
-       int i;
-
-       size = alloc_cpu_set(&target_cpumask);
-       target_cpumask_size = size;
-       for (i = 0; i < max_target_cpus; ++i) {
-               if (!CPU_ISSET_S(target_cpus[i], present_cpumask_size,
-                                present_cpumask))
-                       continue;
+       if (id->pkg < 0 || id->die < 0)
+               return 0;
 
-               CPU_SET_S(target_cpus[i], size, target_cpumask);
-       }
+       return cpu_cnt[id->pkg][id->die];
 }
 
 static void create_cpu_map(void)
 {
        const char *pathname = "/dev/isst_interface";
+       size_t size;
+       DIR *dir;
        int i, fd = 0;
        struct isst_if_cpu_maps map;
 
-       cpu_map = malloc(sizeof(*cpu_map) * topo_max_cpus);
+       /* Use calloc to make sure the memory is initialized to Zero */
+       cpu_map = calloc(topo_max_cpus, sizeof(*cpu_map));
        if (!cpu_map)
                err(3, "cpumap");
 
        fd = open(pathname, O_RDWR);
-       if (fd < 0)
+       if (fd < 0 && !is_clx_n_platform())
                err(-1, "%s open failed", pathname);
 
+       size = alloc_cpu_set(&present_cpumask);
+       present_cpumask_size = size;
+
        for (i = 0; i < topo_max_cpus; ++i) {
-               if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
+               char buffer[256];
+               int pkg_id, die_id, core_id;
+
+               /* check if CPU is online */
+               snprintf(buffer, sizeof(buffer),
+                        "/sys/devices/system/cpu/cpu%d", i);
+               dir = opendir(buffer);
+               if (!dir)
+                       continue;
+               closedir(dir);
+
+               CPU_SET_S(i, size, present_cpumask);
+
+               pkg_id = get_physical_package_id(i);
+               die_id = get_physical_die_id(i);
+               core_id = get_physical_core_id(i);
+
+               if (pkg_id < 0 || die_id < 0 || core_id < 0)
                        continue;
 
+               cpu_map[i].pkg_id = pkg_id;
+               cpu_map[i].die_id = die_id;
+               cpu_map[i].core_id = core_id;
+               cpu_map[i].initialized = 1;
+
+               cpu_cnt[pkg_id][die_id]++;
+
+               if (fd < 0)
+                       continue;
                map.cmd_count = 1;
                map.cpu_map[0].logical_cpu = i;
-
                debug_printf(" map logical_cpu:%d\n",
                             map.cpu_map[0].logical_cpu);
                if (ioctl(fd, ISST_IF_GET_PHY_ID, &map) == -1) {
@@ -648,9 +671,6 @@ static void create_cpu_map(void)
                                map.cpu_map[0].logical_cpu);
                        continue;
                }
-               cpu_map[i].core_id = get_physical_core_id(i);
-               cpu_map[i].pkg_id = get_physical_package_id(i);
-               cpu_map[i].die_id = get_physical_die_id(i);
                cpu_map[i].punit_cpu = map.cpu_map[0].physical_cpu;
                cpu_map[i].punit_cpu_core = (map.cpu_map[0].physical_cpu >>
                                             1); // shift to get core id
@@ -661,35 +681,27 @@ static void create_cpu_map(void)
                        cpu_map[i].pkg_id, cpu_map[i].punit_cpu,
                        cpu_map[i].punit_cpu_core);
        }
-
-       if (fd)
+       if (fd >= 0)
                close(fd);
-}
 
-int find_logical_cpu(int pkg_id, int die_id, int punit_core_id)
-{
-       int i;
+       size = alloc_cpu_set(&target_cpumask);
+       target_cpumask_size = size;
+       for (i = 0; i < max_target_cpus; ++i) {
+               if (!CPU_ISSET_S(target_cpus[i], present_cpumask_size,
+                                present_cpumask))
+                       continue;
 
-       for (i = 0; i < topo_max_cpus; ++i) {
-               if (cpu_map[i].pkg_id == pkg_id &&
-                   cpu_map[i].die_id == die_id &&
-                   cpu_map[i].punit_cpu_core == punit_core_id)
-                       return i;
+               CPU_SET_S(target_cpus[i], size, target_cpumask);
        }
-
-       return -EINVAL;
 }
 
-void set_cpu_mask_from_punit_coremask(int cpu, unsigned long long core_mask,
+void set_cpu_mask_from_punit_coremask(struct isst_id *id, unsigned long long core_mask,
                                      size_t core_cpumask_size,
                                      cpu_set_t *core_cpumask, int *cpu_cnt)
 {
        int i, cnt = 0;
-       int die_id, pkg_id;
 
        *cpu_cnt = 0;
-       die_id = get_physical_die_id(cpu);
-       pkg_id = get_physical_package_id(cpu);
 
        for (i = 0; i < 64; ++i) {
                if (core_mask & BIT_ULL(i)) {
@@ -699,8 +711,7 @@ void set_cpu_mask_from_punit_coremask(int cpu, unsigned long long core_mask,
                                if (!CPU_ISSET_S(j, present_cpumask_size, present_cpumask))
                                        continue;
 
-                               if (cpu_map[j].pkg_id == pkg_id &&
-                                   cpu_map[j].die_id == die_id &&
+                               if (is_cpu_in_power_domain(j, id) &&
                                    cpu_map[j].punit_cpu_core == i) {
                                        CPU_SET_S(j, core_cpumask_size,
                                                  core_cpumask);
@@ -931,6 +942,7 @@ static void isst_print_extended_platform_info(void)
        struct isst_pkg_ctdp pkg_dev;
        int ret, i, j;
        FILE *filep;
+       struct isst_id id;
 
        for (i = 0; i < 256; ++i) {
                char path[256];
@@ -947,7 +959,8 @@ static void isst_print_extended_platform_info(void)
 
        fclose(filep);
 
-       ret = isst_get_ctdp_levels(i, &pkg_dev);
+       set_isst_id(&id, i);
+       ret = isst_get_ctdp_levels(&id, &pkg_dev);
        if (ret)
                return;
 
@@ -964,7 +977,7 @@ static void isst_print_extended_platform_info(void)
                fprintf(outf, "TDP level change control is unlocked, max level: %d \n", pkg_dev.levels);
 
        for (j = 0; j <= pkg_dev.levels; ++j) {
-               ret = isst_get_ctdp_control(i, j, &ctdp_level);
+               ret = isst_get_ctdp_control(&id, j, &ctdp_level);
                if (ret)
                        continue;
 
@@ -985,7 +998,7 @@ static void isst_print_extended_platform_info(void)
        else
                fprintf(outf, "Intel(R) SST-BF (feature base-freq) is not supported\n");
 
-       ret = isst_read_pm_config(i, &cp_state, &cp_cap);
+       ret = isst_read_pm_config(&id, &cp_state, &cp_cap);
        if (ret) {
                fprintf(outf, "Intel(R) SST-CP (feature core-power) status is unknown\n");
                return;
@@ -1007,6 +1020,10 @@ static void isst_print_platform_information(void)
                exit(0);
        }
 
+       /* Early initialization to create working cpu_map */
+       set_max_cpu_num();
+       create_cpu_map();
+
        fd = open(pathname, O_RDWR);
        if (fd < 0)
                err(-1, "%s open failed", pathname);
@@ -1031,18 +1048,18 @@ static void isst_print_platform_information(void)
 }
 
 static char *local_str0, *local_str1;
-static void exec_on_get_ctdp_cpu(int cpu, void *arg1, void *arg2, void *arg3,
+static void exec_on_get_ctdp_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
                                 void *arg4)
 {
-       int (*fn_ptr)(int cpu, void *arg);
+       int (*fn_ptr)(struct isst_id *id, void *arg);
        int ret;
 
        fn_ptr = arg1;
-       ret = fn_ptr(cpu, arg2);
+       ret = fn_ptr(id, arg2);
        if (ret)
                isst_display_error_info_message(1, "get_tdp_* failed", 0, 0);
        else
-               isst_ctdp_display_core_info(cpu, outf, arg3,
+               isst_ctdp_display_core_info(id, outf, arg3,
                                            *(unsigned int *)arg4,
                                            local_str0, local_str1);
 }
@@ -1110,9 +1127,9 @@ static int clx_n_get_base_ratio(void)
        return (int)(value);
 }
 
-static int clx_n_config(int cpu)
+static int clx_n_config(struct isst_id *id)
 {
-       int i, ret, pkg_id, die_id;
+       int i, ret;
        unsigned long cpu_bf;
        struct isst_pkg_ctdp_level_info *ctdp_level;
        struct isst_pbf_info *pbf_info;
@@ -1134,15 +1151,11 @@ static int clx_n_config(int cpu)
        pbf_info->p1_high = 0;
        pbf_info->p1_low = ~0;
 
-       pkg_id = get_physical_package_id(cpu);
-       die_id = get_physical_die_id(cpu);
-
        for (i = 0; i < topo_max_cpus; i++) {
                if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
                        continue;
 
-               if (pkg_id != get_physical_package_id(i) ||
-                   die_id != get_physical_die_id(i))
+               if (!is_cpu_in_power_domain(i, id))
                        continue;
 
                CPU_SET_S(i, ctdp_level->core_cpumask_size,
@@ -1179,8 +1192,7 @@ static int clx_n_config(int cpu)
                if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
                        continue;
 
-               if (pkg_id != get_physical_package_id(i) ||
-                   die_id != get_physical_die_id(i))
+               if (!is_cpu_in_power_domain(i, id))
                        continue;
 
                cpu_bf = parse_int_file(1,
@@ -1206,7 +1218,7 @@ error_ret:
        return ret;
 }
 
-static void dump_clx_n_config_for_cpu(int cpu, void *arg1, void *arg2,
+static void dump_clx_n_config_for_cpu(struct isst_id *id, void *arg1, void *arg2,
                                   void *arg3, void *arg4)
 {
        int ret;
@@ -1216,7 +1228,7 @@ static void dump_clx_n_config_for_cpu(int cpu, void *arg1, void *arg2,
                exit(0);
        }
 
-       ret = clx_n_config(cpu);
+       ret = clx_n_config(id);
        if (ret) {
                debug_printf("clx_n_config failed");
        } else {
@@ -1226,27 +1238,27 @@ static void dump_clx_n_config_for_cpu(int cpu, void *arg1, void *arg2,
                ctdp_level = &clx_n_pkg_dev.ctdp_level[0];
                pbf_info = &ctdp_level->pbf_info;
                clx_n_pkg_dev.processed = 1;
-               isst_ctdp_display_information(cpu, outf, tdp_level, &clx_n_pkg_dev);
+               isst_ctdp_display_information(id, outf, tdp_level, &clx_n_pkg_dev);
                free_cpu_set(ctdp_level->core_cpumask);
                free_cpu_set(pbf_info->core_cpumask);
        }
 }
 
-static void dump_isst_config_for_cpu(int cpu, void *arg1, void *arg2,
+static void dump_isst_config_for_cpu(struct isst_id *id, void *arg1, void *arg2,
                                     void *arg3, void *arg4)
 {
        struct isst_pkg_ctdp pkg_dev;
        int ret;
 
        memset(&pkg_dev, 0, sizeof(pkg_dev));
-       ret = isst_get_process_ctdp(cpu, tdp_level, &pkg_dev);
+       ret = isst_get_process_ctdp(id, tdp_level, &pkg_dev);
        if (ret) {
-               isst_display_error_info_message(1, "Failed to get perf-profile info on cpu", 1, cpu);
+               isst_display_error_info_message(1, "Failed to get perf-profile info on cpu", 1, id->cpu);
                isst_ctdp_display_information_end(outf);
                exit(1);
        } else {
-               isst_ctdp_display_information(cpu, outf, tdp_level, &pkg_dev);
-               isst_get_process_ctdp_complete(cpu, &pkg_dev);
+               isst_ctdp_display_information(id, outf, tdp_level, &pkg_dev);
+               isst_get_process_ctdp_complete(id, &pkg_dev);
        }
 }
 
@@ -1282,23 +1294,21 @@ static void dump_isst_config(int arg)
 
 static void adjust_scaling_max_from_base_freq(int cpu);
 
-static void set_tdp_level_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
+static void set_tdp_level_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
                                  void *arg4)
 {
        int ret;
 
-       ret = isst_set_tdp_level(cpu, tdp_level);
+       ret = isst_set_tdp_level(id, tdp_level);
        if (ret) {
                isst_display_error_info_message(1, "Set TDP level failed", 0, 0);
                isst_ctdp_display_information_end(outf);
                exit(1);
        } else {
-               isst_display_result(cpu, outf, "perf-profile", "set_tdp_level",
+               isst_display_result(id, outf, "perf-profile", "set_tdp_level",
                                    ret);
                if (force_online_offline) {
                        struct isst_pkg_ctdp_level_info ctdp_level;
-                       int pkg_id = get_physical_package_id(cpu);
-                       int die_id = get_physical_die_id(cpu);
 
                        /* Wait for updated base frequencies */
                        usleep(2000);
@@ -1306,7 +1316,7 @@ static void set_tdp_level_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
                        fprintf(stderr, "Option is set to online/offline\n");
                        ctdp_level.core_cpumask_size =
                                alloc_cpu_set(&ctdp_level.core_cpumask);
-                       ret = isst_get_coremask_info(cpu, tdp_level, &ctdp_level);
+                       ret = isst_get_coremask_info(id, tdp_level, &ctdp_level);
                        if (ret) {
                                isst_display_error_info_message(1, "Can't get coremask, online/offline option is ignored", 0, 0);
                                return;
@@ -1314,7 +1324,7 @@ static void set_tdp_level_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
                        if (ctdp_level.cpu_count) {
                                int i, max_cpus = get_topo_max_cpus();
                                for (i = 0; i < max_cpus; ++i) {
-                                       if (pkg_id != get_physical_package_id(i) || die_id != get_physical_die_id(i))
+                                       if (!is_cpu_in_power_domain(i, id))
                                                continue;
                                        if (CPU_ISSET_S(i, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask)) {
                                                fprintf(stderr, "online cpu %d\n", i);
@@ -1357,12 +1367,12 @@ static void set_tdp_level(int arg)
        isst_ctdp_display_information_end(outf);
 }
 
-static void clx_n_dump_pbf_config_for_cpu(int cpu, void *arg1, void *arg2,
+static void clx_n_dump_pbf_config_for_cpu(struct isst_id *id, void *arg1, void *arg2,
                                       void *arg3, void *arg4)
 {
        int ret;
 
-       ret = clx_n_config(cpu);
+       ret = clx_n_config(id);
        if (ret) {
                isst_display_error_info_message(1, "clx_n_config failed", 0, 0);
        } else {
@@ -1371,25 +1381,25 @@ static void clx_n_dump_pbf_config_for_cpu(int cpu, void *arg1, void *arg2,
 
                ctdp_level = &clx_n_pkg_dev.ctdp_level[0];
                pbf_info = &ctdp_level->pbf_info;
-               isst_pbf_display_information(cpu, outf, tdp_level, pbf_info);
+               isst_pbf_display_information(id, outf, tdp_level, pbf_info);
                free_cpu_set(ctdp_level->core_cpumask);
                free_cpu_set(pbf_info->core_cpumask);
        }
 }
 
-static void dump_pbf_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
+static void dump_pbf_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
                                    void *arg4)
 {
        struct isst_pbf_info pbf_info;
        int ret;
 
-       ret = isst_get_pbf_info(cpu, tdp_level, &pbf_info);
+       ret = isst_get_pbf_info(id, tdp_level, &pbf_info);
        if (ret) {
                isst_display_error_info_message(1, "Failed to get base-freq info at this level", 1, tdp_level);
                isst_ctdp_display_information_end(outf);
                exit(1);
        } else {
-               isst_pbf_display_information(cpu, outf, tdp_level, &pbf_info);
+               isst_pbf_display_information(id, outf, tdp_level, &pbf_info);
                isst_get_pbf_info_complete(&pbf_info);
        }
 }
@@ -1426,12 +1436,12 @@ static void dump_pbf_config(int arg)
        isst_ctdp_display_information_end(outf);
 }
 
-static int set_clos_param(int cpu, int clos, int epp, int wt, int min, int max)
+static int set_clos_param(struct isst_id *id, int clos, int epp, int wt, int min, int max)
 {
        struct isst_clos_config clos_config;
        int ret;
 
-       ret = isst_pm_get_clos(cpu, clos, &clos_config);
+       ret = isst_pm_get_clos(id, clos, &clos_config);
        if (ret) {
                isst_display_error_info_message(1, "isst_pm_get_clos failed", 0, 0);
                return ret;
@@ -1440,7 +1450,7 @@ static int set_clos_param(int cpu, int clos, int epp, int wt, int min, int max)
        clos_config.clos_max = max;
        clos_config.epp = epp;
        clos_config.clos_prop_prio = wt;
-       ret = isst_set_clos(cpu, clos, &clos_config);
+       ret = isst_set_clos(id, clos, &clos_config);
        if (ret) {
                isst_display_error_info_message(1, "isst_set_clos failed", 0, 0);
                return ret;
@@ -1502,14 +1512,14 @@ static void adjust_scaling_min_from_base_freq(int cpu)
                set_cpufreq_scaling_min_max(cpu, 0, base_freq);
 }
 
-static int set_clx_pbf_cpufreq_scaling_min_max(int cpu)
+static int set_clx_pbf_cpufreq_scaling_min_max(struct isst_id *id)
 {
        struct isst_pkg_ctdp_level_info *ctdp_level;
        struct isst_pbf_info *pbf_info;
-       int i, pkg_id, die_id, freq, freq_high, freq_low;
+       int i, freq, freq_high, freq_low;
        int ret;
 
-       ret = clx_n_config(cpu);
+       ret = clx_n_config(id);
        if (ret) {
                debug_printf("cpufreq_scaling_min_max failed for CLX");
                return ret;
@@ -1520,11 +1530,8 @@ static int set_clx_pbf_cpufreq_scaling_min_max(int cpu)
        freq_high = pbf_info->p1_high * 100000;
        freq_low = pbf_info->p1_low * 100000;
 
-       pkg_id = get_physical_package_id(cpu);
-       die_id = get_physical_die_id(cpu);
        for (i = 0; i < get_topo_max_cpus(); ++i) {
-               if (pkg_id != get_physical_package_id(i) ||
-                   die_id != get_physical_die_id(i))
+               if (!is_cpu_in_power_domain(i, id))
                        continue;
 
                if (CPU_ISSET_S(i, pbf_info->core_cpumask_size,
@@ -1587,15 +1594,12 @@ static int set_cpufreq_scaling_min_max_from_cpuinfo(int cpu, int cpuinfo_max, in
        return 0;
 }
 
-static void set_scaling_min_to_cpuinfo_max(int cpu)
+static void set_scaling_min_to_cpuinfo_max(struct isst_id *id)
 {
-       int i, pkg_id, die_id;
+       int i;
 
-       pkg_id = get_physical_package_id(cpu);
-       die_id = get_physical_die_id(cpu);
        for (i = 0; i < get_topo_max_cpus(); ++i) {
-               if (pkg_id != get_physical_package_id(i) ||
-                   die_id != get_physical_die_id(i))
+               if (!is_cpu_in_power_domain(i, id))
                        continue;
 
                adjust_scaling_max_from_base_freq(i);
@@ -1604,15 +1608,12 @@ static void set_scaling_min_to_cpuinfo_max(int cpu)
        }
 }
 
-static void set_scaling_min_to_cpuinfo_min(int cpu)
+static void set_scaling_min_to_cpuinfo_min(struct isst_id *id)
 {
-       int i, pkg_id, die_id;
+       int i;
 
-       pkg_id = get_physical_package_id(cpu);
-       die_id = get_physical_die_id(cpu);
        for (i = 0; i < get_topo_max_cpus(); ++i) {
-               if (pkg_id != get_physical_package_id(i) ||
-                   die_id != get_physical_die_id(i))
+               if (!is_cpu_in_power_domain(i, id))
                        continue;
 
                adjust_scaling_max_from_base_freq(i);
@@ -1620,53 +1621,48 @@ static void set_scaling_min_to_cpuinfo_min(int cpu)
        }
 }
 
-static void set_scaling_max_to_cpuinfo_max(int cpu)
+static void set_scaling_max_to_cpuinfo_max(struct isst_id *id)
 {
-       int i, pkg_id, die_id;
+       int i;
 
-       pkg_id = get_physical_package_id(cpu);
-       die_id = get_physical_die_id(cpu);
        for (i = 0; i < get_topo_max_cpus(); ++i) {
-               if (pkg_id != get_physical_package_id(i) ||
-                   die_id != get_physical_die_id(i))
+               if (!is_cpu_in_power_domain(i, id))
                        continue;
 
                set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 1);
        }
 }
 
-static int set_core_priority_and_min(int cpu, int mask_size,
+static int set_core_priority_and_min(struct isst_id *id, int mask_size,
                                     cpu_set_t *cpu_mask, int min_high,
                                     int min_low)
 {
-       int pkg_id, die_id, ret, i;
+       int ret, i;
 
        if (!CPU_COUNT_S(mask_size, cpu_mask))
                return -1;
 
-       ret = set_clos_param(cpu, 0, 0, 0, min_high, 0xff);
+       ret = set_clos_param(id, 0, 0, 0, min_high, 0xff);
        if (ret)
                return ret;
 
-       ret = set_clos_param(cpu, 1, 15, 15, min_low, 0xff);
+       ret = set_clos_param(id, 1, 15, 15, min_low, 0xff);
        if (ret)
                return ret;
 
-       ret = set_clos_param(cpu, 2, 15, 15, min_low, 0xff);
+       ret = set_clos_param(id, 2, 15, 15, min_low, 0xff);
        if (ret)
                return ret;
 
-       ret = set_clos_param(cpu, 3, 15, 15, min_low, 0xff);
+       ret = set_clos_param(id, 3, 15, 15, min_low, 0xff);
        if (ret)
                return ret;
 
-       pkg_id = get_physical_package_id(cpu);
-       die_id = get_physical_die_id(cpu);
        for (i = 0; i < get_topo_max_cpus(); ++i) {
                int clos;
+               struct isst_id tid;
 
-               if (pkg_id != get_physical_package_id(i) ||
-                   die_id != get_physical_die_id(i))
+               if (!is_cpu_in_power_domain(i, id))
                        continue;
 
                if (CPU_ISSET_S(i, mask_size, cpu_mask))
@@ -1675,7 +1671,8 @@ static int set_core_priority_and_min(int cpu, int mask_size,
                        clos = 3;
 
                debug_printf("Associate cpu: %d clos: %d\n", i, clos);
-               ret = isst_clos_associate(i, clos);
+               set_isst_id(&tid, i);
+               ret = isst_clos_associate(&tid, clos);
                if (ret) {
                        isst_display_error_info_message(1, "isst_clos_associate failed", 0, 0);
                        return ret;
@@ -1685,20 +1682,20 @@ static int set_core_priority_and_min(int cpu, int mask_size,
        return 0;
 }
 
-static int set_pbf_core_power(int cpu)
+static int set_pbf_core_power(struct isst_id *id)
 {
        struct isst_pbf_info pbf_info;
        struct isst_pkg_ctdp pkg_dev;
        int ret;
 
-       ret = isst_get_ctdp_levels(cpu, &pkg_dev);
+       ret = isst_get_ctdp_levels(id, &pkg_dev);
        if (ret) {
                debug_printf("isst_get_ctdp_levels failed");
                return ret;
        }
        debug_printf("Current_level: %d\n", pkg_dev.current_level);
 
-       ret = isst_get_pbf_info(cpu, pkg_dev.current_level, &pbf_info);
+       ret = isst_get_pbf_info(id, pkg_dev.current_level, &pbf_info);
        if (ret) {
                debug_printf("isst_get_pbf_info failed");
                return ret;
@@ -1706,7 +1703,7 @@ static int set_pbf_core_power(int cpu)
        debug_printf("p1_high: %d p1_low: %d\n", pbf_info.p1_high,
                     pbf_info.p1_low);
 
-       ret = set_core_priority_and_min(cpu, pbf_info.core_cpumask_size,
+       ret = set_core_priority_and_min(id, pbf_info.core_cpumask_size,
                                        pbf_info.core_cpumask,
                                        pbf_info.p1_high, pbf_info.p1_low);
        if (ret) {
@@ -1714,7 +1711,7 @@ static int set_pbf_core_power(int cpu)
                return ret;
        }
 
-       ret = isst_pm_qos_config(cpu, 1, 1);
+       ret = isst_pm_qos_config(id, 1, 1);
        if (ret) {
                debug_printf("isst_pm_qos_config failed");
                return ret;
@@ -1723,7 +1720,7 @@ static int set_pbf_core_power(int cpu)
        return 0;
 }
 
-static void set_pbf_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
+static void set_pbf_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
                            void *arg4)
 {
        struct isst_pkg_ctdp_level_info ctdp_level;
@@ -1734,22 +1731,22 @@ static void set_pbf_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
        if (is_clx_n_platform()) {
                ret = 0;
                if (status) {
-                       set_clx_pbf_cpufreq_scaling_min_max(cpu);
+                       set_clx_pbf_cpufreq_scaling_min_max(id);
 
                } else {
-                       set_scaling_max_to_cpuinfo_max(cpu);
-                       set_scaling_min_to_cpuinfo_min(cpu);
+                       set_scaling_max_to_cpuinfo_max(id);
+                       set_scaling_min_to_cpuinfo_min(id);
                }
                goto disp_result;
        }
 
-       ret = isst_get_ctdp_levels(cpu, &pkg_dev);
+       ret = isst_get_ctdp_levels(id, &pkg_dev);
        if (ret) {
                isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);
                goto disp_result;
        }
 
-       ret = isst_get_ctdp_control(cpu, pkg_dev.current_level, &ctdp_level);
+       ret = isst_get_ctdp_control(id, pkg_dev.current_level, &ctdp_level);
        if (ret) {
                isst_display_error_info_message(1, "Failed to get current level", 0, 0);
                goto disp_result;
@@ -1762,34 +1759,34 @@ static void set_pbf_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
        }
 
        if (auto_mode && status) {
-               ret = set_pbf_core_power(cpu);
+               ret = set_pbf_core_power(id);
                if (ret)
                        goto disp_result;
        }
 
-       ret = isst_set_pbf_fact_status(cpu, 1, status);
+       ret = isst_set_pbf_fact_status(id, 1, status);
        if (ret) {
                debug_printf("isst_set_pbf_fact_status failed");
                if (auto_mode)
-                       isst_pm_qos_config(cpu, 0, 0);
+                       isst_pm_qos_config(id, 0, 0);
        } else {
                if (auto_mode) {
                        if (status)
-                               set_scaling_min_to_cpuinfo_max(cpu);
+                               set_scaling_min_to_cpuinfo_max(id);
                        else
-                               set_scaling_min_to_cpuinfo_min(cpu);
+                               set_scaling_min_to_cpuinfo_min(id);
                }
        }
 
        if (auto_mode && !status)
-               isst_pm_qos_config(cpu, 0, 1);
+               isst_pm_qos_config(id, 0, 1);
 
 disp_result:
        if (status)
-               isst_display_result(cpu, outf, "base-freq", "enable",
+               isst_display_result(id, outf, "base-freq", "enable",
                                    ret);
        else
-               isst_display_result(cpu, outf, "base-freq", "disable",
+               isst_display_result(id, outf, "base-freq", "disable",
                                    ret);
 }
 
@@ -1838,19 +1835,19 @@ static void set_pbf_enable(int arg)
        isst_ctdp_display_information_end(outf);
 }
 
-static void dump_fact_config_for_cpu(int cpu, void *arg1, void *arg2,
+static void dump_fact_config_for_cpu(struct isst_id *id, void *arg1, void *arg2,
                                     void *arg3, void *arg4)
 {
        struct isst_fact_info fact_info;
        int ret;
 
-       ret = isst_get_fact_info(cpu, tdp_level, fact_bucket, &fact_info);
+       ret = isst_get_fact_info(id, tdp_level, fact_bucket, &fact_info);
        if (ret) {
                isst_display_error_info_message(1, "Failed to get turbo-freq info at this level", 1, tdp_level);
                isst_ctdp_display_information_end(outf);
                exit(1);
        } else {
-               isst_fact_display_information(cpu, outf, tdp_level, fact_bucket,
+               isst_fact_display_information(id, outf, tdp_level, fact_bucket,
                                              fact_avx, &fact_info);
        }
 }
@@ -1884,7 +1881,7 @@ static void dump_fact_config(int arg)
        isst_ctdp_display_information_end(outf);
 }
 
-static void set_fact_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
+static void set_fact_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
                             void *arg4)
 {
        struct isst_pkg_ctdp_level_info ctdp_level;
@@ -1898,13 +1895,13 @@ static void set_fact_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
                goto disp_results;
        }
 
-       ret = isst_get_ctdp_levels(cpu, &pkg_dev);
+       ret = isst_get_ctdp_levels(id, &pkg_dev);
        if (ret) {
                isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);
                goto disp_results;
        }
 
-       ret = isst_get_ctdp_control(cpu, pkg_dev.current_level, &ctdp_level);
+       ret = isst_get_ctdp_control(id, pkg_dev.current_level, &ctdp_level);
        if (ret) {
                isst_display_error_info_message(1, "Failed to get current level", 0, 0);
                goto disp_results;
@@ -1917,16 +1914,16 @@ static void set_fact_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
        }
 
        if (status) {
-               ret = isst_pm_qos_config(cpu, 1, 1);
+               ret = isst_pm_qos_config(id, 1, 1);
                if (ret)
                        goto disp_results;
        }
 
-       ret = isst_set_pbf_fact_status(cpu, 0, status);
+       ret = isst_set_pbf_fact_status(id, 0, status);
        if (ret) {
                debug_printf("isst_set_pbf_fact_status failed");
                if (auto_mode)
-                       isst_pm_qos_config(cpu, 0, 0);
+                       isst_pm_qos_config(id, 0, 0);
 
                goto disp_results;
        }
@@ -1935,31 +1932,32 @@ static void set_fact_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
        if (status) {
                struct isst_pkg_ctdp pkg_dev;
 
-               ret = isst_get_ctdp_levels(cpu, &pkg_dev);
+               ret = isst_get_ctdp_levels(id, &pkg_dev);
                if (!ret)
-                       ret = isst_set_trl(cpu, fact_trl);
+                       ret = isst_set_trl(id, fact_trl);
                if (ret && auto_mode)
-                       isst_pm_qos_config(cpu, 0, 0);
+                       isst_pm_qos_config(id, 0, 0);
        } else {
                if (auto_mode)
-                       isst_pm_qos_config(cpu, 0, 0);
+                       isst_pm_qos_config(id, 0, 0);
        }
 
 disp_results:
        if (status) {
-               isst_display_result(cpu, outf, "turbo-freq", "enable", ret);
+               isst_display_result(id, outf, "turbo-freq", "enable", ret);
                if (ret)
                        fact_enable_fail = ret;
        } else {
                /* Since we modified TRL during Fact enable, restore it */
-               isst_set_trl_from_current_tdp(cpu, fact_trl);
-               isst_display_result(cpu, outf, "turbo-freq", "disable", ret);
+               isst_set_trl_from_current_tdp(id, fact_trl);
+               isst_display_result(id, outf, "turbo-freq", "disable", ret);
        }
 }
 
 static void set_fact_enable(int arg)
 {
        int i, ret, enable = arg;
+       struct isst_id id;
 
        if (cmd_help) {
                if (enable) {
@@ -2033,19 +2031,20 @@ static void set_fact_enable(int arg)
                        if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
                                continue;
 
-                       ret = set_clos_param(i, 0, 0, 0, 0, 0xff);
+                       set_isst_id(&id, i);
+                       ret = set_clos_param(&id, 0, 0, 0, 0, 0xff);
                        if (ret)
                                goto error_disp;
 
-                       ret = set_clos_param(i, 1, 15, 15, 0, 0xff);
+                       ret = set_clos_param(&id, 1, 15, 15, 0, 0xff);
                        if (ret)
                                goto error_disp;
 
-                       ret = set_clos_param(i, 2, 15, 15, 0, 0xff);
+                       ret = set_clos_param(&id, 2, 15, 15, 0, 0xff);
                        if (ret)
                                goto error_disp;
 
-                       ret = set_clos_param(i, 3, 15, 15, 0, 0xff);
+                       ret = set_clos_param(&id, 3, 15, 15, 0, 0xff);
                        if (ret)
                                goto error_disp;
 
@@ -2055,21 +2054,22 @@ static void set_fact_enable(int arg)
                                clos = 3;
 
                        debug_printf("Associate cpu: %d clos: %d\n", i, clos);
-                       ret = isst_clos_associate(i, clos);
+                       ret = isst_clos_associate(&id, clos);
                        if (ret)
                                goto error_disp;
                }
-               isst_display_result(-1, outf, "turbo-freq --auto", "enable", 0);
+               set_isst_id(&id, -1);
+               isst_display_result(&id, outf, "turbo-freq --auto", "enable", 0);
        }
 
        return;
 
 error_disp:
-       isst_display_result(i, outf, "turbo-freq --auto", "enable", ret);
+       isst_display_result(&id, outf, "turbo-freq --auto", "enable", ret);
 
 }
 
-static void enable_clos_qos_config(int cpu, void *arg1, void *arg2, void *arg3,
+static void enable_clos_qos_config(struct isst_id *id, void *arg1, void *arg2, void *arg3,
                                   void *arg4)
 {
        int ret;
@@ -2078,15 +2078,15 @@ static void enable_clos_qos_config(int cpu, void *arg1, void *arg2, void *arg3,
        if (is_skx_based_platform())
                clos_priority_type = 1;
 
-       ret = isst_pm_qos_config(cpu, status, clos_priority_type);
+       ret = isst_pm_qos_config(id, status, clos_priority_type);
        if (ret)
                isst_display_error_info_message(1, "isst_pm_qos_config failed", 0, 0);
 
        if (status)
-               isst_display_result(cpu, outf, "core-power", "enable",
+               isst_display_result(id, outf, "core-power", "enable",
                                    ret);
        else
-               isst_display_result(cpu, outf, "core-power", "disable",
+               isst_display_result(id, outf, "core-power", "disable",
                                    ret);
 }
 
@@ -2125,17 +2125,17 @@ static void set_clos_enable(int arg)
        isst_ctdp_display_information_end(outf);
 }
 
-static void dump_clos_config_for_cpu(int cpu, void *arg1, void *arg2,
+static void dump_clos_config_for_cpu(struct isst_id *id, void *arg1, void *arg2,
                                     void *arg3, void *arg4)
 {
        struct isst_clos_config clos_config;
        int ret;
 
-       ret = isst_pm_get_clos(cpu, current_clos, &clos_config);
+       ret = isst_pm_get_clos(id, current_clos, &clos_config);
        if (ret)
                isst_display_error_info_message(1, "isst_pm_get_clos failed", 0, 0);
        else
-               isst_clos_display_information(cpu, outf, current_clos,
+               isst_clos_display_information(id, outf, current_clos,
                                              &clos_config);
 }
 
@@ -2164,19 +2164,19 @@ static void dump_clos_config(int arg)
        isst_ctdp_display_information_end(outf);
 }
 
-static void get_clos_info_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
+static void get_clos_info_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
                                  void *arg4)
 {
        int enable, ret, prio_type;
 
-       ret = isst_clos_get_clos_information(cpu, &enable, &prio_type);
+       ret = isst_clos_get_clos_information(id, &enable, &prio_type);
        if (ret)
                isst_display_error_info_message(1, "isst_clos_get_info failed", 0, 0);
        else {
                int cp_state, cp_cap;
 
-               isst_read_pm_config(cpu, &cp_state, &cp_cap);
-               isst_clos_display_clos_information(cpu, outf, enable, prio_type,
+               isst_read_pm_config(id, &cp_state, &cp_cap);
+               isst_clos_display_clos_information(id, outf, enable, prio_type,
                                                   cp_state, cp_cap);
        }
 }
@@ -2201,25 +2201,22 @@ static void dump_clos_info(int arg)
 
 }
 
-static void set_clos_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
+static void set_clos_config_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
                                    void *arg4)
 {
        struct isst_clos_config clos_config;
        int ret;
 
-       clos_config.pkg_id = get_physical_package_id(cpu);
-       clos_config.die_id = get_physical_die_id(cpu);
-
        clos_config.epp = clos_epp;
        clos_config.clos_prop_prio = clos_prop_prio;
        clos_config.clos_min = clos_min;
        clos_config.clos_max = clos_max;
        clos_config.clos_desired = clos_desired;
-       ret = isst_set_clos(cpu, current_clos, &clos_config);
+       ret = isst_set_clos(id, current_clos, &clos_config);
        if (ret)
                isst_display_error_info_message(1, "isst_set_clos failed", 0, 0);
        else
-               isst_display_result(cpu, outf, "core-power", "config", ret);
+               isst_display_result(id, outf, "core-power", "config", ret);
 }
 
 static void set_clos_config(int arg)
@@ -2275,16 +2272,16 @@ static void set_clos_config(int arg)
        isst_ctdp_display_information_end(outf);
 }
 
-static void set_clos_assoc_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
+static void set_clos_assoc_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
                                   void *arg4)
 {
        int ret;
 
-       ret = isst_clos_associate(cpu, current_clos);
+       ret = isst_clos_associate(id, current_clos);
        if (ret)
                debug_printf("isst_clos_associate failed");
        else
-               isst_display_result(cpu, outf, "core-power", "assoc", ret);
+               isst_display_result(id, outf, "core-power", "assoc", ret);
 }
 
 static void set_clos_assoc(int arg)
@@ -2312,16 +2309,16 @@ static void set_clos_assoc(int arg)
        }
 }
 
-static void get_clos_assoc_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
+static void get_clos_assoc_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3,
                                   void *arg4)
 {
        int clos, ret;
 
-       ret = isst_clos_get_assoc_status(cpu, &clos);
+       ret = isst_clos_get_assoc_status(id, &clos);
        if (ret)
                isst_display_error_info_message(1, "isst_clos_get_assoc_status failed", 0, 0);
        else
-               isst_clos_display_assoc_information(cpu, outf, clos);
+               isst_clos_display_assoc_information(id, outf, clos);
 }
 
 static void get_clos_assoc(int arg)
@@ -2343,27 +2340,28 @@ static void get_clos_assoc(int arg)
        isst_ctdp_display_information_end(outf);
 }
 
-static void set_turbo_mode_for_cpu(int cpu, int status)
+static void set_turbo_mode_for_cpu(struct isst_id *id, int status)
 {
        int base_freq;
 
        if (status) {
-               base_freq = get_cpufreq_base_freq(cpu);
-               set_cpufreq_scaling_min_max(cpu, 1, base_freq);
+               base_freq = get_cpufreq_base_freq(id->cpu);
+               set_cpufreq_scaling_min_max(id->cpu, 1, base_freq);
        } else {
-               set_scaling_max_to_cpuinfo_max(cpu);
+               set_scaling_max_to_cpuinfo_max(id);
        }
 
        if (status) {
-               isst_display_result(cpu, outf, "turbo-mode", "enable", 0);
+               isst_display_result(id, outf, "turbo-mode", "enable", 0);
        } else {
-               isst_display_result(cpu, outf, "turbo-mode", "disable", 0);
+               isst_display_result(id, outf, "turbo-mode", "disable", 0);
        }
 }
 
 static void set_turbo_mode(int arg)
 {
        int i, enable = arg;
+       struct isst_id id;
 
        if (cmd_help) {
                if (enable)
@@ -2385,14 +2383,16 @@ static void set_turbo_mode(int arg)
                        online =
                                1; /* online entry for CPU 0 needs some special configs */
 
-               if (online)
-                       set_turbo_mode_for_cpu(i, enable);
+               if (online) {
+                       set_isst_id(&id, i);
+                       set_turbo_mode_for_cpu(&id, enable);
+               }
 
        }
        isst_ctdp_display_information_end(outf);
 }
 
-static void get_set_trl(int cpu, void *arg1, void *arg2, void *arg3,
+static void get_set_trl(struct isst_id *id, void *arg1, void *arg2, void *arg3,
                        void *arg4)
 {
        unsigned long long trl;
@@ -2405,16 +2405,16 @@ static void get_set_trl(int cpu, void *arg1, void *arg2, void *arg3,
        }
 
        if (set) {
-               ret = isst_set_trl(cpu, fact_trl);
-               isst_display_result(cpu, outf, "turbo-mode", "set-trl", ret);
+               ret = isst_set_trl(id, fact_trl);
+               isst_display_result(id, outf, "turbo-mode", "set-trl", ret);
                return;
        }
 
-       ret = isst_get_trl(cpu, &trl);
+       ret = isst_get_trl(id, &trl);
        if (ret)
-               isst_display_result(cpu, outf, "turbo-mode", "get-trl", ret);
+               isst_display_result(id, outf, "turbo-mode", "get-trl", ret);
        else
-               isst_trl_display_information(cpu, outf, trl);
+               isst_trl_display_information(id, outf, trl);
 }
 
 static void process_trl(int arg)
@@ -2754,9 +2754,6 @@ void process_command(int argc, char **argv,
                }
        }
 
-       if (!is_clx_n_platform())
-               create_cpu_map();
-
        i = 0;
        while (cmds[i].feature) {
                if (!strcmp(cmds[i].feature, feature) &&
@@ -2960,11 +2957,9 @@ static void cmdline(int argc, char **argv)
        if (force_cpus_online)
                force_all_cpus_online();
        store_cpu_topology();
-       set_cpu_present_cpu_mask();
-       set_cpu_target_cpu_mask();
+       create_cpu_map();
 
        if (oob_mode) {
-               create_cpu_map();
                if (debug_flag)
                        fprintf(stderr, "OOB mode is enabled in debug mode\n");
 
index 4431c8a..f701b45 100644 (file)
@@ -6,7 +6,7 @@
 
 #include "isst.h"
 
-int isst_write_pm_config(int cpu, int cp_state)
+int isst_write_pm_config(struct isst_id *id, int cp_state)
 {
        unsigned int req, resp;
        int ret;
@@ -16,27 +16,27 @@ int isst_write_pm_config(int cpu, int cp_state)
        else
                req = 0;
 
-       ret = isst_send_mbox_command(cpu, WRITE_PM_CONFIG, PM_FEATURE, 0, req,
+       ret = isst_send_mbox_command(id->cpu, WRITE_PM_CONFIG, PM_FEATURE, 0, req,
                                     &resp);
        if (ret)
                return ret;
 
-       debug_printf("cpu:%d WRITE_PM_CONFIG resp:%x\n", cpu, resp);
+       debug_printf("cpu:%d WRITE_PM_CONFIG resp:%x\n", id->cpu, resp);
 
        return 0;
 }
 
-int isst_read_pm_config(int cpu, int *cp_state, int *cp_cap)
+int isst_read_pm_config(struct isst_id *id, int *cp_state, int *cp_cap)
 {
        unsigned int resp;
        int ret;
 
-       ret = isst_send_mbox_command(cpu, READ_PM_CONFIG, PM_FEATURE, 0, 0,
+       ret = isst_send_mbox_command(id->cpu, READ_PM_CONFIG, PM_FEATURE, 0, 0,
                                     &resp);
        if (ret)
                return ret;
 
-       debug_printf("cpu:%d READ_PM_CONFIG resp:%x\n", cpu, resp);
+       debug_printf("cpu:%d READ_PM_CONFIG resp:%x\n", id->cpu, resp);
 
        *cp_state = resp & BIT(16);
        *cp_cap = resp & BIT(0) ? 1 : 0;
@@ -44,12 +44,12 @@ int isst_read_pm_config(int cpu, int *cp_state, int *cp_cap)
        return 0;
 }
 
-int isst_get_ctdp_levels(int cpu, struct isst_pkg_ctdp *pkg_dev)
+int isst_get_ctdp_levels(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev)
 {
        unsigned int resp;
        int ret;
 
-       ret = isst_send_mbox_command(cpu, CONFIG_TDP,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
                                     CONFIG_TDP_GET_LEVELS_INFO, 0, 0, &resp);
        if (ret) {
                pkg_dev->levels = 0;
@@ -60,7 +60,7 @@ int isst_get_ctdp_levels(int cpu, struct isst_pkg_ctdp *pkg_dev)
                return 0;
        }
 
-       debug_printf("cpu:%d CONFIG_TDP_GET_LEVELS_INFO resp:%x\n", cpu, resp);
+       debug_printf("cpu:%d CONFIG_TDP_GET_LEVELS_INFO resp:%x\n", id->cpu, resp);
 
        pkg_dev->version = resp & 0xff;
        pkg_dev->levels = (resp >> 8) & 0xff;
@@ -71,14 +71,14 @@ int isst_get_ctdp_levels(int cpu, struct isst_pkg_ctdp *pkg_dev)
        return 0;
 }
 
-int isst_get_ctdp_control(int cpu, int config_index,
+int isst_get_ctdp_control(struct isst_id *id, int config_index,
                          struct isst_pkg_ctdp_level_info *ctdp_level)
 {
        int cp_state, cp_cap;
        unsigned int resp;
        int ret;
 
-       ret = isst_send_mbox_command(cpu, CONFIG_TDP,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
                                     CONFIG_TDP_GET_TDP_CONTROL, 0,
                                     config_index, &resp);
        if (ret)
@@ -89,30 +89,30 @@ int isst_get_ctdp_control(int cpu, int config_index,
        ctdp_level->fact_enabled = !!(resp & BIT(16));
        ctdp_level->pbf_enabled = !!(resp & BIT(17));
 
-       ret = isst_read_pm_config(cpu, &cp_state, &cp_cap);
+       ret = isst_read_pm_config(id, &cp_state, &cp_cap);
        if (ret) {
-               debug_printf("cpu:%d pm_config is not supported \n", cpu);
+               debug_printf("cpu:%d pm_config is not supported\n", id->cpu);
        } else {
-               debug_printf("cpu:%d pm_config SST-CP state:%d cap:%d \n", cpu, cp_state, cp_cap);
+               debug_printf("cpu:%d pm_config SST-CP state:%d cap:%d\n", id->cpu, cp_state, cp_cap);
                ctdp_level->sst_cp_support = cp_cap;
                ctdp_level->sst_cp_enabled = cp_state;
        }
 
        debug_printf(
                "cpu:%d CONFIG_TDP_GET_TDP_CONTROL resp:%x fact_support:%d pbf_support: %d fact_enabled:%d pbf_enabled:%d\n",
-               cpu, resp, ctdp_level->fact_support, ctdp_level->pbf_support,
+               id->cpu, resp, ctdp_level->fact_support, ctdp_level->pbf_support,
                ctdp_level->fact_enabled, ctdp_level->pbf_enabled);
 
        return 0;
 }
 
-int isst_get_tdp_info(int cpu, int config_index,
+int isst_get_tdp_info(struct isst_id *id, int config_index,
                      struct isst_pkg_ctdp_level_info *ctdp_level)
 {
        unsigned int resp;
        int ret;
 
-       ret = isst_send_mbox_command(cpu, CONFIG_TDP, CONFIG_TDP_GET_TDP_INFO,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_GET_TDP_INFO,
                                     0, config_index, &resp);
        if (ret) {
                isst_display_error_info_message(1, "Invalid level, Can't get TDP information at level", 1, config_index);
@@ -124,18 +124,18 @@ int isst_get_tdp_info(int cpu, int config_index,
 
        debug_printf(
                "cpu:%d ctdp:%d CONFIG_TDP_GET_TDP_INFO resp:%x tdp_ratio:%d pkg_tdp:%d\n",
-               cpu, config_index, resp, ctdp_level->tdp_ratio,
+               id->cpu, config_index, resp, ctdp_level->tdp_ratio,
                ctdp_level->pkg_tdp);
        return 0;
 }
 
-int isst_get_pwr_info(int cpu, int config_index,
+int isst_get_pwr_info(struct isst_id *id, int config_index,
                      struct isst_pkg_ctdp_level_info *ctdp_level)
 {
        unsigned int resp;
        int ret;
 
-       ret = isst_send_mbox_command(cpu, CONFIG_TDP, CONFIG_TDP_GET_PWR_INFO,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_GET_PWR_INFO,
                                     0, config_index, &resp);
        if (ret)
                return ret;
@@ -145,18 +145,18 @@ int isst_get_pwr_info(int cpu, int config_index,
 
        debug_printf(
                "cpu:%d ctdp:%d CONFIG_TDP_GET_PWR_INFO resp:%x pkg_max_power:%d pkg_min_power:%d\n",
-               cpu, config_index, resp, ctdp_level->pkg_max_power,
+               id->cpu, config_index, resp, ctdp_level->pkg_max_power,
                ctdp_level->pkg_min_power);
 
        return 0;
 }
 
-void isst_get_uncore_p0_p1_info(int cpu, int config_index,
+void isst_get_uncore_p0_p1_info(struct isst_id *id, int config_index,
                                struct isst_pkg_ctdp_level_info *ctdp_level)
 {
        unsigned int resp;
        int ret;
-       ret = isst_send_mbox_command(cpu, CONFIG_TDP,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
                                     CONFIG_TDP_GET_UNCORE_P0_P1_INFO, 0,
                                     config_index, &resp);
        if (ret) {
@@ -169,16 +169,16 @@ void isst_get_uncore_p0_p1_info(int cpu, int config_index,
        ctdp_level->uncore_p1 = (resp & GENMASK(15, 8)) >> 8;
        debug_printf(
                "cpu:%d ctdp:%d CONFIG_TDP_GET_UNCORE_P0_P1_INFO resp:%x uncore p0:%d uncore p1:%d\n",
-               cpu, config_index, resp, ctdp_level->uncore_p0,
+               id->cpu, config_index, resp, ctdp_level->uncore_p0,
                ctdp_level->uncore_p1);
 }
 
-void isst_get_p1_info(int cpu, int config_index,
+void isst_get_p1_info(struct isst_id *id, int config_index,
                      struct isst_pkg_ctdp_level_info *ctdp_level)
 {
        unsigned int resp;
        int ret;
-       ret = isst_send_mbox_command(cpu, CONFIG_TDP, CONFIG_TDP_GET_P1_INFO, 0,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_GET_P1_INFO, 0,
                                     config_index, &resp);
        if (ret) {
                ctdp_level->sse_p1 = 0;
@@ -192,17 +192,17 @@ void isst_get_p1_info(int cpu, int config_index,
        ctdp_level->avx512_p1 = (resp & GENMASK(23, 16)) >> 16;
        debug_printf(
                "cpu:%d ctdp:%d CONFIG_TDP_GET_P1_INFO resp:%x sse_p1:%d avx2_p1:%d avx512_p1:%d\n",
-               cpu, config_index, resp, ctdp_level->sse_p1,
+               id->cpu, config_index, resp, ctdp_level->sse_p1,
                ctdp_level->avx2_p1, ctdp_level->avx512_p1);
 }
 
-void isst_get_uncore_mem_freq(int cpu, int config_index,
+void isst_get_uncore_mem_freq(struct isst_id *id, int config_index,
                              struct isst_pkg_ctdp_level_info *ctdp_level)
 {
        unsigned int resp;
        int ret;
 
-       ret = isst_send_mbox_command(cpu, CONFIG_TDP, CONFIG_TDP_GET_MEM_FREQ,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_GET_MEM_FREQ,
                                     0, config_index, &resp);
        if (ret) {
                ctdp_level->mem_freq = 0;
@@ -226,16 +226,16 @@ void isst_get_uncore_mem_freq(int cpu, int config_index,
        }
        debug_printf(
                "cpu:%d ctdp:%d CONFIG_TDP_GET_MEM_FREQ resp:%x uncore mem_freq:%d\n",
-               cpu, config_index, resp, ctdp_level->mem_freq);
+               id->cpu, config_index, resp, ctdp_level->mem_freq);
 }
 
-int isst_get_tjmax_info(int cpu, int config_index,
+int isst_get_tjmax_info(struct isst_id *id, int config_index,
                        struct isst_pkg_ctdp_level_info *ctdp_level)
 {
        unsigned int resp;
        int ret;
 
-       ret = isst_send_mbox_command(cpu, CONFIG_TDP, CONFIG_TDP_GET_TJMAX_INFO,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_GET_TJMAX_INFO,
                                     0, config_index, &resp);
        if (ret)
                return ret;
@@ -244,12 +244,12 @@ int isst_get_tjmax_info(int cpu, int config_index,
 
        debug_printf(
                "cpu:%d ctdp:%d CONFIG_TDP_GET_TJMAX_INFO resp:%x t_proc_hot:%d\n",
-               cpu, config_index, resp, ctdp_level->t_proc_hot);
+               id->cpu, config_index, resp, ctdp_level->t_proc_hot);
 
        return 0;
 }
 
-int isst_get_coremask_info(int cpu, int config_index,
+int isst_get_coremask_info(struct isst_id *id, int config_index,
                           struct isst_pkg_ctdp_level_info *ctdp_level)
 {
        unsigned int resp;
@@ -260,7 +260,7 @@ int isst_get_coremask_info(int cpu, int config_index,
                unsigned long long mask;
                int cpu_count = 0;
 
-               ret = isst_send_mbox_command(cpu, CONFIG_TDP,
+               ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
                                             CONFIG_TDP_GET_CORE_MASK, 0,
                                             (i << 8) | config_index, &resp);
                if (ret)
@@ -268,27 +268,27 @@ int isst_get_coremask_info(int cpu, int config_index,
 
                debug_printf(
                        "cpu:%d ctdp:%d mask:%d CONFIG_TDP_GET_CORE_MASK resp:%x\n",
-                       cpu, config_index, i, resp);
+                       id->cpu, config_index, i, resp);
 
                mask = (unsigned long long)resp << (32 * i);
-               set_cpu_mask_from_punit_coremask(cpu, mask,
+               set_cpu_mask_from_punit_coremask(id, mask,
                                                 ctdp_level->core_cpumask_size,
                                                 ctdp_level->core_cpumask,
                                                 &cpu_count);
                ctdp_level->cpu_count += cpu_count;
-               debug_printf("cpu:%d ctdp:%d mask:%d cpu count:%d\n", cpu,
+               debug_printf("cpu:%d ctdp:%d mask:%d cpu count:%d\n", id->cpu,
                             config_index, i, ctdp_level->cpu_count);
        }
 
        return 0;
 }
 
-int isst_get_get_trl_from_msr(int cpu, int *trl)
+int isst_get_get_trl_from_msr(struct isst_id *id, int *trl)
 {
        unsigned long long msr_trl;
        int ret;
 
-       ret = isst_send_msr_command(cpu, 0x1AD, 0, &msr_trl);
+       ret = isst_send_msr_command(id->cpu, 0x1AD, 0, &msr_trl);
        if (ret)
                return ret;
 
@@ -304,13 +304,13 @@ int isst_get_get_trl_from_msr(int cpu, int *trl)
        return 0;
 }
 
-int isst_get_get_trl(int cpu, int level, int avx_level, int *trl)
+int isst_get_get_trl(struct isst_id *id, int level, int avx_level, int *trl)
 {
        unsigned int req, resp;
        int ret;
 
        req = level | (avx_level << 16);
-       ret = isst_send_mbox_command(cpu, CONFIG_TDP,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
                                     CONFIG_TDP_GET_TURBO_LIMIT_RATIOS, 0, req,
                                     &resp);
        if (ret)
@@ -318,7 +318,7 @@ int isst_get_get_trl(int cpu, int level, int avx_level, int *trl)
 
        debug_printf(
                "cpu:%d CONFIG_TDP_GET_TURBO_LIMIT_RATIOS req:%x resp:%x\n",
-               cpu, req, resp);
+               id->cpu, req, resp);
 
        trl[0] = resp & GENMASK(7, 0);
        trl[1] = (resp & GENMASK(15, 8)) >> 8;
@@ -326,13 +326,13 @@ int isst_get_get_trl(int cpu, int level, int avx_level, int *trl)
        trl[3] = (resp & GENMASK(31, 24)) >> 24;
 
        req = level | BIT(8) | (avx_level << 16);
-       ret = isst_send_mbox_command(cpu, CONFIG_TDP,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
                                     CONFIG_TDP_GET_TURBO_LIMIT_RATIOS, 0, req,
                                     &resp);
        if (ret)
                return ret;
 
-       debug_printf("cpu:%d CONFIG_TDP_GET_TURBO_LIMIT req:%x resp:%x\n", cpu,
+       debug_printf("cpu:%d CONFIG_TDP_GET_TURBO_LIMIT req:%x resp:%x\n", id->cpu,
                     req, resp);
 
        trl[4] = resp & GENMASK(7, 0);
@@ -343,61 +343,37 @@ int isst_get_get_trl(int cpu, int level, int avx_level, int *trl)
        return 0;
 }
 
-int isst_get_trl_bucket_info(int cpu, unsigned long long *buckets_info)
+int isst_get_trl_bucket_info(struct isst_id *id, unsigned long long *buckets_info)
 {
        int ret;
 
-       debug_printf("cpu:%d bucket info via MSR\n", cpu);
+       debug_printf("cpu:%d bucket info via MSR\n", id->cpu);
 
        *buckets_info = 0;
 
-       ret = isst_send_msr_command(cpu, 0x1ae, 0, buckets_info);
+       ret = isst_send_msr_command(id->cpu, 0x1ae, 0, buckets_info);
        if (ret)
                return ret;
 
-       debug_printf("cpu:%d bucket info via MSR successful 0x%llx\n", cpu,
+       debug_printf("cpu:%d bucket info via MSR successful 0x%llx\n", id->cpu,
                     *buckets_info);
 
        return 0;
 }
 
-int isst_set_tdp_level_msr(int cpu, int tdp_level)
-{
-       unsigned long long level = tdp_level;
-       int ret;
-
-       debug_printf("cpu: tdp_level via MSR %d\n", cpu, tdp_level);
-
-       if (isst_get_config_tdp_lock_status(cpu)) {
-               isst_display_error_info_message(1, "tdp_locked", 0, 0);
-               return -1;
-       }
-
-       if (tdp_level > 2)
-               return -1; /* invalid value */
-
-       ret = isst_send_msr_command(cpu, 0x64b, 1, &level);
-       if (ret)
-               return ret;
-
-       debug_printf("cpu: tdp_level via MSR successful %d\n", cpu, tdp_level);
-
-       return 0;
-}
-
-int isst_set_tdp_level(int cpu, int tdp_level)
+int isst_set_tdp_level(struct isst_id *id, int tdp_level)
 {
        unsigned int resp;
        int ret;
 
 
-       if (isst_get_config_tdp_lock_status(cpu)) {
+       if (isst_get_config_tdp_lock_status(id)) {
                isst_display_error_info_message(1, "TDP is locked", 0, 0);
                return -1;
 
        }
 
-       ret = isst_send_mbox_command(cpu, CONFIG_TDP, CONFIG_TDP_SET_LEVEL, 0,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_SET_LEVEL, 0,
                                     tdp_level, &resp);
        if (ret) {
                isst_display_error_info_message(1, "Set TDP level failed for level", 1, tdp_level);
@@ -407,14 +383,14 @@ int isst_set_tdp_level(int cpu, int tdp_level)
        return 0;
 }
 
-int isst_get_pbf_info(int cpu, int level, struct isst_pbf_info *pbf_info)
+int isst_get_pbf_info(struct isst_id *id, int level, struct isst_pbf_info *pbf_info)
 {
        struct isst_pkg_ctdp_level_info ctdp_level;
        struct isst_pkg_ctdp pkg_dev;
        int i, ret, max_punit_core, max_mask_index;
        unsigned int req, resp;
 
-       ret = isst_get_ctdp_levels(cpu, &pkg_dev);
+       ret = isst_get_ctdp_levels(id, &pkg_dev);
        if (ret) {
                isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);
                return ret;
@@ -425,7 +401,7 @@ int isst_get_pbf_info(int cpu, int level, struct isst_pbf_info *pbf_info)
                return -1;
        }
 
-       ret = isst_get_ctdp_control(cpu, level, &ctdp_level);
+       ret = isst_get_ctdp_control(id, level, &ctdp_level);
        if (ret)
                return ret;
 
@@ -436,14 +412,14 @@ int isst_get_pbf_info(int cpu, int level, struct isst_pbf_info *pbf_info)
 
        pbf_info->core_cpumask_size = alloc_cpu_set(&pbf_info->core_cpumask);
 
-       max_punit_core = get_max_punit_core_id(get_physical_package_id(cpu), get_physical_die_id(cpu));
+       max_punit_core = get_max_punit_core_id(id);
        max_mask_index = max_punit_core > 32 ? 2 : 1;
 
        for (i = 0; i < max_mask_index; ++i) {
                unsigned long long mask;
                int count;
 
-               ret = isst_send_mbox_command(cpu, CONFIG_TDP,
+               ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
                                             CONFIG_TDP_PBF_GET_CORE_MASK_INFO,
                                             0, (i << 8) | level, &resp);
                if (ret)
@@ -451,23 +427,23 @@ int isst_get_pbf_info(int cpu, int level, struct isst_pbf_info *pbf_info)
 
                debug_printf(
                        "cpu:%d CONFIG_TDP_PBF_GET_CORE_MASK_INFO resp:%x\n",
-                       cpu, resp);
+                       id->cpu, resp);
 
                mask = (unsigned long long)resp << (32 * i);
-               set_cpu_mask_from_punit_coremask(cpu, mask,
+               set_cpu_mask_from_punit_coremask(id, mask,
                                                 pbf_info->core_cpumask_size,
                                                 pbf_info->core_cpumask,
                                                 &count);
        }
 
        req = level;
-       ret = isst_send_mbox_command(cpu, CONFIG_TDP,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
                                     CONFIG_TDP_PBF_GET_P1HI_P1LO_INFO, 0, req,
                                     &resp);
        if (ret)
                return ret;
 
-       debug_printf("cpu:%d CONFIG_TDP_PBF_GET_P1HI_P1LO_INFO resp:%x\n", cpu,
+       debug_printf("cpu:%d CONFIG_TDP_PBF_GET_P1HI_P1LO_INFO resp:%x\n", id->cpu,
                     resp);
 
        pbf_info->p1_low = resp & 0xff;
@@ -475,21 +451,21 @@ int isst_get_pbf_info(int cpu, int level, struct isst_pbf_info *pbf_info)
 
        req = level;
        ret = isst_send_mbox_command(
-               cpu, CONFIG_TDP, CONFIG_TDP_PBF_GET_TDP_INFO, 0, req, &resp);
+               id->cpu, CONFIG_TDP, CONFIG_TDP_PBF_GET_TDP_INFO, 0, req, &resp);
        if (ret)
                return ret;
 
-       debug_printf("cpu:%d CONFIG_TDP_PBF_GET_TDP_INFO resp:%x\n", cpu, resp);
+       debug_printf("cpu:%d CONFIG_TDP_PBF_GET_TDP_INFO resp:%x\n", id->cpu, resp);
 
        pbf_info->tdp = resp & 0xffff;
 
        req = level;
        ret = isst_send_mbox_command(
-               cpu, CONFIG_TDP, CONFIG_TDP_PBF_GET_TJ_MAX_INFO, 0, req, &resp);
+               id->cpu, CONFIG_TDP, CONFIG_TDP_PBF_GET_TJ_MAX_INFO, 0, req, &resp);
        if (ret)
                return ret;
 
-       debug_printf("cpu:%d CONFIG_TDP_PBF_GET_TJ_MAX_INFO resp:%x\n", cpu,
+       debug_printf("cpu:%d CONFIG_TDP_PBF_GET_TJ_MAX_INFO resp:%x\n", id->cpu,
                     resp);
        pbf_info->t_control = (resp >> 8) & 0xff;
        pbf_info->t_prochot = resp & 0xff;
@@ -502,7 +478,7 @@ void isst_get_pbf_info_complete(struct isst_pbf_info *pbf_info)
        free_cpu_set(pbf_info->core_cpumask);
 }
 
-int isst_set_pbf_fact_status(int cpu, int pbf, int enable)
+int isst_set_pbf_fact_status(struct isst_id *id, int pbf, int enable)
 {
        struct isst_pkg_ctdp pkg_dev;
        struct isst_pkg_ctdp_level_info ctdp_level;
@@ -510,13 +486,13 @@ int isst_set_pbf_fact_status(int cpu, int pbf, int enable)
        unsigned int req = 0, resp;
        int ret;
 
-       ret = isst_get_ctdp_levels(cpu, &pkg_dev);
+       ret = isst_get_ctdp_levels(id, &pkg_dev);
        if (ret)
-               debug_printf("cpu:%d No support for dynamic ISST\n", cpu);
+               debug_printf("cpu:%d No support for dynamic ISST\n", id->cpu);
 
        current_level = pkg_dev.current_level;
 
-       ret = isst_get_ctdp_control(cpu, current_level, &ctdp_level);
+       ret = isst_get_ctdp_control(id, current_level, &ctdp_level);
        if (ret)
                return ret;
 
@@ -542,18 +518,18 @@ int isst_set_pbf_fact_status(int cpu, int pbf, int enable)
                        req &= ~BIT(16);
        }
 
-       ret = isst_send_mbox_command(cpu, CONFIG_TDP,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
                                     CONFIG_TDP_SET_TDP_CONTROL, 0, req, &resp);
        if (ret)
                return ret;
 
        debug_printf("cpu:%d CONFIG_TDP_SET_TDP_CONTROL pbf/fact:%d req:%x\n",
-                    cpu, pbf, req);
+                    id->cpu, pbf, req);
 
        return 0;
 }
 
-int isst_get_fact_bucket_info(int cpu, int level,
+int isst_get_fact_bucket_info(struct isst_id *id, int level,
                              struct isst_fact_bucket_info *bucket_info)
 {
        unsigned int resp;
@@ -563,7 +539,7 @@ int isst_get_fact_bucket_info(int cpu, int level,
                int j;
 
                ret = isst_send_mbox_command(
-                       cpu, CONFIG_TDP,
+                       id->cpu, CONFIG_TDP,
                        CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_NUMCORES, 0,
                        (i << 8) | level, &resp);
                if (ret)
@@ -571,7 +547,7 @@ int isst_get_fact_bucket_info(int cpu, int level,
 
                debug_printf(
                        "cpu:%d CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_NUMCORES index:%d level:%d resp:%x\n",
-                       cpu, i, level, resp);
+                       id->cpu, i, level, resp);
 
                for (j = 0; j < 4; ++j) {
                        bucket_info[j + (i * 4)].high_priority_cores_count =
@@ -584,7 +560,7 @@ int isst_get_fact_bucket_info(int cpu, int level,
                        int j;
 
                        ret = isst_send_mbox_command(
-                               cpu, CONFIG_TDP,
+                               id->cpu, CONFIG_TDP,
                                CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_RATIOS, 0,
                                (k << 16) | (i << 8) | level, &resp);
                        if (ret)
@@ -592,7 +568,7 @@ int isst_get_fact_bucket_info(int cpu, int level,
 
                        debug_printf(
                                "cpu:%d CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_RATIOS index:%d level:%d avx:%d resp:%x\n",
-                               cpu, i, level, k, resp);
+                               id->cpu, i, level, k, resp);
 
                        for (j = 0; j < 4; ++j) {
                                switch (k) {
@@ -618,14 +594,14 @@ int isst_get_fact_bucket_info(int cpu, int level,
        return 0;
 }
 
-int isst_get_fact_info(int cpu, int level, int fact_bucket, struct isst_fact_info *fact_info)
+int isst_get_fact_info(struct isst_id *id, int level, int fact_bucket, struct isst_fact_info *fact_info)
 {
        struct isst_pkg_ctdp_level_info ctdp_level;
        struct isst_pkg_ctdp pkg_dev;
        unsigned int resp;
        int j, ret, print;
 
-       ret = isst_get_ctdp_levels(cpu, &pkg_dev);
+       ret = isst_get_ctdp_levels(id, &pkg_dev);
        if (ret) {
                isst_display_error_info_message(1, "Failed to get number of levels", 0, 0);
                return ret;
@@ -636,7 +612,7 @@ int isst_get_fact_info(int cpu, int level, int fact_bucket, struct isst_fact_inf
                return -1;
        }
 
-       ret = isst_get_ctdp_control(cpu, level, &ctdp_level);
+       ret = isst_get_ctdp_control(id, level, &ctdp_level);
        if (ret)
                return ret;
 
@@ -645,20 +621,20 @@ int isst_get_fact_info(int cpu, int level, int fact_bucket, struct isst_fact_inf
                return -1;
        }
 
-       ret = isst_send_mbox_command(cpu, CONFIG_TDP,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_TDP,
                                     CONFIG_TDP_GET_FACT_LP_CLIPPING_RATIO, 0,
                                     level, &resp);
        if (ret)
                return ret;
 
        debug_printf("cpu:%d CONFIG_TDP_GET_FACT_LP_CLIPPING_RATIO resp:%x\n",
-                    cpu, resp);
+                    id->cpu, resp);
 
        fact_info->lp_clipping_ratio_license_sse = resp & 0xff;
        fact_info->lp_clipping_ratio_license_avx2 = (resp >> 8) & 0xff;
        fact_info->lp_clipping_ratio_license_avx512 = (resp >> 16) & 0xff;
 
-       ret = isst_get_fact_bucket_info(cpu, level, fact_info->bucket_info);
+       ret = isst_get_fact_bucket_info(id, level, fact_info->bucket_info);
        if (ret)
                return ret;
 
@@ -680,32 +656,32 @@ int isst_get_fact_info(int cpu, int level, int fact_bucket, struct isst_fact_inf
        return 0;
 }
 
-int isst_get_trl(int cpu, unsigned long long *trl)
+int isst_get_trl(struct isst_id *id, unsigned long long *trl)
 {
        int ret;
 
-       ret = isst_send_msr_command(cpu, 0x1AD, 0, trl);
+       ret = isst_send_msr_command(id->cpu, 0x1AD, 0, trl);
        if (ret)
                return ret;
 
        return 0;
 }
 
-int isst_set_trl(int cpu, unsigned long long trl)
+int isst_set_trl(struct isst_id *id, unsigned long long trl)
 {
        int ret;
 
        if (!trl)
                trl = 0xFFFFFFFFFFFFFFFFULL;
 
-       ret = isst_send_msr_command(cpu, 0x1AD, 1, &trl);
+       ret = isst_send_msr_command(id->cpu, 0x1AD, 1, &trl);
        if (ret)
                return ret;
 
        return 0;
 }
 
-int isst_set_trl_from_current_tdp(int cpu, unsigned long long trl)
+int isst_set_trl_from_current_tdp(struct isst_id *id, unsigned long long trl)
 {
        unsigned long long msr_trl;
        int ret;
@@ -717,11 +693,11 @@ int isst_set_trl_from_current_tdp(int cpu, unsigned long long trl)
                int trl[8];
                int i;
 
-               ret = isst_get_ctdp_levels(cpu, &pkg_dev);
+               ret = isst_get_ctdp_levels(id, &pkg_dev);
                if (ret)
                        return ret;
 
-               ret = isst_get_get_trl(cpu, pkg_dev.current_level, 0, trl);
+               ret = isst_get_get_trl(id, pkg_dev.current_level, 0, trl);
                if (ret)
                        return ret;
 
@@ -732,7 +708,7 @@ int isst_set_trl_from_current_tdp(int cpu, unsigned long long trl)
                        msr_trl |= (_trl << (i * 8));
                }
        }
-       ret = isst_send_msr_command(cpu, 0x1AD, 1, &msr_trl);
+       ret = isst_send_msr_command(id->cpu, 0x1AD, 1, &msr_trl);
        if (ret)
                return ret;
 
@@ -740,12 +716,12 @@ int isst_set_trl_from_current_tdp(int cpu, unsigned long long trl)
 }
 
 /* Return 1 if locked */
-int isst_get_config_tdp_lock_status(int cpu)
+int isst_get_config_tdp_lock_status(struct isst_id *id)
 {
        unsigned long long tdp_control = 0;
        int ret;
 
-       ret = isst_send_msr_command(cpu, 0x64b, 0, &tdp_control);
+       ret = isst_send_msr_command(id->cpu, 0x64b, 0, &tdp_control);
        if (ret)
                return ret;
 
@@ -754,7 +730,7 @@ int isst_get_config_tdp_lock_status(int cpu)
        return ret;
 }
 
-void isst_get_process_ctdp_complete(int cpu, struct isst_pkg_ctdp *pkg_dev)
+void isst_get_process_ctdp_complete(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev)
 {
        int i;
 
@@ -771,19 +747,19 @@ void isst_get_process_ctdp_complete(int cpu, struct isst_pkg_ctdp *pkg_dev)
        }
 }
 
-int isst_get_process_ctdp(int cpu, int tdp_level, struct isst_pkg_ctdp *pkg_dev)
+int isst_get_process_ctdp(struct isst_id *id, int tdp_level, struct isst_pkg_ctdp *pkg_dev)
 {
        int i, ret, valid = 0;
 
        if (pkg_dev->processed)
                return 0;
 
-       ret = isst_get_ctdp_levels(cpu, pkg_dev);
+       ret = isst_get_ctdp_levels(id, pkg_dev);
        if (ret)
                return ret;
 
        debug_printf("cpu: %d ctdp enable:%d current level: %d levels:%d\n",
-                    cpu, pkg_dev->enabled, pkg_dev->current_level,
+                    id->cpu, pkg_dev->enabled, pkg_dev->current_level,
                     pkg_dev->levels);
 
        if (tdp_level != 0xff && tdp_level > pkg_dev->levels) {
@@ -800,16 +776,16 @@ int isst_get_process_ctdp(int cpu, int tdp_level, struct isst_pkg_ctdp *pkg_dev)
                if (tdp_level != 0xff && i != tdp_level)
                        continue;
 
-               debug_printf("cpu:%d Get Information for TDP level:%d\n", cpu,
+               debug_printf("cpu:%d Get Information for TDP level:%d\n", id->cpu,
                             i);
                ctdp_level = &pkg_dev->ctdp_level[i];
 
                ctdp_level->level = i;
-               ctdp_level->control_cpu = cpu;
-               ctdp_level->pkg_id = get_physical_package_id(cpu);
-               ctdp_level->die_id = get_physical_die_id(cpu);
+               ctdp_level->control_cpu = id->cpu;
+               ctdp_level->pkg_id = id->pkg;
+               ctdp_level->die_id = id->die;
 
-               ret = isst_get_ctdp_control(cpu, i, ctdp_level);
+               ret = isst_get_ctdp_control(id, i, ctdp_level);
                if (ret)
                        continue;
 
@@ -818,13 +794,13 @@ int isst_get_process_ctdp(int cpu, int tdp_level, struct isst_pkg_ctdp *pkg_dev)
                ctdp_level->processed = 1;
 
                if (ctdp_level->pbf_support) {
-                       ret = isst_get_pbf_info(cpu, i, &ctdp_level->pbf_info);
+                       ret = isst_get_pbf_info(id, i, &ctdp_level->pbf_info);
                        if (!ret)
                                ctdp_level->pbf_found = 1;
                }
 
                if (ctdp_level->fact_support) {
-                       ret = isst_get_fact_info(cpu, i, 0xff,
+                       ret = isst_get_fact_info(id, i, 0xff,
                                                 &ctdp_level->fact_info);
                        if (ret)
                                return ret;
@@ -833,76 +809,76 @@ int isst_get_process_ctdp(int cpu, int tdp_level, struct isst_pkg_ctdp *pkg_dev)
                if (!pkg_dev->enabled && is_skx_based_platform()) {
                        int freq;
 
-                       freq = get_cpufreq_base_freq(cpu);
+                       freq = get_cpufreq_base_freq(id->cpu);
                        if (freq > 0) {
                                ctdp_level->sse_p1 = freq / 100000;
                                ctdp_level->tdp_ratio = ctdp_level->sse_p1;
                        }
 
-                       isst_get_get_trl_from_msr(cpu, ctdp_level->trl_sse_active_cores);
-                       isst_get_trl_bucket_info(cpu, &ctdp_level->buckets_info);
+                       isst_get_get_trl_from_msr(id, ctdp_level->trl_sse_active_cores);
+                       isst_get_trl_bucket_info(id, &ctdp_level->buckets_info);
                        continue;
                }
 
-               ret = isst_get_tdp_info(cpu, i, ctdp_level);
+               ret = isst_get_tdp_info(id, i, ctdp_level);
                if (ret)
                        return ret;
 
-               ret = isst_get_pwr_info(cpu, i, ctdp_level);
+               ret = isst_get_pwr_info(id, i, ctdp_level);
                if (ret)
                        return ret;
 
-               ret = isst_get_tjmax_info(cpu, i, ctdp_level);
+               ret = isst_get_tjmax_info(id, i, ctdp_level);
                if (ret)
                        return ret;
 
                ctdp_level->core_cpumask_size =
                        alloc_cpu_set(&ctdp_level->core_cpumask);
-               ret = isst_get_coremask_info(cpu, i, ctdp_level);
+               ret = isst_get_coremask_info(id, i, ctdp_level);
                if (ret)
                        return ret;
 
-               ret = isst_get_trl_bucket_info(cpu, &ctdp_level->buckets_info);
+               ret = isst_get_trl_bucket_info(id, &ctdp_level->buckets_info);
                if (ret)
                        return ret;
 
-               ret = isst_get_get_trl(cpu, i, 0,
+               ret = isst_get_get_trl(id, i, 0,
                                       ctdp_level->trl_sse_active_cores);
                if (ret)
                        return ret;
 
-               ret = isst_get_get_trl(cpu, i, 1,
+               ret = isst_get_get_trl(id, i, 1,
                                       ctdp_level->trl_avx_active_cores);
                if (ret)
                        return ret;
 
-               ret = isst_get_get_trl(cpu, i, 2,
+               ret = isst_get_get_trl(id, i, 2,
                                       ctdp_level->trl_avx_512_active_cores);
                if (ret)
                        return ret;
 
-               isst_get_uncore_p0_p1_info(cpu, i, ctdp_level);
-               isst_get_p1_info(cpu, i, ctdp_level);
-               isst_get_uncore_mem_freq(cpu, i, ctdp_level);
+               isst_get_uncore_p0_p1_info(id, i, ctdp_level);
+               isst_get_p1_info(id, i, ctdp_level);
+               isst_get_uncore_mem_freq(id, i, ctdp_level);
        }
 
        if (!valid)
-               isst_display_error_info_message(0, "Invalid level, Can't get TDP control information at specified levels on cpu", 1, cpu);
+               isst_display_error_info_message(0, "Invalid level, Can't get TDP control information at specified levels on cpu", 1, id->cpu);
 
        return 0;
 }
 
-int isst_clos_get_clos_information(int cpu, int *enable, int *type)
+int isst_clos_get_clos_information(struct isst_id *id, int *enable, int *type)
 {
        unsigned int resp;
        int ret;
 
-       ret = isst_send_mbox_command(cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG, 0, 0,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG, 0, 0,
                                     &resp);
        if (ret)
                return ret;
 
-       debug_printf("cpu:%d CLOS_PM_QOS_CONFIG resp:%x\n", cpu, resp);
+       debug_printf("cpu:%d CLOS_PM_QOS_CONFIG resp:%x\n", id->cpu, resp);
 
        if (resp & BIT(1))
                *enable = 1;
@@ -917,7 +893,7 @@ int isst_clos_get_clos_information(int cpu, int *enable, int *type)
        return 0;
 }
 
-int isst_pm_qos_config(int cpu, int enable_clos, int priority_type)
+int isst_pm_qos_config(struct isst_id *id, int enable_clos, int priority_type)
 {
        unsigned int req, resp;
        int ret;
@@ -926,13 +902,13 @@ int isst_pm_qos_config(int cpu, int enable_clos, int priority_type)
                struct isst_pkg_ctdp pkg_dev;
                struct isst_pkg_ctdp_level_info ctdp_level;
 
-               ret = isst_get_ctdp_levels(cpu, &pkg_dev);
+               ret = isst_get_ctdp_levels(id, &pkg_dev);
                if (ret) {
                        debug_printf("isst_get_ctdp_levels\n");
                        return ret;
                }
 
-               ret = isst_get_ctdp_control(cpu, pkg_dev.current_level,
+               ret = isst_get_ctdp_control(id, pkg_dev.current_level,
                                            &ctdp_level);
                if (ret)
                        return ret;
@@ -941,23 +917,23 @@ int isst_pm_qos_config(int cpu, int enable_clos, int priority_type)
                        isst_display_error_info_message(1, "Ignoring request, turbo-freq feature is still enabled", 0, 0);
                        return -EINVAL;
                }
-               ret = isst_write_pm_config(cpu, 0);
+               ret = isst_write_pm_config(id, 0);
                if (ret)
                        isst_display_error_info_message(0, "WRITE_PM_CONFIG command failed, ignoring error", 0, 0);
        } else {
-               ret = isst_write_pm_config(cpu, 1);
+               ret = isst_write_pm_config(id, 1);
                if (ret)
                        isst_display_error_info_message(0, "WRITE_PM_CONFIG command failed, ignoring error", 0, 0);
        }
 
-       ret = isst_send_mbox_command(cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG, 0, 0,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG, 0, 0,
                                     &resp);
        if (ret) {
                isst_display_error_info_message(1, "CLOS_PM_QOS_CONFIG command failed", 0, 0);
                return ret;
        }
 
-       debug_printf("cpu:%d CLOS_PM_QOS_CONFIG resp:%x\n", cpu, resp);
+       debug_printf("cpu:%d CLOS_PM_QOS_CONFIG resp:%x\n", id->cpu, resp);
 
        req = resp;
 
@@ -974,30 +950,27 @@ int isst_pm_qos_config(int cpu, int enable_clos, int priority_type)
        else
                req = req & ~BIT(2);
 
-       ret = isst_send_mbox_command(cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG,
                                     BIT(MBOX_CMD_WRITE_BIT), req, &resp);
        if (ret)
                return ret;
 
-       debug_printf("cpu:%d CLOS_PM_QOS_CONFIG priority type:%d req:%x\n", cpu,
+       debug_printf("cpu:%d CLOS_PM_QOS_CONFIG priority type:%d req:%x\n", id->cpu,
                     priority_type, req);
 
        return 0;
 }
 
-int isst_pm_get_clos(int cpu, int clos, struct isst_clos_config *clos_config)
+int isst_pm_get_clos(struct isst_id *id, int clos, struct isst_clos_config *clos_config)
 {
        unsigned int resp;
        int ret;
 
-       ret = isst_send_mbox_command(cpu, CONFIG_CLOS, CLOS_PM_CLOS, clos, 0,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PM_CLOS, clos, 0,
                                     &resp);
        if (ret)
                return ret;
 
-       clos_config->pkg_id = get_physical_package_id(cpu);
-       clos_config->die_id = get_physical_die_id(cpu);
-
        clos_config->epp = resp & 0x0f;
        clos_config->clos_prop_prio = (resp >> 4) & 0x0f;
        clos_config->clos_min = (resp >> 8) & 0xff;
@@ -1007,7 +980,7 @@ int isst_pm_get_clos(int cpu, int clos, struct isst_clos_config *clos_config)
        return 0;
 }
 
-int isst_set_clos(int cpu, int clos, struct isst_clos_config *clos_config)
+int isst_set_clos(struct isst_id *id, int clos, struct isst_clos_config *clos_config)
 {
        unsigned int req, resp;
        unsigned int param;
@@ -1021,53 +994,53 @@ int isst_set_clos(int cpu, int clos, struct isst_clos_config *clos_config)
 
        param = BIT(MBOX_CMD_WRITE_BIT) | clos;
 
-       ret = isst_send_mbox_command(cpu, CONFIG_CLOS, CLOS_PM_CLOS, param, req,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PM_CLOS, param, req,
                                     &resp);
        if (ret)
                return ret;
 
-       debug_printf("cpu:%d CLOS_PM_CLOS param:%x req:%x\n", cpu, param, req);
+       debug_printf("cpu:%d CLOS_PM_CLOS param:%x req:%x\n", id->cpu, param, req);
 
        return 0;
 }
 
-int isst_clos_get_assoc_status(int cpu, int *clos_id)
+int isst_clos_get_assoc_status(struct isst_id *id, int *clos_id)
 {
        unsigned int resp;
        unsigned int param;
        int core_id, ret;
 
-       core_id = find_phy_core_num(cpu);
+       core_id = find_phy_core_num(id->cpu);
        param = core_id;
 
-       ret = isst_send_mbox_command(cpu, CONFIG_CLOS, CLOS_PQR_ASSOC, param, 0,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PQR_ASSOC, param, 0,
                                     &resp);
        if (ret)
                return ret;
 
-       debug_printf("cpu:%d CLOS_PQR_ASSOC param:%x resp:%x\n", cpu, param,
+       debug_printf("cpu:%d CLOS_PQR_ASSOC param:%x resp:%x\n", id->cpu, param,
                     resp);
        *clos_id = (resp >> 16) & 0x03;
 
        return 0;
 }
 
-int isst_clos_associate(int cpu, int clos_id)
+int isst_clos_associate(struct isst_id *id, int clos_id)
 {
        unsigned int req, resp;
        unsigned int param;
        int core_id, ret;
 
        req = (clos_id & 0x03) << 16;
-       core_id = find_phy_core_num(cpu);
+       core_id = find_phy_core_num(id->cpu);
        param = BIT(MBOX_CMD_WRITE_BIT) | core_id;
 
-       ret = isst_send_mbox_command(cpu, CONFIG_CLOS, CLOS_PQR_ASSOC, param,
+       ret = isst_send_mbox_command(id->cpu, CONFIG_CLOS, CLOS_PQR_ASSOC, param,
                                     req, &resp);
        if (ret)
                return ret;
 
-       debug_printf("cpu:%d CLOS_PQR_ASSOC param:%x req:%x\n", cpu, param,
+       debug_printf("cpu:%d CLOS_PQR_ASSOC param:%x req:%x\n", id->cpu, param,
                     req);
 
        return 0;
index d0400c6..0699137 100644 (file)
@@ -32,62 +32,60 @@ static void init_levels(void)
                        per_package_levels_info[i][j] = -1;
 }
 
-void process_level_change(int cpu)
+void process_level_change(struct isst_id *id)
 {
        struct isst_pkg_ctdp_level_info ctdp_level;
-       int pkg_id = get_physical_package_id(cpu);
-       int die_id = get_physical_die_id(cpu);
        struct isst_pkg_ctdp pkg_dev;
        time_t tm;
        int ret;
 
-       if (pkg_id >= MAX_PACKAGE_COUNT || die_id >= MAX_DIE_PER_PACKAGE) {
-               debug_printf("Invalid package/die info for cpu:%d\n", cpu);
+       if (id->pkg < 0 || id->die < 0) {
+               debug_printf("Invalid package/die info for cpu:%d\n", id->cpu);
                return;
        }
 
        tm = time(NULL);
-       if (tm - per_package_levels_tm[pkg_id][die_id] < 2 )
+       if (tm - per_package_levels_tm[id->pkg][id->die] < 2)
                return;
 
-       per_package_levels_tm[pkg_id][die_id] = tm;
+       per_package_levels_tm[id->pkg][id->die] = tm;
 
-       ret = isst_get_ctdp_levels(cpu, &pkg_dev);
+       ret = isst_get_ctdp_levels(id, &pkg_dev);
        if (ret) {
-               debug_printf("Can't get tdp levels for cpu:%d\n", cpu);
+               debug_printf("Can't get tdp levels for cpu:%d\n", id->cpu);
                return;
        }
 
-       debug_printf("Get Config level %d pkg:%d die:%d current_level:%d \n", cpu,
-                     pkg_id, die_id, pkg_dev.current_level);
+       debug_printf("Get Config level %d pkg:%d die:%d current_level:%d\n", id->cpu,
+                     id->pkg, id->die, pkg_dev.current_level);
 
        if (pkg_dev.locked) {
                debug_printf("config TDP s locked \n");
                return;
        }
 
-       if (per_package_levels_info[pkg_id][die_id] == pkg_dev.current_level)
+       if (per_package_levels_info[id->pkg][id->die] == pkg_dev.current_level)
                return;
 
        debug_printf("**Config level change for cpu:%d pkg:%d die:%d from %d to %d\n",
-                     cpu, pkg_id, die_id, per_package_levels_info[pkg_id][die_id],
+                     id->cpu, id->pkg, id->die, per_package_levels_info[id->pkg][id->die],
                      pkg_dev.current_level);
 
-       per_package_levels_info[pkg_id][die_id] = pkg_dev.current_level;
+       per_package_levels_info[id->pkg][id->die] = pkg_dev.current_level;
 
        ctdp_level.core_cpumask_size =
                alloc_cpu_set(&ctdp_level.core_cpumask);
-       ret = isst_get_coremask_info(cpu, pkg_dev.current_level, &ctdp_level);
+       ret = isst_get_coremask_info(id, pkg_dev.current_level, &ctdp_level);
        if (ret) {
                free_cpu_set(ctdp_level.core_cpumask);
-               debug_printf("Can't get core_mask:%d\n", cpu);
+               debug_printf("Can't get core_mask:%d\n", id->cpu);
                return;
        }
 
        if (ctdp_level.cpu_count) {
                int i, max_cpus = get_topo_max_cpus();
                for (i = 0; i < max_cpus; ++i) {
-                       if (pkg_id != get_physical_package_id(i) || die_id != get_physical_die_id(i))
+                       if (!is_cpu_in_power_domain(i, id))
                                continue;
                        if (CPU_ISSET_S(i, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask)) {
                                fprintf(stderr, "online cpu %d\n", i);
@@ -102,10 +100,10 @@ void process_level_change(int cpu)
        free_cpu_set(ctdp_level.core_cpumask);
 }
 
-static void _poll_for_config_change(int cpu, void *arg1, void *arg2,
+static void _poll_for_config_change(struct isst_id *id, void *arg1, void *arg2,
                                    void *arg3, void *arg4)
 {
-       process_level_change(cpu);
+       process_level_change(id);
 }
 
 static void poll_for_config_change(void)
index f97d885..b19f57d 100644 (file)
@@ -166,29 +166,27 @@ static void format_and_print(FILE *outf, int level, char *header, char *value)
        last_level = level;
 }
 
-static int print_package_info(int cpu, FILE *outf)
+static int print_package_info(struct isst_id *id, FILE *outf)
 {
        char header[256];
 
        if (out_format_is_json()) {
                snprintf(header, sizeof(header), "package-%d:die-%d:cpu-%d",
-                        get_physical_package_id(cpu), get_physical_die_id(cpu),
-                        cpu);
+                        id->pkg, id->die, id->cpu);
                format_and_print(outf, 1, header, NULL);
                return 1;
        }
-       snprintf(header, sizeof(header), "package-%d",
-                get_physical_package_id(cpu));
+       snprintf(header, sizeof(header), "package-%d", id->pkg);
        format_and_print(outf, 1, header, NULL);
-       snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
+       snprintf(header, sizeof(header), "die-%d", id->die);
        format_and_print(outf, 2, header, NULL);
-       snprintf(header, sizeof(header), "cpu-%d", cpu);
+       snprintf(header, sizeof(header), "cpu-%d", id->cpu);
        format_and_print(outf, 3, header, NULL);
 
        return 3;
 }
 
-static void _isst_pbf_display_information(int cpu, FILE *outf, int level,
+static void _isst_pbf_display_information(struct isst_id *id, FILE *outf, int level,
                                          struct isst_pbf_info *pbf_info,
                                          int disp_level)
 {
@@ -231,7 +229,7 @@ static void _isst_pbf_display_information(int cpu, FILE *outf, int level,
        format_and_print(outf, disp_level + 1, header, value);
 }
 
-static void _isst_fact_display_information(int cpu, FILE *outf, int level,
+static void _isst_fact_display_information(struct isst_id *id, FILE *outf, int level,
                                           int fact_bucket, int fact_avx,
                                           struct isst_fact_info *fact_info,
                                           int base_level)
@@ -319,7 +317,7 @@ static void _isst_fact_display_information(int cpu, FILE *outf, int level,
        format_and_print(outf, base_level + 2, header, value);
 }
 
-void isst_ctdp_display_core_info(int cpu, FILE *outf, char *prefix,
+void isst_ctdp_display_core_info(struct isst_id *id, FILE *outf, char *prefix,
                                 unsigned int val, char *str0, char *str1)
 {
        char header[256];
@@ -328,17 +326,14 @@ void isst_ctdp_display_core_info(int cpu, FILE *outf, char *prefix,
 
        if (out_format_is_json()) {
                snprintf(header, sizeof(header), "package-%d:die-%d:cpu-%d",
-                        get_physical_package_id(cpu), get_physical_die_id(cpu),
-                        cpu);
+                        id->pkg, id->die, id->cpu);
                format_and_print(outf, level++, header, NULL);
        } else {
-               snprintf(header, sizeof(header), "package-%d",
-                        get_physical_package_id(cpu));
+               snprintf(header, sizeof(header), "package-%d", id->pkg);
                format_and_print(outf, level++, header, NULL);
-               snprintf(header, sizeof(header), "die-%d",
-                        get_physical_die_id(cpu));
+               snprintf(header, sizeof(header), "die-%d", id->die);
                format_and_print(outf, level++, header, NULL);
-               snprintf(header, sizeof(header), "cpu-%d", cpu);
+               snprintf(header, sizeof(header), "cpu-%d", id->cpu);
                format_and_print(outf, level++, header, NULL);
        }
 
@@ -353,7 +348,7 @@ void isst_ctdp_display_core_info(int cpu, FILE *outf, char *prefix,
        format_and_print(outf, 1, NULL, NULL);
 }
 
-void isst_ctdp_display_information(int cpu, FILE *outf, int tdp_level,
+void isst_ctdp_display_information(struct isst_id *id, FILE *outf, int tdp_level,
                                   struct isst_pkg_ctdp *pkg_dev)
 {
        char header[256];
@@ -362,7 +357,7 @@ void isst_ctdp_display_information(int cpu, FILE *outf, int tdp_level,
        int i;
 
        if (pkg_dev->processed)
-               level = print_package_info(cpu, outf);
+               level = print_package_info(id, outf);
 
        for (i = 0; i <= pkg_dev->levels; ++i) {
                struct isst_pkg_ctdp_level_info *ctdp_level;
@@ -377,8 +372,7 @@ void isst_ctdp_display_information(int cpu, FILE *outf, int tdp_level,
                format_and_print(outf, level + 1, header, NULL);
 
                snprintf(header, sizeof(header), "cpu-count");
-               j = get_cpu_count(get_physical_die_id(cpu),
-                                 get_physical_die_id(cpu));
+               j = get_cpu_count(id);
                snprintf(value, sizeof(value), "%d", j);
                format_and_print(outf, level + 2, header, value);
 
@@ -485,7 +479,7 @@ void isst_ctdp_display_information(int cpu, FILE *outf, int tdp_level,
 
                if (is_clx_n_platform()) {
                        if (ctdp_level->pbf_support)
-                               _isst_pbf_display_information(cpu, outf,
+                               _isst_pbf_display_information(id, outf,
                                                              tdp_level,
                                                          &ctdp_level->pbf_info,
                                                              level + 2);
@@ -557,11 +551,11 @@ void isst_ctdp_display_information(int cpu, FILE *outf, int tdp_level,
                }
 
                if (ctdp_level->pbf_support)
-                       _isst_pbf_display_information(cpu, outf, i,
+                       _isst_pbf_display_information(id, outf, i,
                                                      &ctdp_level->pbf_info,
                                                      level + 2);
                if (ctdp_level->fact_support)
-                       _isst_fact_display_information(cpu, outf, i, 0xff, 0xff,
+                       _isst_fact_display_information(id, outf, i, 0xff, 0xff,
                                                       &ctdp_level->fact_info,
                                                       level + 2);
        }
@@ -583,36 +577,36 @@ void isst_ctdp_display_information_end(FILE *outf)
        start = 0;
 }
 
-void isst_pbf_display_information(int cpu, FILE *outf, int level,
+void isst_pbf_display_information(struct isst_id *id, FILE *outf, int level,
                                  struct isst_pbf_info *pbf_info)
 {
        int _level;
 
-       _level = print_package_info(cpu, outf);
-       _isst_pbf_display_information(cpu, outf, level, pbf_info, _level + 1);
+       _level = print_package_info(id, outf);
+       _isst_pbf_display_information(id, outf, level, pbf_info, _level + 1);
        format_and_print(outf, 1, NULL, NULL);
 }
 
-void isst_fact_display_information(int cpu, FILE *outf, int level,
+void isst_fact_display_information(struct isst_id *id, FILE *outf, int level,
                                   int fact_bucket, int fact_avx,
                                   struct isst_fact_info *fact_info)
 {
        int _level;
 
-       _level = print_package_info(cpu, outf);
-       _isst_fact_display_information(cpu, outf, level, fact_bucket, fact_avx,
+       _level = print_package_info(id, outf);
+       _isst_fact_display_information(id, outf, level, fact_bucket, fact_avx,
                                       fact_info, _level + 1);
        format_and_print(outf, 1, NULL, NULL);
 }
 
-void isst_clos_display_information(int cpu, FILE *outf, int clos,
+void isst_clos_display_information(struct isst_id *id, FILE *outf, int clos,
                                   struct isst_clos_config *clos_config)
 {
        char header[256];
        char value[256];
        int level;
 
-       level = print_package_info(cpu, outf);
+       level = print_package_info(id, outf);
 
        snprintf(header, sizeof(header), "core-power");
        format_and_print(outf, level + 1, header, NULL);
@@ -647,7 +641,7 @@ void isst_clos_display_information(int cpu, FILE *outf, int clos,
        format_and_print(outf, level, NULL, NULL);
 }
 
-void isst_clos_display_clos_information(int cpu, FILE *outf,
+void isst_clos_display_clos_information(struct isst_id *id, FILE *outf,
                                        int clos_enable, int type,
                                        int state, int cap)
 {
@@ -655,7 +649,7 @@ void isst_clos_display_clos_information(int cpu, FILE *outf,
        char value[256];
        int level;
 
-       level = print_package_info(cpu, outf);
+       level = print_package_info(id, outf);
 
        snprintf(header, sizeof(header), "core-power");
        format_and_print(outf, level + 1, header, NULL);
@@ -691,13 +685,13 @@ void isst_clos_display_clos_information(int cpu, FILE *outf,
        format_and_print(outf, level, NULL, NULL);
 }
 
-void isst_clos_display_assoc_information(int cpu, FILE *outf, int clos)
+void isst_clos_display_assoc_information(struct isst_id *id, FILE *outf, int clos)
 {
        char header[256];
        char value[256];
        int level;
 
-       level = print_package_info(cpu, outf);
+       level = print_package_info(id, outf);
 
        snprintf(header, sizeof(header), "get-assoc");
        format_and_print(outf, level + 1, header, NULL);
@@ -709,15 +703,15 @@ void isst_clos_display_assoc_information(int cpu, FILE *outf, int clos)
        format_and_print(outf, level, NULL, NULL);
 }
 
-void isst_display_result(int cpu, FILE *outf, char *feature, char *cmd,
+void isst_display_result(struct isst_id *id, FILE *outf, char *feature, char *cmd,
                         int result)
 {
        char header[256];
        char value[256];
        int level = 3;
 
-       if (cpu >= 0)
-               level = print_package_info(cpu, outf);
+       if (id->cpu >= 0)
+               level = print_package_info(id, outf);
 
        snprintf(header, sizeof(header), "%s", feature);
        format_and_print(outf, level + 1, header, NULL);
@@ -772,13 +766,13 @@ void isst_display_error_info_message(int error, char *msg, int arg_valid, int ar
                format_and_print(outf, 0, NULL, NULL);
 }
 
-void isst_trl_display_information(int cpu, FILE *outf, unsigned long long trl)
+void isst_trl_display_information(struct isst_id *id, FILE *outf, unsigned long long trl)
 {
        char header[256];
        char value[256];
        int level;
 
-       level = print_package_info(cpu, outf);
+       level = print_package_info(id, outf);
 
        snprintf(header, sizeof(header), "get-trl");
        format_and_print(outf, level + 1, header, NULL);
index 0796d8c..409fcc9 100644 (file)
 #define MAX_PACKAGE_COUNT 8
 #define MAX_DIE_PER_PACKAGE 2
 
+/* Unified structure to specific a CPU or a Power Domain */
+struct isst_id {
+       int cpu;
+       int pkg;
+       int die;
+};
+
 struct isst_clos_config {
-       int pkg_id;
-       int die_id;
        unsigned char epp;
        unsigned char clos_prop_prio;
        unsigned char clos_min;
@@ -171,22 +176,20 @@ struct isst_pkg_ctdp {
        struct isst_pkg_ctdp_level_info ctdp_level[ISST_MAX_TDP_LEVELS];
 };
 
+extern int is_cpu_in_power_domain(int cpu, struct isst_id *id);
 extern int get_topo_max_cpus(void);
-extern int get_cpu_count(int pkg_id, int die_id);
-extern int get_max_punit_core_id(int pkg_id, int die_id);
+extern int get_cpu_count(struct isst_id *id);
+extern int get_max_punit_core_id(struct isst_id *id);
 
 /* Common interfaces */
 FILE *get_output_file(void);
 extern void debug_printf(const char *format, ...);
 extern int out_format_is_json(void);
-extern int get_physical_package_id(int cpu);
-extern int get_physical_die_id(int cpu);
+extern void set_isst_id(struct isst_id *id, int cpu);
 extern size_t alloc_cpu_set(cpu_set_t **cpu_set);
 extern void free_cpu_set(cpu_set_t *cpu_set);
-extern int find_logical_cpu(int pkg_id, int die_id, int phy_cpu);
-extern int find_phy_cpu_num(int logical_cpu);
 extern int find_phy_core_num(int logical_cpu);
-extern void set_cpu_mask_from_punit_coremask(int cpu,
+extern void set_cpu_mask_from_punit_coremask(struct isst_id *id,
                                             unsigned long long core_mask,
                                             size_t core_cpumask_size,
                                             cpu_set_t *core_cpumask,
@@ -200,77 +203,74 @@ extern int isst_send_mbox_command(unsigned int cpu, unsigned char command,
 extern int isst_send_msr_command(unsigned int cpu, unsigned int command,
                                 int write, unsigned long long *req_resp);
 
-extern int isst_get_ctdp_levels(int cpu, struct isst_pkg_ctdp *pkg_dev);
-extern int isst_get_ctdp_control(int cpu, int config_index,
+extern int isst_get_ctdp_levels(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev);
+extern int isst_get_ctdp_control(struct isst_id *id, int config_index,
                                 struct isst_pkg_ctdp_level_info *ctdp_level);
-extern int isst_get_coremask_info(int cpu, int config_index,
+extern int isst_get_coremask_info(struct isst_id *id, int config_index,
                           struct isst_pkg_ctdp_level_info *ctdp_level);
-extern int isst_get_process_ctdp(int cpu, int tdp_level,
+extern int isst_get_process_ctdp(struct isst_id *id, int tdp_level,
                                 struct isst_pkg_ctdp *pkg_dev);
-extern void isst_get_process_ctdp_complete(int cpu,
+extern void isst_get_process_ctdp_complete(struct isst_id *id,
                                           struct isst_pkg_ctdp *pkg_dev);
-extern void isst_ctdp_display_information(int cpu, FILE *outf, int tdp_level,
+extern void isst_ctdp_display_information(struct isst_id *id, FILE *outf, int tdp_level,
                                          struct isst_pkg_ctdp *pkg_dev);
-extern void isst_ctdp_display_core_info(int cpu, FILE *outf, char *prefix,
+extern void isst_ctdp_display_core_info(struct isst_id *id, FILE *outf, char *prefix,
                                        unsigned int val, char *str0, char *str1);
 extern void isst_ctdp_display_information_start(FILE *outf);
 extern void isst_ctdp_display_information_end(FILE *outf);
-extern void isst_pbf_display_information(int cpu, FILE *outf, int level,
+extern void isst_pbf_display_information(struct isst_id *id, FILE *outf, int level,
                                         struct isst_pbf_info *info);
-extern int isst_set_tdp_level(int cpu, int tdp_level);
-extern int isst_set_tdp_level_msr(int cpu, int tdp_level);
-extern int isst_set_pbf_fact_status(int cpu, int pbf, int enable);
-extern int isst_get_pbf_info(int cpu, int level,
+extern int isst_set_tdp_level(struct isst_id *id, int tdp_level);
+extern int isst_set_pbf_fact_status(struct isst_id *id, int pbf, int enable);
+extern int isst_get_pbf_info(struct isst_id *id, int level,
                             struct isst_pbf_info *pbf_info);
 extern void isst_get_pbf_info_complete(struct isst_pbf_info *pbf_info);
-extern int isst_get_fact_info(int cpu, int level, int fact_bucket,
+extern int isst_get_fact_info(struct isst_id *id, int level, int fact_bucket,
                              struct isst_fact_info *fact_info);
-extern int isst_get_fact_bucket_info(int cpu, int level,
+extern int isst_get_fact_bucket_info(struct isst_id *id, int level,
                                     struct isst_fact_bucket_info *bucket_info);
-extern void isst_fact_display_information(int cpu, FILE *outf, int level,
+extern void isst_fact_display_information(struct isst_id *id, FILE *outf, int level,
                                          int fact_bucket, int fact_avx,
                                          struct isst_fact_info *fact_info);
-extern int isst_set_trl(int cpu, unsigned long long trl);
-extern int isst_get_trl(int cpu, unsigned long long *trl);
-extern int isst_set_trl_from_current_tdp(int cpu, unsigned long long trl);
-extern int isst_get_config_tdp_lock_status(int cpu);
+extern int isst_set_trl(struct isst_id *id, unsigned long long trl);
+extern int isst_get_trl(struct isst_id *id, unsigned long long *trl);
+extern int isst_set_trl_from_current_tdp(struct isst_id *id, unsigned long long trl);
+extern int isst_get_config_tdp_lock_status(struct isst_id *id);
 
-extern int isst_pm_qos_config(int cpu, int enable_clos, int priority_type);
-extern int isst_pm_get_clos(int cpu, int clos,
+extern int isst_pm_qos_config(struct isst_id *id, int enable_clos, int priority_type);
+extern int isst_pm_get_clos(struct isst_id *id, int clos,
                            struct isst_clos_config *clos_config);
-extern int isst_set_clos(int cpu, int clos,
+extern int isst_set_clos(struct isst_id *id, int clos,
                         struct isst_clos_config *clos_config);
-extern int isst_clos_associate(int cpu, int clos);
-extern int isst_clos_get_assoc_status(int cpu, int *clos_id);
-extern void isst_clos_display_information(int cpu, FILE *outf, int clos,
+extern int isst_clos_associate(struct isst_id *id, int clos);
+extern int isst_clos_get_assoc_status(struct isst_id *id, int *clos_id);
+extern void isst_clos_display_information(struct isst_id *id, FILE *outf, int clos,
                                          struct isst_clos_config *clos_config);
-extern void isst_clos_display_assoc_information(int cpu, FILE *outf, int clos);
-extern int isst_read_reg(unsigned short reg, unsigned int *val);
-extern int isst_write_reg(int reg, unsigned int val);
+extern void isst_clos_display_assoc_information(struct isst_id *id, FILE *outf, int clos);
 
-extern void isst_display_result(int cpu, FILE *outf, char *feature, char *cmd,
+extern void isst_display_result(struct isst_id *id, FILE *outf, char *feature, char *cmd,
                                int result);
 
-extern int isst_clos_get_clos_information(int cpu, int *enable, int *type);
-extern void isst_clos_display_clos_information(int cpu, FILE *outf,
+extern int isst_clos_get_clos_information(struct isst_id *id, int *enable, int *type);
+extern void isst_clos_display_clos_information(struct isst_id *id, FILE *outf,
                                               int clos_enable, int type,
                                               int state, int cap);
 extern int is_clx_n_platform(void);
 extern int get_cpufreq_base_freq(int cpu);
-extern int isst_read_pm_config(int cpu, int *cp_state, int *cp_cap);
+extern int isst_read_pm_config(struct isst_id *id, int *cp_state, int *cp_cap);
 extern void isst_display_error_info_message(int error, char *msg, int arg_valid, int arg);
 extern int is_skx_based_platform(void);
 extern int is_spr_platform(void);
 extern int is_icx_platform(void);
-extern void isst_trl_display_information(int cpu, FILE *outf, unsigned long long trl);
+extern void isst_trl_display_information(struct isst_id *id, FILE *outf, unsigned long long trl);
 
 extern void set_cpu_online_offline(int cpu, int state);
-extern void for_each_online_package_in_set(void (*callback)(int, void *, void *,
+extern void for_each_online_package_in_set(void (*callback)(struct isst_id *, void *, void *,
                                                            void *, void *),
                                           void *arg1, void *arg2, void *arg3,
                                           void *arg4);
 extern int isst_daemon(int debug_mode, int poll_interval, int no_daemon);
-extern void process_level_change(int cpu);
+extern void process_level_change(struct isst_id *id);
 extern int hfi_main(void);
 extern void hfi_exit(void);
 #endif