diff options
Diffstat (limited to 'drivers/platform/x86/intel_scu_ipc.c')
| -rw-r--r-- | drivers/platform/x86/intel_scu_ipc.c | 180 |
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 | ||
| 79 | static struct intel_scu_ipc_dev ipcdev; /* Only one for now */ | 75 | static struct intel_scu_ipc_dev ipcdev; /* Only one for now */ |
| 80 | 76 | ||
| 81 | static int platform = 1; | 77 | static int platform; /* Platform type */ |
| 82 | module_param(platform, int, 0); | ||
| 83 | MODULE_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 | */ | ||
| 125 | static 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 | */ | ||
| 134 | static 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 | ||
| 157 | static inline u8 ipc_data_readl(u32 offset) /* Read ipc u32 data */ | 130 | static 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 */ |
| 182 | static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) | 158 | static 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) | |||
| 405 | EXPORT_SYMBOL(intel_scu_ipc_update_register); | 389 | EXPORT_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 | */ | ||
| 421 | int 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 | } | ||
| 437 | EXPORT_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 | */ | ||
| 453 | int 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 | } | ||
| 469 | EXPORT_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 | ||
| 804 | static const struct pci_device_id pci_ids[] = { | 724 | static 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 | }; |
| 808 | MODULE_DEVICE_TABLE(pci, pci_ids); | 729 | MODULE_DEVICE_TABLE(pci, pci_ids); |
| @@ -817,6 +738,9 @@ static struct pci_driver ipc_driver = { | |||
| 817 | 738 | ||
| 818 | static int __init intel_scu_ipc_init(void) | 739 | static 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 | ||
