diff mbox series

[08/10] spi: espi_amd: Add support for IO/MMIO configuration

Message ID 20250313183440.261872-9-Raju.Rangoju@amd.com
State New
Headers show
Series spi: Add driver to support AMD eSPI controller | expand

Commit Message

Raju Rangoju March 13, 2025, 6:34 p.m. UTC
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(+)

Comments

Mark Brown March 17, 2025, 2:10 p.m. UTC | #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.
Raju Rangoju March 26, 2025, 10:12 a.m. UTC | #2
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
diff mbox series

Patch

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