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:
commit
7fb68b6c82
13
Documentation/ABI/testing/sysfs-amd-pmc
Normal file
13
Documentation/ABI/testing/sysfs-amd-pmc
Normal 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.
|
13
Documentation/ABI/testing/sysfs-amd-pmf
Normal file
13
Documentation/ABI/testing/sysfs-amd-pmf
Normal 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.
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
===========
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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(®ister_count_mutex);
|
||||
return ret;
|
||||
@ -2261,6 +2228,7 @@ void acpi_video_unregister(void)
|
||||
{
|
||||
mutex_lock(®ister_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(®ister_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(®ister_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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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/
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
16
drivers/platform/x86/amd/pmf/Kconfig
Normal file
16
drivers/platform/x86/amd/pmf/Kconfig
Normal 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.
|
9
drivers/platform/x86/amd/pmf/Makefile
Normal file
9
drivers/platform/x86/amd/pmf/Makefile
Normal 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
|
304
drivers/platform/x86/amd/pmf/acpi.c
Normal file
304
drivers/platform/x86/amd/pmf/acpi.c
Normal 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, ¶ms);
|
||||
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, ¶ms, 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;
|
||||
}
|
305
drivers/platform/x86/amd/pmf/auto-mode.c
Normal file
305
drivers/platform/x86/amd/pmf/auto-mode.c
Normal 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);
|
||||
}
|
395
drivers/platform/x86/amd/pmf/cnqf.c
Normal file
395
drivers/platform/x86/amd/pmf/cnqf.c
Normal 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;
|
||||
}
|
412
drivers/platform/x86/amd/pmf/core.c
Normal file
412
drivers/platform/x86/amd/pmf/core.c
Normal 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,
|
||||
¤t_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");
|
417
drivers/platform/x86/amd/pmf/pmf.h
Normal file
417
drivers/platform/x86/amd/pmf/pmf.h
Normal 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 */
|
146
drivers/platform/x86/amd/pmf/sps.c
Normal file
146
drivers/platform/x86/amd/pmf/sps.c
Normal 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();
|
||||
}
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
@ -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
|
||||
|
@ -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 @@ static int setup_rfkill(void)
|
||||
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 @@ static int compal_probe(struct platform_device *pdev)
|
||||
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);
|
||||
|
@ -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;
|
||||
|
@ -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),
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 } },
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)) {
|
||||
|
@ -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 },
|
||||
{ }
|
||||
|
@ -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;
|
||||
|
@ -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); \
|
||||
} \
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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 @@ static int rfkill_init(struct platform_device *sdev)
|
||||
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 @@ static int __init msi_laptop_input_setup(void)
|
||||
|
||||
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 @@ static int __init load_scm_model_init(struct platform_device *sdev)
|
||||
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 @@ static int __init msi_init(void)
|
||||
|
||||
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:*");
|
||||
|
@ -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 },
|
||||
{ }
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
*/
|
||||
|
@ -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)
|
||||
|
@ -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 =
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
|
||||
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 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
|
||||
|
||||
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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
76
include/linux/platform_data/x86/nvidia-wmi-ec-backlight.h
Normal file
76
include/linux/platform_data/x86/nvidia-wmi-ec-backlight.h
Normal 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
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -136,6 +136,9 @@ static void s2idle_loop(void)
|
||||
break;
|
||||
}
|
||||
|
||||
if (s2idle_ops && s2idle_ops->check)
|
||||
s2idle_ops->check();
|
||||
|
||||
s2idle_enter();
|
||||
}
|
||||
|
||||
|
@ -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
@ -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;
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user