Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-fixes
[pandora-kernel.git] / drivers / staging / csr / csr_wifi_hip_chiphelper.c
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
11 #include "csr_macro.h"
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
61 static const u16 reset_program_a_v1_or_v2[] = {
62     0x0000
63 };
64 static const u16 reset_program_b_v1_or_v2[] = {
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
578 ChipDescript* ChipHelper_GetVersionSdio(u8 sdio_ver)
579 {
580     u32 i;
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
594 ChipDescript* ChipHelper_GetVersionAny(u16 from_FF9A, u16 from_FE81)
595 {
596     u32 i;
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
627 ChipDescript* ChipHelper_GetVersionUniFi(u16 ver)
628 {
629     return ChipHelper_GetVersionAny(0x0000, ver);
630 }
631
632
633 ChipDescript *ChipHelper_Null(void)
634 {
635     return &chip_device_desc_null;
636 }
637
638
639 ChipDescript* ChipHelper_GetVersionBlueCore(enum chip_helper_bluecore_age bc_age, u16 version)
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  */
667 u16 ChipHelper_MapAddress_SPI2HOST(ChipDescript *chip_help, u16 addr)
668 {
669     u32 i;
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
681 u16 ChipHelper_MapAddress_HOST2SPI(ChipDescript *chip_help, u16 addr)
682 {
683     u32 i;
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. */
701 u16 ChipHelper_WINDOW_ADDRESS(ChipDescript                 *chip_help,
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 */
714 u16 ChipHelper_WINDOW_SIZE(ChipDescript                 *chip_help,
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. */
728 u32 ChipHelper_ClockStartupSequence(ChipDescript                          *chip_help,
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. */
737 u32 ChipHelper_HostResetSequence(ChipDescript                           *chip_help,
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. */
746 s32 ChipHelper_DecodeWindow(ChipDescript *chip_help,
747                                  enum chip_helper_window_index window,
748                                  enum chip_helper_window_type type,
749                                  u32 offset,
750                                  u16 *page, u16 *addr, u32 *len)
751 {
752     const struct window_info_t *win;
753     const struct window_shift_info_t *mode;
754     u16 of, pg;
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
777     pg = (u16)(offset >> mode->page_shift) + mode->page_offset;
778     of = (u16)(offset & ((1 << mode->page_shift) - 1));
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