platform-drivers-x86 for v6.1-1

Highlights:
  -  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
 
 The following is an automated git shortlog grouped by driver:
 
 ACPI:
  -  video: Change disable_backlight_sysfs_if quirks to acpi_backlight=native
  -  s2idle: Add a new ->check() callback for platform_s2idle_ops
  -  video: Fix indentation of video_detect_dmi_table[] entries
  -  video: Drop NL5x?U, PF4NU1F and PF5?U?? acpi_backlight=native quirks
  -  video: Drop "Samsung X360" acpi_backlight=native quirk
  -  video: Remove acpi_video_set_dmi_backlight_type()
  -  video: Add Apple GMUX brightness control detection
  -  video: Add Nvidia WMI EC brightness control detection (v3)
  -  video: Refactor acpi_video_get_backlight_type() a bit
  -  video: Remove code to unregister acpi_video backlight when a native backlight registers
  -  video: Make backlight class device registration a separate step (v2)
  -  video: Simplify acpi_video_unregister_backlight()
  -  video: Remove acpi_video_bus from list before tearing it down
  -  video: Drop backlight_device_get_by_type() call from acpi_video_get_backlight_type()
  -  video: Add acpi_video_backlight_use_native() helper
 
 acer-wmi:
  -  Move backlight DMI quirks to acpi/video_detect.c
  -  Acer Aspire One AOD270/Packard Bell Dot keymap fixes
 
 apple-gmux:
  -  Stop calling acpi/video.h functions
 
 asus-wmi:
  -  Expand support of GPU fan to read RPM and label
  -  Make kbd_rgb_mode_groups static
  -  Move acpi_backlight=native quirks to ACPI video_detect.c
  -  Move acpi_backlight=vendor quirks to ACPI video_detect.c
  -  Drop DMI chassis-type check from backlight handling
  -  Increase FAN_CURVE_BUF_LEN to 32
  -  Fix the name of the mic-mute LED classdev
  -  Implement TUF laptop keyboard power states
  -  Implement TUF laptop keyboard LED modes
  -  Support the GPU fan on TUF laptops
  -  Modify behaviour of Fn+F5 fan key
  -  Update tablet_mode_sw module-param help text
  -  Simplify tablet-mode-switch handling
  -  Simplify tablet-mode-switch probing
  -  Add support for ROG X13 tablet mode
  -  Adjust tablet/lidflip handling to use enum
  -  Support the hardware GPU MUX on some laptops
  -  Simplify some of the *_check_present() helpers
  -  Refactor panel_od attribute
  -  Refactor egpu_enable attribute
  -  Refactor disable_gpu attribute
  -  Document the panel_od sysfs attribute
  -  Document the egpu_enable sysfs attribute
  -  Document the dgpu_disable sysfs attribute
  -  Use kobj_to_dev()
  -  Convert all attr-show to use sysfs_emit
 
 compal-laptop:
  -  Get rid of a few forward declarations
 
 dell-privacy:
  -  convert to use dev_groups
 
 dell-smbios-base:
  -  Use sysfs_emit()
 
 dell-wmi:
  -  Add WMI event 0x0012 0x0003 to the list
 
 docs:
  -  ABI: charge_control_end_threshold may not support all values
 
 drivers/platform:
  -  toshiba_acpi: Call HCI_PANEL_POWER_ON on resume on some models
 
 drm/amdgpu:
  -  Register ACPI video backlight when skipping amdgpu backlight registration
  -  Don't register backlight when another backlight should be used (v3)
 
 drm/i915:
  -  Call acpi_video_register_backlight() (v3)
  -  Don't register backlight when another backlight should be used (v2)
 
 drm/nouveau:
  -  Register ACPI video backlight when nv_backlight registration fails (v2)
  -  Don't register backlight when another backlight should be used (v2)
 
 drm/radeon:
  -  Register ACPI video backlight when skipping radeon backlight registration
  -  Don't register backlight when another backlight should be used (v3)
 
 drm/todo:
  -  Add entry about dealing with brightness control on devices with > 1 panel
 
 gpio-f7188x:
  -  use unique labels for banks/chips
  -  Add GPIO support for Nuvoton NCT6116
  -  add a prefix to macros to keep gpio namespace clean
  -  switch over to using pr_fmt
 
 hp-wmi:
  -  Support touchpad on/off
  -  Setting thermal profile fails with 0x06
 
 int3472/discrete:
  -  Drop a forward declaration
 
 intel-uncore-freq:
  -  Use sysfs_emit() to instead of scnprintf()
 
 intel_cht_int33fe:
  -  Fix comment according to the code flow
 
 leds:
  -  simatic-ipc-leds-gpio: Make simatic_ipc_led_gpio_table static
  -  simatic-ipc-leds-gpio: add new model 227G
 
 move from strlcpy with unused retval to strscpy:
  - move from strlcpy with unused retval to strscpy
 
 msi-laptop:
  -  Change DMI match / alias strings to fix module autoloading
  -  Add msi_scm_disable_hw_fn_handling() helper
  -  Add msi_scm_model_exit() helper
  -  Fix resource cleanup
  -  Simplify ec_delay handling
  -  Fix old-ec check for backlight registering
  -  Drop MSI_DRIVER_VERSION
  -  Use MODULE_DEVICE_TABLE()
 
 nvidia-wmi-ec-backlight:
  -  Use acpi_video_get_backlight_type()
  -  Move fw interface definitions to a header (v2)
 
 p2sb:
  -  Fix UAF when caller uses resource name
 
 platform/mellanox:
  -  mlxreg-lc: Make error handling flow consistent
  -  Remove redundant 'NULL' check
  -  Remove unnecessary code
  -  mlxreg-lc: Fix locking issue
  -  mlxreg-lc: Fix coverity warning
 
 platform/surface:
  -  Split memcpy() of struct ssam_event flexible array
  -  aggregator_registry: Add HID devices for sensors and UCSI client to SP8
  -  aggregator_registry: Rename HID device nodes based on new findings
  -  aggregator_registry: Rename HID device nodes based on their function
  -  aggregator_registry: Add support for Surface Laptop Go 2
 
 platform/x86:
  - use PLATFORM_DEVID_NONE instead of -1
 
 platform/x86/amd:
  -  pmc: Dump idle mask during "check" stage instead
  -  pmc: remove CONFIG_DEBUG_FS checks
  -  pmc: Fix build without debugfs
  -  pmc: Add sysfs files for SMU
  -  pmc: Add an extra STB message for checking s2idle entry
  -  pmc: Always write to the STB
  -  pmc: Add defines for STB events
 
 platform/x86/amd/pmf:
  -  Remove unused power_delta instances
  -  install notify handler after acpi init
  -  Add sysfs to toggle CnQF
  -  Add support for CnQF
  -  Fix clang unused variable warning
  -  Fix undefined reference to platform_profile
  -  Force load driver on older supported platforms
  -  Handle AMT and CQL events for Auto mode
  -  Add support for Auto mode feature
  -  Get performance metrics from PMFW
  -  Add fan control support
  -  Add heartbeat signal support
  -  Add debugfs information
  -  Add support SPS PMF feature
  -  Add support for PMF APCI layer
  -  Add support for PMF core layer
  -  Add ABI doc for AMD PMF
  -  Add AMD PMF driver entry
 
 platform/x86/intel/wmi:
  -  thunderbolt: Use dev_groups callback
 
 pmc_atom:
  -  Amend comment style and grammar
  -  Make terminator entry uniform
  -  Improve quirk message to be less cryptic
  -  Fix SLP_TYPx bitfield mask
 
 samsung-laptop:
  -  Move acpi_backlight=[vendor|native] quirks to ACPI video_detect.c
 
 simatic-ipc:
  -  add new model 427G
  -  enable watchdog for 227G
 
 thinkpad_acpi:
  -  Explicitly set to balanced mode on startup
 
 tools/power/x86/intel-speed-select:
  -  Release v1.13
  -  Optimize CPU initialization
  -  Utilize cpu_map to get physical id
  -  Remove unused struct clos_config fields
  -  Enforce isst_id value
  -  Do not export get_physical_id
  -  Introduce is_cpu_in_power_domain helper
  -  Cleanup get_physical_id usage
  -  Convert more function to use isst_id
  -  Add pkg and die in isst_id
  -  Introduce struct isst_id
  -  Remove unused core_mask array
  -  Remove dead code
  -  Fix cpu count for TDP level display
 
 toshiba_acpi:
  -  change turn_on_panel_on_resume to static
  -  Remove duplicate include
  -  Set correct parent for input device.
  -  Add fan RPM reading (hwmon interface)
  -  Add fan RPM reading (internals)
  -  Stop using acpi_video_set_dmi_backlight_type()
  -  Fix ECO LED control on Toshiba Z830
  - Battery charge mode in toshiba_acpi (internals)
  - Battery charge mode in toshiba_acpi (sysfs)
 
 wmi:
  -  Drop forward declaration of static functions
  -  Allow duplicate GUIDs for drivers that use struct wmi_driver
 
 x86-android-tablets:
  -  Fix broken touchscreen on Chuwi Hi8 with Windows BIOS
 -----BEGIN PGP SIGNATURE-----
 
 iQFIBAABCAAyFiEEuvA7XScYQRpenhd+kuxHeUQDJ9wFAmM9eLgUHGhkZWdvZWRl
 QHJlZGhhdC5jb20ACgkQkuxHeUQDJ9zIzAf+JG058wucK0Zsnu4POzGp+uHjnWuu
 AJUmTeRvCD7MidwIv5PiwEtTucQ8OuXYR+tPc8LIwCVZtc05FBmh7Y8le/CX0SS6
 n9EZIvCk3Owosti5w2TPnCK920kh+Wfxl/fmfDbpi6+lpAL8r+F/mZEGKGFdZpWu
 Q+yM/eyxwPH8q8gjrXOUC7rN43aYeO3OCpNG3GYkQ/2S5qrjuz39dXhNVzdSsxm7
 aYOqJRNjZQEjQ3kJcp65kC6oWp3UaI1zdpGwhBG/SY8BCtCYZzlRy7gN2FCJfAa/
 EyYayOvdy0zNwewbIYzck4W80hUDtfidgZgZ9crQscO/JjbGi6LhveD4YA==
 =afGw
 -----END PGP SIGNATURE-----

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

