aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/intel_scu_ipc.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-08-04 13:44:06 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-04 13:44:06 -0400
commitc145307a110c14d09d5d92ff3c49dc0940e44b80 (patch)
treecba923818dea8857022de06ffd94ec6b2967aa1f /drivers/platform/x86/intel_scu_ipc.c
parent5e83f6fbdb020b70c0e413312801424d13c58d68 (diff)
parent1a14703d6b20010401ca273ac1f07bff7992aa2c (diff)
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86: (88 commits) ips driver: make it less chatty intel_scu_ipc: fix size field for intel_scu_ipc_command intel_scu_ipc: return -EIO for error condition in busy_loop intel_scu_ipc: fix data packing of PMIC command on Moorestown Clean up command packing on MRST. zero the stack buffer before giving random garbage to the SCU Fix stack buffer size for IPC writev messages intel_scu_ipc: Use the new cpu identification function intel_scu_ipc: tidy up unused bits Remove indirect read write api support. intel_scu_ipc: Support Medfield processors intel_scu_ipc: detect CPU type automatically x86 plat: limit x86 platform driver menu to X86 acpi ec_sys: Be more cautious about ec write access acpi ec: Fix possible double io port registration hp-wmi: acpi_drivers.h is already included through acpi.h two lines below hp-wmi: Fix mixing up of and/or directive dell-laptop: make dell_laptop_i8042_filter() static asus-laptop: fix asus_input_init error path msi-wmi: make needlessly global symbols static ...
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