Commit | Line | Data |
---|---|---|
635d2b00 GKH |
1 | /***************************************************************************** |
2 | ||
3 | (c) Cambridge Silicon Radio Limited 2011 | |
4 | All rights reserved and confidential information of CSR | |
5 | ||
6 | Refer to LICENSE.txt included with this source for details | |
7 | on the license terms. | |
8 | ||
9 | *****************************************************************************/ | |
10 | ||
980b5a2b | 11 | #include "csr_macro.h" |
635d2b00 GKH |
12 | #include "csr_wifi_hip_chiphelper_private.h" |
13 | ||
14 | #ifndef nelem | |
15 | #define nelem(a) (sizeof(a) / sizeof(a[0])) | |
16 | #endif | |
17 | ||
18 | #define counted(foo) { nelem(foo), foo } | |
19 | #define null_counted() { 0, NULL } | |
20 | ||
21 | /* The init values are a set of register writes that we must | |
22 | perform when we first connect to the chip to get it working. | |
23 | They swicth on the correct clocks and possibly set the host | |
24 | interface as a wkaeup source. They should not be used if | |
25 | proper HIP opperation is required, but are useful before we | |
26 | do a code download. */ | |
27 | static const struct chip_helper_init_values init_vals_v1[] = { | |
28 | { 0xFDBB, 0xFFFF }, | |
29 | { 0xFDB6, 0x03FF }, | |
30 | { 0xFDB1, 0x01E3 }, | |
31 | { 0xFDB3, 0x0FFF }, | |
32 | { 0xFEE3, 0x08F0 }, | |
33 | { 0xFEE7, 0x3C3F }, | |
34 | { 0xFEE6, 0x0050 }, | |
35 | { 0xFDBA, 0x0000 } | |
36 | }; | |
37 | ||
38 | static const struct chip_helper_init_values init_vals_v2[] = { | |
39 | { 0xFDB6, 0x0FFF }, | |
40 | { 0xF023, 0x3F3F }, | |
41 | { 0xFDB1, 0x01E3 }, | |
42 | { 0xFDB3, 0x0FFF }, | |
43 | { 0xF003, 0x08F0 }, | |
44 | { 0xF007, 0x3C3F }, | |
45 | { 0xF006, 0x0050 } | |
46 | }; | |
47 | ||
48 | ||
49 | static const struct chip_helper_init_values init_vals_v22_v23[] = { | |
50 | { 0xF81C, 0x00FF }, | |
51 | /*{ 0x????, 0x???? }, */ | |
52 | { 0xF80C, 0x1FFF }, | |
53 | { 0xFA25, 0x001F }, | |
54 | { 0xF804, 0x00FF }, | |
55 | { 0xF802, 0x0FFF }, | |
56 | /*{ 0x????, 0x???? }, | |
57 | { 0x????, 0x???? }, | |
58 | { 0x????, 0x???? }*/ | |
59 | }; | |
60 | ||
8c87f69a | 61 | static const u16 reset_program_a_v1_or_v2[] = { |
635d2b00 GKH |
62 | 0x0000 |
63 | }; | |
8c87f69a | 64 | static const u16 reset_program_b_v1_or_v2[] = { |
635d2b00 GKH |
65 | 0x0010, 0xFE00, 0xA021, 0xFF00, 0x8111, 0x0009, 0x0CA4, 0x0114, |
66 | 0x0280, 0x04F8, 0xFE00, 0x6F25, 0x06E0, 0x0010, 0xFC00, 0x0121, | |
67 | 0xFC00, 0x0225, 0xFE00, 0x7125, 0xFE00, 0x6D11, 0x03F0, 0xFE00, | |
68 | 0x6E25, 0x0008, 0x00E0 | |
69 | }; | |
70 | ||
71 | static const struct chip_helper_reset_values reset_program_v1_or_v2[] = | |
72 | { | |
73 | { | |
74 | MAKE_GP(REGISTERS, 0x000C), | |
75 | nelem(reset_program_a_v1_or_v2), | |
76 | reset_program_a_v1_or_v2 | |
77 | }, | |
78 | { | |
79 | MAKE_GP(MAC_PMEM, 0x000000), | |
80 | nelem(reset_program_b_v1_or_v2), | |
81 | reset_program_b_v1_or_v2 | |
82 | } | |
83 | }; | |
84 | ||
85 | static const struct chip_map_address_t unifi_map_address_v1_v2[] = | |
86 | { | |
87 | { 0xFE9F, 0xFE7B }, /* PM1_BANK_SELECT */ | |
88 | { 0xFE9E, 0xFE78 }, /* PM2_BANK_SELECT */ | |
89 | { 0xFE9D, 0xFE7E }, /* SHARED_DMEM_PAGE */ | |
90 | { 0xFE91, 0xFE90 }, /* PROC_SELECT */ | |
91 | { 0xFE8D, 0xFE8C }, /* STOP_STATUS */ | |
92 | }; | |
93 | ||
94 | static const struct chip_map_address_t unifi_map_address_v22_v23[] = | |
95 | { | |
96 | { 0xF8F9, 0xF8AC }, /* GW1_CONFIG */ | |
97 | { 0xF8FA, 0xF8AD }, /* GW2_CONFIG */ | |
98 | { 0xF8FB, 0xF8AE }, /* GW3_CONFIG */ | |
99 | { 0xF830, 0xF81E }, /* PROC_SELECT */ | |
100 | { 0xF831, 0xF81F }, /* STOP_STATUS */ | |
101 | { 0xF8FC, 0xF8AF }, /* IO_LOG_ADDRESS */ | |
102 | }; | |
103 | ||
104 | static const struct chip_device_regs_t unifi_device_regs_null = | |
105 | { | |
106 | 0xFE81, /* GBL_CHIP_VERSION */ | |
107 | 0x0000, /* GBL_MISC_ENABLES */ | |
108 | 0x0000, /* DBG_EMU_CMD */ | |
109 | { | |
110 | 0x0000, /* HOST.DBG_PROC_SELECT */ | |
111 | 0x0000, /* HOST.DBG_STOP_STATUS */ | |
112 | 0x0000, /* HOST.WINDOW1_PAGE */ | |
113 | 0x0000, /* HOST.WINDOW2_PAGE */ | |
114 | 0x0000, /* HOST.WINDOW3_PAGE */ | |
115 | 0x0000 /* HOST.IO_LOG_ADDR */ | |
116 | }, | |
117 | { | |
118 | 0x0000, /* SPI.DBG_PROC_SELECT */ | |
119 | 0x0000, /* SPI.DBG_STOP_STATUS */ | |
120 | 0x0000, /* SPI.WINDOW1_PAGE */ | |
121 | 0x0000, /* SPI.WINDOW2_PAGE */ | |
122 | 0x0000, /* SPI.WINDOW3_PAGE */ | |
123 | 0x0000 /* SPI.IO_LOG_ADDR */ | |
124 | }, | |
125 | 0x0000, /* DBG_RESET */ | |
126 | 0x0000, /* > DBG_RESET_VALUE */ | |
127 | 0x0000, /* DBG_RESET_WARN */ | |
128 | 0x0000, /* DBG_RESET_WARN_VALUE */ | |
129 | 0x0000, /* DBG_RESET_RESULT */ | |
130 | 0xFFE9, /* XAP_PCH */ | |
131 | 0xFFEA, /* XAP_PCL */ | |
132 | 0x0000, /* PROC_PC_SNOOP */ | |
133 | 0x0000, /* WATCHDOG_DISABLE */ | |
134 | 0x0000, /* MAILBOX0 */ | |
135 | 0x0000, /* MAILBOX1 */ | |
136 | 0x0000, /* MAILBOX2 */ | |
137 | 0x0000, /* MAILBOX3 */ | |
138 | 0x0000, /* SDIO_HOST_INT */ | |
139 | 0x0000, /* SHARED_IO_INTERRUPT */ | |
140 | 0x0000, /* SDIO HIP HANDSHAKE */ | |
141 | 0x0000 /* COEX_STATUS */ | |
142 | }; | |
143 | ||
144 | /* UF105x */ | |
145 | static const struct chip_device_regs_t unifi_device_regs_v1 = | |
146 | { | |
147 | 0xFE81, /* GBL_CHIP_VERSION */ | |
148 | 0xFE87, /* GBL_MISC_ENABLES */ | |
149 | 0xFE9C, /* DBG_EMU_CMD */ | |
150 | { | |
151 | 0xFE90, /* HOST.DBG_PROC_SELECT */ | |
152 | 0xFE8C, /* HOST.DBG_STOP_STATUS */ | |
153 | 0xFE7B, /* HOST.WINDOW1_PAGE */ | |
154 | 0xFE78, /* HOST.WINDOW2_PAGE */ | |
155 | 0xFE7E, /* HOST.WINDOW3_PAGE */ | |
156 | 0x0000 /* HOST.IO_LOG_ADDR */ | |
157 | }, | |
158 | { | |
159 | 0xFE91, /* SPI.DBG_PROC_SELECT */ | |
160 | 0xFE8D, /* SPI.DBG_STOP_STATUS */ | |
161 | 0xFE9F, /* SPI.WINDOW1_PAGE */ | |
162 | 0xFE9E, /* SPI.WINDOW2_PAGE */ | |
163 | 0xFE9D, /* SPI.WINDOW3_PAGE */ | |
164 | 0x0000 /* SPI.IO_LOG_ADDR */ | |
165 | }, | |
166 | 0xFE92, /* DBG_RESET */ | |
167 | 0x0001, /* > DBG_RESET_VALUE */ | |
168 | 0xFDA0, /* DBG_RESET_WARN (HOST_SELECT) */ | |
169 | 0x0000, /* DBG_RESET_WARN_VALUE */ | |
170 | 0xFE92, /* DBG_RESET_RESULT */ | |
171 | 0xFFE9, /* XAP_PCH */ | |
172 | 0xFFEA, /* XAP_PCL */ | |
173 | 0x0051, /* PROC_PC_SNOOP */ | |
174 | 0xFE70, /* WATCHDOG_DISABLE */ | |
175 | 0xFE6B, /* MAILBOX0 */ | |
176 | 0xFE6A, /* MAILBOX1 */ | |
177 | 0xFE69, /* MAILBOX2 */ | |
178 | 0xFE68, /* MAILBOX3 */ | |
179 | 0xFE67, /* SDIO_HOST_INT */ | |
180 | 0xFE65, /* SHARED_IO_INTERRUPT */ | |
181 | 0xFDE9, /* SDIO HIP HANDSHAKE */ | |
182 | 0x0000 /* COEX_STATUS */ | |
183 | }; | |
184 | ||
185 | /* UF2... */ | |
186 | static const struct chip_device_regs_t unifi_device_regs_v2 = | |
187 | { | |
188 | 0xFE81, /* GBL_CHIP_VERSION */ | |
189 | 0xFE87, /* GBL_MISC_ENABLES */ | |
190 | 0xFE9C, /* DBG_EMU_CMD */ | |
191 | { | |
192 | 0xFE90, /* HOST.DBG_PROC_SELECT */ | |
193 | 0xFE8C, /* HOST.DBG_STOP_STATUS */ | |
194 | 0xFE7B, /* HOST.WINDOW1_PAGE */ | |
195 | 0xFE78, /* HOST.WINDOW2_PAGE */ | |
196 | 0xFE7E, /* HOST.WINDOW3_PAGE */ | |
197 | 0x0000 /* HOST.IO_LOG_ADDR */ | |
198 | }, | |
199 | { | |
200 | 0xFE91, /* SPI.DBG_PROC_SELECT */ | |
201 | 0xFE8D, /* SPI.DBG_STOP_STATUS */ | |
202 | 0xFE9F, /* SPI.WINDOW1_PAGE */ | |
203 | 0xFE9E, /* SPI.WINDOW2_PAGE */ | |
204 | 0xFE9D, /* SPI.WINDOW3_PAGE */ | |
205 | 0x0000 /* SPI.IO_LOG_ADDR */ | |
206 | }, | |
207 | 0xFE92, /* DBG_RESET */ | |
208 | 0x0000, /* > DBG_RESET_VALUE */ | |
209 | 0xFDE9, /* DBG_RESET_WARN (TEST_FLASH_DATA - SHARED_MAILBOX2B) */ | |
210 | 0xFFFF, /* DBG_RESET_WARN_VALUE */ | |
211 | 0xFDE9, /* DBG_RESET_RESULT (TEST_FLASH_DATA) */ | |
212 | 0xFFE9, /* XAP_PCH */ | |
213 | 0xFFEA, /* XAP_PCL */ | |
214 | 0x0051, /* PROC_PC_SNOOP */ | |
215 | 0xFE70, /* WATCHDOG_DISABLE */ | |
216 | 0xFE6B, /* MAILBOX0 */ | |
217 | 0xFE6A, /* MAILBOX1 */ | |
218 | 0xFE69, /* MAILBOX2 */ | |
219 | 0xFE68, /* MAILBOX3 */ | |
220 | 0xFE67, /* SDIO_HOST_INT */ | |
221 | 0xFE65, /* SHARED_IO_INTERRUPT */ | |
222 | 0xFE69, /* SDIO HIP HANDSHAKE */ | |
223 | 0x0000 /* COEX_STATUS */ | |
224 | }; | |
225 | ||
226 | /* UF60xx */ | |
227 | static const struct chip_device_regs_t unifi_device_regs_v22_v23 = | |
228 | { | |
229 | 0xFE81, /* GBL_CHIP_VERSION */ | |
230 | 0xF84F, /* GBL_MISC_ENABLES */ | |
231 | 0xF81D, /* DBG_EMU_CMD */ | |
232 | { | |
233 | 0xF81E, /* HOST.DBG_PROC_SELECT */ | |
234 | 0xF81F, /* HOST.DBG_STOP_STATUS */ | |
235 | 0xF8AC, /* HOST.WINDOW1_PAGE */ | |
236 | 0xF8AD, /* HOST.WINDOW2_PAGE */ | |
237 | 0xF8AE, /* HOST.WINDOW3_PAGE */ | |
238 | 0xF8AF /* HOST.IO_LOG_ADDR */ | |
239 | }, | |
240 | { | |
241 | 0xF830, /* SPI.DBG_PROC_SELECT */ | |
242 | 0xF831, /* SPI.DBG_STOP_STATUS */ | |
243 | 0xF8F9, /* SPI.WINDOW1_PAGE */ | |
244 | 0xF8FA, /* SPI.WINDOW2_PAGE */ | |
245 | 0xF8FB, /* SPI.WINDOW3_PAGE */ | |
246 | 0xF8FC /* SPI.IO_LOG_ADDR */ | |
247 | }, | |
248 | 0xF82F, /* DBG_RESET */ | |
249 | 0x0001, /* > DBG_RESET_VALUE */ | |
250 | 0x0000, /* DBG_RESET_WARN */ | |
251 | 0x0000, /* DBG_RESET_WARN_VALUE */ | |
252 | 0xF82F, /* DBG_RESET_RESULT */ | |
253 | 0xFFE9, /* XAP_PCH */ | |
254 | 0xFFEA, /* XAP_PCL */ | |
255 | 0x001B, /* PROC_PC_SNOOP */ | |
256 | 0x0055, /* WATCHDOG_DISABLE */ | |
257 | 0xF84B, /* MAILBOX0 */ | |
258 | 0xF84C, /* MAILBOX1 */ | |
259 | 0xF84D, /* MAILBOX2 */ | |
260 | 0xF84E, /* MAILBOX3 */ | |
261 | 0xF92F, /* SDIO_HOST_INT */ | |
262 | 0xF92B, /* SDIO_FROMHOST_SCRTACH0 / SHARED_IO_INTERRUPT */ | |
263 | 0xF84D, /* SDIO HIP HANDSHAKE (MAILBOX2) */ | |
264 | 0xF9FB /* COEX_STATUS */ | |
265 | }; | |
266 | ||
267 | /* Program memory window on UF105x. */ | |
268 | static const struct window_shift_info_t prog_window_array_unifi_v1_v2[CHIP_HELPER_WT_COUNT] = | |
269 | { | |
270 | { TRUE, 11, 0x0200 }, /* CODE RAM */ | |
271 | { TRUE, 11, 0x0000 }, /* FLASH */ | |
272 | { TRUE, 11, 0x0400 }, /* External SRAM */ | |
273 | { FALSE, 0, 0 }, /* ROM */ | |
274 | { FALSE, 0, 0 } /* SHARED */ | |
275 | }; | |
276 | ||
277 | /* Shared memory window on UF105x. */ | |
278 | static const struct window_shift_info_t shared_window_array_unifi_v1_v2[CHIP_HELPER_WT_COUNT] = | |
279 | { | |
280 | { FALSE, 0, 0 }, /* CODE RAM */ | |
281 | { FALSE, 0, 0 }, /* FLASH */ | |
282 | { FALSE, 0, 0 }, /* External SRAM */ | |
283 | { FALSE, 0, 0 }, /* ROM */ | |
284 | { TRUE, 11, 0x0000 } /* SHARED */ | |
285 | }; | |
286 | ||
287 | /* One of the Generic Windows on UF60xx and later. */ | |
288 | static const struct window_shift_info_t generic_window_array_unifi_v22_v23[CHIP_HELPER_WT_COUNT] = | |
289 | { | |
290 | { TRUE, 11, 0x3800 }, /* CODE RAM */ | |
291 | { FALSE, 0, 0 }, /* FLASH */ | |
292 | { FALSE, 0, 0 }, /* External SRAM */ | |
293 | { TRUE, 11, 0x2000 }, /* ROM */ | |
294 | { TRUE, 11, 0x0000 } /* SHARED */ | |
295 | }; | |
296 | ||
297 | /* The three windows on UF105x. */ | |
298 | static const struct window_info_t prog1_window_unifi_v1_v2 = { 0x0000, 0x2000, 0x0080, prog_window_array_unifi_v1_v2 }; | |
299 | static const struct window_info_t prog2_window_unifi_v1_v2 = { 0x2000, 0x2000, 0x0000, prog_window_array_unifi_v1_v2 }; | |
300 | static const struct window_info_t shared_window_unifi_v1_v2 = { 0x4000, 0x2000, 0x0000, shared_window_array_unifi_v1_v2 }; | |
301 | ||
302 | /* The three windows on UF60xx and later. */ | |
303 | static const struct window_info_t generic1_window_unifi_v22_v23 = { 0x0000, 0x2000, 0x0080, generic_window_array_unifi_v22_v23 }; | |
304 | static const struct window_info_t generic2_window_unifi_v22_v23 = { 0x2000, 0x2000, 0x0000, generic_window_array_unifi_v22_v23 }; | |
305 | static const struct window_info_t generic3_window_unifi_v22_v23 = { 0x4000, 0x2000, 0x0000, generic_window_array_unifi_v22_v23 }; | |
306 | ||
307 | static const struct chip_device_desc_t chip_device_desc_null = | |
308 | { | |
309 | { FALSE, 0x0000, 0x0000, 0x00 }, | |
310 | "", | |
311 | "", | |
312 | null_counted(), /* init */ | |
313 | null_counted(), /* reset_prog */ | |
314 | &unifi_device_regs_null, /* regs */ | |
315 | { | |
316 | FALSE, /* has_flash */ | |
317 | FALSE, /* has_ext_sram */ | |
318 | FALSE, /* has_rom */ | |
319 | FALSE, /* has_bt */ | |
320 | FALSE, /* has_wlan */ | |
321 | }, | |
322 | null_counted(), | |
323 | /* prog_offset */ | |
324 | { | |
325 | 0x00000000, | |
326 | 0x00000000, | |
327 | 0x00000000, | |
328 | 0x00000000 | |
329 | }, | |
330 | /* data_offset */ | |
331 | { | |
332 | 0x0000 /* ram */ | |
333 | }, | |
334 | /* windows */ | |
335 | { | |
336 | NULL, | |
337 | NULL, | |
338 | NULL | |
339 | } | |
340 | }; | |
341 | ||
342 | static const struct chip_device_desc_t unifi_device_desc_v1 = | |
343 | { | |
344 | { FALSE, 0xf0ff, 0x1001, 0x01 }, /* UF105x R01 */ | |
345 | "UF105x", | |
346 | "UniFi-1", | |
347 | counted(init_vals_v1), /* init */ | |
348 | counted(reset_program_v1_or_v2), /* reset_prog */ | |
349 | &unifi_device_regs_v1, /* regs */ | |
350 | { | |
351 | TRUE, /* has_flash */ | |
352 | TRUE, /* has_ext_sram */ | |
353 | FALSE, /* has_rom */ | |
354 | FALSE, /* has_bt */ | |
355 | TRUE, /* has_wlan */ | |
356 | }, | |
357 | counted(unifi_map_address_v1_v2), /* map */ | |
358 | /* prog_offset */ | |
359 | { | |
360 | 0x00100000, /* ram */ | |
361 | 0x00000000, /* rom (invalid) */ | |
362 | 0x00000000, /* flash */ | |
363 | 0x00200000, /* ext_ram */ | |
364 | }, | |
365 | /* data_offset */ | |
366 | { | |
367 | 0x8000 /* ram */ | |
368 | }, | |
369 | /* windows */ | |
370 | { | |
371 | &prog1_window_unifi_v1_v2, | |
372 | &prog2_window_unifi_v1_v2, | |
373 | &shared_window_unifi_v1_v2 | |
374 | } | |
375 | }; | |
376 | ||
377 | static const struct chip_device_desc_t unifi_device_desc_v2 = | |
378 | { | |
379 | { FALSE, 0xf0ff, 0x2001, 0x02 }, /* UF2... R02 */ | |
380 | "UF2...", | |
381 | "UniFi-2", | |
382 | counted(init_vals_v2), /* init */ | |
383 | counted(reset_program_v1_or_v2), /* reset_prog */ | |
384 | &unifi_device_regs_v2, /* regs */ | |
385 | { | |
386 | TRUE, /* has_flash */ | |
387 | TRUE, /* has_ext_sram */ | |
388 | FALSE, /* has_rom */ | |
389 | FALSE, /* has_bt */ | |
390 | TRUE, /* has_wlan */ | |
391 | }, | |
392 | counted(unifi_map_address_v1_v2), /* map */ | |
393 | /* prog_offset */ | |
394 | { | |
395 | 0x00100000, /* ram */ | |
396 | 0x00000000, /* rom (invalid) */ | |
397 | 0x00000000, /* flash */ | |
398 | 0x00200000, /* ext_ram */ | |
399 | }, | |
400 | /* data_offset */ | |
401 | { | |
402 | 0x8000 /* ram */ | |
403 | }, | |
404 | /* windows */ | |
405 | { | |
406 | &prog1_window_unifi_v1_v2, | |
407 | &prog2_window_unifi_v1_v2, | |
408 | &shared_window_unifi_v1_v2 | |
409 | } | |
410 | }; | |
411 | ||
412 | static const struct chip_device_desc_t unifi_device_desc_v3 = | |
413 | { | |
414 | { FALSE, 0xf0ff, 0x3001, 0x02 }, /* UF2... R03 */ | |
415 | "UF2...", | |
416 | "UniFi-3", | |
417 | counted(init_vals_v2), /* init */ | |
418 | counted(reset_program_v1_or_v2), /* reset_prog */ | |
419 | &unifi_device_regs_v2, /* regs */ | |
420 | { | |
421 | TRUE, /* has_flash */ | |
422 | TRUE, /* has_ext_sram */ | |
423 | FALSE, /* has_rom */ | |
424 | FALSE, /* has_bt */ | |
425 | TRUE, /* has_wlan */ | |
426 | }, | |
427 | counted(unifi_map_address_v1_v2), /* map */ | |
428 | /* prog_offset */ | |
429 | { | |
430 | 0x00100000, /* ram */ | |
431 | 0x00000000, /* rom (invalid) */ | |
432 | 0x00000000, /* flash */ | |
433 | 0x00200000, /* ext_ram */ | |
434 | }, | |
435 | /* data_offset */ | |
436 | { | |
437 | 0x8000 /* ram */ | |
438 | }, | |
439 | /* windows */ | |
440 | { | |
441 | &prog1_window_unifi_v1_v2, | |
442 | &prog2_window_unifi_v1_v2, | |
443 | &shared_window_unifi_v1_v2 | |
444 | } | |
445 | }; | |
446 | ||
447 | static const struct chip_device_desc_t unifi_device_desc_v22 = | |
448 | { | |
449 | { FALSE, 0x00ff, 0x0022, 0x07 }, /* UF60xx */ | |
450 | "UF60xx", | |
451 | "UniFi-4", | |
452 | counted(init_vals_v22_v23), /* init */ | |
453 | null_counted(), /* reset_prog */ | |
454 | &unifi_device_regs_v22_v23, /* regs */ | |
455 | { | |
456 | FALSE, /* has_flash */ | |
457 | FALSE, /* has_ext_sram */ | |
458 | TRUE, /* has_rom */ | |
459 | FALSE, /* has_bt */ | |
460 | TRUE, /* has_wlan */ | |
461 | }, | |
462 | counted(unifi_map_address_v22_v23), /* map */ | |
463 | /* prog_offset */ | |
464 | { | |
465 | 0x00C00000, /* ram */ | |
466 | 0x00000000, /* rom */ | |
467 | 0x00000000, /* flash (invalid) */ | |
468 | 0x00000000, /* ext_ram (invalid) */ | |
469 | }, | |
470 | /* data_offset */ | |
471 | { | |
472 | 0x8000 /* ram */ | |
473 | }, | |
474 | /* windows */ | |
475 | { | |
476 | &generic1_window_unifi_v22_v23, | |
477 | &generic2_window_unifi_v22_v23, | |
478 | &generic3_window_unifi_v22_v23 | |
479 | } | |
480 | }; | |
481 | ||
482 | static const struct chip_device_desc_t unifi_device_desc_v23 = | |
483 | { | |
484 | { FALSE, 0x00ff, 0x0023, 0x08 }, /* UF.... */ | |
485 | "UF....", | |
486 | "UF.... (5)", | |
487 | counted(init_vals_v22_v23), /* init */ | |
488 | null_counted(), /* reset_prog */ | |
489 | &unifi_device_regs_v22_v23, /* regs */ | |
490 | { | |
491 | FALSE, /* has_flash */ | |
492 | FALSE, /* has_ext_sram */ | |
493 | TRUE, /* has_rom */ | |
494 | TRUE, /* has_bt */ | |
495 | TRUE, /* has_wlan */ | |
496 | }, | |
497 | counted(unifi_map_address_v22_v23), | |
498 | /* prog_offset */ | |
499 | { | |
500 | 0x00C00000, /* ram */ | |
501 | 0x00000000, /* rom */ | |
502 | 0x00000000, /* flash (invalid) */ | |
503 | 0x00000000, /* ext_sram (invalid) */ | |
504 | }, | |
505 | /* data_offset */ | |
506 | { | |
507 | 0x8000 /* ram */ | |
508 | }, | |
509 | /* windows */ | |
510 | { | |
511 | &generic1_window_unifi_v22_v23, | |
512 | &generic2_window_unifi_v22_v23, | |
513 | &generic3_window_unifi_v22_v23 | |
514 | } | |
515 | }; | |
516 | ||
517 | static const struct chip_device_desc_t hyd_wlan_subsys_desc_v1 = | |
518 | { | |
519 | { FALSE, 0x00ff, 0x0044, 0x00 }, /* UF.... */ | |
520 | "HYD...", | |
521 | "HYD... ", | |
522 | counted(init_vals_v22_v23), /* init */ | |
523 | null_counted(), /* reset_prog */ | |
524 | &unifi_device_regs_v22_v23, /* regs */ | |
525 | { | |
526 | FALSE, /* has_flash */ | |
527 | FALSE, /* has_ext_sram */ | |
528 | TRUE, /* has_rom */ | |
529 | FALSE, /* has_bt */ | |
530 | TRUE, /* has_wlan */ | |
531 | }, | |
532 | counted(unifi_map_address_v22_v23), | |
533 | /* prog_offset */ | |
534 | { | |
535 | 0x00C00000, /* ram */ | |
536 | 0x00000000, /* rom */ | |
537 | 0x00000000, /* flash (invalid) */ | |
538 | 0x00000000, /* ext_sram (invalid) */ | |
539 | }, | |
540 | /* data_offset */ | |
541 | { | |
542 | 0x8000 /* ram */ | |
543 | }, | |
544 | /* windows */ | |
545 | { | |
546 | &generic1_window_unifi_v22_v23, | |
547 | &generic2_window_unifi_v22_v23, | |
548 | &generic3_window_unifi_v22_v23 | |
549 | } | |
550 | }; | |
551 | ||
552 | ||
553 | /* This is the list of all chips that we know about. I'm | |
554 | assuming that the order here will be important - we | |
555 | might have multiple entries witrh the same SDIO id for | |
556 | instance. The first one in this list will be the one | |
557 | that is returned if a search is done on only that id. | |
558 | The client will then have to call GetVersionXXX again | |
559 | but with more detailed info. | |
560 | ||
561 | I don't know if we need to signal this up to the client | |
562 | in some way? | |
563 | ||
564 | (We get the SDIO id before we know anything else about | |
565 | the chip. We might not be able to read any of the other | |
566 | registers at first, but we still need to know about the | |
567 | chip). */ | |
568 | static const struct chip_device_desc_t *chip_ver_to_desc[] = | |
569 | { | |
570 | &unifi_device_desc_v1, /* UF105x R01 */ | |
571 | &unifi_device_desc_v2, /* UF2... R02 */ | |
572 | &unifi_device_desc_v3, /* UF2... R03 */ | |
573 | &unifi_device_desc_v22, /* UF60xx */ | |
574 | &unifi_device_desc_v23, /* UF.... */ | |
575 | &hyd_wlan_subsys_desc_v1 | |
576 | }; | |
577 | ||
7e6f5794 | 578 | ChipDescript* ChipHelper_GetVersionSdio(u8 sdio_ver) |
635d2b00 | 579 | { |
26a6b2e1 | 580 | u32 i; |
635d2b00 GKH |
581 | |
582 | for (i = 0; i < nelem(chip_ver_to_desc); i++) | |
583 | { | |
584 | if (chip_ver_to_desc[i]->chip_version.sdio == sdio_ver) | |
585 | { | |
586 | return chip_ver_to_desc[i]; | |
587 | } | |
588 | } | |
589 | ||
590 | return &chip_device_desc_null; | |
591 | } | |
592 | ||
593 | ||
8c87f69a | 594 | ChipDescript* ChipHelper_GetVersionAny(u16 from_FF9A, u16 from_FE81) |
635d2b00 | 595 | { |
26a6b2e1 | 596 | u32 i; |
635d2b00 GKH |
597 | |
598 | if ((from_FF9A & 0xFF00) != 0) | |
599 | { | |
600 | for (i = 0; i < nelem(chip_ver_to_desc); i++) | |
601 | { | |
602 | if (chip_ver_to_desc[i]->chip_version.pre_bc7 && | |
603 | ((from_FF9A & chip_ver_to_desc[i]->chip_version.mask) == | |
604 | chip_ver_to_desc[i]->chip_version.result)) | |
605 | { | |
606 | return chip_ver_to_desc[i]; | |
607 | } | |
608 | } | |
609 | } | |
610 | else | |
611 | { | |
612 | for (i = 0; i < nelem(chip_ver_to_desc); i++) | |
613 | { | |
614 | if (!chip_ver_to_desc[i]->chip_version.pre_bc7 && | |
615 | ((from_FE81 & chip_ver_to_desc[i]->chip_version.mask) == | |
616 | chip_ver_to_desc[i]->chip_version.result)) | |
617 | { | |
618 | return chip_ver_to_desc[i]; | |
619 | } | |
620 | } | |
621 | } | |
622 | ||
623 | return &chip_device_desc_null; | |
624 | } | |
625 | ||
626 | ||
8c87f69a | 627 | ChipDescript* ChipHelper_GetVersionUniFi(u16 ver) |
635d2b00 GKH |
628 | { |
629 | return ChipHelper_GetVersionAny(0x0000, ver); | |
630 | } | |
631 | ||
632 | ||
47ec4ed2 | 633 | ChipDescript *ChipHelper_Null(void) |
635d2b00 GKH |
634 | { |
635 | return &chip_device_desc_null; | |
636 | } | |
637 | ||
638 | ||
8c87f69a | 639 | ChipDescript* ChipHelper_GetVersionBlueCore(enum chip_helper_bluecore_age bc_age, u16 version) |
635d2b00 GKH |
640 | { |
641 | if (bc_age == chip_helper_bluecore_pre_bc7) | |
642 | { | |
643 | return ChipHelper_GetVersionAny(version, 0x0000); | |
644 | } | |
645 | else | |
646 | { | |
647 | return ChipHelper_GetVersionAny(0x0000, version); | |
648 | } | |
649 | } | |
650 | ||
651 | ||
652 | /* Expand the DEF0 functions into simple code to return the | |
653 | correct thing. The DEF1 functions expand to nothing in | |
654 | this X macro expansion. */ | |
655 | #define CHIP_HELPER_DEF0_C_DEF(ret_type, name, info) \ | |
656 | ret_type ChipHelper_ ## name(ChipDescript * chip_help) \ | |
657 | { \ | |
658 | return chip_help->info; \ | |
659 | } | |
660 | #define CHIP_HELPER_DEF1_C_DEF(ret_type, name, type1, name1) | |
661 | ||
662 | CHIP_HELPER_LIST(C_DEF) | |
663 | ||
664 | /* | |
665 | * Map register addresses between HOST and SPI access. | |
666 | */ | |
8c87f69a | 667 | u16 ChipHelper_MapAddress_SPI2HOST(ChipDescript *chip_help, u16 addr) |
635d2b00 | 668 | { |
26a6b2e1 | 669 | u32 i; |
635d2b00 GKH |
670 | for (i = 0; i < chip_help->map.len; i++) |
671 | { | |
672 | if (chip_help->map.vals[i].spi == addr) | |
673 | { | |
674 | return chip_help->map.vals[i].host; | |
675 | } | |
676 | } | |
677 | return addr; | |
678 | } | |
679 | ||
680 | ||
8c87f69a | 681 | u16 ChipHelper_MapAddress_HOST2SPI(ChipDescript *chip_help, u16 addr) |
635d2b00 | 682 | { |
26a6b2e1 | 683 | u32 i; |
635d2b00 GKH |
684 | for (i = 0; i < chip_help->map.len; i++) |
685 | { | |
686 | if (chip_help->map.vals[i].host == addr) | |
687 | { | |
688 | return chip_help->map.vals[i].spi; | |
689 | } | |
690 | } | |
691 | return addr; | |
692 | } | |
693 | ||
694 | ||
695 | /* The address returned by this function is the start of the | |
696 | window in the address space, that is where we can start | |
697 | accessing data from. If a section of the window at the | |
698 | start is unusable because something else is cluttering up | |
699 | the address map then that is taken into account and this | |
700 | function returns that address justt past that. */ | |
8c87f69a | 701 | u16 ChipHelper_WINDOW_ADDRESS(ChipDescript *chip_help, |
635d2b00 GKH |
702 | enum chip_helper_window_index window) |
703 | { | |
704 | if (window < CHIP_HELPER_WINDOW_COUNT && | |
705 | chip_help->windows[window] != NULL) | |
706 | { | |
707 | return chip_help->windows[window]->address + chip_help->windows[window]->blocked; | |
708 | } | |
709 | return 0; | |
710 | } | |
711 | ||
712 | ||
713 | /* This returns the size of the window minus any blocked section */ | |
8c87f69a | 714 | u16 ChipHelper_WINDOW_SIZE(ChipDescript *chip_help, |
635d2b00 GKH |
715 | enum chip_helper_window_index window) |
716 | { | |
717 | if (window < CHIP_HELPER_WINDOW_COUNT && | |
718 | chip_help->windows[window] != NULL) | |
719 | { | |
720 | return chip_help->windows[window]->size - chip_help->windows[window]->blocked; | |
721 | } | |
722 | return 0; | |
723 | } | |
724 | ||
725 | ||
726 | /* Get the register writes we should do to make sure that | |
727 | the chip is running with most clocks on. */ | |
26a6b2e1 | 728 | u32 ChipHelper_ClockStartupSequence(ChipDescript *chip_help, |
635d2b00 GKH |
729 | const struct chip_helper_init_values **val) |
730 | { | |
731 | *val = chip_help->init.vals; | |
732 | return chip_help->init.len; | |
733 | } | |
734 | ||
735 | ||
736 | /* Get the set of values tat we should write to the chip to perform a reset. */ | |
26a6b2e1 | 737 | u32 ChipHelper_HostResetSequence(ChipDescript *chip_help, |
635d2b00 GKH |
738 | const struct chip_helper_reset_values **val) |
739 | { | |
740 | *val = chip_help->reset_prog.vals; | |
741 | return chip_help->reset_prog.len; | |
742 | } | |
743 | ||
744 | ||
745 | /* Decode a windowed access to the chip. */ | |
95e326c2 | 746 | s32 ChipHelper_DecodeWindow(ChipDescript *chip_help, |
635d2b00 GKH |
747 | enum chip_helper_window_index window, |
748 | enum chip_helper_window_type type, | |
26a6b2e1 GKH |
749 | u32 offset, |
750 | u16 *page, u16 *addr, u32 *len) | |
635d2b00 GKH |
751 | { |
752 | const struct window_info_t *win; | |
753 | const struct window_shift_info_t *mode; | |
8c87f69a | 754 | u16 of, pg; |
635d2b00 GKH |
755 | |
756 | if (window >= CHIP_HELPER_WINDOW_COUNT) | |
757 | { | |
758 | return FALSE; | |
759 | } | |
760 | if ((win = chip_help->windows[window]) == NULL) | |
761 | { | |
762 | return FALSE; | |
763 | } | |
764 | if (type >= CHIP_HELPER_WT_COUNT) | |
765 | { | |
766 | return FALSE; | |
767 | } | |
768 | if ((mode = &win->mode[type]) == NULL) | |
769 | { | |
770 | return FALSE; | |
771 | } | |
772 | if (!mode->allowed) | |
773 | { | |
774 | return FALSE; | |
775 | } | |
776 | ||
8c87f69a GKH |
777 | pg = (u16)(offset >> mode->page_shift) + mode->page_offset; |
778 | of = (u16)(offset & ((1 << mode->page_shift) - 1)); | |
635d2b00 GKH |
779 | /* If 'blocked' is zero this does nothing, else decrease |
780 | the page register and increase the offset until we aren't | |
781 | in the blocked region of the window. */ | |
782 | while (of < win->blocked) | |
783 | { | |
784 | of += 1 << mode->page_shift; | |
785 | pg--; | |
786 | } | |
787 | *page = pg; | |
788 | *addr = win->address + of; | |
789 | *len = win->size - of; | |
790 | return TRUE; | |
791 | } | |
792 | ||
793 |