Pull x86 platform driver updates from Hans de Goede:

 - AMD 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
  ...
This commit is contained in:
Linus Torvalds 2022-10-05 10:38:24 -07:00
commit 7fb68b6c82
102 changed files with 4611 additions and 1882 deletions

View File

@ -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.

View File

@ -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.

View 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

View 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

View 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
===========

View 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>

View 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

View 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;
@ -462,56 +463,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();
}

View 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);

View 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
@ -27,20 +28,16 @@
#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,62 +132,142 @@ 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
@ -389,6 +496,41 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "JV50"),
},
},
{
/* 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,
@ -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"),
},
},
{
.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,
/* 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,
/* 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,
/* Samsung N250P */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "N250P"),
DMI_MATCH(DMI_BOARD_NAME, "N250P"),
},
},
/*
* 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.
* 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 = "Clevo NL5xRU",
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
/* 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 = "Clevo NL5xRU",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
DMI_MATCH(DMI_BOARD_NAME, "AURA1501"),
/* 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 = "Clevo NL5xRU",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
DMI_MATCH(DMI_BOARD_NAME, "EDUBOOK1502"),
},
},
{
.callback = video_detect_force_native,
.ident = "Clevo NL5xNU",
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
},
},
/*
* 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.
*/
{
.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"),
},
},
{
.callback = video_detect_force_native,
.ident = "TongFang PF5NU1G",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
DMI_MATCH(DMI_BOARD_NAME, "PULSE1501"),
},
},
{
.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;
return acpi_backlight_video;
/* 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;
}
/* No ACPI video (old hw), use vendor specific fw methods. */
return acpi_backlight_vendor;
}
enum acpi_backlight_type acpi_video_get_backlight_type(void)
{
return __acpi_video_get_backlight_type(false);
}
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)
bool acpi_video_backlight_use_native(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();
}
EXPORT_SYMBOL(acpi_video_set_dmi_backlight_type);
void __exit acpi_video_detect_exit(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);

