diff options
author | Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com> | 2013-11-15 19:21:54 -0500 |
---|---|---|
committer | Matthew Garrett <matthew.garrett@nebula.com> | 2013-11-20 20:16:21 -0500 |
commit | ed12f295bfd5c378970106891f12999589aec4e5 (patch) | |
tree | f98475306d6404a1dcc35370b88ed810e30c4494 /drivers/platform/x86 | |
parent | c7094d1d994c23950d8a55d33dcb7ed6d9b13f8f (diff) |
ipc: Added support for IPC interrupt mode
This patch adds support for ipc command interrupt mode.
Also added platform data option to select 'irq_mode'
irq_mode = 1: configure the driver to receive IOC interrupt
for each successful ipc_command.
irq_mode = 0: makes driver use polling method to
track the command completion status.
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: David Cohen <david.a.cohen@linux.intel.com>
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
Diffstat (limited to 'drivers/platform/x86')
-rw-r--r-- | drivers/platform/x86/intel_scu_ipc.c | 48 |
1 files changed, 45 insertions, 3 deletions
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index e26830f6c8dd..60ea476a9130 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c | |||
@@ -60,6 +60,7 @@ | |||
60 | 60 | ||
61 | #define IPC_WWBUF_SIZE 20 /* IPC Write buffer Size */ | 61 | #define IPC_WWBUF_SIZE 20 /* IPC Write buffer Size */ |
62 | #define IPC_RWBUF_SIZE 20 /* IPC Read buffer Size */ | 62 | #define IPC_RWBUF_SIZE 20 /* IPC Read buffer Size */ |
63 | #define IPC_IOC 0x100 /* IPC command register IOC bit */ | ||
63 | 64 | ||
64 | enum { | 65 | enum { |
65 | SCU_IPC_LINCROFT, | 66 | SCU_IPC_LINCROFT, |
@@ -74,6 +75,7 @@ struct intel_scu_ipc_pdata_t { | |||
74 | u32 i2c_base; | 75 | u32 i2c_base; |
75 | u32 ipc_len; | 76 | u32 ipc_len; |
76 | u32 i2c_len; | 77 | u32 i2c_len; |
78 | u8 irq_mode; | ||
77 | }; | 79 | }; |
78 | 80 | ||
79 | static struct intel_scu_ipc_pdata_t intel_scu_ipc_pdata[] = { | 81 | static struct intel_scu_ipc_pdata_t intel_scu_ipc_pdata[] = { |
@@ -82,24 +84,28 @@ static struct intel_scu_ipc_pdata_t intel_scu_ipc_pdata[] = { | |||
82 | .i2c_base = 0xff12b000, | 84 | .i2c_base = 0xff12b000, |
83 | .ipc_len = 0x100, | 85 | .ipc_len = 0x100, |
84 | .i2c_len = 0x10, | 86 | .i2c_len = 0x10, |
87 | .irq_mode = 0, | ||
85 | }, | 88 | }, |
86 | [SCU_IPC_PENWELL] = { | 89 | [SCU_IPC_PENWELL] = { |
87 | .ipc_base = 0xff11c000, | 90 | .ipc_base = 0xff11c000, |
88 | .i2c_base = 0xff12b000, | 91 | .i2c_base = 0xff12b000, |
89 | .ipc_len = 0x100, | 92 | .ipc_len = 0x100, |
90 | .i2c_len = 0x10, | 93 | .i2c_len = 0x10, |
94 | .irq_mode = 1, | ||
91 | }, | 95 | }, |
92 | [SCU_IPC_CLOVERVIEW] = { | 96 | [SCU_IPC_CLOVERVIEW] = { |
93 | .ipc_base = 0xff11c000, | 97 | .ipc_base = 0xff11c000, |
94 | .i2c_base = 0xff12b000, | 98 | .i2c_base = 0xff12b000, |
95 | .ipc_len = 0x100, | 99 | .ipc_len = 0x100, |
96 | .i2c_len = 0x10, | 100 | .i2c_len = 0x10, |
101 | .irq_mode = 1, | ||
97 | }, | 102 | }, |
98 | [SCU_IPC_TANGIER] = { | 103 | [SCU_IPC_TANGIER] = { |
99 | .ipc_base = 0xff009000, | 104 | .ipc_base = 0xff009000, |
100 | .i2c_base = 0xff00d000, | 105 | .i2c_base = 0xff00d000, |
101 | .ipc_len = 0x100, | 106 | .ipc_len = 0x100, |
102 | .i2c_len = 0x10, | 107 | .i2c_len = 0x10, |
108 | .irq_mode = 0, | ||
103 | }, | 109 | }, |
104 | }; | 110 | }; |
105 | 111 | ||
@@ -110,6 +116,8 @@ struct intel_scu_ipc_dev { | |||
110 | struct pci_dev *pdev; | 116 | struct pci_dev *pdev; |
111 | void __iomem *ipc_base; | 117 | void __iomem *ipc_base; |
112 | void __iomem *i2c_base; | 118 | void __iomem *i2c_base; |
119 | struct completion cmd_complete; | ||
120 | u8 irq_mode; | ||
113 | }; | 121 | }; |
114 | 122 | ||
115 | static struct intel_scu_ipc_dev ipcdev; /* Only one for now */ | 123 | static struct intel_scu_ipc_dev ipcdev; /* Only one for now */ |
@@ -136,6 +144,10 @@ static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */ | |||
136 | */ | 144 | */ |
137 | static inline void ipc_command(u32 cmd) /* Send ipc command */ | 145 | static inline void ipc_command(u32 cmd) /* Send ipc command */ |
138 | { | 146 | { |
147 | if (ipcdev.irq_mode) { | ||
148 | reinit_completion(&ipcdev.cmd_complete); | ||
149 | writel(cmd | IPC_IOC, ipcdev.ipc_base); | ||
150 | } | ||
139 | writel(cmd, ipcdev.ipc_base); | 151 | writel(cmd, ipcdev.ipc_base); |
140 | } | 152 | } |
141 | 153 | ||
@@ -194,6 +206,30 @@ static inline int busy_loop(void) /* Wait till scu status is busy */ | |||
194 | return 0; | 206 | return 0; |
195 | } | 207 | } |
196 | 208 | ||
209 | /* Wait till ipc ioc interrupt is received or timeout in 3 HZ */ | ||
210 | static inline int ipc_wait_for_interrupt(void) | ||
211 | { | ||
212 | int status; | ||
213 | |||
214 | if (!wait_for_completion_timeout(&ipcdev.cmd_complete, 3 * HZ)) { | ||
215 | struct device *dev = &ipcdev.pdev->dev; | ||
216 | dev_err(dev, "IPC timed out\n"); | ||
217 | return -ETIMEDOUT; | ||
218 | } | ||
219 | |||
220 | status = ipc_read_status(); | ||
221 | |||
222 | if ((status >> 1) & 1) | ||
223 | return -EIO; | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | int intel_scu_ipc_check_status(void) | ||
229 | { | ||
230 | return ipcdev.irq_mode ? ipc_wait_for_interrupt() : busy_loop(); | ||
231 | } | ||
232 | |||
197 | /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */ | 233 | /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */ |
198 | static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) | 234 | static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) |
199 | { | 235 | { |
@@ -234,7 +270,7 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) | |||
234 | ipc_command(4 << 16 | id << 12 | 0 << 8 | op); | 270 | ipc_command(4 << 16 | id << 12 | 0 << 8 | op); |
235 | } | 271 | } |
236 | 272 | ||
237 | err = busy_loop(); | 273 | err = intel_scu_ipc_check_status(); |
238 | if (!err && id == IPC_CMD_PCNTRL_R) { /* Read rbuf */ | 274 | if (!err && id == IPC_CMD_PCNTRL_R) { /* Read rbuf */ |
239 | /* Workaround: values are read as 0 without memcpy_fromio */ | 275 | /* Workaround: values are read as 0 without memcpy_fromio */ |
240 | memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16); | 276 | memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16); |
@@ -429,7 +465,7 @@ int intel_scu_ipc_simple_command(int cmd, int sub) | |||
429 | return -ENODEV; | 465 | return -ENODEV; |
430 | } | 466 | } |
431 | ipc_command(sub << 12 | cmd); | 467 | ipc_command(sub << 12 | cmd); |
432 | err = busy_loop(); | 468 | err = intel_scu_ipc_check_status(); |
433 | mutex_unlock(&ipclock); | 469 | mutex_unlock(&ipclock); |
434 | return err; | 470 | return err; |
435 | } | 471 | } |
@@ -463,7 +499,7 @@ int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen, | |||
463 | ipc_data_writel(*in++, 4 * i); | 499 | ipc_data_writel(*in++, 4 * i); |
464 | 500 | ||
465 | ipc_command((inlen << 16) | (sub << 12) | cmd); | 501 | ipc_command((inlen << 16) | (sub << 12) | cmd); |
466 | err = busy_loop(); | 502 | err = intel_scu_ipc_check_status(); |
467 | 503 | ||
468 | if (!err) { | 504 | if (!err) { |
469 | for (i = 0; i < outlen; i++) | 505 | for (i = 0; i < outlen; i++) |
@@ -531,6 +567,9 @@ EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl); | |||
531 | */ | 567 | */ |
532 | static irqreturn_t ioc(int irq, void *dev_id) | 568 | static irqreturn_t ioc(int irq, void *dev_id) |
533 | { | 569 | { |
570 | if (ipcdev.irq_mode) | ||
571 | complete(&ipcdev.cmd_complete); | ||
572 | |||
534 | return IRQ_HANDLED; | 573 | return IRQ_HANDLED; |
535 | } | 574 | } |
536 | 575 | ||
@@ -555,6 +594,7 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
555 | pdata = &intel_scu_ipc_pdata[pid]; | 594 | pdata = &intel_scu_ipc_pdata[pid]; |
556 | 595 | ||
557 | ipcdev.pdev = pci_dev_get(dev); | 596 | ipcdev.pdev = pci_dev_get(dev); |
597 | ipcdev.irq_mode = pdata->irq_mode; | ||
558 | 598 | ||
559 | err = pci_enable_device(dev); | 599 | err = pci_enable_device(dev); |
560 | if (err) | 600 | if (err) |
@@ -568,6 +608,8 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
568 | if (!pci_resource) | 608 | if (!pci_resource) |
569 | return -ENOMEM; | 609 | return -ENOMEM; |
570 | 610 | ||
611 | init_completion(&ipcdev.cmd_complete); | ||
612 | |||
571 | if (request_irq(dev->irq, ioc, 0, "intel_scu_ipc", &ipcdev)) | 613 | if (request_irq(dev->irq, ioc, 0, "intel_scu_ipc", &ipcdev)) |
572 | return -EBUSY; | 614 | return -EBUSY; |
573 | 615 | ||