Subject: [PATCH v1 0/3] IPC driver patches

Following patches adds IPC support for addional intel platforms and provides
default interrupt mode support.

Please let me know your review comments.

Kuppuswamy Sathyanarayanan (3):
ipc: Added platform data structure
ipc: Enabled ipc support for additional intel platforms
ipc: Add support for default interrupt mode

drivers/platform/x86/Kconfig | 15 +++++
drivers/platform/x86/intel_scu_ipc.c | 114 ++++++++++++++++++++++++++++++----
2 files changed, 118 insertions(+), 11 deletions(-)

--
1.7.9.5


Subject: [PATCH v1 3/3] ipc: Add support for default interrupt mode

Added intel scu ipc access mode config option.

Also, This patch adds support to enable ipc command interrupt
mode by default. This functionality is enabled by following
config option.

CONFIG_INTEL_SCU_IPC_INTR_MODE=y

Signed-off-by: Kuppuswamy Sathyanarayanan <[email protected]>
---
drivers/platform/x86/Kconfig | 15 ++++++++++
drivers/platform/x86/intel_scu_ipc.c | 53 ++++++++++++++++++++++++++++++++--
2 files changed, 65 insertions(+), 3 deletions(-)

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 36a9e60..26921ce 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -654,6 +654,21 @@ config INTEL_SCU_IPC
some embedded Intel x86 platforms. This is not needed for PC-type
machines.

+choice
+ prompt "IPC access mode"
+ depends on INTEL_SCU_IPC
+ default INTEL_SCU_IPC_INTR_MODE
+ ---help---
+ Select the desired access mode for IPC call.
+
+config INTEL_SCU_IPC_INTR_MODE
+ bool "Intel SCU IPC interrupt mode"
+
+config INTEL_SCU_IPC_POLL_MODE
+ bool "Intel SCU IPC polling mode"
+
+endchoice
+
config INTEL_SCU_IPC_UTIL
tristate "Intel SCU IPC utility driver"
depends on INTEL_SCU_IPC
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index aaaf1c1..6683ee0 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -60,6 +60,7 @@

#define IPC_WWBUF_SIZE 20 /* IPC Write buffer Size */
#define IPC_RWBUF_SIZE 20 /* IPC Read buffer Size */
+#define IPC_IOC 0x100 /* IPC command register IOC bit */

enum {
SCU_IPC_LINCROFT,
@@ -110,6 +111,9 @@ struct intel_scu_ipc_dev {
struct pci_dev *pdev;
void __iomem *ipc_base;
void __iomem *i2c_base;
+#ifdef CONFIG_INTEL_SCU_IPC_INTR_MODE
+ struct completion cmd_complete;
+#endif
};

static struct intel_scu_ipc_dev ipcdev; /* Only one for now */
@@ -136,7 +140,12 @@ static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */
*/
static inline void ipc_command(u32 cmd) /* Send ipc command */
{
+#ifdef CONFIG_INTEL_SCU_IPC_INTR_MODE
+ INIT_COMPLETION(ipcdev.cmd_complete);
+ writel(cmd | IPC_IOC, ipcdev.ipc_base);
+#else
writel(cmd, ipcdev.ipc_base);
+#endif
}

/*
@@ -194,6 +203,37 @@ static inline int busy_loop(void) /* Wait till scu status is busy */
return 0;
}

+#ifdef CONFIG_INTEL_SCU_IPC_INTR_MODE
+/* Wait till ipc ioc interrupt is received or timeout in 3 HZ */
+static inline int ipc_wait_for_interrupt(void)
+{
+ int status;
+ int ret = 0;
+
+ if (!wait_for_completion_timeout(&ipcdev.cmd_complete, 3 * HZ)) {
+ ret = -ETIMEDOUT;
+ goto end;
+ }
+
+ status = ipc_read_status();
+
+ if ((status >> 1) & 1)
+ ret = -EIO;
+
+end:
+ return ret;
+}
+#endif
+
+int intel_scu_ipc_check_status(void)
+{
+#ifdef CONFIG_INTEL_SCU_IPC_INTR_MODE
+ return ipc_wait_for_interrupt();
+#else
+ return busy_loop();
+#endif
+}
+
/* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */
static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
{
@@ -234,7 +274,7 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
ipc_command(4 << 16 | id << 12 | 0 << 8 | op);
}

