Add support to configure the eSPI slave0 IO/MMIO address before
initiating the peripheral channel IO/MMIO read and write operations.
This patch introduces new IOCTLs to enable, disable and read IO/MMIO
configurations.
Co-developed-by: Krishnamoorthi M <krishnamoorthi.m@amd.com>
Signed-off-by: Krishnamoorthi M <krishnamoorthi.m@amd.com>
Co-developed-by: Akshata MukundShetty <akshata.mukundshetty@amd.com>
Signed-off-by: Akshata MukundShetty <akshata.mukundshetty@amd.com>
Signed-off-by: Raju Rangoju <Raju.Rangoju@amd.com>
---
drivers/spi/espi-amd-core.c | 157 ++++++++++++++++++++++++++++++++++++
drivers/spi/espi-amd-dev.c | 53 ++++++++++++
drivers/spi/espi-amd.h | 91 +++++++++++++++++++++
3 files changed, 301 insertions(+)
diff --git a/drivers/spi/espi-amd-core.c b/drivers/spi/espi-amd-core.c
index 72a625b8b16d..3704cbd816ae 100644
--- a/drivers/spi/espi-amd-core.c
+++ b/drivers/spi/espi-amd-core.c
@@ -553,6 +553,163 @@ int amd_espi_setup_vw_channel(struct amd_espi *amd_espi, u32 slave_caps)
CHANNEL_MODE_VW);
}
+void amd_espi_get_io_mmio_decode_info(struct amd_espi *amd_espi,
+ struct io_mmio_decode_config *config)
+{
+ config->io_mmio_dc_enable = readl(ESPI_BASE + AMD_ESPI_SLAVE0_DECODE_EN_REG);
+ config->range0.val = readl(ESPI_BASE + AMD_ESPI_SLAVE0_IO_BASE_REG0_REG);
+ config->range1.val = readl(ESPI_BASE + AMD_ESPI_SLAVE0_IO_BASE_REG1_REG);
+ config->range2.val = readl(ESPI_BASE + AMD_ESPI_SLAVE0_IO_SIZE_REG);
+ config->mmio_target_range0 = readl(ESPI_BASE + AMD_ESPI_SLAVE0_MMIO_BASE_REG0);
+ config->mmio_target_range1 = readl(ESPI_BASE + AMD_ESPI_SLAVE0_MMIO_BASE_REG1);
+ config->mmio_target_range2 = readl(ESPI_BASE + AMD_ESPI_SLAVE0_MMIO_BASE_REG2);
+ config->mmio_target_range3 = readl(ESPI_BASE + AMD_ESPI_SLAVE0_MMIO_BASE_REG3);
+ config->mmio_range4.val = readl(ESPI_BASE + AMD_ESPI_SLAVE0_MMIO_SIZE_REG0);
+ config->mmio_range5.val = readl(ESPI_BASE + AMD_ESPI_SLAVE0_MMIO_SIZE_REG1);
+}
+
+void amd_espi_set_io_mmio_decode_config(struct amd_espi *amd_espi,
+ struct io_mmio_decode_config *config)
+{
+ struct io_mmio_decode_config io_dc_conf;
+
+ amd_espi_get_io_mmio_decode_info(amd_espi, &io_dc_conf);
+ writel(((~(config->io_mmio_dc_enable) & io_dc_conf.io_mmio_dc_enable) |
+ config->io_mmio_dc_enable), (ESPI_BASE + AMD_ESPI_SLAVE0_DECODE_EN_REG));
+
+ /* IO RANGE-0 configuration */
+ if (config->io_mmio_dc_enable & IO_DECODE_RANGE0) {
+ if (config->range0.base_addr_range0 != io_dc_conf.range0.base_addr_range0) {
+ writel(((io_dc_conf.range0.val & CNTRL_IO_DECODE_ADDR_MASK(0)) |
+ config->range0.val),
+ (ESPI_BASE + AMD_ESPI_SLAVE0_IO_BASE_REG0_REG));
+ writel(((io_dc_conf.range2.val & CNTRL_IO_DECODE_SIZE_MASK(0)) |
+ config->range2.val), (ESPI_BASE + AMD_ESPI_SLAVE0_IO_SIZE_REG));
+ }
+ }
+
+ /* IO RANGE-1 configuration */
+ if (config->io_mmio_dc_enable & IO_DECODE_RANGE1) {
+ if (config->range0.base_addr_range1 != io_dc_conf.range0.base_addr_range1) {
+ writel(((io_dc_conf.range0.val & CNTRL_IO_DECODE_ADDR_MASK(16)) |
+ config->range0.val),
+ (ESPI_BASE + AMD_ESPI_SLAVE0_IO_BASE_REG0_REG));
+ writel(((io_dc_conf.range2.val & CNTRL_IO_DECODE_SIZE_MASK(8)) |
+ config->range2.val), (ESPI_BASE + AMD_ESPI_SLAVE0_IO_SIZE_REG));
+ }
+ }
+
+ /* IO RANGE-2 configuration */
+ if (config->io_mmio_dc_enable & IO_DECODE_RANGE2) {
+ if (config->range1.base_addr_range2 != io_dc_conf.range1.base_addr_range2) {
+ writel(((io_dc_conf.range1.val & CNTRL_IO_DECODE_ADDR_MASK(0)) |
+ config->range1.val),
+ (ESPI_BASE + AMD_ESPI_SLAVE0_IO_BASE_REG1_REG));
+ writel(((io_dc_conf.range2.val & CNTRL_IO_DECODE_SIZE_MASK(16)) |
+ config->range2.val), (ESPI_BASE + AMD_ESPI_SLAVE0_IO_SIZE_REG));
+ }
+ }
+
+ /* IO RANGE-3 configuration */
+ if (config->io_mmio_dc_enable & IO_DECODE_RANGE3) {
+ if (config->range1.base_addr_range3 != io_dc_conf.range1.base_addr_range3) {
+ writel(((io_dc_conf.range1.val & CNTRL_IO_DECODE_ADDR_MASK(16)) |
+ config->range1.val),
+ (ESPI_BASE + AMD_ESPI_SLAVE0_IO_BASE_REG1_REG));
+ writel(((io_dc_conf.range2.val & CNTRL_IO_DECODE_SIZE_MASK(24)) |
+ config->range2.val), (ESPI_BASE + AMD_ESPI_SLAVE0_IO_SIZE_REG));
+ }
+ }
+
+ /* MMIO RANGE-0 configure */
+ if (config->io_mmio_dc_enable & MMIO_DECODE_RANGE0) {
+ if (config->mmio_target_range0 != io_dc_conf.mmio_target_range0) {
+ writel(config->mmio_target_range0,
+ (ESPI_BASE + AMD_ESPI_SLAVE0_MMIO_BASE_REG0));
+ writel(((io_dc_conf.mmio_range4.val & CNTRL_MMIO_DECODE_SIZE_MASK(0)) |
+ config->mmio_range4.val),
+ (ESPI_BASE + AMD_ESPI_SLAVE0_MMIO_SIZE_REG0));
+ }
+ }
+
+ /* MMIO RANGE-1 configure */
+ if (config->io_mmio_dc_enable & MMIO_DECODE_RANGE1) {
+ if (config->mmio_target_range1 != io_dc_conf.mmio_target_range1) {
+ writel(config->mmio_target_range1,
+ (ESPI_BASE + AMD_ESPI_SLAVE0_MMIO_BASE_REG1));
+ writel(((io_dc_conf.mmio_range4.val & CNTRL_MMIO_DECODE_SIZE_MASK(16)) |
+ config->mmio_range4.val),
+ (ESPI_BASE + AMD_ESPI_SLAVE0_MMIO_SIZE_REG0));
+ }
+ }
+
+ /* MMIO RANGE-2 configure */
+ if (config->io_mmio_dc_enable & MMIO_DECODE_RANGE2) {
+ if (config->mmio_target_range2 != io_dc_conf.mmio_target_range2) {
+ writel(config->mmio_target_range2,
+ (ESPI_BASE + AMD_ESPI_SLAVE0_MMIO_BASE_REG2));
+ writel(((io_dc_conf.mmio_range5.val & CNTRL_MMIO_DECODE_SIZE_MASK(0)) |
+ config->mmio_range5.val),
+ (ESPI_BASE + AMD_ESPI_SLAVE0_MMIO_SIZE_REG1));
+ }
+ }
+
+ /* MMIO RANGE-3 configure */
+ if (config->io_mmio_dc_enable & MMIO_DECODE_RANGE3) {
+ if (config->mmio_target_range3 != io_dc_conf.mmio_target_range3) {
+ writel(config->mmio_target_range3,
+ (ESPI_BASE + AMD_ESPI_SLAVE0_MMIO_BASE_REG3));
+ writel(((io_dc_conf.mmio_range5.val & CNTRL_MMIO_DECODE_SIZE_MASK(16)) |
+ config->mmio_range5.val),
+ (ESPI_BASE + AMD_ESPI_SLAVE0_MMIO_SIZE_REG1));
+ }
+ }
+}
+
+void amd_espi_disable_io_decode_range(struct amd_espi *amd_espi, u32 io_range)
+{
+ u32 io_mmio_dc_enable = readl(ESPI_BASE + AMD_ESPI_SLAVE0_DECODE_EN_REG);
+
+ switch (io_range) {
+ case 1:
+ if (io_mmio_dc_enable & IO_DECODE_RANGE0)
+ io_mmio_dc_enable = io_mmio_dc_enable ^ IO_DECODE_RANGE0;
+ break;
+ case 2:
+ if (io_mmio_dc_enable & IO_DECODE_RANGE1)
+ io_mmio_dc_enable = io_mmio_dc_enable ^ IO_DECODE_RANGE1;
+ break;
+ case 3:
+ if (io_mmio_dc_enable & IO_DECODE_RANGE2)
+ io_mmio_dc_enable = io_mmio_dc_enable ^ IO_DECODE_RANGE2;
+ break;
+ case 4:
+ if (io_mmio_dc_enable & IO_DECODE_RANGE3)
+ io_mmio_dc_enable = io_mmio_dc_enable ^ IO_DECODE_RANGE3;
+ break;
+ case 5:
+ if (io_mmio_dc_enable & MMIO_DECODE_RANGE0)
+ io_mmio_dc_enable = io_mmio_dc_enable ^ MMIO_DECODE_RANGE0;
+ break;
+ case 6:
+ if (io_mmio_dc_enable & MMIO_DECODE_RANGE1)
+ io_mmio_dc_enable = io_mmio_dc_enable ^ MMIO_DECODE_RANGE1;
+ break;
+ case 7:
+ if (io_mmio_dc_enable & MMIO_DECODE_RANGE2)
+ io_mmio_dc_enable = io_mmio_dc_enable ^ MMIO_DECODE_RANGE2;
+ break;
+ case 8:
+ if (io_mmio_dc_enable & MMIO_DECODE_RANGE3)
+ io_mmio_dc_enable = io_mmio_dc_enable ^ MMIO_DECODE_RANGE3;
+ break;
+ default:
+ break;
+ }
+
+ writel(io_mmio_dc_enable, (ESPI_BASE + AMD_ESPI_SLAVE0_DECODE_EN_REG));
+}
+
static int amd_espi_get_master_cap(struct amd_espi *amd_espi, struct espi_master *master)
{
u32 master_cap_reg, info;
diff --git a/drivers/spi/espi-amd-dev.c b/drivers/spi/espi-amd-dev.c
index 9f1968566980..31fb06f4a3ff 100644
--- a/drivers/spi/espi-amd-dev.c
+++ b/drivers/spi/espi-amd-dev.c
@@ -286,9 +286,49 @@ static int amd_espi_ioctl_set_freq(struct amd_espi *amd_espi, unsigned long arg)
return ret;
}
+static int amd_espi_ioctl_get_io_decode_conf(struct amd_espi *amd_espi, unsigned long arg)
+{
+ struct io_mmio_decode_config *io_dc_config;
+ int ret = 0;
+
+ io_dc_config = kzalloc(sizeof(*io_dc_config), GFP_KERNEL);
+ if (!io_dc_config)
+ return -ENOMEM;
+
+ amd_espi_get_io_mmio_decode_info(amd_espi, io_dc_config);
+
+ if (copy_to_user((void __user *)arg, io_dc_config, sizeof(struct io_mmio_decode_config)))
+ ret = -EFAULT;
+
+ kfree(io_dc_config);
+ return ret;
+}
+
+static int amd_espi_ioctl_enable_io_decode_conf(struct amd_espi *amd_espi, unsigned long arg)
+{
+ struct io_mmio_decode_config *io_dc_config;
+ int ret = 0;
+
+ io_dc_config = kzalloc(sizeof(*io_dc_config), GFP_KERNEL);
+ if (!io_dc_config)
+ return -ENOMEM;
+
+ if (copy_from_user(io_dc_config, (void __user *)arg,
+ sizeof(struct io_mmio_decode_config))) {
+ ret = -EFAULT;
+ goto decode_config_free;
+ }
+ amd_espi_set_io_mmio_decode_config(amd_espi, io_dc_config);
+
+decode_config_free:
+ kfree(io_dc_config);
+ return ret;
+}
+
static long amd_espi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct amd_espi *amd_espi = filp->private_data;
+ u32 io_range = 0;
int ret = 0;
/* Check type and command number */
@@ -316,6 +356,19 @@ static long amd_espi_ioctl(struct file *filp, unsigned int cmd, unsigned long ar
case ESPI_SET_FREQ:
ret = amd_espi_ioctl_set_freq(amd_espi, arg);
break;
+ case ESPI_GET_IODECODE_CONFIG:
+ ret = amd_espi_ioctl_get_io_decode_conf(amd_espi, arg);
+ break;
+ case ESPI_EN_IODECODE_CONFIG:
+ ret = amd_espi_ioctl_enable_io_decode_conf(amd_espi, arg);
+ break;
+ case ESPI_DS_IODECODE_CONFIG:
+ if (copy_from_user(&io_range, (void __user *)arg, sizeof(unsigned int))) {
+ ret = -EFAULT;
+ break;
+ }
+ amd_espi_disable_io_decode_range(amd_espi, io_range);
+ break;
default:
dev_err(amd_espi->dev, "ESPI command not found, returning error\n");
ret = -EINVAL;
diff --git a/drivers/spi/espi-amd.h b/drivers/spi/espi-amd.h
index e5760db7c1d3..ae76243786f0 100644
--- a/drivers/spi/espi-amd.h
+++ b/drivers/spi/espi-amd.h
@@ -33,6 +33,19 @@
#define AMD_ESPI_MISC_CNTRL_REG0 0x38
#define AMD_ESPI_MISC_CNTRL_REG1 0x3c
+/* Slave-0 registers IO and MMIO config registers */
+#define AMD_ESPI_SLAVE0_DECODE_EN_REG 0x40
+#define AMD_ESPI_SLAVE0_IO_BASE_REG0_REG 0x44
+#define AMD_ESPI_SLAVE0_IO_BASE_REG1_REG 0x48
+#define AMD_ESPI_SLAVE0_IO_SIZE_REG 0x4C
+#define AMD_ESPI_SLAVE0_MMIO_BASE_REG0 0x50
+#define AMD_ESPI_SLAVE0_MMIO_BASE_REG1 0x54
+#define AMD_ESPI_SLAVE0_MMIO_BASE_REG2 0x58
+#define AMD_ESPI_SLAVE0_MMIO_BASE_REG3 0x5C
+#define AMD_ESPI_SLAVE0_MMIO_SIZE_REG0 0x60
+#define AMD_ESPI_SLAVE0_MMIO_SIZE_REG1 0x64
+#define AMD_ESPI_MMIO_ADDR_LEN 4
+
/* Slave-0 configuration and interrupt registers */
#define AMD_ESPI_SLAVE0_CONFIG_REG 0x68
#define AMD_ESPI_SLAVE0_INT_EN_REG 0x6C
@@ -136,6 +149,20 @@
#define ESPI_CNTRL_SET_OP_FREQ(conf, freq) (((conf) & ESPI_CNTRL_OP_MODE_MASK) |\
((freq) << ESPI_CNTRL_SLAVE0_FREQ_SHIFT))
+/* Slave-0 IO and MMIO decode enable configurations */
+#define IO_DECODE_RANGE0 BIT(8)
+#define IO_DECODE_RANGE1 BIT(9)
+#define IO_DECODE_RANGE2 BIT(10)
+#define IO_DECODE_RANGE3 BIT(11)
+#define MMIO_DECODE_RANGE0 BIT(12)
+#define MMIO_DECODE_RANGE1 BIT(13)
+#define MMIO_DECODE_RANGE2 BIT(14)
+#define MMIO_DECODE_RANGE3 BIT(15)
+
+#define CNTRL_IO_DECODE_ADDR_MASK(val) (~(GENMASK(15, 0) << (val)))
+#define CNTRL_IO_DECODE_SIZE_MASK(val) (~(GENMASK(3, 0) << (val)))
+#define CNTRL_MMIO_DECODE_SIZE_MASK(val) (~(GENMASK(15, 0) << (val)))
+
#define ESPI_BASE ((u8 __iomem *)amd_espi->io_remap_addr)
/* IOCTL calls */
@@ -146,6 +173,9 @@
#define ESPI_SET_IO_MODE _IOW(ESPI_MAGIC_NUMBER, 0x4, struct config)
#define ESPI_SET_CHAN_MODE _IOW(ESPI_MAGIC_NUMBER, 0x5, struct config)
#define ESPI_SET_FREQ _IOW(ESPI_MAGIC_NUMBER, 0x6, struct config)
+#define ESPI_GET_IODECODE_CONFIG _IOWR(ESPI_MAGIC_NUMBER, 0x7, struct io_mmio_decode_config)
+#define ESPI_EN_IODECODE_CONFIG _IOWR(ESPI_MAGIC_NUMBER, 0x8, struct io_mmio_decode_config)
+#define ESPI_DS_IODECODE_CONFIG _IOWR(ESPI_MAGIC_NUMBER, 0x9, u32)
/*
* enum amd_espi_versions - eSPI controller versions
@@ -282,6 +312,62 @@ struct espi_txcmd {
u32 expected_status_codes;
};
+/* IO/MMIO decode configuartions */
+union io_target_range0 {
+ u32 val;
+ struct {
+ u16 base_addr_range0;
+ u16 base_addr_range1;
+ };
+};
+
+union io_target_range1 {
+ u32 val;
+ struct {
+ u16 base_addr_range2;
+ u16 base_addr_range3;
+ };
+};
+
+union io_target_range2 {
+ u32 val;
+ struct {
+ u32 io_range0_size:8;
+ u32 io_range1_size:8;
+ u32 io_range2_size:8;
+ u32 io_range3_size:8;
+ };
+};
+
+union mmio_target_range4 {
+ u32 val;
+ struct {
+ u32 mmio_range0_size : 16;
+ u32 mmio_range1_size : 16;
+ };
+};
+
+union mmio_target_range5 {
+ u32 val;
+ struct {
+ u32 mmio_range2_size : 16;
+ u32 mmio_range3_size : 16;
+ };
+};
+
+struct io_mmio_decode_config {
+ u32 io_mmio_dc_enable;
+ union io_target_range0 range0;
+ union io_target_range1 range1;
+ union io_target_range2 range2;
+ u32 mmio_target_range0;
+ u32 mmio_target_range1;
+ u32 mmio_target_range2;
+ u32 mmio_target_range3;
+ union mmio_target_range4 mmio_range4;
+ union mmio_target_range5 mmio_range5;
+};
+
/* Function prototypes */
int amd_espi_device_create(struct amd_espi *amd_espi, struct device *dev);
void amd_espi_device_remove(struct amd_espi *amd_espi);
@@ -297,4 +383,9 @@ int amd_espi_get_channel_config(struct amd_espi *amd_espi);
int amd_espi_setup_periph_channel(struct amd_espi *amd_espi, u32 slave_caps);
int amd_espi_setup_vw_channel(struct amd_espi *amd_espi, u32 slave_caps);
void amd_espi_clr_all_intr(struct amd_espi *amd_espi);
+void amd_espi_get_io_mmio_decode_info(struct amd_espi *amd_espi,
+ struct io_mmio_decode_config *config);
+void amd_espi_set_io_mmio_decode_config(struct amd_espi *amd_espi,
+ struct io_mmio_decode_config *config);
+void amd_espi_disable_io_decode_range(struct amd_espi *amd_espi, u32 io_range);
#endif
--
2.34.1
On Fri, Mar 14, 2025 at 12:04:38AM +0530, Raju Rangoju wrote: > Add support to configure the eSPI slave0 IO/MMIO address before > initiating the peripheral channel IO/MMIO read and write operations. > This patch introduces new IOCTLs to enable, disable and read IO/MMIO > configurations. This absolutely does not seem like something that should be exposed to userspace, if there is some reason for this to be runtime configured it needs to be clearly explained.
On 3/17/2025 7:40 PM, Mark Brown wrote: > On Fri, Mar 14, 2025 at 12:04:38AM +0530, Raju Rangoju wrote: > >> Add support to configure the eSPI slave0 IO/MMIO address before >> initiating the peripheral channel IO/MMIO read and write operations. >> This patch introduces new IOCTLs to enable, disable and read IO/MMIO >> configurations. > > This absolutely does not seem like something that should be exposed to > userspace, if there is some reason for this to be runtime configured it > needs to be clearly explained. Hi Mark, Thanks for reviewing this. In subsequent series we are planning to drop the IOCTLS that are exposed to userspace
© 2016 - 2025 Red Hat, Inc.