Commit 4707375ff667c7b090985a846883a671d7391895
Committed by
Ingo Molnar
1 parent
33e9970add
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
x86/mid/scu_ipc: Remove Moorestown support
All the production devices use the PC compatible version of this device so don't use the SCU interfaces or the SCU firmware interfaces. Delete lots of code and conditional paths Signed-off-by: Alan Cox <alan@linux.intel.com> Acked-by: H. Peter Anvin <hpa@zytor.com> Cc: Matthew Garrett <mjg@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Link: http://lkml.kernel.org/n/tip-4bg4fn9na37b350ohhgiy18n@git.kernel.org Signed-off-by: Ingo Molnar <mingo@elte.hu>
Showing 2 changed files with 30 additions and 210 deletions Inline Diff
drivers/platform/x86/intel_scu_ipc.c
1 | /* | 1 | /* |
2 | * intel_scu_ipc.c: Driver for the Intel SCU IPC mechanism | 2 | * intel_scu_ipc.c: Driver for the Intel SCU IPC mechanism |
3 | * | 3 | * |
4 | * (C) Copyright 2008-2010 Intel Corporation | 4 | * (C) Copyright 2008-2010 Intel Corporation |
5 | * Author: Sreedhara DS (sreedhara.ds@intel.com) | 5 | * Author: Sreedhara DS (sreedhara.ds@intel.com) |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
9 | * as published by the Free Software Foundation; version 2 | 9 | * as published by the Free Software Foundation; version 2 |
10 | * of the License. | 10 | * of the License. |
11 | * | 11 | * |
12 | * SCU running in ARC processor communicates with other entity running in IA | 12 | * SCU running in ARC processor communicates with other entity running in IA |
13 | * core through IPC mechanism which in turn messaging between IA core ad SCU. | 13 | * core through IPC mechanism which in turn messaging between IA core ad SCU. |
14 | * SCU has two IPC mechanism IPC-1 and IPC-2. IPC-1 is used between IA32 and | 14 | * SCU has two IPC mechanism IPC-1 and IPC-2. IPC-1 is used between IA32 and |
15 | * SCU where IPC-2 is used between P-Unit and SCU. This driver delas with | 15 | * SCU where IPC-2 is used between P-Unit and SCU. This driver delas with |
16 | * IPC-1 Driver provides an API for power control unit registers (e.g. MSIC) | 16 | * IPC-1 Driver provides an API for power control unit registers (e.g. MSIC) |
17 | * along with other APIs. | 17 | * along with other APIs. |
18 | */ | 18 | */ |
19 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
20 | #include <linux/errno.h> | 20 | #include <linux/errno.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/device.h> | 22 | #include <linux/device.h> |
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 <linux/sfi.h> | 26 | #include <linux/sfi.h> |
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <asm/mrst.h> | 28 | #include <asm/mrst.h> |
29 | #include <asm/intel_scu_ipc.h> | 29 | #include <asm/intel_scu_ipc.h> |
30 | 30 | ||
31 | /* IPC defines the following message types */ | 31 | /* IPC defines the following message types */ |
32 | #define IPCMSG_WATCHDOG_TIMER 0xF8 /* Set Kernel Watchdog Threshold */ | 32 | #define IPCMSG_WATCHDOG_TIMER 0xF8 /* Set Kernel Watchdog Threshold */ |
33 | #define IPCMSG_BATTERY 0xEF /* Coulomb Counter Accumulator */ | 33 | #define IPCMSG_BATTERY 0xEF /* Coulomb Counter Accumulator */ |
34 | #define IPCMSG_FW_UPDATE 0xFE /* Firmware update */ | 34 | #define IPCMSG_FW_UPDATE 0xFE /* Firmware update */ |
35 | #define IPCMSG_PCNTRL 0xFF /* Power controller unit read/write */ | 35 | #define IPCMSG_PCNTRL 0xFF /* Power controller unit read/write */ |
36 | #define IPCMSG_FW_REVISION 0xF4 /* Get firmware revision */ | 36 | #define IPCMSG_FW_REVISION 0xF4 /* Get firmware revision */ |
37 | 37 | ||
38 | /* Command id associated with message IPCMSG_PCNTRL */ | 38 | /* Command id associated with message IPCMSG_PCNTRL */ |
39 | #define IPC_CMD_PCNTRL_W 0 /* Register write */ | 39 | #define IPC_CMD_PCNTRL_W 0 /* Register write */ |
40 | #define IPC_CMD_PCNTRL_R 1 /* Register read */ | 40 | #define IPC_CMD_PCNTRL_R 1 /* Register read */ |
41 | #define IPC_CMD_PCNTRL_M 2 /* Register read-modify-write */ | 41 | #define IPC_CMD_PCNTRL_M 2 /* Register read-modify-write */ |
42 | 42 | ||
43 | /* | 43 | /* |
44 | * IPC register summary | 44 | * IPC register summary |
45 | * | 45 | * |
46 | * IPC register blocks are memory mapped at fixed address of 0xFF11C000 | 46 | * IPC register blocks are memory mapped at fixed address of 0xFF11C000 |
47 | * To read or write information to the SCU, driver writes to IPC-1 memory | 47 | * To read or write information to the SCU, driver writes to IPC-1 memory |
48 | * mapped registers (base address 0xFF11C000). The following is the IPC | 48 | * mapped registers (base address 0xFF11C000). The following is the IPC |
49 | * mechanism | 49 | * mechanism |
50 | * | 50 | * |
51 | * 1. IA core cDMI interface claims this transaction and converts it to a | 51 | * 1. IA core cDMI interface claims this transaction and converts it to a |
52 | * Transaction Layer Packet (TLP) message which is sent across the cDMI. | 52 | * Transaction Layer Packet (TLP) message which is sent across the cDMI. |
53 | * | 53 | * |
54 | * 2. South Complex cDMI block receives this message and writes it to | 54 | * 2. South Complex cDMI block receives this message and writes it to |
55 | * the IPC-1 register block, causing an interrupt to the SCU | 55 | * the IPC-1 register block, causing an interrupt to the SCU |
56 | * | 56 | * |
57 | * 3. SCU firmware decodes this interrupt and IPC message and the appropriate | 57 | * 3. SCU firmware decodes this interrupt and IPC message and the appropriate |
58 | * message handler is called within firmware. | 58 | * message handler is called within firmware. |
59 | */ | 59 | */ |
60 | 60 | ||
61 | #define IPC_BASE_ADDR 0xFF11C000 /* IPC1 base register address */ | 61 | #define IPC_BASE_ADDR 0xFF11C000 /* IPC1 base register address */ |
62 | #define IPC_MAX_ADDR 0x100 /* Maximum IPC regisers */ | 62 | #define IPC_MAX_ADDR 0x100 /* Maximum IPC regisers */ |
63 | #define IPC_WWBUF_SIZE 20 /* IPC Write buffer Size */ | 63 | #define IPC_WWBUF_SIZE 20 /* IPC Write buffer Size */ |
64 | #define IPC_RWBUF_SIZE 20 /* IPC Read buffer Size */ | 64 | #define IPC_RWBUF_SIZE 20 /* IPC Read buffer Size */ |
65 | #define IPC_I2C_BASE 0xFF12B000 /* I2C control register base address */ | 65 | #define IPC_I2C_BASE 0xFF12B000 /* I2C control register base address */ |
66 | #define IPC_I2C_MAX_ADDR 0x10 /* Maximum I2C regisers */ | 66 | #define IPC_I2C_MAX_ADDR 0x10 /* Maximum I2C regisers */ |
67 | 67 | ||
68 | static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id); | 68 | static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id); |
69 | static void ipc_remove(struct pci_dev *pdev); | 69 | static void ipc_remove(struct pci_dev *pdev); |
70 | 70 | ||
71 | struct intel_scu_ipc_dev { | 71 | struct intel_scu_ipc_dev { |
72 | struct pci_dev *pdev; | 72 | struct pci_dev *pdev; |
73 | void __iomem *ipc_base; | 73 | void __iomem *ipc_base; |
74 | void __iomem *i2c_base; | 74 | void __iomem *i2c_base; |
75 | }; | 75 | }; |
76 | 76 | ||
77 | static struct intel_scu_ipc_dev ipcdev; /* Only one for now */ | 77 | static struct intel_scu_ipc_dev ipcdev; /* Only one for now */ |
78 | 78 | ||
79 | static int platform; /* Platform type */ | 79 | static int platform; /* Platform type */ |
80 | 80 | ||
81 | /* | 81 | /* |
82 | * IPC Read Buffer (Read Only): | 82 | * IPC Read Buffer (Read Only): |
83 | * 16 byte buffer for receiving data from SCU, if IPC command | 83 | * 16 byte buffer for receiving data from SCU, if IPC command |
84 | * processing results in response data | 84 | * processing results in response data |
85 | */ | 85 | */ |
86 | #define IPC_READ_BUFFER 0x90 | 86 | #define IPC_READ_BUFFER 0x90 |
87 | 87 | ||
88 | #define IPC_I2C_CNTRL_ADDR 0 | 88 | #define IPC_I2C_CNTRL_ADDR 0 |
89 | #define I2C_DATA_ADDR 0x04 | 89 | #define I2C_DATA_ADDR 0x04 |
90 | 90 | ||
91 | static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */ | 91 | static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */ |
92 | 92 | ||
93 | /* | 93 | /* |
94 | * Command Register (Write Only): | 94 | * Command Register (Write Only): |
95 | * A write to this register results in an interrupt to the SCU core processor | 95 | * A write to this register results in an interrupt to the SCU core processor |
96 | * Format: | 96 | * Format: |
97 | * |rfu2(8) | size(8) | command id(4) | rfu1(3) | ioc(1) | command(8)| | 97 | * |rfu2(8) | size(8) | command id(4) | rfu1(3) | ioc(1) | command(8)| |
98 | */ | 98 | */ |
99 | static inline void ipc_command(u32 cmd) /* Send ipc command */ | 99 | static inline void ipc_command(u32 cmd) /* Send ipc command */ |
100 | { | 100 | { |
101 | writel(cmd, ipcdev.ipc_base); | 101 | writel(cmd, ipcdev.ipc_base); |
102 | } | 102 | } |
103 | 103 | ||
104 | /* | 104 | /* |
105 | * IPC Write Buffer (Write Only): | 105 | * IPC Write Buffer (Write Only): |
106 | * 16-byte buffer for sending data associated with IPC command to | 106 | * 16-byte buffer for sending data associated with IPC command to |
107 | * SCU. Size of the data is specified in the IPC_COMMAND_REG register | 107 | * SCU. Size of the data is specified in the IPC_COMMAND_REG register |
108 | */ | 108 | */ |
109 | static inline void ipc_data_writel(u32 data, u32 offset) /* Write ipc data */ | 109 | static inline void ipc_data_writel(u32 data, u32 offset) /* Write ipc data */ |
110 | { | 110 | { |
111 | writel(data, ipcdev.ipc_base + 0x80 + offset); | 111 | writel(data, ipcdev.ipc_base + 0x80 + offset); |
112 | } | 112 | } |
113 | 113 | ||
114 | /* | 114 | /* |
115 | * Status Register (Read Only): | 115 | * Status Register (Read Only): |
116 | * Driver will read this register to get the ready/busy status of the IPC | 116 | * Driver will read this register to get the ready/busy status of the IPC |
117 | * block and error status of the IPC command that was just processed by SCU | 117 | * block and error status of the IPC command that was just processed by SCU |
118 | * Format: | 118 | * Format: |
119 | * |rfu3(8)|error code(8)|initiator id(8)|cmd id(4)|rfu1(2)|error(1)|busy(1)| | 119 | * |rfu3(8)|error code(8)|initiator id(8)|cmd id(4)|rfu1(2)|error(1)|busy(1)| |
120 | */ | 120 | */ |
121 | 121 | ||
122 | static inline u8 ipc_read_status(void) | 122 | static inline u8 ipc_read_status(void) |
123 | { | 123 | { |
124 | return __raw_readl(ipcdev.ipc_base + 0x04); | 124 | return __raw_readl(ipcdev.ipc_base + 0x04); |
125 | } | 125 | } |
126 | 126 | ||
127 | static inline u8 ipc_data_readb(u32 offset) /* Read ipc byte data */ | 127 | static inline u8 ipc_data_readb(u32 offset) /* Read ipc byte data */ |
128 | { | 128 | { |
129 | return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset); | 129 | return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset); |
130 | } | 130 | } |
131 | 131 | ||
132 | static inline u32 ipc_data_readl(u32 offset) /* Read ipc u32 data */ | 132 | static inline u32 ipc_data_readl(u32 offset) /* Read ipc u32 data */ |
133 | { | 133 | { |
134 | return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset); | 134 | return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset); |
135 | } | 135 | } |
136 | 136 | ||
137 | static inline int busy_loop(void) /* Wait till scu status is busy */ | 137 | static inline int busy_loop(void) /* Wait till scu status is busy */ |
138 | { | 138 | { |
139 | u32 status = 0; | 139 | u32 status = 0; |
140 | u32 loop_count = 0; | 140 | u32 loop_count = 0; |
141 | 141 | ||
142 | status = ipc_read_status(); | 142 | status = ipc_read_status(); |
143 | while (status & 1) { | 143 | while (status & 1) { |
144 | udelay(1); /* scu processing time is in few u secods */ | 144 | udelay(1); /* scu processing time is in few u secods */ |
145 | status = ipc_read_status(); | 145 | status = ipc_read_status(); |
146 | loop_count++; | 146 | loop_count++; |
147 | /* break if scu doesn't reset busy bit after huge retry */ | 147 | /* break if scu doesn't reset busy bit after huge retry */ |
148 | if (loop_count > 100000) { | 148 | if (loop_count > 100000) { |
149 | dev_err(&ipcdev.pdev->dev, "IPC timed out"); | 149 | dev_err(&ipcdev.pdev->dev, "IPC timed out"); |
150 | return -ETIMEDOUT; | 150 | return -ETIMEDOUT; |
151 | } | 151 | } |
152 | } | 152 | } |
153 | if ((status >> 1) & 1) | 153 | if ((status >> 1) & 1) |
154 | return -EIO; | 154 | return -EIO; |
155 | 155 | ||
156 | return 0; | 156 | return 0; |
157 | } | 157 | } |
158 | 158 | ||
159 | /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */ | 159 | /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */ |
160 | static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) | 160 | static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) |
161 | { | 161 | { |
162 | int i, nc, bytes, d; | 162 | int nc; |
163 | u32 offset = 0; | 163 | u32 offset = 0; |
164 | int err; | 164 | int err; |
165 | u8 cbuf[IPC_WWBUF_SIZE] = { }; | 165 | u8 cbuf[IPC_WWBUF_SIZE] = { }; |
166 | u32 *wbuf = (u32 *)&cbuf; | 166 | u32 *wbuf = (u32 *)&cbuf; |
167 | 167 | ||
168 | mutex_lock(&ipclock); | 168 | mutex_lock(&ipclock); |
169 | 169 | ||
170 | memset(cbuf, 0, sizeof(cbuf)); | 170 | memset(cbuf, 0, sizeof(cbuf)); |
171 | 171 | ||
172 | if (ipcdev.pdev == NULL) { | 172 | if (ipcdev.pdev == NULL) { |
173 | mutex_unlock(&ipclock); | 173 | mutex_unlock(&ipclock); |
174 | return -ENODEV; | 174 | return -ENODEV; |
175 | } | 175 | } |
176 | 176 | ||
177 | if (platform != MRST_CPU_CHIP_PENWELL) { | 177 | for (nc = 0; nc < count; nc++, offset += 2) { |
178 | bytes = 0; | 178 | cbuf[offset] = addr[nc]; |
179 | d = 0; | 179 | cbuf[offset + 1] = addr[nc] >> 8; |
180 | for (i = 0; i < count; i++) { | 180 | } |
181 | cbuf[bytes++] = addr[i]; | ||
182 | cbuf[bytes++] = addr[i] >> 8; | ||
183 | if (id != IPC_CMD_PCNTRL_R) | ||
184 | cbuf[bytes++] = data[d++]; | ||
185 | if (id == IPC_CMD_PCNTRL_M) | ||
186 | cbuf[bytes++] = data[d++]; | ||
187 | } | ||
188 | for (i = 0; i < bytes; i += 4) | ||
189 | ipc_data_writel(wbuf[i/4], i); | ||
190 | ipc_command(bytes << 16 | id << 12 | 0 << 8 | op); | ||
191 | } else { | ||
192 | for (nc = 0; nc < count; nc++, offset += 2) { | ||
193 | cbuf[offset] = addr[nc]; | ||
194 | cbuf[offset + 1] = addr[nc] >> 8; | ||
195 | } | ||
196 | 181 | ||
197 | if (id == IPC_CMD_PCNTRL_R) { | 182 | if (id == IPC_CMD_PCNTRL_R) { |
198 | for (nc = 0, offset = 0; nc < count; nc++, offset += 4) | 183 | for (nc = 0, offset = 0; nc < count; nc++, offset += 4) |
199 | ipc_data_writel(wbuf[nc], offset); | 184 | ipc_data_writel(wbuf[nc], offset); |
200 | ipc_command((count*2) << 16 | id << 12 | 0 << 8 | op); | 185 | ipc_command((count*2) << 16 | id << 12 | 0 << 8 | op); |
201 | } else if (id == IPC_CMD_PCNTRL_W) { | 186 | } else if (id == IPC_CMD_PCNTRL_W) { |
202 | for (nc = 0; nc < count; nc++, offset += 1) | 187 | for (nc = 0; nc < count; nc++, offset += 1) |
203 | cbuf[offset] = data[nc]; | 188 | cbuf[offset] = data[nc]; |
204 | for (nc = 0, offset = 0; nc < count; nc++, offset += 4) | 189 | for (nc = 0, offset = 0; nc < count; nc++, offset += 4) |
205 | ipc_data_writel(wbuf[nc], offset); | 190 | ipc_data_writel(wbuf[nc], offset); |
206 | ipc_command((count*3) << 16 | id << 12 | 0 << 8 | op); | 191 | ipc_command((count*3) << 16 | id << 12 | 0 << 8 | op); |
207 | } else if (id == IPC_CMD_PCNTRL_M) { | 192 | } else if (id == IPC_CMD_PCNTRL_M) { |
208 | cbuf[offset] = data[0]; | 193 | cbuf[offset] = data[0]; |
209 | cbuf[offset + 1] = data[1]; | 194 | cbuf[offset + 1] = data[1]; |
210 | ipc_data_writel(wbuf[0], 0); /* Write wbuff */ | 195 | ipc_data_writel(wbuf[0], 0); /* Write wbuff */ |
211 | ipc_command(4 << 16 | id << 12 | 0 << 8 | op); | 196 | ipc_command(4 << 16 | id << 12 | 0 << 8 | op); |
212 | } | ||
213 | } | 197 | } |
214 | 198 | ||
215 | err = busy_loop(); | 199 | err = busy_loop(); |
216 | if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */ | 200 | if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */ |
217 | /* Workaround: values are read as 0 without memcpy_fromio */ | 201 | /* Workaround: values are read as 0 without memcpy_fromio */ |
218 | memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16); | 202 | memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16); |
219 | if (platform != MRST_CPU_CHIP_PENWELL) { | 203 | for (nc = 0; nc < count; nc++) |
220 | for (nc = 0, offset = 2; nc < count; nc++, offset += 3) | 204 | data[nc] = ipc_data_readb(nc); |
221 | data[nc] = ipc_data_readb(offset); | ||
222 | } else { | ||
223 | for (nc = 0; nc < count; nc++) | ||
224 | data[nc] = ipc_data_readb(nc); | ||
225 | } | ||
226 | } | 205 | } |
227 | mutex_unlock(&ipclock); | 206 | mutex_unlock(&ipclock); |
228 | return err; | 207 | return err; |
229 | } | 208 | } |
230 | 209 | ||
231 | /** | 210 | /** |
232 | * intel_scu_ipc_ioread8 - read a word via the SCU | 211 | * intel_scu_ipc_ioread8 - read a word via the SCU |
233 | * @addr: register on SCU | 212 | * @addr: register on SCU |
234 | * @data: return pointer for read byte | 213 | * @data: return pointer for read byte |
235 | * | 214 | * |
236 | * Read a single register. Returns 0 on success or an error code. All | 215 | * Read a single register. Returns 0 on success or an error code. All |
237 | * locking between SCU accesses is handled for the caller. | 216 | * locking between SCU accesses is handled for the caller. |
238 | * | 217 | * |
239 | * This function may sleep. | 218 | * This function may sleep. |
240 | */ | 219 | */ |
241 | int intel_scu_ipc_ioread8(u16 addr, u8 *data) | 220 | int intel_scu_ipc_ioread8(u16 addr, u8 *data) |
242 | { | 221 | { |
243 | return pwr_reg_rdwr(&addr, data, 1, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R); | 222 | return pwr_reg_rdwr(&addr, data, 1, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R); |
244 | } | 223 | } |
245 | EXPORT_SYMBOL(intel_scu_ipc_ioread8); | 224 | EXPORT_SYMBOL(intel_scu_ipc_ioread8); |
246 | 225 | ||
247 | /** | 226 | /** |
248 | * intel_scu_ipc_ioread16 - read a word via the SCU | 227 | * intel_scu_ipc_ioread16 - read a word via the SCU |
249 | * @addr: register on SCU | 228 | * @addr: register on SCU |
250 | * @data: return pointer for read word | 229 | * @data: return pointer for read word |
251 | * | 230 | * |
252 | * Read a register pair. Returns 0 on success or an error code. All | 231 | * Read a register pair. Returns 0 on success or an error code. All |
253 | * locking between SCU accesses is handled for the caller. | 232 | * locking between SCU accesses is handled for the caller. |
254 | * | 233 | * |
255 | * This function may sleep. | 234 | * This function may sleep. |
256 | */ | 235 | */ |
257 | int intel_scu_ipc_ioread16(u16 addr, u16 *data) | 236 | int intel_scu_ipc_ioread16(u16 addr, u16 *data) |
258 | { | 237 | { |
259 | u16 x[2] = {addr, addr + 1 }; | 238 | u16 x[2] = {addr, addr + 1 }; |
260 | return pwr_reg_rdwr(x, (u8 *)data, 2, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R); | 239 | return pwr_reg_rdwr(x, (u8 *)data, 2, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R); |
261 | } | 240 | } |
262 | EXPORT_SYMBOL(intel_scu_ipc_ioread16); | 241 | EXPORT_SYMBOL(intel_scu_ipc_ioread16); |
263 | 242 | ||
264 | /** | 243 | /** |
265 | * intel_scu_ipc_ioread32 - read a dword via the SCU | 244 | * intel_scu_ipc_ioread32 - read a dword via the SCU |
266 | * @addr: register on SCU | 245 | * @addr: register on SCU |
267 | * @data: return pointer for read dword | 246 | * @data: return pointer for read dword |
268 | * | 247 | * |
269 | * Read four registers. Returns 0 on success or an error code. All | 248 | * Read four registers. Returns 0 on success or an error code. All |
270 | * locking between SCU accesses is handled for the caller. | 249 | * locking between SCU accesses is handled for the caller. |
271 | * | 250 | * |
272 | * This function may sleep. | 251 | * This function may sleep. |
273 | */ | 252 | */ |
274 | int intel_scu_ipc_ioread32(u16 addr, u32 *data) | 253 | int intel_scu_ipc_ioread32(u16 addr, u32 *data) |
275 | { | 254 | { |
276 | u16 x[4] = {addr, addr + 1, addr + 2, addr + 3}; | 255 | u16 x[4] = {addr, addr + 1, addr + 2, addr + 3}; |
277 | return pwr_reg_rdwr(x, (u8 *)data, 4, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R); | 256 | return pwr_reg_rdwr(x, (u8 *)data, 4, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R); |
278 | } | 257 | } |
279 | EXPORT_SYMBOL(intel_scu_ipc_ioread32); | 258 | EXPORT_SYMBOL(intel_scu_ipc_ioread32); |
280 | 259 | ||
281 | /** | 260 | /** |
282 | * intel_scu_ipc_iowrite8 - write a byte via the SCU | 261 | * intel_scu_ipc_iowrite8 - write a byte via the SCU |
283 | * @addr: register on SCU | 262 | * @addr: register on SCU |
284 | * @data: byte to write | 263 | * @data: byte to write |
285 | * | 264 | * |
286 | * Write a single register. Returns 0 on success or an error code. All | 265 | * Write a single register. Returns 0 on success or an error code. All |
287 | * locking between SCU accesses is handled for the caller. | 266 | * locking between SCU accesses is handled for the caller. |
288 | * | 267 | * |
289 | * This function may sleep. | 268 | * This function may sleep. |
290 | */ | 269 | */ |
291 | int intel_scu_ipc_iowrite8(u16 addr, u8 data) | 270 | int intel_scu_ipc_iowrite8(u16 addr, u8 data) |
292 | { | 271 | { |
293 | return pwr_reg_rdwr(&addr, &data, 1, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W); | 272 | return pwr_reg_rdwr(&addr, &data, 1, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W); |
294 | } | 273 | } |
295 | EXPORT_SYMBOL(intel_scu_ipc_iowrite8); | 274 | EXPORT_SYMBOL(intel_scu_ipc_iowrite8); |
296 | 275 | ||
297 | /** | 276 | /** |
298 | * intel_scu_ipc_iowrite16 - write a word via the SCU | 277 | * intel_scu_ipc_iowrite16 - write a word via the SCU |
299 | * @addr: register on SCU | 278 | * @addr: register on SCU |
300 | * @data: word to write | 279 | * @data: word to write |
301 | * | 280 | * |
302 | * Write two registers. Returns 0 on success or an error code. All | 281 | * Write two registers. Returns 0 on success or an error code. All |
303 | * locking between SCU accesses is handled for the caller. | 282 | * locking between SCU accesses is handled for the caller. |
304 | * | 283 | * |
305 | * This function may sleep. | 284 | * This function may sleep. |
306 | */ | 285 | */ |
307 | int intel_scu_ipc_iowrite16(u16 addr, u16 data) | 286 | int intel_scu_ipc_iowrite16(u16 addr, u16 data) |
308 | { | 287 | { |
309 | u16 x[2] = {addr, addr + 1 }; | 288 | u16 x[2] = {addr, addr + 1 }; |
310 | return pwr_reg_rdwr(x, (u8 *)&data, 2, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W); | 289 | return pwr_reg_rdwr(x, (u8 *)&data, 2, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W); |
311 | } | 290 | } |
312 | EXPORT_SYMBOL(intel_scu_ipc_iowrite16); | 291 | EXPORT_SYMBOL(intel_scu_ipc_iowrite16); |
313 | 292 | ||
314 | /** | 293 | /** |
315 | * intel_scu_ipc_iowrite32 - write a dword via the SCU | 294 | * intel_scu_ipc_iowrite32 - write a dword via the SCU |
316 | * @addr: register on SCU | 295 | * @addr: register on SCU |
317 | * @data: dword to write | 296 | * @data: dword to write |
318 | * | 297 | * |
319 | * Write four registers. Returns 0 on success or an error code. All | 298 | * Write four registers. Returns 0 on success or an error code. All |
320 | * locking between SCU accesses is handled for the caller. | 299 | * locking between SCU accesses is handled for the caller. |
321 | * | 300 | * |
322 | * This function may sleep. | 301 | * This function may sleep. |
323 | */ | 302 | */ |
324 | int intel_scu_ipc_iowrite32(u16 addr, u32 data) | 303 | int intel_scu_ipc_iowrite32(u16 addr, u32 data) |
325 | { | 304 | { |
326 | u16 x[4] = {addr, addr + 1, addr + 2, addr + 3}; | 305 | u16 x[4] = {addr, addr + 1, addr + 2, addr + 3}; |
327 | return pwr_reg_rdwr(x, (u8 *)&data, 4, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W); | 306 | return pwr_reg_rdwr(x, (u8 *)&data, 4, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W); |
328 | } | 307 | } |
329 | EXPORT_SYMBOL(intel_scu_ipc_iowrite32); | 308 | EXPORT_SYMBOL(intel_scu_ipc_iowrite32); |
330 | 309 | ||
331 | /** | 310 | /** |
332 | * intel_scu_ipc_readvv - read a set of registers | 311 | * intel_scu_ipc_readvv - read a set of registers |
333 | * @addr: register list | 312 | * @addr: register list |
334 | * @data: bytes to return | 313 | * @data: bytes to return |
335 | * @len: length of array | 314 | * @len: length of array |
336 | * | 315 | * |
337 | * Read registers. Returns 0 on success or an error code. All | 316 | * Read registers. Returns 0 on success or an error code. All |
338 | * locking between SCU accesses is handled for the caller. | 317 | * locking between SCU accesses is handled for the caller. |
339 | * | 318 | * |
340 | * The largest array length permitted by the hardware is 5 items. | 319 | * The largest array length permitted by the hardware is 5 items. |
341 | * | 320 | * |
342 | * This function may sleep. | 321 | * This function may sleep. |
343 | */ | 322 | */ |
344 | int intel_scu_ipc_readv(u16 *addr, u8 *data, int len) | 323 | int intel_scu_ipc_readv(u16 *addr, u8 *data, int len) |
345 | { | 324 | { |
346 | return pwr_reg_rdwr(addr, data, len, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R); | 325 | return pwr_reg_rdwr(addr, data, len, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R); |
347 | } | 326 | } |
348 | EXPORT_SYMBOL(intel_scu_ipc_readv); | 327 | EXPORT_SYMBOL(intel_scu_ipc_readv); |
349 | 328 | ||
350 | /** | 329 | /** |
351 | * intel_scu_ipc_writev - write a set of registers | 330 | * intel_scu_ipc_writev - write a set of registers |
352 | * @addr: register list | 331 | * @addr: register list |
353 | * @data: bytes to write | 332 | * @data: bytes to write |
354 | * @len: length of array | 333 | * @len: length of array |
355 | * | 334 | * |
356 | * Write registers. Returns 0 on success or an error code. All | 335 | * Write registers. Returns 0 on success or an error code. All |
357 | * locking between SCU accesses is handled for the caller. | 336 | * locking between SCU accesses is handled for the caller. |
358 | * | 337 | * |
359 | * The largest array length permitted by the hardware is 5 items. | 338 | * The largest array length permitted by the hardware is 5 items. |
360 | * | 339 | * |
361 | * This function may sleep. | 340 | * This function may sleep. |
362 | * | 341 | * |
363 | */ | 342 | */ |
364 | int intel_scu_ipc_writev(u16 *addr, u8 *data, int len) | 343 | int intel_scu_ipc_writev(u16 *addr, u8 *data, int len) |
365 | { | 344 | { |
366 | return pwr_reg_rdwr(addr, data, len, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W); | 345 | return pwr_reg_rdwr(addr, data, len, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W); |
367 | } | 346 | } |
368 | EXPORT_SYMBOL(intel_scu_ipc_writev); | 347 | EXPORT_SYMBOL(intel_scu_ipc_writev); |
369 | 348 | ||
370 | 349 | ||
371 | /** | 350 | /** |
372 | * intel_scu_ipc_update_register - r/m/w a register | 351 | * intel_scu_ipc_update_register - r/m/w a register |
373 | * @addr: register address | 352 | * @addr: register address |
374 | * @bits: bits to update | 353 | * @bits: bits to update |
375 | * @mask: mask of bits to update | 354 | * @mask: mask of bits to update |
376 | * | 355 | * |
377 | * Read-modify-write power control unit register. The first data argument | 356 | * Read-modify-write power control unit register. The first data argument |
378 | * must be register value and second is mask value | 357 | * must be register value and second is mask value |
379 | * mask is a bitmap that indicates which bits to update. | 358 | * mask is a bitmap that indicates which bits to update. |
380 | * 0 = masked. Don't modify this bit, 1 = modify this bit. | 359 | * 0 = masked. Don't modify this bit, 1 = modify this bit. |
381 | * returns 0 on success or an error code. | 360 | * returns 0 on success or an error code. |
382 | * | 361 | * |
383 | * This function may sleep. Locking between SCU accesses is handled | 362 | * This function may sleep. Locking between SCU accesses is handled |
384 | * for the caller. | 363 | * for the caller. |
385 | */ | 364 | */ |
386 | int intel_scu_ipc_update_register(u16 addr, u8 bits, u8 mask) | 365 | int intel_scu_ipc_update_register(u16 addr, u8 bits, u8 mask) |
387 | { | 366 | { |
388 | u8 data[2] = { bits, mask }; | 367 | u8 data[2] = { bits, mask }; |
389 | return pwr_reg_rdwr(&addr, data, 1, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_M); | 368 | return pwr_reg_rdwr(&addr, data, 1, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_M); |
390 | } | 369 | } |
391 | EXPORT_SYMBOL(intel_scu_ipc_update_register); | 370 | EXPORT_SYMBOL(intel_scu_ipc_update_register); |
392 | 371 | ||
393 | /** | 372 | /** |
394 | * intel_scu_ipc_simple_command - send a simple command | 373 | * intel_scu_ipc_simple_command - send a simple command |
395 | * @cmd: command | 374 | * @cmd: command |
396 | * @sub: sub type | 375 | * @sub: sub type |
397 | * | 376 | * |
398 | * Issue a simple command to the SCU. Do not use this interface if | 377 | * Issue a simple command to the SCU. Do not use this interface if |
399 | * you must then access data as any data values may be overwritten | 378 | * you must then access data as any data values may be overwritten |
400 | * by another SCU access by the time this function returns. | 379 | * by another SCU access by the time this function returns. |
401 | * | 380 | * |
402 | * This function may sleep. Locking for SCU accesses is handled for | 381 | * This function may sleep. Locking for SCU accesses is handled for |
403 | * the caller. | 382 | * the caller. |
404 | */ | 383 | */ |
405 | int intel_scu_ipc_simple_command(int cmd, int sub) | 384 | int intel_scu_ipc_simple_command(int cmd, int sub) |
406 | { | 385 | { |
407 | int err; | 386 | int err; |
408 | 387 | ||
409 | mutex_lock(&ipclock); | 388 | mutex_lock(&ipclock); |
410 | if (ipcdev.pdev == NULL) { | 389 | if (ipcdev.pdev == NULL) { |
411 | mutex_unlock(&ipclock); | 390 | mutex_unlock(&ipclock); |
412 | return -ENODEV; | 391 | return -ENODEV; |
413 | } | 392 | } |
414 | ipc_command(sub << 12 | cmd); | 393 | ipc_command(sub << 12 | cmd); |
415 | err = busy_loop(); | 394 | err = busy_loop(); |
416 | mutex_unlock(&ipclock); | 395 | mutex_unlock(&ipclock); |
417 | return err; | 396 | return err; |
418 | } | 397 | } |
419 | EXPORT_SYMBOL(intel_scu_ipc_simple_command); | 398 | EXPORT_SYMBOL(intel_scu_ipc_simple_command); |
420 | 399 | ||
421 | /** | 400 | /** |
422 | * intel_scu_ipc_command - command with data | 401 | * intel_scu_ipc_command - command with data |
423 | * @cmd: command | 402 | * @cmd: command |
424 | * @sub: sub type | 403 | * @sub: sub type |
425 | * @in: input data | 404 | * @in: input data |
426 | * @inlen: input length in dwords | 405 | * @inlen: input length in dwords |
427 | * @out: output data | 406 | * @out: output data |
428 | * @outlein: output length in dwords | 407 | * @outlein: output length in dwords |
429 | * | 408 | * |
430 | * Issue a command to the SCU which involves data transfers. Do the | 409 | * Issue a command to the SCU which involves data transfers. Do the |
431 | * data copies under the lock but leave it for the caller to interpret | 410 | * data copies under the lock but leave it for the caller to interpret |
432 | */ | 411 | */ |
433 | 412 | ||
434 | int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen, | 413 | int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen, |
435 | u32 *out, int outlen) | 414 | u32 *out, int outlen) |
436 | { | 415 | { |
437 | int i, err; | 416 | int i, err; |
438 | 417 | ||
439 | mutex_lock(&ipclock); | 418 | mutex_lock(&ipclock); |
440 | if (ipcdev.pdev == NULL) { | 419 | if (ipcdev.pdev == NULL) { |
441 | mutex_unlock(&ipclock); | 420 | mutex_unlock(&ipclock); |
442 | return -ENODEV; | 421 | return -ENODEV; |
443 | } | 422 | } |
444 | 423 | ||
445 | for (i = 0; i < inlen; i++) | 424 | for (i = 0; i < inlen; i++) |
446 | ipc_data_writel(*in++, 4 * i); | 425 | ipc_data_writel(*in++, 4 * i); |
447 | 426 | ||
448 | ipc_command((inlen << 16) | (sub << 12) | cmd); | 427 | ipc_command((inlen << 16) | (sub << 12) | cmd); |
449 | err = busy_loop(); | 428 | err = busy_loop(); |
450 | 429 | ||
451 | for (i = 0; i < outlen; i++) | 430 | for (i = 0; i < outlen; i++) |
452 | *out++ = ipc_data_readl(4 * i); | 431 | *out++ = ipc_data_readl(4 * i); |
453 | 432 | ||
454 | mutex_unlock(&ipclock); | 433 | mutex_unlock(&ipclock); |
455 | return err; | 434 | return err; |
456 | } | 435 | } |
457 | EXPORT_SYMBOL(intel_scu_ipc_command); | 436 | EXPORT_SYMBOL(intel_scu_ipc_command); |
458 | 437 | ||
459 | /*I2C commands */ | 438 | /*I2C commands */ |
460 | #define IPC_I2C_WRITE 1 /* I2C Write command */ | 439 | #define IPC_I2C_WRITE 1 /* I2C Write command */ |
461 | #define IPC_I2C_READ 2 /* I2C Read command */ | 440 | #define IPC_I2C_READ 2 /* I2C Read command */ |
462 | 441 | ||
463 | /** | 442 | /** |
464 | * intel_scu_ipc_i2c_cntrl - I2C read/write operations | 443 | * intel_scu_ipc_i2c_cntrl - I2C read/write operations |
465 | * @addr: I2C address + command bits | 444 | * @addr: I2C address + command bits |
466 | * @data: data to read/write | 445 | * @data: data to read/write |
467 | * | 446 | * |
468 | * Perform an an I2C read/write operation via the SCU. All locking is | 447 | * Perform an an I2C read/write operation via the SCU. All locking is |
469 | * handled for the caller. This function may sleep. | 448 | * handled for the caller. This function may sleep. |
470 | * | 449 | * |
471 | * Returns an error code or 0 on success. | 450 | * Returns an error code or 0 on success. |
472 | * | 451 | * |
473 | * This has to be in the IPC driver for the locking. | 452 | * This has to be in the IPC driver for the locking. |
474 | */ | 453 | */ |
475 | int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data) | 454 | int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data) |
476 | { | 455 | { |
477 | u32 cmd = 0; | 456 | u32 cmd = 0; |
478 | 457 | ||
479 | mutex_lock(&ipclock); | 458 | mutex_lock(&ipclock); |
480 | if (ipcdev.pdev == NULL) { | 459 | if (ipcdev.pdev == NULL) { |
481 | mutex_unlock(&ipclock); | 460 | mutex_unlock(&ipclock); |
482 | return -ENODEV; | 461 | return -ENODEV; |
483 | } | 462 | } |
484 | cmd = (addr >> 24) & 0xFF; | 463 | cmd = (addr >> 24) & 0xFF; |
485 | if (cmd == IPC_I2C_READ) { | 464 | if (cmd == IPC_I2C_READ) { |
486 | writel(addr, ipcdev.i2c_base + IPC_I2C_CNTRL_ADDR); | 465 | writel(addr, ipcdev.i2c_base + IPC_I2C_CNTRL_ADDR); |
487 | /* Write not getting updated without delay */ | 466 | /* Write not getting updated without delay */ |
488 | mdelay(1); | 467 | mdelay(1); |
489 | *data = readl(ipcdev.i2c_base + I2C_DATA_ADDR); | 468 | *data = readl(ipcdev.i2c_base + I2C_DATA_ADDR); |
490 | } else if (cmd == IPC_I2C_WRITE) { | 469 | } else if (cmd == IPC_I2C_WRITE) { |
491 | writel(*data, ipcdev.i2c_base + I2C_DATA_ADDR); | 470 | writel(*data, ipcdev.i2c_base + I2C_DATA_ADDR); |
492 | mdelay(1); | 471 | mdelay(1); |
493 | writel(addr, ipcdev.i2c_base + IPC_I2C_CNTRL_ADDR); | 472 | writel(addr, ipcdev.i2c_base + IPC_I2C_CNTRL_ADDR); |
494 | } else { | 473 | } else { |
495 | dev_err(&ipcdev.pdev->dev, | 474 | dev_err(&ipcdev.pdev->dev, |
496 | "intel_scu_ipc: I2C INVALID_CMD = 0x%x\n", cmd); | 475 | "intel_scu_ipc: I2C INVALID_CMD = 0x%x\n", cmd); |
497 | 476 | ||
498 | mutex_unlock(&ipclock); | 477 | mutex_unlock(&ipclock); |
499 | return -EIO; | 478 | return -EIO; |
500 | } | 479 | } |
501 | mutex_unlock(&ipclock); | 480 | mutex_unlock(&ipclock); |
502 | return 0; | 481 | return 0; |
503 | } | 482 | } |
504 | EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl); | 483 | EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl); |
505 | 484 | ||
506 | #define IPC_FW_LOAD_ADDR 0xFFFC0000 /* Storage location for FW image */ | ||
507 | #define IPC_FW_UPDATE_MBOX_ADDR 0xFFFFDFF4 /* Mailbox between ipc and scu */ | ||
508 | #define IPC_MAX_FW_SIZE 262144 /* 256K storage size for loading the FW image */ | ||
509 | #define IPC_FW_MIP_HEADER_SIZE 2048 /* Firmware MIP header size */ | ||
510 | /* IPC inform SCU to get ready for update process */ | ||
511 | #define IPC_CMD_FW_UPDATE_READY 0x10FE | ||
512 | /* IPC inform SCU to go for update process */ | ||
513 | #define IPC_CMD_FW_UPDATE_GO 0x20FE | ||
514 | /* Status code for fw update */ | ||
515 | #define IPC_FW_UPDATE_SUCCESS 0x444f4e45 /* Status code 'DONE' */ | ||
516 | #define IPC_FW_UPDATE_BADN 0x4241444E /* Status code 'BADN' */ | ||
517 | #define IPC_FW_TXHIGH 0x54784849 /* Status code 'IPC_FW_TXHIGH' */ | ||
518 | #define IPC_FW_TXLOW 0x54784c4f /* Status code 'IPC_FW_TXLOW' */ | ||
519 | |||
520 | struct fw_update_mailbox { | ||
521 | u32 status; | ||
522 | u32 scu_flag; | ||
523 | u32 driver_flag; | ||
524 | }; | ||
525 | |||
526 | |||
527 | /** | ||
528 | * intel_scu_ipc_fw_update - Firmware update utility | ||
529 | * @buffer: firmware buffer | ||
530 | * @length: size of firmware buffer | ||
531 | * | ||
532 | * This function provides an interface to load the firmware into | ||
533 | * the SCU. Returns 0 on success or -1 on failure | ||
534 | */ | ||
535 | int intel_scu_ipc_fw_update(u8 *buffer, u32 length) | ||
536 | { | ||
537 | void __iomem *fw_update_base; | ||
538 | struct fw_update_mailbox __iomem *mailbox = NULL; | ||
539 | int retry_cnt = 0; | ||
540 | u32 status; | ||
541 | |||
542 | mutex_lock(&ipclock); | ||
543 | fw_update_base = ioremap_nocache(IPC_FW_LOAD_ADDR, (128*1024)); | ||
544 | if (fw_update_base == NULL) { | ||
545 | mutex_unlock(&ipclock); | ||
546 | return -ENOMEM; | ||
547 | } | ||
548 | mailbox = ioremap_nocache(IPC_FW_UPDATE_MBOX_ADDR, | ||
549 | sizeof(struct fw_update_mailbox)); | ||
550 | if (mailbox == NULL) { | ||
551 | iounmap(fw_update_base); | ||
552 | mutex_unlock(&ipclock); | ||
553 | return -ENOMEM; | ||
554 | } | ||
555 | |||
556 | ipc_command(IPC_CMD_FW_UPDATE_READY); | ||
557 | |||
558 | /* Intitialize mailbox */ | ||
559 | writel(0, &mailbox->status); | ||
560 | writel(0, &mailbox->scu_flag); | ||
561 | writel(0, &mailbox->driver_flag); | ||
562 | |||
563 | /* Driver copies the 2KB MIP header to SRAM at 0xFFFC0000*/ | ||
564 | memcpy_toio(fw_update_base, buffer, 0x800); | ||
565 | |||
566 | /* Driver sends "FW Update" IPC command (CMD_ID 0xFE; MSG_ID 0x02). | ||
567 | * Upon receiving this command, SCU will write the 2K MIP header | ||
568 | * from 0xFFFC0000 into NAND. | ||
569 | * SCU will write a status code into the Mailbox, and then set scu_flag. | ||
570 | */ | ||
571 | |||
572 | ipc_command(IPC_CMD_FW_UPDATE_GO); | ||
573 | |||
574 | /*Driver stalls until scu_flag is set */ | ||
575 | while (readl(&mailbox->scu_flag) != 1) { | ||
576 | rmb(); | ||
577 | mdelay(1); | ||
578 | } | ||
579 | |||
580 | /* Driver checks Mailbox status. | ||
581 | * If the status is 'BADN', then abort (bad NAND). | ||
582 | * If the status is 'IPC_FW_TXLOW', then continue. | ||
583 | */ | ||
584 | while (readl(&mailbox->status) != IPC_FW_TXLOW) { | ||
585 | rmb(); | ||
586 | mdelay(10); | ||
587 | } | ||
588 | mdelay(10); | ||
589 | |||
590 | update_retry: | ||
591 | if (retry_cnt > 5) | ||
592 | goto update_end; | ||
593 | |||
594 | if (readl(&mailbox->status) != IPC_FW_TXLOW) | ||
595 | goto update_end; | ||
596 | buffer = buffer + 0x800; | ||
597 | memcpy_toio(fw_update_base, buffer, 0x20000); | ||
598 | writel(1, &mailbox->driver_flag); | ||
599 | while (readl(&mailbox->scu_flag) == 1) { | ||
600 | rmb(); | ||
601 | mdelay(1); | ||
602 | } | ||
603 | |||
604 | /* check for 'BADN' */ | ||
605 | if (readl(&mailbox->status) == IPC_FW_UPDATE_BADN) | ||
606 | goto update_end; | ||
607 | |||
608 | while (readl(&mailbox->status) != IPC_FW_TXHIGH) { | ||
609 | rmb(); | ||
610 | mdelay(10); | ||
611 | } | ||
612 | mdelay(10); | ||
613 | |||
614 | if (readl(&mailbox->status) != IPC_FW_TXHIGH) | ||
615 | goto update_end; | ||
616 | |||
617 | buffer = buffer + 0x20000; | ||
618 | memcpy_toio(fw_update_base, buffer, 0x20000); | ||
619 | writel(0, &mailbox->driver_flag); | ||
620 | |||
621 | while (mailbox->scu_flag == 0) { | ||
622 | rmb(); | ||
623 | mdelay(1); | ||
624 | } | ||
625 | |||
626 | /* check for 'BADN' */ | ||
627 | if (readl(&mailbox->status) == IPC_FW_UPDATE_BADN) | ||
628 | goto update_end; | ||
629 | |||
630 | if (readl(&mailbox->status) == IPC_FW_TXLOW) { | ||
631 | ++retry_cnt; | ||
632 | goto update_retry; | ||
633 | } | ||
634 | |||
635 | update_end: | ||
636 | status = readl(&mailbox->status); | ||
637 | |||
638 | iounmap(fw_update_base); | ||
639 | iounmap(mailbox); | ||
640 | mutex_unlock(&ipclock); | ||
641 | |||
642 | if (status == IPC_FW_UPDATE_SUCCESS) | ||
643 | return 0; | ||
644 | return -EIO; | ||
645 | } | ||
646 | EXPORT_SYMBOL(intel_scu_ipc_fw_update); | ||
647 | |||
648 | /* | 485 | /* |
649 | * Interrupt handler gets called when ioc bit of IPC_COMMAND_REG set to 1 | 486 | * Interrupt handler gets called when ioc bit of IPC_COMMAND_REG set to 1 |
650 | * When ioc bit is set to 1, caller api must wait for interrupt handler called | 487 | * When ioc bit is set to 1, caller api must wait for interrupt handler called |
651 | * which in turn unlocks the caller api. Currently this is not used | 488 | * which in turn unlocks the caller api. Currently this is not used |
652 | * | 489 | * |
653 | * This is edge triggered so we need take no action to clear anything | 490 | * This is edge triggered so we need take no action to clear anything |
654 | */ | 491 | */ |
655 | static irqreturn_t ioc(int irq, void *dev_id) | 492 | static irqreturn_t ioc(int irq, void *dev_id) |
656 | { | 493 | { |
657 | return IRQ_HANDLED; | 494 | return IRQ_HANDLED; |
658 | } | 495 | } |
659 | 496 | ||
660 | /** | 497 | /** |
661 | * ipc_probe - probe an Intel SCU IPC | 498 | * ipc_probe - probe an Intel SCU IPC |
662 | * @dev: the PCI device matching | 499 | * @dev: the PCI device matching |
663 | * @id: entry in the match table | 500 | * @id: entry in the match table |
664 | * | 501 | * |
665 | * Enable and install an intel SCU IPC. This appears in the PCI space | 502 | * Enable and install an intel SCU IPC. This appears in the PCI space |
666 | * but uses some hard coded addresses as well. | 503 | * but uses some hard coded addresses as well. |
667 | */ | 504 | */ |
668 | static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id) | 505 | static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id) |
669 | { | 506 | { |
670 | int err; | 507 | int err; |
671 | resource_size_t pci_resource; | 508 | resource_size_t pci_resource; |
672 | 509 | ||
673 | if (ipcdev.pdev) /* We support only one SCU */ | 510 | if (ipcdev.pdev) /* We support only one SCU */ |
674 | return -EBUSY; | 511 | return -EBUSY; |
675 | 512 | ||
676 | ipcdev.pdev = pci_dev_get(dev); | 513 | ipcdev.pdev = pci_dev_get(dev); |
677 | 514 | ||
678 | err = pci_enable_device(dev); | 515 | err = pci_enable_device(dev); |
679 | if (err) | 516 | if (err) |
680 | return err; | 517 | return err; |
681 | 518 | ||
682 | err = pci_request_regions(dev, "intel_scu_ipc"); | 519 | err = pci_request_regions(dev, "intel_scu_ipc"); |
683 | if (err) | 520 | if (err) |
684 | return err; | 521 | return err; |
685 | 522 | ||
686 | pci_resource = pci_resource_start(dev, 0); | 523 | pci_resource = pci_resource_start(dev, 0); |
687 | if (!pci_resource) | 524 | if (!pci_resource) |
688 | return -ENOMEM; | 525 | return -ENOMEM; |
689 | 526 | ||
690 | if (request_irq(dev->irq, ioc, 0, "intel_scu_ipc", &ipcdev)) | 527 | if (request_irq(dev->irq, ioc, 0, "intel_scu_ipc", &ipcdev)) |
691 | return -EBUSY; | 528 | return -EBUSY; |
692 | 529 | ||
693 | ipcdev.ipc_base = ioremap_nocache(IPC_BASE_ADDR, IPC_MAX_ADDR); | 530 | ipcdev.ipc_base = ioremap_nocache(IPC_BASE_ADDR, IPC_MAX_ADDR); |
694 | if (!ipcdev.ipc_base) | 531 | if (!ipcdev.ipc_base) |
695 | return -ENOMEM; | 532 | return -ENOMEM; |
696 | 533 | ||
697 | ipcdev.i2c_base = ioremap_nocache(IPC_I2C_BASE, IPC_I2C_MAX_ADDR); | 534 | ipcdev.i2c_base = ioremap_nocache(IPC_I2C_BASE, IPC_I2C_MAX_ADDR); |
698 | if (!ipcdev.i2c_base) { | 535 | if (!ipcdev.i2c_base) { |
699 | iounmap(ipcdev.ipc_base); | 536 | iounmap(ipcdev.ipc_base); |
700 | return -ENOMEM; | 537 | return -ENOMEM; |
701 | } | 538 | } |
702 | 539 | ||
703 | intel_scu_devices_create(); | 540 | intel_scu_devices_create(); |
704 | 541 | ||
705 | return 0; | 542 | return 0; |
706 | } | 543 | } |
707 | 544 | ||
708 | /** | 545 | /** |
709 | * ipc_remove - remove a bound IPC device | 546 | * ipc_remove - remove a bound IPC device |
710 | * @pdev: PCI device | 547 | * @pdev: PCI device |
711 | * | 548 | * |
712 | * In practice the SCU is not removable but this function is also | 549 | * In practice the SCU is not removable but this function is also |
713 | * called for each device on a module unload or cleanup which is the | 550 | * called for each device on a module unload or cleanup which is the |
714 | * path that will get used. | 551 | * path that will get used. |
715 | * | 552 | * |
716 | * Free up the mappings and release the PCI resources | 553 | * Free up the mappings and release the PCI resources |
717 | */ | 554 | */ |
718 | static void ipc_remove(struct pci_dev *pdev) | 555 | static void ipc_remove(struct pci_dev *pdev) |
719 | { | 556 | { |
720 | free_irq(pdev->irq, &ipcdev); | 557 | free_irq(pdev->irq, &ipcdev); |
721 | pci_release_regions(pdev); | 558 | pci_release_regions(pdev); |
722 | pci_dev_put(ipcdev.pdev); | 559 | pci_dev_put(ipcdev.pdev); |
723 | iounmap(ipcdev.ipc_base); | 560 | iounmap(ipcdev.ipc_base); |
724 | iounmap(ipcdev.i2c_base); | 561 | iounmap(ipcdev.i2c_base); |
725 | ipcdev.pdev = NULL; | 562 | ipcdev.pdev = NULL; |
726 | intel_scu_devices_destroy(); | 563 | intel_scu_devices_destroy(); |
727 | } | 564 | } |
728 | 565 | ||
729 | static DEFINE_PCI_DEVICE_TABLE(pci_ids) = { | 566 | static DEFINE_PCI_DEVICE_TABLE(pci_ids) = { |
730 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080e)}, | ||
731 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)}, | 567 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)}, |
732 | { 0,} | 568 | { 0,} |
733 | }; | 569 | }; |
734 | MODULE_DEVICE_TABLE(pci, pci_ids); | 570 | MODULE_DEVICE_TABLE(pci, pci_ids); |
735 | 571 | ||
736 | static struct pci_driver ipc_driver = { | 572 | static struct pci_driver ipc_driver = { |
737 | .name = "intel_scu_ipc", | 573 | .name = "intel_scu_ipc", |
738 | .id_table = pci_ids, | 574 | .id_table = pci_ids, |
739 | .probe = ipc_probe, | 575 | .probe = ipc_probe, |
740 | .remove = ipc_remove, | 576 | .remove = ipc_remove, |
741 | }; | 577 | }; |
742 | 578 | ||
743 | 579 | ||
744 | static int __init intel_scu_ipc_init(void) | 580 | static int __init intel_scu_ipc_init(void) |
745 | { | 581 | { |
746 | platform = mrst_identify_cpu(); | 582 | platform = mrst_identify_cpu(); |
747 | if (platform == 0) | 583 | if (platform == 0) |
748 | return -ENODEV; | 584 | return -ENODEV; |
749 | return pci_register_driver(&ipc_driver); | 585 | return pci_register_driver(&ipc_driver); |
750 | } | 586 | } |
751 | 587 | ||
752 | static void __exit intel_scu_ipc_exit(void) | 588 | static void __exit intel_scu_ipc_exit(void) |
753 | { | 589 | { |
754 | pci_unregister_driver(&ipc_driver); | 590 | pci_unregister_driver(&ipc_driver); |
755 | } | 591 | } |
756 | 592 | ||
757 | MODULE_AUTHOR("Sreedhara DS <sreedhara.ds@intel.com>"); | 593 | MODULE_AUTHOR("Sreedhara DS <sreedhara.ds@intel.com>"); |
758 | MODULE_DESCRIPTION("Intel SCU IPC driver"); | 594 | MODULE_DESCRIPTION("Intel SCU IPC driver"); |
759 | MODULE_LICENSE("GPL"); | 595 | MODULE_LICENSE("GPL"); |
760 | 596 | ||
761 | module_init(intel_scu_ipc_init); | 597 | module_init(intel_scu_ipc_init); |
762 | module_exit(intel_scu_ipc_exit); | 598 | module_exit(intel_scu_ipc_exit); |
763 | 599 |
drivers/platform/x86/intel_scu_ipcutil.c
1 | /* | 1 | /* |
2 | * intel_scu_ipc.c: Driver for the Intel SCU IPC mechanism | 2 | * intel_scu_ipc.c: Driver for the Intel SCU IPC mechanism |
3 | * | 3 | * |
4 | * (C) Copyright 2008-2010 Intel Corporation | 4 | * (C) Copyright 2008-2010 Intel Corporation |
5 | * Author: Sreedhara DS (sreedhara.ds@intel.com) | 5 | * Author: Sreedhara DS (sreedhara.ds@intel.com) |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
9 | * as published by the Free Software Foundation; version 2 | 9 | * as published by the Free Software Foundation; version 2 |
10 | * of the License. | 10 | * of the License. |
11 | * | 11 | * |
12 | * This driver provides ioctl interfaces to call intel scu ipc driver api | 12 | * This driver provides ioctl interfaces to call intel scu ipc driver api |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
18 | #include <linux/types.h> | 18 | #include <linux/types.h> |
19 | #include <linux/fs.h> | 19 | #include <linux/fs.h> |
20 | #include <linux/fcntl.h> | 20 | #include <linux/fcntl.h> |
21 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
22 | #include <linux/uaccess.h> | 22 | #include <linux/uaccess.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
25 | #include <asm/intel_scu_ipc.h> | 25 | #include <asm/intel_scu_ipc.h> |
26 | 26 | ||
27 | static int major; | 27 | static int major; |
28 | 28 | ||
29 | #define MAX_FW_SIZE 264192 | ||
30 | |||
31 | /* ioctl commnds */ | 29 | /* ioctl commnds */ |
32 | #define INTE_SCU_IPC_REGISTER_READ 0 | 30 | #define INTE_SCU_IPC_REGISTER_READ 0 |
33 | #define INTE_SCU_IPC_REGISTER_WRITE 1 | 31 | #define INTE_SCU_IPC_REGISTER_WRITE 1 |
34 | #define INTE_SCU_IPC_REGISTER_UPDATE 2 | 32 | #define INTE_SCU_IPC_REGISTER_UPDATE 2 |
35 | #define INTE_SCU_IPC_FW_UPDATE 0xA2 | ||
36 | 33 | ||
37 | struct scu_ipc_data { | 34 | struct scu_ipc_data { |
38 | u32 count; /* No. of registers */ | 35 | u32 count; /* No. of registers */ |
39 | u16 addr[5]; /* Register addresses */ | 36 | u16 addr[5]; /* Register addresses */ |
40 | u8 data[5]; /* Register data */ | 37 | u8 data[5]; /* Register data */ |
41 | u8 mask; /* Valid for read-modify-write */ | 38 | u8 mask; /* Valid for read-modify-write */ |
42 | }; | 39 | }; |
43 | 40 | ||
44 | /** | 41 | /** |
45 | * scu_reg_access - implement register access ioctls | 42 | * scu_reg_access - implement register access ioctls |
46 | * @cmd: command we are doing (read/write/update) | 43 | * @cmd: command we are doing (read/write/update) |
47 | * @data: kernel copy of ioctl data | 44 | * @data: kernel copy of ioctl data |
48 | * | 45 | * |
49 | * Allow the user to perform register accesses on the SCU via the | 46 | * Allow the user to perform register accesses on the SCU via the |
50 | * kernel interface | 47 | * kernel interface |
51 | */ | 48 | */ |
52 | 49 | ||
53 | static int scu_reg_access(u32 cmd, struct scu_ipc_data *data) | 50 | static int scu_reg_access(u32 cmd, struct scu_ipc_data *data) |
54 | { | 51 | { |
55 | int count = data->count; | 52 | int count = data->count; |
56 | 53 | ||
57 | if (count == 0 || count == 3 || count > 4) | 54 | if (count == 0 || count == 3 || count > 4) |
58 | return -EINVAL; | 55 | return -EINVAL; |
59 | 56 | ||
60 | switch (cmd) { | 57 | switch (cmd) { |
61 | case INTE_SCU_IPC_REGISTER_READ: | 58 | case INTE_SCU_IPC_REGISTER_READ: |
62 | return intel_scu_ipc_readv(data->addr, data->data, count); | 59 | return intel_scu_ipc_readv(data->addr, data->data, count); |
63 | case INTE_SCU_IPC_REGISTER_WRITE: | 60 | case INTE_SCU_IPC_REGISTER_WRITE: |
64 | return intel_scu_ipc_writev(data->addr, data->data, count); | 61 | return intel_scu_ipc_writev(data->addr, data->data, count); |
65 | case INTE_SCU_IPC_REGISTER_UPDATE: | 62 | case INTE_SCU_IPC_REGISTER_UPDATE: |
66 | return intel_scu_ipc_update_register(data->addr[0], | 63 | return intel_scu_ipc_update_register(data->addr[0], |
67 | data->data[0], data->mask); | 64 | data->data[0], data->mask); |
68 | default: | 65 | default: |
69 | return -ENOTTY; | 66 | return -ENOTTY; |
70 | } | 67 | } |
71 | } | 68 | } |
72 | 69 | ||
73 | /** | 70 | /** |
74 | * scu_ipc_ioctl - control ioctls for the SCU | 71 | * scu_ipc_ioctl - control ioctls for the SCU |
75 | * @fp: file handle of the SCU device | 72 | * @fp: file handle of the SCU device |
76 | * @cmd: ioctl coce | 73 | * @cmd: ioctl coce |
77 | * @arg: pointer to user passed structure | 74 | * @arg: pointer to user passed structure |
78 | * | 75 | * |
79 | * Support the I/O and firmware flashing interfaces of the SCU | 76 | * Support the I/O and firmware flashing interfaces of the SCU |
80 | */ | 77 | */ |
81 | static long scu_ipc_ioctl(struct file *fp, unsigned int cmd, | 78 | static long scu_ipc_ioctl(struct file *fp, unsigned int cmd, |
82 | unsigned long arg) | 79 | unsigned long arg) |
83 | { | 80 | { |
84 | int ret; | 81 | int ret; |
85 | struct scu_ipc_data data; | 82 | struct scu_ipc_data data; |
86 | void __user *argp = (void __user *)arg; | 83 | void __user *argp = (void __user *)arg; |
87 | 84 | ||
88 | if (!capable(CAP_SYS_RAWIO)) | 85 | if (!capable(CAP_SYS_RAWIO)) |
89 | return -EPERM; | 86 | return -EPERM; |
90 | 87 | ||
91 | if (cmd == INTE_SCU_IPC_FW_UPDATE) { | 88 | if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data))) |
92 | u8 *fwbuf = kmalloc(MAX_FW_SIZE, GFP_KERNEL); | 89 | return -EFAULT; |
93 | if (fwbuf == NULL) | 90 | ret = scu_reg_access(cmd, &data); |
94 | return -ENOMEM; | 91 | if (ret < 0) |
95 | if (copy_from_user(fwbuf, (u8 *)arg, MAX_FW_SIZE)) { | 92 | return ret; |
96 | kfree(fwbuf); | 93 | if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data))) |
97 | return -EFAULT; | 94 | return -EFAULT; |
98 | } | 95 | return 0; |
99 | ret = intel_scu_ipc_fw_update(fwbuf, MAX_FW_SIZE); | ||
100 | kfree(fwbuf); | ||
101 | return ret; | ||
102 | } else { | ||
103 | if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data))) | ||
104 | return -EFAULT; | ||
105 | ret = scu_reg_access(cmd, &data); | ||
106 | if (ret < 0) | ||
107 | return ret; | ||
108 | if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data))) | ||
109 | return -EFAULT; | ||
110 | return 0; | ||
111 | } | ||
112 | } | 96 | } |
113 | 97 | ||
114 | static const struct file_operations scu_ipc_fops = { | 98 | static const struct file_operations scu_ipc_fops = { |
115 | .unlocked_ioctl = scu_ipc_ioctl, | 99 | .unlocked_ioctl = scu_ipc_ioctl, |
116 | }; | 100 | }; |
117 | 101 | ||
118 | static int __init ipc_module_init(void) | 102 | static int __init ipc_module_init(void) |
119 | { | 103 | { |
120 | major = register_chrdev(0, "intel_mid_scu", &scu_ipc_fops); | 104 | major = register_chrdev(0, "intel_mid_scu", &scu_ipc_fops); |
121 | if (major < 0) | 105 | if (major < 0) |
122 | return major; | 106 | return major; |
123 | 107 | ||
124 | return 0; | 108 | return 0; |
125 | } | 109 | } |
126 | 110 | ||
127 | static void __exit ipc_module_exit(void) | 111 | static void __exit ipc_module_exit(void) |
128 | { | 112 | { |
129 | unregister_chrdev(major, "intel_mid_scu"); | 113 | unregister_chrdev(major, "intel_mid_scu"); |
130 | } | 114 | } |
131 | 115 | ||
132 | module_init(ipc_module_init); | 116 | module_init(ipc_module_init); |
133 | module_exit(ipc_module_exit); | 117 | module_exit(ipc_module_exit); |
134 | 118 | ||
135 | MODULE_LICENSE("GPL v2"); | 119 | MODULE_LICENSE("GPL v2"); |
136 | MODULE_DESCRIPTION("Utility driver for intel scu ipc"); | 120 | MODULE_DESCRIPTION("Utility driver for intel scu ipc"); |
137 | MODULE_AUTHOR("Sreedhara <sreedhara.ds@intel.com>"); | 121 | MODULE_AUTHOR("Sreedhara <sreedhara.ds@intel.com>"); |
138 | 122 |