summaryrefslogtreecommitdiff
path: root/drivers/platform/x86/intel
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/x86/intel')
-rw-r--r--drivers/platform/x86/intel/atomisp2/led.c1
-rw-r--r--drivers/platform/x86/intel/atomisp2/pm.c1
-rw-r--r--drivers/platform/x86/intel/bxtwc_tmu.c1
-rw-r--r--drivers/platform/x86/intel/ehl_pse_io.c1
-rw-r--r--drivers/platform/x86/intel/hid.c22
-rw-r--r--drivers/platform/x86/intel/int1092/intel_sar.c39
-rw-r--r--drivers/platform/x86/intel/int3472/discrete.c51
-rw-r--r--drivers/platform/x86/intel/int3472/tps68470_board_data.c158
-rw-r--r--drivers/platform/x86/intel/ishtp_eclite.c5
-rw-r--r--drivers/platform/x86/intel/plr_tpmi.c46
-rw-r--r--drivers/platform/x86/intel/pmc/Kconfig25
-rw-r--r--drivers/platform/x86/intel/pmc/Makefile5
-rw-r--r--drivers/platform/x86/intel/pmc/arl.c13
-rw-r--r--drivers/platform/x86/intel/pmc/core.c142
-rw-r--r--drivers/platform/x86/intel/pmc/core.h84
-rw-r--r--drivers/platform/x86/intel/pmc/lnl.c6
-rw-r--r--drivers/platform/x86/intel/pmc/mtl.c7
-rw-r--r--drivers/platform/x86/intel/pmc/nvl.c1539
-rw-r--r--drivers/platform/x86/intel/pmc/ptl.c8
-rw-r--r--drivers/platform/x86/intel/pmc/pwrm_telemetry.c214
-rw-r--r--drivers/platform/x86/intel/pmc/ssram_telemetry.c396
-rw-r--r--drivers/platform/x86/intel/pmc/wcl.c6
-rw-r--r--drivers/platform/x86/intel/pmt/class.c156
-rw-r--r--drivers/platform/x86/intel/pmt/class.h6
-rw-r--r--drivers/platform/x86/intel/pmt/crashlog.c19
-rw-r--r--drivers/platform/x86/intel/pmt/telemetry.c34
-rw-r--r--drivers/platform/x86/intel/punit_ipc.c1
-rw-r--r--drivers/platform/x86/intel/rst.c6
-rw-r--r--drivers/platform/x86/intel/smartconnect.c6
-rw-r--r--drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c84
-rw-r--r--drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c23
-rw-r--r--drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h8
-rw-r--r--drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c15
-rw-r--r--drivers/platform/x86/intel/vbtn.c6
-rw-r--r--drivers/platform/x86/intel/vsec.c102
-rw-r--r--drivers/platform/x86/intel/vsec_tpmi.c82
36 files changed, 3035 insertions, 283 deletions
diff --git a/drivers/platform/x86/intel/atomisp2/led.c b/drivers/platform/x86/intel/atomisp2/led.c
index 10077a61d8c5..344ea57d9736 100644
--- a/drivers/platform/x86/intel/atomisp2/led.c
+++ b/drivers/platform/x86/intel/atomisp2/led.c
@@ -11,7 +11,6 @@
#include <linux/gpio/machine.h>
#include <linux/leds.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
diff --git a/drivers/platform/x86/intel/atomisp2/pm.c b/drivers/platform/x86/intel/atomisp2/pm.c
index 805fc0d8515c..ad1f99140962 100644
--- a/drivers/platform/x86/intel/atomisp2/pm.c
+++ b/drivers/platform/x86/intel/atomisp2/pm.c
@@ -13,7 +13,6 @@
#include <linux/delay.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <asm/iosf_mbi.h>
diff --git a/drivers/platform/x86/intel/bxtwc_tmu.c b/drivers/platform/x86/intel/bxtwc_tmu.c
index 99437b2ccc25..b3666704d85b 100644
--- a/drivers/platform/x86/intel/bxtwc_tmu.c
+++ b/drivers/platform/x86/intel/bxtwc_tmu.c
@@ -10,7 +10,6 @@
*/
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/mfd/intel_soc_pmic.h>
diff --git a/drivers/platform/x86/intel/ehl_pse_io.c b/drivers/platform/x86/intel/ehl_pse_io.c
index 861e14808b35..f75f3a8cc6b0 100644
--- a/drivers/platform/x86/intel/ehl_pse_io.c
+++ b/drivers/platform/x86/intel/ehl_pse_io.c
@@ -12,7 +12,6 @@
#include <linux/errno.h>
#include <linux/gfp_types.h>
#include <linux/ioport.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/sizes.h>
diff --git a/drivers/platform/x86/intel/hid.c b/drivers/platform/x86/intel/hid.c
index 2ddd8af8c1ce..acd42e639fa4 100644
--- a/drivers/platform/x86/intel/hid.c
+++ b/drivers/platform/x86/intel/hid.c
@@ -7,11 +7,13 @@
*/
#include <linux/acpi.h>
+#include <linux/cleanup.h>
#include <linux/dmi.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/string_choices.h>
#include <linux/suspend.h>
@@ -156,6 +158,13 @@ static const struct dmi_system_id button_array_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Surface Go 4"),
},
},
+ {
+ .ident = "HP ProBook x360 440 G1",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook x360 440 G1"),
+ },
+ },
{ }
};
@@ -230,6 +239,7 @@ static const struct dmi_system_id dmi_auto_add_switch[] = {
};
struct intel_hid_priv {
+ struct mutex mutex; /* Avoid notify_handler() racing with itself */
struct input_dev *input_dev;
struct input_dev *array;
struct input_dev *switches;
@@ -565,6 +575,8 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)
struct key_entry *ke;
int err;
+ guard(mutex)(&priv->mutex);
+
/*
* Some convertible have unreliable VGBS return which could cause incorrect
* SW_TABLET_MODE report, in these cases we enable support when receiving
@@ -688,12 +700,16 @@ static bool button_array_present(struct platform_device *device)
static int intel_hid_probe(struct platform_device *device)
{
- acpi_handle handle = ACPI_HANDLE(&device->dev);
unsigned long long mode, dummy;
struct intel_hid_priv *priv;
+ acpi_handle handle;
acpi_status status;
int err;
+ handle = ACPI_HANDLE(&device->dev);
+ if (!handle)
+ return -ENODEV;
+
intel_hid_init_dsm(handle);
if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_HDMM_FN, &mode)) {
@@ -716,6 +732,10 @@ static int intel_hid_probe(struct platform_device *device)
return -ENOMEM;
dev_set_drvdata(&device->dev, priv);
+ err = devm_mutex_init(&device->dev, &priv->mutex);
+ if (err)
+ return err;
+
/* See dual_accel_detect.h for more info on the dual_accel check. */
if (enable_sw_tablet_mode == TABLET_SW_AUTO) {
if (dmi_check_system(dmi_vgbs_allow_list))
diff --git a/drivers/platform/x86/intel/int1092/intel_sar.c b/drivers/platform/x86/intel/int1092/intel_sar.c
index 88822023a149..f506155f35d4 100644
--- a/drivers/platform/x86/intel/int1092/intel_sar.c
+++ b/drivers/platform/x86/intel/int1092/intel_sar.c
@@ -91,8 +91,10 @@ static acpi_status parse_package(struct wwan_sar_context *context, union acpi_ob
item->package.count <= data->total_dev_mode)
return AE_ERROR;
- data->device_mode_info = kmalloc_objs(struct wwan_device_mode_info,
- data->total_dev_mode);
+ data->device_mode_info = devm_kcalloc(&context->sar_device->dev,
+ data->total_dev_mode,
+ sizeof(*data->device_mode_info),
+ GFP_KERNEL);
if (!data->device_mode_info)
return AE_ERROR;
@@ -245,21 +247,26 @@ static void sar_get_data(int reg, struct wwan_sar_context *context)
static int sar_probe(struct platform_device *device)
{
struct wwan_sar_context *context;
+ acpi_handle handle;
int reg;
int result;
- context = kzalloc_obj(*context);
+ handle = ACPI_HANDLE(&device->dev);
+ if (!handle)
+ return -ENODEV;
+
+ context = devm_kzalloc(&device->dev, sizeof(*context), GFP_KERNEL);
if (!context)
return -ENOMEM;
context->sar_device = device;
- context->handle = ACPI_HANDLE(&device->dev);
+ context->handle = handle;
dev_set_drvdata(&device->dev, context);
result = guid_parse(SAR_DSM_UUID, &context->guid);
if (result) {
dev_err(&device->dev, "SAR UUID parse error: %d\n", result);
- goto r_free;
+ return result;
}
for (reg = 0; reg < MAX_REGULATORY; reg++)
@@ -267,43 +274,29 @@ static int sar_probe(struct platform_device *device)
if (sar_get_device_mode(device) != AE_OK) {
dev_err(&device->dev, "Failed to get device mode\n");
- result = -EIO;
- goto r_free;
+ return -EIO;
}
result = sysfs_create_group(&device->dev.kobj, &intcsar_group);
if (result) {
dev_err(&device->dev, "sysfs creation failed\n");
- goto r_free;
+ return result;
}
if (acpi_install_notify_handler(ACPI_HANDLE(&device->dev), ACPI_DEVICE_NOTIFY,
sar_notify, (void *)device) != AE_OK) {
dev_err(&device->dev, "Failed acpi_install_notify_handler\n");
- result = -EIO;
- goto r_sys;
+ sysfs_remove_group(&device->dev.kobj, &intcsar_group);
+ return -EIO;
}
return 0;
-
-r_sys:
- sysfs_remove_group(&device->dev.kobj, &intcsar_group);
-r_free:
- kfree(context);
- return result;
}
static void sar_remove(struct platform_device *device)
{
- struct wwan_sar_context *context = dev_get_drvdata(&device->dev);
- int reg;
-
acpi_remove_notify_handler(ACPI_HANDLE(&device->dev),
ACPI_DEVICE_NOTIFY, sar_notify);
sysfs_remove_group(&device->dev.kobj, &intcsar_group);
- for (reg = 0; reg < MAX_REGULATORY; reg++)
- kfree(context->config_data[reg].device_mode_info);
-
- kfree(context);
}
static struct platform_driver sar_driver = {
diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c
index 115bb37577a1..6c729fcfce5d 100644
--- a/drivers/platform/x86/intel/int3472/discrete.c
+++ b/drivers/platform/x86/intel/int3472/discrete.c
@@ -123,10 +123,31 @@ skl_int3472_gpiod_get_from_temp_lookup(struct int3472_discrete_device *int3472,
return desc;
}
+/*
+ * Other vana-supply users (e.g. ST, Toshiba, Sony sensors) can be added to
+ * this array instead of adding new quirk table entries.
+ */
+static const char * const power_enable_hids_vana[] = {
+ "SONY471A", /* imx471 on Lenovo X9-14 and X9-15 */
+ "TBE20A0", /* imx471 on Lenovo X1 Carbon G14 */
+ NULL
+};
+
+static const char * const power_enable_hids_vdd[] = {
+ "INT33F0", /* mt9m114 */
+ NULL
+};
+
+static const char * const power_enable_hids_enable[] = {
+ "INT347E", /* ov7251 */
+ NULL
+};
+
/**
* struct int3472_gpio_map - Map GPIOs to whatever is expected by the
* sensor driver (as in DT bindings)
- * @hid: The ACPI HID of the device without the instance number e.g. INT347E
+ * @hids: NULL-terminated array of ACPI HIDs of the devices without the
+ * instance number e.g. INT347E
* @type_from: The GPIO type from ACPI ?SDT
* @type_to: The assigned GPIO type, typically same as @type_from
* @enable_time_us: Enable time in usec for GPIOs mapped to regulators
@@ -135,7 +156,7 @@ skl_int3472_gpiod_get_from_temp_lookup(struct int3472_discrete_device *int3472,
* GPIO_ACTIVE_HIGH otherwise
*/
struct int3472_gpio_map {
- const char *hid;
+ const char * const *hids;
u8 type_from;
u8 type_to;
bool polarity_low;
@@ -145,27 +166,45 @@ struct int3472_gpio_map {
static const struct int3472_gpio_map int3472_gpio_map[] = {
{ /* mt9m114 designs declare a powerdown pin which controls the regulators */
- .hid = "INT33F0",
+ .hids = power_enable_hids_vdd,
.type_from = INT3472_GPIO_TYPE_POWERDOWN,
.type_to = INT3472_GPIO_TYPE_POWER_ENABLE,
.con_id = "vdd",
.enable_time_us = GPIO_REGULATOR_ENABLE_TIME,
},
{ /* ov7251 driver / DT-bindings expect "enable" as con_id for reset */
- .hid = "INT347E",
+ .hids = power_enable_hids_enable,
.type_from = INT3472_GPIO_TYPE_RESET,
.type_to = INT3472_GPIO_TYPE_RESET,
.con_id = "enable",
},
{ /* ov08x40's handshake pin needs a 45 ms delay on some HP laptops */
- .hid = "OVTI08F4",
+ .hids = (const char * const[]) { "OVTI08F4", NULL },
.type_from = INT3472_GPIO_TYPE_HANDSHAKE,
.type_to = INT3472_GPIO_TYPE_HANDSHAKE,
.con_id = "dvdd",
.enable_time_us = 45 * USEC_PER_MSEC,
},
+ { /* Sensors which expect "vana" as con_id for power enable */
+ .hids = power_enable_hids_vana,
+ .type_from = INT3472_GPIO_TYPE_POWER_ENABLE,
+ .type_to = INT3472_GPIO_TYPE_POWER_ENABLE,
+ .con_id = "vana",
+ .enable_time_us = GPIO_REGULATOR_ENABLE_TIME,
+ },
};
+static bool int3472_gpio_map_hids_match(struct acpi_device *adev,
+ const char * const *hids)
+{
+ for (unsigned int i = 0; hids[i]; i++) {
+ if (acpi_dev_hid_uid_match(adev, hids[i], NULL))
+ return true;
+ }
+
+ return false;
+}
+
static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3472, u8 *type,
const char **con_id, unsigned long *gpio_flags,
unsigned int *enable_time_us)
@@ -182,7 +221,7 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3
if (*type != int3472_gpio_map[i].type_from)
continue;
- if (!acpi_dev_hid_uid_match(adev, int3472_gpio_map[i].hid, NULL))
+ if (!int3472_gpio_map_hids_match(adev, int3472_gpio_map[i].hids))
continue;
dev_dbg(int3472->dev, "mapping type 0x%02x pin to 0x%02x %s\n",
diff --git a/drivers/platform/x86/intel/int3472/tps68470_board_data.c b/drivers/platform/x86/intel/int3472/tps68470_board_data.c
index c1ddbf9a82c0..c53542465fb4 100644
--- a/drivers/platform/x86/intel/int3472/tps68470_board_data.c
+++ b/drivers/platform/x86/intel/int3472/tps68470_board_data.c
@@ -238,7 +238,7 @@ static struct regulator_consumer_supply ovti5675_dvdd_consumer_supplies[] = {
REGULATOR_SUPPLY("dvdd", "i2c-OVTI5675:00"),
};
-static const struct regulator_init_data msi_p14_ai_evo_tps68470_core_reg_init_data = {
+static const struct regulator_init_data msi_prestige_ai_evo_tps68470_core_reg_init_data = {
.constraints = {
.min_uV = 1200000,
.max_uV = 1200000,
@@ -249,7 +249,7 @@ static const struct regulator_init_data msi_p14_ai_evo_tps68470_core_reg_init_da
.consumer_supplies = ovti5675_dvdd_consumer_supplies,
};
-static const struct regulator_init_data msi_p14_ai_evo_tps68470_ana_reg_init_data = {
+static const struct regulator_init_data msi_prestige_ai_evo_tps68470_ana_reg_init_data = {
.constraints = {
.min_uV = 2815200,
.max_uV = 2815200,
@@ -260,7 +260,7 @@ static const struct regulator_init_data msi_p14_ai_evo_tps68470_ana_reg_init_dat
.consumer_supplies = ovti5675_avdd_consumer_supplies,
};
-static const struct regulator_init_data msi_p14_ai_evo_tps68470_vio_reg_init_data = {
+static const struct regulator_init_data msi_prestige_ai_evo_tps68470_vio_reg_init_data = {
.constraints = {
.min_uV = 1800600,
.max_uV = 1800600,
@@ -269,7 +269,7 @@ static const struct regulator_init_data msi_p14_ai_evo_tps68470_vio_reg_init_dat
},
};
-static const struct regulator_init_data msi_p14_ai_evo_tps68470_vsio_reg_init_data = {
+static const struct regulator_init_data msi_prestige_ai_evo_tps68470_vsio_reg_init_data = {
.constraints = {
.min_uV = 1800600,
.max_uV = 1800600,
@@ -280,12 +280,92 @@ static const struct regulator_init_data msi_p14_ai_evo_tps68470_vsio_reg_init_da
.consumer_supplies = ovti5675_dovdd_consumer_supplies,
};
-static const struct tps68470_regulator_platform_data msi_p14_ai_evo_tps68470_pdata = {
+static const struct tps68470_regulator_platform_data msi_prestige_ai_evo_tps68470_pdata = {
.reg_init_data = {
- [TPS68470_CORE] = &msi_p14_ai_evo_tps68470_core_reg_init_data,
- [TPS68470_ANA] = &msi_p14_ai_evo_tps68470_ana_reg_init_data,
- [TPS68470_VIO] = &msi_p14_ai_evo_tps68470_vio_reg_init_data,
- [TPS68470_VSIO] = &msi_p14_ai_evo_tps68470_vsio_reg_init_data,
+ [TPS68470_CORE] = &msi_prestige_ai_evo_tps68470_core_reg_init_data,
+ [TPS68470_ANA] = &msi_prestige_ai_evo_tps68470_ana_reg_init_data,
+ [TPS68470_VIO] = &msi_prestige_ai_evo_tps68470_vio_reg_init_data,
+ [TPS68470_VSIO] = &msi_prestige_ai_evo_tps68470_vsio_reg_init_data,
+ },
+};
+
+/* Settings for Intel NVL platform */
+
+static struct regulator_consumer_supply ovti13b1_core_consumer_supplies[] = {
+ REGULATOR_SUPPLY("dvdd", "i2c-OVTI13B1:01"),
+};
+
+static struct regulator_consumer_supply ovti13b1_ana_consumer_supplies[] = {
+ REGULATOR_SUPPLY("avdd", "i2c-OVTI13B1:01"),
+};
+
+static struct regulator_consumer_supply ovti13b1_vcm_consumer_supplies[] = {
+ REGULATOR_SUPPLY("vcc", "i2c-OVTI13B1:01-VCM"),
+};
+
+static struct regulator_consumer_supply ovti13b1_vsio_consumer_supplies[] = {
+ REGULATOR_SUPPLY("dovdd", "i2c-OVTI13B1:01"),
+};
+
+static const struct regulator_init_data intel_nvl_tps68470_core_reg_init_data = {
+ .constraints = {
+ .min_uV = 1200000,
+ .max_uV = 1200000,
+ .apply_uV = true,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ovti13b1_core_consumer_supplies),
+ .consumer_supplies = ovti13b1_core_consumer_supplies,
+};
+
+static const struct regulator_init_data intel_nvl_tps68470_ana_reg_init_data = {
+ .constraints = {
+ .min_uV = 2815200,
+ .max_uV = 2815200,
+ .apply_uV = true,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ovti13b1_ana_consumer_supplies),
+ .consumer_supplies = ovti13b1_ana_consumer_supplies,
+};
+static const struct regulator_init_data intel_nvl_tps68470_vcm_reg_init_data = {
+ .constraints = {
+ .min_uV = 2815200,
+ .max_uV = 2815200,
+ .apply_uV = true,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ovti13b1_vcm_consumer_supplies),
+ .consumer_supplies = ovti13b1_vcm_consumer_supplies,
+};
+
+/* Ensure the always-on VIO regulator has the same voltage as VSIO */
+static const struct regulator_init_data intel_nvl_tps68470_vio_reg_init_data = {
+ .constraints = {
+ .min_uV = 1800600,
+ .max_uV = 1800600,
+ .apply_uV = true,
+ .always_on = true,
+ },
+};
+static const struct regulator_init_data intel_nvl_tps68470_vsio_reg_init_data = {
+ .constraints = {
+ .min_uV = 1800600,
+ .max_uV = 1800600,
+ .apply_uV = true,
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(ovti13b1_vsio_consumer_supplies),
+ .consumer_supplies = ovti13b1_vsio_consumer_supplies,
+};
+
+static const struct tps68470_regulator_platform_data intel_nvl_tps68470_pdata = {
+ .reg_init_data = {
+ [TPS68470_CORE] = &intel_nvl_tps68470_core_reg_init_data,
+ [TPS68470_ANA] = &intel_nvl_tps68470_ana_reg_init_data,
+ [TPS68470_VCM] = &intel_nvl_tps68470_vcm_reg_init_data,
+ [TPS68470_VIO] = &intel_nvl_tps68470_vio_reg_init_data,
+ [TPS68470_VSIO] = &intel_nvl_tps68470_vsio_reg_init_data,
},
};
@@ -315,7 +395,7 @@ static struct gpiod_lookup_table dell_7212_int3479_gpios = {
}
};
-static struct gpiod_lookup_table msi_p14_ai_evo_ovti5675_gpios = {
+static struct gpiod_lookup_table msi_prestige_ai_evo_ovti5675_gpios = {
.dev_id = "i2c-OVTI5675:00",
.table = {
GPIO_LOOKUP("tps68470-gpio", 9, "reset", GPIO_ACTIVE_LOW),
@@ -323,13 +403,21 @@ static struct gpiod_lookup_table msi_p14_ai_evo_ovti5675_gpios = {
}
};
-static const struct property_entry msi_p14_ai_evo_gpio_props[] = {
+static struct gpiod_lookup_table intel_nvl_tps68470_gpios = {
+ .dev_id = "i2c-OVTI13B1:01",
+ .table = {
+ GPIO_LOOKUP("tps68470-gpio", 9, "reset", GPIO_ACTIVE_LOW),
+ { }
+ }
+};
+
+static const struct property_entry int3472_tps68470_daisy_chain_gpio_props[] = {
PROPERTY_ENTRY_BOOL("daisy-chain-enable"),
{ }
};
-static const struct software_node msi_p14_ai_evo_tps68470_gpio_swnode = {
- .properties = msi_p14_ai_evo_gpio_props,
+static const struct software_node int3472_tps68470_daisy_chain_gpio_swnode = {
+ .properties = int3472_tps68470_daisy_chain_gpio_props,
};
static const struct int3472_tps68470_board_data surface_go_tps68470_board_data = {
@@ -361,13 +449,23 @@ static const struct int3472_tps68470_board_data dell_7212_tps68470_board_data =
},
};
-static const struct int3472_tps68470_board_data msi_p14_ai_evo_tps68470_board_data = {
+static const struct int3472_tps68470_board_data msi_prestige_ai_evo_tps68470_board_data = {
.dev_name = "i2c-INT3472:06",
- .tps68470_regulator_pdata = &msi_p14_ai_evo_tps68470_pdata,
- .tps68470_gpio_swnode = &msi_p14_ai_evo_tps68470_gpio_swnode,
+ .tps68470_regulator_pdata = &msi_prestige_ai_evo_tps68470_pdata,
+ .tps68470_gpio_swnode = &int3472_tps68470_daisy_chain_gpio_swnode,
.n_gpiod_lookups = 1,
.tps68470_gpio_lookup_tables = {
- &msi_p14_ai_evo_ovti5675_gpios,
+ &msi_prestige_ai_evo_ovti5675_gpios,
+ },
+};
+
+static const struct int3472_tps68470_board_data intel_nvl_tps68470_board_data = {
+ .dev_name = "i2c-INT3472:04",
+ .tps68470_regulator_pdata = &intel_nvl_tps68470_pdata,
+ .tps68470_gpio_swnode = &int3472_tps68470_daisy_chain_gpio_swnode,
+ .n_gpiod_lookups = 1,
+ .tps68470_gpio_lookup_tables = {
+ &intel_nvl_tps68470_gpios,
},
};
@@ -403,9 +501,33 @@ static const struct dmi_system_id int3472_tps68470_board_data_table[] = {
{
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Prestige 13 AI+ Evo A2VMG"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "MS-13Q3"),
+ },
+ .driver_data = (void *)&msi_prestige_ai_evo_tps68470_board_data,
+ },
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Prestige 14 AI+ Evo C2VMG"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "MS-14N3"),
+ },
+ .driver_data = (void *)&msi_prestige_ai_evo_tps68470_board_data,
+ },
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Prestige 16 AI+ Evo B2VMG"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "MS-15A3"),
+ },
+ .driver_data = (void *)&msi_prestige_ai_evo_tps68470_board_data,
+ },
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Nova Lake Client Platform"),
},
- .driver_data = (void *)&msi_p14_ai_evo_tps68470_board_data,
+ .driver_data = (void *)&intel_nvl_tps68470_board_data,
},
{ }
};
diff --git a/drivers/platform/x86/intel/ishtp_eclite.c b/drivers/platform/x86/intel/ishtp_eclite.c
index 93ac8b2dbf38..bca7e217878b 100644
--- a/drivers/platform/x86/intel/ishtp_eclite.c
+++ b/drivers/platform/x86/intel/ishtp_eclite.c
@@ -600,13 +600,16 @@ static int ecl_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
rv = acpi_opregion_init(opr_dev);
if (rv) {
dev_err(cl_data_to_dev(opr_dev), "ACPI opregion init failed\n");
- goto err_exit;
+ goto err_put;
}
/* Reprobe devices depending on ECLite - battery, fan, etc. */
acpi_dev_clear_dependencies(opr_dev->adev);
return 0;
+
+err_put:
+ acpi_dev_put(opr_dev->adev);
err_exit:
ishtp_set_connection_state(ecl_ishtp_cl, ISHTP_CL_DISCONNECTING);
ishtp_cl_disconnect(ecl_ishtp_cl);
diff --git a/drivers/platform/x86/intel/plr_tpmi.c b/drivers/platform/x86/intel/plr_tpmi.c
index 05727169f49c..f98c241edee4 100644
--- a/drivers/platform/x86/intel/plr_tpmi.c
+++ b/drivers/platform/x86/intel/plr_tpmi.c
@@ -20,8 +20,8 @@
#include <linux/kstrtox.h>
#include <linux/lockdep.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
+#include <linux/notifier.h>
#include <linux/seq_file.h>
#include <linux/sprintf.h>
#include <linux/types.h>
@@ -60,6 +60,8 @@ struct tpmi_plr {
struct tpmi_plr_die *die_info;
int num_dies;
struct auxiliary_device *auxdev;
+ struct notifier_block nb;
+ struct mutex lock; /* Protect access to dbgfs_dir */
};
static const char * const plr_coarse_reasons[] = {
@@ -255,6 +257,30 @@ static ssize_t plr_status_write(struct file *filp, const char __user *ubuf,
}
DEFINE_SHOW_STORE_ATTRIBUTE(plr_status);
+static int intel_plr_notify(struct notifier_block *self, unsigned long action, void *data)
+{
+ struct tpmi_plr *plr = container_of(self, struct tpmi_plr, nb);
+
+ if (action == TPMI_CORE_EXIT) {
+ guard(mutex)(&plr->lock);
+ plr->dbgfs_dir = NULL;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static int intel_plr_register_notifier(struct notifier_block *nb)
+{
+ nb->notifier_call = intel_plr_notify;
+ nb->priority = 0;
+ return tpmi_register_notifier(nb);
+}
+
+static void intel_plr_unregister_notifier(struct notifier_block *nb)
+{
+ tpmi_unregister_notifier(nb);
+}
+
static int intel_plr_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id)
{
struct oobmsm_plat_info *plat_info;
@@ -282,10 +308,18 @@ static int intel_plr_probe(struct auxiliary_device *auxdev, const struct auxilia
if (!plr)
return -ENOMEM;
+ err = devm_mutex_init(&auxdev->dev, &plr->lock);
+ if (err)
+ return err;
+
+ intel_plr_register_notifier(&plr->nb);
+
plr->die_info = devm_kcalloc(&auxdev->dev, num_resources, sizeof(*plr->die_info),
GFP_KERNEL);
- if (!plr->die_info)
- return -ENOMEM;
+ if (!plr->die_info) {
+ err = -ENOMEM;
+ goto err_notify;
+ }
plr->num_dies = num_resources;
plr->dbgfs_dir = debugfs_create_dir("plr", dentry);
@@ -326,6 +360,9 @@ static int intel_plr_probe(struct auxiliary_device *auxdev, const struct auxilia
err:
debugfs_remove_recursive(plr->dbgfs_dir);
+err_notify:
+ intel_plr_unregister_notifier(&plr->nb);
+
return err;
}
@@ -333,6 +370,9 @@ static void intel_plr_remove(struct auxiliary_device *auxdev)
{
struct tpmi_plr *plr = auxiliary_get_drvdata(auxdev);
+ intel_plr_unregister_notifier(&plr->nb);
+
+ guard(mutex)(&plr->lock);
debugfs_remove_recursive(plr->dbgfs_dir);
}
diff --git a/drivers/platform/x86/intel/pmc/Kconfig b/drivers/platform/x86/intel/pmc/Kconfig
index c6ef0bcf76af..561d46634ab2 100644
--- a/drivers/platform/x86/intel/pmc/Kconfig
+++ b/drivers/platform/x86/intel/pmc/Kconfig
@@ -9,6 +9,7 @@ config INTEL_PMC_CORE
depends on ACPI
depends on INTEL_PMT_TELEMETRY
select INTEL_PMC_SSRAM_TELEMETRY
+ select INTEL_PMC_PWRM_TELEMETRY
help
The Intel Platform Controller Hub for Intel Core SoCs provides access
to Power Management Controller registers via various interfaces. This
@@ -28,3 +29,27 @@ config INTEL_PMC_CORE
config INTEL_PMC_SSRAM_TELEMETRY
tristate
+ help
+ This driver discovers PMC SSRAM telemetry regions through the PMC's
+ MMIO interface (PCI) or ACPI _DSD properties and registers them with
+ the Intel VSEC framework as Intel PMT telemetry devices.
+
+ It probes the PMC SSRAM device, extracts DVSEC information from MMIO,
+ reads device IDs and base addresses for multiple PMCs (main, IOE, PCH),
+ and exposes the discovered telemetry through Intel PMT interfaces
+ (including sysfs).
+
+ This option is selected by INTEL_PMC_CORE.
+
+config INTEL_PMC_PWRM_TELEMETRY
+ tristate
+ help
+ This driver discovers PMC PWRM telemetry regions described in ACPI
+ _DSD and registers them with the Intel VSEC framework as Intel PMT
+ telemetry devices.
+
+ It validates the ACPI discovery data and publishes the discovered
+ regions so they can be accessed through the Intel PMT telemetry
+ interfaces (including sysfs).
+
+ This option is selected by INTEL_PMC_CORE.
diff --git a/drivers/platform/x86/intel/pmc/Makefile b/drivers/platform/x86/intel/pmc/Makefile
index bb960c8721d7..5b595176f812 100644
--- a/drivers/platform/x86/intel/pmc/Makefile
+++ b/drivers/platform/x86/intel/pmc/Makefile
@@ -4,7 +4,8 @@
#
intel_pmc_core-y := core.o spt.o cnp.o icl.o \
- tgl.o adl.o mtl.o arl.o lnl.o ptl.o wcl.o
+ tgl.o adl.o mtl.o arl.o \
+ lnl.o ptl.o wcl.o nvl.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
@@ -12,3 +13,5 @@ obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core_pltdrv.o
# Intel PMC SSRAM driver
intel_pmc_ssram_telemetry-y += ssram_telemetry.o
obj-$(CONFIG_INTEL_PMC_SSRAM_TELEMETRY) += intel_pmc_ssram_telemetry.o
+intel_pmc_pwrm_telemetry-y += pwrm_telemetry.o
+obj-$(CONFIG_INTEL_PMC_PWRM_TELEMETRY) += intel_pmc_pwrm_telemetry.o
diff --git a/drivers/platform/x86/intel/pmc/arl.c b/drivers/platform/x86/intel/pmc/arl.c
index eb23bc68340a..11609d593383 100644
--- a/drivers/platform/x86/intel/pmc/arl.c
+++ b/drivers/platform/x86/intel/pmc/arl.c
@@ -672,6 +672,9 @@ static struct pmc_info arl_pmc_info_list[] = {
{}
};
+static const u8 arl_pmc_list[] = {PMC_IDX_MAIN, PMC_IDX_IOE, PMC_IDX_PCH};
+static const u8 arl_h_pmc_list[] = {PMC_IDX_MAIN, PMC_IDX_IOE};
+
#define ARL_NPU_PCI_DEV 0xad1d
#define ARL_GNA_PCI_DEV 0xae4c
#define ARL_H_NPU_PCI_DEV 0x7d1d
@@ -720,8 +723,9 @@ static int arl_h_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_
static u32 ARL_PMT_DMU_GUIDS[] = {ARL_PMT_DMU_GUID, 0x0};
struct pmc_dev_info arl_pmc_dev = {
- .pci_func = 0,
.dmu_guids = ARL_PMT_DMU_GUIDS,
+ .num_pmcs = ARRAY_SIZE(arl_pmc_list),
+ .pmc_list = arl_pmc_list,
.regmap_list = arl_pmc_info_list,
.map = &arl_socs_reg_map,
.sub_req_show = &pmc_core_substate_req_regs_fops,
@@ -729,12 +733,15 @@ struct pmc_dev_info arl_pmc_dev = {
.resume = arl_resume,
.init = arl_core_init,
.sub_req = pmc_core_pmt_get_lpm_req,
+ .ssram_hidden = true,
+ .die_c6_offset = MTL_PMT_DMU_DIE_C6_OFFSET,
};
static u32 ARL_H_PMT_DMU_GUIDS[] = {ARL_PMT_DMU_GUID, ARL_H_PMT_DMU_GUID, 0x0};
struct pmc_dev_info arl_h_pmc_dev = {
- .pci_func = 2,
.dmu_guids = ARL_H_PMT_DMU_GUIDS,
+ .num_pmcs = ARRAY_SIZE(arl_h_pmc_list),
+ .pmc_list = arl_h_pmc_list,
.regmap_list = arl_pmc_info_list,
.map = &mtl_socm_reg_map,
.sub_req_show = &pmc_core_substate_req_regs_fops,
@@ -742,4 +749,6 @@ struct pmc_dev_info arl_h_pmc_dev = {
.resume = arl_h_resume,
.init = arl_h_core_init,
.sub_req = pmc_core_pmt_get_lpm_req,
+ .ssram_hidden = true,
+ .die_c6_offset = MTL_PMT_DMU_DIE_C6_OFFSET,
};
diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c
index d91e1ab842d6..9f77c0716e59 100644
--- a/drivers/platform/x86/intel/pmc/core.c
+++ b/drivers/platform/x86/intel/pmc/core.c
@@ -623,7 +623,8 @@ static u32 convert_ltr_scale(u32 val)
* ----------------------------------------------
*/
if (val > 5) {
- pr_warn("Invalid LTR scale factor.\n");
+ pr_warn_once("Invalid LTR scale factor %u (only 0-5 are valid per PCIe spec)\n",
+ val);
return 0;
}
@@ -1071,6 +1072,44 @@ static int pmc_core_die_c6_us_show(struct seq_file *s, void *unused)
}
DEFINE_SHOW_ATTRIBUTE(pmc_core_die_c6_us);
+static int pmc_core_pkgc_counters_show(struct seq_file *s,
+ struct telem_endpoint *ep,
+ u32 offset, const char **counters)
+{
+ unsigned int i;
+ u32 counter;
+ int ret;
+
+ for (i = 0; counters[i]; i++) {
+ ret = pmt_telem_read32(ep, offset + i, &counter, 1);
+ if (ret)
+ return ret;
+ seq_printf(s, "%-30s %-30u\n", counters[i], counter);
+ }
+
+ return 0;
+}
+
+static int pmc_core_pkgc_ltr_blocker_show(struct seq_file *s, void *unused)
+{
+ struct pmc_dev *pmcdev = s->private;
+
+ return pmc_core_pkgc_counters_show(s, pmcdev->pc_ep,
+ pmcdev->pkgc_ltr_blocker_offset,
+ pmcdev->pkgc_ltr_blocker_counters);
+}
+DEFINE_SHOW_ATTRIBUTE(pmc_core_pkgc_ltr_blocker);
+
+static int pmc_core_pkgc_blocker_residency_show(struct seq_file *s, void *unused)
+{
+ struct pmc_dev *pmcdev = s->private;
+
+ return pmc_core_pkgc_counters_show(s, pmcdev->pc_ep,
+ pmcdev->pkgc_blocker_offset,
+ pmcdev->pkgc_blocker_counters);
+}
+DEFINE_SHOW_ATTRIBUTE(pmc_core_pkgc_blocker_residency);
+
static int pmc_core_lpm_latch_mode_show(struct seq_file *s, void *unused)
{
struct pmc_dev *pmcdev = s->private;
@@ -1322,28 +1361,45 @@ static struct telem_endpoint *pmc_core_register_endpoint(struct pci_dev *pcidev,
return ERR_PTR(-ENODEV);
}
-void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 *guids)
+void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
{
struct telem_endpoint *ep;
- struct pci_dev *pcidev;
- pcidev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(10, 0));
+ struct pci_dev *pcidev __free(pci_dev_put) = pci_get_domain_bus_and_slot(0, 0,
+ PCI_DEVFN(10, 0));
if (!pcidev) {
dev_err(&pmcdev->pdev->dev, "PUNIT PMT device not found.");
return;
}
- ep = pmc_core_register_endpoint(pcidev, guids);
- pci_dev_put(pcidev);
- if (IS_ERR(ep)) {
- dev_err(&pmcdev->pdev->dev,
- "pmc_core: couldn't get DMU telem endpoint %ld",
- PTR_ERR(ep));
- return;
+ if (pmc_dev_info->dmu_guids) {
+ ep = pmc_core_register_endpoint(pcidev, pmc_dev_info->dmu_guids);
+ if (IS_ERR(ep)) {
+ dev_err(&pmcdev->pdev->dev,
+ "pmc_core: couldn't get DMU telem endpoint %ld",
+ PTR_ERR(ep));
+ return;
+ }
+
+ pmcdev->punit_ep = ep;
+ pmcdev->die_c6_offset = pmc_dev_info->die_c6_offset;
}
- pmcdev->punit_ep = ep;
- pmcdev->die_c6_offset = MTL_PMT_DMU_DIE_C6_OFFSET;
+ if (pmc_dev_info->pc_guid) {
+ ep = pmt_telem_find_and_register_endpoint(&pcidev->dev, pmc_dev_info->pc_guid, 0);
+ if (IS_ERR(ep)) {
+ dev_err(&pmcdev->pdev->dev,
+ "pmc_core: couldn't get Package C-state telem endpoint %ld",
+ PTR_ERR(ep));
+ return;
+ }
+
+ pmcdev->pc_ep = ep;
+ pmcdev->pkgc_ltr_blocker_counters = pmc_dev_info->pkgc_ltr_blocker_counters;
+ pmcdev->pkgc_ltr_blocker_offset = pmc_dev_info->pkgc_ltr_blocker_offset;
+ pmcdev->pkgc_blocker_counters = pmc_dev_info->pkgc_blocker_counters;
+ pmcdev->pkgc_blocker_offset = pmc_dev_info->pkgc_blocker_offset;
+ }
}
void pmc_core_set_device_d3(unsigned int device)
@@ -1467,6 +1523,16 @@ static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev, struct pmc_dev_info
pmcdev->dbgfs_dir, pmcdev,
&pmc_core_die_c6_us_fops);
}
+
+ if (pmcdev->pc_ep) {
+ debugfs_create_file("pkgc_ltr_blocker_show", 0444,
+ pmcdev->dbgfs_dir, pmcdev,
+ &pmc_core_pkgc_ltr_blocker_fops);
+ debugfs_create_file("pkgc_blocker_residency_show", 0444,
+ pmcdev->dbgfs_dir, pmcdev,
+ &pmc_core_pkgc_blocker_residency_fops);
+ }
+
}
/*
@@ -1517,7 +1583,7 @@ int pmc_core_pmt_get_lpm_req(struct pmc_dev *pmcdev, struct pmc *pmc, struct tel
{
const u8 *lpm_indices;
int num_maps, mode_offset = 0;
- int ret, lpm_size;
+ int ret = 0, lpm_size;
u8 mode;
lpm_indices = pmc->map->lpm_reg_index;
@@ -1581,17 +1647,13 @@ int pmc_core_pmt_get_blk_sub_req(struct pmc_dev *pmcdev, struct pmc *pmc,
static int pmc_core_get_telem_info(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
{
- struct pci_dev *pcidev __free(pci_dev_put) = NULL;
struct telem_endpoint *ep;
unsigned int pmc_idx;
int ret;
- pcidev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(20, pmc_dev_info->pci_func));
- if (!pcidev)
- return -ENODEV;
-
for (pmc_idx = 0; pmc_idx < ARRAY_SIZE(pmcdev->pmcs); ++pmc_idx) {
struct pmc *pmc;
+ u16 devid;
pmc = pmcdev->pmcs[pmc_idx];
if (!pmc)
@@ -1600,6 +1662,16 @@ static int pmc_core_get_telem_info(struct pmc_dev *pmcdev, struct pmc_dev_info *
if (!pmc->map->lpm_req_guid)
return -ENXIO;
+ if (pmc_dev_info->ssram_hidden)
+ devid = pmcdev->pmcs[PMC_IDX_MAIN]->devid;
+ else
+ devid = pmc->devid;
+
+ struct pci_dev *pcidev __free(pci_dev_put) =
+ pci_get_device(PCI_VENDOR_ID_INTEL, devid, NULL);
+ if (!pcidev)
+ return -ENODEV;
+
ep = pmt_telem_find_and_register_endpoint(&pcidev->dev, pmc->map->lpm_req_guid, 0);
if (IS_ERR(ep)) {
dev_dbg(&pmcdev->pdev->dev, "couldn't get telem endpoint %pe", ep);
@@ -1650,6 +1722,7 @@ static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_idx)
pmc->map = map;
pmc->base_addr = pmc_ssram_telemetry.base_addr;
+ pmc->devid = pmc_ssram_telemetry.devid;
pmc->regbase = ioremap(pmc->base_addr, pmc->map->regmap_length);
if (!pmc->regbase) {
@@ -1662,16 +1735,17 @@ static int pmc_core_pmc_add(struct pmc_dev *pmcdev, unsigned int pmc_idx)
return 0;
}
-static int pmc_core_ssram_get_reg_base(struct pmc_dev *pmcdev)
+static int pmc_core_ssram_get_reg_base(struct pmc_dev *pmcdev, u8 num_pmcs, const u8 *pmc_list)
{
+ unsigned int i;
int ret;
- ret = pmc_core_pmc_add(pmcdev, PMC_IDX_MAIN);
- if (ret)
- return ret;
-
- pmc_core_pmc_add(pmcdev, PMC_IDX_IOE);
- pmc_core_pmc_add(pmcdev, PMC_IDX_PCH);
+ for (i = 0; i < num_pmcs; ++i) {
+ /* Non-MAIN PMCs are allowed to fail */
+ ret = pmc_core_pmc_add(pmcdev, pmc_list[i]);
+ if (ret && (pmc_list[i] == PMC_IDX_MAIN))
+ return ret;
+ }
return 0;
}
@@ -1693,7 +1767,9 @@ int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
ssram = pmc_dev_info->regmap_list != NULL;
if (ssram) {
pmcdev->regmap_list = pmc_dev_info->regmap_list;
- ret = pmc_core_ssram_get_reg_base(pmcdev);
+ ret = pmc_core_ssram_get_reg_base(pmcdev,
+ pmc_dev_info->num_pmcs,
+ pmc_dev_info->pmc_list);
/*
* EAGAIN error code indicates Intel PMC SSRAM Telemetry driver
* has not finished probe and PMC info is not available yet. Try
@@ -1717,8 +1793,8 @@ int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
}
pmc_core_get_low_power_modes(pmcdev);
- if (pmc_dev_info->dmu_guids)
- pmc_core_punit_pmt_init(pmcdev, pmc_dev_info->dmu_guids);
+ if (pmc_dev_info->dmu_guids || pmc_dev_info->pc_guid)
+ pmc_core_punit_pmt_init(pmcdev, pmc_dev_info);
if (ssram) {
ret = pmc_core_get_telem_info(pmcdev, pmc_dev_info);
@@ -1739,6 +1815,9 @@ unmap_regbase:
if (pmcdev->punit_ep)
pmt_telem_unregister_endpoint(pmcdev->punit_ep);
+ if (pmcdev->pc_ep)
+ pmt_telem_unregister_endpoint(pmcdev->pc_ep);
+
return ret;
}
@@ -1771,6 +1850,8 @@ static const struct x86_cpu_id intel_pmc_core_ids[] = {
X86_MATCH_VFM(INTEL_LUNARLAKE_M, &lnl_pmc_dev),
X86_MATCH_VFM(INTEL_PANTHERLAKE_L, &ptl_pmc_dev),
X86_MATCH_VFM(INTEL_WILDCATLAKE_L, &wcl_pmc_dev),
+ X86_MATCH_VFM(INTEL_NOVALAKE, &nvl_s_pmc_dev),
+ X86_MATCH_VFM(INTEL_NOVALAKE_L, &nvl_h_pmc_dev),
{}
};
@@ -1835,6 +1916,9 @@ static void pmc_core_clean_structure(struct platform_device *pdev)
if (pmcdev->punit_ep)
pmt_telem_unregister_endpoint(pmcdev->punit_ep);
+ if (pmcdev->pc_ep)
+ pmt_telem_unregister_endpoint(pmcdev->pc_ep);
+
platform_set_drvdata(pdev, NULL);
}
diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h
index 118c8740ad3a..b4c7399f8369 100644
--- a/drivers/platform/x86/intel/pmc/core.h
+++ b/drivers/platform/x86/intel/pmc/core.h
@@ -14,10 +14,15 @@
#include <linux/acpi.h>
#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/intel_vsec.h>
#include <linux/platform_device.h>
+#include <linux/uuid.h>
struct telem_endpoint;
+DEFINE_FREE(pmc_acpi_free, void *, if (_T) ACPI_FREE(_T))
+
#define SLP_S0_RES_COUNTER_MASK GENMASK(31, 0)
#define PMC_BASE_ADDR_DEFAULT 0xFE000000
@@ -46,7 +51,7 @@ struct telem_endpoint;
#define SPT_PMC_SLP_S0_RES_COUNTER_STEP 0x68
#define PMC_BASE_ADDR_MASK ~(SPT_PMC_MMIO_REG_LEN - 1)
#define MTPMC_MASK 0xffff0000
-#define PPFEAR_MAX_NUM_ENTRIES 12
+#define PPFEAR_MAX_NUM_ENTRIES 13
#define SPT_PPFEAR_NUM_ENTRIES 5
#define SPT_PMC_READ_DISABLE_BIT 0x16
#define SPT_PMC_MSG_FULL_STS_BIT 0x18
@@ -307,6 +312,29 @@ enum ppfear_regs {
#define WCL_NUM_S0IX_BLOCKER 94
#define WCL_BLK_REQ_OFFSET 50
+/* Nova Lake */
+#define NVL_PCDH_PPFEAR_NUM_ENTRIES 13
+#define NVL_PCDH_PMC_MMIO_REG_LEN 0x363c
+#define NVL_PCDS_PMC_MMIO_REG_LEN 0x3118
+#define NVL_PCHS_PMC_MMIO_REG_LEN 0x30d8
+#define NVL_LPM_PRI_OFFSET 0x17a4
+#define NVL_LPM_EN_OFFSET 0x17a0
+#define NVL_LPM_RESIDENCY_OFFSET 0x17a8
+#define NVL_LPM_LIVE_STATUS_OFFSET 0x1760
+#define NVL_LPM_NUM_MAPS 15
+#define NVL_PCDH_NUM_S0IX_BLOCKER 107
+#define NVL_PCDS_NUM_S0IX_BLOCKER 71
+#define NVL_PCHS_NUM_S0IX_BLOCKER 54
+#define NVL_PCDS_PMC_LTR_RESERVED 0x1bac
+#define NVL_PCDH_BLK_REQ_OFFSET 53
+#define NVL_PCDS_BLK_REQ_OFFSET 18
+#define NVL_PCHS_BLK_REQ_OFFSET 46
+#define NVL_PMT_PC_GUID 0x13000101
+#define NVL_PMT_DMU_GUID 0x1a000101
+#define NVL_LTR_BLK_OFFSET 64
+#define NVL_PKGC_BLK_OFFSET 4
+#define NVL_PMT_DMU_DIE_C6_OFFSET 25
+
/* SSRAM PMC Device ID */
/* LNL */
#define PMC_DEVID_LNL_SOCM 0xa87f
@@ -329,6 +357,11 @@ enum ppfear_regs {
#define PMC_DEVID_MTL_IOEP 0x7ecf
#define PMC_DEVID_MTL_IOEM 0x7ebf
+/* NVL */
+#define PMC_DEVID_NVL_PCDH 0xd37e
+#define PMC_DEVID_NVL_PCDS 0xd47e
+#define PMC_DEVID_NVL_PCHS 0x6e27
+
extern const char *pmc_lpm_modes[];
struct pmc_bit_map {
@@ -425,6 +458,7 @@ struct pmc_info {
* @ltr_ign: Holds LTR ignore data while suspended
* @num_lpm_modes: Count of enabled modes
* @lpm_en_modes: Array of enabled modes from lowest to highest priority
+ * @devid: Device ID of the SSRAM device
*
* pmc contains info about one power management controller device.
*/
@@ -436,6 +470,7 @@ struct pmc {
u32 ltr_ign;
u8 num_lpm_modes;
u8 lpm_en_modes[LPM_MAX_NUM_MODES];
+ u16 devid;
};
/**
@@ -453,6 +488,11 @@ struct pmc {
* @suspend: Function to perform platform specific suspend
* @resume: Function to perform platform specific resume
*
+ * @pkgc_ltr_blocker_counters: Array of PKGC LTR blocker counters
+ * @pkgc_ltr_blocker_offset: Offset to PKGC LTR blockers in telemetry region
+ * @pkgc_blocker_counters: Array of PKGC blocker counters
+ * @pkgc_blocker_offset: Offset to PKGC blocker in telemetry region
+ *
* pmc_dev contains info about power management controller device.
*/
struct pmc_dev {
@@ -471,8 +511,14 @@ struct pmc_dev {
u8 num_of_pkgc;
u32 die_c6_offset;
+ struct telem_endpoint *pc_ep;
struct telem_endpoint *punit_ep;
struct pmc_info *regmap_list;
+
+ const char **pkgc_ltr_blocker_counters;
+ u32 pkgc_ltr_blocker_offset;
+ const char **pkgc_blocker_counters;
+ u32 pkgc_blocker_offset;
};
enum pmc_index {
@@ -484,29 +530,45 @@ enum pmc_index {
/**
* struct pmc_dev_info - Structure to keep PMC device info
- * @pci_func: Function number of the primary PMC
* @dmu_guids: List of Die Management Unit GUID
+ * @pc_guid: GUID for telemetry region to read PKGC blocker info
+ * @pkgc_ltr_blocker_offset: Offset to PKGC LTR blockers in telemetry region
+ * @pkgc_blocker_offset:Offset to PKGC blocker in telemetry region
+ * @num_pmcs: Number of entries in @pmc_list
+ * @pmc_list: Index list of available PMC
* @regmap_list: Pointer to a list of pmc_info structure that could be
* available for the platform. When set, this field implies
* SSRAM support.
* @map: Pointer to a pmc_reg_map struct that contains platform
* specific attributes of the primary PMC
* @sub_req_show: File operations to show substate requirements
+ * @pkgc_ltr_blocker_counters: Array of PKGC LTR blocker counters
+ * @pkgc_blocker_counters: Array of PKGC blocker counters
* @suspend: Function to perform platform specific suspend
* @resume: Function to perform platform specific resume
* @init: Function to perform platform specific init action
* @sub_req: Function to achieve low power mode substate requirements
+ * @ssram_hidden: Some SSRAM devices are hidden on this platform
+ * @die_c6_offset: Telemetry offset to read Die C6 residency
*/
struct pmc_dev_info {
- u8 pci_func;
u32 *dmu_guids;
+ u32 pc_guid;
+ u32 pkgc_ltr_blocker_offset;
+ u32 pkgc_blocker_offset;
+ u8 num_pmcs;
+ const u8 *pmc_list;
struct pmc_info *regmap_list;
const struct pmc_reg_map *map;
const struct file_operations *sub_req_show;
+ const char **pkgc_ltr_blocker_counters;
+ const char **pkgc_blocker_counters;
void (*suspend)(struct pmc_dev *pmcdev);
int (*resume)(struct pmc_dev *pmcdev);
int (*init)(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info);
int (*sub_req)(struct pmc_dev *pmcdev, struct pmc *pmc, struct telem_endpoint *ep);
+ bool ssram_hidden;
+ u32 die_c6_offset;
};
extern const struct pmc_bit_map msr_map[];
@@ -529,13 +591,14 @@ extern const struct pmc_reg_map mtl_ioep_reg_map;
extern const struct pmc_bit_map ptl_pcdp_clocksource_status_map[];
extern const struct pmc_bit_map ptl_pcdp_vnn_req_status_3_map[];
extern const struct pmc_bit_map ptl_pcdp_signal_status_map[];
+extern const struct pmc_bit_map ptl_pcdp_ltr_show_map[];
void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev);
int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value, int ignore);
int pmc_core_resume_common(struct pmc_dev *pmcdev);
int get_primary_reg_base(struct pmc *pmc);
-void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, u32 *guids);
+void pmc_core_punit_pmt_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info);
void pmc_core_set_device_d3(unsigned int device);
int generic_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info);
@@ -552,6 +615,8 @@ extern struct pmc_dev_info arl_h_pmc_dev;
extern struct pmc_dev_info lnl_pmc_dev;
extern struct pmc_dev_info ptl_pmc_dev;
extern struct pmc_dev_info wcl_pmc_dev;
+extern struct pmc_dev_info nvl_s_pmc_dev;
+extern struct pmc_dev_info nvl_h_pmc_dev;
void cnl_suspend(struct pmc_dev *pmcdev);
int cnl_resume(struct pmc_dev *pmcdev);
@@ -562,6 +627,8 @@ int pmc_core_pmt_get_blk_sub_req(struct pmc_dev *pmcdev, struct pmc *pmc,
extern const struct file_operations pmc_core_substate_req_regs_fops;
extern const struct file_operations pmc_core_substate_blk_req_fops;
+extern const guid_t intel_vsec_guid;
+
#define pmc_for_each_mode(mode, pmc) \
for (unsigned int __i = 0, __cond; \
__cond = __i < (pmc)->num_lpm_modes, \
@@ -583,4 +650,13 @@ static const struct file_operations __name ## _fops = { \
.release = single_release, \
}
+struct intel_vsec_header;
+union acpi_object;
+
+/* Avoid checkpatch warning */
+typedef u32 (*acpi_disc_t)[PMT_DISC_DWORDS];
+
+acpi_disc_t pmc_parse_telem_dsd(union acpi_object *obj,
+ struct intel_vsec_header *header);
+union acpi_object *pmc_find_telem_guid(union acpi_object *dsd);
#endif /* PMC_CORE_H */
diff --git a/drivers/platform/x86/intel/pmc/lnl.c b/drivers/platform/x86/intel/pmc/lnl.c
index 1cd81ee54dcf..5ff4922825d9 100644
--- a/drivers/platform/x86/intel/pmc/lnl.c
+++ b/drivers/platform/x86/intel/pmc/lnl.c
@@ -544,6 +544,8 @@ static struct pmc_info lnl_pmc_info_list[] = {
{}
};
+static const u8 lnl_pmc_list[] = {PMC_IDX_MAIN};
+
#define LNL_NPU_PCI_DEV 0x643e
#define LNL_IPU_PCI_DEV 0x645d
@@ -571,7 +573,8 @@ static int lnl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_in
}
struct pmc_dev_info lnl_pmc_dev = {
- .pci_func = 2,
+ .num_pmcs = ARRAY_SIZE(lnl_pmc_list),
+ .pmc_list = lnl_pmc_list,
.regmap_list = lnl_pmc_info_list,
.map = &lnl_socm_reg_map,
.sub_req_show = &pmc_core_substate_req_regs_fops,
@@ -579,4 +582,5 @@ struct pmc_dev_info lnl_pmc_dev = {
.resume = lnl_resume,
.init = lnl_core_init,
.sub_req = pmc_core_pmt_get_lpm_req,
+ .ssram_hidden = true,
};
diff --git a/drivers/platform/x86/intel/pmc/mtl.c b/drivers/platform/x86/intel/pmc/mtl.c
index 57508cbf9cd4..9abeabd3dbe2 100644
--- a/drivers/platform/x86/intel/pmc/mtl.c
+++ b/drivers/platform/x86/intel/pmc/mtl.c
@@ -965,6 +965,8 @@ static struct pmc_info mtl_pmc_info_list[] = {
{}
};
+static const u8 mtl_pmc_list[] = {PMC_IDX_MAIN, PMC_IDX_IOE};
+
#define MTL_GNA_PCI_DEV 0x7e4c
#define MTL_IPU_PCI_DEV 0x7d19
#define MTL_VPU_PCI_DEV 0x7d1d
@@ -994,8 +996,9 @@ static int mtl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_in
static u32 MTL_PMT_DMU_GUIDS[] = {MTL_PMT_DMU_GUID, 0x0};
struct pmc_dev_info mtl_pmc_dev = {
- .pci_func = 2,
.dmu_guids = MTL_PMT_DMU_GUIDS,
+ .num_pmcs = ARRAY_SIZE(mtl_pmc_list),
+ .pmc_list = mtl_pmc_list,
.regmap_list = mtl_pmc_info_list,
.map = &mtl_socm_reg_map,
.sub_req_show = &pmc_core_substate_req_regs_fops,
@@ -1003,4 +1006,6 @@ struct pmc_dev_info mtl_pmc_dev = {
.resume = mtl_resume,
.init = mtl_core_init,
.sub_req = pmc_core_pmt_get_lpm_req,
+ .ssram_hidden = true,
+ .die_c6_offset = MTL_PMT_DMU_DIE_C6_OFFSET,
};
diff --git a/drivers/platform/x86/intel/pmc/nvl.c b/drivers/platform/x86/intel/pmc/nvl.c
new file mode 100644
index 000000000000..8dabf2511dd9
--- /dev/null
+++ b/drivers/platform/x86/intel/pmc/nvl.c
@@ -0,0 +1,1539 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file contains platform specific structure definitions
+ * and init function used by Nova Lake PCH.
+ *
+ * Copyright (c) 2026, Intel Corporation.
+ */
+
+#include <linux/bits.h>
+#include <linux/pci.h>
+
+#include "core.h"
+
+/* PMC SSRAM PMT Telemetry GUIDS */
+#define PCDH_LPM_REQ_GUID 0x01093101
+#define PCHS_LPM_REQ_GUID 0x01092101
+#define PCDS_LPM_REQ_GUID 0x01091102
+
+/*
+ * Die Mapping to Product.
+ * Product PCDDie PCHDie
+ * NVL-H PCD-H None
+ * NVL-S PCD-S PCH-S
+ */
+
+static const struct pmc_bit_map nvl_pcdh_pfear_map[] = {
+ {"PMC_PGD0", BIT(0)},
+ {"FUSE_OSSE_PGD0", BIT(1)},
+ {"SPI_PGD0", BIT(2)},
+ {"XHCI_PGD0", BIT(3)},
+ {"SPA_PGD0", BIT(4)},
+ {"SPB_PGD0", BIT(5)},
+ {"MPFPW2_PGD0", BIT(6)},
+ {"GBE_PGD0", BIT(7)},
+
+ {"SBR16B20_PGD0", BIT(0)},
+ {"DBG_SBR_PGD0", BIT(1)},
+ {"SBR16B7_PGD0", BIT(2)},
+ {"STRC_PGD0", BIT(3)},
+ {"SBR16B8_PGD0", BIT(4)},
+ {"D2D_DISP_PGD1", BIT(5)},
+ {"LPSS_PGD0", BIT(6)},
+ {"LPC_PGD0", BIT(7)},
+
+ {"SMB_PGD0", BIT(0)},
+ {"ISH_PGD0", BIT(1)},
+ {"SBR16B2_PGD0", BIT(2)},
+ {"NPK_PGD0", BIT(3)},
+ {"D2D_NOC_PGD1", BIT(4)},
+ {"DBG_SBR16B_PGD0", BIT(5)},
+ {"FUSE_PGD0", BIT(6)},
+ {"SBR16B0_PGD0", BIT(7)},
+
+ {"P2SB0_PGD0", BIT(0)},
+ {"OTG_PGD0", BIT(1)},
+ {"EXI_PGD0", BIT(2)},
+ {"CSE_PGD0", BIT(3)},
+ {"CSME_KVM_PGD0", BIT(4)},
+ {"CSME_PMT_PGD0", BIT(5)},
+ {"CSME_CLINK_PGD0", BIT(6)},
+ {"SBR16B21_PGD0", BIT(7)},
+
+ {"CSME_USBR_PGD0", BIT(0)},
+ {"SBR16B22_PGD0", BIT(1)},
+ {"CSME_SMT1_PGD0", BIT(2)},
+ {"MPFPW1_PGD0", BIT(3)},
+ {"CSME_SMS2_PGD0", BIT(4)},
+ {"CSME_SMS_PGD0", BIT(5)},
+ {"CSME_RTC_PGD0", BIT(6)},
+ {"CSMEPSF_PGD0", BIT(7)},
+
+ {"D2D_NOC_PGD0", BIT(0)},
+ {"ESE_PGD0", BIT(1)},
+ {"SBR16B6_PGD0", BIT(2)},
+ {"P2SB1_PGD0", BIT(3)},
+ {"SBR16B3_PGD0", BIT(4)},
+ {"OSSE_SMT1_PGD0", BIT(5)},
+ {"D2D_DISP_PGD0", BIT(6)},
+ {"SNPS_USB2_A_PGD0", BIT(7)},
+
+ {"U3FPW1_PGD0", BIT(0)},
+ {"FIA_X_PGD0", BIT(1)},
+ {"PSF4_PGD0", BIT(2)},
+ {"CNVI_PGD0", BIT(3)},
+ {"UFSX2_PGD0", BIT(4)},
+ {"ENDBG_PGD0", BIT(5)},
+ {"DBC_PGD0", BIT(6)},
+ {"FIA_PG_PGD0", BIT(7)},
+
+ {"D2D_IPU_PGD0", BIT(0)},
+ {"NPK_PGD1", BIT(1)},
+ {"FIACPCB_X_PGD0", BIT(2)},
+ {"SBR8B4_PGD0", BIT(3)},
+ {"DBG_PSF_PGD0", BIT(4)},
+ {"PSF6_PGD0", BIT(5)},
+ {"UFSPW1_PGD0", BIT(6)},
+ {"FIA_U_PGD0", BIT(7)},
+
+ {"PSF8_PGD0", BIT(0)},
+ {"SBR16B9_PGD0", BIT(1)},
+ {"PSF0_PGD0", BIT(2)},
+ {"FIACPCB_U_PGD0", BIT(3)},
+ {"TAM_PGD0", BIT(4)},
+ {"D2D_NOC_PGD2", BIT(5)},
+ {"SBR8B2_PGD0", BIT(6)},
+ {"THC0_PGD0", BIT(7)},
+
+ {"THC1_PGD0", BIT(0)},
+ {"PMC_PGD1", BIT(1)},
+ {"DISP_PGA1_PGD0", BIT(2)},
+ {"TCSS_PGD0", BIT(3)},
+ {"DISP_PGA_PGD0", BIT(4)},
+ {"SBR16B1_PGD0", BIT(5)},
+ {"SBRG_PGD0", BIT(6)},
+ {"PSF5_PGD0", BIT(7)},
+
+ {"SBR8B3_PGD0", BIT(0)},
+ {"ACE_PGD0", BIT(1)},
+ {"ACE_PGD1", BIT(2)},
+ {"ACE_PGD2", BIT(3)},
+ {"ACE_PGD3", BIT(4)},
+ {"ACE_PGD4", BIT(5)},
+ {"ACE_PGD5", BIT(6)},
+ {"ACE_PGD6", BIT(7)},
+
+ {"ACE_PGD7", BIT(0)},
+ {"ACE_PGD8", BIT(1)},
+ {"ACE_PGD9", BIT(2)},
+ {"ACE_PGD10", BIT(3)},
+ {"FIACPCB_PG_PGD0", BIT(4)},
+ {"SNPS_USB2_B_PGD0", BIT(5)},
+ {"OSSE_PGD0", BIT(6)},
+ {"SBR8B0_PGD0", BIT(7)},
+
+ {"SBR16B4_PGD0", BIT(0)},
+ {"CSME_PTIO_PGD0", BIT(1)},
+ {}
+};
+
+static const struct pmc_bit_map *ext_nvl_pcdh_pfear_map[] = {
+ nvl_pcdh_pfear_map,
+ NULL
+};
+
+static const struct pmc_bit_map nvl_pcdh_clocksource_status_map[] = {
+ {"AON2_OFF_STS", BIT(0), 1},
+ {"AON3_OFF_STS", BIT(1), 0},
+ {"AON4_OFF_STS", BIT(2), 1},
+ {"AON5_OFF_STS", BIT(3), 1},
+ {"AON1_OFF_STS", BIT(4), 0},
+ {"XTAL_LVM_OFF_STS", BIT(5), 0},
+ {"MPFPW1_0_PLL_OFF_STS", BIT(6), 1},
+ {"D2D_PLL_OFF_STS", BIT(7), 1},
+ {"USB3_PLL_OFF_STS", BIT(8), 1},
+ {"AON3_SPL_OFF_STS", BIT(9), 1},
+ {"MPFPW2_0_PLL_OFF_STS", BIT(12), 1},
+ {"XTAL_AGGR_OFF_STS", BIT(17), 1},
+ {"USB2_PLL_OFF_STS", BIT(18), 0},
+ {"DDI2_PLL_OFF_STS", BIT(19), 1},
+ {"SE_TCSS_PLL_OFF_STS", BIT(20), 1},
+ {"DDI_PLL_OFF_STS", BIT(21), 1},
+ {"FILTER_PLL_OFF_STS", BIT(22), 1},
+ {"ACE_PLL_OFF_STS", BIT(24), 0},
+ {"FABRIC_PLL_OFF_STS", BIT(25), 1},
+ {"SOC_PLL_OFF_STS", BIT(26), 1},
+ {"REF_PLL_OFF_STS", BIT(28), 1},
+ {"IMG_PLL_OFF_STS", BIT(29), 1},
+ {"GENLOCK_FILTER_PLL_OFF_STS", BIT(30), 1},
+ {"RTC_PLL_OFF_STS", BIT(31), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcdh_power_gating_status_0_map[] = {
+ {"PMC_PGD0_PG_STS", BIT(0), 0},
+ {"FUSE_OSSE_PGD0_PG_STS", BIT(1), 0},
+ {"ESPISPI_PGD0_PG_STS", BIT(2), 0},
+ {"XHCI_PGD0_PG_STS", BIT(3), 1},
+ {"SPA_PGD0_PG_STS", BIT(4), 1},
+ {"SPB_PGD0_PG_STS", BIT(5), 1},
+ {"MPFPW2_PGD0_PG_STS", BIT(6), 0},
+ {"GBE_PGD0_PG_STS", BIT(7), 1},
+ {"SBR16B20_PGD0_PG_STS", BIT(8), 0},
+ {"DBG_PGD0_PG_STS", BIT(9), 0},
+ {"SBR16B7_PGD0_PG_STS", BIT(10), 0},
+ {"STRC_PGD0_PG_STS", BIT(11), 0},
+ {"SBR16B8_PGD0_PG_STS", BIT(12), 0},
+ {"D2D_DISP_PGD1_PG_STS", BIT(13), 1},
+ {"LPSS_PGD0_PG_STS", BIT(14), 1},
+ {"LPC_PGD0_PG_STS", BIT(15), 0},
+ {"SMB_PGD0_PG_STS", BIT(16), 0},
+ {"ISH_PGD0_PG_STS", BIT(17), 0},
+ {"SBR16B2_PGD0_PG_STS", BIT(18), 0},
+ {"NPK_PGD0_PG_STS", BIT(19), 0},
+ {"D2D_NOC_PGD1_PG_STS", BIT(20), 1},
+ {"DBG_SBR16B_PGD0_PG_STS", BIT(21), 0},
+ {"FUSE_PGD0_PG_STS", BIT(22), 0},
+ {"SBR16B0_PGD0_PG_STS", BIT(23), 0},
+ {"P2SB0_PGD0_PG_STS", BIT(24), 1},
+ {"XDCI_PGD0_PG_STS", BIT(25), 1},
+ {"EXI_PGD0_PG_STS", BIT(26), 0},
+ {"CSE_PGD0_PG_STS", BIT(27), 1},
+ {"KVMCC_PGD0_PG_STS", BIT(28), 1},
+ {"PMT_PGD0_PG_STS", BIT(29), 1},
+ {"CLINK_PGD0_PG_STS", BIT(30), 1},
+ {"SBR16B21_PGD0_PG_STS", BIT(31), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcdh_power_gating_status_1_map[] = {
+ {"USBR0_PGD0_PG_STS", BIT(0), 1},
+ {"SBR16B22_PGD0_PG_STS", BIT(1), 0},
+ {"SMT1_PGD0_PG_STS", BIT(2), 1},
+ {"MPFPW1_PGD0_PG_STS", BIT(3), 0},
+ {"SMS2_PGD0_PG_STS", BIT(4), 1},
+ {"SMS1_PGD0_PG_STS", BIT(5), 1},
+ {"CSMERTC_PGD0_PG_STS", BIT(6), 0},
+ {"CSMEPSF_PGD0_PG_STS", BIT(7), 0},
+ {"D2D_NOC_PGD0_PG_STS", BIT(8), 0},
+ {"ESE_PGD0_PG_STS", BIT(9), 1},
+ {"SBR16B6_PGD0_PG_STS", BIT(10), 0},
+ {"P2SB1_PGD0_PG_STS", BIT(11), 1},
+ {"SBR16B3_PGD0_PG_STS", BIT(12), 0},
+ {"OSSE_SMT1_PGD0_PG_STS", BIT(13), 1},
+ {"D2D_DISP_PGD0_PG_STS", BIT(14), 1},
+ {"SNPA_USB2_A_PGD0_PG_STS", BIT(15), 0},
+ {"U3FPW1_PGD0_PG_STS", BIT(16), 0},
+ {"FIA_X_PGD0_PG_STS", BIT(17), 0},
+ {"PSF4_PGD0_PG_STS", BIT(18), 0},
+ {"CNVI_PGD0_PG_STS", BIT(19), 0},
+ {"UFSX2_PGD0_PG_STS", BIT(20), 1},
+ {"ENDBG_PGD0_PG_STS", BIT(21), 0},
+ {"DBC_PGD0_PG_STS", BIT(22), 0},
+ {"FIA_PG_PGD0_PG_STS", BIT(23), 0},
+ {"D2D_IPU_PGD0_PG_STS", BIT(24), 1},
+ {"NPK_PGD1_PG_STS", BIT(25), 0},
+ {"FIACPCB_X_PGD0_PG_STS", BIT(26), 0},
+ {"SBR8B4_PGD0_PG_STS", BIT(27), 0},
+ {"DBG_PSF_PGD0_PG_STS", BIT(28), 0},
+ {"PSF6_PGD0_PG_STS", BIT(29), 0},
+ {"UFSPW1_PGD0_PG_STS", BIT(30), 0},
+ {"FIA_U_PGD0_PG_STS", BIT(31), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcdh_power_gating_status_2_map[] = {
+ {"PSF8_PGD0_PG_STS", BIT(0), 0},
+ {"SBR16B9_PGD0_PG_STS", BIT(1), 0},
+ {"PSF0_PGD0_PG_STS", BIT(2), 0},
+ {"FIACPCB_U_PGD0_PG_STS", BIT(3), 0},
+ {"TAM_PGD0_PG_STS", BIT(4), 1},
+ {"D2D_NOC_PGD2_PG_STS", BIT(5), 1},
+ {"SBR8B2_PGD0_PG_STS", BIT(6), 0},
+ {"THC0_PGD0_PG_STS", BIT(7), 1},
+ {"THC1_PGD0_PG_STS", BIT(8), 1},
+ {"PMC_PGD1_PG_STS", BIT(9), 0},
+ {"DISP_PGA1_PGD0_PG_STS", BIT(10), 0},
+ {"TCSS_PGD0_PG_STS", BIT(11), 0},
+ {"DISP_PGA_PGD0_PG_STS", BIT(12), 0},
+ {"SBR16B1_PGD0_PG_STS", BIT(13), 0},
+ {"SBRG_PGD0_PG_STS", BIT(14), 0},
+ {"PSF5_PGD0_PG_STS", BIT(15), 0},
+ {"SBR8B3_PGD0_PG_STS", BIT(16), 0},
+ {"ACE_PGD0_PG_STS", BIT(17), 0},
+ {"ACE_PGD1_PG_STS", BIT(18), 0},
+ {"ACE_PGD2_PG_STS", BIT(19), 0},
+ {"ACE_PGD3_PG_STS", BIT(20), 0},
+ {"ACE_PGD4_PG_STS", BIT(21), 0},
+ {"ACE_PGD5_PG_STS", BIT(22), 0},
+ {"ACE_PGD6_PG_STS", BIT(23), 0},
+ {"ACE_PGD7_PG_STS", BIT(24), 0},
+ {"ACE_PGD8_PG_STS", BIT(25), 0},
+ {"ACE_PGD9_PG_STS", BIT(26), 0},
+ {"ACE_PGD10_PG_STS", BIT(27), 0},
+ {"FIACPCB_PG_PGD0_PG_STS", BIT(28), 0},
+ {"SNPS_USB2_B_PGD0_PG_STS", BIT(29), 0},
+ {"OSSE_PGD0_PG_STS", BIT(30), 1},
+ {"SBR8B0_PGD0_PG_STS", BIT(31), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcdh_power_gating_status_3_map[] = {
+ {"SBR16B4_PGD0_PG_STS", BIT(0), 0},
+ {"PTIO_PGD0_PG_STS", BIT(1), 1},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcdh_d3_status_0_map[] = {
+ {"LPSS_D3_STS", BIT(3), 1},
+ {"XDCI_D3_STS", BIT(4), 1},
+ {"XHCI_D3_STS", BIT(5), 1},
+ {"OSSE_D3_STS", BIT(6), 0},
+ {"SPA_D3_STS", BIT(12), 0},
+ {"SPB_D3_STS", BIT(13), 0},
+ {"ESPISPI_D3_STS", BIT(18), 0},
+ {"PSTH_D3_STS", BIT(21), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcdh_d3_status_1_map[] = {
+ {"OSSE_SMT1_D3_STS", BIT(0), 0},
+ {"GBE_D3_STS", BIT(19), 0},
+ {"ITSS_D3_STS", BIT(23), 0},
+ {"CNVI_D3_STS", BIT(27), 0},
+ {"UFSX2_D3_STS", BIT(28), 0},
+ {"ESE_D3_STS", BIT(29), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcdh_d3_status_2_map[] = {
+ {"CSMERTC_D3_STS", BIT(1), 0},
+ {"CSE_D3_STS", BIT(4), 0},
+ {"KVMCC_D3_STS", BIT(5), 0},
+ {"USBR0_D3_STS", BIT(6), 0},
+ {"ISH_D3_STS", BIT(7), 0},
+ {"SMT1_D3_STS", BIT(8), 0},
+ {"SMT2_D3_STS", BIT(9), 0},
+ {"SMT3_D3_STS", BIT(10), 0},
+ {"OSSE_SMT2_D3_STS", BIT(11), 0},
+ {"CLINK_D3_STS", BIT(14), 0},
+ {"PTIO_D3_STS", BIT(16), 0},
+ {"PMT_D3_STS", BIT(17), 0},
+ {"SMS1_D3_STS", BIT(18), 0},
+ {"SMS2_D3_STS", BIT(19), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcdh_d3_status_3_map[] = {
+ {"THC0_D3_STS", BIT(14), 1},
+ {"THC1_D3_STS", BIT(15), 1},
+ {"OSSE_SMT3_D3_STS", BIT(16), 0},
+ {"ACE_D3_STS", BIT(23), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcdh_vnn_req_status_0_map[] = {
+ {"LPSS_VNN_REQ_STS", BIT(3), 1},
+ {"OSSE_VNN_REQ_STS", BIT(6), 1},
+ {"ESPISPI_VNN_REQ_STS", BIT(18), 1},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcdh_vnn_req_status_1_map[] = {
+ {"OSSE_SMT1_VNN_REQ_STS", BIT(0), 1},
+ {"NPK_VNN_REQ_STS", BIT(4), 1},
+ {"DFXAGG_VNN_REQ_STS", BIT(8), 0},
+ {"EXI_VNN_REQ_STS", BIT(9), 1},
+ {"P2D_VNN_REQ_STS", BIT(18), 1},
+ {"GBE_VNN_REQ_STS", BIT(19), 1},
+ {"SMB_VNN_REQ_STS", BIT(25), 1},
+ {"LPC_VNN_REQ_STS", BIT(26), 0},
+ {"ESE_VNN_REQ_STS", BIT(29), 1},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcdh_vnn_req_status_2_map[] = {
+ {"CSMERTC_VNN_REQ_STS", BIT(1), 1},
+ {"CSE_VNN_REQ_STS", BIT(4), 1},
+ {"ISH_VNN_REQ_STS", BIT(7), 1},
+ {"SMT1_VNN_REQ_STS", BIT(8), 1},
+ {"CLINK_VNN_REQ_STS", BIT(14), 1},
+ {"SMS1_VNN_REQ_STS", BIT(18), 1},
+ {"SMS2_VNN_REQ_STS", BIT(19), 1},
+ {"GPIOCOM4_VNN_REQ_STS", BIT(20), 1},
+ {"GPIOCOM3_VNN_REQ_STS", BIT(21), 1},
+ {"DISP_SHIM_VNN_REQ_STS", BIT(22), 1},
+ {"GPIOCOM1_VNN_REQ_STS", BIT(23), 1},
+ {"GPIOCOM0_VNN_REQ_STS", BIT(24), 1},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcdh_vnn_req_status_3_map[] = {
+ {"DTS0_VNN_REQ_STS", BIT(7), 0},
+ {"GPIOCOM5_VNN_REQ_STS", BIT(11), 1},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcdh_vnn_misc_status_map[] = {
+ {"CPU_C10_REQ_STS", BIT(0), 0},
+ {"TS_OFF_REQ_STS", BIT(1), 0},
+ {"PNDE_MET_REQ_STS", BIT(2), 1},
+ {"PG5_PMA0_REQ_STS", BIT(3), 1},
+ {"FW_THROTTLE_ALLOWED_REQ_STS", BIT(4), 0},
+ {"VNN_SOC_REQ_STS", BIT(6), 1},
+ {"ISH_VNNAON_REQ_STS", BIT(7), 0},
+ {"D2D_NOC_CFI_QACTIVE_REQ_STS", BIT(8), 1},
+ {"D2D_NOC_GPSB_QACTIVE_REQ_STS", BIT(9), 1},
+ {"D2D_IPU_QACTIVE_REQ_STS", BIT(10), 1},
+ {"PLT_GREATER_REQ_STS", BIT(11), 1},
+ {"ALL_SBR_IDLE_REQ_STS", BIT(12), 0},
+ {"PMC_IDLE_FB_OCP_REQ_STS", BIT(13), 0},
+ {"PM_SYNC_STATES_REQ_STS", BIT(14), 0},
+ {"EA_REQ_STS", BIT(15), 0},
+ {"MPHY_CORE_OFF_REQ_STS", BIT(16), 0},
+ {"BRK_EV_EN_REQ_STS", BIT(17), 0},
+ {"AUTO_DEMO_EN_REQ_STS", BIT(18), 0},
+ {"ITSS_CLK_SRC_REQ_STS", BIT(19), 1},
+ {"ARC_IDLE_REQ_STS", BIT(21), 0},
+ {"PG5_PMA1_REQ_STS", BIT(22), 1},
+ {"FIA_DEEP_PM_REQ_STS", BIT(23), 0},
+ {"XDCI_ATTACHED_REQ_STS", BIT(24), 1},
+ {"ARC_INTERRUPT_WAKE_REQ_STS", BIT(25), 0},
+ {"D2D_DISP_DDI_QACTIVE_REQ_STS", BIT(26), 1},
+ {"PRE_WAKE0_REQ_STS", BIT(27), 1},
+ {"PRE_WAKE1_REQ_STS", BIT(28), 1},
+ {"PRE_WAKE2_REQ_STS", BIT(29), 1},
+ {"PG5_PMA2_GVNN", BIT(30), 1},
+ {"D2D_DISP_EDP_QACTIVE_REQ_STS", BIT(31), 1},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcdh_rsc_status_map[] = {
+ {"CORE", 0, 1},
+ {"Memory", 0, 1},
+ {"PRIM_D2D", 0, 1},
+ {"PSF0", 0, 1},
+ {"PSF4", 0, 1},
+ {"PSF6", 0, 1},
+ {"PSF8", 0, 1},
+ {"SB", 0, 1},
+ {}
+};
+
+static const struct pmc_bit_map *nvl_pcdh_lpm_maps[] = {
+ nvl_pcdh_clocksource_status_map,
+ nvl_pcdh_power_gating_status_0_map,
+ nvl_pcdh_power_gating_status_1_map,
+ nvl_pcdh_power_gating_status_2_map,
+ nvl_pcdh_power_gating_status_3_map,
+ nvl_pcdh_d3_status_0_map,
+ nvl_pcdh_d3_status_1_map,
+ nvl_pcdh_d3_status_2_map,
+ nvl_pcdh_d3_status_3_map,
+ nvl_pcdh_vnn_req_status_0_map,
+ nvl_pcdh_vnn_req_status_1_map,
+ nvl_pcdh_vnn_req_status_2_map,
+ nvl_pcdh_vnn_req_status_3_map,
+ nvl_pcdh_vnn_misc_status_map,
+ ptl_pcdp_signal_status_map,
+ NULL
+};
+
+static const struct pmc_bit_map *nvl_pcdh_blk_maps[] = {
+ nvl_pcdh_power_gating_status_0_map,
+ nvl_pcdh_power_gating_status_1_map,
+ nvl_pcdh_power_gating_status_2_map,
+ nvl_pcdh_power_gating_status_3_map,
+ nvl_pcdh_rsc_status_map,
+ nvl_pcdh_vnn_req_status_0_map,
+ nvl_pcdh_vnn_req_status_1_map,
+ nvl_pcdh_vnn_req_status_2_map,
+ nvl_pcdh_vnn_req_status_3_map,
+ nvl_pcdh_d3_status_0_map,
+ nvl_pcdh_d3_status_1_map,
+ nvl_pcdh_d3_status_2_map,
+ nvl_pcdh_d3_status_3_map,
+ nvl_pcdh_clocksource_status_map,
+ nvl_pcdh_vnn_misc_status_map,
+ ptl_pcdp_signal_status_map,
+ NULL
+};
+
+static const struct pmc_bit_map nvl_pcds_pfear_map[] = {
+ {"PMC_PGD0", BIT(0)},
+ {"FUSE_OSSE_PGD0", BIT(1)},
+ {"SPI_PGD0", BIT(2)},
+ {"XHCI_PGD0", BIT(3)},
+ {"SPA_PGD0", BIT(4)},
+ {"SPB_PGD0", BIT(5)},
+ {"RSVD6", BIT(6)},
+ {"GBE_PGD0", BIT(7)},
+
+ {"RSVD8", BIT(0)},
+ {"RSVD9", BIT(1)},
+ {"SBR16B7_PGD0", BIT(2)},
+ {"SBR16B21_PGD0", BIT(3)},
+ {"RSVD12", BIT(4)},
+ {"D2D_DISP_PGD1", BIT(5)},
+ {"LPSS_PGD0", BIT(6)},
+ {"LPC_PGD0", BIT(7)},
+
+ {"SMB_PGD0", BIT(0)},
+ {"ISH_PGD0", BIT(1)},
+ {"SBR16B1_PGD0", BIT(2)},
+ {"NPK_PGD0", BIT(3)},
+ {"D2D_NOC_PGD1", BIT(4)},
+ {"DBG_SBR16B_PGD0", BIT(5)},
+ {"FUSE_PGD0", BIT(6)},
+ {"RSVD23", BIT(7)},
+
+ {"P2SB0_PGD0", BIT(0)},
+ {"OTG_PGD0", BIT(1)},
+ {"EXI_PGD0", BIT(2)},
+ {"CSE_PGD0", BIT(3)},
+ {"CSME_KVM_PGD0", BIT(4)},
+ {"CSME_PMT_PGD0", BIT(5)},
+ {"CSME_CLINK_PGD0", BIT(6)},
+ {"CSME_PTIO_PGD0", BIT(7)},
+
+ {"CSME_USBR_PGD0", BIT(0)},
+ {"SBR16B22_PGD0", BIT(1)},
+ {"CSME_SMT1_PGD0", BIT(2)},
+ {"P2SB1_PGD0", BIT(3)},
+ {"CSME_SMS2_PGD0", BIT(4)},
+ {"CSME_SMS_PGD0", BIT(5)},
+ {"CSME_RTC_PGD0", BIT(6)},
+ {"CSMEPSF_PGD0", BIT(7)},
+
+ {"D2D_NOC_PGD0", BIT(0)},
+ {"RSVD41", BIT(1)},
+ {"RSVD42", BIT(2)},
+ {"RSVD43", BIT(3)},
+ {"SBR16B2_PGD0", BIT(4)},
+ {"OSSE_SMT1_PGD0", BIT(5)},
+ {"D2D_DISP_PGD0", BIT(6)},
+ {"RSVD47_PGD0", BIT(7)},
+
+ {"RSVD48", BIT(0)},
+ {"DBG_PSF_PGD0", BIT(1)},
+ {"RSVD50", BIT(2)},
+ {"CNVI_PGD0", BIT(3)},
+ {"UFSX2_PGD0", BIT(4)},
+ {"ENDBG_PGD0", BIT(5)},
+ {"DBC_PGD0", BIT(6)},
+ {"SBR16B4_PGD0", BIT(7)},
+
+ {"RSVD56", BIT(0)},
+ {"NPK_PGD1", BIT(1)},
+ {"RSVD58", BIT(2)},
+ {"SBR16B20_PGD0", BIT(3)},
+ {"RSVD60", BIT(4)},
+ {"SBR8B20_PGD0", BIT(5)},
+ {"RSVD62", BIT(6)},
+ {"FIA_U_PGD0", BIT(7)},
+
+ {"PSF8_PGD0", BIT(0)},
+ {"RSVD65", BIT(1)},
+ {"RSVD66", BIT(2)},
+ {"FIACPCB_U_PGD0", BIT(3)},
+ {"TAM_PGD0", BIT(4)},
+ {"D2D_NOC_PGD2", BIT(5)},
+ {"SBR8B2_PGD0", BIT(6)},
+ {"THC0_PGD0", BIT(7)},
+
+ {"THC1_PGD0", BIT(0)},
+ {"PMC_PGD1", BIT(1)},
+ {"SBR16B3_PGD0", BIT(2)},
+ {"TCSS_PGD0", BIT(3)},
+ {"DISP_PGA_PGD0", BIT(4)},
+ {"RSVD77", BIT(5)},
+ {"RSVD78", BIT(6)},
+ {"RSVD79", BIT(7)},
+
+ {"SBRG_PGD0", BIT(0)},
+ {"RSVD81", BIT(1)},
+ {"SBR16B0_PGD0", BIT(2)},
+ {"SBR8B0_PGD0", BIT(3)},
+ {"PSF7_PGD0", BIT(4)},
+ {"RSVD85", BIT(5)},
+ {"RSVD86", BIT(6)},
+ {"RSVD87", BIT(7)},
+
+ {"SBR16B6_PGD0", BIT(0)},
+ {"PSD0_PGD0", BIT(1)},
+ {"STRC_PGD0", BIT(2)},
+ {"RSVD91", BIT(3)},
+ {"DBG_SBR_PGD0", BIT(4)},
+ {"RSVD93", BIT(5)},
+ {"OSSE_PGD0", BIT(6)},
+ {"DISP_PGA1_PGD0", BIT(7)},
+ {}
+};
+
+static const struct pmc_bit_map *ext_nvl_pcds_pfear_map[] = {
+ nvl_pcds_pfear_map,
+ NULL
+};
+
+static const struct pmc_bit_map nvl_pcds_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},
+ {"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", PTL_PMC_LTR_SATA2},
+ {"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},
+ {"WIGIG", ICL_PMC_LTR_WIGIG},
+ {"THC0", TGL_PMC_LTR_THC0},
+ {"THC1", TGL_PMC_LTR_THC1},
+ {"SOUTHPORT_G", MTL_PMC_LTR_SPG},
+ {"RSVD", NVL_PCDS_PMC_LTR_RESERVED},
+ {"IOE_PMC", MTL_PMC_LTR_IOE_PMC},
+ {"DMI3", ARL_PMC_LTR_DMI3},
+ {"OSSE", LNL_PMC_LTR_OSSE},
+
+ /* Below two cannot be used for LTR_IGNORE */
+ {"CURRENT_PLATFORM", PTL_PMC_LTR_CUR_PLT},
+ {"AGGREGATED_SYSTEM", PTL_PMC_LTR_CUR_ASLT},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcds_clocksource_status_map[] = {
+ {"AON2_OFF_STS", BIT(0), 1},
+ {"AON3_OFF_STS", BIT(1), 0},
+ {"AON4_OFF_STS", BIT(2), 1},
+ {"AON5_OFF_STS", BIT(3), 1},
+ {"AON1_OFF_STS", BIT(4), 0},
+ {"XTAL_LVM_OFF_STS", BIT(5), 0},
+ {"D2D_OFF_STS", BIT(8), 1},
+ {"AON3_SPL_OFF_STS", BIT(9), 1},
+ {"XTAL_AGGR_OFF_STS", BIT(17), 1},
+ {"BCLK_EXT_INJ_OFF_STS", BIT(18), 1},
+ {"DDI2_PLL_OFF_STS", BIT(19), 1},
+ {"SE_TCSS_PLL_OFF_STS", BIT(20), 1},
+ {"DDI_PLL_OFF_STS", BIT(21), 1},
+ {"FILTER_PLL_OFF_STS", BIT(22), 1},
+ {"PHY_OC_EXT_INJ_OFF_STS", BIT(23), 1},
+ {"ACE_PLL_OFF_STS", BIT(24), 0},
+ {"FABRIC_PLL_OFF_STS", BIT(25), 1},
+ {"SOC_PLL_OFF_STS", BIT(26), 1},
+ {"REF_PLL_OFF_STS", BIT(28), 1},
+ {"GENLOCK_FILTER_PLL_OFF_STS", BIT(30), 1},
+ {"RTC_PLL_OFF_STS", BIT(31), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcds_power_gating_status_0_map[] = {
+ {"PMC_PGD0_PG_STS", BIT(0), 0},
+ {"FUSE_OSSE_PGD0_PG_STS", BIT(1), 0},
+ {"ESPISPI_PGD0_PG_STS", BIT(2), 0},
+ {"XHCI_PGD0_PG_STS", BIT(3), 0},
+ {"SPA_PGD0_PG_STS", BIT(4), 0},
+ {"SPB_PGD0_PG_STS", BIT(5), 0},
+ {"RSVD_6", BIT(6), 0},
+ {"GBE_PGD0_PG_STS", BIT(7), 0},
+ {"RSVD_8", BIT(8), 0},
+ {"RSVD_9", BIT(9), 0},
+ {"SBR16B7_PGD0_PG_STS", BIT(10), 0},
+ {"SBR16B21_PGD0_PG_STS", BIT(11), 0},
+ {"RSVD_12", BIT(12), 0},
+ {"D2D_DISP_PGD1_PG_STS", BIT(13), 1},
+ {"LPSS_PGD0_PG_STS", BIT(14), 0},
+ {"LPC_PGD0_PG_STS", BIT(15), 0},
+ {"SMB_PGD0_PG_STS", BIT(16), 0},
+ {"ISH_PGD0_PG_STS", BIT(17), 0},
+ {"SBR16B1_PGD0_PG_STS", BIT(18), 0},
+ {"NPK_PGD0_PG_STS", BIT(19), 0},
+ {"D2D_NOC_PGD1_PG_STS", BIT(20), 1},
+ {"DBG_SBR16B_PGD0_PG_STS", BIT(21), 0},
+ {"FUSE_PGD0_PG_STS", BIT(22), 0},
+ {"RSVD_23", BIT(23), 0},
+ {"P2SB0_PGD0_PG_STS", BIT(24), 1},
+ {"XDCI_PGD0_PG_STS", BIT(25), 0},
+ {"EXI_PGD0_PG_STS", BIT(26), 0},
+ {"CSE_PGD0_PG_STS", BIT(27), 1},
+ {"KVMCC_PGD0_PG_STS", BIT(28), 0},
+ {"PMT_PGD0_PG_STS", BIT(29), 0},
+ {"CLINK_PGD0_PG_STS", BIT(30), 0},
+ {"PTIO_PGD0_PG_STS", BIT(31), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcds_power_gating_status_1_map[] = {
+ {"USBR0_PGD0_PG_STS", BIT(0), 0},
+ {"SBR16B22_PGD0_PG_STS", BIT(1), 0},
+ {"SMT1_PGD0_PG_STS", BIT(2), 0},
+ {"P2SB1_PGD0_PG_STS", BIT(3), 1},
+ {"SMS2_PGD0_PG_STS", BIT(4), 0},
+ {"SMS1_PGD0_PG_STS", BIT(5), 0},
+ {"CSMERTC_PGD0_PG_STS", BIT(6), 0},
+ {"CSMEPSF_PGD0_PG_STS", BIT(7), 0},
+ {"D2D_NOC_PGD0_PG_STS", BIT(8), 0},
+ {"RSVD_9", BIT(9), 0},
+ {"RSVD_10", BIT(10), 0},
+ {"RSVD_11", BIT(11), 0},
+ {"SBR16B2_PGD0_PG_STS", BIT(12), 0},
+ {"OSSE_SMT1_PGD0_PG_STS", BIT(13), 1},
+ {"D2D_DISP_PGD0_PG_STS", BIT(14), 1},
+ {"RSVD_15", BIT(15), 0},
+ {"RSVD_16", BIT(16), 0},
+ {"DBG_PSF_PGD0_PG_STS", BIT(17), 0},
+ {"RSVD_18", BIT(18), 0},
+ {"CNVI_PGD0_PG_STS", BIT(19), 0},
+ {"UFSX2_PGD0_PG_STS", BIT(20), 0},
+ {"ENDBG_PGD0_PG_STS", BIT(21), 0},
+ {"DBC_PGD0_PG_STS", BIT(22), 0},
+ {"SBR16B4_PGD0_PG_STS", BIT(23), 0},
+ {"RSVD_24", BIT(24), 0},
+ {"NPK_PGD1_PG_STS", BIT(25), 0},
+ {"RSVD_26", BIT(26), 0},
+ {"SBR16B20_PGD0_PG_STS", BIT(27), 0},
+ {"RSVD_28", BIT(28), 0},
+ {"SBR8B20_PGD0_PG_STS", BIT(29), 0},
+ {"RSVD_30", BIT(30), 0},
+ {"FIA_U_PGD0_PG_STS", BIT(31), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcds_power_gating_status_2_map[] = {
+ {"PSF8_PGD0_PG_STS", BIT(0), 0},
+ {"RSVD_1", BIT(1), 0},
+ {"RSVD_2", BIT(2), 0},
+ {"FIACPCB_U_PGD0_PG_STS", BIT(3), 0},
+ {"TAM_PGD0_PG_STS", BIT(4), 1},
+ {"D2D_NOC_PGD2_PG_STS", BIT(5), 1},
+ {"SBR8B2_PGD0_PG_STS", BIT(6), 0},
+ {"THC0_PGD0_PG_STS", BIT(7), 0},
+ {"THC1_PGD0_PG_STS", BIT(8), 0},
+ {"PMC_PGD1_PG_STS", BIT(9), 0},
+ {"SBR16B3_PGD0_PG_STS", BIT(10), 0},
+ {"TCSS_PGD0_PG_STS", BIT(11), 0},
+ {"DISP_PGA_PGD0_PG_STS", BIT(12), 0},
+ {"RSVD_13", BIT(13), 0},
+ {"RSVD_14", BIT(14), 0},
+ {"RSVD_15", BIT(15), 0},
+ {"SBRG_PGD0_PG_STS", BIT(16), 0},
+ {"RSVD_17", BIT(17), 0},
+ {"SBR16B0_PGD0_PG_STS", BIT(18), 0},
+ {"SBR8B0_PGD0_PG_STS", BIT(19), 0},
+ {"PSF7_PGD0_PG_STS", BIT(20), 0},
+ {"RSVD_21", BIT(21), 0},
+ {"RSVD_22", BIT(22), 0},
+ {"RSVD_23", BIT(23), 0},
+ {"SBR16B6_PGD0_PG_STS", BIT(24), 0},
+ {"PSF0_PGD0_PG_STS", BIT(25), 0},
+ {"STRC_PGD0_PG_STS", BIT(26), 0},
+ {"RSVD_27", BIT(27), 0},
+ {"DBG_SBR_PGD0_PG_STS", BIT(28), 0},
+ {"RSVD_29", BIT(29), 0},
+ {"OSSE_PGD0_PG_STS", BIT(30), 1},
+ {"DISP_PGA1_PGD0_PG_STS", BIT(31), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcds_d3_status_0_map[] = {
+ {"LPSS_D3_STS", BIT(3), 1},
+ {"XDCI_D3_STS", BIT(4), 1},
+ {"XHCI_D3_STS", BIT(5), 1},
+ {"SPA_D3_STS", BIT(12), 0},
+ {"SPB_D3_STS", BIT(13), 0},
+ {"ESPISPI_D3_STS", BIT(18), 0},
+ {"PSTH_D3_STS", BIT(21), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcds_d3_status_1_map[] = {
+ {"OSSE_D3_STS", BIT(14), 0},
+ {"GBE_D3_STS", BIT(19), 0},
+ {"ITSS_D3_STS", BIT(23), 0},
+ {"CNVI_D3_STS", BIT(27), 0},
+ {"UFSX2_D3_STS", BIT(28), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcds_d3_status_2_map[] = {
+ {"CSMERTC_D3_STS", BIT(1), 0},
+ {"CSE_D3_STS", BIT(4), 0},
+ {"KVMCC_D3_STS", BIT(5), 0},
+ {"USBR0_D3_STS", BIT(6), 0},
+ {"ISH_D3_STS", BIT(7), 0},
+ {"SMT1_D3_STS", BIT(8), 0},
+ {"SMT2_D3_STS", BIT(9), 0},
+ {"SMT3_D3_STS", BIT(10), 0},
+ {"OSSE_SMT1_D3_STS", BIT(12), 0},
+ {"CLINK_D3_STS", BIT(14), 0},
+ {"PTIO_D3_STS", BIT(16), 0},
+ {"PMT_D3_STS", BIT(17), 0},
+ {"SMS1_D3_STS", BIT(18), 0},
+ {"SMS2_D3_STS", BIT(19), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcds_d3_status_3_map[] = {
+ {"OSSE_SMT2_D3_STS", BIT(0), 0},
+ {"THC0_D3_STS", BIT(14), 1},
+ {"THC1_D3_STS", BIT(15), 1},
+ {"OSSE_SMT3_D3_STS", BIT(19), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcds_vnn_req_status_0_map[] = {
+ {"LPSS_VNN_REQ_STS", BIT(3), 0},
+ {"ESPISPI_VNN_REQ_STS", BIT(18), 1},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcds_vnn_req_status_1_map[] = {
+ {"NPK_VNN_REQ_STS", BIT(4), 1},
+ {"DFXAGG_VNN_REQ_STS", BIT(8), 0},
+ {"EXI_VNN_REQ_STS", BIT(9), 1},
+ {"OSSE_VNN_REQ_STS", BIT(14), 1},
+ {"P2D_VNN_REQ_STS", BIT(18), 1},
+ {"GBE_VNN_REQ_STS", BIT(19), 0},
+ {"SMB_VNN_REQ_STS", BIT(25), 1},
+ {"LPC_VNN_REQ_STS", BIT(26), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcds_vnn_req_status_2_map[] = {
+ {"CSMERTC_VNN_REQ_STS", BIT(1), 0},
+ {"CSE_VNN_REQ_STS", BIT(4), 1},
+ {"ISH_VNN_REQ_STS", BIT(7), 0},
+ {"SMT1_VNN_REQ_STS", BIT(8), 0},
+ {"OSSE_SMT1_VNN_REQ_STS", BIT(12), 1},
+ {"CLINK_VNN_REQ_STS", BIT(14), 0},
+ {"SMS1_VNN_REQ_STS", BIT(18), 0},
+ {"SMS2_VNN_REQ_STS", BIT(19), 0},
+ {"GPIOCOM4_VNN_REQ_STS", BIT(20), 0},
+ {"GPIOCOM3_VNN_REQ_STS", BIT(21), 1},
+ {"GPIOCOM1_VNN_REQ_STS", BIT(23), 1},
+ {"GPIOCOM0_VNN_REQ_STS", BIT(24), 1},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcds_vnn_req_status_3_map[] = {
+ {"DISP_SHIM_VNN_REQ_STS", BIT(4), 1},
+ {"DTS0_VNN_REQ_STS", BIT(7), 0},
+ {"GPIOCOM5_VNN_REQ_STS", BIT(11), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcds_vnn_misc_status_map[] = {
+ {"CPU_C10_REQ_STS", BIT(0), 0},
+ {"TS_OFF_REQ_STS", BIT(1), 0},
+ {"PNDE_MET_REQ_STS", BIT(2), 1},
+ {"PG5_PMA0_REQ_STS", BIT(3), 1},
+ {"FW_THROTTLE_ALLOWED_REQ_STS", BIT(4), 0},
+ {"VNN_SOC_REQ_STS", BIT(6), 1},
+ {"ISH_VNNAON_REQ_STS", BIT(7), 0},
+ {"D2D_NOC_CFI_QACTIVE_REQ_STS", BIT(8), 1},
+ {"D2D_NOC_GPSB_QACTIVE_REQ_STS", BIT(9), 1},
+ {"PLT_GREATER_REQ_STS", BIT(11), 1},
+ {"ALL_SBR_IDLE_REQ_STS", BIT(12), 0},
+ {"PMC_IDLE_FB_OCP_REQ_STS", BIT(13), 0},
+ {"PM_SYNC_STATES_REQ_STS", BIT(14), 0},
+ {"EA_REQ_STS", BIT(15), 0},
+ {"MPHY_CORE_OFF_REQ_STS", BIT(16), 0},
+ {"BRK_EV_EN_REQ_STS", BIT(17), 0},
+ {"AUTO_DEMO_EN_REQ_STS", BIT(18), 0},
+ {"ITSS_CLK_SRC_REQ_STS", BIT(19), 1},
+ {"ARC_IDLE_REQ_STS", BIT(21), 0},
+ {"PG5_PMA1_REQ_STS", BIT(22), 1},
+ {"DG5_PMA0_REQ_STS", BIT(23), 1},
+ {"ARC_INTERRUPT_WAKE_REQ_STS", BIT(25), 0},
+ {"D2D_DISP_DDI_QACTIVE_REQ_STS", BIT(26), 1},
+ {"PRE_WAKE0_REQ_STS", BIT(27), 1},
+ {"PRE_WAKE1_REQ_STS", BIT(28), 1},
+ {"PRE_WAKE2_REQ_STS", BIT(29), 1},
+ {"D2D_DISP_EDP_QACTIVE_REQ_STS", BIT(31), 1},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcds_rsc_status_map[] = {
+ {"CORE", 0, 1},
+ {"Memory", 0, 1},
+ {"PRIM_D2D", 0, 1},
+ {"PSF0", 0, 1},
+ {"SB", 0, 1},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pcds_signal_status_map[] = {
+ {"LSX_Wake0_STS", BIT(0), 0},
+ {"LSX_Wake1_STS", BIT(1), 0},
+ {"LSX_Wake2_STS", BIT(2), 0},
+ {"LSX_Wake3_STS", BIT(3), 0},
+ {"LSX_Wake4_STS", BIT(4), 0},
+ {"LSX_Wake5_STS", BIT(5), 0},
+ {"LSX_Wake6_STS", BIT(6), 0},
+ {"LSX_Wake7_STS", BIT(7), 0},
+ {"LPSS_Wake0_STS", BIT(8), 1},
+ {"LPSS_Wake1_STS", BIT(9), 1},
+ {"Int_Timer_SS_Wake0_STS", BIT(10), 1},
+ {"Int_Timer_SS_Wake1_STS", BIT(11), 1},
+ {"Int_Timer_SS_Wake2_STS", BIT(12), 1},
+ {"Int_Timer_SS_Wake3_STS", BIT(13), 1},
+ {"Int_Timer_SS_Wake4_STS", BIT(14), 1},
+ {"Int_Timer_SS_Wake5_STS", BIT(15), 1},
+ {}
+};
+
+static const struct pmc_bit_map *nvl_pcds_lpm_maps[] = {
+ nvl_pcds_clocksource_status_map,
+ nvl_pcds_power_gating_status_0_map,
+ nvl_pcds_power_gating_status_1_map,
+ nvl_pcds_power_gating_status_2_map,
+ nvl_pcds_d3_status_0_map,
+ nvl_pcds_d3_status_1_map,
+ nvl_pcds_d3_status_2_map,
+ nvl_pcds_d3_status_3_map,
+ nvl_pcds_vnn_req_status_0_map,
+ nvl_pcds_vnn_req_status_1_map,
+ nvl_pcds_vnn_req_status_2_map,
+ nvl_pcds_vnn_req_status_3_map,
+ nvl_pcds_vnn_misc_status_map,
+ nvl_pcds_signal_status_map,
+ NULL
+};
+
+static const struct pmc_bit_map *nvl_pcds_blk_maps[] = {
+ nvl_pcds_power_gating_status_0_map,
+ nvl_pcds_power_gating_status_1_map,
+ nvl_pcds_power_gating_status_2_map,
+ nvl_pcds_rsc_status_map,
+ nvl_pcds_vnn_req_status_0_map,
+ nvl_pcds_vnn_req_status_1_map,
+ nvl_pcds_vnn_req_status_2_map,
+ nvl_pcds_vnn_req_status_3_map,
+ nvl_pcds_d3_status_0_map,
+ nvl_pcds_d3_status_1_map,
+ nvl_pcds_d3_status_2_map,
+ nvl_pcds_d3_status_3_map,
+ nvl_pcds_clocksource_status_map,
+ nvl_pcds_vnn_misc_status_map,
+ nvl_pcds_signal_status_map,
+ NULL
+};
+
+static const struct pmc_bit_map nvl_pchs_pfear_map[] = {
+ {"PMC_PGD0", BIT(0)},
+ {"FIA_D_PGD0", BIT(1)},
+ {"SPI_PGD0", BIT(2)},
+ {"XHCI_PGD0", BIT(3)},
+ {"SPA_PGD0", BIT(4)},
+ {"SPB_PGD0", BIT(5)},
+ {"MPFPW2_PGD0", BIT(6)},
+ {"GBE_PGD0", BIT(7)},
+
+ {"RSVD8", BIT(0)},
+ {"PSF3_PGD0", BIT(1)},
+ {"SBR5_PGD0", BIT(2)},
+ {"SBR0_PGD0", BIT(3)},
+ {"RSVD12", BIT(4)},
+ {"D2D_DISP_PGD1", BIT(5)},
+ {"LPSS_PGD0", BIT(6)},
+ {"LPC_PGD0", BIT(7)},
+
+ {"SMB_PGD0", BIT(0)},
+ {"ISH_PGD0", BIT(1)},
+ {"P2SB_PGD0", BIT(2)},
+ {"NPK_PGD0", BIT(3)},
+ {"D2D_NOC_PGD1", BIT(4)},
+ {"EAH_PGD0", BIT(5)},
+ {"FUSE_PGD0", BIT(6)},
+ {"SBR8_PGD0", BIT(7)},
+
+ {"PSF7_PGD0", BIT(0)},
+ {"OTG_PGD0", BIT(1)},
+ {"EXI_PGD0", BIT(2)},
+ {"CSE_PGD0", BIT(3)},
+ {"CSME_KVM_PGD0", BIT(4)},
+ {"CSME_PMT_PGD0", BIT(5)},
+ {"CSME_CLINK_PGD0", BIT(6)},
+ {"CSME_PTIO_PGD0", BIT(7)},
+
+ {"CSME_USBR_PGD0", BIT(0)},
+ {"SBR1_PGD0", BIT(1)},
+ {"CSME_SMT1_PGD0", BIT(2)},
+ {"MPFPW1_PGD0", BIT(3)},
+ {"CSME_SMS2_PGD0", BIT(4)},
+ {"CSME_SMS_PGD0", BIT(5)},
+ {"CSME_RTC_PGD0", BIT(6)},
+ {"CSMEPSF_PGD0", BIT(7)},
+
+ {"D2D_NOC_PGD0", BIT(0)},
+ {"ESE_PGD0", BIT(1)},
+ {"SBR2_PGD0", BIT(2)},
+ {"SBR3_PGD0", BIT(3)},
+ {"SBR4_PGD0", BIT(4)},
+ {"RSVD45", BIT(5)},
+ {"D2D_DISP_PGD0", BIT(6)},
+ {"PSF1_PGD0", BIT(7)},
+
+ {"U3FPW1_PGD0", BIT(0)},
+ {"DMI3FPW_PGD0", BIT(1)},
+ {"PSF4_PGD0", BIT(2)},
+ {"CNVI_PGD0", BIT(3)},
+ {"RSVD52", BIT(4)},
+ {"ENDBG_PGD0", BIT(5)},
+ {"DBC_PGD0", BIT(6)},
+ {"SMT4_PGD0", BIT(7)},
+
+ {"RSVD56", BIT(0)},
+ {"NPK_PGD1", BIT(1)},
+ {"RSVD58", BIT(2)},
+ {"DMI3_PGD0", BIT(3)},
+ {"RSVD60", BIT(4)},
+ {"FIACPCB_D_PGD0", BIT(5)},
+ {"RSVD62", BIT(6)},
+ {"FIA_U_PGD0", BIT(7)},
+
+ {"FIACPCB_PGS_PGD0", BIT(0)},
+ {"FIA_PGS_PGD0", BIT(1)},
+ {"RSVD66", BIT(2)},
+ {"FIACPCB_U_PGD0", BIT(3)},
+ {"TAM_PGD0", BIT(4)},
+ {"D2D_NOC_PGD2", BIT(5)},
+ {"PSF2_PGD0", BIT(6)},
+ {"THC0_PGD0", BIT(7)},
+
+ {"THC1_PGD0", BIT(0)},
+ {"PMC_PGD1", BIT(1)},
+ {"SBR9_PGD0", BIT(2)},
+ {"U3FPW2_PGD0", BIT(3)},
+ {"RSVD76", BIT(4)},
+ {"DBG_PSF_PGD0", BIT(5)},
+ {"DBG_SBR_PGD0", BIT(6)},
+ {"SBR6_PGD0", BIT(7)},
+
+ {"SPC_PGD0", BIT(0)},
+ {"ACE_PGD0", BIT(1)},
+ {"ACE_PGD1", BIT(2)},
+ {"ACE_PGD2", BIT(3)},
+ {"ACE_PGD3", BIT(4)},
+ {"ACE_PGD4", BIT(5)},
+ {"ACE_PGD5", BIT(6)},
+ {"ACE_PGD6", BIT(7)},
+
+ {"ACE_PGD7", BIT(0)},
+ {"ACE_PGD8", BIT(1)},
+ {"ACE_PGD9", BIT(2)},
+ {"ACE_PGD10", BIT(3)},
+ {"U3FPW3_PGD0", BIT(4)},
+ {"SBR7_PGD0", BIT(5)},
+ {"OSSE_PGD0", BIT(6)},
+ {"ST_PGD0", BIT(7)},
+ {}
+};
+
+static const struct pmc_bit_map *ext_nvl_pchs_pfear_map[] = {
+ nvl_pchs_pfear_map,
+ NULL
+};
+
+static const struct pmc_bit_map nvl_pchs_clocksource_status_map[] = {
+ {"AON2_OFF_STS", BIT(0), 1},
+ {"AON3_OFF_STS", BIT(1), 0},
+ {"AON4_OFF_STS", BIT(2), 0},
+ {"AON2_SPL_OFF_STS", BIT(3), 0},
+ {"AONL_OFF_STS", BIT(4), 0},
+ {"XTAL_LVM_OFF_STS", BIT(5), 0},
+ {"AON5_OFF_STS", BIT(6), 0},
+ {"USB3_PLL_OFF_STS", BIT(8), 1},
+ {"MAIN_CRO_OFF_STS", BIT(11), 0},
+ {"MAIN_DIVIDER_OFF_STS", BIT(12), 1},
+ {"REF_PLL_NON_OC_OFF_STS", BIT(13), 1},
+ {"DMI_PLL_OFF_STS", BIT(14), 1},
+ {"PHY_EXT_INJ_OFF_STS", BIT(15), 1},
+ {"AON6_MCRO_OFF_STS", BIT(16), 0},
+ {"XTAL_AGGR_OFF_STS", BIT(17), 0},
+ {"USB2_PLL_OFF_STS", BIT(18), 1},
+ {"GBE_PLL_OFF_STS", BIT(21), 1},
+ {"SATA_PLL_OFF_STS", BIT(22), 1},
+ {"PCIE0_PLL_OFF_STS", BIT(23), 1},
+ {"PCIE1_PLL_OFF_STS", BIT(24), 1},
+ {"FABRIC_PLL_OFF_STS", BIT(25), 1},
+ {"PCIE2_PLL_OFF_STS", BIT(26), 1},
+ {"REF_PLL_OFF_STS", BIT(28), 1},
+ {"REF38P4_PLL_OFF_STS", BIT(31), 1},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pchs_power_gating_status_0_map[] = {
+ {"PMC_PGD0_PG_STS", BIT(0), 0},
+ {"FIA_D_PGD0_PG_STS", BIT(1), 0},
+ {"ESPISPI_PGD0_PG_STS", BIT(2), 0},
+ {"XHCI_PGD0_PG_STS", BIT(3), 0},
+ {"SPA_PGD0_PG_STS", BIT(4), 1},
+ {"SPB_PGD0_PG_STS", BIT(5), 1},
+ {"MPFPW2_PGD0_PG_STS", BIT(6), 0},
+ {"GBE_PGD0_PG_STS", BIT(7), 1},
+ {"RSVD_8", BIT(8), 0},
+ {"PSF3_PGD0_PG_STS", BIT(9), 0},
+ {"SBR5_PGD0_PG_STS", BIT(10), 0},
+ {"SBR0_PGD0_PG_STS", BIT(11), 0},
+ {"RSVD_12", BIT(12), 0},
+ {"D2D_DISP_PGD1_PG_STS", BIT(13), 0},
+ {"LPSS_PGD0_PG_STS", BIT(14), 1},
+ {"LPC_PGD0_PG_STS", BIT(15), 0},
+ {"SMB_PGD0_PG_STS", BIT(16), 0},
+ {"ISH_PGD0_PG_STS", BIT(17), 0},
+ {"P2S_PGD0_PG_STS", BIT(18), 0},
+ {"NPK_PGD0_PG_STS", BIT(19), 0},
+ {"D2D_NOC_PGD1_PG_STS", BIT(20), 0},
+ {"EAH_PGD0_PG_STS", BIT(21), 0},
+ {"FUSE_PGD0_PG_STS", BIT(22), 0},
+ {"SBR8_PGD0_PG_STS", BIT(23), 0},
+ {"PSF7_PGD0_PG_STS", BIT(24), 0},
+ {"XDCI_PGD0_PG_STS", BIT(25), 1},
+ {"EXI_PGD0_PG_STS", BIT(26), 0},
+ {"CSE_PGD0_PG_STS", BIT(27), 1},
+ {"KVMCC_PGD0_PG_STS", BIT(28), 1},
+ {"PMT_PGD0_PG_STS", BIT(29), 1},
+ {"CLINK_PGD0_PG_STS", BIT(30), 1},
+ {"PTIO_PGD0_PG_STS", BIT(31), 1},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pchs_power_gating_status_1_map[] = {
+ {"USBR0_PGD0_PG_STS", BIT(0), 1},
+ {"SBR1_PGD0_PG_STS", BIT(1), 0},
+ {"SMT1_PGD0_PG_STS", BIT(2), 1},
+ {"MPFPW1_PGD0_PG_STS", BIT(3), 0},
+ {"SMS2_PGD0_PG_STS", BIT(4), 1},
+ {"SMS1_PGD0_PG_STS", BIT(5), 1},
+ {"CSMERTC_PGD0_PG_STS", BIT(6), 0},
+ {"CSMEPSF_PGD0_PG_STS", BIT(7), 0},
+ {"D2D_NOC_PGD0_PG_STS", BIT(8), 0},
+ {"ESE_PGD0_PG_STS", BIT(9), 1},
+ {"SBR2_PGD0_PG_STS", BIT(10), 0},
+ {"SBR3_PGD0_PG_STS", BIT(11), 0},
+ {"SBR4_PGD0_PG_STS", BIT(12), 0},
+ {"RSVD_13", BIT(13), 0},
+ {"D2D_DISP_PGD0_PG_STS", BIT(14), 0},
+ {"PSF1_PGD0_PG_STS", BIT(15), 0},
+ {"U3FPW1_PGD0_PG_STS", BIT(16), 0},
+ {"DMI3FPW_PGD0_PG_STS", BIT(17), 0},
+ {"PSF4_PGD0_PG_STS", BIT(18), 0},
+ {"CNVI_PGD0_PG_STS", BIT(19), 0},
+ {"RSVD_20", BIT(20), 0},
+ {"ENDBG_PGD0_PG_STS", BIT(21), 0},
+ {"DBC_PGD0_PG_STS", BIT(22), 0},
+ {"SMT4_PGD0_PG_STS", BIT(23), 1},
+ {"RSVD_24", BIT(24), 0},
+ {"NPK_PGD1_PG_STS", BIT(25), 0},
+ {"RSVD_26", BIT(26), 0},
+ {"DMI3_PGD0_PG_STS", BIT(27), 1},
+ {"RSVD_28", BIT(28), 0},
+ {"FIACPCB_D_PGD0_PG_STS", BIT(29), 0},
+ {"RSVD_30", BIT(30), 0},
+ {"FIA_U_PGD0_PG_STS", BIT(31), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pchs_power_gating_status_2_map[] = {
+ {"FIACPCB_PGS_PGD0_PG_STS", BIT(0), 0},
+ {"FIA_PGS_PGD0_PG_STS", BIT(1), 0},
+ {"RSVD_2", BIT(2), 0},
+ {"FIACPCB_U_PGD0_PG_STS", BIT(3), 0},
+ {"TAM_PGD0_PG_STS", BIT(4), 0},
+ {"D2D_NOC_PGD2_PG_STS", BIT(5), 0},
+ {"PSF2_PGD0_PG_STS", BIT(6), 0},
+ {"THC0_PGD0_PG_STS", BIT(7), 1},
+ {"THC1_PGD0_PG_STS", BIT(8), 1},
+ {"PMC_PGD1_PG_STS", BIT(9), 0},
+ {"SBR9_PGA0_PGD0_PG_STS", BIT(10), 0},
+ {"U3FPW2_PGD0_PG_STS", BIT(11), 0},
+ {"RSVD_12", BIT(12), 0},
+ {"DBG_PSF_PGD0_PG_STS", BIT(13), 0},
+ {"DBG_SBR_PGD0_PG_STS", BIT(14), 0},
+ {"SBR6_PGD0_PG_STS", BIT(15), 0},
+ {"SPC_PGD0_PG_STS", BIT(16), 1},
+ {"ACE_PGD0_PG_STS", BIT(17), 0},
+ {"ACE_PGD1_PG_STS", BIT(18), 0},
+ {"ACE_PGD2_PG_STS", BIT(19), 0},
+ {"ACE_PGD3_PG_STS", BIT(20), 0},
+ {"ACE_PGD4_PG_STS", BIT(21), 0},
+ {"ACE_PGD5_PG_STS", BIT(22), 0},
+ {"ACE_PGD6_PG_STS", BIT(23), 0},
+ {"ACE_PGD7_PG_STS", BIT(24), 0},
+ {"ACE_PGD8_PG_STS", BIT(25), 0},
+ {"ACE_PGD9_PG_STS", BIT(26), 0},
+ {"ACE_PGD10_PG_STS", BIT(27), 0},
+ {"U3FPW3_PGD0_PG_STS", BIT(28), 0},
+ {"SBR7_PGD0_PG_STS", BIT(29), 0},
+ {"OSSE_PGD0_PG_STS", BIT(30), 0},
+ {"SATA_PGD0_PG_STS", BIT(31), 1},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pchs_d3_status_0_map[] = {
+ {"LPSS_D3_STS", BIT(3), 1},
+ {"XDCI_D3_STS", BIT(4), 1},
+ {"XHCI_D3_STS", BIT(5), 0},
+ {"SPA_D3_STS", BIT(12), 0},
+ {"SPB_D3_STS", BIT(13), 0},
+ {"SPC_D3_STS", BIT(14), 0},
+ {"ESPISPI_D3_STS", BIT(18), 0},
+ {"SATA_D3_STS", BIT(20), 1},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pchs_d3_status_1_map[] = {
+ {"OSSE_D3_STS", BIT(6), 0},
+ {"GBE_D3_STS", BIT(19), 0},
+ {"ITSS_D3_STS", BIT(23), 0},
+ {"P2S_D3_STS", BIT(24), 0},
+ {"CNVI_D3_STS", BIT(27), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pchs_d3_status_2_map[] = {
+ {"CSMERTC_D3_STS", BIT(1), 0},
+ {"CSE_D3_STS", BIT(4), 0},
+ {"KVMCC_D3_STS", BIT(5), 0},
+ {"USBR0_D3_STS", BIT(6), 0},
+ {"ISH_D3_STS", BIT(7), 0},
+ {"SMT1_D3_STS", BIT(8), 0},
+ {"SMT2_D3_STS", BIT(9), 0},
+ {"SMT3_D3_STS", BIT(10), 0},
+ {"SMT4_D3_STS", BIT(11), 0},
+ {"SMT5_D3_STS", BIT(12), 0},
+ {"SMT6_D3_STS", BIT(13), 0},
+ {"CLINK_D3_STS", BIT(14), 0},
+ {"PTIO_D3_STS", BIT(16), 0},
+ {"PMT_D3_STS", BIT(17), 0},
+ {"SMS1_D3_STS", BIT(18), 0},
+ {"SMS2_D3_STS", BIT(19), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pchs_d3_status_3_map[] = {
+ {"THC0_D3_STS", BIT(14), 0},
+ {"THC1_D3_STS", BIT(15), 0},
+ {"ACE_D3_STS", BIT(23), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pchs_vnn_req_status_1_map[] = {
+ {"NPK_VNN_REQ_STS", BIT(4), 0},
+ {"OSSE_VNN_REQ_STS", BIT(6), 0},
+ {"DFXAGG_VNN_REQ_STS", BIT(8), 0},
+ {"EXI_VNN_REQ_STS", BIT(9), 0},
+ {"GBE_VNN_REQ_STS", BIT(19), 0},
+ {"SMB_VNN_REQ_STS", BIT(25), 0},
+ {"LPC_VNN_REQ_STS", BIT(26), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pchs_vnn_req_status_2_map[] = {
+ {"CSMERTC_VNN_REQ_STS", BIT(1), 0},
+ {"CSE_VNN_REQ_STS", BIT(4), 0},
+ {"ISH_VNN_REQ_STS", BIT(7), 0},
+ {"SMT1_VNN_REQ_STS", BIT(8), 0},
+ {"SMT4_VNN_REQ_STS", BIT(11), 0},
+ {"CLINK_VNN_REQ_STS", BIT(14), 0},
+ {"SMS1_VNN_REQ_STS", BIT(18), 0},
+ {"SMS2_VNN_REQ_STS", BIT(19), 0},
+ {"GPIOCOM4_VNN_REQ_STS", BIT(20), 0},
+ {"GPIOCOM3_VNN_REQ_STS", BIT(21), 0},
+ {"GPIOCOM2_VNN_REQ_STS", BIT(22), 0},
+ {"GPIOCOM1_VNN_REQ_STS", BIT(23), 0},
+ {"GPIOCOM0_VNN_REQ_STS", BIT(24), 0},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pchs_vnn_misc_status_map[] = {
+ {"CPU_C10_REQ_STS", BIT(0), 0},
+ {"TS_OFF_REQ_STS", BIT(1), 0},
+ {"PNDE_MET_REQ_STS", BIT(2), 1},
+ {"PG5_PMA0_GVNN_REQ_STS", BIT(3), 1},
+ {"FW_THROTTLE_ALLOWED_REQ_STS", BIT(4), 0},
+ {"DMI_IN_L1_REQ_STS", BIT(6), 0},
+ {"ISH_VNNAON_REQ_STS", BIT(7), 0},
+ {"PLT_GREATER_REQ_STS", BIT(11), 1},
+ {"ALL_SBR_IDLE_REQ_STS", BIT(12), 0},
+ {"PMC_IDLE_FB_OCP_REQ_STS", BIT(13), 0},
+ {"PM_SYNC_STATES_REQ_STS", BIT(14), 0},
+ {"EA_REQ_STS", BIT(15), 0},
+ {"DMI_CLKREQ_B_REQ_STS", BIT(16), 0},
+ {"BRK_EV_EN_REQ_STS", BIT(17), 0},
+ {"AUTO_DEMO_EN_REQ_STS", BIT(18), 0},
+ {"ITSS_CLK_SRC_REQ_STS", BIT(19), 1},
+ {"ARC_IDLE_REQ_STS", BIT(21), 0},
+ {"PG5_PMA1_GVNN_REQ_STS", BIT(22), 1},
+ {"FIA_DEEP_PM_REQ_STS", BIT(23), 0},
+ {"XDCI_ATTACHED_REQ_STS", BIT(24), 0},
+ {"ARC_INTERRUPT_WAKE_REQ_STS", BIT(25), 0},
+ {"PRE_WAKE0_REQ_STS", BIT(27), 1},
+ {"PRE_WAKE1_REQ_STS", BIT(28), 1},
+ {"PRE_WAKE2_EN_REQ_STS", BIT(29), 0},
+ {"PG5_PMA2_GVNN_REQ_STS", BIT(30), 1},
+ {}
+};
+
+static const struct pmc_bit_map nvl_pchs_rsc_status_map[] = {
+ {"Memory", 0, 1},
+ {"Memory_NS", 0, 1},
+ {"PSF1", 0, 1},
+ {"PSF2", 0, 1},
+ {"PSF3", 0, 1},
+ {"REF_PLL", 0, 1},
+ {"SB", 0, 1},
+ {}
+};
+
+static const struct pmc_bit_map *nvl_pchs_lpm_maps[] = {
+ nvl_pchs_clocksource_status_map,
+ nvl_pchs_power_gating_status_0_map,
+ nvl_pchs_power_gating_status_1_map,
+ nvl_pchs_power_gating_status_2_map,
+ nvl_pchs_d3_status_0_map,
+ nvl_pchs_d3_status_1_map,
+ nvl_pchs_d3_status_2_map,
+ nvl_pchs_d3_status_3_map,
+ nvl_pcds_vnn_req_status_0_map,
+ nvl_pchs_vnn_req_status_1_map,
+ nvl_pchs_vnn_req_status_2_map,
+ nvl_pcdh_vnn_req_status_3_map,
+ nvl_pchs_vnn_misc_status_map,
+ ptl_pcdp_signal_status_map,
+ NULL
+};
+
+static const struct pmc_bit_map *nvl_pchs_blk_maps[] = {
+ nvl_pchs_power_gating_status_0_map,
+ nvl_pchs_power_gating_status_1_map,
+ nvl_pchs_power_gating_status_2_map,
+ nvl_pchs_rsc_status_map,
+ nvl_pchs_d3_status_0_map,
+ nvl_pchs_clocksource_status_map,
+ nvl_pchs_vnn_misc_status_map,
+ NULL
+};
+
+static const struct pmc_reg_map nvl_pcdh_reg_map = {
+ .pfear_sts = ext_nvl_pcdh_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 = ptl_pcdp_ltr_show_map,
+ .msr_sts = msr_map,
+ .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
+ .regmap_length = NVL_PCDH_PMC_MMIO_REG_LEN,
+ .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
+ .ppfear_buckets = NVL_PCDH_PPFEAR_NUM_ENTRIES,
+ .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
+ .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
+ .lpm_num_maps = NVL_LPM_NUM_MAPS,
+ .ltr_ignore_max = LNL_NUM_IP_IGN_ALLOWED,
+ .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 = NVL_LPM_PRI_OFFSET,
+ .lpm_en_offset = NVL_LPM_EN_OFFSET,
+ .lpm_residency_offset = NVL_LPM_RESIDENCY_OFFSET,
+ .lpm_sts = nvl_pcdh_lpm_maps,
+ .lpm_status_offset = MTL_LPM_STATUS_OFFSET,
+ .lpm_live_status_offset = NVL_LPM_LIVE_STATUS_OFFSET,
+ .s0ix_blocker_maps = nvl_pcdh_blk_maps,
+ .s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET,
+ .num_s0ix_blocker = NVL_PCDH_NUM_S0IX_BLOCKER,
+ .blocker_req_offset = NVL_PCDH_BLK_REQ_OFFSET,
+ .lpm_req_guid = PCDH_LPM_REQ_GUID,
+};
+
+static const struct pmc_reg_map nvl_pcds_reg_map = {
+ .pfear_sts = ext_nvl_pcds_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 = nvl_pcds_ltr_show_map,
+ .msr_sts = msr_map,
+ .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
+ .regmap_length = NVL_PCDS_PMC_MMIO_REG_LEN,
+ .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
+ .ppfear_buckets = LNL_PPFEAR_NUM_ENTRIES,
+ .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
+ .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
+ .lpm_num_maps = PTL_LPM_NUM_MAPS,
+ .ltr_ignore_max = LNL_NUM_IP_IGN_ALLOWED,
+ .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 = nvl_pcds_lpm_maps,
+ .lpm_status_offset = MTL_LPM_STATUS_OFFSET,
+ .lpm_live_status_offset = MTL_LPM_LIVE_STATUS_OFFSET,
+ .s0ix_blocker_maps = nvl_pcds_blk_maps,
+ .s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET,
+ .num_s0ix_blocker = NVL_PCDS_NUM_S0IX_BLOCKER,
+ .lpm_req_guid = PCDS_LPM_REQ_GUID,
+ .blocker_req_offset = NVL_PCDS_BLK_REQ_OFFSET,
+};
+
+static const struct pmc_reg_map nvl_pchs_reg_map = {
+ .pfear_sts = ext_nvl_pchs_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 = ptl_pcdp_ltr_show_map,
+ .msr_sts = msr_map,
+ .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
+ .regmap_length = NVL_PCHS_PMC_MMIO_REG_LEN,
+ .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
+ .ppfear_buckets = LNL_PPFEAR_NUM_ENTRIES,
+ .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET,
+ .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT,
+ .lpm_num_maps = PTL_LPM_NUM_MAPS,
+ .ltr_ignore_max = LNL_NUM_IP_IGN_ALLOWED,
+ .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 = nvl_pchs_lpm_maps,
+ .lpm_status_offset = MTL_LPM_STATUS_OFFSET,
+ .lpm_live_status_offset = MTL_LPM_LIVE_STATUS_OFFSET,
+ .s0ix_blocker_maps = nvl_pchs_blk_maps,
+ .s0ix_blocker_offset = LNL_S0IX_BLOCKER_OFFSET,
+ .num_s0ix_blocker = NVL_PCHS_NUM_S0IX_BLOCKER,
+ .blocker_req_offset = NVL_PCHS_BLK_REQ_OFFSET,
+ .lpm_req_guid = PCHS_LPM_REQ_GUID,
+};
+
+static struct pmc_info nvl_pmc_info_list[] = {
+ {
+ .devid = PMC_DEVID_NVL_PCDH,
+ .map = &nvl_pcdh_reg_map,
+ },
+ {
+ .devid = PMC_DEVID_NVL_PCDS,
+ .map = &nvl_pcds_reg_map,
+ },
+ {
+ .devid = PMC_DEVID_NVL_PCHS,
+ .map = &nvl_pchs_reg_map,
+ },
+ {}
+};
+
+static const char *nvl_ltr_block_counter_arr[] = {
+ "PKGC_PREVENT_LTR_IADOMAIN",
+ "PKGC_PREVENT_LTR_GDIE",
+ "PKGC_PREVENT_LTR_PCH",
+ "PKGC_PREVENT_LTR_DISPLAY",
+ "PKGC_PREVENT_LTR_IPU",
+ NULL
+};
+
+static const char *nvl_pkgc_blocker_residency[] = {
+ "PKGC_BLOCK_RESIDENCY_INVALID",
+ "PKGC_BLOCK_RESIDENCY_MISC",
+ "PKGC_BLOCK_RESIDENCY_CDIE_MISC",
+ "PKGC_BLOCK_RESIDENCY_MEDIA_MISC",
+ "PKGC_BLOCK_RESIDENCY_GT_MISC",
+ "PKGC_BLOCK_RESIDENCY_HUBATOM_MISC",
+ "PKGC_BLOCK_RESIDENCY_IPU_BUSY",
+ "PKGC_BLOCK_RESIDENCY_IPU_LTR",
+ "PKGC_BLOCK_RESIDENCY_IPU_TIMER",
+ "PKGC_BLOCK_RESIDENCY_DISP_BUSY",
+ "PKGC_BLOCK_RESIDENCY_DISP_LTR",
+ "PKGC_BLOCK_RESIDENCY_DISP_TIMER",
+ "PKGC_BLOCK_RESIDENCY_VPU_BUSY",
+ "PKGC_BLOCK_RESIDENCY_VPU_TIMER",
+ "PKGC_BLOCK_RESIDENCY_PMC_BUSY",
+ "PKGC_BLOCK_RESIDENCY_PMC_LTR",
+ "PKGC_BLOCK_RESIDENCY_PMC_TIMER",
+ "PKGC_BLOCK_RESIDENCY_HUBATOM_ARAT",
+ "PKGC_BLOCK_RESIDENCY_CDIE0_ARAT",
+ "PKGC_BLOCK_RESIDENCY_CDIE1_ARAT",
+ "PKGC_BLOCK_RESIDENCY_GT_ARAT",
+ "PKGC_BLOCK_RESIDENCY_MEDIA_ARAT",
+ "PKGC_BLOCK_RESIDENCY_DEMOTION",
+ "PKGC_BLOCK_RESIDENCY_THERMALS",
+ "PKGC_BLOCK_RESIDENCY_SNCU",
+ "PKGC_BLOCK_RESIDENCY_SVTU",
+ "PKGC_BLOCK_RESIDENCY_IAA",
+ "PKGC_BLOCK_RESIDENCY_IOC",
+ NULL,
+};
+
+static const u8 nvl_pmc_list[] = {PMC_IDX_MAIN, PMC_IDX_PCH};
+
+#define NVL_NPU_PCI_DEV 0xd71d
+
+/*
+ * Set power state of select devices that do not have drivers to D3
+ * so that they do not block Package C entry.
+ */
+static void nvl_d3_fixup(void)
+{
+ pmc_core_set_device_d3(NVL_NPU_PCI_DEV);
+}
+
+static int nvl_resume(struct pmc_dev *pmcdev)
+{
+ nvl_d3_fixup();
+ return cnl_resume(pmcdev);
+}
+
+static int nvl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_info)
+{
+ nvl_d3_fixup();
+ return generic_core_init(pmcdev, pmc_dev_info);
+}
+
+static u32 nvl_pmt_dmu_guids[] = {NVL_PMT_DMU_GUID, 0x0};
+struct pmc_dev_info nvl_s_pmc_dev = {
+ .num_pmcs = ARRAY_SIZE(nvl_pmc_list),
+ .pmc_list = nvl_pmc_list,
+ .regmap_list = nvl_pmc_info_list,
+ .map = &nvl_pcds_reg_map,
+ .sub_req_show = &pmc_core_substate_blk_req_fops,
+ .suspend = cnl_suspend,
+ .resume = nvl_resume,
+ .init = nvl_core_init,
+ .sub_req = pmc_core_pmt_get_blk_sub_req,
+ .dmu_guids = nvl_pmt_dmu_guids,
+ .pc_guid = NVL_PMT_PC_GUID,
+ .pkgc_ltr_blocker_offset = NVL_LTR_BLK_OFFSET,
+ .pkgc_ltr_blocker_counters = nvl_ltr_block_counter_arr,
+ .pkgc_blocker_offset = NVL_PKGC_BLK_OFFSET,
+ .pkgc_blocker_counters = nvl_pkgc_blocker_residency,
+ .ssram_hidden = false,
+ .die_c6_offset = NVL_PMT_DMU_DIE_C6_OFFSET,
+};
+
+struct pmc_dev_info nvl_h_pmc_dev = {
+ .num_pmcs = ARRAY_SIZE(nvl_pmc_list),
+ .pmc_list = nvl_pmc_list,
+ .regmap_list = nvl_pmc_info_list,
+ .map = &nvl_pcdh_reg_map,
+ .sub_req_show = &pmc_core_substate_blk_req_fops,
+ .suspend = cnl_suspend,
+ .resume = nvl_resume,
+ .init = nvl_core_init,
+ .sub_req = pmc_core_pmt_get_blk_sub_req,
+ .dmu_guids = nvl_pmt_dmu_guids,
+ .pc_guid = NVL_PMT_PC_GUID,
+ .pkgc_ltr_blocker_offset = NVL_LTR_BLK_OFFSET,
+ .pkgc_ltr_blocker_counters = nvl_ltr_block_counter_arr,
+ .pkgc_blocker_offset = NVL_PKGC_BLK_OFFSET,
+ .pkgc_blocker_counters = nvl_pkgc_blocker_residency,
+ .ssram_hidden = false,
+ .die_c6_offset = NVL_PMT_DMU_DIE_C6_OFFSET,
+};
diff --git a/drivers/platform/x86/intel/pmc/ptl.c b/drivers/platform/x86/intel/pmc/ptl.c
index 1f48e2bbc699..a7d5d4f77934 100644
--- a/drivers/platform/x86/intel/pmc/ptl.c
+++ b/drivers/platform/x86/intel/pmc/ptl.c
@@ -137,7 +137,7 @@ static const struct pmc_bit_map *ext_ptl_pcdp_pfear_map[] = {
NULL
};
-static const struct pmc_bit_map ptl_pcdp_ltr_show_map[] = {
+const struct pmc_bit_map ptl_pcdp_ltr_show_map[] = {
{"SOUTHPORT_A", CNP_PMC_LTR_SPA},
{"SOUTHPORT_B", CNP_PMC_LTR_SPB},
{"SATA", CNP_PMC_LTR_SATA},
@@ -543,6 +543,8 @@ static struct pmc_info ptl_pmc_info_list[] = {
{}
};
+static const u8 ptl_pmc_list[] = {PMC_IDX_MAIN};
+
#define PTL_NPU_PCI_DEV 0xb03e
#define PTL_IPU_PCI_DEV 0xb05d
@@ -569,7 +571,8 @@ static int ptl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_in
}
struct pmc_dev_info ptl_pmc_dev = {
- .pci_func = 2,
+ .num_pmcs = ARRAY_SIZE(ptl_pmc_list),
+ .pmc_list = ptl_pmc_list,
.regmap_list = ptl_pmc_info_list,
.map = &ptl_pcdp_reg_map,
.sub_req_show = &pmc_core_substate_blk_req_fops,
@@ -577,4 +580,5 @@ struct pmc_dev_info ptl_pmc_dev = {
.resume = ptl_resume,
.init = ptl_core_init,
.sub_req = pmc_core_pmt_get_blk_sub_req,
+ .ssram_hidden = true,
};
diff --git a/drivers/platform/x86/intel/pmc/pwrm_telemetry.c b/drivers/platform/x86/intel/pmc/pwrm_telemetry.c
new file mode 100644
index 000000000000..013f779f20a4
--- /dev/null
+++ b/drivers/platform/x86/intel/pmc/pwrm_telemetry.c
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel PMC PWRM ACPI driver
+ *
+ * Copyright (C) 2025, Intel Corporation
+ */
+
+#include <linux/acpi.h>
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/intel_vsec.h>
+#include <linux/limits.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/resource.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uuid.h>
+
+#include "core.h"
+
+#define ENTRY_LEN 5
+
+/* DWORD2 */
+#define DVSEC_ID_MASK GENMASK(15, 0)
+#define NUM_ENTRIES_MASK GENMASK(23, 16)
+#define ENTRY_SIZE_MASK GENMASK(31, 24)
+
+/* DWORD3 */
+#define TBIR_MASK GENMASK(2, 0)
+#define DISC_TBL_OFF_MASK GENMASK(31, 3)
+
+const guid_t intel_vsec_guid =
+ GUID_INIT(0x294903fb, 0x634d, 0x4fc7, 0xaf, 0x1f, 0x0f, 0xb9,
+ 0x56, 0xb0, 0x4f, 0xc1);
+
+static bool is_valid_entry(union acpi_object *pkg)
+{
+ int i;
+
+ if (!pkg || pkg->type != ACPI_TYPE_PACKAGE || pkg->package.count != ENTRY_LEN)
+ return false;
+
+ if (pkg->package.elements[0].type != ACPI_TYPE_STRING)
+ return false;
+
+ for (i = 1; i < ENTRY_LEN; i++)
+ if (pkg->package.elements[i].type != ACPI_TYPE_INTEGER)
+ return false;
+
+ return true;
+}
+
+acpi_disc_t pmc_parse_telem_dsd(union acpi_object *obj,
+ struct intel_vsec_header *header)
+{
+ union acpi_object *vsec_pkg;
+ union acpi_object *disc_pkg;
+ u64 hdr0, hdr1;
+ int num_regions;
+ int i;
+
+ if (!header)
+ return ERR_PTR(-EINVAL);
+
+ if (!obj || obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 2)
+ return ERR_PTR(-EINVAL);
+
+ /* First Package is DVSEC info */
+ vsec_pkg = &obj->package.elements[0];
+ if (!is_valid_entry(vsec_pkg))
+ return ERR_PTR(-EINVAL);
+
+ hdr0 = vsec_pkg->package.elements[3].integer.value;
+ hdr1 = vsec_pkg->package.elements[4].integer.value;
+
+ header->id = FIELD_GET(DVSEC_ID_MASK, hdr0);
+ header->num_entries = FIELD_GET(NUM_ENTRIES_MASK, hdr0);
+ header->entry_size = FIELD_GET(ENTRY_SIZE_MASK, hdr0);
+ header->tbir = FIELD_GET(TBIR_MASK, hdr1);
+ header->offset = hdr1 & DISC_TBL_OFF_MASK;
+
+ /* Second Package contains the discovery tables */
+ disc_pkg = &obj->package.elements[1];
+ if (disc_pkg->type != ACPI_TYPE_PACKAGE || disc_pkg->package.count < 1)
+ return ERR_PTR(-EINVAL);
+
+ num_regions = disc_pkg->package.count;
+ if (header->num_entries != num_regions)
+ return ERR_PTR(-EINVAL);
+
+ acpi_disc_t disc __free(kfree) = kmalloc_objs(*disc, num_regions);
+ if (!disc)
+ return ERR_PTR(-ENOMEM);
+
+ for (i = 0; i < num_regions; i++) {
+ union acpi_object *pkg;
+ u64 value;
+ int j;
+
+ pkg = &disc_pkg->package.elements[i];
+ if (!is_valid_entry(pkg))
+ return ERR_PTR(-EINVAL);
+
+ /* Element 0 is a descriptive string; DWORD values start at index 1. */
+ for (j = 1; j < ENTRY_LEN; j++) {
+ value = pkg->package.elements[j].integer.value;
+ if (value > U32_MAX)
+ return ERR_PTR(-ERANGE);
+
+ disc[i][j - 1] = value;
+ }
+ }
+
+ return no_free_ptr(disc);
+}
+EXPORT_SYMBOL_NS_GPL(pmc_parse_telem_dsd, "INTEL_PMC_CORE");
+
+union acpi_object *pmc_find_telem_guid(union acpi_object *dsd)
+{
+ int i;
+
+ if (!dsd || dsd->type != ACPI_TYPE_PACKAGE)
+ return NULL;
+
+ for (i = 0; i + 1 < dsd->package.count; i += 2) {
+ union acpi_object *uuid_obj, *data_obj;
+ guid_t uuid;
+
+ uuid_obj = &dsd->package.elements[i];
+ data_obj = &dsd->package.elements[i + 1];
+
+ if (uuid_obj->type != ACPI_TYPE_BUFFER ||
+ uuid_obj->buffer.length != 16)
+ continue;
+
+ memcpy(&uuid, uuid_obj->buffer.pointer, 16);
+ if (guid_equal(&uuid, &intel_vsec_guid))
+ return data_obj;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_NS_GPL(pmc_find_telem_guid, "INTEL_PMC_CORE");
+
+static int pmc_pwrm_acpi_probe(struct platform_device *pdev)
+{
+ struct intel_vsec_header header;
+ struct intel_vsec_header *headers[2] = { &header, NULL };
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct intel_vsec_platform_info info = { };
+ struct device *dev = &pdev->dev;
+ union acpi_object *dsd;
+ struct resource *res;
+ acpi_handle handle;
+ acpi_status status;
+
+ handle = ACPI_HANDLE(&pdev->dev);
+ if (!handle)
+ return -ENODEV;
+
+ status = acpi_evaluate_object(handle, "_DSD", NULL, &buf);
+ if (ACPI_FAILURE(status)) {
+ return dev_err_probe(dev, -ENODEV, "Could not evaluate _DSD: %s\n",
+ acpi_format_exception(status));
+ }
+
+ void *dsd_buf __free(pmc_acpi_free) = buf.pointer;
+
+ dsd = pmc_find_telem_guid(dsd_buf);
+ if (!dsd)
+ return -ENODEV;
+
+ acpi_disc_t acpi_disc __free(kfree) = pmc_parse_telem_dsd(dsd, &header);
+ if (IS_ERR(acpi_disc))
+ return PTR_ERR(acpi_disc);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, header.tbir);
+ if (!res)
+ return -EINVAL;
+
+ info.headers = headers;
+ info.caps = VSEC_CAP_TELEMETRY;
+ info.acpi_disc = acpi_disc;
+ info.src = INTEL_VSEC_DISC_ACPI;
+ info.base_addr = res->start;
+
+ return intel_vsec_register(&pdev->dev, &info);
+}
+
+static const struct acpi_device_id pmc_pwrm_acpi_ids[] = {
+ { "INTC1122", 0 }, /* Nova Lake */
+ { "INTC1129", 0 }, /* Nova Lake */
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, pmc_pwrm_acpi_ids);
+
+static struct platform_driver pmc_pwrm_acpi_driver = {
+ .probe = pmc_pwrm_acpi_probe,
+ .driver = {
+ .name = "intel_pmc_pwrm_acpi",
+ .acpi_match_table = ACPI_PTR(pmc_pwrm_acpi_ids),
+ },
+};
+module_platform_driver(pmc_pwrm_acpi_driver);
+
+MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
+MODULE_DESCRIPTION("Intel PMC PWRM ACPI driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("INTEL_VSEC");
diff --git a/drivers/platform/x86/intel/pmc/ssram_telemetry.c b/drivers/platform/x86/intel/pmc/ssram_telemetry.c
index 6f6e83e70fc5..8e280ec525a6 100644
--- a/drivers/platform/x86/intel/pmc/ssram_telemetry.c
+++ b/drivers/platform/x86/intel/pmc/ssram_telemetry.c
@@ -5,7 +5,11 @@
* Copyright (c) 2023, Intel Corporation.
*/
+#include <linux/acpi.h>
+#include <linux/bitmap.h>
+#include <linux/bits.h>
#include <linux/cleanup.h>
+#include <linux/device.h>
#include <linux/intel_vsec.h>
#include <linux/pci.h>
#include <linux/types.h>
@@ -21,11 +25,114 @@
#define SSRAM_PCH_OFFSET 0x60
#define SSRAM_IOE_OFFSET 0x68
#define SSRAM_DEVID_OFFSET 0x70
+#define SSRAM_BASE_ADDR_MASK GENMASK_ULL(63, 3)
+#define SSRAM_PCI_PMC_MASK (BIT(PMC_IDX_MAIN) | BIT(PMC_IDX_IOE) | BIT(PMC_IDX_PCH))
DEFINE_FREE(pmc_ssram_telemetry_iounmap, void __iomem *, if (_T) iounmap(_T))
-static struct pmc_ssram_telemetry *pmc_ssram_telems;
-static bool device_probed;
+enum resource_method {
+ RES_METHOD_PCI,
+ RES_METHOD_ACPI,
+};
+
+struct ssram_type {
+ enum resource_method method;
+ enum pmc_index p_index;
+};
+
+static const struct ssram_type pci_main = {
+ .method = RES_METHOD_PCI,
+ .p_index = PMC_IDX_MAIN,
+};
+
+static const struct ssram_type acpi_main = {
+ .method = RES_METHOD_ACPI,
+ .p_index = PMC_IDX_MAIN,
+};
+
+static const struct ssram_type acpi_pch = {
+ .method = RES_METHOD_ACPI,
+ .p_index = PMC_IDX_PCH,
+};
+
+enum pmc_ssram_state {
+ PMC_SSRAM_UNPROBED = 0,
+ PMC_SSRAM_PROBING,
+ PMC_SSRAM_PRESENT,
+ PMC_SSRAM_ABSENT,
+};
+
+static enum pmc_ssram_state pmc_ssram_state[MAX_NUM_PMC];
+static struct pmc_ssram_telemetry pmc_ssram_telems[MAX_NUM_PMC];
+
+struct pmc_ssram_probe_cache {
+ /* Per-index values staged by probe before publishing globally. */
+ struct pmc_ssram_telemetry telems[MAX_NUM_PMC];
+ /* PMCs this probe instance is responsible for publishing. */
+ unsigned long owned_mask;
+ /* Subset of owned_mask that was discovered successfully. */
+ unsigned long valid_mask;
+};
+
+struct pmc_ssram_drvdata {
+ /* PMCs published by this bound device; used to unpublish on remove. */
+ unsigned long owned_mask;
+};
+
+static inline u64 get_base(void __iomem *addr, u32 offset)
+{
+ return lo_hi_readq(addr + offset) & SSRAM_BASE_ADDR_MASK;
+}
+
+static void pmc_ssram_get_devid_pwrmbase(struct pmc_ssram_probe_cache *probe_cache,
+ void __iomem *ssram, unsigned int pmc_idx)
+{
+ u64 pwrm_base;
+ u16 devid;
+
+ pwrm_base = get_base(ssram, SSRAM_PWRM_OFFSET);
+ devid = readw(ssram + SSRAM_DEVID_OFFSET);
+
+ probe_cache->telems[pmc_idx].base_addr = pwrm_base;
+ probe_cache->telems[pmc_idx].devid = devid;
+}
+
+static void pmc_ssram_publish_absent(unsigned int pmc_idx)
+{
+ /*
+ * Publish only the state without modifying base_addr and devid. This
+ * lets a reader that already observed PRESENT finish copying the
+ * previous values even if unbind concurrently publishes ABSENT. Readers
+ * that observe ABSENT return -ENODEV without accessing data.
+ */
+ smp_store_release(&pmc_ssram_state[pmc_idx], PMC_SSRAM_ABSENT);
+}
+
+static void pmc_ssram_publish_present(struct pmc_ssram_probe_cache *probe_cache,
+ unsigned int pmc_idx)
+{
+ /*
+ * The devid and base_addr fields are read from hardware MMIO registers
+ * whose values are stable for a given PMC index. A reader that observed
+ * PRESENT from an earlier probe can safely copy them while a concurrent
+ * rebind republishes those fields because both probes read the same
+ * hardware values.
+ */
+ pmc_ssram_telems[pmc_idx] = probe_cache->telems[pmc_idx];
+ /*
+ * Publish base_addr and devid before publishing PRESENT. Pairs with the
+ * acquire load in the reader that consumes them after observing PRESENT.
+ */
+ smp_store_release(&pmc_ssram_state[pmc_idx], PMC_SSRAM_PRESENT);
+}
+
+static void pmc_ssram_mark_probing(unsigned long mask)
+{
+ unsigned long bit;
+
+ for_each_set_bit(bit, &mask, MAX_NUM_PMC)
+ WRITE_ONCE(pmc_ssram_state[bit], PMC_SSRAM_PROBING);
+}
static int
pmc_ssram_telemetry_add_pmt(struct pci_dev *pcidev, u64 ssram_base, void __iomem *ssram)
@@ -63,18 +170,15 @@ pmc_ssram_telemetry_add_pmt(struct pci_dev *pcidev, u64 ssram_base, void __iomem
return intel_vsec_register(&pcidev->dev, &info);
}
-static inline u64 get_base(void __iomem *addr, u32 offset)
-{
- return lo_hi_readq(addr + offset) & GENMASK_ULL(63, 3);
-}
-
static int
-pmc_ssram_telemetry_get_pmc(struct pci_dev *pcidev, unsigned int pmc_idx, u32 offset)
+pmc_ssram_telemetry_get_pmc_pci(struct pci_dev *pcidev,
+ struct pmc_ssram_probe_cache *probe_cache,
+ unsigned int pmc_idx, u32 offset)
{
void __iomem __free(pmc_ssram_telemetry_iounmap) *tmp_ssram = NULL;
void __iomem __free(pmc_ssram_telemetry_iounmap) *ssram = NULL;
- u64 ssram_base, pwrm_base;
- u16 devid;
+ u64 ssram_base;
+ int ret;
ssram_base = pci_resource_start(pcidev, 0);
tmp_ssram = ioremap(ssram_base, SSRAM_HDR_SIZE);
@@ -99,14 +203,107 @@ pmc_ssram_telemetry_get_pmc(struct pci_dev *pcidev, unsigned int pmc_idx, u32 of
ssram = no_free_ptr(tmp_ssram);
}
- pwrm_base = get_base(ssram, SSRAM_PWRM_OFFSET);
- devid = readw(ssram + SSRAM_DEVID_OFFSET);
-
- pmc_ssram_telems[pmc_idx].devid = devid;
- pmc_ssram_telems[pmc_idx].base_addr = pwrm_base;
+ pmc_ssram_get_devid_pwrmbase(probe_cache, ssram, pmc_idx);
/* Find and register and PMC telemetry entries */
- return pmc_ssram_telemetry_add_pmt(pcidev, ssram_base, ssram);
+ ret = pmc_ssram_telemetry_add_pmt(pcidev, ssram_base, ssram);
+ if (ret)
+ dev_warn(&pcidev->dev, "could not register PMT\n");
+
+ probe_cache->valid_mask |= BIT(pmc_idx);
+
+ return 0;
+}
+
+static int pmc_ssram_telemetry_pci_init(struct pci_dev *pcidev,
+ struct pmc_ssram_probe_cache *probe_cache)
+{
+ int ret;
+
+ ret = pmc_ssram_telemetry_get_pmc_pci(pcidev, probe_cache, PMC_IDX_MAIN, 0);
+ if (ret)
+ return ret;
+
+ /*
+ * If MAIN PMC enumeration is successful but either IOE or PCH fail,
+ * don't fail probe as the MAIN PMC is still useful as it provides the
+ * global reset and slp_s0 counter access. Failed or missing secondary
+ * PMCs are left out of valid_mask and published as absent.
+ */
+ pmc_ssram_telemetry_get_pmc_pci(pcidev, probe_cache, PMC_IDX_IOE,
+ SSRAM_IOE_OFFSET);
+
+ pmc_ssram_telemetry_get_pmc_pci(pcidev, probe_cache, PMC_IDX_PCH,
+ SSRAM_PCH_OFFSET);
+
+ return 0;
+}
+
+static int pmc_ssram_telemetry_get_pmc_acpi(struct pci_dev *pcidev,
+ struct pmc_ssram_probe_cache *probe_cache,
+ unsigned int pmc_idx)
+{
+ u64 ssram_base;
+
+ ssram_base = pci_resource_start(pcidev, 0);
+ if (!ssram_base)
+ return -ENODEV;
+
+ void __iomem __free(pmc_ssram_telemetry_iounmap) *ssram =
+ ioremap(ssram_base, SSRAM_HDR_SIZE);
+ if (!ssram)
+ return -ENOMEM;
+
+ pmc_ssram_get_devid_pwrmbase(probe_cache, ssram, pmc_idx);
+ probe_cache->valid_mask |= BIT(pmc_idx);
+
+ return 0;
+}
+
+static int pmc_ssram_telemetry_acpi_init(struct pci_dev *pcidev,
+ struct pmc_ssram_probe_cache *probe_cache,
+ enum pmc_index index)
+{
+ struct intel_vsec_header header;
+ struct intel_vsec_header *headers[2] = { &header, NULL };
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct intel_vsec_platform_info info = { };
+ union acpi_object *dsd;
+ acpi_handle handle;
+ acpi_status status;
+ int ret;
+
+ handle = ACPI_HANDLE(&pcidev->dev);
+ if (!handle)
+ return -ENODEV;
+
+ status = acpi_evaluate_object(handle, "_DSD", NULL, &buf);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ void *dsd_buf __free(pmc_acpi_free) = buf.pointer;
+
+ dsd = pmc_find_telem_guid(dsd_buf);
+ if (!dsd)
+ return -ENODEV;
+
+ acpi_disc_t disc __free(kfree) = pmc_parse_telem_dsd(dsd, &header);
+ if (IS_ERR(disc))
+ return PTR_ERR(disc);
+
+ info.headers = headers;
+ info.caps = VSEC_CAP_TELEMETRY;
+ info.acpi_disc = disc;
+ info.src = INTEL_VSEC_DISC_ACPI;
+
+ /* This is an ACPI companion device. PCI BAR will be used for base addr. */
+ info.base_addr = 0;
+
+ ret = intel_vsec_register(&pcidev->dev, &info);
+ if (ret)
+ dev_warn(&pcidev->dev, "could not register PMT\n");
+
+ return pmc_ssram_telemetry_get_pmc_acpi(pcidev, probe_cache, index);
}
/**
@@ -114,48 +311,107 @@ pmc_ssram_telemetry_get_pmc(struct pci_dev *pcidev, unsigned int pmc_idx, u32 of
* @pmc_idx: Index of the PMC
* @pmc_ssram_telemetry: pmc_ssram_telemetry structure to store the PMC information
*
+ * State flow per PMC index:
+ * - PMC_SSRAM_UNPROBED: Probe has not started for this index.
+ * - PMC_SSRAM_PROBING: Probe is currently discovering data for this index.
+ * - PMC_SSRAM_PRESENT: base_addr/devid were published and can be read.
+ * - PMC_SSRAM_ABSENT: No data is available for this index.
+ *
+ * Readers use an acquire load of the state. If state is PRESENT, reads of
+ * base_addr/devid are ordered after the state observation and pair with the
+ * writer's release-store when publishing PRESENT.
+ *
* Return:
* * 0 - Success
* * -EAGAIN - Probe function has not finished yet. Try again.
* * -EINVAL - Invalid pmc_idx
- * * -ENODEV - PMC device is not available
+ * * -ENODEV - PMC device is not available (hardware absent or driver failed to initialize)
*/
int pmc_ssram_telemetry_get_pmc_info(unsigned int pmc_idx,
struct pmc_ssram_telemetry *pmc_ssram_telemetry)
{
+ enum pmc_ssram_state state;
+
+ if (pmc_idx >= MAX_NUM_PMC)
+ return -EINVAL;
+
/*
* PMCs are discovered in probe function. If this function is called before
- * probe function complete, the result would be invalid. Use device_probed
- * variable to avoid this case. Return -EAGAIN to inform the consumer to call
- * again later.
+ * probe function complete, the result would be invalid. Use per-PMC state
+ * to inform the consumer to call again later.
*/
- if (!device_probed)
+ state = smp_load_acquire(&pmc_ssram_state[pmc_idx]);
+ if (state == PMC_SSRAM_UNPROBED || state == PMC_SSRAM_PROBING)
return -EAGAIN;
- /*
- * Memory barrier is used to ensure the correct read order between
- * device_probed variable and PMC info.
- */
- smp_rmb();
- if (pmc_idx >= MAX_NUM_PMC)
- return -EINVAL;
-
- if (!pmc_ssram_telems || !pmc_ssram_telems[pmc_idx].devid)
+ if (state == PMC_SSRAM_ABSENT)
return -ENODEV;
+ /*
+ * Acquire semantics order reads of devid and base_addr after observing
+ * PRESENT and pair with the writer's release-store.
+ */
pmc_ssram_telemetry->devid = pmc_ssram_telems[pmc_idx].devid;
pmc_ssram_telemetry->base_addr = pmc_ssram_telems[pmc_idx].base_addr;
return 0;
}
EXPORT_SYMBOL_GPL(pmc_ssram_telemetry_get_pmc_info);
-static int intel_pmc_ssram_telemetry_probe(struct pci_dev *pcidev, const struct pci_device_id *id)
+static void pmc_ssram_publish_absent_mask(unsigned long mask)
+{
+ unsigned long bit;
+
+ for_each_set_bit(bit, &mask, MAX_NUM_PMC)
+ pmc_ssram_publish_absent(bit);
+}
+
+static void pmc_ssram_publish_telems(struct pmc_ssram_probe_cache *probe_cache, int ret)
{
+ unsigned long bit;
+
+ /* If probe failed, all owned indexes become absent for readers. */
+ if (ret) {
+ pmc_ssram_publish_absent_mask(probe_cache->owned_mask);
+ return;
+ }
+
+ /* Publish each owned index independently based on discovery result. */
+ for_each_set_bit(bit, &probe_cache->owned_mask, MAX_NUM_PMC) {
+ if (probe_cache->valid_mask & BIT(bit))
+ pmc_ssram_publish_present(probe_cache, bit);
+ else
+ pmc_ssram_publish_absent(bit);
+ }
+}
+
+static int pmc_ssram_telemetry_probe(struct pci_dev *pcidev, const struct pci_device_id *id)
+{
+ struct pmc_ssram_probe_cache probe_cache = {};
+ struct pmc_ssram_drvdata *drvdata;
+ const struct ssram_type *ssram_type;
+ enum resource_method method;
+ enum pmc_index index;
int ret;
- pmc_ssram_telems = devm_kzalloc(&pcidev->dev, sizeof(*pmc_ssram_telems) * MAX_NUM_PMC,
- GFP_KERNEL);
- if (!pmc_ssram_telems) {
+ ssram_type = (const struct ssram_type *)id->driver_data;
+ if (!ssram_type) {
+ dev_dbg(&pcidev->dev, "missing driver data\n");
+ return -EINVAL;
+ }
+
+ index = ssram_type->p_index;
+ method = ssram_type->method;
+ if (method == RES_METHOD_PCI)
+ probe_cache.owned_mask = SSRAM_PCI_PMC_MASK;
+ else if (method == RES_METHOD_ACPI)
+ probe_cache.owned_mask = BIT(index);
+ else
+ return -EINVAL;
+
+ pmc_ssram_mark_probing(probe_cache.owned_mask);
+
+ drvdata = devm_kzalloc(&pcidev->dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata) {
ret = -ENOMEM;
goto probe_finish;
}
@@ -166,43 +422,67 @@ static int intel_pmc_ssram_telemetry_probe(struct pci_dev *pcidev, const struct
goto probe_finish;
}
- ret = pmc_ssram_telemetry_get_pmc(pcidev, PMC_IDX_MAIN, 0);
- if (ret)
- goto probe_finish;
+ if (method == RES_METHOD_PCI)
+ ret = pmc_ssram_telemetry_pci_init(pcidev, &probe_cache);
+ else if (method == RES_METHOD_ACPI)
+ ret = pmc_ssram_telemetry_acpi_init(pcidev, &probe_cache, index);
+ else
+ ret = -EINVAL;
- pmc_ssram_telemetry_get_pmc(pcidev, PMC_IDX_IOE, SSRAM_IOE_OFFSET);
- pmc_ssram_telemetry_get_pmc(pcidev, PMC_IDX_PCH, SSRAM_PCH_OFFSET);
+ if (!ret) {
+ drvdata->owned_mask = probe_cache.owned_mask;
+ pci_set_drvdata(pcidev, drvdata);
+ }
probe_finish:
- /*
- * Memory barrier is used to ensure the correct write order between PMC info
- * and device_probed variable.
- */
- smp_wmb();
- device_probed = true;
+ pmc_ssram_publish_telems(&probe_cache, ret);
+
return ret;
}
-static const struct pci_device_id intel_pmc_ssram_telemetry_pci_ids[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_MTL_SOCM) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_ARL_SOCS) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_ARL_SOCM) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_LNL_SOCM) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_PTL_PCDH) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_PTL_PCDP) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_WCL_PCDN) },
+static void pmc_ssram_telemetry_remove(struct pci_dev *pcidev)
+{
+ struct pmc_ssram_drvdata *drvdata = pci_get_drvdata(pcidev);
+
+ if (drvdata)
+ pmc_ssram_publish_absent_mask(drvdata->owned_mask);
+}
+
+static const struct pci_device_id pmc_ssram_telemetry_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_MTL_SOCM),
+ .driver_data = (kernel_ulong_t)&pci_main },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_ARL_SOCS),
+ .driver_data = (kernel_ulong_t)&pci_main },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_ARL_SOCM),
+ .driver_data = (kernel_ulong_t)&pci_main },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_LNL_SOCM),
+ .driver_data = (kernel_ulong_t)&pci_main },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_PTL_PCDH),
+ .driver_data = (kernel_ulong_t)&pci_main },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_PTL_PCDP),
+ .driver_data = (kernel_ulong_t)&pci_main },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_WCL_PCDN),
+ .driver_data = (kernel_ulong_t)&pci_main },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_NVL_PCDH),
+ .driver_data = (kernel_ulong_t)&acpi_main },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_NVL_PCDS),
+ .driver_data = (kernel_ulong_t)&acpi_main },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PMC_DEVID_NVL_PCHS),
+ .driver_data = (kernel_ulong_t)&acpi_pch },
{ }
};
-MODULE_DEVICE_TABLE(pci, intel_pmc_ssram_telemetry_pci_ids);
+MODULE_DEVICE_TABLE(pci, pmc_ssram_telemetry_pci_ids);
-static struct pci_driver intel_pmc_ssram_telemetry_driver = {
+static struct pci_driver pmc_ssram_telemetry_driver = {
.name = "intel_pmc_ssram_telemetry",
- .id_table = intel_pmc_ssram_telemetry_pci_ids,
- .probe = intel_pmc_ssram_telemetry_probe,
+ .id_table = pmc_ssram_telemetry_pci_ids,
+ .probe = pmc_ssram_telemetry_probe,
+ .remove = pmc_ssram_telemetry_remove,
};
-module_pci_driver(intel_pmc_ssram_telemetry_driver);
+module_pci_driver(pmc_ssram_telemetry_driver);
MODULE_IMPORT_NS("INTEL_VSEC");
+MODULE_IMPORT_NS("INTEL_PMC_CORE");
MODULE_AUTHOR("Xi Pardee <xi.pardee@intel.com>");
MODULE_DESCRIPTION("Intel PMC SSRAM Telemetry driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/intel/pmc/wcl.c b/drivers/platform/x86/intel/pmc/wcl.c
index a45707e6364f..d34ac916907d 100644
--- a/drivers/platform/x86/intel/pmc/wcl.c
+++ b/drivers/platform/x86/intel/pmc/wcl.c
@@ -469,6 +469,8 @@ static struct pmc_info wcl_pmc_info_list[] = {
{}
};
+static const u8 wcl_pmc_list[] = {PMC_IDX_MAIN};
+
#define WCL_NPU_PCI_DEV 0xfd3e
/*
@@ -493,12 +495,14 @@ static int wcl_core_init(struct pmc_dev *pmcdev, struct pmc_dev_info *pmc_dev_in
}
struct pmc_dev_info wcl_pmc_dev = {
- .pci_func = 2,
.regmap_list = wcl_pmc_info_list,
+ .num_pmcs = ARRAY_SIZE(wcl_pmc_list),
+ .pmc_list = wcl_pmc_list,
.map = &wcl_pcdn_reg_map,
.sub_req_show = &pmc_core_substate_blk_req_fops,
.suspend = cnl_suspend,
.resume = wcl_resume,
.init = wcl_core_init,
.sub_req = pmc_core_pmt_get_blk_sub_req,
+ .ssram_hidden = true,
};
diff --git a/drivers/platform/x86/intel/pmt/class.c b/drivers/platform/x86/intel/pmt/class.c
index b4c9964df807..d0ab8e33c62a 100644
--- a/drivers/platform/x86/intel/pmt/class.c
+++ b/drivers/platform/x86/intel/pmt/class.c
@@ -12,6 +12,7 @@
#include <linux/log2.h>
#include <linux/intel_vsec.h>
#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/pci.h>
@@ -204,13 +205,14 @@ struct class intel_pmt_class = {
};
EXPORT_SYMBOL_GPL(intel_pmt_class);
-static int intel_pmt_populate_entry(struct intel_pmt_entry *entry,
- struct intel_vsec_device *ivdev,
- struct resource *disc_res)
+static int pmt_resolve_access_pci(struct intel_pmt_entry *entry,
+ struct intel_vsec_device *ivdev,
+ int idx)
{
struct pci_dev *pci_dev = to_pci_dev(ivdev->dev);
struct device *dev = &ivdev->auxdev.dev;
struct intel_pmt_header *header = &entry->header;
+ struct resource *disc_res;
u8 bir;
/*
@@ -235,6 +237,7 @@ static int intel_pmt_populate_entry(struct intel_pmt_entry *entry,
* For access_type LOCAL, the base address is as follows:
* base address = end of discovery region + base offset
*/
+ disc_res = &ivdev->resource[idx];
entry->base_addr = disc_res->end + 1 + header->base_offset;
/*
@@ -284,6 +287,81 @@ static int intel_pmt_populate_entry(struct intel_pmt_entry *entry,
}
entry->pcidev = pci_dev;
+
+ return 0;
+}
+
+static int pmt_resolve_access_acpi(struct intel_pmt_entry *entry,
+ struct intel_vsec_device *ivdev)
+{
+ struct pci_dev *pci_dev = NULL;
+ struct device *dev = &ivdev->auxdev.dev;
+ struct intel_pmt_header *header = &entry->header;
+ u8 bir;
+
+ if (dev_is_pci(ivdev->dev))
+ pci_dev = to_pci_dev(ivdev->dev);
+
+ /*
+ * The base offset should always be 8 byte aligned.
+ *
+ * For non-local access types the lower 3 bits of base offset
+ * contains the index of the base address register where the
+ * telemetry can be found.
+ */
+ bir = GET_BIR(header->base_offset);
+
+ switch (header->access_type) {
+ case ACCESS_BARID:
+ /* ACPI platform drivers use base_addr */
+ if (ivdev->base_addr) {
+ entry->base_addr = ivdev->base_addr +
+ GET_ADDRESS(header->base_offset);
+ break;
+ }
+
+ /* If base_addr is not provided, then this is an ACPI companion device */
+ if (!pci_dev) {
+ dev_err(dev, "ACCESS_BARID requires PCI BAR resources or base_addr\n");
+ return -EINVAL;
+ }
+
+ entry->base_addr = pci_resource_start(pci_dev, bir) +
+ GET_ADDRESS(header->base_offset);
+ break;
+ default:
+ dev_err(dev, "Unsupported access type %d for ACPI based PMT\n",
+ header->access_type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int intel_pmt_populate_entry(struct intel_pmt_entry *entry,
+ struct intel_vsec_device *ivdev,
+ int idx)
+{
+ struct intel_pmt_header *header = &entry->header;
+ struct device *dev = &ivdev->auxdev.dev;
+ int ret;
+
+ switch (ivdev->src) {
+ case INTEL_VSEC_DISC_PCI:
+ ret = pmt_resolve_access_pci(entry, ivdev, idx);
+ if (ret)
+ return ret;
+ break;
+ case INTEL_VSEC_DISC_ACPI:
+ ret = pmt_resolve_access_acpi(entry, ivdev);
+ if (ret)
+ return ret;
+ break;
+ default:
+ dev_err(dev, "Unknown discovery source: %d\n", ivdev->src);
+ return -EINVAL;
+ }
+
entry->guid = header->guid;
entry->size = header->size;
entry->cb = ivdev->priv_data;
@@ -368,24 +446,84 @@ fail_dev_create:
return ret;
}
+static int pmt_get_headers(struct intel_vsec_device *ivdev, int idx,
+ struct intel_pmt_entry *entry)
+{
+ struct device *dev = &ivdev->auxdev.dev;
+ size_t header_bytes = sizeof(entry->disc_header);
+
+ switch (ivdev->src) {
+ case INTEL_VSEC_DISC_PCI: {
+ struct resource *disc_res = &ivdev->resource[idx];
+ void __iomem *disc_table;
+
+ disc_table = devm_ioremap_resource(dev, disc_res);
+ if (IS_ERR(disc_table))
+ return PTR_ERR(disc_table);
+
+ /*
+ * The mapped resource is sized by the namespace's DVSEC
+ * entry_size (in dwords), which can be less than the default
+ * size (e.g. telemetry uses entry_size = 3, 12 bytes). Cap the
+ * copy to resource_size() to avoid reading past the mapped
+ * region.
+ */
+ memset(entry->disc_header, 0, header_bytes);
+ memcpy_fromio(entry->disc_header, disc_table,
+ min(header_bytes, resource_size(disc_res)));
+
+ /* Used by crashlog driver */
+ entry->disc_table = disc_table;
+
+ return 0;
+ }
+ case INTEL_VSEC_DISC_ACPI: {
+ memcpy(entry->disc_header, &ivdev->acpi_disc[idx][0], header_bytes);
+ /*
+ * No MMIO mapping exists on the ACPI source path; the cached
+ * headers are the only view of the discovery record. Consumers
+ * that dereference disc_table (e.g. crashlog) must therefore
+ * only be wired to namespaces backed by INTEL_VSEC_DISC_PCI.
+ */
+ entry->disc_table = NULL;
+
+ return 0;
+ }
+ default:
+ dev_err(dev, "Unknown discovery source type: %d\n", ivdev->src);
+ break;
+ }
+
+ return -EINVAL;
+}
+
int intel_pmt_dev_create(struct intel_pmt_entry *entry, struct intel_pmt_namespace *ns,
struct intel_vsec_device *intel_vsec_dev, int idx)
{
struct device *dev = &intel_vsec_dev->auxdev.dev;
- struct resource *disc_res;
int ret;
- disc_res = &intel_vsec_dev->resource[idx];
+ ret = pmt_get_headers(intel_vsec_dev, idx, entry);
+ if (ret)
+ return ret;
- entry->disc_table = devm_ioremap_resource(dev, disc_res);
- if (IS_ERR(entry->disc_table))
- return PTR_ERR(entry->disc_table);
+ if (ns->pmt_pre_decode) {
+ ret = ns->pmt_pre_decode(intel_vsec_dev, entry);
+ if (ret)
+ return ret;
+ }
ret = ns->pmt_header_decode(entry, dev);
if (ret)
return ret;
- ret = intel_pmt_populate_entry(entry, intel_vsec_dev, disc_res);
+ if (ns->pmt_post_decode) {
+ ret = ns->pmt_post_decode(intel_vsec_dev, entry);
+ if (ret)
+ return ret;
+ }
+
+ ret = intel_pmt_populate_entry(entry, intel_vsec_dev, idx);
if (ret)
return ret;
diff --git a/drivers/platform/x86/intel/pmt/class.h b/drivers/platform/x86/intel/pmt/class.h
index 1ae56a5baad2..a0ece4fc3837 100644
--- a/drivers/platform/x86/intel/pmt/class.h
+++ b/drivers/platform/x86/intel/pmt/class.h
@@ -37,12 +37,14 @@ struct intel_pmt_header {
u32 size;
u32 guid;
u8 access_type;
+ u8 telem_type;
};
struct intel_pmt_entry {
struct telem_endpoint *ep;
struct pci_dev *pcidev;
struct intel_pmt_header header;
+ u32 disc_header[PMT_DISC_DWORDS];
struct bin_attribute pmt_bin_attr;
const struct attribute_group *attr_grp;
struct kobject *kobj;
@@ -62,6 +64,10 @@ struct intel_pmt_namespace {
struct xarray *xa;
int (*pmt_header_decode)(struct intel_pmt_entry *entry,
struct device *dev);
+ int (*pmt_pre_decode)(struct intel_vsec_device *ivdev,
+ struct intel_pmt_entry *entry);
+ int (*pmt_post_decode)(struct intel_vsec_device *ivdev,
+ struct intel_pmt_entry *entry);
int (*pmt_add_endpoint)(struct intel_vsec_device *ivdev,
struct intel_pmt_entry *entry);
};
diff --git a/drivers/platform/x86/intel/pmt/crashlog.c b/drivers/platform/x86/intel/pmt/crashlog.c
index b0393c9c5b4b..f936daf99e4d 100644
--- a/drivers/platform/x86/intel/pmt/crashlog.c
+++ b/drivers/platform/x86/intel/pmt/crashlog.c
@@ -496,11 +496,9 @@ static const struct crashlog_info *select_crashlog_info(u32 type, u32 version)
return &crashlog_type1_ver2;
}
-static int pmt_crashlog_header_decode(struct intel_pmt_entry *entry,
- struct device *dev)
+static int pmt_crashlog_pre_decode(struct intel_vsec_device *ivdev,
+ struct intel_pmt_entry *entry)
{
- void __iomem *disc_table = entry->disc_table;
- struct intel_pmt_header *header = &entry->header;
struct crashlog_entry *crashlog;
u32 version;
u32 type;
@@ -513,6 +511,16 @@ static int pmt_crashlog_header_decode(struct intel_pmt_entry *entry,
mutex_init(&crashlog->control_mutex);
crashlog->info = select_crashlog_info(type, version);
+ entry->attr_grp = crashlog->info->attr_grp;
+
+ return 0;
+}
+
+static int pmt_crashlog_header_decode(struct intel_pmt_entry *entry,
+ struct device *dev)
+{
+ void __iomem *disc_table = entry->disc_table;
+ struct intel_pmt_header *header = &entry->header;
header->access_type = GET_ACCESS(readl(disc_table));
header->guid = readl(disc_table + GUID_OFFSET);
@@ -521,8 +529,6 @@ static int pmt_crashlog_header_decode(struct intel_pmt_entry *entry,
/* Size is measured in DWORDS, but accessor returns bytes */
header->size = GET_SIZE(readl(disc_table + SIZE_OFFSET));
- entry->attr_grp = crashlog->info->attr_grp;
-
return 0;
}
@@ -530,6 +536,7 @@ static DEFINE_XARRAY_ALLOC(crashlog_array);
static struct intel_pmt_namespace pmt_crashlog_ns = {
.name = "crashlog",
.xa = &crashlog_array,
+ .pmt_pre_decode = pmt_crashlog_pre_decode,
.pmt_header_decode = pmt_crashlog_header_decode,
};
diff --git a/drivers/platform/x86/intel/pmt/telemetry.c b/drivers/platform/x86/intel/pmt/telemetry.c
index bdc7c24a3678..953f35b6daec 100644
--- a/drivers/platform/x86/intel/pmt/telemetry.c
+++ b/drivers/platform/x86/intel/pmt/telemetry.c
@@ -58,14 +58,9 @@ struct pmt_telem_priv {
struct intel_pmt_entry entry[];
};
-static bool pmt_telem_region_overlaps(struct intel_pmt_entry *entry,
- struct device *dev)
+static bool pmt_telem_region_overlaps(struct device *dev, u32 guid, u32 type)
{
- u32 guid = readl(entry->disc_table + TELEM_GUID_OFFSET);
-
if (intel_pmt_is_early_client_hw(dev)) {
- u32 type = TELEM_TYPE(readl(entry->disc_table));
-
if ((type == TELEM_TYPE_PUNIT_FIXED) ||
(guid == TELEM_CLIENT_FIXED_BLOCK_GUID))
return true;
@@ -77,18 +72,28 @@ static bool pmt_telem_region_overlaps(struct intel_pmt_entry *entry,
static int pmt_telem_header_decode(struct intel_pmt_entry *entry,
struct device *dev)
{
- void __iomem *disc_table = entry->disc_table;
struct intel_pmt_header *header = &entry->header;
+ u32 *disc_header = entry->disc_header;
- if (pmt_telem_region_overlaps(entry, dev))
- return 1;
-
- header->access_type = TELEM_ACCESS(readl(disc_table));
- header->guid = readl(disc_table + TELEM_GUID_OFFSET);
- header->base_offset = readl(disc_table + TELEM_BASE_OFFSET);
+ header->access_type = TELEM_ACCESS(disc_header[0]);
+ header->guid = disc_header[1];
+ header->base_offset = disc_header[2];
/* Size is measured in DWORDS, but accessor returns bytes */
- header->size = TELEM_SIZE(readl(disc_table));
+ header->size = TELEM_SIZE(disc_header[0]);
+ header->telem_type = TELEM_TYPE(disc_header[0]);
+
+ return 0;
+}
+
+static int pmt_telem_post_decode(struct intel_vsec_device *ivdev,
+ struct intel_pmt_entry *entry)
+{
+ struct intel_pmt_header *header = &entry->header;
+ struct device *dev = &ivdev->auxdev.dev;
+
+ if (pmt_telem_region_overlaps(dev, header->guid, header->telem_type))
+ return 1;
/*
* Some devices may expose non-functioning entries that are
@@ -131,6 +136,7 @@ static struct intel_pmt_namespace pmt_telem_ns = {
.name = "telem",
.xa = &telem_array,
.pmt_header_decode = pmt_telem_header_decode,
+ .pmt_post_decode = pmt_telem_post_decode,
.pmt_add_endpoint = pmt_telem_add_endpoint,
};
diff --git a/drivers/platform/x86/intel/punit_ipc.c b/drivers/platform/x86/intel/punit_ipc.c
index 14513010daad..6d770b950dfb 100644
--- a/drivers/platform/x86/intel/punit_ipc.c
+++ b/drivers/platform/x86/intel/punit_ipc.c
@@ -13,7 +13,6 @@
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
diff --git a/drivers/platform/x86/intel/rst.c b/drivers/platform/x86/intel/rst.c
index 4bd10927aad9..bb19f0d89305 100644
--- a/drivers/platform/x86/intel/rst.c
+++ b/drivers/platform/x86/intel/rst.c
@@ -102,9 +102,13 @@ static struct device_attribute irst_timeout_attr = {
static int irst_probe(struct platform_device *pdev)
{
- struct acpi_device *acpi = ACPI_COMPANION(&pdev->dev);
+ struct acpi_device *acpi;
int error;
+ acpi = ACPI_COMPANION(&pdev->dev);
+ if (!acpi)
+ return -ENODEV;
+
error = device_create_file(&acpi->dev, &irst_timeout_attr);
if (unlikely(error))
return error;
diff --git a/drivers/platform/x86/intel/smartconnect.c b/drivers/platform/x86/intel/smartconnect.c
index 4d866b6366d6..71e91ac60e5d 100644
--- a/drivers/platform/x86/intel/smartconnect.c
+++ b/drivers/platform/x86/intel/smartconnect.c
@@ -12,10 +12,14 @@ MODULE_LICENSE("GPL");
static int smartconnect_acpi_probe(struct platform_device *pdev)
{
- acpi_handle handle = ACPI_HANDLE(&pdev->dev);
unsigned long long value;
+ acpi_handle handle;
acpi_status status;
+ handle = ACPI_HANDLE(&pdev->dev);
+ if (!handle)
+ return -ENODEV;
+
status = acpi_evaluate_integer(handle, "GAOS", NULL, &value);
if (ACPI_FAILURE(status))
return -EINVAL;
diff --git a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c
index b804cb753f94..bb0d0b8fc54a 100644
--- a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c
+++ b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c
@@ -336,8 +336,11 @@ static int sst_add_perf_profiles(struct auxiliary_device *auxdev,
int i;
pd_info->perf_levels = devm_kcalloc(dev, levels, sizeof(struct perf_level), GFP_KERNEL);
- if (!pd_info->perf_levels)
- return 0;
+ if (!pd_info->perf_levels) {
+ pd_info->pp_header.allowed_level_mask = 0;
+ pd_info->pp_header.level_en_mask = 0;
+ return -ENOMEM;
+ }
pd_info->ratio_unit = pd_info->pp_header.ratio_unit;
pd_info->avx_levels = SST_MAX_AVX_LEVELS;
@@ -367,7 +370,7 @@ static int sst_add_perf_profiles(struct auxiliary_device *auxdev,
static int sst_main(struct auxiliary_device *auxdev, struct tpmi_per_power_domain_info *pd_info)
{
struct device *dev = &auxdev->dev;
- int i, mask, levels;
+ int i, ret, mask, levels;
*((u64 *)&pd_info->sst_header) = readq(pd_info->sst_base);
pd_info->sst_header.cp_offset *= 8;
@@ -399,8 +402,12 @@ static int sst_main(struct auxiliary_device *auxdev, struct tpmi_per_power_domai
levels = i;
mask <<= 1;
}
+
+ ret = sst_add_perf_profiles(auxdev, pd_info, levels + 1);
+ if (ret)
+ return ret;
+
pd_info->max_level = levels;
- sst_add_perf_profiles(auxdev, pd_info, levels + 1);
return 0;
}
@@ -558,7 +565,7 @@ static bool disable_dynamic_sst_features(void)
{
u64 value;
- if (!static_cpu_has(X86_FEATURE_HWP))
+ if (!cpu_feature_enabled(X86_FEATURE_HWP))
return true;
rdmsrq(MSR_PM_ENABLE, value);
@@ -599,6 +606,9 @@ static bool disable_dynamic_sst_features(void)
#define SST_CP_PRIORITY_TYPE_START 1
#define SST_CP_PRIORITY_TYPE_WIDTH 1
+#define SST_CP_MAX_ENABLE 1
+#define SST_CP_MAX_PRIORITY_TYPE 1
+
static long isst_if_core_power_state(void __user *argp)
{
struct tpmi_per_power_domain_info *power_domain_info;
@@ -618,6 +628,10 @@ static long isst_if_core_power_state(void __user *argp)
if (power_domain_info->write_blocked || !capable(CAP_SYS_ADMIN))
return -EPERM;
+ if (core_power.enable > SST_CP_MAX_ENABLE ||
+ core_power.priority_type > SST_CP_MAX_PRIORITY_TYPE)
+ return -EINVAL;
+
_write_cp_info("cp_enable", core_power.enable, SST_CP_CONTROL_OFFSET,
SST_CP_ENABLE_START, SST_CP_ENABLE_WIDTH, SST_MUL_FACTOR_NONE)
_write_cp_info("cp_prio_type", core_power.priority_type, SST_CP_CONTROL_OFFSET,
@@ -649,6 +663,11 @@ static long isst_if_core_power_state(void __user *argp)
#define SST_CLOS_CONFIG_MAX_START 16
#define SST_CLOS_CONFIG_MAX_WIDTH 8
+#define SST_MAX_CLOS 3
+
+#define SST_MAX_FREQ 0xff
+#define SST_CLOS_MAX_PRIORITY 0x0f
+
static long isst_if_clos_param(void __user *argp)
{
struct tpmi_per_power_domain_info *power_domain_info;
@@ -657,6 +676,9 @@ static long isst_if_clos_param(void __user *argp)
if (copy_from_user(&clos_param, argp, sizeof(clos_param)))
return -EFAULT;
+ if (clos_param.clos > SST_MAX_CLOS)
+ return -EINVAL;
+
power_domain_info = get_instance(clos_param.socket_id, clos_param.power_domain_id);
if (!power_domain_info)
return -EINVAL;
@@ -665,6 +687,15 @@ static long isst_if_clos_param(void __user *argp)
if (power_domain_info->write_blocked || !capable(CAP_SYS_ADMIN))
return -EPERM;
+ if (!in_range(clos_param.min_freq_mhz / SST_MUL_FACTOR_FREQ, 0, SST_MAX_FREQ + 1))
+ return -EINVAL;
+
+ if (!in_range(clos_param.max_freq_mhz / SST_MUL_FACTOR_FREQ, 0, SST_MAX_FREQ + 1))
+ return -EINVAL;
+
+ if (!in_range(clos_param.prop_prio, 0, SST_CLOS_MAX_PRIORITY + 1))
+ return -EINVAL;
+
_write_cp_info("clos.min_freq", clos_param.min_freq_mhz,
(SST_CLOS_CONFIG_0_OFFSET + clos_param.clos * SST_REG_SIZE),
SST_CLOS_CONFIG_MIN_START, SST_CLOS_CONFIG_MIN_WIDTH,
@@ -703,6 +734,8 @@ static long isst_if_clos_param(void __user *argp)
#define SST_CLOS_ASSOC_CPUS_PER_REG 16
#define SST_CLOS_ASSOC_BITS_PER_CPU 4
+#define SST_CLOS_ASSOC_MAX_LOGICAL_CPU 63
+
static long isst_if_clos_assoc(void __user *argp)
{
struct isst_if_clos_assoc_cmds assoc_cmds;
@@ -729,7 +762,13 @@ static long isst_if_clos_assoc(void __user *argp)
if (copy_from_user(&clos_assoc, ptr, sizeof(clos_assoc)))
return -EFAULT;
- if (clos_assoc.socket_id > topology_max_packages())
+ if (clos_assoc.clos > SST_MAX_CLOS)
+ return -EINVAL;
+
+ if (clos_assoc.socket_id >= topology_max_packages())
+ return -EINVAL;
+
+ if (clos_assoc.logical_cpu > SST_CLOS_ASSOC_MAX_LOGICAL_CPU)
return -EINVAL;
cpu = clos_assoc.logical_cpu;
@@ -747,6 +786,8 @@ static long isst_if_clos_assoc(void __user *argp)
pkg_id = clos_assoc.socket_id;
sst_inst = isst_common.sst_inst[pkg_id];
+ if (!sst_inst)
+ return -EINVAL;
punit_id = map_partition_power_domain_id(sst_inst, punit_id, &part);
if (punit_id < 0)
@@ -845,6 +886,7 @@ static long isst_if_clos_assoc(void __user *argp)
#define SST_PP_FEATURE_STATE_START 8
#define SST_PP_FEATURE_STATE_WIDTH 8
+#define SST_PP_FEATURE_STATE_VALID_MASK GENMASK(1, 0)
#define SST_BF_FEATURE_SUPPORTED_START 12
#define SST_BF_FEATURE_SUPPORTED_WIDTH 1
@@ -877,7 +919,7 @@ static int isst_if_get_perf_level(void __user *argp)
SST_PP_FEATURE_STATE_START, SST_PP_FEATURE_STATE_WIDTH, SST_MUL_FACTOR_NONE)
perf_level.enabled = !!(power_domain_info->sst_header.cap_mask & BIT(1));
- level_mask = perf_level.level_mask;
+ level_mask = perf_level.level_mask & power_domain_info->pp_header.level_en_mask;
perf_level.sst_bf_support = 0;
for_each_set_bit(level, &level_mask, BITS_PER_BYTE) {
/*
@@ -932,6 +974,9 @@ static int isst_if_set_perf_level(void __user *argp)
if (!power_domain_info)
return -EINVAL;
+ if (perf_level.level > power_domain_info->max_level)
+ return -EINVAL;
+
if (power_domain_info->write_blocked || !capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -995,6 +1040,9 @@ static int isst_if_set_perf_feature(void __user *argp)
if (power_domain_info->write_blocked || !capable(CAP_SYS_ADMIN))
return -EPERM;
+ if (perf_feature.feature & ~SST_PP_FEATURE_STATE_VALID_MASK)
+ return -EINVAL;
+
_write_pp_info("perf_feature", perf_feature.feature, SST_PP_CONTROL_OFFSET,
SST_PP_FEATURE_STATE_START, SST_PP_FEATURE_STATE_WIDTH,
SST_MUL_FACTOR_NONE)
@@ -1261,6 +1309,12 @@ static int isst_if_get_perf_level_mask(void __user *argp)
if (!power_domain_info)
return -EINVAL;
+ if (cpumask.level > power_domain_info->max_level)
+ return -EINVAL;
+
+ if (!(power_domain_info->pp_header.level_en_mask & BIT(cpumask.level)))
+ return -EINVAL;
+
_read_pp_level_info("mask", mask, cpumask.level, SST_PP_INFO_2_OFFSET,
SST_PP_RSLVD_CORE_MASK_START, SST_PP_RSLVD_CORE_MASK_WIDTH,
SST_MUL_FACTOR_NONE)
@@ -1306,6 +1360,9 @@ static int isst_if_get_base_freq_info(void __user *argp)
if (base_freq.level > power_domain_info->max_level)
return -EINVAL;
+ if (!(power_domain_info->pp_header.level_en_mask & BIT(base_freq.level)))
+ return -EINVAL;
+
_read_bf_level_info("p1_high", base_freq.high_base_freq_mhz, base_freq.level,
SST_BF_INFO_0_OFFSET, SST_BF_P1_HIGH_START, SST_BF_P1_HIGH_WIDTH,
SST_MUL_FACTOR_FREQ)
@@ -1342,6 +1399,12 @@ static int isst_if_get_base_freq_mask(void __user *argp)
if (!power_domain_info)
return -EINVAL;
+ if (cpumask.level > power_domain_info->max_level)
+ return -EINVAL;
+
+ if (!(power_domain_info->pp_header.level_en_mask & BIT(cpumask.level)))
+ return -EINVAL;
+
_read_bf_level_info("BF-cpumask", mask, cpumask.level, SST_BF_INFO_1_OFFSET,
P1_HI_CORE_MASK_START, P1_HI_CORE_MASK_WIDTH,
SST_MUL_FACTOR_NONE)
@@ -1370,6 +1433,8 @@ static int isst_if_get_tpmi_instance_count(void __user *argp)
return -EINVAL;
sst_inst = isst_common.sst_inst[tpmi_inst.socket_id];
+ if (!sst_inst)
+ return -EINVAL;
tpmi_inst.count = isst_instance_count(sst_inst);
@@ -1437,6 +1502,9 @@ static int isst_if_get_turbo_freq_info(void __user *argp)
if (turbo_freq.level > power_domain_info->max_level)
return -EINVAL;
+ if (!(power_domain_info->pp_header.level_en_mask & BIT(turbo_freq.level)))
+ return -EINVAL;
+
turbo_freq.max_buckets = TRL_MAX_BUCKETS;
turbo_freq.max_trl_levels = TRL_MAX_LEVELS;
turbo_freq.max_clip_freqs = SST_TF_MAX_LP_CLIP_RATIOS;
@@ -1804,7 +1872,7 @@ process_pp_resume:
if (!(pd_info->sst_header.cap_mask & SST_PP_CAP_PP_ENABLE))
continue;
- writeq(pd_info->saved_pp_control, power_domain_info->sst_base +
+ writeq(pd_info->saved_pp_control, pd_info->sst_base +
pd_info->sst_header.pp_offset + SST_PP_CONTROL_OFFSET);
}
}
diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
index 7070c94324e0..4bcafedf68ef 100644
--- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
+++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
@@ -29,6 +29,13 @@ static ssize_t show_domain_id(struct kobject *kobj, struct kobj_attribute *attr,
return sysfs_emit(buf, "%u\n", data->domain_id);
}
+static ssize_t show_instance_id(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ struct uncore_data *data = container_of(attr, struct uncore_data, instance_id_kobj_attr);
+
+ return sysfs_emit(buf, "%u\n", data->instance_id);
+}
+
static ssize_t show_fabric_cluster_id(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
struct uncore_data *data = container_of(attr, struct uncore_data, fabric_cluster_id_kobj_attr);
@@ -200,6 +207,9 @@ static int create_attr_group(struct uncore_data *data, char *name)
if (data->domain_id != UNCORE_DOMAIN_ID_INVALID) {
init_attribute_root_ro(domain_id);
data->uncore_attrs[index++] = &data->domain_id_kobj_attr.attr;
+ init_attribute_root_ro(instance_id);
+ data->uncore_attrs[index++] = &data->instance_id_kobj_attr.attr;
+
init_attribute_root_ro(fabric_cluster_id);
data->uncore_attrs[index++] = &data->fabric_cluster_id_kobj_attr.attr;
init_attribute_root_ro(package_id);
@@ -268,22 +278,27 @@ int uncore_freq_add_entry(struct uncore_data *data, int cpu)
if (ret < 0)
goto uncore_unlock;
- data->instance_id = ret;
+ data->seqnum_id = ret;
scnprintf(data->name, sizeof(data->name), "uncore%02d", ret);
} else {
scnprintf(data->name, sizeof(data->name), "package_%02d_die_%02d",
data->package_id, data->die_id);
}
+ /*
+ * Set the control CPU before any read path so entry recreation after CPU
+ * hotplug can populate read-only attributes from the new online CPU.
+ */
+ data->control_cpu = cpu;
uncore_read(data, &data->initial_min_freq_khz, UNCORE_INDEX_MIN_FREQ);
uncore_read(data, &data->initial_max_freq_khz, UNCORE_INDEX_MAX_FREQ);
ret = create_attr_group(data, data->name);
if (ret) {
+ data->control_cpu = -1;
if (data->domain_id != UNCORE_DOMAIN_ID_INVALID)
- ida_free(&intel_uncore_ida, data->instance_id);
+ ida_free(&intel_uncore_ida, data->seqnum_id);
} else {
- data->control_cpu = cpu;
data->valid = true;
}
@@ -301,7 +316,7 @@ void uncore_freq_remove_die_entry(struct uncore_data *data)
data->control_cpu = -1;
data->valid = false;
if (data->domain_id != UNCORE_DOMAIN_ID_INVALID)
- ida_free(&intel_uncore_ida, data->instance_id);
+ ida_free(&intel_uncore_ida, data->seqnum_id);
mutex_unlock(&uncore_lock);
}
diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h
index 0abe850ef54e..e319448dc1a4 100644
--- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h
+++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h
@@ -35,7 +35,8 @@
* @die_id: Die id for this instance
* @domain_id: Power domain id for this instance
* @cluster_id: cluster id in a domain
- * @instance_id: Unique instance id to append to directory name
+ * @seqnum_id: Unique sequential id to append to directory name
+ * @instance_id: Die indices or feature instances for a single TPMI device
* @name: Sysfs entry name for this instance
* @agent_type_mask: Bit mask of all hardware agents for this domain
* @uncore_attr_group: Attribute group storage
@@ -56,6 +57,7 @@
* @elc_floor_freq_khz_kobj_attr: Storage for kobject attribute elc_floor_freq_khz
* @agent_types_kobj_attr: Storage for kobject attribute agent_type
* @die_id_kobj_attr: Attribute storage for die_id information
+ * @instance_id_kobj_attr: Attribute storage for instance_id value
* @uncore_attrs: Attribute storage for group creation
*
* This structure is used to encapsulate all data related to uncore sysfs
@@ -71,6 +73,7 @@ struct uncore_data {
int die_id;
int domain_id;
int cluster_id;
+ int seqnum_id;
int instance_id;
char name[32];
u16 agent_type_mask;
@@ -90,7 +93,8 @@ struct uncore_data {
struct kobj_attribute elc_floor_freq_khz_kobj_attr;
struct kobj_attribute agent_types_kobj_attr;
struct kobj_attribute die_id_kobj_attr;
- struct attribute *uncore_attrs[15];
+ struct kobj_attribute instance_id_kobj_attr;
+ struct attribute *uncore_attrs[16];
};
#define UNCORE_DOMAIN_ID_INVALID -1
diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c
index 88015a2c6a0d..44e2a90004df 100644
--- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c
+++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c
@@ -385,7 +385,19 @@ static u8 io_die_index_next;
/* Lock to protect io_die_start, io_die_index_next */
static DEFINE_MUTEX(domain_lock);
-static void set_domain_id(int id, int num_resources,
+static inline void set_instance_id(int id, struct tpmi_uncore_cluster_info *cluster_info)
+{
+ /*
+ * On non-partitioned systems domain_id can be used for mapping both
+ * CPUs to compute die IDs and physical die indexes to MMIO mapped
+ * memory. However on partitioned systems domain_id loses the second
+ * association. Therefore instance_id should be used for that instead,
+ * while domain_id should still be used to match CPUs to compute dies.
+ */
+ cluster_info->uncore_data.instance_id = id;
+}
+
+static void set_domain_id(int id, int num_resources,
struct oobmsm_plat_info *plat_info,
struct tpmi_uncore_cluster_info *cluster_info)
{
@@ -690,6 +702,7 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_
set_cdie_id(i, cluster_info, plat_info);
set_domain_id(i, num_resources, plat_info, cluster_info);
+ set_instance_id(i, cluster_info);
cluster_info->uncore_root = tpmi_uncore;
diff --git a/drivers/platform/x86/intel/vbtn.c b/drivers/platform/x86/intel/vbtn.c
index 9ca87e707582..874023c38fd1 100644
--- a/drivers/platform/x86/intel/vbtn.c
+++ b/drivers/platform/x86/intel/vbtn.c
@@ -275,12 +275,16 @@ static bool intel_vbtn_has_switches(acpi_handle handle, bool dual_accel)
static int intel_vbtn_probe(struct platform_device *device)
{
- acpi_handle handle = ACPI_HANDLE(&device->dev);
bool dual_accel, has_buttons, has_switches;
struct intel_vbtn_priv *priv;
+ acpi_handle handle;
acpi_status status;
int err;
+ handle = ACPI_HANDLE(&device->dev);
+ if (!handle)
+ return -ENODEV;
+
dual_accel = dual_accel_detect();
has_buttons = acpi_has_method(handle, "VBDL");
has_switches = intel_vbtn_has_switches(handle, dual_accel);
diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c
index 7d5dbc1c1d05..5ab2215fdd7f 100644
--- a/drivers/platform/x86/intel/vsec.c
+++ b/drivers/platform/x86/intel/vsec.c
@@ -103,6 +103,12 @@ static void intel_vsec_remove_aux(void *data)
auxiliary_device_uninit(data);
}
+static void intel_vsec_dev_free(struct intel_vsec_device *intel_vsec_dev)
+{
+ kfree(intel_vsec_dev->acpi_disc);
+ kfree(intel_vsec_dev);
+}
+
static void intel_vsec_dev_release(struct device *dev)
{
struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(dev);
@@ -111,9 +117,7 @@ static void intel_vsec_dev_release(struct device *dev)
ida_free(intel_vsec_dev->ida, intel_vsec_dev->auxdev.id);
- kfree(intel_vsec_dev->acpi_disc);
- kfree(intel_vsec_dev->resource);
- kfree(intel_vsec_dev);
+ intel_vsec_dev_free(intel_vsec_dev);
}
static const struct vsec_feature_dependency *
@@ -219,22 +223,22 @@ int intel_vsec_add_aux(struct device *parent,
struct auxiliary_device *auxdev = &intel_vsec_dev->auxdev;
int ret, id;
- if (!parent)
+ if (!parent) {
+ intel_vsec_dev_free(intel_vsec_dev);
return -EINVAL;
+ }
ret = xa_alloc(&auxdev_array, &intel_vsec_dev->id, intel_vsec_dev,
PMT_XA_LIMIT, GFP_KERNEL);
if (ret < 0) {
- kfree(intel_vsec_dev->resource);
- kfree(intel_vsec_dev);
+ intel_vsec_dev_free(intel_vsec_dev);
return ret;
}
id = ida_alloc(intel_vsec_dev->ida, GFP_KERNEL);
if (id < 0) {
xa_erase(&auxdev_array, intel_vsec_dev->id);
- kfree(intel_vsec_dev->resource);
- kfree(intel_vsec_dev);
+ intel_vsec_dev_free(intel_vsec_dev);
return id;
}
@@ -282,7 +286,7 @@ static int intel_vsec_add_dev(struct device *dev, struct intel_vsec_header *head
unsigned long cap_id, u64 base_addr)
{
struct intel_vsec_device __free(kfree) *intel_vsec_dev = NULL;
- struct resource __free(kfree) *res = NULL;
+ struct resource *res;
struct resource *tmp;
struct device *parent;
unsigned long quirks = info->quirks;
@@ -306,13 +310,12 @@ static int intel_vsec_add_dev(struct device *dev, struct intel_vsec_header *head
return -EINVAL;
}
- intel_vsec_dev = kzalloc_obj(*intel_vsec_dev);
+ intel_vsec_dev = kzalloc_flex(*intel_vsec_dev, resource, header->num_entries);
if (!intel_vsec_dev)
return -ENOMEM;
- res = kzalloc_objs(*res, header->num_entries);
- if (!res)
- return -ENOMEM;
+ intel_vsec_dev->num_resources = header->num_entries;
+ res = intel_vsec_dev->resource;
if (quirks & VSEC_QUIRK_TABLE_SHIFT)
header->offset >>= TABLE_OFFSET_SHIFT;
@@ -342,8 +345,6 @@ static int intel_vsec_add_dev(struct device *dev, struct intel_vsec_header *head
}
intel_vsec_dev->dev = dev;
- intel_vsec_dev->resource = no_free_ptr(res);
- intel_vsec_dev->num_resources = header->num_entries;
intel_vsec_dev->quirks = info->quirks;
intel_vsec_dev->base_addr = info->base_addr;
intel_vsec_dev->priv_data = info->priv_data;
@@ -488,10 +489,25 @@ static int intel_vsec_walk_header(struct device *dev,
const struct intel_vsec_platform_info *info)
{
struct intel_vsec_header **header = info->headers;
+ u64 base_addr;
int ret;
for ( ; *header; header++) {
- ret = intel_vsec_register_device(dev, *header, info, info->base_addr);
+ if (info->base_addr) {
+ base_addr = info->base_addr;
+ } else {
+ struct pci_dev *pdev;
+
+ if (!dev_is_pci(dev)) {
+ dev_err(dev, "non-PCI device without a base address\n");
+ return -EINVAL;
+ }
+
+ pdev = to_pci_dev(dev);
+ base_addr = pci_resource_start(pdev, (*header)->tbir);
+ }
+
+ ret = intel_vsec_register_device(dev, *header, info, base_addr);
if (ret)
return ret;
}
@@ -649,29 +665,13 @@ static void intel_vsec_skip_missing_dependencies(struct pci_dev *pdev)
}
}
-static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+static int intel_vsec_pci_init(struct pci_dev *pdev)
{
- const struct intel_vsec_platform_info *info;
- struct vsec_priv *priv;
- int num_caps, ret;
+ struct vsec_priv *priv = pci_get_drvdata(pdev);
+ const struct intel_vsec_platform_info *info = priv->info;
int run_once = 0;
bool found_any = false;
-
- ret = pcim_enable_device(pdev);
- if (ret)
- return ret;
-
- pci_save_state(pdev);
- info = (const struct intel_vsec_platform_info *)id->driver_data;
- if (!info)
- return -EINVAL;
-
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- priv->info = info;
- pci_set_drvdata(pdev, priv);
+ int num_caps;
num_caps = hweight_long(info->caps);
while (num_caps--) {
@@ -692,6 +692,31 @@ static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id
return 0;
}
+static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ const struct intel_vsec_platform_info *info;
+ struct vsec_priv *priv;
+ int ret;
+
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ pci_save_state(pdev);
+ info = (const struct intel_vsec_platform_info *)id->driver_data;
+ if (!info)
+ return -EINVAL;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->info = info;
+ pci_set_drvdata(pdev, priv);
+
+ return intel_vsec_pci_init(pdev);
+}
+
int intel_vsec_set_mapping(struct oobmsm_plat_info *plat_info,
struct intel_vsec_device *vsec_dev)
{
@@ -832,7 +857,6 @@ static pci_ers_result_t intel_vsec_pci_slot_reset(struct pci_dev *pdev)
{
struct intel_vsec_device *intel_vsec_dev;
pci_ers_result_t status = PCI_ERS_RESULT_DISCONNECT;
- const struct pci_device_id *pci_dev_id;
unsigned long index;
dev_info(&pdev->dev, "Resetting PCI slot\n");
@@ -853,10 +877,8 @@ static pci_ers_result_t intel_vsec_pci_slot_reset(struct pci_dev *pdev)
devm_release_action(&pdev->dev, intel_vsec_remove_aux,
&intel_vsec_dev->auxdev);
}
- pci_disable_device(pdev);
pci_restore_state(pdev);
- pci_dev_id = pci_match_id(intel_vsec_pci_ids, pdev);
- intel_vsec_pci_probe(pdev, pci_dev_id);
+ intel_vsec_pci_init(pdev);
out:
return status;
diff --git a/drivers/platform/x86/intel/vsec_tpmi.c b/drivers/platform/x86/intel/vsec_tpmi.c
index 7fc6ff8d1040..0153dd57838e 100644
--- a/drivers/platform/x86/intel/vsec_tpmi.c
+++ b/drivers/platform/x86/intel/vsec_tpmi.c
@@ -50,12 +50,14 @@
#include <linux/auxiliary_bus.h>
#include <linux/bitfield.h>
#include <linux/debugfs.h>
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/intel_tpmi.h>
#include <linux/intel_vsec.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
+#include <linux/notifier.h>
#include <linux/pci.h>
#include <linux/security.h>
#include <linux/sizes.h>
@@ -188,6 +190,20 @@ struct tpmi_feature_state {
/* Used during auxbus device creation */
static DEFINE_IDA(intel_vsec_tpmi_ida);
+static BLOCKING_NOTIFIER_HEAD(tpmi_notify_list);
+
+int tpmi_register_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&tpmi_notify_list, nb);
+}
+EXPORT_SYMBOL_NS_GPL(tpmi_register_notifier, "INTEL_TPMI");
+
+int tpmi_unregister_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&tpmi_notify_list, nb);
+}
+EXPORT_SYMBOL_NS_GPL(tpmi_unregister_notifier, "INTEL_TPMI");
+
struct oobmsm_plat_info *tpmi_get_platform_data(struct auxiliary_device *auxdev)
{
struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev);
@@ -458,7 +474,7 @@ static ssize_t mem_write(struct file *file, const char __user *userbuf, size_t l
struct seq_file *m = file->private_data;
struct intel_tpmi_pm_feature *pfs = m->private;
u32 addr, value, punit, size;
- u32 num_elems, *array;
+ u32 num_elems;
void __iomem *mem;
int ret;
@@ -466,15 +482,14 @@ static ssize_t mem_write(struct file *file, const char __user *userbuf, size_t l
if (!size)
return -EIO;
+ u32 *array __free(kfree) = NULL;
ret = parse_int_array_user(userbuf, len, (int **)&array);
if (ret < 0)
return ret;
num_elems = *array;
- if (num_elems != 3) {
- ret = -EINVAL;
- goto exit_write;
- }
+ if (num_elems != 3)
+ return -EINVAL;
punit = array[1];
addr = array[2];
@@ -483,37 +498,23 @@ static ssize_t mem_write(struct file *file, const char __user *userbuf, size_t l
if (!IS_ALIGNED(addr, sizeof(u32)))
return -EINVAL;
- if (punit >= pfs->pfs_header.num_entries) {
- ret = -EINVAL;
- goto exit_write;
- }
+ if (punit >= pfs->pfs_header.num_entries)
+ return -EINVAL;
- if (addr >= size) {
- ret = -EINVAL;
- goto exit_write;
- }
+ if (addr >= size)
+ return -EINVAL;
- mutex_lock(&tpmi_dev_lock);
+ guard(mutex)(&tpmi_dev_lock);
mem = ioremap(pfs->vsec_offset + punit * size, size);
- if (!mem) {
- ret = -ENOMEM;
- goto unlock_mem_write;
- }
+ if (!mem)
+ return -ENOMEM;
writel(value, mem + addr);
iounmap(mem);
- ret = len;
-
-unlock_mem_write:
- mutex_unlock(&tpmi_dev_lock);
-
-exit_write:
- kfree(array);
-
- return ret;
+ return len;
}
static int mem_write_show(struct seq_file *s, void *unused)
@@ -626,15 +627,12 @@ static int tpmi_create_device(struct intel_tpmi_info *tpmi_info,
if (!name)
return -EOPNOTSUPP;
- res = kzalloc_objs(*res, pfs->pfs_header.num_entries);
- if (!res)
+ feature_vsec_dev = kzalloc_flex(*feature_vsec_dev, resource, pfs->pfs_header.num_entries);
+ if (!feature_vsec_dev)
return -ENOMEM;
- feature_vsec_dev = kzalloc_obj(*feature_vsec_dev);
- if (!feature_vsec_dev) {
- kfree(res);
- return -ENOMEM;
- }
+ feature_vsec_dev->num_resources = pfs->pfs_header.num_entries;
+ res = feature_vsec_dev->resource;
snprintf(feature_id_name, sizeof(feature_id_name), "tpmi-%s", name);
@@ -647,8 +645,6 @@ static int tpmi_create_device(struct intel_tpmi_info *tpmi_info,
}
feature_vsec_dev->dev = vsec_dev->dev;
- feature_vsec_dev->resource = res;
- feature_vsec_dev->num_resources = pfs->pfs_header.num_entries;
feature_vsec_dev->priv_data = &tpmi_info->plat_info;
feature_vsec_dev->priv_data_size = sizeof(tpmi_info->plat_info);
feature_vsec_dev->ida = &intel_vsec_tpmi_ida;
@@ -817,10 +813,6 @@ static int intel_vsec_tpmi_init(struct auxiliary_device *auxdev)
auxiliary_set_drvdata(auxdev, tpmi_info);
- ret = tpmi_create_devices(tpmi_info);
- if (ret)
- return ret;
-
/*
* Allow debugfs when security policy allows. Everything this debugfs
* interface provides, can also be done via /dev/mem access. If
@@ -830,6 +822,14 @@ static int intel_vsec_tpmi_init(struct auxiliary_device *auxdev)
if (!security_locked_down(LOCKDOWN_DEV_MEM) && capable(CAP_SYS_RAWIO))
tpmi_dbgfs_register(tpmi_info);
+ ret = tpmi_create_devices(tpmi_info);
+ if (ret) {
+ debugfs_remove_recursive(tpmi_info->dbgfs_dir);
+ return ret;
+ }
+
+ blocking_notifier_call_chain(&tpmi_notify_list, TPMI_CORE_INIT, auxdev);
+
return 0;
}
@@ -843,6 +843,8 @@ static void tpmi_remove(struct auxiliary_device *auxdev)
{
struct intel_tpmi_info *tpmi_info = auxiliary_get_drvdata(auxdev);
+ blocking_notifier_call_chain(&tpmi_notify_list, TPMI_CORE_EXIT, auxdev);
+
debugfs_remove_recursive(tpmi_info->dbgfs_dir);
}