platform-drivers-x86 for v6.2-1
Highlights: - Intel: - PMC: Add support for Meteor Lake - Intel On Demand: various updates - ideapad-laptop: - Add support for various Fn keys on new models - Fix touchpad on/off handling in a generic way to avoid having to add more and more quirks - android-x86-tablets: Add support for 2 more X86 Android tablet models - New Dell WMI DDV driver - Miscellaneous cleanups and small bugfixes The following is an automated git shortlog grouped by driver: ACPI: - battery: Pass battery hook pointer to hook callbacks ISST: - Fix typo in comments Move existing HP drivers to a new hp subdir: - Move existing HP drivers to a new hp subdir dell: - Add new dell-wmi-ddv driver dell-ddv: - Warn if ePPID has a suspicious length - Improve buffer handling huawei-wmi: - remove unnecessary member - fix return value calculation - do not hard-code sizes ideapad-laptop: - Make touchpad_ctrl_via_ec a module option - Stop writing VPCCMD_W_TOUCHPAD at probe time - Send KEY_TOUCHPAD_TOGGLE on some models - Only toggle ps2 aux port on/off on select models - Do not send KEY_TOUCHPAD* events on probe / resume - Refactor ideapad_sync_touchpad_state() - support for more special keys in WMI - Add new _CFG bit numbers for future use - Revert "check for touchpad support in _CFG" intel/pmc: - Relocate Alder Lake PCH support - Relocate Tiger Lake PCH support - Relocate Ice Lake PCH support - Relocate Cannon Lake Point PCH support - Relocate Sunrise Point PCH support - Move variable declarations and definitions to header and core.c - Replace all the reg_map with init functions intel/pmc/core: - Add Meteor Lake support to pmc core driver intel_scu_ipc: - fix possible name leak in __intel_scu_ipc_register() mxm-wmi: - fix memleak in mxm_wmi_call_mx[ds|mx]() platform/mellanox: - mlxbf-pmc: Fix event typo - Add BlueField-3 support in the tmfifo driver platform/x86/amd: - pmc: Add a workaround for an s0i3 issue on Cezanne platform/x86/amd/pmf: - pass the struct by reference platform/x86/dell: - alienware-wmi: Use sysfs_emit() instead of scnprintf() platform/x86/intel: - pmc: Fix repeated word in comment platform/x86/intel/hid: - Add module-params for 5 button array + SW_TABLET_MODE reporting platform/x86/intel/sdsi: - Add meter certificate support - Support different GUIDs - Hide attributes if hardware doesn't support - Add Intel On Demand text sony-laptop: - Convert to use sysfs_emit_at() API thinkpad_acpi: - use strstarts() - Fix max_brightness of thinklight tools/arch/x86: - intel_sdsi: Add support for reading meter certificates - intel_sdsi: Add support for new GUID - intel_sdsi: Read more On Demand registers - intel_sdsi: Add Intel On Demand text - intel_sdsi: Add support for reading state certificates uv_sysfs: - Use sysfs_emit() instead of scnprintf() wireless-hotkey: - use ACPI HID as phys x86-android-tablets: - Add Advantech MICA-071 extra button - Add Lenovo Yoga Tab 3 (YT3-X90F) charger + fuel-gauge data - Add Medion Lifetab S10346 data -----BEGIN PGP SIGNATURE----- iQFIBAABCAAyFiEEuvA7XScYQRpenhd+kuxHeUQDJ9wFAmOW+QgUHGhkZWdvZWRl QHJlZGhhdC5jb20ACgkQkuxHeUQDJ9yAPwf/dAYLHiC2ox5YlNTLX2DvU+jOpeBv W+EIx4oHQz1+O9jrWMLyvS9zTwTEAf6ANLiMP3damEvtJnB72ClgFITzlJAaB4zN yj0SdxoBRMt6zDL2QwMkwitvb5kJonLfO2H7NsMwA6f0KP1X8sio3oVRAMMVwlzz nwDKM/VBpuxmy+d880wRRoAkgRkTsPIOwBkYdo1525NU7kkTmtrMpgM+SXQsHTJn TB9uQnyuiq5/znh3k1Qn+OGwXQezmGz2Fb76IcW5RzUQDew6n6b3kzILee5ddynT Pa7/ibwpV+FtZjm2kS/l4tV+WPdA+s5TSWoq7Hz0jzBX9GdOORcMZmEneg== =z16d -----END PGP SIGNATURE----- Merge tag 'platform-drivers-x86-v6.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86 Pull x86 platform driver updates from Hans de Goede: - Intel: - PMC: Add support for Meteor Lake - Intel On Demand: various updates - Ideapad-laptop: - Add support for various Fn keys on new models - Fix touchpad on/off handling in a generic way to avoid having to add more and more quirks - Android x86 tablets: - Add support for two more X86 Android tablet models - New Dell WMI DDV driver - Miscellaneous cleanups and small bugfixes * tag 'platform-drivers-x86-v6.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (52 commits) platform/mellanox: mlxbf-pmc: Fix event typo platform/x86: intel_scu_ipc: fix possible name leak in __intel_scu_ipc_register() platform/x86: sony-laptop: Convert to use sysfs_emit_at() API platform/x86/dell: alienware-wmi: Use sysfs_emit() instead of scnprintf() platform/x86: uv_sysfs: Use sysfs_emit() instead of scnprintf() platform/x86: mxm-wmi: fix memleak in mxm_wmi_call_mx[ds|mx]() platform/x86: x86-android-tablets: Add Advantech MICA-071 extra button platform/x86: x86-android-tablets: Add Lenovo Yoga Tab 3 (YT3-X90F) charger + fuel-gauge data platform/x86: x86-android-tablets: Add Medion Lifetab S10346 data platform/x86: wireless-hotkey: use ACPI HID as phys platform/x86/intel/hid: Add module-params for 5 button array + SW_TABLET_MODE reporting platform/x86: ideapad-laptop: Make touchpad_ctrl_via_ec a module option platform/x86: ideapad-laptop: Stop writing VPCCMD_W_TOUCHPAD at probe time platform/x86: ideapad-laptop: Send KEY_TOUCHPAD_TOGGLE on some models platform/x86: ideapad-laptop: Only toggle ps2 aux port on/off on select models platform/x86: ideapad-laptop: Do not send KEY_TOUCHPAD* events on probe / resume platform/x86: ideapad-laptop: Refactor ideapad_sync_touchpad_state() tools/arch/x86: intel_sdsi: Add support for reading meter certificates tools/arch/x86: intel_sdsi: Add support for new GUID tools/arch/x86: intel_sdsi: Read more On Demand registers ...
This commit is contained in:
commit
7a76117f9f
21
Documentation/ABI/testing/debugfs-dell-wmi-ddv
Normal file
21
Documentation/ABI/testing/debugfs-dell-wmi-ddv
Normal file
@ -0,0 +1,21 @@
|
||||
What: /sys/kernel/debug/dell-wmi-ddv-<wmi_device_name>/fan_sensor_information
|
||||
Date: September 2022
|
||||
KernelVersion: 6.1
|
||||
Contact: Armin Wolf <W_Armin@gmx.de>
|
||||
Description:
|
||||
This file contains the contents of the fan sensor information buffer,
|
||||
which contains fan sensor entries and a terminating character (0xFF).
|
||||
|
||||
Each fan sensor entry consists of three bytes with an unknown meaning,
|
||||
interested people may use this file for reverse-engineering.
|
||||
|
||||
What: /sys/kernel/debug/dell-wmi-ddv-<wmi_device_name>/thermal_sensor_information
|
||||
Date: September 2022
|
||||
KernelVersion: 6.1
|
||||
Contact: Armin Wolf <W_Armin@gmx.de>
|
||||
Description:
|
||||
This file contains the contents of the thermal sensor information buffer,
|
||||
which contains thermal sensor entries and a terminating character (0xFF).
|
||||
|
||||
Each thermal sensor entry consists of five bytes with an unknown meaning,
|
||||
interested people may use this file for reverse-engineering.
|
@ -4,21 +4,21 @@ KernelVersion: 5.18
|
||||
Contact: "David E. Box" <david.e.box@linux.intel.com>
|
||||
Description:
|
||||
This directory contains interface files for accessing Intel
|
||||
Software Defined Silicon (SDSi) features on a CPU. X
|
||||
represents the socket instance (though not the socket ID).
|
||||
The socket ID is determined by reading the registers file
|
||||
and decoding it per the specification.
|
||||
On Demand (formerly Software Defined Silicon or SDSi) features
|
||||
on a CPU. X represents the socket instance (though not the
|
||||
socket ID). The socket ID is determined by reading the
|
||||
registers file and decoding it per the specification.
|
||||
|
||||
Some files communicate with SDSi hardware through a mailbox.
|
||||
Should the operation fail, one of the following error codes
|
||||
may be returned:
|
||||
Some files communicate with On Demand hardware through a
|
||||
mailbox. Should the operation fail, one of the following error
|
||||
codes may be returned:
|
||||
|
||||
========== =====
|
||||
Error Code Cause
|
||||
========== =====
|
||||
EIO General mailbox failure. Log may indicate cause.
|
||||
EBUSY Mailbox is owned by another agent.
|
||||
EPERM SDSI capability is not enabled in hardware.
|
||||
EPERM On Demand capability is not enabled in hardware.
|
||||
EPROTO Failure in mailbox protocol detected by driver.
|
||||
See log for details.
|
||||
EOVERFLOW For provision commands, the size of the data
|
||||
@ -54,8 +54,8 @@ KernelVersion: 5.18
|
||||
Contact: "David E. Box" <david.e.box@linux.intel.com>
|
||||
Description:
|
||||
(WO) Used to write an Authentication Key Certificate (AKC) to
|
||||
the SDSi NVRAM for the CPU. The AKC is used to authenticate a
|
||||
Capability Activation Payload. Mailbox command.
|
||||
the On Demand NVRAM for the CPU. The AKC is used to authenticate
|
||||
a Capability Activation Payload. Mailbox command.
|
||||
|
||||
What: /sys/bus/auxiliary/devices/intel_vsec.sdsi.X/provision_cap
|
||||
Date: Feb 2022
|
||||
@ -63,17 +63,28 @@ KernelVersion: 5.18
|
||||
Contact: "David E. Box" <david.e.box@linux.intel.com>
|
||||
Description:
|
||||
(WO) Used to write a Capability Activation Payload (CAP) to the
|
||||
SDSi NVRAM for the CPU. CAPs are used to activate a given CPU
|
||||
feature. A CAP is validated by SDSi hardware using a previously
|
||||
provisioned AKC file. Upon successful authentication, the CPU
|
||||
configuration is updated. A cold reboot is required to fully
|
||||
activate the feature. Mailbox command.
|
||||
On Demand NVRAM for the CPU. CAPs are used to activate a given
|
||||
CPU feature. A CAP is validated by On Demand hardware using a
|
||||
previously provisioned AKC file. Upon successful authentication,
|
||||
the CPU configuration is updated. A cold reboot is required to
|
||||
fully activate the feature. Mailbox command.
|
||||
|
||||
What: /sys/bus/auxiliary/devices/intel_vsec.sdsi.X/meter_certificate
|
||||
Date: Nov 2022
|
||||
KernelVersion: 6.2
|
||||
Contact: "David E. Box" <david.e.box@linux.intel.com>
|
||||
Description:
|
||||
(RO) Used to read back the current meter certificate for the CPU
|
||||
from Intel On Demand hardware. The meter certificate contains
|
||||
utilization metrics of On Demand enabled features. Mailbox
|
||||
command.
|
||||
|
||||
What: /sys/bus/auxiliary/devices/intel_vsec.sdsi.X/state_certificate
|
||||
Date: Feb 2022
|
||||
KernelVersion: 5.18
|
||||
Contact: "David E. Box" <david.e.box@linux.intel.com>
|
||||
Description:
|
||||
(RO) Used to read back the current State Certificate for the CPU
|
||||
from SDSi hardware. The State Certificate contains information
|
||||
about the current licenses on the CPU. Mailbox command.
|
||||
(RO) Used to read back the current state certificate for the CPU
|
||||
from On Demand hardware. The state certificate contains
|
||||
information about the current licenses on the CPU. Mailbox
|
||||
command.
|
||||
|
7
Documentation/ABI/testing/sysfs-platform-dell-wmi-ddv
Normal file
7
Documentation/ABI/testing/sysfs-platform-dell-wmi-ddv
Normal file
@ -0,0 +1,7 @@
|
||||
What: /sys/class/power_supply/<battery_name>/eppid
|
||||
Date: September 2022
|
||||
KernelVersion: 6.1
|
||||
Contact: Armin Wolf <W_Armin@gmx.de>
|
||||
Description:
|
||||
Reports the Dell ePPID (electronic Dell Piece Part Identification)
|
||||
of the ACPI battery.
|
11
MAINTAINERS
11
MAINTAINERS
@ -5867,6 +5867,13 @@ L: Dell.Client.Kernel@dell.com
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/dell/dell-wmi-descriptor.c
|
||||
|
||||
DELL WMI DDV DRIVER
|
||||
M: Armin Wolf <W_Armin@gmx.de>
|
||||
S: Maintained
|
||||
F: Documentation/ABI/testing/debugfs-dell-wmi-ddv
|
||||
F: Documentation/ABI/testing/sysfs-platform-dell-wmi-ddv
|
||||
F: drivers/platform/x86/dell/dell-wmi-ddv.c
|
||||
|
||||
DELL WMI SYSMAN DRIVER
|
||||
M: Divya Bharathi <divya.bharathi@dell.com>
|
||||
M: Prasanth Ksr <prasanth.ksr@dell.com>
|
||||
@ -9376,7 +9383,7 @@ F: drivers/net/wireless/intersil/hostap/
|
||||
HP COMPAQ TC1100 TABLET WMI EXTRAS DRIVER
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Orphan
|
||||
F: drivers/platform/x86/tc1100-wmi.c
|
||||
F: drivers/platform/x86/hp/tc1100-wmi.c
|
||||
|
||||
HPET: High Precision Event Timers driver
|
||||
M: Clemens Ladisch <clemens@ladisch.de>
|
||||
@ -11870,7 +11877,7 @@ M: Eric Piel <eric.piel@tremplin-utc.net>
|
||||
S: Maintained
|
||||
F: Documentation/misc-devices/lis3lv02d.rst
|
||||
F: drivers/misc/lis3lv02d/
|
||||
F: drivers/platform/x86/hp_accel.c
|
||||
F: drivers/platform/x86/hp/hp_accel.c
|
||||
|
||||
LIST KUNIT TEST
|
||||
M: David Gow <davidgow@google.com>
|
||||
|
@ -696,7 +696,7 @@ static void __battery_hook_unregister(struct acpi_battery_hook *hook, int lock)
|
||||
if (lock)
|
||||
mutex_lock(&hook_mutex);
|
||||
list_for_each_entry(battery, &acpi_battery_list, list) {
|
||||
hook->remove_battery(battery->bat);
|
||||
hook->remove_battery(battery->bat, hook);
|
||||
}
|
||||
list_del(&hook->list);
|
||||
if (lock)
|
||||
@ -724,7 +724,7 @@ void battery_hook_register(struct acpi_battery_hook *hook)
|
||||
* its attributes.
|
||||
*/
|
||||
list_for_each_entry(battery, &acpi_battery_list, list) {
|
||||
if (hook->add_battery(battery->bat)) {
|
||||
if (hook->add_battery(battery->bat, hook)) {
|
||||
/*
|
||||
* If a add-battery returns non-zero,
|
||||
* the registration of the extension has failed,
|
||||
@ -762,7 +762,7 @@ static void battery_hook_add_battery(struct acpi_battery *battery)
|
||||
* during the battery module initialization.
|
||||
*/
|
||||
list_for_each_entry_safe(hook_node, tmp, &battery_hook_list, list) {
|
||||
if (hook_node->add_battery(battery->bat)) {
|
||||
if (hook_node->add_battery(battery->bat, hook_node)) {
|
||||
/*
|
||||
* The notification of the extensions has failed, to
|
||||
* prevent further errors we will unload the extension.
|
||||
@ -785,7 +785,7 @@ static void battery_hook_remove_battery(struct acpi_battery *battery)
|
||||
* custom attributes from the battery.
|
||||
*/
|
||||
list_for_each_entry(hook, &battery_hook_list, list) {
|
||||
hook->remove_battery(battery->bat);
|
||||
hook->remove_battery(battery->bat, hook);
|
||||
}
|
||||
/* Then, just remove the battery from the list */
|
||||
list_del(&battery->list);
|
||||
|
@ -358,7 +358,7 @@ static const struct mlxbf_pmc_events mlxbf_pmc_hnfnet_events[] = {
|
||||
{ 0x32, "DDN_DIAG_W_INGRESS" },
|
||||
{ 0x33, "DDN_DIAG_C_INGRESS" },
|
||||
{ 0x34, "DDN_DIAG_CORE_SENT" },
|
||||
{ 0x35, "NDN_DIAG_S_OUT_OF_CRED" },
|
||||
{ 0x35, "NDN_DIAG_N_OUT_OF_CRED" },
|
||||
{ 0x36, "NDN_DIAG_S_OUT_OF_CRED" },
|
||||
{ 0x37, "NDN_DIAG_E_OUT_OF_CRED" },
|
||||
{ 0x38, "NDN_DIAG_W_OUT_OF_CRED" },
|
||||
|
@ -60,4 +60,14 @@
|
||||
#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_RMASK GENMASK_ULL(8, 0)
|
||||
#define MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_MASK GENMASK_ULL(40, 32)
|
||||
|
||||
/* BF3 register offsets within resource 0. */
|
||||
#define MLXBF_TMFIFO_RX_DATA_BF3 0x0000
|
||||
#define MLXBF_TMFIFO_TX_DATA_BF3 0x1000
|
||||
|
||||
/* BF3 register offsets within resource 1. */
|
||||
#define MLXBF_TMFIFO_RX_STS_BF3 0x0000
|
||||
#define MLXBF_TMFIFO_RX_CTL_BF3 0x0008
|
||||
#define MLXBF_TMFIFO_TX_STS_BF3 0x0100
|
||||
#define MLXBF_TMFIFO_TX_CTL_BF3 0x0108
|
||||
|
||||
#endif /* !defined(__MLXBF_TMFIFO_REGS_H__) */
|
||||
|
@ -47,6 +47,9 @@
|
||||
/* Message with data needs at least two words (for header & data). */
|
||||
#define MLXBF_TMFIFO_DATA_MIN_WORDS 2
|
||||
|
||||
/* ACPI UID for BlueField-3. */
|
||||
#define TMFIFO_BF3_UID 1
|
||||
|
||||
struct mlxbf_tmfifo;
|
||||
|
||||
/**
|
||||
@ -136,12 +139,26 @@ struct mlxbf_tmfifo_irq_info {
|
||||
int index;
|
||||
};
|
||||
|
||||
/**
|
||||
* mlxbf_tmfifo_io - Structure of the TmFifo IO resource (for both rx & tx)
|
||||
* @ctl: control register offset (TMFIFO_RX_CTL / TMFIFO_TX_CTL)
|
||||
* @sts: status register offset (TMFIFO_RX_STS / TMFIFO_TX_STS)
|
||||
* @data: data register offset (TMFIFO_RX_DATA / TMFIFO_TX_DATA)
|
||||
*/
|
||||
struct mlxbf_tmfifo_io {
|
||||
void __iomem *ctl;
|
||||
void __iomem *sts;
|
||||
void __iomem *data;
|
||||
};
|
||||
|
||||
/**
|
||||
* mlxbf_tmfifo - Structure of the TmFifo
|
||||
* @vdev: array of the virtual devices running over the TmFifo
|
||||
* @lock: lock to protect the TmFifo access
|
||||
* @rx_base: mapped register base address for the Rx FIFO
|
||||
* @tx_base: mapped register base address for the Tx FIFO
|
||||
* @res0: mapped resource block 0
|
||||
* @res1: mapped resource block 1
|
||||
* @rx: rx io resource
|
||||
* @tx: tx io resource
|
||||
* @rx_fifo_size: number of entries of the Rx FIFO
|
||||
* @tx_fifo_size: number of entries of the Tx FIFO
|
||||
* @pend_events: pending bits for deferred events
|
||||
@ -155,8 +172,10 @@ struct mlxbf_tmfifo_irq_info {
|
||||
struct mlxbf_tmfifo {
|
||||
struct mlxbf_tmfifo_vdev *vdev[MLXBF_TMFIFO_VDEV_MAX];
|
||||
struct mutex lock; /* TmFifo lock */
|
||||
void __iomem *rx_base;
|
||||
void __iomem *tx_base;
|
||||
void __iomem *res0;
|
||||
void __iomem *res1;
|
||||
struct mlxbf_tmfifo_io rx;
|
||||
struct mlxbf_tmfifo_io tx;
|
||||
int rx_fifo_size;
|
||||
int tx_fifo_size;
|
||||
unsigned long pend_events;
|
||||
@ -472,7 +491,7 @@ static int mlxbf_tmfifo_get_rx_avail(struct mlxbf_tmfifo *fifo)
|
||||
{
|
||||
u64 sts;
|
||||
|
||||
sts = readq(fifo->rx_base + MLXBF_TMFIFO_RX_STS);
|
||||
sts = readq(fifo->rx.sts);
|
||||
return FIELD_GET(MLXBF_TMFIFO_RX_STS__COUNT_MASK, sts);
|
||||
}
|
||||
|
||||
@ -489,7 +508,7 @@ static int mlxbf_tmfifo_get_tx_avail(struct mlxbf_tmfifo *fifo, int vdev_id)
|
||||
else
|
||||
tx_reserve = 1;
|
||||
|
||||
sts = readq(fifo->tx_base + MLXBF_TMFIFO_TX_STS);
|
||||
sts = readq(fifo->tx.sts);
|
||||
count = FIELD_GET(MLXBF_TMFIFO_TX_STS__COUNT_MASK, sts);
|
||||
return fifo->tx_fifo_size - tx_reserve - count;
|
||||
}
|
||||
@ -525,7 +544,7 @@ static void mlxbf_tmfifo_console_tx(struct mlxbf_tmfifo *fifo, int avail)
|
||||
/* Write header. */
|
||||
hdr.type = VIRTIO_ID_CONSOLE;
|
||||
hdr.len = htons(size);
|
||||
writeq(*(u64 *)&hdr, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
|
||||
writeq(*(u64 *)&hdr, fifo->tx.data);
|
||||
|
||||
/* Use spin-lock to protect the 'cons->tx_buf'. */
|
||||
spin_lock_irqsave(&fifo->spin_lock[0], flags);
|
||||
@ -542,7 +561,7 @@ static void mlxbf_tmfifo_console_tx(struct mlxbf_tmfifo *fifo, int avail)
|
||||
memcpy((u8 *)&data + seg, cons->tx_buf.buf,
|
||||
sizeof(u64) - seg);
|
||||
}
|
||||
writeq(data, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
|
||||
writeq(data, fifo->tx.data);
|
||||
|
||||
if (size >= sizeof(u64)) {
|
||||
cons->tx_buf.tail = (cons->tx_buf.tail + sizeof(u64)) %
|
||||
@ -573,7 +592,7 @@ static void mlxbf_tmfifo_rxtx_word(struct mlxbf_tmfifo_vring *vring,
|
||||
|
||||
/* Read a word from FIFO for Rx. */
|
||||
if (is_rx)
|
||||
data = readq(fifo->rx_base + MLXBF_TMFIFO_RX_DATA);
|
||||
data = readq(fifo->rx.data);
|
||||
|
||||
if (vring->cur_len + sizeof(u64) <= len) {
|
||||
/* The whole word. */
|
||||
@ -595,7 +614,7 @@ static void mlxbf_tmfifo_rxtx_word(struct mlxbf_tmfifo_vring *vring,
|
||||
|
||||
/* Write the word into FIFO for Tx. */
|
||||
if (!is_rx)
|
||||
writeq(data, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
|
||||
writeq(data, fifo->tx.data);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -617,7 +636,7 @@ static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring,
|
||||
/* Read/Write packet header. */
|
||||
if (is_rx) {
|
||||
/* Drain one word from the FIFO. */
|
||||
*(u64 *)&hdr = readq(fifo->rx_base + MLXBF_TMFIFO_RX_DATA);
|
||||
*(u64 *)&hdr = readq(fifo->rx.data);
|
||||
|
||||
/* Skip the length 0 packets (keepalive). */
|
||||
if (hdr.len == 0)
|
||||
@ -661,7 +680,7 @@ static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring,
|
||||
hdr.type = (vring->vdev_id == VIRTIO_ID_NET) ?
|
||||
VIRTIO_ID_NET : VIRTIO_ID_CONSOLE;
|
||||
hdr.len = htons(vring->pkt_len - hdr_len);
|
||||
writeq(*(u64 *)&hdr, fifo->tx_base + MLXBF_TMFIFO_TX_DATA);
|
||||
writeq(*(u64 *)&hdr, fifo->tx.data);
|
||||
}
|
||||
|
||||
vring->cur_len = hdr_len;
|
||||
@ -1157,7 +1176,7 @@ static void mlxbf_tmfifo_set_threshold(struct mlxbf_tmfifo *fifo)
|
||||
u64 ctl;
|
||||
|
||||
/* Get Tx FIFO size and set the low/high watermark. */
|
||||
ctl = readq(fifo->tx_base + MLXBF_TMFIFO_TX_CTL);
|
||||
ctl = readq(fifo->tx.ctl);
|
||||
fifo->tx_fifo_size =
|
||||
FIELD_GET(MLXBF_TMFIFO_TX_CTL__MAX_ENTRIES_MASK, ctl);
|
||||
ctl = (ctl & ~MLXBF_TMFIFO_TX_CTL__LWM_MASK) |
|
||||
@ -1166,17 +1185,17 @@ static void mlxbf_tmfifo_set_threshold(struct mlxbf_tmfifo *fifo)
|
||||
ctl = (ctl & ~MLXBF_TMFIFO_TX_CTL__HWM_MASK) |
|
||||
FIELD_PREP(MLXBF_TMFIFO_TX_CTL__HWM_MASK,
|
||||
fifo->tx_fifo_size - 1);
|
||||
writeq(ctl, fifo->tx_base + MLXBF_TMFIFO_TX_CTL);
|
||||
writeq(ctl, fifo->tx.ctl);
|
||||
|
||||
/* Get Rx FIFO size and set the low/high watermark. */
|
||||
ctl = readq(fifo->rx_base + MLXBF_TMFIFO_RX_CTL);
|
||||
ctl = readq(fifo->rx.ctl);
|
||||
fifo->rx_fifo_size =
|
||||
FIELD_GET(MLXBF_TMFIFO_RX_CTL__MAX_ENTRIES_MASK, ctl);
|
||||
ctl = (ctl & ~MLXBF_TMFIFO_RX_CTL__LWM_MASK) |
|
||||
FIELD_PREP(MLXBF_TMFIFO_RX_CTL__LWM_MASK, 0);
|
||||
ctl = (ctl & ~MLXBF_TMFIFO_RX_CTL__HWM_MASK) |
|
||||
FIELD_PREP(MLXBF_TMFIFO_RX_CTL__HWM_MASK, 1);
|
||||
writeq(ctl, fifo->rx_base + MLXBF_TMFIFO_RX_CTL);
|
||||
writeq(ctl, fifo->rx.ctl);
|
||||
}
|
||||
|
||||
static void mlxbf_tmfifo_cleanup(struct mlxbf_tmfifo *fifo)
|
||||
@ -1197,8 +1216,15 @@ static int mlxbf_tmfifo_probe(struct platform_device *pdev)
|
||||
struct virtio_net_config net_config;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mlxbf_tmfifo *fifo;
|
||||
u64 dev_id;
|
||||
int i, rc;
|
||||
|
||||
rc = acpi_dev_uid_to_integer(ACPI_COMPANION(dev), &dev_id);
|
||||
if (rc) {
|
||||
dev_err(dev, "Cannot retrieve UID\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
fifo = devm_kzalloc(dev, sizeof(*fifo), GFP_KERNEL);
|
||||
if (!fifo)
|
||||
return -ENOMEM;
|
||||
@ -1209,14 +1235,30 @@ static int mlxbf_tmfifo_probe(struct platform_device *pdev)
|
||||
mutex_init(&fifo->lock);
|
||||
|
||||
/* Get the resource of the Rx FIFO. */
|
||||
fifo->rx_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(fifo->rx_base))
|
||||
return PTR_ERR(fifo->rx_base);
|
||||
fifo->res0 = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(fifo->res0))
|
||||
return PTR_ERR(fifo->res0);
|
||||
|
||||
/* Get the resource of the Tx FIFO. */
|
||||
fifo->tx_base = devm_platform_ioremap_resource(pdev, 1);
|
||||
if (IS_ERR(fifo->tx_base))
|
||||
return PTR_ERR(fifo->tx_base);
|
||||
fifo->res1 = devm_platform_ioremap_resource(pdev, 1);
|
||||
if (IS_ERR(fifo->res1))
|
||||
return PTR_ERR(fifo->res1);
|
||||
|
||||
if (dev_id == TMFIFO_BF3_UID) {
|
||||
fifo->rx.ctl = fifo->res1 + MLXBF_TMFIFO_RX_CTL_BF3;
|
||||
fifo->rx.sts = fifo->res1 + MLXBF_TMFIFO_RX_STS_BF3;
|
||||
fifo->rx.data = fifo->res0 + MLXBF_TMFIFO_RX_DATA_BF3;
|
||||
fifo->tx.ctl = fifo->res1 + MLXBF_TMFIFO_TX_CTL_BF3;
|
||||
fifo->tx.sts = fifo->res1 + MLXBF_TMFIFO_TX_STS_BF3;
|
||||
fifo->tx.data = fifo->res0 + MLXBF_TMFIFO_TX_DATA_BF3;
|
||||
} else {
|
||||
fifo->rx.ctl = fifo->res0 + MLXBF_TMFIFO_RX_CTL;
|
||||
fifo->rx.sts = fifo->res0 + MLXBF_TMFIFO_RX_STS;
|
||||
fifo->rx.data = fifo->res0 + MLXBF_TMFIFO_RX_DATA;
|
||||
fifo->tx.ctl = fifo->res1 + MLXBF_TMFIFO_TX_CTL;
|
||||
fifo->tx.sts = fifo->res1 + MLXBF_TMFIFO_TX_STS;
|
||||
fifo->tx.data = fifo->res1 + MLXBF_TMFIFO_TX_DATA;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, fifo);
|
||||
|
||||
|
@ -424,24 +424,7 @@ config GPD_POCKET_FAN
|
||||
of the CPU temperature. Say Y or M if the kernel may be used on a
|
||||
GPD pocket.
|
||||
|
||||
config HP_ACCEL
|
||||
tristate "HP laptop accelerometer"
|
||||
depends on INPUT && ACPI
|
||||
depends on SERIO_I8042
|
||||
select SENSORS_LIS3LV02D
|
||||
select NEW_LEDS
|
||||
select LEDS_CLASS
|
||||
help
|
||||
This driver provides support for the "Mobile Data Protection System 3D"
|
||||
or "3D DriveGuard" feature of HP laptops. On such systems the driver
|
||||
should load automatically (via ACPI alias).
|
||||
|
||||
Support for a led indicating disk protection will be provided as
|
||||
hp::hddprotect. For more information on the feature, refer to
|
||||
Documentation/misc-devices/lis3lv02d.rst.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called hp_accel.
|
||||
source "drivers/platform/x86/hp/Kconfig"
|
||||
|
||||
config WIRELESS_HOTKEY
|
||||
tristate "Wireless hotkey button"
|
||||
@ -455,30 +438,6 @@ config WIRELESS_HOTKEY
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called wireless-hotkey.
|
||||
|
||||
config HP_WMI
|
||||
tristate "HP WMI extras"
|
||||
depends on ACPI_WMI
|
||||
depends on INPUT
|
||||
depends on RFKILL || RFKILL = n
|
||||
select INPUT_SPARSEKMAP
|
||||
select ACPI_PLATFORM_PROFILE
|
||||
select HWMON
|
||||
help
|
||||
Say Y here if you want to support WMI-based hotkeys on HP laptops and
|
||||
to read data from WMI such as docking or ambient light sensor state.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called hp-wmi.
|
||||
|
||||
config TC1100_WMI
|
||||
tristate "HP Compaq TC1100 Tablet WMI Extras"
|
||||
depends on !X86_64
|
||||
depends on ACPI
|
||||
depends on ACPI_WMI
|
||||
help
|
||||
This is a driver for the WMI extensions (wireless and bluetooth power
|
||||
control) of the HP Compaq TC1100 tablet.
|
||||
|
||||
config IBM_RTL
|
||||
tristate "Device driver to enable PRTL support"
|
||||
depends on PCI
|
||||
|
@ -55,9 +55,7 @@ obj-$(CONFIG_FUJITSU_TABLET) += fujitsu-tablet.o
|
||||
obj-$(CONFIG_GPD_POCKET_FAN) += gpd-pocket-fan.o
|
||||
|
||||
# Hewlett Packard
|
||||
obj-$(CONFIG_HP_ACCEL) += hp_accel.o
|
||||
obj-$(CONFIG_HP_WMI) += hp-wmi.o
|
||||
obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
|
||||
obj-$(CONFIG_X86_PLATFORM_DRIVERS_HP) += hp/
|
||||
|
||||
# Hewlett Packard Enterprise
|
||||
obj-$(CONFIG_UV_SYSFS) += uv_sysfs.o
|
||||
|
@ -158,100 +158,100 @@ int amd_pmf_trans_cnqf(struct amd_pmf_dev *dev, int socket_power, ktime_t time_l
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amd_pmf_update_trans_data(int idx, struct apmf_dyn_slider_output out)
|
||||
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->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->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->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->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->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->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)
|
||||
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_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];
|
||||
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;
|
||||
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_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];
|
||||
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;
|
||||
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_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];
|
||||
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;
|
||||
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_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];
|
||||
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;
|
||||
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)
|
||||
@ -284,8 +284,8 @@ static int amd_pmf_load_defaults_cnqf(struct amd_pmf_dev *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
amd_pmf_update_mode_set(i, out);
|
||||
amd_pmf_update_trans_data(i, out);
|
||||
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++) {
|
||||
|
@ -883,7 +883,7 @@ static ssize_t charge_control_end_threshold_show(struct device *device,
|
||||
|
||||
static DEVICE_ATTR_RW(charge_control_end_threshold);
|
||||
|
||||
static int asus_wmi_battery_add(struct power_supply *battery)
|
||||
static int asus_wmi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
|
||||
{
|
||||
/* The WMI method does not provide a way to specific a battery, so we
|
||||
* just assume it is the first battery.
|
||||
@ -910,7 +910,7 @@ static int asus_wmi_battery_add(struct power_supply *battery)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int asus_wmi_battery_remove(struct power_supply *battery)
|
||||
static int asus_wmi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook)
|
||||
{
|
||||
device_remove_file(&battery->dev,
|
||||
&dev_attr_charge_control_end_threshold);
|
||||
|
@ -189,6 +189,19 @@ config DELL_WMI_DESCRIPTOR
|
||||
default n
|
||||
depends on ACPI_WMI
|
||||
|
||||
config DELL_WMI_DDV
|
||||
tristate "Dell WMI sensors Support"
|
||||
default m
|
||||
depends on ACPI_BATTERY
|
||||
depends on ACPI_WMI
|
||||
help
|
||||
This option adds support for WMI-based sensors like
|
||||
battery temperature sensors found on some Dell notebooks.
|
||||
It also supports reading of the battery ePPID.
|
||||
|
||||
To compile this drivers as a module, choose M here: the module will
|
||||
be called dell-wmi-ddv.
|
||||
|
||||
config DELL_WMI_LED
|
||||
tristate "External LED on Dell Business Netbooks"
|
||||
default m
|
||||
|
@ -19,5 +19,6 @@ dell-wmi-objs := dell-wmi-base.o
|
||||
dell-wmi-$(CONFIG_DELL_WMI_PRIVACY) += dell-wmi-privacy.o
|
||||
obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o
|
||||
obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o
|
||||
obj-$(CONFIG_DELL_WMI_DDV) += dell-wmi-ddv.o
|
||||
obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o
|
||||
obj-$(CONFIG_DELL_WMI_SYSMAN) += dell-wmi-sysman/
|
||||
|
@ -398,10 +398,10 @@ static ssize_t show_control_state(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
if (lighting_control_state == LEGACY_BOOTING)
|
||||
return scnprintf(buf, PAGE_SIZE, "[booting] running suspend\n");
|
||||
return sysfs_emit(buf, "[booting] running suspend\n");
|
||||
else if (lighting_control_state == LEGACY_SUSPEND)
|
||||
return scnprintf(buf, PAGE_SIZE, "booting running [suspend]\n");
|
||||
return scnprintf(buf, PAGE_SIZE, "booting [running] suspend\n");
|
||||
return sysfs_emit(buf, "booting running [suspend]\n");
|
||||
return sysfs_emit(buf, "booting [running] suspend\n");
|
||||
}
|
||||
|
||||
static ssize_t store_control_state(struct device *dev,
|
||||
@ -547,14 +547,12 @@ static ssize_t show_hdmi_cable(struct device *dev,
|
||||
(u32 *) &out_data);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
if (out_data == 0)
|
||||
return scnprintf(buf, PAGE_SIZE,
|
||||
"[unconnected] connected unknown\n");
|
||||
return sysfs_emit(buf, "[unconnected] connected unknown\n");
|
||||
else if (out_data == 1)
|
||||
return scnprintf(buf, PAGE_SIZE,
|
||||
"unconnected [connected] unknown\n");
|
||||
return sysfs_emit(buf, "unconnected [connected] unknown\n");
|
||||
}
|
||||
pr_err("alienware-wmi: unknown HDMI cable status: %d\n", status);
|
||||
return scnprintf(buf, PAGE_SIZE, "unconnected connected [unknown]\n");
|
||||
return sysfs_emit(buf, "unconnected connected [unknown]\n");
|
||||
}
|
||||
|
||||
static ssize_t show_hdmi_source(struct device *dev,
|
||||
@ -571,14 +569,12 @@ static ssize_t show_hdmi_source(struct device *dev,
|
||||
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
if (out_data == 1)
|
||||
return scnprintf(buf, PAGE_SIZE,
|
||||
"[input] gpu unknown\n");
|
||||
return sysfs_emit(buf, "[input] gpu unknown\n");
|
||||
else if (out_data == 2)
|
||||
return scnprintf(buf, PAGE_SIZE,
|
||||
"input [gpu] unknown\n");
|
||||
return sysfs_emit(buf, "input [gpu] unknown\n");
|
||||
}
|
||||
pr_err("alienware-wmi: unknown HDMI source status: %u\n", status);
|
||||
return scnprintf(buf, PAGE_SIZE, "input gpu [unknown]\n");
|
||||
return sysfs_emit(buf, "input gpu [unknown]\n");
|
||||
}
|
||||
|
||||
static ssize_t toggle_hdmi_source(struct device *dev,
|
||||
@ -652,14 +648,12 @@ static ssize_t show_amplifier_status(struct device *dev,
|
||||
(u32 *) &out_data);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
if (out_data == 0)
|
||||
return scnprintf(buf, PAGE_SIZE,
|
||||
"[unconnected] connected unknown\n");
|
||||
return sysfs_emit(buf, "[unconnected] connected unknown\n");
|
||||
else if (out_data == 1)
|
||||
return scnprintf(buf, PAGE_SIZE,
|
||||
"unconnected [connected] unknown\n");
|
||||
return sysfs_emit(buf, "unconnected [connected] unknown\n");
|
||||
}
|
||||
pr_err("alienware-wmi: unknown amplifier cable status: %d\n", status);
|
||||
return scnprintf(buf, PAGE_SIZE, "unconnected connected [unknown]\n");
|
||||
return sysfs_emit(buf, "unconnected connected [unknown]\n");
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(status, S_IRUGO, show_amplifier_status, NULL);
|
||||
@ -706,17 +700,14 @@ static ssize_t show_deepsleep_status(struct device *dev,
|
||||
(u32 *) &out_data);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
if (out_data == 0)
|
||||
return scnprintf(buf, PAGE_SIZE,
|
||||
"[disabled] s5 s5_s4\n");
|
||||
return sysfs_emit(buf, "[disabled] s5 s5_s4\n");
|
||||
else if (out_data == 1)
|
||||
return scnprintf(buf, PAGE_SIZE,
|
||||
"disabled [s5] s5_s4\n");
|
||||
return sysfs_emit(buf, "disabled [s5] s5_s4\n");
|
||||
else if (out_data == 2)
|
||||
return scnprintf(buf, PAGE_SIZE,
|
||||
"disabled s5 [s5_s4]\n");
|
||||
return sysfs_emit(buf, "disabled s5 [s5_s4]\n");
|
||||
}
|
||||
pr_err("alienware-wmi: unknown deep sleep status: %d\n", status);
|
||||
return scnprintf(buf, PAGE_SIZE, "disabled s5 s5_s4 [unknown]\n");
|
||||
return sysfs_emit(buf, "disabled s5 s5_s4 [unknown]\n");
|
||||
}
|
||||
|
||||
static ssize_t toggle_deepsleep(struct device *dev,
|
||||
|
375
drivers/platform/x86/dell/dell-wmi-ddv.c
Normal file
375
drivers/platform/x86/dell/dell-wmi-ddv.c
Normal file
@ -0,0 +1,375 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Linux driver for WMI sensor information on Dell notebooks.
|
||||
*
|
||||
* Copyright (C) 2022 Armin Wolf <W_Armin@gmx.de>
|
||||
*/
|
||||
|
||||
#define pr_format(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kstrtox.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/wmi.h>
|
||||
|
||||
#include <acpi/battery.h>
|
||||
|
||||
#define DRIVER_NAME "dell-wmi-ddv"
|
||||
|
||||
#define DELL_DDV_SUPPORTED_INTERFACE 2
|
||||
#define DELL_DDV_GUID "8A42EA14-4F2A-FD45-6422-0087F7A7E608"
|
||||
|
||||
#define DELL_EPPID_LENGTH 20
|
||||
#define DELL_EPPID_EXT_LENGTH 23
|
||||
|
||||
enum dell_ddv_method {
|
||||
DELL_DDV_BATTERY_DESIGN_CAPACITY = 0x01,
|
||||
DELL_DDV_BATTERY_FULL_CHARGE_CAPACITY = 0x02,
|
||||
DELL_DDV_BATTERY_MANUFACTURE_NAME = 0x03,
|
||||
DELL_DDV_BATTERY_MANUFACTURE_DATE = 0x04,
|
||||
DELL_DDV_BATTERY_SERIAL_NUMBER = 0x05,
|
||||
DELL_DDV_BATTERY_CHEMISTRY_VALUE = 0x06,
|
||||
DELL_DDV_BATTERY_TEMPERATURE = 0x07,
|
||||
DELL_DDV_BATTERY_CURRENT = 0x08,
|
||||
DELL_DDV_BATTERY_VOLTAGE = 0x09,
|
||||
DELL_DDV_BATTERY_MANUFACTURER_ACCESS = 0x0A,
|
||||
DELL_DDV_BATTERY_RELATIVE_CHARGE_STATE = 0x0B,
|
||||
DELL_DDV_BATTERY_CYCLE_COUNT = 0x0C,
|
||||
DELL_DDV_BATTERY_EPPID = 0x0D,
|
||||
DELL_DDV_BATTERY_RAW_ANALYTICS_START = 0x0E,
|
||||
DELL_DDV_BATTERY_RAW_ANALYTICS = 0x0F,
|
||||
DELL_DDV_BATTERY_DESIGN_VOLTAGE = 0x10,
|
||||
|
||||
DELL_DDV_INTERFACE_VERSION = 0x12,
|
||||
|
||||
DELL_DDV_FAN_SENSOR_INFORMATION = 0x20,
|
||||
DELL_DDV_THERMAL_SENSOR_INFORMATION = 0x22,
|
||||
};
|
||||
|
||||
struct dell_wmi_ddv_data {
|
||||
struct acpi_battery_hook hook;
|
||||
struct device_attribute temp_attr;
|
||||
struct device_attribute eppid_attr;
|
||||
struct wmi_device *wdev;
|
||||
};
|
||||
|
||||
static int dell_wmi_ddv_query_type(struct wmi_device *wdev, enum dell_ddv_method method, u32 arg,
|
||||
union acpi_object **result, acpi_object_type type)
|
||||
{
|
||||
struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
const struct acpi_buffer in = {
|
||||
.length = sizeof(arg),
|
||||
.pointer = &arg,
|
||||
};
|
||||
union acpi_object *obj;
|
||||
acpi_status ret;
|
||||
|
||||
ret = wmidev_evaluate_method(wdev, 0x0, method, &in, &out);
|
||||
if (ACPI_FAILURE(ret))
|
||||
return -EIO;
|
||||
|
||||
obj = out.pointer;
|
||||
if (!obj)
|
||||
return -ENODATA;
|
||||
|
||||
if (obj->type != type) {
|
||||
kfree(obj);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
*result = obj;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_query_integer(struct wmi_device *wdev, enum dell_ddv_method method,
|
||||
u32 arg, u32 *res)
|
||||
{
|
||||
union acpi_object *obj;
|
||||
int ret;
|
||||
|
||||
ret = dell_wmi_ddv_query_type(wdev, method, arg, &obj, ACPI_TYPE_INTEGER);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (obj->integer.value <= U32_MAX)
|
||||
*res = (u32)obj->integer.value;
|
||||
else
|
||||
ret = -ERANGE;
|
||||
|
||||
kfree(obj);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_query_buffer(struct wmi_device *wdev, enum dell_ddv_method method,
|
||||
u32 arg, union acpi_object **result)
|
||||
{
|
||||
union acpi_object *obj;
|
||||
u64 buffer_size;
|
||||
int ret;
|
||||
|
||||
ret = dell_wmi_ddv_query_type(wdev, method, arg, &obj, ACPI_TYPE_PACKAGE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (obj->package.count != 2)
|
||||
goto err_free;
|
||||
|
||||
if (obj->package.elements[0].type != ACPI_TYPE_INTEGER)
|
||||
goto err_free;
|
||||
|
||||
buffer_size = obj->package.elements[0].integer.value;
|
||||
|
||||
if (obj->package.elements[1].type != ACPI_TYPE_BUFFER)
|
||||
goto err_free;
|
||||
|
||||
if (buffer_size > obj->package.elements[1].buffer.length) {
|
||||
dev_warn(&wdev->dev,
|
||||
FW_WARN "WMI buffer size (%llu) exceeds ACPI buffer size (%d)\n",
|
||||
buffer_size, obj->package.elements[1].buffer.length);
|
||||
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
*result = obj;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
kfree(obj);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_query_string(struct wmi_device *wdev, enum dell_ddv_method method,
|
||||
u32 arg, union acpi_object **result)
|
||||
{
|
||||
return dell_wmi_ddv_query_type(wdev, method, arg, result, ACPI_TYPE_STRING);
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_battery_index(struct acpi_device *acpi_dev, u32 *index)
|
||||
{
|
||||
const char *uid_str;
|
||||
|
||||
uid_str = acpi_device_uid(acpi_dev);
|
||||
if (!uid_str)
|
||||
return -ENODEV;
|
||||
|
||||
return kstrtou32(uid_str, 10, index);
|
||||
}
|
||||
|
||||
static ssize_t temp_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct dell_wmi_ddv_data *data = container_of(attr, struct dell_wmi_ddv_data, temp_attr);
|
||||
u32 index, value;
|
||||
int ret;
|
||||
|
||||
ret = dell_wmi_ddv_battery_index(to_acpi_device(dev->parent), &index);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = dell_wmi_ddv_query_integer(data->wdev, DELL_DDV_BATTERY_TEMPERATURE, index, &value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%d\n", DIV_ROUND_CLOSEST(value, 10));
|
||||
}
|
||||
|
||||
static ssize_t eppid_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct dell_wmi_ddv_data *data = container_of(attr, struct dell_wmi_ddv_data, eppid_attr);
|
||||
union acpi_object *obj;
|
||||
u32 index;
|
||||
int ret;
|
||||
|
||||
ret = dell_wmi_ddv_battery_index(to_acpi_device(dev->parent), &index);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = dell_wmi_ddv_query_string(data->wdev, DELL_DDV_BATTERY_EPPID, index, &obj);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (obj->string.length != DELL_EPPID_LENGTH && obj->string.length != DELL_EPPID_EXT_LENGTH)
|
||||
dev_info_once(&data->wdev->dev, FW_INFO "Suspicious ePPID length (%d)\n",
|
||||
obj->string.length);
|
||||
|
||||
ret = sysfs_emit(buf, "%s\n", obj->string.pointer);
|
||||
|
||||
kfree(obj);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
|
||||
{
|
||||
struct dell_wmi_ddv_data *data = container_of(hook, struct dell_wmi_ddv_data, hook);
|
||||
u32 index;
|
||||
int ret;
|
||||
|
||||
/* Return 0 instead of error to avoid being unloaded */
|
||||
ret = dell_wmi_ddv_battery_index(to_acpi_device(battery->dev.parent), &index);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
|
||||
ret = device_create_file(&battery->dev, &data->temp_attr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = device_create_file(&battery->dev, &data->eppid_attr);
|
||||
if (ret < 0) {
|
||||
device_remove_file(&battery->dev, &data->temp_attr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
|
||||
{
|
||||
struct dell_wmi_ddv_data *data = container_of(hook, struct dell_wmi_ddv_data, hook);
|
||||
|
||||
device_remove_file(&battery->dev, &data->temp_attr);
|
||||
device_remove_file(&battery->dev, &data->eppid_attr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dell_wmi_ddv_battery_remove(void *data)
|
||||
{
|
||||
struct acpi_battery_hook *hook = data;
|
||||
|
||||
battery_hook_unregister(hook);
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_battery_add(struct dell_wmi_ddv_data *data)
|
||||
{
|
||||
data->hook.name = "Dell DDV Battery Extension";
|
||||
data->hook.add_battery = dell_wmi_ddv_add_battery;
|
||||
data->hook.remove_battery = dell_wmi_ddv_remove_battery;
|
||||
|
||||
sysfs_attr_init(&data->temp_attr.attr);
|
||||
data->temp_attr.attr.name = "temp";
|
||||
data->temp_attr.attr.mode = 0444;
|
||||
data->temp_attr.show = temp_show;
|
||||
|
||||
sysfs_attr_init(&data->eppid_attr.attr);
|
||||
data->eppid_attr.attr.name = "eppid";
|
||||
data->eppid_attr.attr.mode = 0444;
|
||||
data->eppid_attr.show = eppid_show;
|
||||
|
||||
battery_hook_register(&data->hook);
|
||||
|
||||
return devm_add_action_or_reset(&data->wdev->dev, dell_wmi_ddv_battery_remove, &data->hook);
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_buffer_read(struct seq_file *seq, enum dell_ddv_method method)
|
||||
{
|
||||
struct device *dev = seq->private;
|
||||
struct dell_wmi_ddv_data *data = dev_get_drvdata(dev);
|
||||
union acpi_object *obj;
|
||||
u64 size;
|
||||
u8 *buf;
|
||||
int ret;
|
||||
|
||||
ret = dell_wmi_ddv_query_buffer(data->wdev, method, 0, &obj);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
size = obj->package.elements[0].integer.value;
|
||||
buf = obj->package.elements[1].buffer.pointer;
|
||||
ret = seq_write(seq, buf, size);
|
||||
kfree(obj);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_fan_read(struct seq_file *seq, void *offset)
|
||||
{
|
||||
return dell_wmi_ddv_buffer_read(seq, DELL_DDV_FAN_SENSOR_INFORMATION);
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_temp_read(struct seq_file *seq, void *offset)
|
||||
{
|
||||
return dell_wmi_ddv_buffer_read(seq, DELL_DDV_THERMAL_SENSOR_INFORMATION);
|
||||
}
|
||||
|
||||
static void dell_wmi_ddv_debugfs_remove(void *data)
|
||||
{
|
||||
struct dentry *entry = data;
|
||||
|
||||
debugfs_remove(entry);
|
||||
}
|
||||
|
||||
static void dell_wmi_ddv_debugfs_init(struct wmi_device *wdev)
|
||||
{
|
||||
struct dentry *entry;
|
||||
char name[64];
|
||||
|
||||
scnprintf(name, ARRAY_SIZE(name), "%s-%s", DRIVER_NAME, dev_name(&wdev->dev));
|
||||
entry = debugfs_create_dir(name, NULL);
|
||||
|
||||
debugfs_create_devm_seqfile(&wdev->dev, "fan_sensor_information", entry,
|
||||
dell_wmi_ddv_fan_read);
|
||||
debugfs_create_devm_seqfile(&wdev->dev, "thermal_sensor_information", entry,
|
||||
dell_wmi_ddv_temp_read);
|
||||
|
||||
devm_add_action_or_reset(&wdev->dev, dell_wmi_ddv_debugfs_remove, entry);
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_probe(struct wmi_device *wdev, const void *context)
|
||||
{
|
||||
struct dell_wmi_ddv_data *data;
|
||||
u32 version;
|
||||
int ret;
|
||||
|
||||
ret = dell_wmi_ddv_query_integer(wdev, DELL_DDV_INTERFACE_VERSION, 0, &version);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev_dbg(&wdev->dev, "WMI interface version: %d\n", version);
|
||||
if (version != DELL_DDV_SUPPORTED_INTERFACE)
|
||||
return -ENODEV;
|
||||
|
||||
data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(&wdev->dev, data);
|
||||
data->wdev = wdev;
|
||||
|
||||
dell_wmi_ddv_debugfs_init(wdev);
|
||||
|
||||
return dell_wmi_ddv_battery_add(data);
|
||||
}
|
||||
|
||||
static const struct wmi_device_id dell_wmi_ddv_id_table[] = {
|
||||
{ DELL_DDV_GUID, NULL },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(wmi, dell_wmi_ddv_id_table);
|
||||
|
||||
static struct wmi_driver dell_wmi_ddv_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
},
|
||||
.id_table = dell_wmi_ddv_id_table,
|
||||
.probe = dell_wmi_ddv_probe,
|
||||
};
|
||||
module_wmi_driver(dell_wmi_ddv_driver);
|
||||
|
||||
MODULE_AUTHOR("Armin Wolf <W_Armin@gmx.de>");
|
||||
MODULE_DESCRIPTION("Dell WMI sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
63
drivers/platform/x86/hp/Kconfig
Normal file
63
drivers/platform/x86/hp/Kconfig
Normal file
@ -0,0 +1,63 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
#
|
||||
# X86 Platform Specific Drivers
|
||||
#
|
||||
menuconfig X86_PLATFORM_DRIVERS_HP
|
||||
bool "HP X86 Platform Specific Device Drivers"
|
||||
depends on X86_PLATFORM_DEVICES
|
||||
help
|
||||
Say Y here to get to see options for device drivers for various
|
||||
HP x86 platforms, including vendor-specific laptop extension drivers.
|
||||
This option alone does not add any kernel code.
|
||||
|
||||
If you say N, all options in this submenu will be skipped and disabled.
|
||||
|
||||
if X86_PLATFORM_DRIVERS_HP
|
||||
|
||||
config HP_ACCEL
|
||||
tristate "HP laptop accelerometer"
|
||||
default m
|
||||
depends on INPUT && ACPI
|
||||
depends on SERIO_I8042
|
||||
select SENSORS_LIS3LV02D
|
||||
select NEW_LEDS
|
||||
select LEDS_CLASS
|
||||
help
|
||||
This driver provides support for the "Mobile Data Protection System 3D"
|
||||
or "3D DriveGuard" feature of HP laptops. On such systems the driver
|
||||
should load automatically (via ACPI alias).
|
||||
|
||||
Support for a led indicating disk protection will be provided as
|
||||
hp::hddprotect. For more information on the feature, refer to
|
||||
Documentation/misc-devices/lis3lv02d.rst.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called hp_accel.
|
||||
|
||||
config HP_WMI
|
||||
tristate "HP WMI extras"
|
||||
default m
|
||||
depends on ACPI_WMI
|
||||
depends on INPUT
|
||||
depends on RFKILL || RFKILL = n
|
||||
select INPUT_SPARSEKMAP
|
||||
select ACPI_PLATFORM_PROFILE
|
||||
select HWMON
|
||||
help
|
||||
Say Y here if you want to support WMI-based hotkeys on HP laptops and
|
||||
to read data from WMI such as docking or ambient light sensor state.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called hp-wmi.
|
||||
|
||||
config TC1100_WMI
|
||||
tristate "HP Compaq TC1100 Tablet WMI Extras"
|
||||
default m
|
||||
depends on !X86_64
|
||||
depends on ACPI
|
||||
depends on ACPI_WMI
|
||||
help
|
||||
This is a driver for the WMI extensions (wireless and bluetooth power
|
||||
control) of the HP Compaq TC1100 tablet.
|
||||
|
||||
endif # X86_PLATFORM_DRIVERS_HP
|
10
drivers/platform/x86/hp/Makefile
Normal file
10
drivers/platform/x86/hp/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for linux/drivers/platform/x86/hp
|
||||
# HP x86 Platform-Specific Drivers
|
||||
#
|
||||
|
||||
# Hewlett Packard
|
||||
obj-$(CONFIG_HP_ACCEL) += hp_accel.o
|
||||
obj-$(CONFIG_HP_WMI) += hp-wmi.o
|
||||
obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
|
@ -26,7 +26,7 @@
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/i8042.h>
|
||||
#include <linux/serio.h>
|
||||
#include "../../misc/lis3lv02d/lis3lv02d.h"
|
||||
#include "../../../misc/lis3lv02d/lis3lv02d.h"
|
||||
|
||||
/* Delayed LEDs infrastructure ------------------------------------ */
|
||||
|
@ -63,7 +63,6 @@ struct huawei_wmi {
|
||||
bool fn_lock_available;
|
||||
|
||||
struct huawei_wmi_debug debug;
|
||||
struct input_dev *idev[2];
|
||||
struct led_classdev cdev;
|
||||
struct device *dev;
|
||||
|
||||
@ -323,12 +322,12 @@ static int huawei_wmi_battery_get(int *start, int *end)
|
||||
u8 ret[0x100];
|
||||
int err, i;
|
||||
|
||||
err = huawei_wmi_cmd(BATTERY_THRESH_GET, ret, 0x100);
|
||||
err = huawei_wmi_cmd(BATTERY_THRESH_GET, ret, sizeof(ret));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Find the last two non-zero values. Return status is ignored. */
|
||||
i = 0xff;
|
||||
i = ARRAY_SIZE(ret) - 1;
|
||||
do {
|
||||
if (start)
|
||||
*start = ret[i-1];
|
||||
@ -468,7 +467,7 @@ static DEVICE_ATTR_RW(charge_control_start_threshold);
|
||||
static DEVICE_ATTR_RW(charge_control_end_threshold);
|
||||
static DEVICE_ATTR_RW(charge_control_thresholds);
|
||||
|
||||
static int huawei_wmi_battery_add(struct power_supply *battery)
|
||||
static int huawei_wmi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
@ -483,7 +482,7 @@ static int huawei_wmi_battery_add(struct power_supply *battery)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int huawei_wmi_battery_remove(struct power_supply *battery)
|
||||
static int huawei_wmi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook)
|
||||
{
|
||||
device_remove_file(&battery->dev, &dev_attr_charge_control_start_threshold);
|
||||
device_remove_file(&battery->dev, &dev_attr_charge_control_end_threshold);
|
||||
@ -756,23 +755,34 @@ static void huawei_wmi_input_notify(u32 value, void *context)
|
||||
kfree(response.pointer);
|
||||
}
|
||||
|
||||
static int huawei_wmi_input_setup(struct device *dev,
|
||||
const char *guid,
|
||||
struct input_dev **idev)
|
||||
static int huawei_wmi_input_setup(struct device *dev, const char *guid)
|
||||
{
|
||||
*idev = devm_input_allocate_device(dev);
|
||||
if (!*idev)
|
||||
struct input_dev *idev;
|
||||
acpi_status status;
|
||||
int err;
|
||||
|
||||
idev = devm_input_allocate_device(dev);
|
||||
if (!idev)
|
||||
return -ENOMEM;
|
||||
|
||||
(*idev)->name = "Huawei WMI hotkeys";
|
||||
(*idev)->phys = "wmi/input0";
|
||||
(*idev)->id.bustype = BUS_HOST;
|
||||
(*idev)->dev.parent = dev;
|
||||
idev->name = "Huawei WMI hotkeys";
|
||||
idev->phys = "wmi/input0";
|
||||
idev->id.bustype = BUS_HOST;
|
||||
idev->dev.parent = dev;
|
||||
|
||||
return sparse_keymap_setup(*idev, huawei_wmi_keymap, NULL) ||
|
||||
input_register_device(*idev) ||
|
||||
wmi_install_notify_handler(guid, huawei_wmi_input_notify,
|
||||
*idev);
|
||||
err = sparse_keymap_setup(idev, huawei_wmi_keymap, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = input_register_device(idev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
status = wmi_install_notify_handler(guid, huawei_wmi_input_notify, idev);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void huawei_wmi_input_exit(struct device *dev, const char *guid)
|
||||
@ -797,17 +807,14 @@ static int huawei_wmi_probe(struct platform_device *pdev)
|
||||
huawei_wmi->dev = &pdev->dev;
|
||||
|
||||
while (*guid->guid_string) {
|
||||
struct input_dev *idev = *huawei_wmi->idev;
|
||||
|
||||
if (wmi_has_guid(guid->guid_string)) {
|
||||
err = huawei_wmi_input_setup(&pdev->dev, guid->guid_string, &idev);
|
||||
err = huawei_wmi_input_setup(&pdev->dev, guid->guid_string);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Failed to setup input on %s\n", guid->guid_string);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
idev++;
|
||||
guid++;
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/wmi.h>
|
||||
|
||||
#include <acpi/video.h>
|
||||
|
||||
@ -37,20 +38,23 @@
|
||||
|
||||
#define IDEAPAD_RFKILL_DEV_NUM 3
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI_WMI)
|
||||
static const char *const ideapad_wmi_fnesc_events[] = {
|
||||
"26CAB2E5-5CF1-46AE-AAC3-4A12B6BA50E6", /* Yoga 3 */
|
||||
"56322276-8493-4CE8-A783-98C991274F5E", /* Yoga 700 */
|
||||
"8FC0DE0C-B4E4-43FD-B0F3-8871711C1294", /* Legion 5 */
|
||||
};
|
||||
#endif
|
||||
|
||||
enum {
|
||||
CFG_CAP_BT_BIT = 16,
|
||||
CFG_CAP_3G_BIT = 17,
|
||||
CFG_CAP_WIFI_BIT = 18,
|
||||
CFG_CAP_CAM_BIT = 19,
|
||||
CFG_CAP_TOUCHPAD_BIT = 30,
|
||||
|
||||
/*
|
||||
* These are OnScreenDisplay support bits that can be useful to determine
|
||||
* whether a hotkey exists/should show OSD. But they aren't particularly
|
||||
* meaningful since they were introduced later, i.e. 2010 IdeaPads
|
||||
* don't have these, but they still have had OSD for hotkeys.
|
||||
*/
|
||||
CFG_OSD_NUMLK_BIT = 27,
|
||||
CFG_OSD_CAPSLK_BIT = 28,
|
||||
CFG_OSD_MICMUTE_BIT = 29,
|
||||
CFG_OSD_TOUCHPAD_BIT = 30,
|
||||
CFG_OSD_CAM_BIT = 31,
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -130,7 +134,7 @@ struct ideapad_private {
|
||||
struct ideapad_dytc_priv *dytc;
|
||||
struct dentry *debug;
|
||||
unsigned long cfg;
|
||||
const char *fnesc_guid;
|
||||
unsigned long r_touchpad_val;
|
||||
struct {
|
||||
bool conservation_mode : 1;
|
||||
bool dytc : 1;
|
||||
@ -140,6 +144,7 @@ struct ideapad_private {
|
||||
bool hw_rfkill_switch : 1;
|
||||
bool kbd_bl : 1;
|
||||
bool touchpad_ctrl_via_ec : 1;
|
||||
bool ctrl_ps2_aux_port : 1;
|
||||
bool usb_charging : 1;
|
||||
} features;
|
||||
struct {
|
||||
@ -171,6 +176,54 @@ MODULE_PARM_DESC(set_fn_lock_led,
|
||||
"Enable driver based updates of the fn-lock LED on fn-lock changes. "
|
||||
"If you need this please report this to: platform-driver-x86@vger.kernel.org");
|
||||
|
||||
static bool ctrl_ps2_aux_port;
|
||||
module_param(ctrl_ps2_aux_port, bool, 0444);
|
||||
MODULE_PARM_DESC(ctrl_ps2_aux_port,
|
||||
"Enable driver based PS/2 aux port en-/dis-abling on touchpad on/off toggle. "
|
||||
"If you need this please report this to: platform-driver-x86@vger.kernel.org");
|
||||
|
||||
static bool touchpad_ctrl_via_ec;
|
||||
module_param(touchpad_ctrl_via_ec, bool, 0444);
|
||||
MODULE_PARM_DESC(touchpad_ctrl_via_ec,
|
||||
"Enable registering a 'touchpad' sysfs-attribute which can be used to manually "
|
||||
"tell the EC to enable/disable the touchpad. This may not work on all models.");
|
||||
|
||||
/*
|
||||
* shared data
|
||||
*/
|
||||
|
||||
static struct ideapad_private *ideapad_shared;
|
||||
static DEFINE_MUTEX(ideapad_shared_mutex);
|
||||
|
||||
static int ideapad_shared_init(struct ideapad_private *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ideapad_shared_mutex);
|
||||
|
||||
if (!ideapad_shared) {
|
||||
ideapad_shared = priv;
|
||||
ret = 0;
|
||||
} else {
|
||||
dev_warn(&priv->adev->dev, "found multiple platform devices\n");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
mutex_unlock(&ideapad_shared_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ideapad_shared_exit(struct ideapad_private *priv)
|
||||
{
|
||||
mutex_lock(&ideapad_shared_mutex);
|
||||
|
||||
if (ideapad_shared == priv)
|
||||
ideapad_shared = NULL;
|
||||
|
||||
mutex_unlock(&ideapad_shared_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* ACPI Helpers
|
||||
*/
|
||||
@ -386,8 +439,19 @@ static int debugfs_cfg_show(struct seq_file *s, void *data)
|
||||
seq_puts(s, " wifi");
|
||||
if (test_bit(CFG_CAP_CAM_BIT, &priv->cfg))
|
||||
seq_puts(s, " camera");
|
||||
if (test_bit(CFG_CAP_TOUCHPAD_BIT, &priv->cfg))
|
||||
seq_puts(s, "\n");
|
||||
|
||||
seq_puts(s, "OSD support:");
|
||||
if (test_bit(CFG_OSD_NUMLK_BIT, &priv->cfg))
|
||||
seq_puts(s, " num-lock");
|
||||
if (test_bit(CFG_OSD_CAPSLK_BIT, &priv->cfg))
|
||||
seq_puts(s, " caps-lock");
|
||||
if (test_bit(CFG_OSD_MICMUTE_BIT, &priv->cfg))
|
||||
seq_puts(s, " mic-mute");
|
||||
if (test_bit(CFG_OSD_TOUCHPAD_BIT, &priv->cfg))
|
||||
seq_puts(s, " touchpad");
|
||||
if (test_bit(CFG_OSD_CAM_BIT, &priv->cfg))
|
||||
seq_puts(s, " camera");
|
||||
seq_puts(s, "\n");
|
||||
|
||||
seq_puts(s, "Graphics: ");
|
||||
@ -593,6 +657,8 @@ static ssize_t touchpad_show(struct device *dev,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
priv->r_touchpad_val = result;
|
||||
|
||||
return sysfs_emit(buf, "%d\n", !!result);
|
||||
}
|
||||
|
||||
@ -612,6 +678,8 @@ static ssize_t touchpad_store(struct device *dev,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
priv->r_touchpad_val = state;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -680,8 +748,7 @@ static umode_t ideapad_is_visible(struct kobject *kobj,
|
||||
else if (attr == &dev_attr_fn_lock.attr)
|
||||
supported = priv->features.fn_lock;
|
||||
else if (attr == &dev_attr_touchpad.attr)
|
||||
supported = priv->features.touchpad_ctrl_via_ec &&
|
||||
test_bit(CFG_CAP_TOUCHPAD_BIT, &priv->cfg);
|
||||
supported = priv->features.touchpad_ctrl_via_ec;
|
||||
else if (attr == &dev_attr_usb_charging.attr)
|
||||
supported = priv->features.usb_charging;
|
||||
|
||||
@ -1089,6 +1156,8 @@ static void ideapad_sysfs_exit(struct ideapad_private *priv)
|
||||
/*
|
||||
* input device
|
||||
*/
|
||||
#define IDEAPAD_WMI_KEY 0x100
|
||||
|
||||
static const struct key_entry ideapad_keymap[] = {
|
||||
{ KE_KEY, 6, { KEY_SWITCHVIDEOMODE } },
|
||||
{ KE_KEY, 7, { KEY_CAMERA } },
|
||||
@ -1101,7 +1170,30 @@ static const struct key_entry ideapad_keymap[] = {
|
||||
{ KE_KEY, 65, { KEY_PROG4 } },
|
||||
{ KE_KEY, 66, { KEY_TOUCHPAD_OFF } },
|
||||
{ KE_KEY, 67, { KEY_TOUCHPAD_ON } },
|
||||
{ KE_KEY, 68, { KEY_TOUCHPAD_TOGGLE } },
|
||||
{ KE_KEY, 128, { KEY_ESC } },
|
||||
|
||||
/*
|
||||
* WMI keys
|
||||
*/
|
||||
|
||||
/* FnLock (handled by the firmware) */
|
||||
{ KE_IGNORE, 0x02 | IDEAPAD_WMI_KEY },
|
||||
/* Esc (handled by the firmware) */
|
||||
{ KE_IGNORE, 0x03 | IDEAPAD_WMI_KEY },
|
||||
/* Customizable Lenovo Hotkey ("star" with 'S' inside) */
|
||||
{ KE_KEY, 0x01 | IDEAPAD_WMI_KEY, { KEY_FAVORITES } },
|
||||
/* Dark mode toggle */
|
||||
{ KE_KEY, 0x13 | IDEAPAD_WMI_KEY, { KEY_PROG1 } },
|
||||
/* Sound profile switch */
|
||||
{ KE_KEY, 0x12 | IDEAPAD_WMI_KEY, { KEY_PROG2 } },
|
||||
/* Lenovo Virtual Background application */
|
||||
{ KE_KEY, 0x28 | IDEAPAD_WMI_KEY, { KEY_PROG3 } },
|
||||
/* Lenovo Support */
|
||||
{ KE_KEY, 0x27 | IDEAPAD_WMI_KEY, { KEY_HELP } },
|
||||
/* Refresh Rate Toggle */
|
||||
{ KE_KEY, 0x0a | IDEAPAD_WMI_KEY, { KEY_DISPLAYTOGGLE } },
|
||||
|
||||
{ KE_END },
|
||||
};
|
||||
|
||||
@ -1414,26 +1506,41 @@ static void ideapad_kbd_bl_exit(struct ideapad_private *priv)
|
||||
/*
|
||||
* module init/exit
|
||||
*/
|
||||
static void ideapad_sync_touchpad_state(struct ideapad_private *priv)
|
||||
static void ideapad_sync_touchpad_state(struct ideapad_private *priv, bool send_events)
|
||||
{
|
||||
unsigned long value;
|
||||
|
||||
if (!priv->features.touchpad_ctrl_via_ec)
|
||||
return;
|
||||
unsigned char param;
|
||||
int ret;
|
||||
|
||||
/* Without reading from EC touchpad LED doesn't switch state */
|
||||
if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value)) {
|
||||
unsigned char param;
|
||||
/*
|
||||
* Some IdeaPads don't really turn off touchpad - they only
|
||||
* switch the LED state. We (de)activate KBC AUX port to turn
|
||||
* touchpad off and on. We send KEY_TOUCHPAD_OFF and
|
||||
* KEY_TOUCHPAD_ON to not to get out of sync with LED
|
||||
*/
|
||||
ret = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Some IdeaPads don't really turn off touchpad - they only
|
||||
* switch the LED state. We (de)activate KBC AUX port to turn
|
||||
* touchpad off and on. We send KEY_TOUCHPAD_OFF and
|
||||
* KEY_TOUCHPAD_ON to not to get out of sync with LED
|
||||
*/
|
||||
if (priv->features.ctrl_ps2_aux_port)
|
||||
i8042_command(¶m, value ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE);
|
||||
ideapad_input_report(priv, value ? 67 : 66);
|
||||
sysfs_notify(&priv->platform_device->dev.kobj, NULL, "touchpad");
|
||||
|
||||
if (send_events) {
|
||||
/*
|
||||
* On older models the EC controls the touchpad and toggles it
|
||||
* on/off itself, in this case we report KEY_TOUCHPAD_ON/_OFF.
|
||||
* If the EC did not toggle, report KEY_TOUCHPAD_TOGGLE.
|
||||
*/
|
||||
if (value != priv->r_touchpad_val) {
|
||||
ideapad_input_report(priv, value ? 67 : 66);
|
||||
sysfs_notify(&priv->platform_device->dev.kobj, NULL, "touchpad");
|
||||
} else {
|
||||
ideapad_input_report(priv, 68);
|
||||
}
|
||||
}
|
||||
|
||||
priv->r_touchpad_val = value;
|
||||
}
|
||||
|
||||
static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
|
||||
@ -1474,7 +1581,7 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
|
||||
ideapad_sync_rfk_state(priv);
|
||||
break;
|
||||
case 5:
|
||||
ideapad_sync_touchpad_state(priv);
|
||||
ideapad_sync_touchpad_state(priv, true);
|
||||
break;
|
||||
case 4:
|
||||
ideapad_backlight_notify_brightness(priv);
|
||||
@ -1505,33 +1612,6 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
|
||||
}
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI_WMI)
|
||||
static void ideapad_wmi_notify(u32 value, void *context)
|
||||
{
|
||||
struct ideapad_private *priv = context;
|
||||
unsigned long result;
|
||||
|
||||
switch (value) {
|
||||
case 128:
|
||||
ideapad_input_report(priv, value);
|
||||
break;
|
||||
case 208:
|
||||
if (!priv->features.set_fn_lock_led)
|
||||
break;
|
||||
|
||||
if (!eval_hals(priv->adev->handle, &result)) {
|
||||
bool state = test_bit(HALS_FNLOCK_STATE_BIT, &result);
|
||||
|
||||
exec_sals(priv->adev->handle, state ? SALS_FNLOCK_ON : SALS_FNLOCK_OFF);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dev_info(&priv->platform_device->dev,
|
||||
"Unknown WMI event: %u\n", value);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* On some models we need to call exec_sals(SALS_FNLOCK_ON/OFF) to set the LED */
|
||||
static const struct dmi_system_id set_fn_lock_led_list[] = {
|
||||
{
|
||||
@ -1563,19 +1643,18 @@ static const struct dmi_system_id hw_rfkill_list[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct dmi_system_id no_touchpad_switch_list[] = {
|
||||
/*
|
||||
* On some models the EC toggles the touchpad muted LED on touchpad toggle
|
||||
* hotkey presses, but the EC does not actually disable the touchpad itself.
|
||||
* On these models the driver needs to explicitly enable/disable the i8042
|
||||
* (PS/2) aux port.
|
||||
*/
|
||||
static const struct dmi_system_id ctrl_ps2_aux_port_list[] = {
|
||||
{
|
||||
.ident = "Lenovo Yoga 3 Pro 1370",
|
||||
/* Lenovo Ideapad Z570 */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 3"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "ZhaoYang K4e-IML",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "ZhaoYang K4e-IML"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Ideapad Z570"),
|
||||
},
|
||||
},
|
||||
{}
|
||||
@ -1590,14 +1669,9 @@ static void ideapad_check_features(struct ideapad_private *priv)
|
||||
set_fn_lock_led || dmi_check_system(set_fn_lock_led_list);
|
||||
priv->features.hw_rfkill_switch =
|
||||
hw_rfkill_switch || dmi_check_system(hw_rfkill_list);
|
||||
|
||||
/* Most ideapads with ELAN0634 touchpad don't use EC touchpad switch */
|
||||
if (acpi_dev_present("ELAN0634", NULL, -1))
|
||||
priv->features.touchpad_ctrl_via_ec = 0;
|
||||
else if (dmi_check_system(no_touchpad_switch_list))
|
||||
priv->features.touchpad_ctrl_via_ec = 0;
|
||||
else
|
||||
priv->features.touchpad_ctrl_via_ec = 1;
|
||||
priv->features.ctrl_ps2_aux_port =
|
||||
ctrl_ps2_aux_port || dmi_check_system(ctrl_ps2_aux_port_list);
|
||||
priv->features.touchpad_ctrl_via_ec = touchpad_ctrl_via_ec;
|
||||
|
||||
if (!read_ec_data(handle, VPCCMD_R_FAN, &val))
|
||||
priv->features.fan_mode = true;
|
||||
@ -1622,6 +1696,118 @@ static void ideapad_check_features(struct ideapad_private *priv)
|
||||
}
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI_WMI)
|
||||
/*
|
||||
* WMI driver
|
||||
*/
|
||||
enum ideapad_wmi_event_type {
|
||||
IDEAPAD_WMI_EVENT_ESC,
|
||||
IDEAPAD_WMI_EVENT_FN_KEYS,
|
||||
};
|
||||
|
||||
struct ideapad_wmi_private {
|
||||
enum ideapad_wmi_event_type event;
|
||||
};
|
||||
|
||||
static int ideapad_wmi_probe(struct wmi_device *wdev, const void *context)
|
||||
{
|
||||
struct ideapad_wmi_private *wpriv;
|
||||
|
||||
wpriv = devm_kzalloc(&wdev->dev, sizeof(*wpriv), GFP_KERNEL);
|
||||
if (!wpriv)
|
||||
return -ENOMEM;
|
||||
|
||||
*wpriv = *(const struct ideapad_wmi_private *)context;
|
||||
|
||||
dev_set_drvdata(&wdev->dev, wpriv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ideapad_wmi_notify(struct wmi_device *wdev, union acpi_object *data)
|
||||
{
|
||||
struct ideapad_wmi_private *wpriv = dev_get_drvdata(&wdev->dev);
|
||||
struct ideapad_private *priv;
|
||||
unsigned long result;
|
||||
|
||||
mutex_lock(&ideapad_shared_mutex);
|
||||
|
||||
priv = ideapad_shared;
|
||||
if (!priv)
|
||||
goto unlock;
|
||||
|
||||
switch (wpriv->event) {
|
||||
case IDEAPAD_WMI_EVENT_ESC:
|
||||
ideapad_input_report(priv, 128);
|
||||
break;
|
||||
case IDEAPAD_WMI_EVENT_FN_KEYS:
|
||||
if (priv->features.set_fn_lock_led &&
|
||||
!eval_hals(priv->adev->handle, &result)) {
|
||||
bool state = test_bit(HALS_FNLOCK_STATE_BIT, &result);
|
||||
|
||||
exec_sals(priv->adev->handle, state ? SALS_FNLOCK_ON : SALS_FNLOCK_OFF);
|
||||
}
|
||||
|
||||
if (data->type != ACPI_TYPE_INTEGER) {
|
||||
dev_warn(&wdev->dev,
|
||||
"WMI event data is not an integer\n");
|
||||
break;
|
||||
}
|
||||
|
||||
dev_dbg(&wdev->dev, "WMI fn-key event: 0x%llx\n",
|
||||
data->integer.value);
|
||||
|
||||
ideapad_input_report(priv,
|
||||
data->integer.value | IDEAPAD_WMI_KEY);
|
||||
|
||||
break;
|
||||
}
|
||||
unlock:
|
||||
mutex_unlock(&ideapad_shared_mutex);
|
||||
}
|
||||
|
||||
static const struct ideapad_wmi_private ideapad_wmi_context_esc = {
|
||||
.event = IDEAPAD_WMI_EVENT_ESC
|
||||
};
|
||||
|
||||
static const struct ideapad_wmi_private ideapad_wmi_context_fn_keys = {
|
||||
.event = IDEAPAD_WMI_EVENT_FN_KEYS
|
||||
};
|
||||
|
||||
static const struct wmi_device_id ideapad_wmi_ids[] = {
|
||||
{ "26CAB2E5-5CF1-46AE-AAC3-4A12B6BA50E6", &ideapad_wmi_context_esc }, /* Yoga 3 */
|
||||
{ "56322276-8493-4CE8-A783-98C991274F5E", &ideapad_wmi_context_esc }, /* Yoga 700 */
|
||||
{ "8FC0DE0C-B4E4-43FD-B0F3-8871711C1294", &ideapad_wmi_context_fn_keys }, /* Legion 5 */
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(wmi, ideapad_wmi_ids);
|
||||
|
||||
static struct wmi_driver ideapad_wmi_driver = {
|
||||
.driver = {
|
||||
.name = "ideapad_wmi",
|
||||
},
|
||||
.id_table = ideapad_wmi_ids,
|
||||
.probe = ideapad_wmi_probe,
|
||||
.notify = ideapad_wmi_notify,
|
||||
};
|
||||
|
||||
static int ideapad_wmi_driver_register(void)
|
||||
{
|
||||
return wmi_driver_register(&ideapad_wmi_driver);
|
||||
}
|
||||
|
||||
static void ideapad_wmi_driver_unregister(void)
|
||||
{
|
||||
return wmi_driver_unregister(&ideapad_wmi_driver);
|
||||
}
|
||||
|
||||
#else
|
||||
static inline int ideapad_wmi_driver_register(void) { return 0; }
|
||||
static inline void ideapad_wmi_driver_unregister(void) { }
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ACPI driver
|
||||
*/
|
||||
static int ideapad_acpi_add(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
|
||||
@ -1670,16 +1856,12 @@ static int ideapad_acpi_add(struct platform_device *pdev)
|
||||
if (!priv->features.hw_rfkill_switch)
|
||||
write_ec_cmd(priv->adev->handle, VPCCMD_W_RF, 1);
|
||||
|
||||
/* The same for Touchpad */
|
||||
if (!priv->features.touchpad_ctrl_via_ec)
|
||||
write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, 1);
|
||||
|
||||
for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
|
||||
if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
|
||||
ideapad_register_rfkill(priv, i);
|
||||
|
||||
ideapad_sync_rfk_state(priv);
|
||||
ideapad_sync_touchpad_state(priv);
|
||||
ideapad_sync_touchpad_state(priv, false);
|
||||
|
||||
err = ideapad_dytc_profile_init(priv);
|
||||
if (err) {
|
||||
@ -1703,30 +1885,16 @@ static int ideapad_acpi_add(struct platform_device *pdev)
|
||||
goto notification_failed;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI_WMI)
|
||||
for (i = 0; i < ARRAY_SIZE(ideapad_wmi_fnesc_events); i++) {
|
||||
status = wmi_install_notify_handler(ideapad_wmi_fnesc_events[i],
|
||||
ideapad_wmi_notify, priv);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
priv->fnesc_guid = ideapad_wmi_fnesc_events[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ACPI_FAILURE(status) && status != AE_NOT_EXIST) {
|
||||
err = -EIO;
|
||||
goto notification_failed_wmi;
|
||||
}
|
||||
#endif
|
||||
err = ideapad_shared_init(priv);
|
||||
if (err)
|
||||
goto shared_init_failed;
|
||||
|
||||
return 0;
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI_WMI)
|
||||
notification_failed_wmi:
|
||||
shared_init_failed:
|
||||
acpi_remove_notify_handler(priv->adev->handle,
|
||||
ACPI_DEVICE_NOTIFY,
|
||||
ideapad_acpi_notify);
|
||||
#endif
|
||||
|
||||
notification_failed:
|
||||
ideapad_backlight_exit(priv);
|
||||
@ -1752,10 +1920,7 @@ static int ideapad_acpi_remove(struct platform_device *pdev)
|
||||
struct ideapad_private *priv = dev_get_drvdata(&pdev->dev);
|
||||
int i;
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI_WMI)
|
||||
if (priv->fnesc_guid)
|
||||
wmi_remove_notify_handler(priv->fnesc_guid);
|
||||
#endif
|
||||
ideapad_shared_exit(priv);
|
||||
|
||||
acpi_remove_notify_handler(priv->adev->handle,
|
||||
ACPI_DEVICE_NOTIFY,
|
||||
@ -1781,7 +1946,7 @@ static int ideapad_acpi_resume(struct device *dev)
|
||||
struct ideapad_private *priv = dev_get_drvdata(dev);
|
||||
|
||||
ideapad_sync_rfk_state(priv);
|
||||
ideapad_sync_touchpad_state(priv);
|
||||
ideapad_sync_touchpad_state(priv, false);
|
||||
|
||||
if (priv->dytc)
|
||||
dytc_profile_refresh(priv);
|
||||
@ -1807,7 +1972,30 @@ static struct platform_driver ideapad_acpi_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(ideapad_acpi_driver);
|
||||
static int __init ideapad_laptop_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ideapad_wmi_driver_register();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = platform_driver_register(&ideapad_acpi_driver);
|
||||
if (err) {
|
||||
ideapad_wmi_driver_unregister();
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
module_init(ideapad_laptop_init)
|
||||
|
||||
static void __exit ideapad_laptop_exit(void)
|
||||
{
|
||||
ideapad_wmi_driver_unregister();
|
||||
platform_driver_unregister(&ideapad_acpi_driver);
|
||||
}
|
||||
module_exit(ideapad_laptop_exit)
|
||||
|
||||
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
|
||||
MODULE_DESCRIPTION("IdeaPad ACPI Extras");
|
||||
|
@ -157,13 +157,13 @@ config INTEL_RST
|
||||
as usual.
|
||||
|
||||
config INTEL_SDSI
|
||||
tristate "Intel Software Defined Silicon Driver"
|
||||
tristate "Intel On Demand (Software Defined Silicon) Driver"
|
||||
depends on INTEL_VSEC
|
||||
depends on X86_64
|
||||
help
|
||||
This driver enables access to the Intel Software Defined Silicon
|
||||
interface used to provision silicon features with an authentication
|
||||
certificate and capability license.
|
||||
This driver enables access to the Intel On Demand (formerly Software
|
||||
Defined Silicon) interface used to provision silicon features with an
|
||||
authentication certificate and capability license.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called intel_sdsi.
|
||||
|
@ -16,6 +16,25 @@
|
||||
#include <linux/suspend.h>
|
||||
#include "../dual_accel_detect.h"
|
||||
|
||||
enum intel_hid_tablet_sw_mode {
|
||||
TABLET_SW_AUTO = -1,
|
||||
TABLET_SW_OFF = 0,
|
||||
TABLET_SW_AT_EVENT,
|
||||
TABLET_SW_AT_PROBE,
|
||||
};
|
||||
|
||||
static bool enable_5_button_array;
|
||||
module_param(enable_5_button_array, bool, 0444);
|
||||
MODULE_PARM_DESC(enable_5_button_array,
|
||||
"Enable 5 Button Array support. "
|
||||
"If you need this please report this to: platform-driver-x86@vger.kernel.org");
|
||||
|
||||
static int enable_sw_tablet_mode = TABLET_SW_AUTO;
|
||||
module_param(enable_sw_tablet_mode, int, 0444);
|
||||
MODULE_PARM_DESC(enable_sw_tablet_mode,
|
||||
"Enable SW_TABLET_MODE reporting -1:auto 0:off 1:at-first-event 2:at-probe. "
|
||||
"If you need this please report this to: platform-driver-x86@vger.kernel.org");
|
||||
|
||||
/* When NOT in tablet mode, VGBS returns with the flag 0x40 */
|
||||
#define TABLET_MODE_FLAG BIT(6)
|
||||
|
||||
@ -157,7 +176,6 @@ struct intel_hid_priv {
|
||||
struct input_dev *array;
|
||||
struct input_dev *switches;
|
||||
bool wakeup_mode;
|
||||
bool auto_add_switch;
|
||||
};
|
||||
|
||||
#define HID_EVENT_FILTER_UUID "eeec56b3-4442-408f-a792-4edd4d758054"
|
||||
@ -487,7 +505,8 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)
|
||||
* SW_TABLET_MODE report, in these cases we enable support when receiving
|
||||
* the first event instead of during driver setup.
|
||||
*/
|
||||
if (!priv->switches && priv->auto_add_switch && (event == 0xcc || event == 0xcd)) {
|
||||
if (!priv->switches && enable_sw_tablet_mode == TABLET_SW_AT_EVENT &&
|
||||
(event == 0xcc || event == 0xcd)) {
|
||||
dev_info(&device->dev, "switch event received, enable switches supports\n");
|
||||
err = intel_hid_switches_setup(device);
|
||||
if (err)
|
||||
@ -592,7 +611,7 @@ static bool button_array_present(struct platform_device *device)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dmi_check_system(button_array_table))
|
||||
if (enable_5_button_array || dmi_check_system(button_array_table))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -629,7 +648,14 @@ static int intel_hid_probe(struct platform_device *device)
|
||||
dev_set_drvdata(&device->dev, priv);
|
||||
|
||||
/* See dual_accel_detect.h for more info on the dual_accel check. */
|
||||
priv->auto_add_switch = dmi_check_system(dmi_auto_add_switch) && !dual_accel_detect();
|
||||
if (enable_sw_tablet_mode == TABLET_SW_AUTO) {
|
||||
if (dmi_check_system(dmi_vgbs_allow_list))
|
||||
enable_sw_tablet_mode = TABLET_SW_AT_PROBE;
|
||||
else if (dmi_check_system(dmi_auto_add_switch) && !dual_accel_detect())
|
||||
enable_sw_tablet_mode = TABLET_SW_AT_EVENT;
|
||||
else
|
||||
enable_sw_tablet_mode = TABLET_SW_OFF;
|
||||
}
|
||||
|
||||
err = intel_hid_input_setup(device);
|
||||
if (err) {
|
||||
@ -646,7 +672,7 @@ static int intel_hid_probe(struct platform_device *device)
|
||||
}
|
||||
|
||||
/* Setup switches for devices that we know VGBS return correctly */
|
||||
if (dmi_check_system(dmi_vgbs_allow_list)) {
|
||||
if (enable_sw_tablet_mode == TABLET_SW_AT_PROBE) {
|
||||
dev_info(&device->dev, "platform supports switches\n");
|
||||
err = intel_hid_switches_setup(device);
|
||||
if (err)
|
||||
|
@ -3,7 +3,8 @@
|
||||
# Intel x86 Platform-Specific Drivers
|
||||
#
|
||||
|
||||
intel_pmc_core-y := core.o
|
||||
intel_pmc_core-y := core.o spt.o cnp.o icl.o tgl.o \
|
||||
adl.o mtl.o
|
||||
obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o
|
||||
intel_pmc_core_pltdrv-y := pltdrv.o
|
||||
obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core_pltdrv.o
|
||||
|
325
drivers/platform/x86/intel/pmc/adl.c
Normal file
325
drivers/platform/x86/intel/pmc/adl.c
Normal file
@ -0,0 +1,325 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* This file contains platform specific structure definitions
|
||||
* and init function used by Alder Lake PCH.
|
||||
*
|
||||
* Copyright (c) 2022, Intel Corporation.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
|
||||
/* Alder Lake: PGD PFET Enable Ack Status Register(s) bitmap */
|
||||
const struct pmc_bit_map adl_pfear_map[] = {
|
||||
{"SPI/eSPI", BIT(2)},
|
||||
{"XHCI", BIT(3)},
|
||||
{"SPA", BIT(4)},
|
||||
{"SPB", BIT(5)},
|
||||
{"SPC", BIT(6)},
|
||||
{"GBE", BIT(7)},
|
||||
|
||||
{"SATA", BIT(0)},
|
||||
{"HDA_PGD0", BIT(1)},
|
||||
{"HDA_PGD1", BIT(2)},
|
||||
{"HDA_PGD2", BIT(3)},
|
||||
{"HDA_PGD3", BIT(4)},
|
||||
{"SPD", BIT(5)},
|
||||
{"LPSS", BIT(6)},
|
||||
|
||||
{"SMB", BIT(0)},
|
||||
{"ISH", BIT(1)},
|
||||
{"ITH", BIT(3)},
|
||||
|
||||
{"XDCI", BIT(1)},
|
||||
{"DCI", BIT(2)},
|
||||
{"CSE", BIT(3)},
|
||||
{"CSME_KVM", BIT(4)},
|
||||
{"CSME_PMT", BIT(5)},
|
||||
{"CSME_CLINK", BIT(6)},
|
||||
{"CSME_PTIO", BIT(7)},
|
||||
|
||||
{"CSME_USBR", BIT(0)},
|
||||
{"CSME_SUSRAM", BIT(1)},
|
||||
{"CSME_SMT1", BIT(2)},
|
||||
{"CSME_SMS2", BIT(4)},
|
||||
{"CSME_SMS1", BIT(5)},
|
||||
{"CSME_RTC", BIT(6)},
|
||||
{"CSME_PSF", BIT(7)},
|
||||
|
||||
{"CNVI", BIT(3)},
|
||||
{"HDA_PGD4", BIT(2)},
|
||||
{"HDA_PGD5", BIT(3)},
|
||||
{"HDA_PGD6", BIT(4)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map *ext_adl_pfear_map[] = {
|
||||
/*
|
||||
* Check intel_pmc_core_ids[] users of cnp_reg_map for
|
||||
* a list of core SoCs using this.
|
||||
*/
|
||||
adl_pfear_map,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct pmc_bit_map adl_ltr_show_map[] = {
|
||||
{"SOUTHPORT_A", CNP_PMC_LTR_SPA},
|
||||
{"SOUTHPORT_B", CNP_PMC_LTR_SPB},
|
||||
{"SATA", CNP_PMC_LTR_SATA},
|
||||
{"GIGABIT_ETHERNET", CNP_PMC_LTR_GBE},
|
||||
{"XHCI", CNP_PMC_LTR_XHCI},
|
||||
{"SOUTHPORT_F", ADL_PMC_LTR_SPF},
|
||||
{"ME", CNP_PMC_LTR_ME},
|
||||
/* EVA is Enterprise Value Add, doesn't really exist on PCH */
|
||||
{"SATA1", CNP_PMC_LTR_EVA},
|
||||
{"SOUTHPORT_C", CNP_PMC_LTR_SPC},
|
||||
{"HD_AUDIO", CNP_PMC_LTR_AZ},
|
||||
{"CNV", CNP_PMC_LTR_CNV},
|
||||
{"LPSS", CNP_PMC_LTR_LPSS},
|
||||
{"SOUTHPORT_D", CNP_PMC_LTR_SPD},
|
||||
{"SOUTHPORT_E", CNP_PMC_LTR_SPE},
|
||||
{"SATA2", CNP_PMC_LTR_CAM},
|
||||
{"ESPI", CNP_PMC_LTR_ESPI},
|
||||
{"SCC", CNP_PMC_LTR_SCC},
|
||||
{"ISH", CNP_PMC_LTR_ISH},
|
||||
{"UFSX2", CNP_PMC_LTR_UFSX2},
|
||||
{"EMMC", CNP_PMC_LTR_EMMC},
|
||||
/*
|
||||
* Check intel_pmc_core_ids[] users of cnp_reg_map for
|
||||
* a list of core SoCs using this.
|
||||
*/
|
||||
{"WIGIG", ICL_PMC_LTR_WIGIG},
|
||||
{"THC0", TGL_PMC_LTR_THC0},
|
||||
{"THC1", TGL_PMC_LTR_THC1},
|
||||
{"SOUTHPORT_G", CNP_PMC_LTR_RESERVED},
|
||||
|
||||
/* Below two cannot be used for LTR_IGNORE */
|
||||
{"CURRENT_PLATFORM", CNP_PMC_LTR_CUR_PLT},
|
||||
{"AGGREGATED_SYSTEM", CNP_PMC_LTR_CUR_ASLT},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map adl_clocksource_status_map[] = {
|
||||
{"CLKPART1_OFF_STS", BIT(0)},
|
||||
{"CLKPART2_OFF_STS", BIT(1)},
|
||||
{"CLKPART3_OFF_STS", BIT(2)},
|
||||
{"CLKPART4_OFF_STS", BIT(3)},
|
||||
{"CLKPART5_OFF_STS", BIT(4)},
|
||||
{"CLKPART6_OFF_STS", BIT(5)},
|
||||
{"CLKPART7_OFF_STS", BIT(6)},
|
||||
{"CLKPART8_OFF_STS", BIT(7)},
|
||||
{"PCIE0PLL_OFF_STS", BIT(10)},
|
||||
{"PCIE1PLL_OFF_STS", BIT(11)},
|
||||
{"PCIE2PLL_OFF_STS", BIT(12)},
|
||||
{"PCIE3PLL_OFF_STS", BIT(13)},
|
||||
{"PCIE4PLL_OFF_STS", BIT(14)},
|
||||
{"PCIE5PLL_OFF_STS", BIT(15)},
|
||||
{"PCIE6PLL_OFF_STS", BIT(16)},
|
||||
{"USB2PLL_OFF_STS", BIT(18)},
|
||||
{"OCPLL_OFF_STS", BIT(22)},
|
||||
{"AUDIOPLL_OFF_STS", BIT(23)},
|
||||
{"GBEPLL_OFF_STS", BIT(24)},
|
||||
{"Fast_XTAL_Osc_OFF_STS", BIT(25)},
|
||||
{"AC_Ring_Osc_OFF_STS", BIT(26)},
|
||||
{"MC_Ring_Osc_OFF_STS", BIT(27)},
|
||||
{"SATAPLL_OFF_STS", BIT(29)},
|
||||
{"USB3PLL_OFF_STS", BIT(31)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map adl_power_gating_status_0_map[] = {
|
||||
{"PMC_PGD0_PG_STS", BIT(0)},
|
||||
{"DMI_PGD0_PG_STS", BIT(1)},
|
||||
{"ESPISPI_PGD0_PG_STS", BIT(2)},
|
||||
{"XHCI_PGD0_PG_STS", BIT(3)},
|
||||
{"SPA_PGD0_PG_STS", BIT(4)},
|
||||
{"SPB_PGD0_PG_STS", BIT(5)},
|
||||
{"SPC_PGD0_PG_STS", BIT(6)},
|
||||
{"GBE_PGD0_PG_STS", BIT(7)},
|
||||
{"SATA_PGD0_PG_STS", BIT(8)},
|
||||
{"DSP_PGD0_PG_STS", BIT(9)},
|
||||
{"DSP_PGD1_PG_STS", BIT(10)},
|
||||
{"DSP_PGD2_PG_STS", BIT(11)},
|
||||
{"DSP_PGD3_PG_STS", BIT(12)},
|
||||
{"SPD_PGD0_PG_STS", BIT(13)},
|
||||
{"LPSS_PGD0_PG_STS", BIT(14)},
|
||||
{"SMB_PGD0_PG_STS", BIT(16)},
|
||||
{"ISH_PGD0_PG_STS", BIT(17)},
|
||||
{"NPK_PGD0_PG_STS", BIT(19)},
|
||||
{"PECI_PGD0_PG_STS", BIT(21)},
|
||||
{"XDCI_PGD0_PG_STS", BIT(25)},
|
||||
{"EXI_PGD0_PG_STS", BIT(26)},
|
||||
{"CSE_PGD0_PG_STS", BIT(27)},
|
||||
{"KVMCC_PGD0_PG_STS", BIT(28)},
|
||||
{"PMT_PGD0_PG_STS", BIT(29)},
|
||||
{"CLINK_PGD0_PG_STS", BIT(30)},
|
||||
{"PTIO_PGD0_PG_STS", BIT(31)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map adl_power_gating_status_1_map[] = {
|
||||
{"USBR0_PGD0_PG_STS", BIT(0)},
|
||||
{"SMT1_PGD0_PG_STS", BIT(2)},
|
||||
{"CSMERTC_PGD0_PG_STS", BIT(6)},
|
||||
{"CSMEPSF_PGD0_PG_STS", BIT(7)},
|
||||
{"CNVI_PGD0_PG_STS", BIT(19)},
|
||||
{"DSP_PGD4_PG_STS", BIT(26)},
|
||||
{"SPG_PGD0_PG_STS", BIT(27)},
|
||||
{"SPE_PGD0_PG_STS", BIT(28)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map adl_power_gating_status_2_map[] = {
|
||||
{"THC0_PGD0_PG_STS", BIT(7)},
|
||||
{"THC1_PGD0_PG_STS", BIT(8)},
|
||||
{"SPF_PGD0_PG_STS", BIT(14)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map adl_d3_status_0_map[] = {
|
||||
{"ISH_D3_STS", BIT(2)},
|
||||
{"LPSS_D3_STS", BIT(3)},
|
||||
{"XDCI_D3_STS", BIT(4)},
|
||||
{"XHCI_D3_STS", BIT(5)},
|
||||
{"SPA_D3_STS", BIT(12)},
|
||||
{"SPB_D3_STS", BIT(13)},
|
||||
{"SPC_D3_STS", BIT(14)},
|
||||
{"SPD_D3_STS", BIT(15)},
|
||||
{"SPE_D3_STS", BIT(16)},
|
||||
{"DSP_D3_STS", BIT(19)},
|
||||
{"SATA_D3_STS", BIT(20)},
|
||||
{"DMI_D3_STS", BIT(22)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map adl_d3_status_1_map[] = {
|
||||
{"GBE_D3_STS", BIT(19)},
|
||||
{"CNVI_D3_STS", BIT(27)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map adl_d3_status_2_map[] = {
|
||||
{"CSMERTC_D3_STS", BIT(1)},
|
||||
{"CSE_D3_STS", BIT(4)},
|
||||
{"KVMCC_D3_STS", BIT(5)},
|
||||
{"USBR0_D3_STS", BIT(6)},
|
||||
{"SMT1_D3_STS", BIT(8)},
|
||||
{"PTIO_D3_STS", BIT(16)},
|
||||
{"PMT_D3_STS", BIT(17)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map adl_d3_status_3_map[] = {
|
||||
{"THC0_D3_STS", BIT(14)},
|
||||
{"THC1_D3_STS", BIT(15)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map adl_vnn_req_status_0_map[] = {
|
||||
{"ISH_VNN_REQ_STS", BIT(2)},
|
||||
{"ESPISPI_VNN_REQ_STS", BIT(18)},
|
||||
{"DSP_VNN_REQ_STS", BIT(19)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map adl_vnn_req_status_1_map[] = {
|
||||
{"NPK_VNN_REQ_STS", BIT(4)},
|
||||
{"EXI_VNN_REQ_STS", BIT(9)},
|
||||
{"GBE_VNN_REQ_STS", BIT(19)},
|
||||
{"SMB_VNN_REQ_STS", BIT(25)},
|
||||
{"CNVI_VNN_REQ_STS", BIT(27)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map adl_vnn_req_status_2_map[] = {
|
||||
{"CSMERTC_VNN_REQ_STS", BIT(1)},
|
||||
{"CSE_VNN_REQ_STS", BIT(4)},
|
||||
{"SMT1_VNN_REQ_STS", BIT(8)},
|
||||
{"CLINK_VNN_REQ_STS", BIT(14)},
|
||||
{"GPIOCOM4_VNN_REQ_STS", BIT(20)},
|
||||
{"GPIOCOM3_VNN_REQ_STS", BIT(21)},
|
||||
{"GPIOCOM2_VNN_REQ_STS", BIT(22)},
|
||||
{"GPIOCOM1_VNN_REQ_STS", BIT(23)},
|
||||
{"GPIOCOM0_VNN_REQ_STS", BIT(24)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map adl_vnn_req_status_3_map[] = {
|
||||
{"GPIOCOM5_VNN_REQ_STS", BIT(11)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map adl_vnn_misc_status_map[] = {
|
||||
{"CPU_C10_REQ_STS", BIT(0)},
|
||||
{"PCIe_LPM_En_REQ_STS", BIT(3)},
|
||||
{"ITH_REQ_STS", BIT(5)},
|
||||
{"CNVI_REQ_STS", BIT(6)},
|
||||
{"ISH_REQ_STS", BIT(7)},
|
||||
{"USB2_SUS_PG_Sys_REQ_STS", BIT(10)},
|
||||
{"PCIe_Clk_REQ_STS", BIT(12)},
|
||||
{"MPHY_Core_DL_REQ_STS", BIT(16)},
|
||||
{"Break-even_En_REQ_STS", BIT(17)},
|
||||
{"MPHY_SUS_REQ_STS", BIT(22)},
|
||||
{"xDCI_attached_REQ_STS", BIT(24)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map *adl_lpm_maps[] = {
|
||||
adl_clocksource_status_map,
|
||||
adl_power_gating_status_0_map,
|
||||
adl_power_gating_status_1_map,
|
||||
adl_power_gating_status_2_map,
|
||||
adl_d3_status_0_map,
|
||||
adl_d3_status_1_map,
|
||||
adl_d3_status_2_map,
|
||||
adl_d3_status_3_map,
|
||||
adl_vnn_req_status_0_map,
|
||||
adl_vnn_req_status_1_map,
|
||||
adl_vnn_req_status_2_map,
|
||||
adl_vnn_req_status_3_map,
|
||||
adl_vnn_misc_status_map,
|
||||
tgl_signal_status_map,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct pmc_reg_map adl_reg_map = {
|
||||
.pfear_sts = ext_adl_pfear_map,
|
||||
.slp_s0_offset = ADL_PMC_SLP_S0_RES_COUNTER_OFFSET,
|
||||
.slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP,
|
||||
.ltr_show_sts = adl_ltr_show_map,
|
||||
.msr_sts = msr_map,
|
||||
.ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
|
||||
.regmap_length = CNP_PMC_MMIO_REG_LEN,
|
||||
.ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
|
||||
.ppfear_buckets = CNP_PPFEAR_NUM_ENTRIES,
|
||||
.pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
|
||||
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
|
||||
.ltr_ignore_max = ADL_NUM_IP_IGN_ALLOWED,
|
||||
.lpm_num_modes = ADL_LPM_NUM_MODES,
|
||||
.lpm_num_maps = ADL_LPM_NUM_MAPS,
|
||||
.lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2,
|
||||
.etr3_offset = ETR3_OFFSET,
|
||||
.lpm_sts_latch_en_offset = ADL_LPM_STATUS_LATCH_EN_OFFSET,
|
||||
.lpm_priority_offset = ADL_LPM_PRI_OFFSET,
|
||||
.lpm_en_offset = ADL_LPM_EN_OFFSET,
|
||||
.lpm_residency_offset = ADL_LPM_RESIDENCY_OFFSET,
|
||||
.lpm_sts = adl_lpm_maps,
|
||||
.lpm_status_offset = ADL_LPM_STATUS_OFFSET,
|
||||
.lpm_live_status_offset = ADL_LPM_LIVE_STATUS_OFFSET,
|
||||
};
|
||||
|
||||
void adl_core_configure(struct pmc_dev *pmcdev)
|
||||
{
|
||||
/* Due to a hardware limitation, the GBE LTR blocks PC10
|
||||
* when a cable is attached. Tell the PMC to ignore it.
|
||||
*/
|
||||
dev_dbg(&pmcdev->pdev->dev, "ignoring GBE LTR\n");
|
||||
pmc_core_send_ltr_ignore(pmcdev, 3);
|
||||
}
|
||||
|
||||
void adl_core_init(struct pmc_dev *pmcdev)
|
||||
{
|
||||
pmcdev->map = &adl_reg_map;
|
||||
pmcdev->core_configure = adl_core_configure;
|
||||
}
|
210
drivers/platform/x86/intel/pmc/cnp.c
Normal file
210
drivers/platform/x86/intel/pmc/cnp.c
Normal file
@ -0,0 +1,210 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* This file contains platform specific structure definitions
|
||||
* and init function used by Cannon Lake Point PCH.
|
||||
*
|
||||
* Copyright (c) 2022, Intel Corporation.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
|
||||
/* Cannon Lake: PGD PFET Enable Ack Status Register(s) bitmap */
|
||||
const struct pmc_bit_map cnp_pfear_map[] = {
|
||||
{"PMC", BIT(0)},
|
||||
{"OPI-DMI", BIT(1)},
|
||||
{"SPI/eSPI", BIT(2)},
|
||||
{"XHCI", BIT(3)},
|
||||
{"SPA", BIT(4)},
|
||||
{"SPB", BIT(5)},
|
||||
{"SPC", BIT(6)},
|
||||
{"GBE", BIT(7)},
|
||||
|
||||
{"SATA", BIT(0)},
|
||||
{"HDA_PGD0", BIT(1)},
|
||||
{"HDA_PGD1", BIT(2)},
|
||||
{"HDA_PGD2", BIT(3)},
|
||||
{"HDA_PGD3", BIT(4)},
|
||||
{"SPD", BIT(5)},
|
||||
{"LPSS", BIT(6)},
|
||||
{"LPC", BIT(7)},
|
||||
|
||||
{"SMB", BIT(0)},
|
||||
{"ISH", BIT(1)},
|
||||
{"P2SB", BIT(2)},
|
||||
{"NPK_VNN", BIT(3)},
|
||||
{"SDX", BIT(4)},
|
||||
{"SPE", BIT(5)},
|
||||
{"Fuse", BIT(6)},
|
||||
{"SBR8", BIT(7)},
|
||||
|
||||
{"CSME_FSC", BIT(0)},
|
||||
{"USB3_OTG", BIT(1)},
|
||||
{"EXI", BIT(2)},
|
||||
{"CSE", BIT(3)},
|
||||
{"CSME_KVM", BIT(4)},
|
||||
{"CSME_PMT", BIT(5)},
|
||||
{"CSME_CLINK", BIT(6)},
|
||||
{"CSME_PTIO", BIT(7)},
|
||||
|
||||
{"CSME_USBR", BIT(0)},
|
||||
{"CSME_SUSRAM", BIT(1)},
|
||||
{"CSME_SMT1", BIT(2)},
|
||||
{"CSME_SMT4", BIT(3)},
|
||||
{"CSME_SMS2", BIT(4)},
|
||||
{"CSME_SMS1", BIT(5)},
|
||||
{"CSME_RTC", BIT(6)},
|
||||
{"CSME_PSF", BIT(7)},
|
||||
|
||||
{"SBR0", BIT(0)},
|
||||
{"SBR1", BIT(1)},
|
||||
{"SBR2", BIT(2)},
|
||||
{"SBR3", BIT(3)},
|
||||
{"SBR4", BIT(4)},
|
||||
{"SBR5", BIT(5)},
|
||||
{"CSME_PECI", BIT(6)},
|
||||
{"PSF1", BIT(7)},
|
||||
|
||||
{"PSF2", BIT(0)},
|
||||
{"PSF3", BIT(1)},
|
||||
{"PSF4", BIT(2)},
|
||||
{"CNVI", BIT(3)},
|
||||
{"UFS0", BIT(4)},
|
||||
{"EMMC", BIT(5)},
|
||||
{"SPF", BIT(6)},
|
||||
{"SBR6", BIT(7)},
|
||||
|
||||
{"SBR7", BIT(0)},
|
||||
{"NPK_AON", BIT(1)},
|
||||
{"HDA_PGD4", BIT(2)},
|
||||
{"HDA_PGD5", BIT(3)},
|
||||
{"HDA_PGD6", BIT(4)},
|
||||
{"PSF6", BIT(5)},
|
||||
{"PSF7", BIT(6)},
|
||||
{"PSF8", BIT(7)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map *ext_cnp_pfear_map[] = {
|
||||
/*
|
||||
* Check intel_pmc_core_ids[] users of cnp_reg_map for
|
||||
* a list of core SoCs using this.
|
||||
*/
|
||||
cnp_pfear_map,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct pmc_bit_map cnp_slps0_dbg0_map[] = {
|
||||
{"AUDIO_D3", BIT(0)},
|
||||
{"OTG_D3", BIT(1)},
|
||||
{"XHCI_D3", BIT(2)},
|
||||
{"LPIO_D3", BIT(3)},
|
||||
{"SDX_D3", BIT(4)},
|
||||
{"SATA_D3", BIT(5)},
|
||||
{"UFS0_D3", BIT(6)},
|
||||
{"UFS1_D3", BIT(7)},
|
||||
{"EMMC_D3", BIT(8)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map cnp_slps0_dbg1_map[] = {
|
||||
{"SDIO_PLL_OFF", BIT(0)},
|
||||
{"USB2_PLL_OFF", BIT(1)},
|
||||
{"AUDIO_PLL_OFF", BIT(2)},
|
||||
{"OC_PLL_OFF", BIT(3)},
|
||||
{"MAIN_PLL_OFF", BIT(4)},
|
||||
{"XOSC_OFF", BIT(5)},
|
||||
{"LPC_CLKS_GATED", BIT(6)},
|
||||
{"PCIE_CLKREQS_IDLE", BIT(7)},
|
||||
{"AUDIO_ROSC_OFF", BIT(8)},
|
||||
{"HPET_XOSC_CLK_REQ", BIT(9)},
|
||||
{"PMC_ROSC_SLOW_CLK", BIT(10)},
|
||||
{"AON2_ROSC_GATED", BIT(11)},
|
||||
{"CLKACKS_DEASSERTED", BIT(12)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map cnp_slps0_dbg2_map[] = {
|
||||
{"MPHY_CORE_GATED", BIT(0)},
|
||||
{"CSME_GATED", BIT(1)},
|
||||
{"USB2_SUS_GATED", BIT(2)},
|
||||
{"DYN_FLEX_IO_IDLE", BIT(3)},
|
||||
{"GBE_NO_LINK", BIT(4)},
|
||||
{"THERM_SEN_DISABLED", BIT(5)},
|
||||
{"PCIE_LOW_POWER", BIT(6)},
|
||||
{"ISH_VNNAON_REQ_ACT", BIT(7)},
|
||||
{"ISH_VNN_REQ_ACT", BIT(8)},
|
||||
{"CNV_VNNAON_REQ_ACT", BIT(9)},
|
||||
{"CNV_VNN_REQ_ACT", BIT(10)},
|
||||
{"NPK_VNNON_REQ_ACT", BIT(11)},
|
||||
{"PMSYNC_STATE_IDLE", BIT(12)},
|
||||
{"ALST_GT_THRES", BIT(13)},
|
||||
{"PMC_ARC_PG_READY", BIT(14)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map *cnp_slps0_dbg_maps[] = {
|
||||
cnp_slps0_dbg0_map,
|
||||
cnp_slps0_dbg1_map,
|
||||
cnp_slps0_dbg2_map,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct pmc_bit_map cnp_ltr_show_map[] = {
|
||||
{"SOUTHPORT_A", CNP_PMC_LTR_SPA},
|
||||
{"SOUTHPORT_B", CNP_PMC_LTR_SPB},
|
||||
{"SATA", CNP_PMC_LTR_SATA},
|
||||
{"GIGABIT_ETHERNET", CNP_PMC_LTR_GBE},
|
||||
{"XHCI", CNP_PMC_LTR_XHCI},
|
||||
{"Reserved", CNP_PMC_LTR_RESERVED},
|
||||
{"ME", CNP_PMC_LTR_ME},
|
||||
/* EVA is Enterprise Value Add, doesn't really exist on PCH */
|
||||
{"EVA", CNP_PMC_LTR_EVA},
|
||||
{"SOUTHPORT_C", CNP_PMC_LTR_SPC},
|
||||
{"HD_AUDIO", CNP_PMC_LTR_AZ},
|
||||
{"CNV", CNP_PMC_LTR_CNV},
|
||||
{"LPSS", CNP_PMC_LTR_LPSS},
|
||||
{"SOUTHPORT_D", CNP_PMC_LTR_SPD},
|
||||
{"SOUTHPORT_E", CNP_PMC_LTR_SPE},
|
||||
{"CAMERA", CNP_PMC_LTR_CAM},
|
||||
{"ESPI", CNP_PMC_LTR_ESPI},
|
||||
{"SCC", CNP_PMC_LTR_SCC},
|
||||
{"ISH", CNP_PMC_LTR_ISH},
|
||||
{"UFSX2", CNP_PMC_LTR_UFSX2},
|
||||
{"EMMC", CNP_PMC_LTR_EMMC},
|
||||
/*
|
||||
* Check intel_pmc_core_ids[] users of cnp_reg_map for
|
||||
* a list of core SoCs using this.
|
||||
*/
|
||||
{"WIGIG", ICL_PMC_LTR_WIGIG},
|
||||
{"THC0", TGL_PMC_LTR_THC0},
|
||||
{"THC1", TGL_PMC_LTR_THC1},
|
||||
/* Below two cannot be used for LTR_IGNORE */
|
||||
{"CURRENT_PLATFORM", CNP_PMC_LTR_CUR_PLT},
|
||||
{"AGGREGATED_SYSTEM", CNP_PMC_LTR_CUR_ASLT},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_reg_map cnp_reg_map = {
|
||||
.pfear_sts = ext_cnp_pfear_map,
|
||||
.slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
|
||||
.slp_s0_res_counter_step = SPT_PMC_SLP_S0_RES_COUNTER_STEP,
|
||||
.slps0_dbg_maps = cnp_slps0_dbg_maps,
|
||||
.ltr_show_sts = cnp_ltr_show_map,
|
||||
.msr_sts = msr_map,
|
||||
.slps0_dbg_offset = CNP_PMC_SLPS0_DBG_OFFSET,
|
||||
.ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
|
||||
.regmap_length = CNP_PMC_MMIO_REG_LEN,
|
||||
.ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
|
||||
.ppfear_buckets = CNP_PPFEAR_NUM_ENTRIES,
|
||||
.pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
|
||||
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
|
||||
.ltr_ignore_max = CNP_NUM_IP_IGN_ALLOWED,
|
||||
.etr3_offset = ETR3_OFFSET,
|
||||
};
|
||||
|
||||
void cnp_core_init(struct pmc_dev *pmcdev)
|
||||
{
|
||||
pmcdev->map = &cnp_reg_map;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -12,7 +12,9 @@
|
||||
#ifndef PMC_CORE_H
|
||||
#define PMC_CORE_H
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define PMC_BASE_ADDR_DEFAULT 0xFE000000
|
||||
|
||||
@ -236,17 +238,17 @@ enum ppfear_regs {
|
||||
#define ADL_LPM_STATUS_LATCH_EN_OFFSET 0x1704
|
||||
#define ADL_LPM_LIVE_STATUS_OFFSET 0x1764
|
||||
|
||||
static const char *pmc_lpm_modes[] = {
|
||||
"S0i2.0",
|
||||
"S0i2.1",
|
||||
"S0i2.2",
|
||||
"S0i3.0",
|
||||
"S0i3.1",
|
||||
"S0i3.2",
|
||||
"S0i3.3",
|
||||
"S0i3.4",
|
||||
NULL
|
||||
};
|
||||
/* Meteor Lake Power Management Controller register offsets */
|
||||
#define MTL_LPM_EN_OFFSET 0x1798
|
||||
#define MTL_LPM_RESIDENCY_OFFSET 0x17A0
|
||||
|
||||
/* Meteor Lake Low Power Mode debug registers */
|
||||
#define MTL_LPM_PRI_OFFSET 0x179C
|
||||
#define MTL_LPM_STATUS_LATCH_EN_OFFSET 0x16F8
|
||||
#define MTL_LPM_STATUS_OFFSET 0x1700
|
||||
#define MTL_LPM_LIVE_STATUS_OFFSET 0x175C
|
||||
|
||||
extern const char *pmc_lpm_modes[];
|
||||
|
||||
struct pmc_bit_map {
|
||||
const char *name;
|
||||
@ -264,7 +266,7 @@ struct pmc_bit_map {
|
||||
* @slp_s0_offset: PWRMBASE offset to read SLP_S0 residency
|
||||
* @ltr_ignore_offset: PWRMBASE offset to read/write LTR ignore bit
|
||||
* @regmap_length: Length of memory to map from PWRMBASE address to access
|
||||
* @ppfear0_offset: PWRMBASE offset to to read PPFEAR*
|
||||
* @ppfear0_offset: PWRMBASE offset to read PPFEAR*
|
||||
* @ppfear_buckets: Number of 8 bits blocks to read all IP blocks from
|
||||
* PPFEAR
|
||||
* @pm_cfg_offset: PWRMBASE offset to PM_CFG register
|
||||
@ -312,6 +314,7 @@ struct pmc_reg_map {
|
||||
* @regbase: pointer to io-remapped memory location
|
||||
* @map: pointer to pmc_reg_map struct that contains platform
|
||||
* specific attributes
|
||||
* @pdev: pointer to platform_device struct
|
||||
* @dbgfs_dir: path to debugfs interface
|
||||
* @pmc_xram_read_bit: flag to indicate whether PMC XRAM shadow registers
|
||||
* used to read MPHY PG and PLL status are available
|
||||
@ -322,6 +325,7 @@ struct pmc_reg_map {
|
||||
* @num_lpm_modes: Count of enabled modes
|
||||
* @lpm_en_modes: Array of enabled modes from lowest to highest priority
|
||||
* @lpm_req_regs: List of substate requirements
|
||||
* @core_configure: Function pointer to configure the platform
|
||||
*
|
||||
* pmc_dev contains info about power management controller device.
|
||||
*/
|
||||
@ -330,6 +334,7 @@ struct pmc_dev {
|
||||
void __iomem *regbase;
|
||||
const struct pmc_reg_map *map;
|
||||
struct dentry *dbgfs_dir;
|
||||
struct platform_device *pdev;
|
||||
int pmc_xram_read_bit;
|
||||
struct mutex lock; /* generic mutex lock for PMC Core */
|
||||
|
||||
@ -339,8 +344,70 @@ struct pmc_dev {
|
||||
int num_lpm_modes;
|
||||
int lpm_en_modes[LPM_MAX_NUM_MODES];
|
||||
u32 *lpm_req_regs;
|
||||
void (*core_configure)(struct pmc_dev *pmcdev);
|
||||
};
|
||||
|
||||
extern const struct pmc_bit_map msr_map[];
|
||||
extern const struct pmc_bit_map spt_pll_map[];
|
||||
extern const struct pmc_bit_map spt_mphy_map[];
|
||||
extern const struct pmc_bit_map spt_pfear_map[];
|
||||
extern const struct pmc_bit_map *ext_spt_pfear_map[];
|
||||
extern const struct pmc_bit_map spt_ltr_show_map[];
|
||||
extern const struct pmc_reg_map spt_reg_map;
|
||||
extern const struct pmc_bit_map cnp_pfear_map[];
|
||||
extern const struct pmc_bit_map *ext_cnp_pfear_map[];
|
||||
extern const struct pmc_bit_map cnp_slps0_dbg0_map[];
|
||||
extern const struct pmc_bit_map cnp_slps0_dbg1_map[];
|
||||
extern const struct pmc_bit_map cnp_slps0_dbg2_map[];
|
||||
extern const struct pmc_bit_map *cnp_slps0_dbg_maps[];
|
||||
extern const struct pmc_bit_map cnp_ltr_show_map[];
|
||||
extern const struct pmc_reg_map cnp_reg_map;
|
||||
extern const struct pmc_bit_map icl_pfear_map[];
|
||||
extern const struct pmc_bit_map *ext_icl_pfear_map[];
|
||||
extern const struct pmc_reg_map icl_reg_map;
|
||||
extern const struct pmc_bit_map tgl_pfear_map[];
|
||||
extern const struct pmc_bit_map *ext_tgl_pfear_map[];
|
||||
extern const struct pmc_bit_map tgl_clocksource_status_map[];
|
||||
extern const struct pmc_bit_map tgl_power_gating_status_map[];
|
||||
extern const struct pmc_bit_map tgl_d3_status_map[];
|
||||
extern const struct pmc_bit_map tgl_vnn_req_status_map[];
|
||||
extern const struct pmc_bit_map tgl_vnn_misc_status_map[];
|
||||
extern const struct pmc_bit_map tgl_signal_status_map[];
|
||||
extern const struct pmc_bit_map *tgl_lpm_maps[];
|
||||
extern const struct pmc_reg_map tgl_reg_map;
|
||||
extern const struct pmc_bit_map adl_pfear_map[];
|
||||
extern const struct pmc_bit_map *ext_adl_pfear_map[];
|
||||
extern const struct pmc_bit_map adl_ltr_show_map[];
|
||||
extern const struct pmc_bit_map adl_clocksource_status_map[];
|
||||
extern const struct pmc_bit_map adl_power_gating_status_0_map[];
|
||||
extern const struct pmc_bit_map adl_power_gating_status_1_map[];
|
||||
extern const struct pmc_bit_map adl_power_gating_status_2_map[];
|
||||
extern const struct pmc_bit_map adl_d3_status_0_map[];
|
||||
extern const struct pmc_bit_map adl_d3_status_1_map[];
|
||||
extern const struct pmc_bit_map adl_d3_status_2_map[];
|
||||
extern const struct pmc_bit_map adl_d3_status_3_map[];
|
||||
extern const struct pmc_bit_map adl_vnn_req_status_0_map[];
|
||||
extern const struct pmc_bit_map adl_vnn_req_status_1_map[];
|
||||
extern const struct pmc_bit_map adl_vnn_req_status_2_map[];
|
||||
extern const struct pmc_bit_map adl_vnn_req_status_3_map[];
|
||||
extern const struct pmc_bit_map adl_vnn_misc_status_map[];
|
||||
extern const struct pmc_bit_map *adl_lpm_maps[];
|
||||
extern const struct pmc_reg_map adl_reg_map;
|
||||
extern const struct pmc_reg_map mtl_reg_map;
|
||||
|
||||
extern void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev);
|
||||
extern int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value);
|
||||
|
||||
void spt_core_init(struct pmc_dev *pmcdev);
|
||||
void cnp_core_init(struct pmc_dev *pmcdev);
|
||||
void icl_core_init(struct pmc_dev *pmcdev);
|
||||
void tgl_core_init(struct pmc_dev *pmcdev);
|
||||
void adl_core_init(struct pmc_dev *pmcdev);
|
||||
void mtl_core_init(struct pmc_dev *pmcdev);
|
||||
void tgl_core_configure(struct pmc_dev *pmcdev);
|
||||
void adl_core_configure(struct pmc_dev *pmcdev);
|
||||
void mtl_core_configure(struct pmc_dev *pmcdev);
|
||||
|
||||
#define pmc_for_each_mode(i, mode, pmcdev) \
|
||||
for (i = 0, mode = pmcdev->lpm_en_modes[i]; \
|
||||
i < pmcdev->num_lpm_modes; \
|
||||
|
56
drivers/platform/x86/intel/pmc/icl.c
Normal file
56
drivers/platform/x86/intel/pmc/icl.c
Normal file
@ -0,0 +1,56 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* This file contains platform specific structure definitions
|
||||
* and init function used by Ice Lake PCH.
|
||||
*
|
||||
* Copyright (c) 2022, Intel Corporation.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
|
||||
const struct pmc_bit_map icl_pfear_map[] = {
|
||||
{"RES_65", BIT(0)},
|
||||
{"RES_66", BIT(1)},
|
||||
{"RES_67", BIT(2)},
|
||||
{"TAM", BIT(3)},
|
||||
{"GBETSN", BIT(4)},
|
||||
{"TBTLSX", BIT(5)},
|
||||
{"RES_71", BIT(6)},
|
||||
{"RES_72", BIT(7)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map *ext_icl_pfear_map[] = {
|
||||
/*
|
||||
* Check intel_pmc_core_ids[] users of icl_reg_map for
|
||||
* a list of core SoCs using this.
|
||||
*/
|
||||
cnp_pfear_map,
|
||||
icl_pfear_map,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct pmc_reg_map icl_reg_map = {
|
||||
.pfear_sts = ext_icl_pfear_map,
|
||||
.slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
|
||||
.slp_s0_res_counter_step = ICL_PMC_SLP_S0_RES_COUNTER_STEP,
|
||||
.slps0_dbg_maps = cnp_slps0_dbg_maps,
|
||||
.ltr_show_sts = cnp_ltr_show_map,
|
||||
.msr_sts = msr_map,
|
||||
.slps0_dbg_offset = CNP_PMC_SLPS0_DBG_OFFSET,
|
||||
.ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
|
||||
.regmap_length = CNP_PMC_MMIO_REG_LEN,
|
||||
.ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
|
||||
.ppfear_buckets = ICL_PPFEAR_NUM_ENTRIES,
|
||||
.pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
|
||||
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
|
||||
.ltr_ignore_max = ICL_NUM_IP_IGN_ALLOWED,
|
||||
.etr3_offset = ETR3_OFFSET,
|
||||
};
|
||||
|
||||
void icl_core_init(struct pmc_dev *pmcdev)
|
||||
{
|
||||
pmcdev->map = &icl_reg_map;
|
||||
}
|
52
drivers/platform/x86/intel/pmc/mtl.c
Normal file
52
drivers/platform/x86/intel/pmc/mtl.c
Normal file
@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* This file contains platform specific structure definitions
|
||||
* and init function used by Meteor Lake PCH.
|
||||
*
|
||||
* Copyright (c) 2022, Intel Corporation.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
|
||||
const struct pmc_reg_map mtl_reg_map = {
|
||||
.pfear_sts = ext_tgl_pfear_map,
|
||||
.slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
|
||||
.slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP,
|
||||
.ltr_show_sts = adl_ltr_show_map,
|
||||
.msr_sts = msr_map,
|
||||
.ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
|
||||
.regmap_length = CNP_PMC_MMIO_REG_LEN,
|
||||
.ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
|
||||
.ppfear_buckets = ICL_PPFEAR_NUM_ENTRIES,
|
||||
.pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
|
||||
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
|
||||
.ltr_ignore_max = ADL_NUM_IP_IGN_ALLOWED,
|
||||
.lpm_num_modes = ADL_LPM_NUM_MODES,
|
||||
.lpm_num_maps = ADL_LPM_NUM_MAPS,
|
||||
.lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2,
|
||||
.etr3_offset = ETR3_OFFSET,
|
||||
.lpm_sts_latch_en_offset = MTL_LPM_STATUS_LATCH_EN_OFFSET,
|
||||
.lpm_priority_offset = MTL_LPM_PRI_OFFSET,
|
||||
.lpm_en_offset = MTL_LPM_EN_OFFSET,
|
||||
.lpm_residency_offset = MTL_LPM_RESIDENCY_OFFSET,
|
||||
.lpm_sts = adl_lpm_maps,
|
||||
.lpm_status_offset = MTL_LPM_STATUS_OFFSET,
|
||||
.lpm_live_status_offset = MTL_LPM_LIVE_STATUS_OFFSET,
|
||||
};
|
||||
|
||||
void mtl_core_configure(struct pmc_dev *pmcdev)
|
||||
{
|
||||
/* Due to a hardware limitation, the GBE LTR blocks PC10
|
||||
* when a cable is attached. Tell the PMC to ignore it.
|
||||
*/
|
||||
dev_dbg(&pmcdev->pdev->dev, "ignoring GBE LTR\n");
|
||||
pmc_core_send_ltr_ignore(pmcdev, 3);
|
||||
}
|
||||
|
||||
void mtl_core_init(struct pmc_dev *pmcdev)
|
||||
{
|
||||
pmcdev->map = &mtl_reg_map;
|
||||
pmcdev->core_configure = mtl_core_configure;
|
||||
}
|
140
drivers/platform/x86/intel/pmc/spt.c
Normal file
140
drivers/platform/x86/intel/pmc/spt.c
Normal file
@ -0,0 +1,140 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* This file contains platform specific structure definitions
|
||||
* and init function used by Sunrise Point PCH.
|
||||
*
|
||||
* Copyright (c) 2022, Intel Corporation.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
|
||||
const struct pmc_bit_map spt_pll_map[] = {
|
||||
{"MIPI PLL", SPT_PMC_BIT_MPHY_CMN_LANE0},
|
||||
{"GEN2 USB2PCIE2 PLL", SPT_PMC_BIT_MPHY_CMN_LANE1},
|
||||
{"DMIPCIE3 PLL", SPT_PMC_BIT_MPHY_CMN_LANE2},
|
||||
{"SATA PLL", SPT_PMC_BIT_MPHY_CMN_LANE3},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map spt_mphy_map[] = {
|
||||
{"MPHY CORE LANE 0", SPT_PMC_BIT_MPHY_LANE0},
|
||||
{"MPHY CORE LANE 1", SPT_PMC_BIT_MPHY_LANE1},
|
||||
{"MPHY CORE LANE 2", SPT_PMC_BIT_MPHY_LANE2},
|
||||
{"MPHY CORE LANE 3", SPT_PMC_BIT_MPHY_LANE3},
|
||||
{"MPHY CORE LANE 4", SPT_PMC_BIT_MPHY_LANE4},
|
||||
{"MPHY CORE LANE 5", SPT_PMC_BIT_MPHY_LANE5},
|
||||
{"MPHY CORE LANE 6", SPT_PMC_BIT_MPHY_LANE6},
|
||||
{"MPHY CORE LANE 7", SPT_PMC_BIT_MPHY_LANE7},
|
||||
{"MPHY CORE LANE 8", SPT_PMC_BIT_MPHY_LANE8},
|
||||
{"MPHY CORE LANE 9", SPT_PMC_BIT_MPHY_LANE9},
|
||||
{"MPHY CORE LANE 10", SPT_PMC_BIT_MPHY_LANE10},
|
||||
{"MPHY CORE LANE 11", SPT_PMC_BIT_MPHY_LANE11},
|
||||
{"MPHY CORE LANE 12", SPT_PMC_BIT_MPHY_LANE12},
|
||||
{"MPHY CORE LANE 13", SPT_PMC_BIT_MPHY_LANE13},
|
||||
{"MPHY CORE LANE 14", SPT_PMC_BIT_MPHY_LANE14},
|
||||
{"MPHY CORE LANE 15", SPT_PMC_BIT_MPHY_LANE15},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map spt_pfear_map[] = {
|
||||
{"PMC", SPT_PMC_BIT_PMC},
|
||||
{"OPI-DMI", SPT_PMC_BIT_OPI},
|
||||
{"SPI / eSPI", SPT_PMC_BIT_SPI},
|
||||
{"XHCI", SPT_PMC_BIT_XHCI},
|
||||
{"SPA", SPT_PMC_BIT_SPA},
|
||||
{"SPB", SPT_PMC_BIT_SPB},
|
||||
{"SPC", SPT_PMC_BIT_SPC},
|
||||
{"GBE", SPT_PMC_BIT_GBE},
|
||||
{"SATA", SPT_PMC_BIT_SATA},
|
||||
{"HDA-PGD0", SPT_PMC_BIT_HDA_PGD0},
|
||||
{"HDA-PGD1", SPT_PMC_BIT_HDA_PGD1},
|
||||
{"HDA-PGD2", SPT_PMC_BIT_HDA_PGD2},
|
||||
{"HDA-PGD3", SPT_PMC_BIT_HDA_PGD3},
|
||||
{"RSVD", SPT_PMC_BIT_RSVD_0B},
|
||||
{"LPSS", SPT_PMC_BIT_LPSS},
|
||||
{"LPC", SPT_PMC_BIT_LPC},
|
||||
{"SMB", SPT_PMC_BIT_SMB},
|
||||
{"ISH", SPT_PMC_BIT_ISH},
|
||||
{"P2SB", SPT_PMC_BIT_P2SB},
|
||||
{"DFX", SPT_PMC_BIT_DFX},
|
||||
{"SCC", SPT_PMC_BIT_SCC},
|
||||
{"RSVD", SPT_PMC_BIT_RSVD_0C},
|
||||
{"FUSE", SPT_PMC_BIT_FUSE},
|
||||
{"CAMERA", SPT_PMC_BIT_CAMREA},
|
||||
{"RSVD", SPT_PMC_BIT_RSVD_0D},
|
||||
{"USB3-OTG", SPT_PMC_BIT_USB3_OTG},
|
||||
{"EXI", SPT_PMC_BIT_EXI},
|
||||
{"CSE", SPT_PMC_BIT_CSE},
|
||||
{"CSME_KVM", SPT_PMC_BIT_CSME_KVM},
|
||||
{"CSME_PMT", SPT_PMC_BIT_CSME_PMT},
|
||||
{"CSME_CLINK", SPT_PMC_BIT_CSME_CLINK},
|
||||
{"CSME_PTIO", SPT_PMC_BIT_CSME_PTIO},
|
||||
{"CSME_USBR", SPT_PMC_BIT_CSME_USBR},
|
||||
{"CSME_SUSRAM", SPT_PMC_BIT_CSME_SUSRAM},
|
||||
{"CSME_SMT", SPT_PMC_BIT_CSME_SMT},
|
||||
{"RSVD", SPT_PMC_BIT_RSVD_1A},
|
||||
{"CSME_SMS2", SPT_PMC_BIT_CSME_SMS2},
|
||||
{"CSME_SMS1", SPT_PMC_BIT_CSME_SMS1},
|
||||
{"CSME_RTC", SPT_PMC_BIT_CSME_RTC},
|
||||
{"CSME_PSF", SPT_PMC_BIT_CSME_PSF},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map *ext_spt_pfear_map[] = {
|
||||
/*
|
||||
* Check intel_pmc_core_ids[] users of spt_reg_map for
|
||||
* a list of core SoCs using this.
|
||||
*/
|
||||
spt_pfear_map,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct pmc_bit_map spt_ltr_show_map[] = {
|
||||
{"SOUTHPORT_A", SPT_PMC_LTR_SPA},
|
||||
{"SOUTHPORT_B", SPT_PMC_LTR_SPB},
|
||||
{"SATA", SPT_PMC_LTR_SATA},
|
||||
{"GIGABIT_ETHERNET", SPT_PMC_LTR_GBE},
|
||||
{"XHCI", SPT_PMC_LTR_XHCI},
|
||||
{"Reserved", SPT_PMC_LTR_RESERVED},
|
||||
{"ME", SPT_PMC_LTR_ME},
|
||||
/* EVA is Enterprise Value Add, doesn't really exist on PCH */
|
||||
{"EVA", SPT_PMC_LTR_EVA},
|
||||
{"SOUTHPORT_C", SPT_PMC_LTR_SPC},
|
||||
{"HD_AUDIO", SPT_PMC_LTR_AZ},
|
||||
{"LPSS", SPT_PMC_LTR_LPSS},
|
||||
{"SOUTHPORT_D", SPT_PMC_LTR_SPD},
|
||||
{"SOUTHPORT_E", SPT_PMC_LTR_SPE},
|
||||
{"CAMERA", SPT_PMC_LTR_CAM},
|
||||
{"ESPI", SPT_PMC_LTR_ESPI},
|
||||
{"SCC", SPT_PMC_LTR_SCC},
|
||||
{"ISH", SPT_PMC_LTR_ISH},
|
||||
/* Below two cannot be used for LTR_IGNORE */
|
||||
{"CURRENT_PLATFORM", SPT_PMC_LTR_CUR_PLT},
|
||||
{"AGGREGATED_SYSTEM", SPT_PMC_LTR_CUR_ASLT},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_reg_map spt_reg_map = {
|
||||
.pfear_sts = ext_spt_pfear_map,
|
||||
.mphy_sts = spt_mphy_map,
|
||||
.pll_sts = spt_pll_map,
|
||||
.ltr_show_sts = spt_ltr_show_map,
|
||||
.msr_sts = msr_map,
|
||||
.slp_s0_offset = SPT_PMC_SLP_S0_RES_COUNTER_OFFSET,
|
||||
.slp_s0_res_counter_step = SPT_PMC_SLP_S0_RES_COUNTER_STEP,
|
||||
.ltr_ignore_offset = SPT_PMC_LTR_IGNORE_OFFSET,
|
||||
.regmap_length = SPT_PMC_MMIO_REG_LEN,
|
||||
.ppfear0_offset = SPT_PMC_XRAM_PPFEAR0A,
|
||||
.ppfear_buckets = SPT_PPFEAR_NUM_ENTRIES,
|
||||
.pm_cfg_offset = SPT_PMC_PM_CFG_OFFSET,
|
||||
.pm_read_disable_bit = SPT_PMC_READ_DISABLE_BIT,
|
||||
.ltr_ignore_max = SPT_NUM_IP_IGN_ALLOWED,
|
||||
.pm_vric1_offset = SPT_PMC_VRIC1_OFFSET,
|
||||
};
|
||||
|
||||
void spt_core_init(struct pmc_dev *pmcdev)
|
||||
{
|
||||
pmcdev->map = &spt_reg_map;
|
||||
}
|
269
drivers/platform/x86/intel/pmc/tgl.c
Normal file
269
drivers/platform/x86/intel/pmc/tgl.c
Normal file
@ -0,0 +1,269 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* This file contains platform specific structure definitions
|
||||
* and init function used by Tiger Lake PCH.
|
||||
*
|
||||
* Copyright (c) 2022, Intel Corporation.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
|
||||
#define ACPI_S0IX_DSM_UUID "57a6512e-3979-4e9d-9708-ff13b2508972"
|
||||
#define ACPI_GET_LOW_MODE_REGISTERS 1
|
||||
|
||||
const struct pmc_bit_map tgl_pfear_map[] = {
|
||||
{"PSF9", BIT(0)},
|
||||
{"RES_66", BIT(1)},
|
||||
{"RES_67", BIT(2)},
|
||||
{"RES_68", BIT(3)},
|
||||
{"RES_69", BIT(4)},
|
||||
{"RES_70", BIT(5)},
|
||||
{"TBTLSX", BIT(6)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map *ext_tgl_pfear_map[] = {
|
||||
/*
|
||||
* Check intel_pmc_core_ids[] users of tgl_reg_map for
|
||||
* a list of core SoCs using this.
|
||||
*/
|
||||
cnp_pfear_map,
|
||||
tgl_pfear_map,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct pmc_bit_map tgl_clocksource_status_map[] = {
|
||||
{"USB2PLL_OFF_STS", BIT(18)},
|
||||
{"PCIe/USB3.1_Gen2PLL_OFF_STS", BIT(19)},
|
||||
{"PCIe_Gen3PLL_OFF_STS", BIT(20)},
|
||||
{"OPIOPLL_OFF_STS", BIT(21)},
|
||||
{"OCPLL_OFF_STS", BIT(22)},
|
||||
{"MainPLL_OFF_STS", BIT(23)},
|
||||
{"MIPIPLL_OFF_STS", BIT(24)},
|
||||
{"Fast_XTAL_Osc_OFF_STS", BIT(25)},
|
||||
{"AC_Ring_Osc_OFF_STS", BIT(26)},
|
||||
{"MC_Ring_Osc_OFF_STS", BIT(27)},
|
||||
{"SATAPLL_OFF_STS", BIT(29)},
|
||||
{"XTAL_USB2PLL_OFF_STS", BIT(31)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map tgl_power_gating_status_map[] = {
|
||||
{"CSME_PG_STS", BIT(0)},
|
||||
{"SATA_PG_STS", BIT(1)},
|
||||
{"xHCI_PG_STS", BIT(2)},
|
||||
{"UFSX2_PG_STS", BIT(3)},
|
||||
{"OTG_PG_STS", BIT(5)},
|
||||
{"SPA_PG_STS", BIT(6)},
|
||||
{"SPB_PG_STS", BIT(7)},
|
||||
{"SPC_PG_STS", BIT(8)},
|
||||
{"SPD_PG_STS", BIT(9)},
|
||||
{"SPE_PG_STS", BIT(10)},
|
||||
{"SPF_PG_STS", BIT(11)},
|
||||
{"LSX_PG_STS", BIT(13)},
|
||||
{"P2SB_PG_STS", BIT(14)},
|
||||
{"PSF_PG_STS", BIT(15)},
|
||||
{"SBR_PG_STS", BIT(16)},
|
||||
{"OPIDMI_PG_STS", BIT(17)},
|
||||
{"THC0_PG_STS", BIT(18)},
|
||||
{"THC1_PG_STS", BIT(19)},
|
||||
{"GBETSN_PG_STS", BIT(20)},
|
||||
{"GBE_PG_STS", BIT(21)},
|
||||
{"LPSS_PG_STS", BIT(22)},
|
||||
{"MMP_UFSX2_PG_STS", BIT(23)},
|
||||
{"MMP_UFSX2B_PG_STS", BIT(24)},
|
||||
{"FIA_PG_STS", BIT(25)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map tgl_d3_status_map[] = {
|
||||
{"ADSP_D3_STS", BIT(0)},
|
||||
{"SATA_D3_STS", BIT(1)},
|
||||
{"xHCI0_D3_STS", BIT(2)},
|
||||
{"xDCI1_D3_STS", BIT(5)},
|
||||
{"SDX_D3_STS", BIT(6)},
|
||||
{"EMMC_D3_STS", BIT(7)},
|
||||
{"IS_D3_STS", BIT(8)},
|
||||
{"THC0_D3_STS", BIT(9)},
|
||||
{"THC1_D3_STS", BIT(10)},
|
||||
{"GBE_D3_STS", BIT(11)},
|
||||
{"GBE_TSN_D3_STS", BIT(12)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map tgl_vnn_req_status_map[] = {
|
||||
{"GPIO_COM0_VNN_REQ_STS", BIT(1)},
|
||||
{"GPIO_COM1_VNN_REQ_STS", BIT(2)},
|
||||
{"GPIO_COM2_VNN_REQ_STS", BIT(3)},
|
||||
{"GPIO_COM3_VNN_REQ_STS", BIT(4)},
|
||||
{"GPIO_COM4_VNN_REQ_STS", BIT(5)},
|
||||
{"GPIO_COM5_VNN_REQ_STS", BIT(6)},
|
||||
{"Audio_VNN_REQ_STS", BIT(7)},
|
||||
{"ISH_VNN_REQ_STS", BIT(8)},
|
||||
{"CNVI_VNN_REQ_STS", BIT(9)},
|
||||
{"eSPI_VNN_REQ_STS", BIT(10)},
|
||||
{"Display_VNN_REQ_STS", BIT(11)},
|
||||
{"DTS_VNN_REQ_STS", BIT(12)},
|
||||
{"SMBUS_VNN_REQ_STS", BIT(14)},
|
||||
{"CSME_VNN_REQ_STS", BIT(15)},
|
||||
{"SMLINK0_VNN_REQ_STS", BIT(16)},
|
||||
{"SMLINK1_VNN_REQ_STS", BIT(17)},
|
||||
{"CLINK_VNN_REQ_STS", BIT(20)},
|
||||
{"DCI_VNN_REQ_STS", BIT(21)},
|
||||
{"ITH_VNN_REQ_STS", BIT(22)},
|
||||
{"CSME_VNN_REQ_STS", BIT(24)},
|
||||
{"GBE_VNN_REQ_STS", BIT(25)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map tgl_vnn_misc_status_map[] = {
|
||||
{"CPU_C10_REQ_STS_0", BIT(0)},
|
||||
{"PCIe_LPM_En_REQ_STS_3", BIT(3)},
|
||||
{"ITH_REQ_STS_5", BIT(5)},
|
||||
{"CNVI_REQ_STS_6", BIT(6)},
|
||||
{"ISH_REQ_STS_7", BIT(7)},
|
||||
{"USB2_SUS_PG_Sys_REQ_STS_10", BIT(10)},
|
||||
{"PCIe_Clk_REQ_STS_12", BIT(12)},
|
||||
{"MPHY_Core_DL_REQ_STS_16", BIT(16)},
|
||||
{"Break-even_En_REQ_STS_17", BIT(17)},
|
||||
{"Auto-demo_En_REQ_STS_18", BIT(18)},
|
||||
{"MPHY_SUS_REQ_STS_22", BIT(22)},
|
||||
{"xDCI_attached_REQ_STS_24", BIT(24)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map tgl_signal_status_map[] = {
|
||||
{"LSX_Wake0_En_STS", BIT(0)},
|
||||
{"LSX_Wake0_Pol_STS", BIT(1)},
|
||||
{"LSX_Wake1_En_STS", BIT(2)},
|
||||
{"LSX_Wake1_Pol_STS", BIT(3)},
|
||||
{"LSX_Wake2_En_STS", BIT(4)},
|
||||
{"LSX_Wake2_Pol_STS", BIT(5)},
|
||||
{"LSX_Wake3_En_STS", BIT(6)},
|
||||
{"LSX_Wake3_Pol_STS", BIT(7)},
|
||||
{"LSX_Wake4_En_STS", BIT(8)},
|
||||
{"LSX_Wake4_Pol_STS", BIT(9)},
|
||||
{"LSX_Wake5_En_STS", BIT(10)},
|
||||
{"LSX_Wake5_Pol_STS", BIT(11)},
|
||||
{"LSX_Wake6_En_STS", BIT(12)},
|
||||
{"LSX_Wake6_Pol_STS", BIT(13)},
|
||||
{"LSX_Wake7_En_STS", BIT(14)},
|
||||
{"LSX_Wake7_Pol_STS", BIT(15)},
|
||||
{"Intel_Se_IO_Wake0_En_STS", BIT(16)},
|
||||
{"Intel_Se_IO_Wake0_Pol_STS", BIT(17)},
|
||||
{"Intel_Se_IO_Wake1_En_STS", BIT(18)},
|
||||
{"Intel_Se_IO_Wake1_Pol_STS", BIT(19)},
|
||||
{"Int_Timer_SS_Wake0_En_STS", BIT(20)},
|
||||
{"Int_Timer_SS_Wake0_Pol_STS", BIT(21)},
|
||||
{"Int_Timer_SS_Wake1_En_STS", BIT(22)},
|
||||
{"Int_Timer_SS_Wake1_Pol_STS", BIT(23)},
|
||||
{"Int_Timer_SS_Wake2_En_STS", BIT(24)},
|
||||
{"Int_Timer_SS_Wake2_Pol_STS", BIT(25)},
|
||||
{"Int_Timer_SS_Wake3_En_STS", BIT(26)},
|
||||
{"Int_Timer_SS_Wake3_Pol_STS", BIT(27)},
|
||||
{"Int_Timer_SS_Wake4_En_STS", BIT(28)},
|
||||
{"Int_Timer_SS_Wake4_Pol_STS", BIT(29)},
|
||||
{"Int_Timer_SS_Wake5_En_STS", BIT(30)},
|
||||
{"Int_Timer_SS_Wake5_Pol_STS", BIT(31)},
|
||||
{}
|
||||
};
|
||||
|
||||
const struct pmc_bit_map *tgl_lpm_maps[] = {
|
||||
tgl_clocksource_status_map,
|
||||
tgl_power_gating_status_map,
|
||||
tgl_d3_status_map,
|
||||
tgl_vnn_req_status_map,
|
||||
tgl_vnn_misc_status_map,
|
||||
tgl_signal_status_map,
|
||||
NULL
|
||||
};
|
||||
|
||||
const struct pmc_reg_map tgl_reg_map = {
|
||||
.pfear_sts = ext_tgl_pfear_map,
|
||||
.slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
|
||||
.slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP,
|
||||
.ltr_show_sts = cnp_ltr_show_map,
|
||||
.msr_sts = msr_map,
|
||||
.ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
|
||||
.regmap_length = CNP_PMC_MMIO_REG_LEN,
|
||||
.ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
|
||||
.ppfear_buckets = ICL_PPFEAR_NUM_ENTRIES,
|
||||
.pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
|
||||
.pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
|
||||
.ltr_ignore_max = TGL_NUM_IP_IGN_ALLOWED,
|
||||
.lpm_num_maps = TGL_LPM_NUM_MAPS,
|
||||
.lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2,
|
||||
.lpm_sts_latch_en_offset = TGL_LPM_STS_LATCH_EN_OFFSET,
|
||||
.lpm_en_offset = TGL_LPM_EN_OFFSET,
|
||||
.lpm_priority_offset = TGL_LPM_PRI_OFFSET,
|
||||
.lpm_residency_offset = TGL_LPM_RESIDENCY_OFFSET,
|
||||
.lpm_sts = tgl_lpm_maps,
|
||||
.lpm_status_offset = TGL_LPM_STATUS_OFFSET,
|
||||
.lpm_live_status_offset = TGL_LPM_LIVE_STATUS_OFFSET,
|
||||
.etr3_offset = ETR3_OFFSET,
|
||||
};
|
||||
|
||||
void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev)
|
||||
{
|
||||
struct pmc_dev *pmcdev = platform_get_drvdata(pdev);
|
||||
const int num_maps = pmcdev->map->lpm_num_maps;
|
||||
u32 lpm_size = LPM_MAX_NUM_MODES * num_maps * 4;
|
||||
union acpi_object *out_obj;
|
||||
struct acpi_device *adev;
|
||||
guid_t s0ix_dsm_guid;
|
||||
u32 *lpm_req_regs, *addr;
|
||||
|
||||
adev = ACPI_COMPANION(&pdev->dev);
|
||||
if (!adev)
|
||||
return;
|
||||
|
||||
guid_parse(ACPI_S0IX_DSM_UUID, &s0ix_dsm_guid);
|
||||
|
||||
out_obj = acpi_evaluate_dsm(adev->handle, &s0ix_dsm_guid, 0,
|
||||
ACPI_GET_LOW_MODE_REGISTERS, NULL);
|
||||
if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) {
|
||||
u32 size = out_obj->buffer.length;
|
||||
|
||||
if (size != lpm_size) {
|
||||
acpi_handle_debug(adev->handle,
|
||||
"_DSM returned unexpected buffer size, have %u, expect %u\n",
|
||||
size, lpm_size);
|
||||
goto free_acpi_obj;
|
||||
}
|
||||
} else {
|
||||
acpi_handle_debug(adev->handle,
|
||||
"_DSM function 0 evaluation failed\n");
|
||||
goto free_acpi_obj;
|
||||
}
|
||||
|
||||
addr = (u32 *)out_obj->buffer.pointer;
|
||||
|
||||
lpm_req_regs = devm_kzalloc(&pdev->dev, lpm_size * sizeof(u32),
|
||||
GFP_KERNEL);
|
||||
if (!lpm_req_regs)
|
||||
goto free_acpi_obj;
|
||||
|
||||
memcpy(lpm_req_regs, addr, lpm_size);
|
||||
pmcdev->lpm_req_regs = lpm_req_regs;
|
||||
|
||||
free_acpi_obj:
|
||||
ACPI_FREE(out_obj);
|
||||
}
|
||||
|
||||
void tgl_core_configure(struct pmc_dev *pmcdev)
|
||||
{
|
||||
pmc_core_get_tgl_lpm_reqs(pmcdev->pdev);
|
||||
/* Due to a hardware limitation, the GBE LTR blocks PC10
|
||||
* when a cable is attached. Tell the PMC to ignore it.
|
||||
*/
|
||||
dev_dbg(&pmcdev->pdev->dev, "ignoring GBE LTR\n");
|
||||
pmc_core_send_ltr_ignore(pmcdev, 3);
|
||||
}
|
||||
|
||||
void tgl_core_init(struct pmc_dev *pmcdev)
|
||||
{
|
||||
pmcdev->map = &tgl_reg_map;
|
||||
pmcdev->core_configure = tgl_core_configure;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Intel Software Defined Silicon driver
|
||||
* Intel On Demand (Software Defined Silicon) driver
|
||||
*
|
||||
* Copyright (c) 2022, Intel Corporation.
|
||||
* All Rights Reserved.
|
||||
@ -27,9 +27,8 @@
|
||||
#define ACCESS_TYPE_LOCAL 3
|
||||
|
||||
#define SDSI_MIN_SIZE_DWORDS 276
|
||||
#define SDSI_SIZE_CONTROL 8
|
||||
#define SDSI_SIZE_MAILBOX 1024
|
||||
#define SDSI_SIZE_REGS 72
|
||||
#define SDSI_SIZE_REGS 80
|
||||
#define SDSI_SIZE_CMD sizeof(u64)
|
||||
|
||||
/*
|
||||
@ -41,7 +40,9 @@
|
||||
#define SDSI_SIZE_READ_MSG (SDSI_SIZE_MAILBOX * 4)
|
||||
|
||||
#define SDSI_ENABLED_FEATURES_OFFSET 16
|
||||
#define SDSI_ENABLED BIT(3)
|
||||
#define SDSI_FEATURE_SDSI BIT(3)
|
||||
#define SDSI_FEATURE_METERING BIT(26)
|
||||
|
||||
#define SDSI_SOCKET_ID_OFFSET 64
|
||||
#define SDSI_SOCKET_ID GENMASK(3, 0)
|
||||
|
||||
@ -75,10 +76,18 @@
|
||||
#define DT_TBIR GENMASK(2, 0)
|
||||
#define DT_OFFSET(v) ((v) & GENMASK(31, 3))
|
||||
|
||||
#define SDSI_GUID_V1 0x006DD191
|
||||
#define GUID_V1_CNTRL_SIZE 8
|
||||
#define GUID_V1_REGS_SIZE 72
|
||||
#define SDSI_GUID_V2 0xF210D9EF
|
||||
#define GUID_V2_CNTRL_SIZE 16
|
||||
#define GUID_V2_REGS_SIZE 80
|
||||
|
||||
enum sdsi_command {
|
||||
SDSI_CMD_PROVISION_AKC = 0x04,
|
||||
SDSI_CMD_PROVISION_CAP = 0x08,
|
||||
SDSI_CMD_READ_STATE = 0x10,
|
||||
SDSI_CMD_PROVISION_AKC = 0x0004,
|
||||
SDSI_CMD_PROVISION_CAP = 0x0008,
|
||||
SDSI_CMD_READ_STATE = 0x0010,
|
||||
SDSI_CMD_READ_METER = 0x0014,
|
||||
};
|
||||
|
||||
struct sdsi_mbox_info {
|
||||
@ -99,8 +108,11 @@ struct sdsi_priv {
|
||||
void __iomem *control_addr;
|
||||
void __iomem *mbox_addr;
|
||||
void __iomem *regs_addr;
|
||||
int control_size;
|
||||
int maibox_size;
|
||||
int registers_size;
|
||||
u32 guid;
|
||||
bool sdsi_enabled;
|
||||
u32 features;
|
||||
};
|
||||
|
||||
/* SDSi mailbox operations must be performed using 64bit mov instructions */
|
||||
@ -332,9 +344,6 @@ static ssize_t sdsi_provision(struct sdsi_priv *priv, char *buf, size_t count,
|
||||
struct sdsi_mbox_info info;
|
||||
int ret;
|
||||
|
||||
if (!priv->sdsi_enabled)
|
||||
return -EPERM;
|
||||
|
||||
if (count > (SDSI_SIZE_WRITE_MSG - SDSI_SIZE_CMD))
|
||||
return -EOVERFLOW;
|
||||
|
||||
@ -394,20 +403,14 @@ static ssize_t provision_cap_write(struct file *filp, struct kobject *kobj,
|
||||
}
|
||||
static BIN_ATTR_WO(provision_cap, SDSI_SIZE_WRITE_MSG);
|
||||
|
||||
static long state_certificate_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf, loff_t off,
|
||||
size_t count)
|
||||
static ssize_t
|
||||
certificate_read(u64 command, struct sdsi_priv *priv, char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct sdsi_priv *priv = dev_get_drvdata(dev);
|
||||
u64 command = SDSI_CMD_READ_STATE;
|
||||
struct sdsi_mbox_info info;
|
||||
size_t size;
|
||||
int ret;
|
||||
|
||||
if (!priv->sdsi_enabled)
|
||||
return -EPERM;
|
||||
|
||||
if (off)
|
||||
return 0;
|
||||
|
||||
@ -440,7 +443,30 @@ free_buffer:
|
||||
|
||||
return size;
|
||||
}
|
||||
static BIN_ATTR(state_certificate, 0400, state_certificate_read, NULL, SDSI_SIZE_READ_MSG);
|
||||
|
||||
static ssize_t
|
||||
state_certificate_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct sdsi_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
return certificate_read(SDSI_CMD_READ_STATE, priv, buf, off, count);
|
||||
}
|
||||
static BIN_ATTR_ADMIN_RO(state_certificate, SDSI_SIZE_READ_MSG);
|
||||
|
||||
static ssize_t
|
||||
meter_certificate_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct sdsi_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
return certificate_read(SDSI_CMD_READ_METER, priv, buf, off, count);
|
||||
}
|
||||
static BIN_ATTR_ADMIN_RO(meter_certificate, SDSI_SIZE_READ_MSG);
|
||||
|
||||
static ssize_t registers_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf, loff_t off,
|
||||
@ -449,21 +475,55 @@ static ssize_t registers_read(struct file *filp, struct kobject *kobj,
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct sdsi_priv *priv = dev_get_drvdata(dev);
|
||||
void __iomem *addr = priv->regs_addr;
|
||||
int size = priv->registers_size;
|
||||
|
||||
/*
|
||||
* The check below is performed by the sysfs caller based on the static
|
||||
* file size. But this may be greater than the actual size which is based
|
||||
* on the GUID. So check here again based on actual size before reading.
|
||||
*/
|
||||
if (off >= size)
|
||||
return 0;
|
||||
|
||||
if (off + count > size)
|
||||
count = size - off;
|
||||
|
||||
memcpy_fromio(buf, addr + off, count);
|
||||
|
||||
return count;
|
||||
}
|
||||
static BIN_ATTR(registers, 0400, registers_read, NULL, SDSI_SIZE_REGS);
|
||||
static BIN_ATTR_ADMIN_RO(registers, SDSI_SIZE_REGS);
|
||||
|
||||
static struct bin_attribute *sdsi_bin_attrs[] = {
|
||||
&bin_attr_registers,
|
||||
&bin_attr_state_certificate,
|
||||
&bin_attr_meter_certificate,
|
||||
&bin_attr_provision_akc,
|
||||
&bin_attr_provision_cap,
|
||||
NULL
|
||||
};
|
||||
|
||||
static umode_t
|
||||
sdsi_battr_is_visible(struct kobject *kobj, struct bin_attribute *attr, int n)
|
||||
{
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct sdsi_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
/* Registers file is always readable if the device is present */
|
||||
if (attr == &bin_attr_registers)
|
||||
return attr->attr.mode;
|
||||
|
||||
/* All other attributes not visible if BIOS has not enabled On Demand */
|
||||
if (!(priv->features & SDSI_FEATURE_SDSI))
|
||||
return 0;
|
||||
|
||||
if (attr == &bin_attr_meter_certificate)
|
||||
return (priv->features & SDSI_FEATURE_METERING) ?
|
||||
attr->attr.mode : 0;
|
||||
|
||||
return attr->attr.mode;
|
||||
}
|
||||
|
||||
static ssize_t guid_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct sdsi_priv *priv = dev_get_drvdata(dev);
|
||||
@ -480,9 +540,28 @@ static struct attribute *sdsi_attrs[] = {
|
||||
static const struct attribute_group sdsi_group = {
|
||||
.attrs = sdsi_attrs,
|
||||
.bin_attrs = sdsi_bin_attrs,
|
||||
.is_bin_visible = sdsi_battr_is_visible,
|
||||
};
|
||||
__ATTRIBUTE_GROUPS(sdsi);
|
||||
|
||||
static int sdsi_get_layout(struct sdsi_priv *priv, struct disc_table *table)
|
||||
{
|
||||
switch (table->guid) {
|
||||
case SDSI_GUID_V1:
|
||||
priv->control_size = GUID_V1_CNTRL_SIZE;
|
||||
priv->registers_size = GUID_V1_REGS_SIZE;
|
||||
break;
|
||||
case SDSI_GUID_V2:
|
||||
priv->control_size = GUID_V2_CNTRL_SIZE;
|
||||
priv->registers_size = GUID_V2_REGS_SIZE;
|
||||
break;
|
||||
default:
|
||||
dev_err(priv->dev, "Unrecognized GUID 0x%x\n", table->guid);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdsi_map_mbox_registers(struct sdsi_priv *priv, struct pci_dev *parent,
|
||||
struct disc_table *disc_table, struct resource *disc_res)
|
||||
{
|
||||
@ -490,7 +569,6 @@ static int sdsi_map_mbox_registers(struct sdsi_priv *priv, struct pci_dev *paren
|
||||
u32 size = FIELD_GET(DT_SIZE, disc_table->access_info);
|
||||
u32 tbir = FIELD_GET(DT_TBIR, disc_table->offset);
|
||||
u32 offset = DT_OFFSET(disc_table->offset);
|
||||
u32 features_offset;
|
||||
struct resource res = {};
|
||||
|
||||
/* Starting location of SDSi MMIO region based on access type */
|
||||
@ -525,11 +603,10 @@ static int sdsi_map_mbox_registers(struct sdsi_priv *priv, struct pci_dev *paren
|
||||
if (IS_ERR(priv->control_addr))
|
||||
return PTR_ERR(priv->control_addr);
|
||||
|
||||
priv->mbox_addr = priv->control_addr + SDSI_SIZE_CONTROL;
|
||||
priv->mbox_addr = priv->control_addr + priv->control_size;
|
||||
priv->regs_addr = priv->mbox_addr + SDSI_SIZE_MAILBOX;
|
||||
|
||||
features_offset = readq(priv->regs_addr + SDSI_ENABLED_FEATURES_OFFSET);
|
||||
priv->sdsi_enabled = !!(features_offset & SDSI_ENABLED);
|
||||
priv->features = readq(priv->regs_addr + SDSI_ENABLED_FEATURES_OFFSET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -561,6 +638,11 @@ static int sdsi_probe(struct auxiliary_device *auxdev, const struct auxiliary_de
|
||||
|
||||
priv->guid = disc_table.guid;
|
||||
|
||||
/* Get guid based layout info */
|
||||
ret = sdsi_get_layout(priv, &disc_table);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Map the SDSi mailbox registers */
|
||||
ret = sdsi_map_mbox_registers(priv, intel_cap_dev->pcidev, &disc_table, disc_res);
|
||||
if (ret)
|
||||
@ -586,5 +668,5 @@ static struct auxiliary_driver sdsi_aux_driver = {
|
||||
module_auxiliary_driver(sdsi_aux_driver);
|
||||
|
||||
MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
|
||||
MODULE_DESCRIPTION("Intel Software Defined Silicon driver");
|
||||
MODULE_DESCRIPTION("Intel On Demand (SDSi) driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -623,7 +623,7 @@ static long isst_if_def_ioctl(struct file *file, unsigned int cmd,
|
||||
|
||||
/* Lock to prevent module registration when already opened by user space */
|
||||
static DEFINE_MUTEX(punit_misc_dev_open_lock);
|
||||
/* Lock to allow one share misc device for all ISST interace */
|
||||
/* Lock to allow one shared misc device for all ISST interfaces */
|
||||
static DEFINE_MUTEX(punit_misc_dev_reg_lock);
|
||||
static int misc_usage_count;
|
||||
static int misc_device_ret;
|
||||
|
@ -583,7 +583,6 @@ __intel_scu_ipc_register(struct device *parent,
|
||||
scu->dev.parent = parent;
|
||||
scu->dev.class = &intel_scu_ipc_class;
|
||||
scu->dev.release = intel_scu_ipc_release;
|
||||
dev_set_name(&scu->dev, "intel_scu_ipc");
|
||||
|
||||
if (!request_mem_region(scu_data->mem.start, resource_size(&scu_data->mem),
|
||||
"intel_scu_ipc")) {
|
||||
@ -612,6 +611,7 @@ __intel_scu_ipc_register(struct device *parent,
|
||||
* After this point intel_scu_ipc_release() takes care of
|
||||
* releasing the SCU IPC resources once refcount drops to zero.
|
||||
*/
|
||||
dev_set_name(&scu->dev, "intel_scu_ipc");
|
||||
err = device_register(&scu->dev);
|
||||
if (err) {
|
||||
put_device(&scu->dev);
|
||||
|
@ -546,7 +546,7 @@ static DEVICE_ATTR_RW(fn_lock);
|
||||
static DEVICE_ATTR_RW(charge_control_end_threshold);
|
||||
static DEVICE_ATTR_RW(battery_care_limit);
|
||||
|
||||
static int lg_battery_add(struct power_supply *battery)
|
||||
static int lg_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
|
||||
{
|
||||
if (device_create_file(&battery->dev,
|
||||
&dev_attr_charge_control_end_threshold))
|
||||
@ -555,7 +555,7 @@ static int lg_battery_add(struct power_supply *battery)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lg_battery_remove(struct power_supply *battery)
|
||||
static int lg_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook)
|
||||
{
|
||||
device_remove_file(&battery->dev,
|
||||
&dev_attr_charge_control_end_threshold);
|
||||
|
@ -35,13 +35,11 @@ int mxm_wmi_call_mxds(int adapter)
|
||||
.xarg = 1,
|
||||
};
|
||||
struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
|
||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
acpi_status status;
|
||||
|
||||
printk("calling mux switch %d\n", adapter);
|
||||
|
||||
status = wmi_evaluate_method(MXM_WMMX_GUID, 0x0, adapter, &input,
|
||||
&output);
|
||||
status = wmi_evaluate_method(MXM_WMMX_GUID, 0x0, adapter, &input, NULL);
|
||||
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
@ -60,13 +58,11 @@ int mxm_wmi_call_mxmx(int adapter)
|
||||
.xarg = 1,
|
||||
};
|
||||
struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
|
||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
acpi_status status;
|
||||
|
||||
printk("calling mux switch %d\n", adapter);
|
||||
|
||||
status = wmi_evaluate_method(MXM_WMMX_GUID, 0x0, adapter, &input,
|
||||
&output);
|
||||
status = wmi_evaluate_method(MXM_WMMX_GUID, 0x0, adapter, &input, NULL);
|
||||
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
|
@ -820,10 +820,9 @@ static ssize_t sony_nc_handles_show(struct device *dev,
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
|
||||
len += scnprintf(buffer + len, PAGE_SIZE - len, "0x%.4x ",
|
||||
handles->cap[i]);
|
||||
len += sysfs_emit_at(buffer, len, "0x%.4x ", handles->cap[i]);
|
||||
}
|
||||
len += scnprintf(buffer + len, PAGE_SIZE - len, "\n");
|
||||
len += sysfs_emit_at(buffer, len, "\n");
|
||||
|
||||
return len;
|
||||
}
|
||||
@ -2173,10 +2172,9 @@ static ssize_t sony_nc_thermal_profiles_show(struct device *dev,
|
||||
|
||||
for (cnt = 0; cnt < THM_PROFILE_MAX; cnt++) {
|
||||
if (!cnt || (th_handle->profiles & cnt))
|
||||
idx += scnprintf(buffer + idx, PAGE_SIZE - idx, "%s ",
|
||||
snc_thermal_profiles[cnt]);
|
||||
idx += sysfs_emit_at(buffer, idx, "%s ", snc_thermal_profiles[cnt]);
|
||||
}
|
||||
idx += scnprintf(buffer + idx, PAGE_SIZE - idx, "\n");
|
||||
idx += sysfs_emit_at(buffer, idx, "\n");
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
@ -254,7 +254,7 @@ static struct attribute *system76_battery_attrs[] = {
|
||||
|
||||
ATTRIBUTE_GROUPS(system76_battery);
|
||||
|
||||
static int system76_battery_add(struct power_supply *battery)
|
||||
static int system76_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
|
||||
{
|
||||
// System76 EC only supports 1 battery
|
||||
if (strcmp(battery->desc->name, "BAT0") != 0)
|
||||
@ -266,7 +266,7 @@ static int system76_battery_add(struct power_supply *battery)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int system76_battery_remove(struct power_supply *battery)
|
||||
static int system76_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook)
|
||||
{
|
||||
device_remove_groups(&battery->dev, system76_battery_groups);
|
||||
return 0;
|
||||
|
@ -265,9 +265,6 @@ enum tpacpi_hkey_event_t {
|
||||
|
||||
#define FAN_NOT_PRESENT 65535
|
||||
|
||||
#define strlencmp(a, b) (strncmp((a), (b), strlen(b)))
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Driver-wide structs and misc. variables
|
||||
*/
|
||||
@ -1335,9 +1332,9 @@ static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf)
|
||||
return -ENODEV;
|
||||
|
||||
while ((cmd = strsep(&buf, ","))) {
|
||||
if (strlencmp(cmd, "enable") == 0)
|
||||
if (strstarts(cmd, "enable"))
|
||||
status = TPACPI_RFK_RADIO_ON;
|
||||
else if (strlencmp(cmd, "disable") == 0)
|
||||
else if (strstarts(cmd, "disable"))
|
||||
status = TPACPI_RFK_RADIO_OFF;
|
||||
else
|
||||
return -EINVAL;
|
||||
@ -4198,12 +4195,12 @@ static int hotkey_write(char *buf)
|
||||
|
||||
res = 0;
|
||||
while ((cmd = strsep(&buf, ","))) {
|
||||
if (strlencmp(cmd, "enable") == 0) {
|
||||
if (strstarts(cmd, "enable")) {
|
||||
hotkey_enabledisable_warn(1);
|
||||
} else if (strlencmp(cmd, "disable") == 0) {
|
||||
} else if (strstarts(cmd, "disable")) {
|
||||
hotkey_enabledisable_warn(0);
|
||||
res = -EPERM;
|
||||
} else if (strlencmp(cmd, "reset") == 0) {
|
||||
} else if (strstarts(cmd, "reset")) {
|
||||
mask = (hotkey_all_mask | hotkey_source_mask)
|
||||
& ~hotkey_reserved_mask;
|
||||
} else if (sscanf(cmd, "0x%x", &mask) == 1) {
|
||||
@ -5233,33 +5230,33 @@ static int video_write(char *buf)
|
||||
disable = 0;
|
||||
|
||||
while ((cmd = strsep(&buf, ","))) {
|
||||
if (strlencmp(cmd, "lcd_enable") == 0) {
|
||||
if (strstarts(cmd, "lcd_enable")) {
|
||||
enable |= TP_ACPI_VIDEO_S_LCD;
|
||||
} else if (strlencmp(cmd, "lcd_disable") == 0) {
|
||||
} else if (strstarts(cmd, "lcd_disable")) {
|
||||
disable |= TP_ACPI_VIDEO_S_LCD;
|
||||
} else if (strlencmp(cmd, "crt_enable") == 0) {
|
||||
} else if (strstarts(cmd, "crt_enable")) {
|
||||
enable |= TP_ACPI_VIDEO_S_CRT;
|
||||
} else if (strlencmp(cmd, "crt_disable") == 0) {
|
||||
} else if (strstarts(cmd, "crt_disable")) {
|
||||
disable |= TP_ACPI_VIDEO_S_CRT;
|
||||
} else if (video_supported == TPACPI_VIDEO_NEW &&
|
||||
strlencmp(cmd, "dvi_enable") == 0) {
|
||||
strstarts(cmd, "dvi_enable")) {
|
||||
enable |= TP_ACPI_VIDEO_S_DVI;
|
||||
} else if (video_supported == TPACPI_VIDEO_NEW &&
|
||||
strlencmp(cmd, "dvi_disable") == 0) {
|
||||
strstarts(cmd, "dvi_disable")) {
|
||||
disable |= TP_ACPI_VIDEO_S_DVI;
|
||||
} else if (strlencmp(cmd, "auto_enable") == 0) {
|
||||
} else if (strstarts(cmd, "auto_enable")) {
|
||||
res = video_autosw_set(1);
|
||||
if (res)
|
||||
return res;
|
||||
} else if (strlencmp(cmd, "auto_disable") == 0) {
|
||||
} else if (strstarts(cmd, "auto_disable")) {
|
||||
res = video_autosw_set(0);
|
||||
if (res)
|
||||
return res;
|
||||
} else if (strlencmp(cmd, "video_switch") == 0) {
|
||||
} else if (strstarts(cmd, "video_switch")) {
|
||||
res = video_outputsw_cycle();
|
||||
if (res)
|
||||
return res;
|
||||
} else if (strlencmp(cmd, "expand_toggle") == 0) {
|
||||
} else if (strstarts(cmd, "expand_toggle")) {
|
||||
res = video_expand_toggle();
|
||||
if (res)
|
||||
return res;
|
||||
@ -5572,6 +5569,7 @@ static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev)
|
||||
static struct tpacpi_led_classdev tpacpi_led_thinklight = {
|
||||
.led_classdev = {
|
||||
.name = "tpacpi::thinklight",
|
||||
.max_brightness = 1,
|
||||
.brightness_set_blocking = &light_sysfs_set,
|
||||
.brightness_get = &light_sysfs_get,
|
||||
}
|
||||
@ -5652,9 +5650,9 @@ static int light_write(char *buf)
|
||||
return -ENODEV;
|
||||
|
||||
while ((cmd = strsep(&buf, ","))) {
|
||||
if (strlencmp(cmd, "on") == 0) {
|
||||
if (strstarts(cmd, "on")) {
|
||||
newstatus = 1;
|
||||
} else if (strlencmp(cmd, "off") == 0) {
|
||||
} else if (strstarts(cmd, "off")) {
|
||||
newstatus = 0;
|
||||
} else
|
||||
return -EINVAL;
|
||||
@ -7125,10 +7123,10 @@ static int brightness_write(char *buf)
|
||||
return level;
|
||||
|
||||
while ((cmd = strsep(&buf, ","))) {
|
||||
if (strlencmp(cmd, "up") == 0) {
|
||||
if (strstarts(cmd, "up")) {
|
||||
if (level < bright_maxlvl)
|
||||
level++;
|
||||
} else if (strlencmp(cmd, "down") == 0) {
|
||||
} else if (strstarts(cmd, "down")) {
|
||||
if (level > 0)
|
||||
level--;
|
||||
} else if (sscanf(cmd, "level %d", &level) == 1 &&
|
||||
@ -7877,13 +7875,13 @@ static int volume_write(char *buf)
|
||||
|
||||
while ((cmd = strsep(&buf, ","))) {
|
||||
if (!tp_features.mixer_no_level_control) {
|
||||
if (strlencmp(cmd, "up") == 0) {
|
||||
if (strstarts(cmd, "up")) {
|
||||
if (new_mute)
|
||||
new_mute = 0;
|
||||
else if (new_level < TP_EC_VOLUME_MAX)
|
||||
new_level++;
|
||||
continue;
|
||||
} else if (strlencmp(cmd, "down") == 0) {
|
||||
} else if (strstarts(cmd, "down")) {
|
||||
if (new_mute)
|
||||
new_mute = 0;
|
||||
else if (new_level > 0)
|
||||
@ -7895,9 +7893,9 @@ static int volume_write(char *buf)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (strlencmp(cmd, "mute") == 0)
|
||||
if (strstarts(cmd, "mute"))
|
||||
new_mute = TP_EC_AUDIO_MUTESW_MSK;
|
||||
else if (strlencmp(cmd, "unmute") == 0)
|
||||
else if (strstarts(cmd, "unmute"))
|
||||
new_mute = 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
@ -9120,10 +9118,9 @@ static int fan_write_cmd_level(const char *cmd, int *rc)
|
||||
{
|
||||
int level;
|
||||
|
||||
if (strlencmp(cmd, "level auto") == 0)
|
||||
if (strstarts(cmd, "level auto"))
|
||||
level = TP_EC_FAN_AUTO;
|
||||
else if ((strlencmp(cmd, "level disengaged") == 0) ||
|
||||
(strlencmp(cmd, "level full-speed") == 0))
|
||||
else if (strstarts(cmd, "level disengaged") || strstarts(cmd, "level full-speed"))
|
||||
level = TP_EC_FAN_FULLSPEED;
|
||||
else if (sscanf(cmd, "level %d", &level) != 1)
|
||||
return 0;
|
||||
@ -9141,7 +9138,7 @@ static int fan_write_cmd_level(const char *cmd, int *rc)
|
||||
|
||||
static int fan_write_cmd_enable(const char *cmd, int *rc)
|
||||
{
|
||||
if (strlencmp(cmd, "enable") != 0)
|
||||
if (!strstarts(cmd, "enable"))
|
||||
return 0;
|
||||
|
||||
*rc = fan_set_enable();
|
||||
@ -9156,7 +9153,7 @@ static int fan_write_cmd_enable(const char *cmd, int *rc)
|
||||
|
||||
static int fan_write_cmd_disable(const char *cmd, int *rc)
|
||||
{
|
||||
if (strlencmp(cmd, "disable") != 0)
|
||||
if (!strstarts(cmd, "disable"))
|
||||
return 0;
|
||||
|
||||
*rc = fan_set_disable();
|
||||
@ -9907,7 +9904,7 @@ ATTRIBUTE_GROUPS(tpacpi_battery);
|
||||
|
||||
/* ACPI battery hooking */
|
||||
|
||||
static int tpacpi_battery_add(struct power_supply *battery)
|
||||
static int tpacpi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
|
||||
{
|
||||
int batteryid = tpacpi_battery_get_id(battery->desc->name);
|
||||
|
||||
@ -9918,7 +9915,7 @@ static int tpacpi_battery_add(struct power_supply *battery)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tpacpi_battery_remove(struct power_supply *battery)
|
||||
static int tpacpi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook)
|
||||
{
|
||||
device_remove_groups(&battery->dev, tpacpi_battery_groups);
|
||||
return 0;
|
||||
|
@ -3113,7 +3113,7 @@ static struct attribute *toshiba_acpi_battery_attrs[] = {
|
||||
|
||||
ATTRIBUTE_GROUPS(toshiba_acpi_battery);
|
||||
|
||||
static int toshiba_acpi_battery_add(struct power_supply *battery)
|
||||
static int toshiba_acpi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
|
||||
{
|
||||
if (toshiba_acpi == NULL) {
|
||||
pr_err("Init order issue\n");
|
||||
@ -3126,7 +3126,7 @@ static int toshiba_acpi_battery_add(struct power_supply *battery)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int toshiba_acpi_battery_remove(struct power_supply *battery)
|
||||
static int toshiba_acpi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook)
|
||||
{
|
||||
device_remove_groups(&battery->dev, toshiba_acpi_battery_groups);
|
||||
return 0;
|
||||
|
@ -119,12 +119,12 @@ struct uv_hub {
|
||||
|
||||
static ssize_t hub_name_show(struct uv_bios_hub_info *hub_info, char *buf)
|
||||
{
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n", hub_info->name);
|
||||
return sysfs_emit(buf, "%s\n", hub_info->name);
|
||||
}
|
||||
|
||||
static ssize_t hub_location_show(struct uv_bios_hub_info *hub_info, char *buf)
|
||||
{
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n", hub_info->location);
|
||||
return sysfs_emit(buf, "%s\n", hub_info->location);
|
||||
}
|
||||
|
||||
static ssize_t hub_partition_show(struct uv_bios_hub_info *hub_info, char *buf)
|
||||
@ -460,12 +460,12 @@ struct uv_pci_top_obj {
|
||||
|
||||
static ssize_t uv_pci_type_show(struct uv_pci_top_obj *top_obj, char *buf)
|
||||
{
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n", top_obj->type);
|
||||
return sysfs_emit(buf, "%s\n", top_obj->type);
|
||||
}
|
||||
|
||||
static ssize_t uv_pci_location_show(struct uv_pci_top_obj *top_obj, char *buf)
|
||||
{
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n", top_obj->location);
|
||||
return sysfs_emit(buf, "%s\n", top_obj->location);
|
||||
}
|
||||
|
||||
static ssize_t uv_pci_iio_stack_show(struct uv_pci_top_obj *top_obj, char *buf)
|
||||
@ -475,7 +475,7 @@ static ssize_t uv_pci_iio_stack_show(struct uv_pci_top_obj *top_obj, char *buf)
|
||||
|
||||
static ssize_t uv_pci_ppb_addr_show(struct uv_pci_top_obj *top_obj, char *buf)
|
||||
{
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n", top_obj->ppb_addr);
|
||||
return sysfs_emit(buf, "%s\n", top_obj->ppb_addr);
|
||||
}
|
||||
|
||||
static ssize_t uv_pci_slot_show(struct uv_pci_top_obj *top_obj, char *buf)
|
||||
@ -737,7 +737,7 @@ static ssize_t coherence_id_show(struct kobject *kobj,
|
||||
static ssize_t uv_type_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n", uv_type_string());
|
||||
return sysfs_emit(buf, "%s\n", uv_type_string());
|
||||
}
|
||||
|
||||
static ssize_t uv_archtype_show(struct kobject *kobj,
|
||||
@ -749,13 +749,13 @@ static ssize_t uv_archtype_show(struct kobject *kobj,
|
||||
static ssize_t uv_hub_type_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
return scnprintf(buf, PAGE_SIZE, "0x%x\n", uv_hub_type());
|
||||
return sysfs_emit(buf, "0x%x\n", uv_hub_type());
|
||||
}
|
||||
|
||||
static ssize_t uv_hubless_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
return scnprintf(buf, PAGE_SIZE, "0x%x\n", uv_get_hubless_system());
|
||||
return sysfs_emit(buf, "0x%x\n", uv_get_hubless_system());
|
||||
}
|
||||
|
||||
static struct kobj_attribute partition_id_attr =
|
||||
|
@ -20,7 +20,10 @@ MODULE_ALIAS("acpi*:HPQ6001:*");
|
||||
MODULE_ALIAS("acpi*:WSTADEF:*");
|
||||
MODULE_ALIAS("acpi*:AMDI0051:*");
|
||||
|
||||
static struct input_dev *wl_input_dev;
|
||||
struct wl_button {
|
||||
struct input_dev *input_dev;
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
static const struct acpi_device_id wl_ids[] = {
|
||||
{"HPQ6001", 0},
|
||||
@ -29,63 +32,80 @@ static const struct acpi_device_id wl_ids[] = {
|
||||
{"", 0},
|
||||
};
|
||||
|
||||
static int wireless_input_setup(void)
|
||||
static int wireless_input_setup(struct acpi_device *device)
|
||||
{
|
||||
struct wl_button *button = acpi_driver_data(device);
|
||||
int err;
|
||||
|
||||
wl_input_dev = input_allocate_device();
|
||||
if (!wl_input_dev)
|
||||
button->input_dev = input_allocate_device();
|
||||
if (!button->input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
wl_input_dev->name = "Wireless hotkeys";
|
||||
wl_input_dev->phys = "hpq6001/input0";
|
||||
wl_input_dev->id.bustype = BUS_HOST;
|
||||
wl_input_dev->evbit[0] = BIT(EV_KEY);
|
||||
set_bit(KEY_RFKILL, wl_input_dev->keybit);
|
||||
snprintf(button->phys, sizeof(button->phys), "%s/input0", acpi_device_hid(device));
|
||||
|
||||
err = input_register_device(wl_input_dev);
|
||||
button->input_dev->name = "Wireless hotkeys";
|
||||
button->input_dev->phys = button->phys;
|
||||
button->input_dev->id.bustype = BUS_HOST;
|
||||
button->input_dev->evbit[0] = BIT(EV_KEY);
|
||||
set_bit(KEY_RFKILL, button->input_dev->keybit);
|
||||
|
||||
err = input_register_device(button->input_dev);
|
||||
if (err)
|
||||
goto err_free_dev;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_dev:
|
||||
input_free_device(wl_input_dev);
|
||||
input_free_device(button->input_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void wireless_input_destroy(void)
|
||||
static void wireless_input_destroy(struct acpi_device *device)
|
||||
{
|
||||
input_unregister_device(wl_input_dev);
|
||||
struct wl_button *button = acpi_driver_data(device);
|
||||
|
||||
input_unregister_device(button->input_dev);
|
||||
kfree(button);
|
||||
}
|
||||
|
||||
static void wl_notify(struct acpi_device *acpi_dev, u32 event)
|
||||
{
|
||||
struct wl_button *button = acpi_driver_data(acpi_dev);
|
||||
|
||||
if (event != 0x80) {
|
||||
pr_info("Received unknown event (0x%x)\n", event);
|
||||
return;
|
||||
}
|
||||
|
||||
input_report_key(wl_input_dev, KEY_RFKILL, 1);
|
||||
input_sync(wl_input_dev);
|
||||
input_report_key(wl_input_dev, KEY_RFKILL, 0);
|
||||
input_sync(wl_input_dev);
|
||||
input_report_key(button->input_dev, KEY_RFKILL, 1);
|
||||
input_sync(button->input_dev);
|
||||
input_report_key(button->input_dev, KEY_RFKILL, 0);
|
||||
input_sync(button->input_dev);
|
||||
}
|
||||
|
||||
static int wl_add(struct acpi_device *device)
|
||||
{
|
||||
struct wl_button *button;
|
||||
int err;
|
||||
|
||||
err = wireless_input_setup();
|
||||
if (err)
|
||||
button = kzalloc(sizeof(struct wl_button), GFP_KERNEL);
|
||||
if (!button)
|
||||
return -ENOMEM;
|
||||
|
||||
device->driver_data = button;
|
||||
|
||||
err = wireless_input_setup(device);
|
||||
if (err) {
|
||||
pr_err("Failed to setup wireless hotkeys\n");
|
||||
kfree(button);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int wl_remove(struct acpi_device *device)
|
||||
{
|
||||
wireless_input_destroy();
|
||||
wireless_input_destroy(device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -105,6 +105,7 @@ MODULE_DEVICE_TABLE(acpi, wmi_device_ids);
|
||||
/* allow duplicate GUIDs as these device drivers use struct wmi_driver */
|
||||
static const char * const allow_duplicates[] = {
|
||||
"05901221-D566-11D1-B2F0-00A0C9062910", /* wmi-bmof */
|
||||
"8A42EA14-4F2A-FD45-6422-0087F7A7E608", /* dell-wmi-ddv */
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
* devices typically have a bunch of things hardcoded, rather than specified
|
||||
* in their DSDT.
|
||||
*
|
||||
* Copyright (C) 2021 Hans de Goede <hdegoede@redhat.com>
|
||||
* Copyright (C) 2021-2022 Hans de Goede <hdegoede@redhat.com>
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
@ -265,6 +265,56 @@ static struct gpiod_lookup_table int3496_gpo2_pin22_gpios = {
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Advantech MICA-071
|
||||
* This is a standard Windows tablet, but it has an extra "quick launch" button
|
||||
* which is not described in the ACPI tables in anyway.
|
||||
* Use the x86-android-tablets infra to create a gpio-button device for this.
|
||||
*/
|
||||
static struct gpio_keys_button advantech_mica_071_button = {
|
||||
.code = KEY_PROG1,
|
||||
/* .gpio gets filled in by advantech_mica_071_init() */
|
||||
.active_low = true,
|
||||
.desc = "prog1_key",
|
||||
.type = EV_KEY,
|
||||
.wakeup = false,
|
||||
.debounce_interval = 50,
|
||||
};
|
||||
|
||||
static const struct gpio_keys_platform_data advantech_mica_071_button_pdata __initconst = {
|
||||
.buttons = &advantech_mica_071_button,
|
||||
.nbuttons = 1,
|
||||
.name = "prog1_key",
|
||||
};
|
||||
|
||||
static const struct platform_device_info advantech_mica_071_pdevs[] __initconst = {
|
||||
{
|
||||
.name = "gpio-keys",
|
||||
.id = PLATFORM_DEVID_AUTO,
|
||||
.data = &advantech_mica_071_button_pdata,
|
||||
.size_data = sizeof(advantech_mica_071_button_pdata),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init advantech_mica_071_init(void)
|
||||
{
|
||||
struct gpio_desc *gpiod;
|
||||
int ret;
|
||||
|
||||
ret = x86_android_tablet_get_gpiod("INT33FC:00", 2, &gpiod);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
advantech_mica_071_button.gpio = desc_to_gpio(gpiod);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct x86_dev_info advantech_mica_071_info __initconst = {
|
||||
.pdev_info = advantech_mica_071_pdevs,
|
||||
.pdev_count = ARRAY_SIZE(advantech_mica_071_pdevs),
|
||||
.init = advantech_mica_071_init,
|
||||
};
|
||||
|
||||
/* Asus ME176C and TF103C tablets shared data */
|
||||
static struct gpio_keys_button asus_me176c_tf103c_lid = {
|
||||
.code = SW_LID,
|
||||
@ -987,6 +1037,212 @@ static void lenovo_yoga_tab2_830_1050_exit(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Lenovo Yoga Tab 3 Pro YT3-X90F */
|
||||
|
||||
/*
|
||||
* There are 2 batteries, with 2 bq27500 fuel-gauges and 2 bq25892 chargers,
|
||||
* "bq25890-charger-1" is instantiated from: drivers/i2c/busses/i2c-cht-wc.c.
|
||||
*/
|
||||
static const char * const lenovo_yt3_bq25892_0_suppliers[] = { "cht_wcove_pwrsrc" };
|
||||
static const char * const bq25890_1_psy[] = { "bq25890-charger-1" };
|
||||
|
||||
static const struct property_entry fg_bq25890_1_supply_props[] = {
|
||||
PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq25890_1_psy),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct software_node fg_bq25890_1_supply_node = {
|
||||
.properties = fg_bq25890_1_supply_props,
|
||||
};
|
||||
|
||||
/* bq25892 charger settings for the flat lipo battery behind the screen */
|
||||
static const struct property_entry lenovo_yt3_bq25892_0_props[] = {
|
||||
PROPERTY_ENTRY_STRING_ARRAY("supplied-from", lenovo_yt3_bq25892_0_suppliers),
|
||||
PROPERTY_ENTRY_STRING("linux,power-supply-name", "bq25892-second-chrg"),
|
||||
PROPERTY_ENTRY_U32("linux,iinlim-percentage", 40),
|
||||
PROPERTY_ENTRY_BOOL("linux,skip-reset"),
|
||||
/* Values taken from Android Factory Image */
|
||||
PROPERTY_ENTRY_U32("ti,charge-current", 2048000),
|
||||
PROPERTY_ENTRY_U32("ti,battery-regulation-voltage", 4352000),
|
||||
PROPERTY_ENTRY_U32("ti,termination-current", 128000),
|
||||
PROPERTY_ENTRY_U32("ti,precharge-current", 128000),
|
||||
PROPERTY_ENTRY_U32("ti,minimum-sys-voltage", 3700000),
|
||||
PROPERTY_ENTRY_U32("ti,boost-voltage", 4998000),
|
||||
PROPERTY_ENTRY_U32("ti,boost-max-current", 500000),
|
||||
PROPERTY_ENTRY_BOOL("ti,use-ilim-pin"),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct software_node lenovo_yt3_bq25892_0_node = {
|
||||
.properties = lenovo_yt3_bq25892_0_props,
|
||||
};
|
||||
|
||||
static const struct x86_i2c_client_info lenovo_yt3_i2c_clients[] __initconst = {
|
||||
{
|
||||
/* bq27500 fuel-gauge for the flat lipo battery behind the screen */
|
||||
.board_info = {
|
||||
.type = "bq27500",
|
||||
.addr = 0x55,
|
||||
.dev_name = "bq27500_0",
|
||||
.swnode = &fg_bq25890_supply_node,
|
||||
},
|
||||
.adapter_path = "\\_SB_.PCI0.I2C1",
|
||||
}, {
|
||||
/* bq25892 charger for the flat lipo battery behind the screen */
|
||||
.board_info = {
|
||||
.type = "bq25892",
|
||||
.addr = 0x6b,
|
||||
.dev_name = "bq25892_0",
|
||||
.swnode = &lenovo_yt3_bq25892_0_node,
|
||||
},
|
||||
.adapter_path = "\\_SB_.PCI0.I2C1",
|
||||
.irq_data = {
|
||||
.type = X86_ACPI_IRQ_TYPE_GPIOINT,
|
||||
.chip = "INT33FF:01",
|
||||
.index = 5,
|
||||
.trigger = ACPI_EDGE_SENSITIVE,
|
||||
.polarity = ACPI_ACTIVE_LOW,
|
||||
},
|
||||
}, {
|
||||
/* bq27500 fuel-gauge for the round li-ion cells in the hinge */
|
||||
.board_info = {
|
||||
.type = "bq27500",
|
||||
.addr = 0x55,
|
||||
.dev_name = "bq27500_1",
|
||||
.swnode = &fg_bq25890_1_supply_node,
|
||||
},
|
||||
.adapter_path = "\\_SB_.PCI0.I2C2",
|
||||
}
|
||||
};
|
||||
|
||||
static int __init lenovo_yt3_init(void)
|
||||
{
|
||||
struct gpio_desc *gpiod;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The "bq25892_0" charger IC has its /CE (Charge-Enable) and OTG pins
|
||||
* connected to GPIOs, rather then having them hardwired to the correct
|
||||
* values as is normally done.
|
||||
*
|
||||
* The bq25890_charger driver controls these through I2C, but this only
|
||||
* works if not overridden by the pins. Set these pins here:
|
||||
* 1. Set /CE to 0 to allow charging.
|
||||
* 2. Set OTG to 0 disable V5 boost output since the 5V boost output of
|
||||
* the main "bq25892_1" charger is used when necessary.
|
||||
*/
|
||||
|
||||
/* /CE pin */
|
||||
ret = x86_android_tablet_get_gpiod("INT33FF:02", 22, &gpiod);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* The gpio_desc returned by x86_android_tablet_get_gpiod() is a "raw"
|
||||
* gpio_desc, that is there is no way to pass lookup-flags like
|
||||
* GPIO_ACTIVE_LOW. Set the GPIO to 0 here to enable charging since
|
||||
* the /CE pin is active-low, but not marked as such in the gpio_desc.
|
||||
*/
|
||||
gpiod_set_value(gpiod, 0);
|
||||
|
||||
/* OTG pin */
|
||||
ret = x86_android_tablet_get_gpiod("INT33FF:03", 19, &gpiod);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
gpiod_set_value(gpiod, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct x86_dev_info lenovo_yt3_info __initconst = {
|
||||
.i2c_client_info = lenovo_yt3_i2c_clients,
|
||||
.i2c_client_count = ARRAY_SIZE(lenovo_yt3_i2c_clients),
|
||||
.init = lenovo_yt3_init,
|
||||
};
|
||||
|
||||
/* Medion Lifetab S10346 tablets have an Android factory img with everything hardcoded */
|
||||
static const char * const medion_lifetab_s10346_accel_mount_matrix[] = {
|
||||
"0", "1", "0",
|
||||
"1", "0", "0",
|
||||
"0", "0", "1"
|
||||
};
|
||||
|
||||
static const struct property_entry medion_lifetab_s10346_accel_props[] = {
|
||||
PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", medion_lifetab_s10346_accel_mount_matrix),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct software_node medion_lifetab_s10346_accel_node = {
|
||||
.properties = medion_lifetab_s10346_accel_props,
|
||||
};
|
||||
|
||||
/* Note the LCD panel is mounted upside down, this is correctly indicated in the VBT */
|
||||
static const struct property_entry medion_lifetab_s10346_touchscreen_props[] = {
|
||||
PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"),
|
||||
PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct software_node medion_lifetab_s10346_touchscreen_node = {
|
||||
.properties = medion_lifetab_s10346_touchscreen_props,
|
||||
};
|
||||
|
||||
static const struct x86_i2c_client_info medion_lifetab_s10346_i2c_clients[] __initconst = {
|
||||
{
|
||||
/* kxtj21009 accel */
|
||||
.board_info = {
|
||||
.type = "kxtj21009",
|
||||
.addr = 0x0f,
|
||||
.dev_name = "kxtj21009",
|
||||
.swnode = &medion_lifetab_s10346_accel_node,
|
||||
},
|
||||
.adapter_path = "\\_SB_.I2C3",
|
||||
.irq_data = {
|
||||
.type = X86_ACPI_IRQ_TYPE_GPIOINT,
|
||||
.chip = "INT33FC:02",
|
||||
.index = 23,
|
||||
.trigger = ACPI_EDGE_SENSITIVE,
|
||||
.polarity = ACPI_ACTIVE_HIGH,
|
||||
},
|
||||
}, {
|
||||
/* goodix touchscreen */
|
||||
.board_info = {
|
||||
.type = "GDIX1001:00",
|
||||
.addr = 0x14,
|
||||
.dev_name = "goodix_ts",
|
||||
.swnode = &medion_lifetab_s10346_touchscreen_node,
|
||||
},
|
||||
.adapter_path = "\\_SB_.I2C4",
|
||||
.irq_data = {
|
||||
.type = X86_ACPI_IRQ_TYPE_APIC,
|
||||
.index = 0x44,
|
||||
.trigger = ACPI_EDGE_SENSITIVE,
|
||||
.polarity = ACPI_ACTIVE_LOW,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table medion_lifetab_s10346_goodix_gpios = {
|
||||
.dev_id = "i2c-goodix_ts",
|
||||
.table = {
|
||||
GPIO_LOOKUP("INT33FC:01", 26, "reset", GPIO_ACTIVE_HIGH),
|
||||
GPIO_LOOKUP("INT33FC:02", 3, "irq", GPIO_ACTIVE_HIGH),
|
||||
{ }
|
||||
},
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table * const medion_lifetab_s10346_gpios[] = {
|
||||
&medion_lifetab_s10346_goodix_gpios,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct x86_dev_info medion_lifetab_s10346_info __initconst = {
|
||||
.i2c_client_info = medion_lifetab_s10346_i2c_clients,
|
||||
.i2c_client_count = ARRAY_SIZE(medion_lifetab_s10346_i2c_clients),
|
||||
.gpiod_lookup_tables = medion_lifetab_s10346_gpios,
|
||||
};
|
||||
|
||||
/* Nextbook Ares 8 tablets have an Android factory img with everything hardcoded */
|
||||
static const char * const nextbook_ares8_accel_mount_matrix[] = {
|
||||
"0", "-1", "0",
|
||||
@ -1179,6 +1435,14 @@ static const struct x86_dev_info xiaomi_mipad2_info __initconst = {
|
||||
};
|
||||
|
||||
static const struct dmi_system_id x86_android_tablet_ids[] __initconst = {
|
||||
{
|
||||
/* Advantech MICA-071 */
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Advantech"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "MICA-071"),
|
||||
},
|
||||
.driver_data = (void *)&advantech_mica_071_info,
|
||||
},
|
||||
{
|
||||
/* Asus MeMO Pad 7 ME176C */
|
||||
.matches = {
|
||||
@ -1245,6 +1509,25 @@ static const struct dmi_system_id x86_android_tablet_ids[] __initconst = {
|
||||
},
|
||||
.driver_data = (void *)&lenovo_yoga_tab2_830_1050_info,
|
||||
},
|
||||
{
|
||||
/* Lenovo Yoga Tab 3 Pro YT3-X90F */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
|
||||
DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"),
|
||||
},
|
||||
.driver_data = (void *)&lenovo_yt3_info,
|
||||
},
|
||||
{
|
||||
/* Medion Lifetab S10346 */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
|
||||
/* Above strings are much too generic, also match on BIOS date */
|
||||
DMI_MATCH(DMI_BIOS_DATE, "10/22/2015"),
|
||||
},
|
||||
.driver_data = (void *)&medion_lifetab_s10346_info,
|
||||
},
|
||||
{
|
||||
/* Nextbook Ares 8 */
|
||||
.matches = {
|
||||
|
@ -12,8 +12,8 @@
|
||||
|
||||
struct acpi_battery_hook {
|
||||
const char *name;
|
||||
int (*add_battery)(struct power_supply *battery);
|
||||
int (*remove_battery)(struct power_supply *battery);
|
||||
int (*add_battery)(struct power_supply *battery, struct acpi_battery_hook *hook);
|
||||
int (*remove_battery)(struct power_supply *battery, struct acpi_battery_hook *hook);
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* sdsi: Intel Software Defined Silicon tool for provisioning certificates
|
||||
* and activation payloads on supported cpus.
|
||||
* sdsi: Intel On Demand (formerly Software Defined Silicon) tool for
|
||||
* provisioning certificates and activation payloads on supported cpus.
|
||||
*
|
||||
* See https://github.com/intel/intel-sdsi/blob/master/os-interface.rst
|
||||
* for register descriptions.
|
||||
@ -22,19 +22,54 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef __packed
|
||||
#define __packed __attribute__((packed))
|
||||
#endif
|
||||
|
||||
#define min(x, y) ({ \
|
||||
typeof(x) _min1 = (x); \
|
||||
typeof(y) _min2 = (y); \
|
||||
(void) (&_min1 == &_min2); \
|
||||
_min1 < _min2 ? _min1 : _min2; })
|
||||
|
||||
#define SDSI_DEV "intel_vsec.sdsi"
|
||||
#define AUX_DEV_PATH "/sys/bus/auxiliary/devices/"
|
||||
#define SDSI_PATH (AUX_DEV_DIR SDSI_DEV)
|
||||
#define GUID 0x6dd191
|
||||
#define REGISTERS_MIN_SIZE 72
|
||||
#define GUID_V1 0x6dd191
|
||||
#define REGS_SIZE_GUID_V1 72
|
||||
#define GUID_V2 0xF210D9EF
|
||||
#define REGS_SIZE_GUID_V2 80
|
||||
#define STATE_CERT_MAX_SIZE 4096
|
||||
#define METER_CERT_MAX_SIZE 4096
|
||||
#define STATE_MAX_NUM_LICENSES 16
|
||||
#define STATE_MAX_NUM_IN_BUNDLE (uint32_t)8
|
||||
#define METER_MAX_NUM_BUNDLES 8
|
||||
|
||||
#define __round_mask(x, y) ((__typeof__(x))((y) - 1))
|
||||
#define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1)
|
||||
|
||||
struct nvram_content_auth_err_sts {
|
||||
uint64_t reserved:3;
|
||||
uint64_t sdsi_content_auth_err:1;
|
||||
uint64_t reserved1:1;
|
||||
uint64_t sdsi_metering_auth_err:1;
|
||||
uint64_t reserved2:58;
|
||||
};
|
||||
|
||||
struct enabled_features {
|
||||
uint64_t reserved:3;
|
||||
uint64_t sdsi:1;
|
||||
uint64_t reserved1:60;
|
||||
uint64_t reserved1:8;
|
||||
uint64_t attestation:1;
|
||||
uint64_t reserved2:13;
|
||||
uint64_t metering:1;
|
||||
uint64_t reserved3:37;
|
||||
};
|
||||
|
||||
struct key_provision_status {
|
||||
uint64_t reserved:1;
|
||||
uint64_t license_key_provisioned:1;
|
||||
uint64_t reserved2:62;
|
||||
};
|
||||
|
||||
struct auth_fail_count {
|
||||
@ -49,31 +84,102 @@ struct availability {
|
||||
uint64_t reserved:48;
|
||||
uint64_t available:3;
|
||||
uint64_t threshold:3;
|
||||
uint64_t reserved2:10;
|
||||
};
|
||||
|
||||
struct nvram_update_limit {
|
||||
uint64_t reserved:12;
|
||||
uint64_t sdsi_50_pct:1;
|
||||
uint64_t sdsi_75_pct:1;
|
||||
uint64_t sdsi_90_pct:1;
|
||||
uint64_t reserved2:49;
|
||||
};
|
||||
|
||||
struct sdsi_regs {
|
||||
uint64_t ppin;
|
||||
uint64_t reserved;
|
||||
struct nvram_content_auth_err_sts auth_err_sts;
|
||||
struct enabled_features en_features;
|
||||
uint64_t reserved1;
|
||||
struct key_provision_status key_prov_sts;
|
||||
struct auth_fail_count auth_fail_count;
|
||||
struct availability prov_avail;
|
||||
uint64_t reserved2;
|
||||
uint64_t reserved3;
|
||||
uint64_t socket_id;
|
||||
struct nvram_update_limit limits;
|
||||
uint64_t pcu_cr3_capid_cfg;
|
||||
union {
|
||||
struct {
|
||||
uint64_t socket_id;
|
||||
} v1;
|
||||
struct {
|
||||
uint64_t reserved;
|
||||
uint64_t socket_id;
|
||||
uint64_t reserved2;
|
||||
} v2;
|
||||
} extra;
|
||||
};
|
||||
#define CONTENT_TYPE_LK_ENC 0xD
|
||||
#define CONTENT_TYPE_LK_BLOB_ENC 0xE
|
||||
|
||||
struct state_certificate {
|
||||
uint32_t content_type;
|
||||
uint32_t region_rev_id;
|
||||
uint32_t header_size;
|
||||
uint32_t total_size;
|
||||
uint32_t key_size;
|
||||
uint32_t num_licenses;
|
||||
};
|
||||
|
||||
struct license_key_info {
|
||||
uint32_t key_rev_id;
|
||||
uint64_t key_image_content[6];
|
||||
} __packed;
|
||||
|
||||
#define LICENSE_BLOB_SIZE(l) (((l) & 0x7fffffff) * 4)
|
||||
#define LICENSE_VALID(l) (!!((l) & 0x80000000))
|
||||
|
||||
// License Group Types
|
||||
#define LBT_ONE_TIME_UPGRADE 1
|
||||
#define LBT_METERED_UPGRADE 2
|
||||
|
||||
struct license_blob_content {
|
||||
uint32_t type;
|
||||
uint64_t id;
|
||||
uint64_t ppin;
|
||||
uint64_t previous_ppin;
|
||||
uint32_t rev_id;
|
||||
uint32_t num_bundles;
|
||||
} __packed;
|
||||
|
||||
struct bundle_encoding {
|
||||
uint32_t encoding;
|
||||
uint32_t encoding_rsvd[7];
|
||||
};
|
||||
|
||||
struct meter_certificate {
|
||||
uint32_t block_signature;
|
||||
uint32_t counter_unit;
|
||||
uint64_t ppin;
|
||||
uint32_t bundle_length;
|
||||
uint32_t reserved;
|
||||
uint32_t mmrc_encoding;
|
||||
uint32_t mmrc_counter;
|
||||
};
|
||||
|
||||
struct bundle_encoding_counter {
|
||||
uint32_t encoding;
|
||||
uint32_t counter;
|
||||
};
|
||||
|
||||
struct sdsi_dev {
|
||||
struct sdsi_regs regs;
|
||||
struct state_certificate sc;
|
||||
char *dev_name;
|
||||
char *dev_path;
|
||||
int guid;
|
||||
uint32_t guid;
|
||||
};
|
||||
|
||||
enum command {
|
||||
CMD_NONE,
|
||||
CMD_SOCKET_INFO,
|
||||
CMD_DUMP_CERT,
|
||||
CMD_METER_CERT,
|
||||
CMD_STATE_CERT,
|
||||
CMD_PROV_AKC,
|
||||
CMD_PROV_CAP,
|
||||
};
|
||||
@ -98,7 +204,7 @@ static void sdsi_list_devices(void)
|
||||
}
|
||||
|
||||
if (!found)
|
||||
fprintf(stderr, "No sdsi devices found.\n");
|
||||
fprintf(stderr, "No On Demand devices found.\n");
|
||||
}
|
||||
|
||||
static int sdsi_update_registers(struct sdsi_dev *s)
|
||||
@ -121,7 +227,7 @@ static int sdsi_update_registers(struct sdsi_dev *s)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (s->guid != GUID) {
|
||||
if (s->guid != GUID_V1 && s->guid != GUID_V2) {
|
||||
fprintf(stderr, "Unrecognized guid, 0x%x\n", s->guid);
|
||||
fclose(regs_ptr);
|
||||
return -1;
|
||||
@ -129,7 +235,8 @@ static int sdsi_update_registers(struct sdsi_dev *s)
|
||||
|
||||
/* Update register info for this guid */
|
||||
ret = fread(&s->regs, sizeof(uint8_t), sizeof(s->regs), regs_ptr);
|
||||
if (ret != sizeof(s->regs)) {
|
||||
if ((s->guid == GUID_V1 && ret != REGS_SIZE_GUID_V1) ||
|
||||
(s->guid == GUID_V2 && ret != REGS_SIZE_GUID_V2)) {
|
||||
fprintf(stderr, "Could not read 'registers' file\n");
|
||||
fclose(regs_ptr);
|
||||
return -1;
|
||||
@ -153,8 +260,18 @@ static int sdsi_read_reg(struct sdsi_dev *s)
|
||||
printf("Socket information for device %s\n", s->dev_name);
|
||||
printf("\n");
|
||||
printf("PPIN: 0x%lx\n", s->regs.ppin);
|
||||
printf("NVRAM Content Authorization Error Status\n");
|
||||
printf(" SDSi Auth Err Sts: %s\n", !!s->regs.auth_err_sts.sdsi_content_auth_err ? "Error" : "Okay");
|
||||
|
||||
if (!!s->regs.en_features.metering)
|
||||
printf(" Metering Auth Err Sts: %s\n", !!s->regs.auth_err_sts.sdsi_metering_auth_err ? "Error" : "Okay");
|
||||
|
||||
printf("Enabled Features\n");
|
||||
printf(" SDSi: %s\n", !!s->regs.en_features.sdsi ? "Enabled" : "Disabled");
|
||||
printf(" On Demand: %s\n", !!s->regs.en_features.sdsi ? "Enabled" : "Disabled");
|
||||
printf(" Attestation: %s\n", !!s->regs.en_features.attestation ? "Enabled" : "Disabled");
|
||||
printf(" On Demand: %s\n", !!s->regs.en_features.sdsi ? "Enabled" : "Disabled");
|
||||
printf(" Metering: %s\n", !!s->regs.en_features.metering ? "Enabled" : "Disabled");
|
||||
printf("License Key (AKC) Provisioned: %s\n", !!s->regs.key_prov_sts.license_key_provisioned ? "Yes" : "No");
|
||||
printf("Authorization Failure Count\n");
|
||||
printf(" AKC Failure Count: %d\n", s->regs.auth_fail_count.key_failure_count);
|
||||
printf(" AKC Failure Threshold: %d\n", s->regs.auth_fail_count.key_failure_threshold);
|
||||
@ -163,25 +280,148 @@ static int sdsi_read_reg(struct sdsi_dev *s)
|
||||
printf("Provisioning Availability\n");
|
||||
printf(" Updates Available: %d\n", s->regs.prov_avail.available);
|
||||
printf(" Updates Threshold: %d\n", s->regs.prov_avail.threshold);
|
||||
printf("Socket ID: %ld\n", s->regs.socket_id & 0xF);
|
||||
printf("NVRAM Udate Limit\n");
|
||||
printf(" 50%% Limit Reached: %s\n", !!s->regs.limits.sdsi_50_pct ? "Yes" : "No");
|
||||
printf(" 75%% Limit Reached: %s\n", !!s->regs.limits.sdsi_75_pct ? "Yes" : "No");
|
||||
printf(" 90%% Limit Reached: %s\n", !!s->regs.limits.sdsi_90_pct ? "Yes" : "No");
|
||||
if (s->guid == GUID_V1)
|
||||
printf("Socket ID: %ld\n", s->regs.extra.v1.socket_id & 0xF);
|
||||
else
|
||||
printf("Socket ID: %ld\n", s->regs.extra.v2.socket_id & 0xF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdsi_certificate_dump(struct sdsi_dev *s)
|
||||
static char *license_blob_type(uint32_t type)
|
||||
{
|
||||
uint64_t state_certificate[512] = {0};
|
||||
bool first_instance;
|
||||
uint64_t previous;
|
||||
switch (type) {
|
||||
case LBT_ONE_TIME_UPGRADE:
|
||||
return "One time upgrade";
|
||||
case LBT_METERED_UPGRADE:
|
||||
return "Metered upgrade";
|
||||
default:
|
||||
return "Unknown license blob type";
|
||||
}
|
||||
}
|
||||
|
||||
static char *content_type(uint32_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case CONTENT_TYPE_LK_ENC:
|
||||
return "Licencse key encoding";
|
||||
case CONTENT_TYPE_LK_BLOB_ENC:
|
||||
return "License key + Blob encoding";
|
||||
default:
|
||||
return "Unknown content type";
|
||||
}
|
||||
}
|
||||
|
||||
static void get_feature(uint32_t encoding, char *feature)
|
||||
{
|
||||
char *name = (char *)&encoding;
|
||||
|
||||
feature[3] = name[0];
|
||||
feature[2] = name[1];
|
||||
feature[1] = name[2];
|
||||
feature[0] = name[3];
|
||||
}
|
||||
|
||||
static int sdsi_meter_cert_show(struct sdsi_dev *s)
|
||||
{
|
||||
char buf[METER_CERT_MAX_SIZE] = {0};
|
||||
struct bundle_encoding_counter *bec;
|
||||
struct meter_certificate *mc;
|
||||
uint32_t count = 0;
|
||||
FILE *cert_ptr;
|
||||
int i, ret, size;
|
||||
int ret, size;
|
||||
|
||||
ret = sdsi_update_registers(s);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!s->regs.en_features.sdsi) {
|
||||
fprintf(stderr, "SDSi feature is present but not enabled.");
|
||||
fprintf(stderr, "SDSi feature is present but not enabled.\n");
|
||||
fprintf(stderr, " Unable to read meter certificate\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!s->regs.en_features.metering) {
|
||||
fprintf(stderr, "Metering not supporting on this socket.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = chdir(s->dev_path);
|
||||
if (ret == -1) {
|
||||
perror("chdir");
|
||||
return ret;
|
||||
}
|
||||
|
||||
cert_ptr = fopen("meter_certificate", "r");
|
||||
if (!cert_ptr) {
|
||||
perror("Could not open 'meter_certificate' file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
size = fread(buf, 1, sizeof(buf), cert_ptr);
|
||||
if (!size) {
|
||||
fprintf(stderr, "Could not read 'meter_certificate' file\n");
|
||||
fclose(cert_ptr);
|
||||
return -1;
|
||||
}
|
||||
fclose(cert_ptr);
|
||||
|
||||
mc = (struct meter_certificate *)buf;
|
||||
|
||||
printf("\n");
|
||||
printf("Meter certificate for device %s\n", s->dev_name);
|
||||
printf("\n");
|
||||
printf("Block Signature: 0x%x\n", mc->block_signature);
|
||||
printf("Count Unit: %dms\n", mc->counter_unit);
|
||||
printf("PPIN: 0x%lx\n", mc->ppin);
|
||||
printf("Feature Bundle Length: %d\n", mc->bundle_length);
|
||||
printf("MMRC encoding: %d\n", mc->mmrc_encoding);
|
||||
printf("MMRC counter: %d\n", mc->mmrc_counter);
|
||||
if (mc->bundle_length % 8) {
|
||||
fprintf(stderr, "Invalid bundle length\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mc->bundle_length > METER_MAX_NUM_BUNDLES * 8) {
|
||||
fprintf(stderr, "More than %d bundles: %d\n",
|
||||
METER_MAX_NUM_BUNDLES, mc->bundle_length / 8);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bec = (void *)(mc) + sizeof(mc);
|
||||
|
||||
printf("Number of Feature Counters: %d\n", mc->bundle_length / 8);
|
||||
while (count++ < mc->bundle_length / 8) {
|
||||
char feature[5];
|
||||
|
||||
feature[4] = '\0';
|
||||
get_feature(bec[count].encoding, feature);
|
||||
printf(" %s: %d\n", feature, bec[count].counter);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdsi_state_cert_show(struct sdsi_dev *s)
|
||||
{
|
||||
char buf[STATE_CERT_MAX_SIZE] = {0};
|
||||
struct state_certificate *sc;
|
||||
struct license_key_info *lki;
|
||||
uint32_t offset = 0;
|
||||
uint32_t count = 0;
|
||||
FILE *cert_ptr;
|
||||
int ret, size;
|
||||
|
||||
ret = sdsi_update_registers(s);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!s->regs.en_features.sdsi) {
|
||||
fprintf(stderr, "On Demand feature is present but not enabled.");
|
||||
fprintf(stderr, " Unable to read state certificate");
|
||||
return -1;
|
||||
}
|
||||
@ -198,40 +438,82 @@ static int sdsi_certificate_dump(struct sdsi_dev *s)
|
||||
return -1;
|
||||
}
|
||||
|
||||
size = fread(state_certificate, 1, sizeof(state_certificate), cert_ptr);
|
||||
size = fread(buf, 1, sizeof(buf), cert_ptr);
|
||||
if (!size) {
|
||||
fprintf(stderr, "Could not read 'state_certificate' file\n");
|
||||
fclose(cert_ptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("%3d: 0x%lx\n", 0, state_certificate[0]);
|
||||
previous = state_certificate[0];
|
||||
first_instance = true;
|
||||
|
||||
for (i = 1; i < (int)(round_up(size, sizeof(uint64_t))/sizeof(uint64_t)); i++) {
|
||||
if (state_certificate[i] == previous) {
|
||||
if (first_instance) {
|
||||
puts("*");
|
||||
first_instance = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
printf("%3d: 0x%lx\n", i, state_certificate[i]);
|
||||
previous = state_certificate[i];
|
||||
first_instance = true;
|
||||
}
|
||||
printf("%3d\n", i);
|
||||
|
||||
fclose(cert_ptr);
|
||||
|
||||
sc = (struct state_certificate *)buf;
|
||||
|
||||
/* Print register info for this guid */
|
||||
printf("\n");
|
||||
printf("State certificate for device %s\n", s->dev_name);
|
||||
printf("\n");
|
||||
printf("Content Type: %s\n", content_type(sc->content_type));
|
||||
printf("Region Revision ID: %d\n", sc->region_rev_id);
|
||||
printf("Header Size: %d\n", sc->header_size * 4);
|
||||
printf("Total Size: %d\n", sc->total_size);
|
||||
printf("OEM Key Size: %d\n", sc->key_size * 4);
|
||||
printf("Number of Licenses: %d\n", sc->num_licenses);
|
||||
|
||||
/* Skip over the license sizes 4 bytes per license) to get the license key info */
|
||||
lki = (void *)sc + sizeof(*sc) + (4 * sc->num_licenses);
|
||||
|
||||
printf("License blob Info:\n");
|
||||
printf(" License Key Revision ID: 0x%x\n", lki->key_rev_id);
|
||||
printf(" License Key Image Content: 0x%lx%lx%lx%lx%lx%lx\n",
|
||||
lki->key_image_content[5], lki->key_image_content[4],
|
||||
lki->key_image_content[3], lki->key_image_content[2],
|
||||
lki->key_image_content[1], lki->key_image_content[0]);
|
||||
|
||||
while (count++ < sc->num_licenses) {
|
||||
uint32_t blob_size_field = *(uint32_t *)(buf + 0x14 + count * 4);
|
||||
uint32_t blob_size = LICENSE_BLOB_SIZE(blob_size_field);
|
||||
bool license_valid = LICENSE_VALID(blob_size_field);
|
||||
struct license_blob_content *lbc =
|
||||
(void *)(sc) + // start of the state certificate
|
||||
sizeof(*sc) + // size of the state certificate
|
||||
(4 * sc->num_licenses) + // total size of the blob size blocks
|
||||
sizeof(*lki) + // size of the license key info
|
||||
offset; // offset to this blob content
|
||||
struct bundle_encoding *bundle = (void *)(lbc) + sizeof(*lbc);
|
||||
char feature[5];
|
||||
uint32_t i;
|
||||
|
||||
printf(" Blob %d:\n", count - 1);
|
||||
printf(" License blob size: %u\n", blob_size);
|
||||
printf(" License is valid: %s\n", license_valid ? "Yes" : "No");
|
||||
printf(" License blob type: %s\n", license_blob_type(lbc->type));
|
||||
printf(" License blob ID: 0x%lx\n", lbc->id);
|
||||
printf(" PPIN: 0x%lx\n", lbc->ppin);
|
||||
printf(" Previous PPIN: 0x%lx\n", lbc->previous_ppin);
|
||||
printf(" Blob revision ID: %u\n", lbc->rev_id);
|
||||
printf(" Number of Features: %u\n", lbc->num_bundles);
|
||||
|
||||
feature[4] = '\0';
|
||||
|
||||
for (i = 0; i < min(lbc->num_bundles, STATE_MAX_NUM_IN_BUNDLE); i++) {
|
||||
get_feature(bundle[i].encoding, feature);
|
||||
printf(" Feature %d: %s\n", i, feature);
|
||||
}
|
||||
|
||||
if (lbc->num_bundles > STATE_MAX_NUM_IN_BUNDLE)
|
||||
fprintf(stderr, " Warning: %d > %d licenses in bundle reported.\n",
|
||||
lbc->num_bundles, STATE_MAX_NUM_IN_BUNDLE);
|
||||
|
||||
offset += blob_size;
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdsi_provision(struct sdsi_dev *s, char *bin_file, enum command command)
|
||||
{
|
||||
int bin_fd, prov_fd, size, ret;
|
||||
char buf[4096] = { 0 };
|
||||
char buf[STATE_CERT_MAX_SIZE] = { 0 };
|
||||
char cap[] = "provision_cap";
|
||||
char akc[] = "provision_akc";
|
||||
char *prov_file;
|
||||
@ -266,7 +548,7 @@ static int sdsi_provision(struct sdsi_dev *s, char *bin_file, enum command comma
|
||||
}
|
||||
|
||||
/* Read the binary file into the buffer */
|
||||
size = read(bin_fd, buf, 4096);
|
||||
size = read(bin_fd, buf, STATE_CERT_MAX_SIZE);
|
||||
if (size == -1) {
|
||||
close(bin_fd);
|
||||
close(prov_fd);
|
||||
@ -298,7 +580,7 @@ static int sdsi_provision_akc(struct sdsi_dev *s, char *bin_file)
|
||||
return ret;
|
||||
|
||||
if (!s->regs.en_features.sdsi) {
|
||||
fprintf(stderr, "SDSi feature is present but not enabled. Unable to provision");
|
||||
fprintf(stderr, "On Demand feature is present but not enabled. Unable to provision");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -328,7 +610,7 @@ static int sdsi_provision_cap(struct sdsi_dev *s, char *bin_file)
|
||||
return ret;
|
||||
|
||||
if (!s->regs.en_features.sdsi) {
|
||||
fprintf(stderr, "SDSi feature is present but not enabled. Unable to provision");
|
||||
fprintf(stderr, "On Demand feature is present but not enabled. Unable to provision");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -443,25 +725,27 @@ static void sdsi_free_dev(struct sdsi_dev *s)
|
||||
|
||||
static void usage(char *prog)
|
||||
{
|
||||
printf("Usage: %s [-l] [-d DEVNO [-iD] [-a FILE] [-c FILE]]\n", prog);
|
||||
printf("Usage: %s [-l] [-d DEVNO [-i] [-s] [-m] [-a FILE] [-c FILE]]\n", prog);
|
||||
}
|
||||
|
||||
static void show_help(void)
|
||||
{
|
||||
printf("Commands:\n");
|
||||
printf(" %-18s\t%s\n", "-l, --list", "list available sdsi devices");
|
||||
printf(" %-18s\t%s\n", "-d, --devno DEVNO", "sdsi device number");
|
||||
printf(" %-18s\t%s\n", "-i --info", "show socket information");
|
||||
printf(" %-18s\t%s\n", "-D --dump", "dump state certificate data");
|
||||
printf(" %-18s\t%s\n", "-a --akc FILE", "provision socket with AKC FILE");
|
||||
printf(" %-18s\t%s\n", "-c --cap FILE>", "provision socket with CAP FILE");
|
||||
printf(" %-18s\t%s\n", "-l, --list", "list available On Demand devices");
|
||||
printf(" %-18s\t%s\n", "-d, --devno DEVNO", "On Demand device number");
|
||||
printf(" %-18s\t%s\n", "-i, --info", "show socket information");
|
||||
printf(" %-18s\t%s\n", "-s, --state", "show state certificate");
|
||||
printf(" %-18s\t%s\n", "-m, --meter", "show meter certificate");
|
||||
printf(" %-18s\t%s\n", "-a, --akc FILE", "provision socket with AKC FILE");
|
||||
printf(" %-18s\t%s\n", "-c, --cap FILE>", "provision socket with CAP FILE");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char bin_file[PATH_MAX], *dev_no = NULL;
|
||||
bool device_selected = false;
|
||||
char *progname;
|
||||
enum command command = CMD_NONE;
|
||||
enum command command = -1;
|
||||
struct sdsi_dev *s;
|
||||
int ret = 0, opt;
|
||||
int option_index = 0;
|
||||
@ -470,21 +754,23 @@ int main(int argc, char *argv[])
|
||||
{"akc", required_argument, 0, 'a'},
|
||||
{"cap", required_argument, 0, 'c'},
|
||||
{"devno", required_argument, 0, 'd'},
|
||||
{"dump", no_argument, 0, 'D'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"info", no_argument, 0, 'i'},
|
||||
{"list", no_argument, 0, 'l'},
|
||||
{"meter", no_argument, 0, 'm'},
|
||||
{"state", no_argument, 0, 's'},
|
||||
{0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
progname = argv[0];
|
||||
|
||||
while ((opt = getopt_long_only(argc, argv, "+a:c:d:Da:c:h", long_options,
|
||||
while ((opt = getopt_long_only(argc, argv, "+a:c:d:hilms", long_options,
|
||||
&option_index)) != -1) {
|
||||
switch (opt) {
|
||||
case 'd':
|
||||
dev_no = optarg;
|
||||
device_selected = true;
|
||||
break;
|
||||
case 'l':
|
||||
sdsi_list_devices();
|
||||
@ -492,8 +778,11 @@ int main(int argc, char *argv[])
|
||||
case 'i':
|
||||
command = CMD_SOCKET_INFO;
|
||||
break;
|
||||
case 'D':
|
||||
command = CMD_DUMP_CERT;
|
||||
case 'm':
|
||||
command = CMD_METER_CERT;
|
||||
break;
|
||||
case 's':
|
||||
command = CMD_STATE_CERT;
|
||||
break;
|
||||
case 'a':
|
||||
case 'c':
|
||||
@ -520,39 +809,38 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (!dev_no) {
|
||||
if (command != CMD_NONE)
|
||||
fprintf(stderr, "Missing device number, DEVNO, for this command\n");
|
||||
usage(progname);
|
||||
if (device_selected) {
|
||||
s = sdsi_create_dev(dev_no);
|
||||
if (!s)
|
||||
return -1;
|
||||
|
||||
switch (command) {
|
||||
case CMD_SOCKET_INFO:
|
||||
ret = sdsi_read_reg(s);
|
||||
break;
|
||||
case CMD_METER_CERT:
|
||||
ret = sdsi_meter_cert_show(s);
|
||||
break;
|
||||
case CMD_STATE_CERT:
|
||||
ret = sdsi_state_cert_show(s);
|
||||
break;
|
||||
case CMD_PROV_AKC:
|
||||
ret = sdsi_provision_akc(s, bin_file);
|
||||
break;
|
||||
case CMD_PROV_CAP:
|
||||
ret = sdsi_provision_cap(s, bin_file);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "No command specified\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sdsi_free_dev(s);
|
||||
|
||||
} else {
|
||||
fprintf(stderr, "No device specified\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
s = sdsi_create_dev(dev_no);
|
||||
if (!s)
|
||||
return -1;
|
||||
|
||||
/* Run the command */
|
||||
switch (command) {
|
||||
case CMD_NONE:
|
||||
fprintf(stderr, "Missing command for device %s\n", dev_no);
|
||||
usage(progname);
|
||||
break;
|
||||
case CMD_SOCKET_INFO:
|
||||
ret = sdsi_read_reg(s);
|
||||
break;
|
||||
case CMD_DUMP_CERT:
|
||||
ret = sdsi_certificate_dump(s);
|
||||
break;
|
||||
case CMD_PROV_AKC:
|
||||
ret = sdsi_provision_akc(s, bin_file);
|
||||
break;
|
||||
case CMD_PROV_CAP:
|
||||
ret = sdsi_provision_cap(s, bin_file);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
sdsi_free_dev(s);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user