- err = busy_loop();
+ err = intel_scu_ipc_check_status();
if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */
/* Workaround: values are read as 0 without memcpy_fromio */
memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16);
@@ -429,7 +469,7 @@ int intel_scu_ipc_simple_command(int cmd, int sub)
return -ENODEV;
}
ipc_command(sub << 12 | cmd);
- err = busy_loop();
+ err = intel_scu_ipc_check_status();
mutex_unlock(&ipclock);
return err;
}
@@ -463,7 +503,7 @@ int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
ipc_data_writel(*in++, 4 * i);

ipc_command((inlen << 16) | (sub << 12) | cmd);
- err = busy_loop();
+ err = intel_scu_ipc_check_status();

for (i = 0; i < outlen; i++)
*out++ = ipc_data_readl(4 * i);
@@ -529,6 +569,9 @@ EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl);
*/
static irqreturn_t ioc(int irq, void *dev_id)
{
+#ifdef CONFIG_INTEL_SCU_IPC_INTR_MODE
+ complete(&ipcdev.cmd_complete);
+#endif
return IRQ_HANDLED;
}

@@ -566,6 +609,10 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (!pci_resource)
return -ENOMEM;

+#ifdef CONFIG_INTEL_SCU_IPC_INTR_MODE
+ init_completion(&ipcdev.cmd_complete);
+#endif
+
if (request_irq(dev->irq, ioc, 0, "intel_scu_ipc", &ipcdev))
return -EBUSY;

--
1.7.9.5

Subject: [PATCH v1 2/3] ipc: Enabled ipc support for additional intel platforms

Enabled ipc support for penwell, clovertrail & tangier platforms.

Signed-off-by: Kuppuswamy Sathyanarayanan <[email protected]>
---
drivers/platform/x86/intel_scu_ipc.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)

diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index 93c1b57..aaaf1c1 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -63,6 +63,9 @@

enum {
SCU_IPC_LINCROFT,
+ SCU_IPC_PENWELL,
+ SCU_IPC_CLOVERVIEW,
+ SCU_IPC_TANGIER,
};

/* intel scu ipc driver data*/
@@ -80,6 +83,24 @@ static struct intel_scu_ipc_pdata_t intel_scu_ipc_pdata[] = {
.ipc_len = 0x100,
.i2c_len = 0x10,
},
+ [SCU_IPC_PENWELL] = {
+ .ipc_base = 0xff11c000,
+ .i2c_base = 0xff12b000,
+ .ipc_len = 0x100,
+ .i2c_len = 0x10,
+ },
+ [SCU_IPC_CLOVERVIEW] = {
+ .ipc_base = 0xff11c000,
+ .i2c_base = 0xff12b000,
+ .ipc_len = 0x100,
+ .i2c_len = 0x10,
+ },
+ [SCU_IPC_TANGIER] = {
+ .ipc_base = 0xff009000,
+ .i2c_base = 0xff00d000,
+ .ipc_len = 0x100,
+ .i2c_len = 0x10,
+ },
};

static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id);
@@ -586,6 +607,9 @@ static void ipc_remove(struct pci_dev *pdev)

static DEFINE_PCI_DEVICE_TABLE(pci_ids) = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a), SCU_IPC_LINCROFT},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080e), SCU_IPC_PENWELL},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08ea), SCU_IPC_CLOVERVIEW},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x11a0), SCU_IPC_TANGIER},
{ 0,}
};
MODULE_DEVICE_TABLE(pci, pci_ids);
--
1.7.9.5

Subject: [PATCH v1 1/3] ipc: Added platform data structure

Since the same ipc driver can be used by many platforms, using
macros for defining ipc_base and i2c_base addresses is not
a scalable approach. So added a platform data structure to pass
this information.

Signed-off-by: Kuppuswamy Sathyanarayanan <[email protected]>
---
drivers/platform/x86/intel_scu_ipc.c | 37 ++++++++++++++++++++++++++--------
1 file changed, 29 insertions(+), 8 deletions(-)

diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index 9215ed7..93c1b57 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -58,12 +58,29 @@
* message handler is called within firmware.
*/

