aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/intel_scu_ipc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/x86/intel_scu_ipc.c')
-rw-r--r--drivers/platform/x86/intel_scu_ipc.c180
1 files changed, 52 insertions, 128 deletions
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index bb2f1fba637..943f9084dcb 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -23,7 +23,7 @@
23#include <linux/pm.h> 23#include <linux/pm.h>
24#include <linux/pci.h> 24#include <linux/pci.h>
25#include <linux/interrupt.h> 25#include <linux/interrupt.h>
26#include <asm/setup.h> 26#include <asm/mrst.h>
27#include <asm/intel_scu_ipc.h> 27#include <asm/intel_scu_ipc.h>
28 28
29/* IPC defines the following message types */ 29/* IPC defines the following message types */
@@ -38,10 +38,6 @@
38#define IPC_CMD_PCNTRL_R 1 /* Register read */ 38#define IPC_CMD_PCNTRL_R 1 /* Register read */
39#define IPC_CMD_PCNTRL_M 2 /* Register read-modify-write */ 39#define IPC_CMD_PCNTRL_M 2 /* Register read-modify-write */
40 40
41/* Miscelaneous Command ids */
42#define IPC_CMD_INDIRECT_RD 2 /* 32bit indirect read */
43#define IPC_CMD_INDIRECT_WR 5 /* 32bit indirect write */
44
45/* 41/*
46 * IPC register summary 42 * IPC register summary
47 * 43 *
@@ -62,8 +58,8 @@
62 58
63#define IPC_BASE_ADDR 0xFF11C000 /* IPC1 base register address */ 59#define IPC_BASE_ADDR 0xFF11C000 /* IPC1 base register address */
64#define IPC_MAX_ADDR 0x100 /* Maximum IPC regisers */ 60#define IPC_MAX_ADDR 0x100 /* Maximum IPC regisers */
65#define IPC_WWBUF_SIZE 16 /* IPC Write buffer Size */ 61#define IPC_WWBUF_SIZE 20 /* IPC Write buffer Size */
66#define IPC_RWBUF_SIZE 16 /* IPC Read buffer Size */ 62#define IPC_RWBUF_SIZE 20 /* IPC Read buffer Size */
67#define IPC_I2C_BASE 0xFF12B000 /* I2C control register base address */ 63#define IPC_I2C_BASE 0xFF12B000 /* I2C control register base address */
68#define IPC_I2C_MAX_ADDR 0x10 /* Maximum I2C regisers */ 64#define IPC_I2C_MAX_ADDR 0x10 /* Maximum I2C regisers */
69 65
@@ -78,12 +74,7 @@ struct intel_scu_ipc_dev {
78 74
79static struct intel_scu_ipc_dev ipcdev; /* Only one for now */ 75static struct intel_scu_ipc_dev ipcdev; /* Only one for now */
80 76
81static int platform = 1; 77static int platform; /* Platform type */
82module_param(platform, int, 0);
83MODULE_PARM_DESC(platform, "1 for moorestown platform");
84
85
86
87 78
88/* 79/*
89 * IPC Read Buffer (Read Only): 80 * IPC Read Buffer (Read Only):
@@ -119,24 +110,6 @@ static inline void ipc_data_writel(u32 data, u32 offset) /* Write ipc data */
119} 110}
120 111
121/* 112/*
122 * IPC destination Pointer (Write Only):
123 * Use content as pointer for destination write
124 */
125static inline void ipc_write_dptr(u32 data) /* Write dptr data */
126{
127 writel(data, ipcdev.ipc_base + 0x0C);
128}
129
130/*
131 * IPC Source Pointer (Write Only):
132 * Use content as pointer for read location
133*/
134static inline void ipc_write_sptr(u32 data) /* Write dptr data */
135{
136 writel(data, ipcdev.ipc_base + 0x08);
137}
138
139/*
140 * Status Register (Read Only): 113 * Status Register (Read Only):
141 * Driver will read this register to get the ready/busy status of the IPC 114 * Driver will read this register to get the ready/busy status of the IPC
142 * block and error status of the IPC command that was just processed by SCU 115 * block and error status of the IPC command that was just processed by SCU
@@ -154,7 +127,7 @@ static inline u8 ipc_data_readb(u32 offset) /* Read ipc byte data */
154 return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset); 127 return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
155} 128}
156 129
157static inline u8 ipc_data_readl(u32 offset) /* Read ipc u32 data */ 130static inline u32 ipc_data_readl(u32 offset) /* Read ipc u32 data */
158{ 131{
159 return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset); 132 return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
160} 133}
@@ -175,62 +148,73 @@ static inline int busy_loop(void) /* Wait till scu status is busy */
175 return -ETIMEDOUT; 148 return -ETIMEDOUT;
176 } 149 }
177 } 150 }
178 return (status >> 1) & 1; 151 if ((status >> 1) & 1)
152 return -EIO;
153
154 return 0;
179} 155}
180 156
181/* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */ 157/* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */
182static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) 158static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
183{ 159{
184 int nc; 160 int i, nc, bytes, d;
185 u32 offset = 0; 161 u32 offset = 0;
186 u32 err = 0; 162 u32 err = 0;
187 u8 cbuf[IPC_WWBUF_SIZE] = { '\0' }; 163 u8 cbuf[IPC_WWBUF_SIZE] = { };
188 u32 *wbuf = (u32 *)&cbuf; 164 u32 *wbuf = (u32 *)&cbuf;
189 165
190 mutex_lock(&ipclock); 166 mutex_lock(&ipclock);
167
168 memset(cbuf, 0, sizeof(cbuf));
169
191 if (ipcdev.pdev == NULL) { 170 if (ipcdev.pdev == NULL) {
192 mutex_unlock(&ipclock); 171 mutex_unlock(&ipclock);
193 return -ENODEV; 172 return -ENODEV;
194 } 173 }
195 174
196 if (platform == 1) { 175 if (platform != MRST_CPU_CHIP_PENWELL) {
197 /* Entry is 4 bytes for read/write, 5 bytes for read modify */ 176 bytes = 0;
198 for (nc = 0; nc < count; nc++) { 177 d = 0;
178 for (i = 0; i < count; i++) {
179 cbuf[bytes++] = addr[i];
180 cbuf[bytes++] = addr[i] >> 8;
181 if (id != IPC_CMD_PCNTRL_R)
182 cbuf[bytes++] = data[d++];
183 if (id == IPC_CMD_PCNTRL_M)
184 cbuf[bytes++] = data[d++];
185 }
186 for (i = 0; i < bytes; i += 4)
187 ipc_data_writel(wbuf[i/4], i);
188 ipc_command(bytes << 16 | id << 12 | 0 << 8 | op);
189 } else {
190 for (nc = 0; nc < count; nc++, offset += 2) {
199 cbuf[offset] = addr[nc]; 191 cbuf[offset] = addr[nc];
200 cbuf[offset + 1] = addr[nc] >> 8; 192 cbuf[offset + 1] = addr[nc] >> 8;
201 if (id != IPC_CMD_PCNTRL_R)
202 cbuf[offset + 2] = data[nc];
203 if (id == IPC_CMD_PCNTRL_M) {
204 cbuf[offset + 3] = data[nc + 1];
205 offset += 1;
206 }
207 offset += 3;
208 } 193 }
209 for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
210 ipc_data_writel(wbuf[nc], offset); /* Write wbuff */
211 194
212 } else { 195 if (id == IPC_CMD_PCNTRL_R) {
213 for (nc = 0, offset = 0; nc < count; nc++, offset += 2) 196 for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
214 ipc_data_writel(addr[nc], offset); /* Write addresses */ 197 ipc_data_writel(wbuf[nc], offset);
215 if (id != IPC_CMD_PCNTRL_R) { 198 ipc_command((count*2) << 16 | id << 12 | 0 << 8 | op);
216 for (nc = 0; nc < count; nc++, offset++) 199 } else if (id == IPC_CMD_PCNTRL_W) {
217 ipc_data_writel(data[nc], offset); /* Write data */ 200 for (nc = 0; nc < count; nc++, offset += 1)
218 if (id == IPC_CMD_PCNTRL_M) 201 cbuf[offset] = data[nc];
219 ipc_data_writel(data[nc + 1], offset); /* Mask value*/ 202 for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
203 ipc_data_writel(wbuf[nc], offset);
204 ipc_command((count*3) << 16 | id << 12 | 0 << 8 | op);
205 } else if (id == IPC_CMD_PCNTRL_M) {
206 cbuf[offset] = data[0];
207 cbuf[offset + 1] = data[1];
208 ipc_data_writel(wbuf[0], 0); /* Write wbuff */
209 ipc_command(4 << 16 | id << 12 | 0 << 8 | op);
220 } 210 }
221 } 211 }
222 212
223 if (id != IPC_CMD_PCNTRL_M)
224 ipc_command((count * 3) << 16 | id << 12 | 0 << 8 | op);
225 else
226 ipc_command((count * 4) << 16 | id << 12 | 0 << 8 | op);
227
228 err = busy_loop(); 213 err = busy_loop();
229
230 if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */ 214 if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */
231 /* Workaround: values are read as 0 without memcpy_fromio */ 215 /* Workaround: values are read as 0 without memcpy_fromio */
232 memcpy_fromio(cbuf, ipcdev.ipc_base + IPC_READ_BUFFER, 16); 216 memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16);
233 if (platform == 1) { 217 if (platform != MRST_CPU_CHIP_PENWELL) {
234 for (nc = 0, offset = 2; nc < count; nc++, offset += 3) 218 for (nc = 0, offset = 2; nc < count; nc++, offset += 3)
235 data[nc] = ipc_data_readb(offset); 219 data[nc] = ipc_data_readb(offset);
236 } else { 220 } else {
@@ -405,70 +389,6 @@ int intel_scu_ipc_update_register(u16 addr, u8 bits, u8 mask)
405EXPORT_SYMBOL(intel_scu_ipc_update_register); 389EXPORT_SYMBOL(intel_scu_ipc_update_register);
406 390
407/** 391/**
408 * intel_scu_ipc_register_read - 32bit indirect read
409 * @addr: register address
410 * @value: 32bit value return
411 *
412 * Performs IA 32 bit indirect read, returns 0 on success, or an
413 * error code.
414 *
415 * Can be used when SCCB(System Controller Configuration Block) register
416 * HRIM(Honor Restricted IPC Messages) is set (bit 23)
417 *
418 * This function may sleep. Locking for SCU accesses is handled for
419 * the caller.
420 */
421int intel_scu_ipc_register_read(u32 addr, u32 *value)
422{
423 u32 err = 0;
424
425 mutex_lock(&ipclock);
426 if (ipcdev.pdev == NULL) {
427 mutex_unlock(&ipclock);
428 return -ENODEV;
429 }
430 ipc_write_sptr(addr);
431 ipc_command(4 << 16 | IPC_CMD_INDIRECT_RD);
432 err = busy_loop();
433 *value = ipc_data_readl(0);
434 mutex_unlock(&ipclock);
435 return err;
436}
437EXPORT_SYMBOL(intel_scu_ipc_register_read);
438
439/**
440 * intel_scu_ipc_register_write - 32bit indirect write
441 * @addr: register address
442 * @value: 32bit value to write
443 *
444 * Performs IA 32 bit indirect write, returns 0 on success, or an
445 * error code.
446 *
447 * Can be used when SCCB(System Controller Configuration Block) register
448 * HRIM(Honor Restricted IPC Messages) is set (bit 23)
449 *
450 * This function may sleep. Locking for SCU accesses is handled for
451 * the caller.
452 */
453int intel_scu_ipc_register_write(u32 addr, u32 value)
454{
455 u32 err = 0;
456
457 mutex_lock(&ipclock);
458 if (ipcdev.pdev == NULL) {
459 mutex_unlock(&ipclock);
460 return -ENODEV;
461 }
462 ipc_write_dptr(addr);
463 ipc_data_writel(value, 0);
464 ipc_command(4 << 16 | IPC_CMD_INDIRECT_WR);
465 err = busy_loop();
466 mutex_unlock(&ipclock);
467 return err;
468}
469EXPORT_SYMBOL(intel_scu_ipc_register_write);
470
471/**
472 * intel_scu_ipc_simple_command - send a simple command 392 * intel_scu_ipc_simple_command - send a simple command
473 * @cmd: command 393 * @cmd: command
474 * @sub: sub type 394 * @sub: sub type
@@ -524,7 +444,7 @@ int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
524 for (i = 0; i < inlen; i++) 444 for (i = 0; i < inlen; i++)
525 ipc_data_writel(*in++, 4 * i); 445 ipc_data_writel(*in++, 4 * i);
526 446
527 ipc_command((sub << 12) | cmd | (inlen << 18)); 447 ipc_command((inlen << 16) | (sub << 12) | cmd);
528 err = busy_loop(); 448 err = busy_loop();
529 449
530 for (i = 0; i < outlen; i++) 450 for (i = 0; i < outlen; i++)
@@ -803,6 +723,7 @@ static void ipc_remove(struct pci_dev *pdev)
803 723
804static const struct pci_device_id pci_ids[] = { 724static const struct pci_device_id pci_ids[] = {
805 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080e)}, 725 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080e)},
726 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)},
806 { 0,} 727 { 0,}
807}; 728};
808MODULE_DEVICE_TABLE(pci, pci_ids); 729MODULE_DEVICE_TABLE(pci, pci_ids);
@@ -817,6 +738,9 @@ static struct pci_driver ipc_driver = {
817 738
818static int __init intel_scu_ipc_init(void) 739static int __init intel_scu_ipc_init(void)
819{ 740{
741 platform = mrst_identify_cpu();
742 if (platform == 0)
743 return -ENODEV;
820 return pci_register_driver(&ipc_driver); 744 return pci_register_driver(&ipc_driver);
821} 745}
822 746