[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250313183440.261872-9-Raju.Rangoju@amd.com>
Date: Fri, 14 Mar 2025 00:04:38 +0530
From: Raju Rangoju <Raju.Rangoju@....com>
To: <broonie@...nel.org>, <linux-spi@...r.kernel.org>,
<linux-kernel@...r.kernel.org>
CC: <Raju.Rangoju@....com>, <krishnamoorthi.m@....com>,
<akshata.mukundshetty@....com>
Subject: [PATCH 08/10] spi: espi_amd: Add support for IO/MMIO configuration
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@....com>
Signed-off-by: Krishnamoorthi M <krishnamoorthi.m@....com>
Co-developed-by: Akshata MukundShetty <akshata.mukundshetty@....com>
Signed-off-by: Akshata MukundShetty <akshata.mukundshetty@....com>
Signed-off-by: Raju Rangoju <Raju.Rangoju@....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
Powered by blists - more mailing lists