platform/x86/amd/pmc: Use per-SoC cpu_info struct for SMU mailbox and IP info

Replace the scattered per-field assignments in amd_pmc_get_ip_info() with
a single amd_pmc_cpu_info struct capturing all SoC-specific parameters
such as SMU offsets, IP block table, and OS hint.

Define static const instances per SoC variant and embed them as driver_data
in the PCI ID table via PCI_DEVICE_DATA(). Consolidate pci_match_id() into
amd_pmc_set_cpu_info(), which assigns driver_data directly to cpu_info,
the switch falls through only for 1Ah M20H/M60H variants requiring
boot_cpu_data.x86_model detection to distinguish the M70 sub-variant.

Add scratch_reg to amd_pmc_cpu_info and populate it for each SoC
variant, allowing amd_pmc_idlemask_read() to drop its cpu_id switch
in favour of a single cpu_info->scratch_reg lookup.

Move dev->cpu_id assignment into amd_pmc_set_cpu_info() so it is valid
before the switch statement. Handle SP/SHP directly in the switch since
their NULL driver_data bypasses the early return, and remove the duplicate
check from probe.

Remove amd_pmc_get_os_hint() and use cpu_info->os_hint directly at call
sites and rename AMD_CPU_ID_* to PCI_DEVICE_ID_AMD_CPU_ID_* with backward
compatibility aliases.

Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
Link: https://patch.msgid.link/20260609143952.2999707-2-Shyam-sundar.S-k@amd.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
This commit is contained in:
Shyam Sundar S K 2026-06-09 20:09:51 +05:30 committed by Ilpo Järvinen
parent c39023ca9a
commit c3a2521bcc
No known key found for this signature in database
GPG Key ID: 59AC4F6153E5CE31
2 changed files with 177 additions and 120 deletions

View File

