1 /*****************************************************************************
3 (c) Cambridge Silicon Radio Limited 2011
4 All rights reserved and confidential information of CSR
6 Refer to LICENSE.txt included with this source for details
9 *****************************************************************************/
11 #include "csr_macro.h"
12 #include "csr_wifi_hip_chiphelper_private.h"
15 #define nelem(a) (sizeof(a) / sizeof(a[0]))
18 #define counted(foo) { nelem(foo), foo }
19 #define null_counted() { 0, NULL }
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[] = {
38 static const struct chip_helper_init_values init_vals_v2[] = {
49 static const struct chip_helper_init_values init_vals_v22_v23[] = {
51 /*{ 0x????, 0x???? }, */
61 static const u16 reset_program_a_v1_or_v2[] = {
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
71 static const struct chip_helper_reset_values reset_program_v1_or_v2[] =
74 MAKE_GP(REGISTERS, 0x000C),
75 nelem(reset_program_a_v1_or_v2),
76 reset_program_a_v1_or_v2
79 MAKE_GP(MAC_PMEM, 0x000000),
80 nelem(reset_program_b_v1_or_v2),
81 reset_program_b_v1_or_v2
85 static const struct chip_map_address_t unifi_map_address_v1_v2[] =
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 */
94 static const struct chip_map_address_t unifi_map_address_v22_v23[] =
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 */
104 static const struct chip_device_regs_t unifi_device_regs_null =
106 0xFE81, /* GBL_CHIP_VERSION */
107 0x0000, /* GBL_MISC_ENABLES */
108 0x0000, /* DBG_EMU_CMD */
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 */
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 */
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 */
145 static const struct chip_device_regs_t unifi_device_regs_v1 =
147 0xFE81, /* GBL_CHIP_VERSION */
148 0xFE87, /* GBL_MISC_ENABLES */
149 0xFE9C, /* DBG_EMU_CMD */
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 */
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 */
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 */
186 static const struct chip_device_regs_t unifi_device_regs_v2 =
188 0xFE81, /* GBL_CHIP_VERSION */
189 0xFE87, /* GBL_MISC_ENABLES */
190 0xFE9C, /* DBG_EMU_CMD */
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 */
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 */
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 */
227 static const struct chip_device_regs_t unifi_device_regs_v22_v23 =
229 0xFE81, /* GBL_CHIP_VERSION */
230 0xF84F, /* GBL_MISC_ENABLES */
231 0xF81D, /* DBG_EMU_CMD */
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 */
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 */
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 */
267 /* Program memory window on UF105x. */
268 static const struct window_shift_info_t prog_window_array_unifi_v1_v2[CHIP_HELPER_WT_COUNT] =
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 */
277 /* Shared memory window on UF105x. */
278 static const struct window_shift_info_t shared_window_array_unifi_v1_v2[CHIP_HELPER_WT_COUNT] =
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 */
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] =
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 */
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 };
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 };
307 static const struct chip_device_desc_t chip_device_desc_null =
309 { FALSE, 0x0000, 0x0000, 0x00 },
312 null_counted(), /* init */
313 null_counted(), /* reset_prog */
314 &unifi_device_regs_null, /* regs */
316 FALSE, /* has_flash */
317 FALSE, /* has_ext_sram */
320 FALSE, /* has_wlan */
342 static const struct chip_device_desc_t unifi_device_desc_v1 =
344 { FALSE, 0xf0ff, 0x1001, 0x01 }, /* UF105x R01 */
347 counted(init_vals_v1), /* init */
348 counted(reset_program_v1_or_v2), /* reset_prog */
349 &unifi_device_regs_v1, /* regs */
351 TRUE, /* has_flash */
352 TRUE, /* has_ext_sram */
357 counted(unifi_map_address_v1_v2), /* map */
360 0x00100000, /* ram */
361 0x00000000, /* rom (invalid) */
362 0x00000000, /* flash */
363 0x00200000, /* ext_ram */
371 &prog1_window_unifi_v1_v2,
372 &prog2_window_unifi_v1_v2,
373 &shared_window_unifi_v1_v2
377 static const struct chip_device_desc_t unifi_device_desc_v2 =
379 { FALSE, 0xf0ff, 0x2001, 0x02 }, /* UF2... R02 */
382 counted(init_vals_v2), /* init */
383 counted(reset_program_v1_or_v2), /* reset_prog */
384 &unifi_device_regs_v2, /* regs */
386 TRUE, /* has_flash */
387 TRUE, /* has_ext_sram */
392 counted(unifi_map_address_v1_v2), /* map */
395 0x00100000, /* ram */
396 0x00000000, /* rom (invalid) */
397 0x00000000, /* flash */
398 0x00200000, /* ext_ram */
406 &prog1_window_unifi_v1_v2,
407 &prog2_window_unifi_v1_v2,
408 &shared_window_unifi_v1_v2
412 static const struct chip_device_desc_t unifi_device_desc_v3 =
414 { FALSE, 0xf0ff, 0x3001, 0x02 }, /* UF2... R03 */
417 counted(init_vals_v2), /* init */
418 counted(reset_program_v1_or_v2), /* reset_prog */
419 &unifi_device_regs_v2, /* regs */
421 TRUE, /* has_flash */
422 TRUE, /* has_ext_sram */
427 counted(unifi_map_address_v1_v2), /* map */
430 0x00100000, /* ram */
431 0x00000000, /* rom (invalid) */
432 0x00000000, /* flash */
433 0x00200000, /* ext_ram */
441 &prog1_window_unifi_v1_v2,
442 &prog2_window_unifi_v1_v2,
443 &shared_window_unifi_v1_v2
447 static const struct chip_device_desc_t unifi_device_desc_v22 =
449 { FALSE, 0x00ff, 0x0022, 0x07 }, /* UF60xx */
452 counted(init_vals_v22_v23), /* init */
453 null_counted(), /* reset_prog */
454 &unifi_device_regs_v22_v23, /* regs */
456 FALSE, /* has_flash */
457 FALSE, /* has_ext_sram */
462 counted(unifi_map_address_v22_v23), /* map */
465 0x00C00000, /* ram */
466 0x00000000, /* rom */
467 0x00000000, /* flash (invalid) */
468 0x00000000, /* ext_ram (invalid) */
476 &generic1_window_unifi_v22_v23,
477 &generic2_window_unifi_v22_v23,
478 &generic3_window_unifi_v22_v23
482 static const struct chip_device_desc_t unifi_device_desc_v23 =
484 { FALSE, 0x00ff, 0x0023, 0x08 }, /* UF.... */
487 counted(init_vals_v22_v23), /* init */
488 null_counted(), /* reset_prog */
489 &unifi_device_regs_v22_v23, /* regs */
491 FALSE, /* has_flash */
492 FALSE, /* has_ext_sram */
497 counted(unifi_map_address_v22_v23),
500 0x00C00000, /* ram */
501 0x00000000, /* rom */
502 0x00000000, /* flash (invalid) */
503 0x00000000, /* ext_sram (invalid) */
511 &generic1_window_unifi_v22_v23,
512 &generic2_window_unifi_v22_v23,
513 &generic3_window_unifi_v22_v23
517 static const struct chip_device_desc_t hyd_wlan_subsys_desc_v1 =
519 { FALSE, 0x00ff, 0x0044, 0x00 }, /* UF.... */
522 counted(init_vals_v22_v23), /* init */
523 null_counted(), /* reset_prog */
524 &unifi_device_regs_v22_v23, /* regs */
526 FALSE, /* has_flash */
527 FALSE, /* has_ext_sram */
532 counted(unifi_map_address_v22_v23),
535 0x00C00000, /* ram */
536 0x00000000, /* rom */
537 0x00000000, /* flash (invalid) */
538 0x00000000, /* ext_sram (invalid) */
546 &generic1_window_unifi_v22_v23,
547 &generic2_window_unifi_v22_v23,
548 &generic3_window_unifi_v22_v23
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.
561 I don't know if we need to signal this up to the client
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
568 static const struct chip_device_desc_t *chip_ver_to_desc[] =
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
578 ChipDescript* ChipHelper_GetVersionSdio(u8 sdio_ver)
582 for (i = 0; i < nelem(chip_ver_to_desc); i++)
584 if (chip_ver_to_desc[i]->chip_version.sdio == sdio_ver)
586 return chip_ver_to_desc[i];
590 return &chip_device_desc_null;
594 ChipDescript* ChipHelper_GetVersionAny(u16 from_FF9A, u16 from_FE81)
598 if ((from_FF9A & 0xFF00) != 0)
600 for (i = 0; i < nelem(chip_ver_to_desc); i++)
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))
606 return chip_ver_to_desc[i];
612 for (i = 0; i < nelem(chip_ver_to_desc); i++)
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))
618 return chip_ver_to_desc[i];
623 return &chip_device_desc_null;
627 ChipDescript* ChipHelper_GetVersionUniFi(u16 ver)
629 return ChipHelper_GetVersionAny(0x0000, ver);
633 ChipDescript *ChipHelper_Null(void)
635 return &chip_device_desc_null;
639 ChipDescript* ChipHelper_GetVersionBlueCore(enum chip_helper_bluecore_age bc_age, u16 version)
641 if (bc_age == chip_helper_bluecore_pre_bc7)
643 return ChipHelper_GetVersionAny(version, 0x0000);
647 return ChipHelper_GetVersionAny(0x0000, version);
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) \
658 return chip_help->info; \
660 #define CHIP_HELPER_DEF1_C_DEF(ret_type, name, type1, name1)
662 CHIP_HELPER_LIST(C_DEF)
665 * Map register addresses between HOST and SPI access.
667 u16 ChipHelper_MapAddress_SPI2HOST(ChipDescript *chip_help, u16 addr)
670 for (i = 0; i < chip_help->map.len; i++)
672 if (chip_help->map.vals[i].spi == addr)
674 return chip_help->map.vals[i].host;
681 u16 ChipHelper_MapAddress_HOST2SPI(ChipDescript *chip_help, u16 addr)
684 for (i = 0; i < chip_help->map.len; i++)
686 if (chip_help->map.vals[i].host == addr)
688 return chip_help->map.vals[i].spi;
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)
704 if (window < CHIP_HELPER_WINDOW_COUNT &&
705 chip_help->windows[window] != NULL)
707 return chip_help->windows[window]->address + chip_help->windows[window]->blocked;
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)
717 if (window < CHIP_HELPER_WINDOW_COUNT &&
718 chip_help->windows[window] != NULL)
720 return chip_help->windows[window]->size - chip_help->windows[window]->blocked;
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)
731 *val = chip_help->init.vals;
732 return chip_help->init.len;
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)
740 *val = chip_help->reset_prog.vals;
741 return chip_help->reset_prog.len;
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,
750 u16 *page, u16 *addr, u32 *len)
752 const struct window_info_t *win;
753 const struct window_shift_info_t *mode;
756 if (window >= CHIP_HELPER_WINDOW_COUNT)
760 if ((win = chip_help->windows[window]) == NULL)
764 if (type >= CHIP_HELPER_WT_COUNT)
768 if ((mode = &win->mode[type]) == NULL)
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)
784 of += 1 << mode->page_shift;
788 *addr = win->address + of;
789 *len = win->size - of;