-#define IPC_BASE_ADDR 0xFF11C000 /* IPC1 base register address */
-#define IPC_MAX_ADDR 0x100 /* Maximum IPC regisers */
#define IPC_WWBUF_SIZE 20 /* IPC Write buffer Size */
#define IPC_RWBUF_SIZE 20 /* IPC Read buffer Size */
-#define IPC_I2C_BASE 0xFF12B000 /* I2C control register base address */
-#define IPC_I2C_MAX_ADDR 0x10 /* Maximum I2C regisers */
+
+enum {
+ SCU_IPC_LINCROFT,
+};
+
+/* intel scu ipc driver data*/
+struct intel_scu_ipc_pdata_t {
+ u32 ipc_base;
+ u32 i2c_base;
+ u32 ipc_len;
+ u32 i2c_len;
+};
+
+static struct intel_scu_ipc_pdata_t intel_scu_ipc_pdata[] = {
+ [SCU_IPC_LINCROFT] = {
+ .ipc_base = 0xff11c000,
+ .i2c_base = 0xff12b000,
+ .ipc_len = 0x100,
+ .i2c_len = 0x10,
+ },
+};

static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id);
static void ipc_remove(struct pci_dev *pdev);
@@ -504,12 +521,16 @@ static irqreturn_t ioc(int irq, void *dev_id)
*/
static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
- int err;
+ int err, pid;
+ struct intel_scu_ipc_pdata_t *pdata;
resource_size_t pci_resource;

if (ipcdev.pdev) /* We support only one SCU */
return -EBUSY;

+ pid = id->driver_data;
+ pdata = &intel_scu_ipc_pdata[pid];
+
ipcdev.pdev = pci_dev_get(dev);

err = pci_enable_device(dev);
@@ -527,11 +548,11 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (request_irq(dev->irq, ioc, 0, "intel_scu_ipc", &ipcdev))
return -EBUSY;

- ipcdev.ipc_base = ioremap_nocache(IPC_BASE_ADDR, IPC_MAX_ADDR);
+ ipcdev.ipc_base = ioremap_nocache(pdata->ipc_base, pdata->ipc_len);
if (!ipcdev.ipc_base)
return -ENOMEM;

- ipcdev.i2c_base = ioremap_nocache(IPC_I2C_BASE, IPC_I2C_MAX_ADDR);
+ ipcdev.i2c_base = ioremap_nocache(pdata->i2c_base, pdata->i2c_len);
if (!ipcdev.i2c_base) {
iounmap(ipcdev.ipc_base);
return -ENOMEM;
@@ -564,7 +585,7 @@ static void ipc_remove(struct pci_dev *pdev)
}

static DEFINE_PCI_DEVICE_TABLE(pci_ids) = {
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a), SCU_IPC_LINCROFT},
{ 0,}
};
MODULE_DEVICE_TABLE(pci, pci_ids);
--
1.7.9.5

2013-09-03 11:48:31

by Matthew Garrett

[permalink] [raw]
Subject: Re: [PATCH v1 3/3] ipc: Add support for default interrupt mode

On Mon, 2013-07-22 at 19:48 -0700, Kuppuswamy Sathyanarayanan wrote:
> Added intel scu ipc access mode config option.
>
> Also, This patch adds support to enable ipc command interrupt
> mode by default. This functionality is enabled by following
> config option.
>
> CONFIG_INTEL_SCU_IPC_INTR_MODE=y

Can you document this in the help text? It's unclear whether people
should enable this option or not.
--
Matthew Garrett <[email protected]>
????{.n?+???????+%?????ݶ??w??{.n?+????{??G?????{ay?ʇڙ?,j??f???h?????????z_??(?階?ݢj"???m??????G????????????&???~???iO???z??v?^?m???? ????????I?

Subject: Re: [PATCH v1 3/3] ipc: Add support for default interrupt mode

> On Mon, 2013-07-22 at 19:48 -0700, Kuppuswamy Sathyanarayanan wrote:
>> Added intel scu ipc access mode config option.
>>
>> Also, This patch adds support to enable ipc command interrupt
>> mode by default. This functionality is enabled by following
>> config option.
>>
>> CONFIG_INTEL_SCU_IPC_INTR_MODE=y
>
> Can you document this in the help text? It's unclear whether people
> should enable this option or not.

Thanks for the review. I will update the help content in my next patchset.

> --
> Matthew Garrett <[email protected]>
>

--
Sathyanarayanan Kuppuswamy