diff options
Diffstat (limited to 'drivers/platform/x86/amd/pmc')
-rw-r--r-- | drivers/platform/x86/amd/pmc/Kconfig | 2 | ||||
-rw-r--r-- | drivers/platform/x86/amd/pmc/Makefile | 6 | ||||
-rw-r--r-- | drivers/platform/x86/amd/pmc/mp1_stb.c | 332 | ||||
-rw-r--r-- | drivers/platform/x86/amd/pmc/pmc-quirks.c | 10 | ||||
-rw-r--r-- | drivers/platform/x86/amd/pmc/pmc.c | 510 | ||||
-rw-r--r-- | drivers/platform/x86/amd/pmc/pmc.h | 106 |
6 files changed, 543 insertions, 423 deletions
diff --git a/drivers/platform/x86/amd/pmc/Kconfig b/drivers/platform/x86/amd/pmc/Kconfig index 94f9563d8be7..eeffdafd686e 100644 --- a/drivers/platform/x86/amd/pmc/Kconfig +++ b/drivers/platform/x86/amd/pmc/Kconfig @@ -5,7 +5,7 @@ config AMD_PMC tristate "AMD SoC PMC driver" - depends on ACPI && PCI && RTC_CLASS && AMD_NB + depends on ACPI && PCI && RTC_CLASS && AMD_NODE depends on SUSPEND select SERIO help diff --git a/drivers/platform/x86/amd/pmc/Makefile b/drivers/platform/x86/amd/pmc/Makefile index f1d9ab19d24c..bb6905c4cae9 100644 --- a/drivers/platform/x86/amd/pmc/Makefile +++ b/drivers/platform/x86/amd/pmc/Makefile @@ -4,6 +4,6 @@ # AMD Power Management Controller Driver # -amd-pmc-objs := pmc.o pmc-quirks.o -obj-$(CONFIG_AMD_PMC) += amd-pmc.o -amd-pmc-$(CONFIG_AMD_MP2_STB) += mp2_stb.o +obj-$(CONFIG_AMD_PMC) += amd-pmc.o +amd-pmc-y := pmc.o pmc-quirks.o mp1_stb.o +amd-pmc-$(CONFIG_AMD_MP2_STB) += mp2_stb.o diff --git a/drivers/platform/x86/amd/pmc/mp1_stb.c b/drivers/platform/x86/amd/pmc/mp1_stb.c new file mode 100644 index 000000000000..3b9b9f30faa3 --- /dev/null +++ b/drivers/platform/x86/amd/pmc/mp1_stb.c @@ -0,0 +1,332 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD MP1 Smart Trace Buffer (STB) Layer + * + * Copyright (c) 2024, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> + * Sanket Goswami <Sanket.Goswami@amd.com> + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <asm/amd/nb.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/uaccess.h> + +#include "pmc.h" + +/* STB Spill to DRAM Parameters */ +#define S2D_TELEMETRY_DRAMBYTES_MAX 0x1000000 +#define S2D_TELEMETRY_BYTES_MAX 0x100000U +#define S2D_RSVD_RAM_SPACE 0x100000 + +/* STB Registers */ +#define AMD_STB_PMI_0 0x03E30600 +#define AMD_PMC_STB_DUMMY_PC 0xC6000007 + +/* STB Spill to DRAM Message Definition */ +#define STB_FORCE_FLUSH_DATA 0xCF +#define FIFO_SIZE 4096 + +/* STB S2D(Spill to DRAM) has different message port offset */ +#define AMD_S2D_REGISTER_MESSAGE 0xA20 +#define AMD_S2D_REGISTER_RESPONSE 0xA80 +#define AMD_S2D_REGISTER_ARGUMENT 0xA88 + +/* STB S2D (Spill to DRAM) message port offset for 44h model */ +#define AMD_GNR_REGISTER_MESSAGE 0x524 +#define AMD_GNR_REGISTER_RESPONSE 0x570 +#define AMD_GNR_REGISTER_ARGUMENT 0xA40 + +static bool enable_stb; +module_param(enable_stb, bool, 0644); +MODULE_PARM_DESC(enable_stb, "Enable the STB debug mechanism"); + +static bool dump_custom_stb; +module_param(dump_custom_stb, bool, 0644); +MODULE_PARM_DESC(dump_custom_stb, "Enable to dump full STB buffer"); + +enum s2d_arg { + S2D_TELEMETRY_SIZE = 0x01, + S2D_PHYS_ADDR_LOW, + S2D_PHYS_ADDR_HIGH, + S2D_NUM_SAMPLES, + S2D_DRAM_SIZE, +}; + +struct amd_stb_v2_data { + size_t size; + u8 data[] __counted_by(size); +}; + +int amd_stb_write(struct amd_pmc_dev *dev, u32 data) +{ + int err; + + err = amd_smn_write(0, AMD_STB_PMI_0, data); + if (err) { + dev_err(dev->dev, "failed to write data in stb: 0x%X\n", AMD_STB_PMI_0); + return pcibios_err_to_errno(err); + } + + return 0; +} + +int amd_stb_read(struct amd_pmc_dev *dev, u32 *buf) +{ + int i, err; + + for (i = 0; i < FIFO_SIZE; i++) { + err = amd_smn_read(0, AMD_STB_PMI_0, buf++); + if (err) { + dev_err(dev->dev, "error reading data from stb: 0x%X\n", AMD_STB_PMI_0); + return pcibios_err_to_errno(err); + } + } + + return 0; +} + +static int amd_stb_debugfs_open(struct inode *inode, struct file *filp) +{ + struct amd_pmc_dev *dev = filp->f_inode->i_private; + u32 size = FIFO_SIZE * sizeof(u32); + u32 *buf; + int rc; + + buf = kzalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + rc = amd_stb_read(dev, buf); + if (rc) { + kfree(buf); + return rc; + } + + filp->private_data = buf; + return rc; +} + +static ssize_t amd_stb_debugfs_read(struct file *filp, char __user *buf, size_t size, loff_t *pos) +{ + if (!filp->private_data) + return -EINVAL; + + return simple_read_from_buffer(buf, size, pos, filp->private_data, + FIFO_SIZE * sizeof(u32)); +} + +static int amd_stb_debugfs_release(struct inode *inode, struct file *filp) +{ + kfree(filp->private_data); + return 0; +} + +static const struct file_operations amd_stb_debugfs_fops = { + .owner = THIS_MODULE, + .open = amd_stb_debugfs_open, + .read = amd_stb_debugfs_read, + .release = amd_stb_debugfs_release, +}; + +/* Enhanced STB Firmware Reporting Mechanism */ +static int amd_stb_handle_efr(struct file *filp) +{ + struct amd_pmc_dev *dev = filp->f_inode->i_private; + struct amd_stb_v2_data *stb_data_arr; + u32 fsize; + + fsize = dev->dram_size - S2D_RSVD_RAM_SPACE; + stb_data_arr = kmalloc(struct_size(stb_data_arr, data, fsize), GFP_KERNEL); + if (!stb_data_arr) + return -ENOMEM; + + stb_data_arr->size = fsize; + memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr, fsize); + filp->private_data = stb_data_arr; + + return 0; +} + +static int amd_stb_debugfs_open_v2(struct inode *inode, struct file *filp) +{ + struct amd_pmc_dev *dev = filp->f_inode->i_private; + u32 fsize, num_samples, val, stb_rdptr_offset = 0; + struct amd_stb_v2_data *stb_data_arr; + int ret; + + /* Write dummy postcode while reading the STB buffer */ + ret = amd_stb_write(dev, AMD_PMC_STB_DUMMY_PC); + if (ret) + dev_err(dev->dev, "error writing to STB: %d\n", ret); + + /* Spill to DRAM num_samples uses separate SMU message port */ + dev->msg_port = MSG_PORT_S2D; + + ret = amd_pmc_send_cmd(dev, 0, &val, STB_FORCE_FLUSH_DATA, 1); + if (ret) + dev_dbg_once(dev->dev, "S2D force flush not supported: %d\n", ret); + + /* + * We have a custom stb size and the PMFW is supposed to give + * the enhanced dram size. Note that we land here only for the + * platforms that support enhanced dram size reporting. + */ + if (dump_custom_stb) + return amd_stb_handle_efr(filp); + + /* Get the num_samples to calculate the last push location */ + ret = amd_pmc_send_cmd(dev, S2D_NUM_SAMPLES, &num_samples, dev->stb_arg.s2d_msg_id, true); + /* Clear msg_port for other SMU operation */ + dev->msg_port = MSG_PORT_PMC; + if (ret) { + dev_err(dev->dev, "error: S2D_NUM_SAMPLES not supported : %d\n", ret); + return ret; + } + + fsize = min(num_samples, S2D_TELEMETRY_BYTES_MAX); + stb_data_arr = kmalloc(struct_size(stb_data_arr, data, fsize), GFP_KERNEL); + if (!stb_data_arr) + return -ENOMEM; + + stb_data_arr->size = fsize; + + /* + * Start capturing data from the last push location. + * This is for general cases, where the stb limits + * are meant for standard usage. + */ + if (num_samples > S2D_TELEMETRY_BYTES_MAX) { + /* First read oldest data starting 1 behind last write till end of ringbuffer */ + stb_rdptr_offset = num_samples % S2D_TELEMETRY_BYTES_MAX; + fsize = S2D_TELEMETRY_BYTES_MAX - stb_rdptr_offset; + + memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr + stb_rdptr_offset, fsize); + /* Second copy the newer samples from offset 0 - last write */ + memcpy_fromio(stb_data_arr->data + fsize, dev->stb_virt_addr, stb_rdptr_offset); + } else { + memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr, fsize); + } + + filp->private_data = stb_data_arr; + + return 0; +} + +static ssize_t amd_stb_debugfs_read_v2(struct file *filp, char __user *buf, size_t size, + loff_t *pos) +{ + struct amd_stb_v2_data *data = filp->private_data; + + return simple_read_from_buffer(buf, size, pos, data->data, data->size); +} + +static int amd_stb_debugfs_release_v2(struct inode *inode, struct file *filp) +{ + kfree(filp->private_data); + return 0; +} + +static const struct file_operations amd_stb_debugfs_fops_v2 = { + .owner = THIS_MODULE, + .open = amd_stb_debugfs_open_v2, + .read = amd_stb_debugfs_read_v2, + .release = amd_stb_debugfs_release_v2, +}; + +static void amd_stb_update_args(struct amd_pmc_dev *dev) +{ + if (cpu_feature_enabled(X86_FEATURE_ZEN5)) + switch (boot_cpu_data.x86_model) { + case 0x44: + dev->stb_arg.msg = AMD_GNR_REGISTER_MESSAGE; + dev->stb_arg.arg = AMD_GNR_REGISTER_ARGUMENT; + dev->stb_arg.resp = AMD_GNR_REGISTER_RESPONSE; + return; + default: + break; + } + + dev->stb_arg.msg = AMD_S2D_REGISTER_MESSAGE; + dev->stb_arg.arg = AMD_S2D_REGISTER_ARGUMENT; + dev->stb_arg.resp = AMD_S2D_REGISTER_RESPONSE; +} + +static bool amd_is_stb_supported(struct amd_pmc_dev *dev) +{ + switch (dev->cpu_id) { + case AMD_CPU_ID_YC: + case AMD_CPU_ID_CB: + if (boot_cpu_data.x86_model == 0x44) + dev->stb_arg.s2d_msg_id = 0x9B; + else + dev->stb_arg.s2d_msg_id = 0xBE; + break; + case AMD_CPU_ID_PS: + dev->stb_arg.s2d_msg_id = 0x85; + 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->stb_arg.s2d_msg_id = 0xF1; + else + dev->stb_arg.s2d_msg_id = 0xDE; + break; + default: + return false; + } + + amd_stb_update_args(dev); + return true; +} + +int amd_stb_s2d_init(struct amd_pmc_dev *dev) +{ + u32 phys_addr_low, phys_addr_hi; + u64 stb_phys_addr; + u32 size = 0; + int ret; + + if (!enable_stb) + return 0; + + if (amd_is_stb_supported(dev)) { + debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev, + &amd_stb_debugfs_fops_v2); + } else { + debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev, + &amd_stb_debugfs_fops); + return 0; + } + + /* Spill to DRAM feature uses separate SMU message port */ + dev->msg_port = MSG_PORT_S2D; + + amd_pmc_send_cmd(dev, S2D_TELEMETRY_SIZE, &size, dev->stb_arg.s2d_msg_id, true); + if (size != S2D_TELEMETRY_BYTES_MAX) + return -EIO; + + /* Get DRAM size */ + ret = amd_pmc_send_cmd(dev, S2D_DRAM_SIZE, &dev->dram_size, dev->stb_arg.s2d_msg_id, true); + if (ret || !dev->dram_size) + dev->dram_size = S2D_TELEMETRY_DRAMBYTES_MAX; + + /* Get STB DRAM address */ + amd_pmc_send_cmd(dev, S2D_PHYS_ADDR_LOW, &phys_addr_low, dev->stb_arg.s2d_msg_id, true); + amd_pmc_send_cmd(dev, S2D_PHYS_ADDR_HIGH, &phys_addr_hi, dev->stb_arg.s2d_msg_id, true); + + stb_phys_addr = ((u64)phys_addr_hi << 32 | phys_addr_low); + + /* Clear msg_port for other SMU operation */ + dev->msg_port = MSG_PORT_PMC; + + dev->stb_virt_addr = devm_ioremap(dev->dev, stb_phys_addr, dev->dram_size); + if (!dev->stb_virt_addr) + return -ENOMEM; + + return 0; +} diff --git a/drivers/platform/x86/amd/pmc/pmc-quirks.c b/drivers/platform/x86/amd/pmc/pmc-quirks.c index b4f49720c87f..5c7c01f66cde 100644 --- a/drivers/platform/x86/amd/pmc/pmc-quirks.c +++ b/drivers/platform/x86/amd/pmc/pmc-quirks.c @@ -11,6 +11,7 @@ #include <linux/dmi.h> #include <linux/io.h> #include <linux/ioport.h> +#include <asm/amd/fch.h> #include "pmc.h" @@ -20,7 +21,7 @@ struct quirk_entry { }; static struct quirk_entry quirk_s2idle_bug = { - .s2idle_bug_mmio = 0xfed80380, + .s2idle_bug_mmio = FCH_PM_BASE + FCH_PM_SCRATCH, }; static struct quirk_entry quirk_spurious_8042 = { @@ -217,6 +218,13 @@ static const struct dmi_system_id fwbug_list[] = { DMI_MATCH(DMI_BIOS_VERSION, "03.05"), } }, + { + .ident = "MECHREVO Wujie 14X (GX4HRXL)", + .driver_data = &quirk_spurious_8042, + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "WUJIE14-GX4HRXL"), + } + }, {} }; diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c index a254debb9256..37c7a57afee5 100644 --- a/drivers/platform/x86/amd/pmc/pmc.c +++ b/drivers/platform/x86/amd/pmc/pmc.c @@ -10,8 +10,8 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <asm/amd_nb.h> #include <linux/acpi.h> +#include <linux/array_size.h> #include <linux/bitfield.h> #include <linux/bits.h> #include <linux/debugfs.h> @@ -28,99 +28,36 @@ #include <linux/seq_file.h> #include <linux/uaccess.h> -#include "pmc.h" - -/* SMU communication registers */ -#define AMD_PMC_REGISTER_RESPONSE 0x980 -#define AMD_PMC_REGISTER_ARGUMENT 0x9BC - -/* PMC Scratch Registers */ -#define AMD_PMC_SCRATCH_REG_CZN 0x94 -#define AMD_PMC_SCRATCH_REG_YC 0xD14 -#define AMD_PMC_SCRATCH_REG_1AH 0xF14 - -/* STB Registers */ -#define AMD_PMC_STB_PMI_0 0x03E30600 -#define AMD_PMC_STB_S2IDLE_PREPARE 0xC6000001 -#define AMD_PMC_STB_S2IDLE_RESTORE 0xC6000002 -#define AMD_PMC_STB_S2IDLE_CHECK 0xC6000003 -#define AMD_PMC_STB_DUMMY_PC 0xC6000007 - -/* STB S2D(Spill to DRAM) has different message port offset */ -#define AMD_S2D_REGISTER_MESSAGE 0xA20 -#define AMD_S2D_REGISTER_RESPONSE 0xA80 -#define AMD_S2D_REGISTER_ARGUMENT 0xA88 - -/* STB Spill to DRAM Parameters */ -#define S2D_TELEMETRY_BYTES_MAX 0x100000U -#define S2D_RSVD_RAM_SPACE 0x100000 -#define S2D_TELEMETRY_DRAMBYTES_MAX 0x1000000 - -/* STB Spill to DRAM Message Definition */ -#define STB_FORCE_FLUSH_DATA 0xCF - -/* Base address of SMU for mapping physical address to virtual address */ -#define AMD_PMC_MAPPING_SIZE 0x01000 -#define AMD_PMC_BASE_ADDR_OFFSET 0x10000 -#define AMD_PMC_BASE_ADDR_LO 0x13B102E8 -#define AMD_PMC_BASE_ADDR_HI 0x13B102EC -#define AMD_PMC_BASE_ADDR_LO_MASK GENMASK(15, 0) -#define AMD_PMC_BASE_ADDR_HI_MASK GENMASK(31, 20) - -/* SMU Response Codes */ -#define AMD_PMC_RESULT_OK 0x01 -#define AMD_PMC_RESULT_CMD_REJECT_BUSY 0xFC -#define AMD_PMC_RESULT_CMD_REJECT_PREREQ 0xFD -#define AMD_PMC_RESULT_CMD_UNKNOWN 0xFE -#define AMD_PMC_RESULT_FAILED 0xFF - -/* FCH SSC Registers */ -#define FCH_S0I3_ENTRY_TIME_L_OFFSET 0x30 -#define FCH_S0I3_ENTRY_TIME_H_OFFSET 0x34 -#define FCH_S0I3_EXIT_TIME_L_OFFSET 0x38 -#define FCH_S0I3_EXIT_TIME_H_OFFSET 0x3C -#define FCH_SSC_MAPPING_SIZE 0x800 -#define FCH_BASE_PHY_ADDR_LOW 0xFED81100 -#define FCH_BASE_PHY_ADDR_HIGH 0x00000000 - -/* SMU Message Definations */ -#define SMU_MSG_GETSMUVERSION 0x02 -#define SMU_MSG_LOG_GETDRAM_ADDR_HI 0x04 -#define SMU_MSG_LOG_GETDRAM_ADDR_LO 0x05 -#define SMU_MSG_LOG_START 0x06 -#define SMU_MSG_LOG_RESET 0x07 -#define SMU_MSG_LOG_DUMP_DATA 0x08 -#define SMU_MSG_GET_SUP_CONSTRAINTS 0x09 - -#define PMC_MSG_DELAY_MIN_US 50 -#define RESPONSE_REGISTER_LOOP_MAX 20000 - -#define DELAY_MIN_US 2000 -#define DELAY_MAX_US 3000 -#define FIFO_SIZE 4096 - -enum amd_pmc_def { - MSG_TEST = 0x01, - MSG_OS_HINT_PCO, - MSG_OS_HINT_RN, -}; - -enum s2d_arg { - S2D_TELEMETRY_SIZE = 0x01, - S2D_PHYS_ADDR_LOW, - S2D_PHYS_ADDR_HIGH, - S2D_NUM_SAMPLES, - S2D_DRAM_SIZE, -}; +#include <asm/amd/node.h> -struct amd_pmc_stb_v2_data { - size_t size; - u8 data[] __counted_by(size); -}; +#include "pmc.h" -struct amd_pmc_bit_map { - const char *name; - u32 bit_mask; +static const struct amd_pmc_bit_map soc15_ip_blk_v2[] = { + {"DISPLAY", BIT(0)}, + {"CPU", BIT(1)}, + {"GFX", BIT(2)}, + {"VDD", BIT(3)}, + {"VDD_CCX", BIT(4)}, + {"ACP", BIT(5)}, + {"VCN_0", BIT(6)}, + {"VCN_1", BIT(7)}, + {"ISP", BIT(8)}, + {"NBIO", BIT(9)}, + {"DF", BIT(10)}, + {"USB3_0", BIT(11)}, + {"USB3_1", BIT(12)}, + {"LAPIC", BIT(13)}, + {"USB3_2", BIT(14)}, + {"USB4_RT0", BIT(15)}, + {"USB4_RT1", BIT(16)}, + {"USB4_0", BIT(17)}, + {"USB4_1", BIT(18)}, + {"MPM", BIT(19)}, + {"JPEG_0", BIT(20)}, + {"JPEG_1", BIT(21)}, + {"IPU", BIT(22)}, + {"UMSCH", BIT(23)}, + {"VPE", BIT(24)}, }; static const struct amd_pmc_bit_map soc15_ip_blk[] = { @@ -146,25 +83,13 @@ static const struct amd_pmc_bit_map soc15_ip_blk[] = { {"IPU", BIT(19)}, {"UMSCH", BIT(20)}, {"VPE", BIT(21)}, - {} }; -static bool enable_stb; -module_param(enable_stb, bool, 0644); -MODULE_PARM_DESC(enable_stb, "Enable the STB debug mechanism"); - static bool disable_workarounds; module_param(disable_workarounds, bool, 0644); MODULE_PARM_DESC(disable_workarounds, "Disable workarounds for platform bugs"); -static bool dump_custom_stb; -module_param(dump_custom_stb, bool, 0644); -MODULE_PARM_DESC(dump_custom_stb, "Enable to dump full STB buffer"); - static struct amd_pmc_dev pmc; -static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret); -static int amd_pmc_read_stb(struct amd_pmc_dev *dev, u32 *buf); -static int amd_pmc_write_stb(struct amd_pmc_dev *dev, u32 data); static inline u32 amd_pmc_reg_read(struct amd_pmc_dev *dev, int reg_offset) { @@ -176,172 +101,6 @@ static inline void amd_pmc_reg_write(struct amd_pmc_dev *dev, int reg_offset, u3 iowrite32(val, dev->regbase + reg_offset); } -struct smu_metrics { - u32 table_version; - u32 hint_count; - u32 s0i3_last_entry_status; - u32 timein_s0i2; - u64 timeentering_s0i3_lastcapture; - u64 timeentering_s0i3_totaltime; - u64 timeto_resume_to_os_lastcapture; - u64 timeto_resume_to_os_totaltime; - u64 timein_s0i3_lastcapture; - u64 timein_s0i3_totaltime; - u64 timein_swdrips_lastcapture; - u64 timein_swdrips_totaltime; - u64 timecondition_notmet_lastcapture[32]; - u64 timecondition_notmet_totaltime[32]; -} __packed; - -static int amd_pmc_stb_debugfs_open(struct inode *inode, struct file *filp) -{ - struct amd_pmc_dev *dev = filp->f_inode->i_private; - u32 size = FIFO_SIZE * sizeof(u32); - u32 *buf; - int rc; - - buf = kzalloc(size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - rc = amd_pmc_read_stb(dev, buf); - if (rc) { - kfree(buf); - return rc; - } - - filp->private_data = buf; - return rc; -} - -static ssize_t amd_pmc_stb_debugfs_read(struct file *filp, char __user *buf, size_t size, - loff_t *pos) -{ - if (!filp->private_data) - return -EINVAL; - - return simple_read_from_buffer(buf, size, pos, filp->private_data, - FIFO_SIZE * sizeof(u32)); -} - -static int amd_pmc_stb_debugfs_release(struct inode *inode, struct file *filp) -{ - kfree(filp->private_data); - return 0; -} - -static const struct file_operations amd_pmc_stb_debugfs_fops = { - .owner = THIS_MODULE, - .open = amd_pmc_stb_debugfs_open, - .read = amd_pmc_stb_debugfs_read, - .release = amd_pmc_stb_debugfs_release, -}; - -/* Enhanced STB Firmware Reporting Mechanism */ -static int amd_pmc_stb_handle_efr(struct file *filp) -{ - struct amd_pmc_dev *dev = filp->f_inode->i_private; - struct amd_pmc_stb_v2_data *stb_data_arr; - u32 fsize; - - fsize = dev->dram_size - S2D_RSVD_RAM_SPACE; - stb_data_arr = kmalloc(struct_size(stb_data_arr, data, fsize), GFP_KERNEL); - if (!stb_data_arr) - return -ENOMEM; - - stb_data_arr->size = fsize; - memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr, fsize); - filp->private_data = stb_data_arr; - - return 0; -} - -static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp) -{ - struct amd_pmc_dev *dev = filp->f_inode->i_private; - u32 fsize, num_samples, val, stb_rdptr_offset = 0; - struct amd_pmc_stb_v2_data *stb_data_arr; - int ret; - - /* Write dummy postcode while reading the STB buffer */ - ret = amd_pmc_write_stb(dev, AMD_PMC_STB_DUMMY_PC); - if (ret) - dev_err(dev->dev, "error writing to STB: %d\n", ret); - - /* Spill to DRAM num_samples uses separate SMU message port */ - dev->msg_port = 1; - - ret = amd_pmc_send_cmd(dev, 0, &val, STB_FORCE_FLUSH_DATA, 1); - if (ret) - dev_dbg_once(dev->dev, "S2D force flush not supported: %d\n", ret); - - /* - * We have a custom stb size and the PMFW is supposed to give - * the enhanced dram size. Note that we land here only for the - * platforms that support enhanced dram size reporting. - */ - if (dump_custom_stb) - return amd_pmc_stb_handle_efr(filp); - - /* Get the num_samples to calculate the last push location */ - ret = amd_pmc_send_cmd(dev, S2D_NUM_SAMPLES, &num_samples, dev->s2d_msg_id, true); - /* Clear msg_port for other SMU operation */ - dev->msg_port = 0; - if (ret) { - dev_err(dev->dev, "error: S2D_NUM_SAMPLES not supported : %d\n", ret); - return ret; - } - - fsize = min(num_samples, S2D_TELEMETRY_BYTES_MAX); - stb_data_arr = kmalloc(struct_size(stb_data_arr, data, fsize), GFP_KERNEL); - if (!stb_data_arr) - return -ENOMEM; - - stb_data_arr->size = fsize; - - /* - * Start capturing data from the last push location. - * This is for general cases, where the stb limits - * are meant for standard usage. - */ - if (num_samples > S2D_TELEMETRY_BYTES_MAX) { - /* First read oldest data starting 1 behind last write till end of ringbuffer */ - stb_rdptr_offset = num_samples % S2D_TELEMETRY_BYTES_MAX; - fsize = S2D_TELEMETRY_BYTES_MAX - stb_rdptr_offset; - - memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr + stb_rdptr_offset, fsize); - /* Second copy the newer samples from offset 0 - last write */ - memcpy_fromio(stb_data_arr->data + fsize, dev->stb_virt_addr, stb_rdptr_offset); - } else { - memcpy_fromio(stb_data_arr->data, dev->stb_virt_addr, fsize); - } - - filp->private_data = stb_data_arr; - - return 0; -} - -static ssize_t amd_pmc_stb_debugfs_read_v2(struct file *filp, char __user *buf, size_t size, - loff_t *pos) -{ - struct amd_pmc_stb_v2_data *data = filp->private_data; - - return simple_read_from_buffer(buf, size, pos, data->data, data->size); -} - -static int amd_pmc_stb_debugfs_release_v2(struct inode *inode, struct file *filp) -{ - kfree(filp->private_data); - return 0; -} - -static const struct file_operations amd_pmc_stb_debugfs_fops_v2 = { - .owner = THIS_MODULE, - .open = amd_pmc_stb_debugfs_open_v2, - .read = amd_pmc_stb_debugfs_read_v2, - .release = amd_pmc_stb_debugfs_release_v2, -}; - static void amd_pmc_get_ip_info(struct amd_pmc_dev *dev) { switch (dev->cpu_id) { @@ -350,18 +109,23 @@ static void amd_pmc_get_ip_info(struct amd_pmc_dev *dev) case AMD_CPU_ID_YC: case AMD_CPU_ID_CB: dev->num_ips = 12; - dev->s2d_msg_id = 0xBE; + dev->ips_ptr = soc15_ip_blk; dev->smu_msg = 0x538; break; case AMD_CPU_ID_PS: dev->num_ips = 21; - dev->s2d_msg_id = 0x85; + 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: - dev->num_ips = 22; - dev->s2d_msg_id = 0xDE; + 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; break; } @@ -402,11 +166,12 @@ static int amd_pmc_setup_smu_logging(struct amd_pmc_dev *dev) static int get_metrics_table(struct amd_pmc_dev *pdev, struct smu_metrics *table) { - if (!pdev->smu_virt_addr) { - int ret = amd_pmc_setup_smu_logging(pdev); + int rc; - if (ret) - return ret; + if (!pdev->smu_virt_addr) { + rc = amd_pmc_setup_smu_logging(pdev); + if (rc) + return rc; } if (pdev->cpu_id == AMD_CPU_ID_PCO) @@ -455,10 +220,10 @@ static ssize_t smu_fw_version_show(struct device *d, struct device_attribute *at char *buf) { struct amd_pmc_dev *dev = dev_get_drvdata(d); + int rc; if (!dev->major) { - int rc = amd_pmc_get_smu_version(dev); - + rc = amd_pmc_get_smu_version(dev); if (rc) return rc; } @@ -469,10 +234,10 @@ static ssize_t smu_program_show(struct device *d, struct device_attribute *attr, char *buf) { struct amd_pmc_dev *dev = dev_get_drvdata(d); + int rc; if (!dev->major) { - int rc = amd_pmc_get_smu_version(dev); - + rc = amd_pmc_get_smu_version(dev); if (rc) return rc; } @@ -529,8 +294,8 @@ static int smu_fw_info_show(struct seq_file *s, void *unused) seq_puts(s, "\n=== Active time (in us) ===\n"); for (idx = 0 ; idx < dev->num_ips ; idx++) { - if (soc15_ip_blk[idx].bit_mask & dev->active_ips) - seq_printf(s, "%-8s : %lld\n", soc15_ip_blk[idx].name, + if (dev->ips_ptr[idx].bit_mask & dev->active_ips) + seq_printf(s, "%-8s : %lld\n", dev->ips_ptr[idx].name, table.timecondition_notmet_lastcapture[idx]); } @@ -625,20 +390,6 @@ static void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev) debugfs_remove_recursive(dev->dbgfs_dir); } -static bool amd_pmc_is_stb_supported(struct amd_pmc_dev *dev) -{ - switch (dev->cpu_id) { - 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 true; - default: - return false; - } -} - static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) { dev->dbgfs_dir = debugfs_create_dir("amd_pmc", NULL); @@ -648,14 +399,17 @@ static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) &s0ix_stats_fops); debugfs_create_file("amd_pmc_idlemask", 0644, dev->dbgfs_dir, dev, &amd_pmc_idlemask_fops); - /* Enable STB only when the module_param is set */ - if (enable_stb) { - if (amd_pmc_is_stb_supported(dev)) - debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev, - &amd_pmc_stb_debugfs_fops_v2); - else - debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev, - &amd_pmc_stb_debugfs_fops); +} + +static char *amd_pmc_get_msg_port(struct amd_pmc_dev *dev) +{ + switch (dev->msg_port) { + case MSG_PORT_PMC: + return "PMC"; + case MSG_PORT_S2D: + return "S2D"; + default: + return "Invalid message port"; } } @@ -663,10 +417,10 @@ static void amd_pmc_dump_registers(struct amd_pmc_dev *dev) { u32 value, message, argument, response; - if (dev->msg_port) { - message = AMD_S2D_REGISTER_MESSAGE; - argument = AMD_S2D_REGISTER_ARGUMENT; - response = AMD_S2D_REGISTER_RESPONSE; + if (dev->msg_port == MSG_PORT_S2D) { + message = dev->stb_arg.msg; + argument = dev->stb_arg.arg; + response = dev->stb_arg.resp; } else { message = dev->smu_msg; argument = AMD_PMC_REGISTER_ARGUMENT; @@ -674,26 +428,26 @@ static void amd_pmc_dump_registers(struct amd_pmc_dev *dev) } value = amd_pmc_reg_read(dev, response); - dev_dbg(dev->dev, "AMD_%s_REGISTER_RESPONSE:%x\n", dev->msg_port ? "S2D" : "PMC", value); + dev_dbg(dev->dev, "AMD_%s_REGISTER_RESPONSE:%x\n", amd_pmc_get_msg_port(dev), value); value = amd_pmc_reg_read(dev, argument); - dev_dbg(dev->dev, "AMD_%s_REGISTER_ARGUMENT:%x\n", dev->msg_port ? "S2D" : "PMC", value); + dev_dbg(dev->dev, "AMD_%s_REGISTER_ARGUMENT:%x\n", amd_pmc_get_msg_port(dev), value); value = amd_pmc_reg_read(dev, message); - dev_dbg(dev->dev, "AMD_%s_REGISTER_MESSAGE:%x\n", dev->msg_port ? "S2D" : "PMC", value); + dev_dbg(dev->dev, "AMD_%s_REGISTER_MESSAGE:%x\n", amd_pmc_get_msg_port(dev), value); } -static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret) +int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret) { int rc; u32 val, message, argument, response; - mutex_lock(&dev->lock); + guard(mutex)(&dev->lock); - if (dev->msg_port) { - message = AMD_S2D_REGISTER_MESSAGE; - argument = AMD_S2D_REGISTER_ARGUMENT; - response = AMD_S2D_REGISTER_RESPONSE; + if (dev->msg_port == MSG_PORT_S2D) { + message = dev->stb_arg.msg; + argument = dev->stb_arg.arg; + response = dev->stb_arg.resp; } else { message = dev->smu_msg; argument = AMD_PMC_REGISTER_ARGUMENT; @@ -706,7 +460,7 @@ static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, PMC_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX); if (rc) { dev_err(dev->dev, "failed to talk to SMU\n"); - goto out_unlock; + return rc; } /* Write zero to response register */ @@ -724,7 +478,7 @@ static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, PMC_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX); if (rc) { dev_err(dev->dev, "SMU response timed out\n"); - goto out_unlock; + return rc; } switch (val) { @@ -738,21 +492,19 @@ static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, case AMD_PMC_RESULT_CMD_REJECT_BUSY: dev_err(dev->dev, "SMU not ready. err: 0x%x\n", val); rc = -EBUSY; - goto out_unlock; + break; case AMD_PMC_RESULT_CMD_UNKNOWN: dev_err(dev->dev, "SMU cmd unknown. err: 0x%x\n", val); rc = -EINVAL; - goto out_unlock; + break; case AMD_PMC_RESULT_CMD_REJECT_PREREQ: case AMD_PMC_RESULT_FAILED: default: dev_err(dev->dev, "SMU cmd failed. err: 0x%x\n", val); rc = -EIO; - goto out_unlock; + break; } -out_unlock: - mutex_unlock(&dev->lock); amd_pmc_dump_registers(dev); return rc; } @@ -881,7 +633,7 @@ static void amd_pmc_s2idle_prepare(void) return; } - rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_S2IDLE_PREPARE); + rc = amd_stb_write(pdev, AMD_PMC_STB_S2IDLE_PREPARE); if (rc) dev_err(pdev->dev, "error writing to STB: %d\n", rc); } @@ -892,15 +644,14 @@ static void amd_pmc_s2idle_check(void) struct smu_metrics table; int rc; - /* CZN: Ensure that future s0i3 entry attempts at least 10ms passed */ - if (pdev->cpu_id == AMD_CPU_ID_CZN && !get_metrics_table(pdev, &table) && - table.s0i3_last_entry_status) - usleep_range(10000, 20000); + /* Avoid triggering OVP */ + if (!get_metrics_table(pdev, &table) && table.s0i3_last_entry_status) + msleep(2500); /* Dump the IdleMask before we add to the STB */ amd_pmc_idlemask_read(pdev, pdev->dev, NULL); - rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_S2IDLE_CHECK); + rc = amd_stb_write(pdev, AMD_PMC_STB_S2IDLE_CHECK); if (rc) dev_err(pdev->dev, "error writing to STB: %d\n", rc); } @@ -927,7 +678,7 @@ static void amd_pmc_s2idle_restore(void) /* Let SMU know that we are looking for stats */ amd_pmc_dump_data(pdev); - rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_S2IDLE_RESTORE); + rc = amd_stb_write(pdev, AMD_PMC_STB_S2IDLE_RESTORE); if (rc) dev_err(pdev->dev, "error writing to STB: %d\n", rc); @@ -946,14 +697,14 @@ static struct acpi_s2idle_dev_ops amd_pmc_s2idle_dev_ops = { static int amd_pmc_suspend_handler(struct device *dev) { struct amd_pmc_dev *pdev = dev_get_drvdata(dev); + int rc; /* * Must be called only from the same set of dev_pm_ops handlers * as i8042_pm_suspend() is called: currently just from .suspend. */ if (pdev->disable_8042_wakeup && !disable_workarounds) { - int rc = amd_pmc_wa_irq1(pdev); - + rc = amd_pmc_wa_irq1(pdev); if (rc) { dev_err(pdev->dev, "failed to adjust keyboard wakeup: %d\n", rc); return rc; @@ -976,79 +727,12 @@ static const struct pci_device_id pmc_pci_ids[] = { { 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, PCI_DEVICE_ID_AMD_1AH_M20H_ROOT) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M60H_ROOT) }, { } }; -static int amd_pmc_s2d_init(struct amd_pmc_dev *dev) -{ - u32 phys_addr_low, phys_addr_hi; - u64 stb_phys_addr; - u32 size = 0; - int ret; - - /* Spill to DRAM feature uses separate SMU message port */ - dev->msg_port = 1; - - amd_pmc_send_cmd(dev, S2D_TELEMETRY_SIZE, &size, dev->s2d_msg_id, true); - if (size != S2D_TELEMETRY_BYTES_MAX) - return -EIO; - - /* Get DRAM size */ - ret = amd_pmc_send_cmd(dev, S2D_DRAM_SIZE, &dev->dram_size, dev->s2d_msg_id, true); - if (ret || !dev->dram_size) - dev->dram_size = S2D_TELEMETRY_DRAMBYTES_MAX; - - /* Get STB DRAM address */ - amd_pmc_send_cmd(dev, S2D_PHYS_ADDR_LOW, &phys_addr_low, dev->s2d_msg_id, true); - amd_pmc_send_cmd(dev, S2D_PHYS_ADDR_HIGH, &phys_addr_hi, dev->s2d_msg_id, true); - - if (!phys_addr_hi && !phys_addr_low) { - dev_err(dev->dev, "STB is not enabled on the system; disable enable_stb or contact system vendor\n"); - return -EINVAL; - } - - stb_phys_addr = ((u64)phys_addr_hi << 32 | phys_addr_low); - - /* Clear msg_port for other SMU operation */ - dev->msg_port = 0; - - dev->stb_virt_addr = devm_ioremap(dev->dev, stb_phys_addr, dev->dram_size); - if (!dev->stb_virt_addr) - return -ENOMEM; - - return 0; -} - -static int amd_pmc_write_stb(struct amd_pmc_dev *dev, u32 data) -{ - int err; - - err = amd_smn_write(0, AMD_PMC_STB_PMI_0, data); - if (err) { - dev_err(dev->dev, "failed to write data in stb: 0x%X\n", AMD_PMC_STB_PMI_0); - return pcibios_err_to_errno(err); - } - - return 0; -} - -static int amd_pmc_read_stb(struct amd_pmc_dev *dev, u32 *buf) -{ - int i, err; - - for (i = 0; i < FIFO_SIZE; i++) { - err = amd_smn_read(0, AMD_PMC_STB_PMI_0, buf++); - if (err) { - dev_err(dev->dev, "error reading data from stb: 0x%X\n", AMD_PMC_STB_PMI_0); - return pcibios_err_to_errno(err); - } - } - - return 0; -} - static int amd_pmc_probe(struct platform_device *pdev) { struct amd_pmc_dev *dev = &pmc; @@ -1059,7 +743,6 @@ static int amd_pmc_probe(struct platform_device *pdev) u32 val; 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)) { err = -ENODEV; @@ -1067,8 +750,7 @@ static int amd_pmc_probe(struct platform_device *pdev) } dev->cpu_id = rdev->device; - - if (dev->cpu_id == AMD_CPU_ID_SP) { + 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; goto err_pci_dev_put; @@ -1083,7 +765,6 @@ static int amd_pmc_probe(struct platform_device *pdev) } base_addr_lo = val & AMD_PMC_BASE_ADDR_HI_MASK; - err = amd_smn_read(0, AMD_PMC_BASE_ADDR_HI, &val); if (err) { dev_err(dev->dev, "error reading 0x%x\n", AMD_PMC_BASE_ADDR_HI); @@ -1101,17 +782,13 @@ static int amd_pmc_probe(struct platform_device *pdev) goto err_pci_dev_put; } - mutex_init(&dev->lock); + err = devm_mutex_init(dev->dev, &dev->lock); + if (err) + goto err_pci_dev_put; /* Get num of IP blocks within the SoC */ amd_pmc_get_ip_info(dev); - if (enable_stb && amd_pmc_is_stb_supported(dev)) { - err = amd_pmc_s2d_init(dev); - if (err) - goto err_pci_dev_put; - } - platform_set_drvdata(pdev, dev); if (IS_ENABLED(CONFIG_SUSPEND)) { err = acpi_register_lps0_dev(&amd_pmc_s2idle_dev_ops); @@ -1122,6 +799,10 @@ static int amd_pmc_probe(struct platform_device *pdev) } amd_pmc_dbgfs_register(dev); + err = amd_stb_s2d_init(dev); + if (err) + goto err_pci_dev_put; + if (IS_ENABLED(CONFIG_AMD_MP2_STB)) amd_mp2_stb_init(dev); pm_report_max_hw_sleep(U64_MAX); @@ -1142,7 +823,6 @@ static void amd_pmc_remove(struct platform_device *pdev) pci_dev_put(dev->rdev); if (IS_ENABLED(CONFIG_AMD_MP2_STB)) amd_mp2_stb_deinit(dev); - mutex_destroy(&dev->lock); } static const struct acpi_device_id amd_pmc_acpi_ids[] = { diff --git a/drivers/platform/x86/amd/pmc/pmc.h b/drivers/platform/x86/amd/pmc/pmc.h index f1166d15c856..62f3e51020fd 100644 --- a/drivers/platform/x86/amd/pmc/pmc.h +++ b/drivers/platform/x86/amd/pmc/pmc.h @@ -14,6 +14,64 @@ #include <linux/types.h> #include <linux/mutex.h> +/* SMU communication registers */ +#define AMD_PMC_REGISTER_RESPONSE 0x980 +#define AMD_PMC_REGISTER_ARGUMENT 0x9BC + +/* PMC Scratch Registers */ +#define AMD_PMC_SCRATCH_REG_CZN 0x94 +#define AMD_PMC_SCRATCH_REG_YC 0xD14 +#define AMD_PMC_SCRATCH_REG_1AH 0xF14 + +/* STB Registers */ +#define AMD_PMC_STB_S2IDLE_PREPARE 0xC6000001 +#define AMD_PMC_STB_S2IDLE_RESTORE 0xC6000002 +#define AMD_PMC_STB_S2IDLE_CHECK 0xC6000003 + +/* Base address of SMU for mapping physical address to virtual address */ +#define AMD_PMC_MAPPING_SIZE 0x01000 +#define AMD_PMC_BASE_ADDR_OFFSET 0x10000 +#define AMD_PMC_BASE_ADDR_LO 0x13B102E8 +#define AMD_PMC_BASE_ADDR_HI 0x13B102EC +#define AMD_PMC_BASE_ADDR_LO_MASK GENMASK(15, 0) +#define AMD_PMC_BASE_ADDR_HI_MASK GENMASK(31, 20) + +/* SMU Response Codes */ +#define AMD_PMC_RESULT_OK 0x01 +#define AMD_PMC_RESULT_CMD_REJECT_BUSY 0xFC +#define AMD_PMC_RESULT_CMD_REJECT_PREREQ 0xFD +#define AMD_PMC_RESULT_CMD_UNKNOWN 0xFE +#define AMD_PMC_RESULT_FAILED 0xFF + +/* FCH SSC Registers */ +#define FCH_S0I3_ENTRY_TIME_L_OFFSET 0x30 +#define FCH_S0I3_ENTRY_TIME_H_OFFSET 0x34 +#define FCH_S0I3_EXIT_TIME_L_OFFSET 0x38 +#define FCH_S0I3_EXIT_TIME_H_OFFSET 0x3C +#define FCH_SSC_MAPPING_SIZE 0x800 +#define FCH_BASE_PHY_ADDR_LOW 0xFED81100 +#define FCH_BASE_PHY_ADDR_HIGH 0x00000000 + +/* SMU Message Definations */ +#define SMU_MSG_GETSMUVERSION 0x02 +#define SMU_MSG_LOG_GETDRAM_ADDR_HI 0x04 +#define SMU_MSG_LOG_GETDRAM_ADDR_LO 0x05 +#define SMU_MSG_LOG_START 0x06 +#define SMU_MSG_LOG_RESET 0x07 +#define SMU_MSG_LOG_DUMP_DATA 0x08 +#define SMU_MSG_GET_SUP_CONSTRAINTS 0x09 + +#define PMC_MSG_DELAY_MIN_US 50 +#define RESPONSE_REGISTER_LOOP_MAX 20000 + +#define DELAY_MIN_US 2000 +#define DELAY_MAX_US 3000 + +enum s2d_msg_port { + MSG_PORT_PMC, + MSG_PORT_S2D, +}; + struct amd_mp2_dev { void __iomem *mmio; void __iomem *vslbase; @@ -25,24 +83,31 @@ struct amd_mp2_dev { bool is_stb_data; }; +struct stb_arg { + u32 s2d_msg_id; + u32 msg; + u32 arg; + u32 resp; +}; + struct amd_pmc_dev { void __iomem *regbase; void __iomem *smu_virt_addr; void __iomem *stb_virt_addr; void __iomem *fch_virt_addr; - bool msg_port; u32 base_addr; u32 cpu_id; - u32 active_ips; u32 dram_size; + u32 active_ips; + const struct amd_pmc_bit_map *ips_ptr; u32 num_ips; - u32 s2d_msg_id; u32 smu_msg; /* SMU version information */ u8 smu_program; u8 major; u8 minor; u8 rev; + u8 msg_port; struct device *dev; struct pci_dev *rdev; struct mutex lock; /* generic mutex lock */ @@ -50,6 +115,35 @@ struct amd_pmc_dev { struct quirk_entry *quirks; 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; +}; + +struct smu_metrics { + u32 table_version; + u32 hint_count; + u32 s0i3_last_entry_status; + u32 timein_s0i2; + u64 timeentering_s0i3_lastcapture; + u64 timeentering_s0i3_totaltime; + u64 timeto_resume_to_os_lastcapture; + u64 timeto_resume_to_os_totaltime; + u64 timein_s0i3_lastcapture; + u64 timein_s0i3_totaltime; + u64 timein_swdrips_lastcapture; + u64 timein_swdrips_totaltime; + u64 timecondition_notmet_lastcapture[32]; + u64 timecondition_notmet_totaltime[32]; +} __packed; + +enum amd_pmc_def { + MSG_TEST = 0x01, + MSG_OS_HINT_PCO, + MSG_OS_HINT_RN, }; void amd_pmc_process_restore_quirks(struct amd_pmc_dev *dev); @@ -66,8 +160,14 @@ void amd_mp2_stb_deinit(struct amd_pmc_dev *dev); #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 +int amd_stb_s2d_init(struct amd_pmc_dev *dev); +int amd_stb_read(struct amd_pmc_dev *dev, u32 *buf); +int amd_stb_write(struct amd_pmc_dev *dev, u32 data); +int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret); + #endif /* PMC_H */ |