@ -85,6 +85,89 @@ static const struct amd_pmc_bit_map soc15_ip_blk[] = {
{"VPE", BIT(21)},
};
/* CPU info structures for different SoC variants */
static const struct amd_pmc_cpu_info amd_pco_cpu_info = {
.smu_msg = AMD_PMC_REGISTER_MESSAGE,
.smu_arg = AMD_PMC_REGISTER_ARGUMENT,
.smu_rsp = AMD_PMC_REGISTER_RESPONSE,
.num_ips = 12,
.ips_ptr = soc15_ip_blk,
.os_hint = MSG_OS_HINT_PCO,
};
static const struct amd_pmc_cpu_info amd_czn_cpu_info = {
.smu_msg = AMD_PMC_REGISTER_MESSAGE,
.smu_arg = AMD_PMC_REGISTER_ARGUMENT,
.smu_rsp = AMD_PMC_REGISTER_RESPONSE,
.num_ips = 12,
.scratch_reg = AMD_PMC_SCRATCH_REG_CZN,
.ips_ptr = soc15_ip_blk,
.os_hint = MSG_OS_HINT_RN,
};
static const struct amd_pmc_cpu_info amd_vg_cpu_info = {
.smu_msg = AMD_PMC_REGISTER_MESSAGE,
.smu_arg = AMD_PMC_REGISTER_ARGUMENT,
.smu_rsp = AMD_PMC_REGISTER_RESPONSE,
.num_ips = 12,
.ips_ptr = soc15_ip_blk,
.os_hint = MSG_OS_HINT_RN,
};
static const struct amd_pmc_cpu_info amd_yc_cpu_info = {
.smu_msg = AMD_PMC_REGISTER_MESSAGE,
.smu_arg = AMD_PMC_REGISTER_ARGUMENT,
.smu_rsp = AMD_PMC_REGISTER_RESPONSE,
.num_ips = 12,
.scratch_reg = AMD_PMC_SCRATCH_REG_YC,
.ips_ptr = soc15_ip_blk,
.os_hint = MSG_OS_HINT_RN,
};
static const struct amd_pmc_cpu_info amd_ps_cpu_info = {
.smu_msg = AMD_PMC_REGISTER_MESSAGE,
.smu_arg = AMD_PMC_REGISTER_ARGUMENT,
.smu_rsp = AMD_PMC_REGISTER_RESPONSE,
.num_ips = 21,
.scratch_reg = AMD_PMC_SCRATCH_REG_YC,
.ips_ptr = soc15_ip_blk,
.os_hint = MSG_OS_HINT_RN,
};
static const struct amd_pmc_cpu_info amd_1ah_cpu_info = {
.smu_msg = AMD_PMC_REGISTER_MSG_1AH_20H,
.smu_arg = AMD_PMC_REGISTER_ARGUMENT,
.smu_rsp = AMD_PMC_REGISTER_RESPONSE,
.num_ips = ARRAY_SIZE(soc15_ip_blk),
.scratch_reg = AMD_PMC_SCRATCH_REG_1AH,
.ips_ptr = soc15_ip_blk,
.os_hint = MSG_OS_HINT_RN,
};
static const struct amd_pmc_cpu_info amd_1ah_m70_cpu_info = {
.smu_msg = AMD_PMC_REGISTER_MSG_1AH_20H,
.smu_arg = AMD_PMC_REGISTER_ARGUMENT,
.smu_rsp = AMD_PMC_REGISTER_RESPONSE,
.num_ips = ARRAY_SIZE(soc15_ip_blk_v2),
.scratch_reg = AMD_PMC_SCRATCH_REG_1AH,
.ips_ptr = soc15_ip_blk_v2,
.os_hint = MSG_OS_HINT_RN,
};
static const struct pci_device_id pmc_pci_ids[] = {
{ PCI_DEVICE_DATA(AMD, CPU_ID_PCO, &amd_pco_cpu_info) },
{ PCI_DEVICE_DATA(AMD, CPU_ID_CZN, &amd_czn_cpu_info) },
{ PCI_DEVICE_DATA(AMD, CPU_ID_VG, &amd_vg_cpu_info) },
{ PCI_DEVICE_DATA(AMD, CPU_ID_YC, &amd_yc_cpu_info) },
{ PCI_DEVICE_DATA(AMD, CPU_ID_CB, &amd_yc_cpu_info) },
{ PCI_DEVICE_DATA(AMD, CPU_ID_PS, &amd_ps_cpu_info) },
{ PCI_DEVICE_DATA(AMD, CPU_ID_SP, NULL) },
{ PCI_DEVICE_DATA(AMD, CPU_ID_SHP, NULL) },
{ PCI_DEVICE_DATA(AMD, 1AH_M20H_ROOT, NULL) },
{ PCI_DEVICE_DATA(AMD, 1AH_M60H_ROOT, NULL) },
{ }
};
static bool disable_workarounds;
module_param(disable_workarounds, bool, 0644);
MODULE_PARM_DESC(disable_workarounds, "Disable workarounds for platform bugs");
@ -101,35 +184,40 @@ static inline void amd_pmc_reg_write(struct amd_pmc_dev *dev, int reg_offset, u3
iowrite32(val, dev->regbase + reg_offset);
}
static void amd_pmc_get_ip_info(struct amd_pmc_dev *dev)
static int amd_pmc_set_cpu_info(struct amd_pmc_dev *dev, struct pci_dev *rdev)
{
const struct pci_device_id *id;
id = pci_match_id(pmc_pci_ids, rdev);
if (!id)
return -ENODEV;
dev->cpu_id = rdev->device;
if (id->driver_data) {
dev->cpu_info = (const struct amd_pmc_cpu_info *)id->driver_data;
return 0;
}
/* Special case: 1Ah M20H/M60H needs x86_model detection */
switch (dev->cpu_id) {
case AMD_CPU_ID_PCO:
case AMD_CPU_ID_RN:
case AMD_CPU_ID_VG:
case AMD_CPU_ID_YC:
case AMD_CPU_ID_CB:
dev->num_ips = 12;
dev->ips_ptr = soc15_ip_blk;
dev->smu_msg = 0x538;
break;
case AMD_CPU_ID_PS:
dev->num_ips = 21;
dev->ips_ptr = soc15_ip_blk;
dev->smu_msg = 0x538;
break;
case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:
if (boot_cpu_data.x86_model == 0x70) {
dev->num_ips = ARRAY_SIZE(soc15_ip_blk_v2);
dev->ips_ptr = soc15_ip_blk_v2;
} else {
dev->num_ips = ARRAY_SIZE(soc15_ip_blk);
dev->ips_ptr = soc15_ip_blk;
}
dev->smu_msg = 0x938;
if (boot_cpu_data.x86_model == 0x70)
dev->cpu_info = &amd_1ah_m70_cpu_info;
else
dev->cpu_info = &amd_1ah_cpu_info;
break;
case AMD_CPU_ID_SP:
case AMD_CPU_ID_SHP:
dev_warn_once(dev->dev, "S0i3 is not supported on this hardware\n");
return -ENODEV;
default:
dev_err(dev->dev, "Unknown CPU ID: 0x%x\n", dev->cpu_id);
return -ENODEV;
}
return 0;
}
static int amd_pmc_setup_smu_logging(struct amd_pmc_dev *dev)
@ -296,9 +384,9 @@ static int smu_fw_info_show(struct seq_file *s, void *unused)
table.timeto_resume_to_os_lastcapture);
seq_puts(s, "\n=== Active time (in us) ===\n");
for (idx = 0 ; idx < dev->num_ips ; idx++) {
if (dev->ips_ptr[idx].bit_mask & dev->active_ips)
seq_printf(s, "%-8s : %lld\n", dev->ips_ptr[idx].name,
for (idx = 0 ; idx < dev->cpu_info->num_ips ; idx++) {
if (dev->cpu_info->ips_ptr[idx].bit_mask & dev->active_ips)
seq_printf(s, "%-8s : %lld\n", dev->cpu_info->ips_ptr[idx].name,
table.timecondition_notmet_lastcapture[idx]);
}
@ -347,32 +435,22 @@ static int amd_pmc_idlemask_read(struct amd_pmc_dev *pdev, struct device *dev,
u32 val;
int rc;
switch (pdev->cpu_id) {
case AMD_CPU_ID_CZN:
/* we haven't yet read SMU version */
/* we haven't yet read SMU version */
if (pdev->cpu_id == AMD_CPU_ID_CZN) {
if (!pdev->major) {
rc = amd_pmc_get_smu_version(pdev);
if (rc)
return rc;
}
if (pdev->major > 56 || (pdev->major >= 55 && pdev->minor >= 37))
val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_CZN);
else
if (!(pdev->major > 56 || (pdev->major >= 55 && pdev->minor >= 37)))
return -EINVAL;
break;
case AMD_CPU_ID_YC:
case AMD_CPU_ID_CB:
case AMD_CPU_ID_PS:
val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_YC);
break;
case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:
val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_1AH);
break;
default:
return -EINVAL;
}
if (!pdev->cpu_info->scratch_reg)
return -EINVAL;
val = amd_pmc_reg_read(pdev, pdev->cpu_info->scratch_reg);
if (dev)
pm_pr_dbg("SMU idlemask s0i3: 0x%x\n", val);
@ -425,9 +503,9 @@ static void amd_pmc_dump_registers(struct amd_pmc_dev *dev)
argument = dev->stb_arg.arg;
response = dev->stb_arg.resp;
} else {
message = dev->smu_msg;
argument = AMD_PMC_REGISTER_ARGUMENT;
response = AMD_PMC_REGISTER_RESPONSE;
message = dev->cpu_info->smu_msg;
argument = dev->cpu_info->smu_arg;
response = dev->cpu_info->smu_rsp;
}
value = amd_pmc_reg_read(dev, response);
@ -452,9 +530,9 @@ int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool r
argument = dev->stb_arg.arg;
response = dev->stb_arg.resp;
} else {
message = dev->smu_msg;
argument = AMD_PMC_REGISTER_ARGUMENT;
response = AMD_PMC_REGISTER_RESPONSE;
message = dev->cpu_info->smu_msg;
argument = dev->cpu_info->smu_arg;
response = dev->cpu_info->smu_rsp;
}
/* Wait until we get a valid response */
@ -512,23 +590,6 @@ int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool r
return rc;
}
static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev)
{
switch (dev->cpu_id) {
case AMD_CPU_ID_PCO:
return MSG_OS_HINT_PCO;
case AMD_CPU_ID_RN:
case AMD_CPU_ID_VG:
case AMD_CPU_ID_YC:
case AMD_CPU_ID_CB:
case AMD_CPU_ID_PS:
case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
case PCI_DEVICE_ID_AMD_1AH_M60H_ROOT:
return MSG_OS_HINT_RN;
}
return -EINVAL;
}
static int amd_pmc_wa_irq1(struct amd_pmc_dev *pdev)
{
struct device *d;
@ -602,7 +663,6 @@ static void amd_pmc_s2idle_prepare(void)
{
struct amd_pmc_dev *pdev = &pmc;
int rc;
u8 msg;
u32 arg = 1;
/* Reset and Start SMU logging - to monitor the s0i3 stats */
@ -617,8 +677,7 @@ static void amd_pmc_s2idle_prepare(void)
}
}
msg = amd_pmc_get_os_hint(pdev);
rc = amd_pmc_send_cmd(pdev, arg, NULL, msg, false);
rc = amd_pmc_send_cmd(pdev, arg, NULL, pdev->cpu_info->os_hint, false);
if (rc) {
dev_err(pdev->dev, "suspend failed: %d\n", rc);
return;
@ -659,10 +718,8 @@ static void amd_pmc_s2idle_restore(void)
{
struct amd_pmc_dev *pdev = &pmc;
int rc;
u8 msg;
msg = amd_pmc_get_os_hint(pdev);
rc = amd_pmc_send_cmd(pdev, 0, NULL, msg, false);
rc = amd_pmc_send_cmd(pdev, 0, NULL, pdev->cpu_info->os_hint, false);
if (rc)
dev_err(pdev->dev, "resume failed: %d\n", rc);
@ -709,22 +766,6 @@ static const struct dev_pm_ops amd_pmc_pm = {
.suspend = amd_pmc_suspend_handler,
};
static const struct pci_device_id pmc_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PS) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_CB) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_YC) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_CZN) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RN) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PCO) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RV) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_SP) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_SHP) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_VG) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M20H_ROOT) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M60H_ROOT) },
{ }
};
static int amd_pmc_probe(struct platform_device *pdev)
{
struct amd_pmc_dev *dev = &pmc;
@ -736,17 +777,14 @@ static int amd_pmc_probe(struct platform_device *pdev)
dev->dev = &pdev->dev;
rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
if (!rdev || !pci_match_id(pmc_pci_ids, rdev)) {
if (!rdev) {
err = -ENODEV;
goto err_pci_dev_put;
}
dev->cpu_id = rdev->device;
if (dev->cpu_id == AMD_CPU_ID_SP || dev->cpu_id == AMD_CPU_ID_SHP) {
dev_warn_once(dev->dev, "S0i3 is not supported on this hardware\n");
err = -ENODEV;
err = amd_pmc_set_cpu_info(dev, rdev);
if (err)
goto err_pci_dev_put;
}
dev->rdev = rdev;
err = amd_smn_read(0, AMD_PMC_BASE_ADDR_LO, &val);
@ -778,9 +816,6 @@ static int amd_pmc_probe(struct platform_device *pdev)
if (err)
goto err_pci_dev_put;
/* Get num of IP blocks within the SoC */
amd_pmc_get_ip_info(dev);
platform_set_drvdata(pdev, dev);
if (IS_ENABLED(CONFIG_SUSPEND)) {
err = acpi_register_lps0_dev(&amd_pmc_s2idle_dev_ops);

View File

@ -17,6 +17,10 @@
/* SMU communication registers */
#define AMD_PMC_REGISTER_RESPONSE 0x980
#define AMD_PMC_REGISTER_ARGUMENT 0x9BC
#define AMD_PMC_REGISTER_MESSAGE 0x538
/* SMU communication registers for 1Ah 20h SoC */
#define AMD_PMC_REGISTER_MSG_1AH_20H 0x938
/* PMC Scratch Registers */
#define AMD_PMC_SCRATCH_REG_CZN 0x94
@ -90,6 +94,22 @@ struct stb_arg {
u32 resp;
};
struct amd_pmc_bit_map {
const char *name;
u32 bit_mask;
};
/* SoC-specific information */
struct amd_pmc_cpu_info {
u32 smu_msg;
u32 smu_arg;
u32 smu_rsp;
u32 num_ips;
u32 scratch_reg;
const struct amd_pmc_bit_map *ips_ptr;
u8 os_hint;
};
struct amd_pmc_dev {
void __iomem *regbase;
void __iomem *smu_virt_addr;
@ -99,9 +119,6 @@ struct amd_pmc_dev {
u32 cpu_id;
u32 dram_size;
u32 active_ips;
const struct amd_pmc_bit_map *ips_ptr;
u32 num_ips;
u32 smu_msg;
/* SMU version information */
u8 smu_program;
u8 major;
@ -116,11 +133,7 @@ struct amd_pmc_dev {
bool disable_8042_wakeup;
struct amd_mp2_dev *mp2;
struct stb_arg stb_arg;
};
struct amd_pmc_bit_map {
const char *name;
u32 bit_mask;
const struct amd_pmc_cpu_info *cpu_info;
};
struct smu_metrics {
@ -151,20 +164,29 @@ void amd_pmc_quirks_init(struct amd_pmc_dev *dev);
void amd_mp2_stb_init(struct amd_pmc_dev *dev);
void amd_mp2_stb_deinit(struct amd_pmc_dev *dev);
/* List of supported CPU ids */
#define AMD_CPU_ID_RV 0x15D0
#define AMD_CPU_ID_RN 0x1630
#define AMD_CPU_ID_PCO AMD_CPU_ID_RV
#define AMD_CPU_ID_CZN AMD_CPU_ID_RN
#define AMD_CPU_ID_VG 0x1645
#define AMD_CPU_ID_YC 0x14B5
#define AMD_CPU_ID_CB 0x14D8
#define AMD_CPU_ID_PS 0x14E8
#define AMD_CPU_ID_SP 0x14A4
#define AMD_CPU_ID_SHP 0x153A
#define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507
#define PCI_DEVICE_ID_AMD_1AH_M60H_ROOT 0x1122
#define PCI_DEVICE_ID_AMD_MP2_STB 0x172c
/* List of supported CPU/device IDs */
#define PCI_DEVICE_ID_AMD_CPU_ID_PCO 0x15D0
#define PCI_DEVICE_ID_AMD_CPU_ID_CZN 0x1630
#define PCI_DEVICE_ID_AMD_CPU_ID_VG 0x1645
#define PCI_DEVICE_ID_AMD_CPU_ID_YC 0x14B5
#define PCI_DEVICE_ID_AMD_CPU_ID_CB 0x14D8
#define PCI_DEVICE_ID_AMD_CPU_ID_PS 0x14E8
#define PCI_DEVICE_ID_AMD_CPU_ID_SP 0x14A4
#define PCI_DEVICE_ID_AMD_CPU_ID_SHP 0x153A
/* Backward compatibility aliases */
#define AMD_CPU_ID_PCO PCI_DEVICE_ID_AMD_CPU_ID_PCO
#define AMD_CPU_ID_CZN PCI_DEVICE_ID_AMD_CPU_ID_CZN
#define AMD_CPU_ID_VG PCI_DEVICE_ID_AMD_CPU_ID_VG
#define AMD_CPU_ID_YC PCI_DEVICE_ID_AMD_CPU_ID_YC
#define AMD_CPU_ID_CB PCI_DEVICE_ID_AMD_CPU_ID_CB
#define AMD_CPU_ID_PS PCI_DEVICE_ID_AMD_CPU_ID_PS
#define AMD_CPU_ID_SP PCI_DEVICE_ID_AMD_CPU_ID_SP
#define AMD_CPU_ID_SHP PCI_DEVICE_ID_AMD_CPU_ID_SHP
#define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507
#define PCI_DEVICE_ID_AMD_1AH_M60H_ROOT 0x1122
#define PCI_DEVICE_ID_AMD_MP2_STB 0x172c
int amd_stb_s2d_init(struct amd_pmc_dev *dev);
int amd_stb_read(struct amd_pmc_dev *dev, u32 *buf);