View 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,

View 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.

View 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>
@ -14,30 +17,41 @@
#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;
}

View 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.

View 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

View 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;

View 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

View 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

View 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);
}

View 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__ */

View 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;

View 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);

View 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();
}

View 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

View 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;
}

View 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");

View 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

View 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");

View File

@ -13,28 +13,45 @@
#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,

View 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;

View 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))

View 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;

View 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

View 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;

View 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;

View 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

View 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/

View 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;

View 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,

View File

@ -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.

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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");

View File

@ -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 */

View File

@ -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();
}

View 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);

View 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();
}

View 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);

View 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,
},
{
@ -379,15 +372,6 @@ static const struct dmi_system_id asus_quirks[] = {
},
.driver_data = &quirk_asus_x200ca,
},
{
.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",
@ -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},
};

File diff suppressed because it is too large Load Diff

View 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

View 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,69 +955,6 @@ err_wifi:
return ret;
}
static int __init compal_init(void)
{
int ret;
if (acpi_disabled) {
pr_err("ACPI needs to be enabled for this driver to work!\n");
return -ENODEV;
}
if (!force && !dmi_check_system(compal_dmi_table)) {
pr_err("Motherboard not recognized (You could try the module's force-parameter)\n");
return -ENODEV;
}
if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
struct backlight_properties props;
memset(&props, 0, sizeof(struct backlight_properties));
props.type = BACKLIGHT_PLATFORM;
props.max_brightness = BACKLIGHT_LEVEL_MAX;
compalbl_device = backlight_device_register(DRIVER_NAME,
NULL, NULL,
&compalbl_ops,
&props);
if (IS_ERR(compalbl_device))
return PTR_ERR(compalbl_device);
}
ret = platform_driver_register(&compal_driver);
if (ret)
goto err_backlight;
compal_device = platform_device_alloc(DRIVER_NAME, -1);
if (!compal_device) {
ret = -ENOMEM;
goto err_platform_driver;
}
ret = platform_device_add(compal_device); /* This calls compal_probe */
if (ret)
goto err_platform_device;
ret = setup_rfkill();
if (ret)
goto err_rfkill;
pr_info("Driver " DRIVER_VERSION " successfully loaded\n");
return 0;
err_rfkill:
platform_device_del(compal_device);
err_platform_device:
platform_device_put(compal_device);
err_platform_driver:
platform_driver_unregister(&compal_driver);
err_backlight:
backlight_device_unregister(compalbl_device);
return ret;
}
static int compal_probe(struct platform_device *pdev)
{
int err;
@ -1076,19 +1003,6 @@ remove:
return err;
}
static void __exit compal_cleanup(void)
{
platform_device_unregister(compal_device);
platform_driver_unregister(&compal_driver);
backlight_device_unregister(compalbl_device);
rfkill_unregister(wifi_rfkill);
rfkill_unregister(bt_rfkill);
rfkill_destroy(wifi_rfkill);
rfkill_destroy(bt_rfkill);
pr_info("Driver unloaded\n");
}
static int compal_remove(struct platform_device *pdev)
{
struct compal_data *data;
@ -1107,6 +1021,89 @@ static int compal_remove(struct platform_device *pdev)
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;
if (acpi_disabled) {
pr_err("ACPI needs to be enabled for this driver to work!\n");
return -ENODEV;
}
if (!force && !dmi_check_system(compal_dmi_table)) {
pr_err("Motherboard not recognized (You could try the module's force-parameter)\n");
return -ENODEV;
}
if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
struct backlight_properties props;
memset(&props, 0, sizeof(struct backlight_properties));
props.type = BACKLIGHT_PLATFORM;
props.max_brightness = BACKLIGHT_LEVEL_MAX;
compalbl_device = backlight_device_register(DRIVER_NAME,
NULL, NULL,
&compalbl_ops,
&props);
if (IS_ERR(compalbl_device))
return PTR_ERR(compalbl_device);
}
ret = platform_driver_register(&compal_driver);
if (ret)
goto err_backlight;
compal_device = platform_device_alloc(DRIVER_NAME, PLATFORM_DEVID_NONE);
if (!compal_device) {
ret = -ENOMEM;
goto err_platform_driver;
}
ret = platform_device_add(compal_device); /* This calls compal_probe */
if (ret)
goto err_platform_device;
ret = setup_rfkill();
if (ret)
goto err_rfkill;
pr_info("Driver " DRIVER_VERSION " successfully loaded\n");
return 0;
err_rfkill:
platform_device_del(compal_device);
err_platform_device:
platform_device_put(compal_device);
err_platform_driver:
platform_driver_unregister(&compal_driver);
err_backlight:
backlight_device_unregister(compalbl_device);
return ret;
}
static void __exit compal_cleanup(void)
{
platform_device_unregister(compal_device);
platform_driver_unregister(&compal_driver);
backlight_device_unregister(compalbl_device);
rfkill_unregister(wifi_rfkill);
rfkill_unregister(bt_rfkill);
rfkill_destroy(wifi_rfkill);
rfkill_destroy(bt_rfkill);
pr_info("Driver unloaded\n");
}
module_init(compal_init);
module_exit(compal_cleanup);

View 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;

View 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),
};

View 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;

View 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;
}

View 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 } },

View 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,

View 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

View 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);

View 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);

View 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,

View 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;

View 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;

View 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;

View 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;

View 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)) {

View 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 },
{ }

View 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;

View 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); \
} \

View 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,
};

View 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));

View 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:*");

View 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 },
{ }

View 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;

View 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");
*/

View 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);
@ -1540,76 +1530,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",
@ -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)

View 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 =

View 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;

View 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;

View 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;

View 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;

View 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>
@ -38,18 +39,24 @@
#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;
@ -271,14 +286,6 @@ static const struct key_entry toshiba_acpi_alt_keymap[] = {
{ KE_END, 0 },
};
/*
* 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

View 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);

View 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;

View 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)
{

View 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);

View 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
@ -99,6 +101,15 @@
/* 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

View File

@ -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

View 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

View 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;

View 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)

View 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);

View File

@ -136,6 +136,9 @@ static void s2idle_loop(void)
break;
}
if (s2idle_ops && s2idle_ops->check)
s2idle_ops->check();
s2idle_enter();
}

View 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)

File diff suppressed because it is too large Load Diff

View 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;

View 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)

Some files were not shown because too many files have changed in this diff Show More