1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
|
/*****************************************************************************
(c) Cambridge Silicon Radio Limited 2011
All rights reserved and confidential information of CSR
Refer to LICENSE.txt included with this source for details
on the license terms.
*****************************************************************************/
#ifndef CSR_WIFI_HIP_CHIPHELPER_H__
#define CSR_WIFI_HIP_CHIPHELPER_H__
#include <linux/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/* The age of the BlueCore chip. This is probably not useful, if
you know the age then you can probably work out the version directly. */
enum chip_helper_bluecore_age
{
chip_helper_bluecore_pre_bc7,
chip_helper_bluecore_bc7_or_later
};
/* We support up to three windowed regions at the moment.
Don't reorder these - they're used to index into an array. */
enum chip_helper_window_index
{
CHIP_HELPER_WINDOW_1 = 0,
CHIP_HELPER_WINDOW_2 = 1,
CHIP_HELPER_WINDOW_3 = 2,
CHIP_HELPER_WINDOW_COUNT = 3
};
/* These are the things that we can access through a window.
Don't reorder these - they're used to index into an array. */
enum chip_helper_window_type
{
CHIP_HELPER_WT_CODE_RAM = 0,
CHIP_HELPER_WT_FLASH = 1,
CHIP_HELPER_WT_EXT_SRAM = 2,
CHIP_HELPER_WT_ROM = 3,
CHIP_HELPER_WT_SHARED = 4,
CHIP_HELPER_WT_COUNT = 5
};
/* Commands to stop and start the XAP */
enum chip_helper_dbg_emu_cmd_enum
{
CHIP_HELPER_DBG_EMU_CMD_XAP_STEP_MASK = 0x0001,
CHIP_HELPER_DBG_EMU_CMD_XAP_RUN_B_MASK = 0x0002,
CHIP_HELPER_DBG_EMU_CMD_XAP_BRK_MASK = 0x0004,
CHIP_HELPER_DBG_EMU_CMD_XAP_WAKEUP_MASK = 0x0008
};
/* Bitmasks for Stop and sleep status: DBG_SPI_STOP_STATUS & DBG_HOST_STOP_STATUS */
enum chip_helper_dbg_stop_status_enum
{
CHIP_HELPER_DBG_STOP_STATUS_NONE_MASK = 0x0000,
CHIP_HELPER_DBG_STOP_STATUS_P0_MASK = 0x0001,
CHIP_HELPER_DBG_STOP_STATUS_P1_MASK = 0x0002,
CHIP_HELPER_DBG_STOP_STATUS_P2_MASK = 0x0004,
CHIP_HELPER_DBG_STOP_STATUS_SLEEP_STATUS_P0_MASK = 0x0008,
CHIP_HELPER_DBG_STOP_STATUS_SLEEP_STATUS_P1_MASK = 0x0010,
CHIP_HELPER_DBG_STOP_STATUS_SLEEP_STATUS_P2_MASK = 0x0020,
/* Legacy names/alias */
CHIP_HELPER_DBG_STOP_STATUS_MAC_MASK = 0x0001,
CHIP_HELPER_DBG_STOP_STATUS_PHY_MASK = 0x0002,
CHIP_HELPER_DBG_STOP_STATUS_BT_MASK = 0x0004,
CHIP_HELPER_DBG_STOP_STATUS_SLEEP_STATUS_MAC_MASK = 0x0008,
CHIP_HELPER_DBG_STOP_STATUS_SLEEP_STATUS_PHY_MASK = 0x0010,
CHIP_HELPER_DBG_STOP_STATUS_SLEEP_STATUS_BT_MASK = 0x0020
};
/* Codes to disable the watchdog */
enum chip_helper_watchdog_disable_enum
{
CHIP_HELPER_WATCHDOG_DISABLE_CODE1 = 0x6734,
CHIP_HELPER_WATCHDOG_DISABLE_CODE2 = 0xD6BF,
CHIP_HELPER_WATCHDOG_DISABLE_CODE3 = 0xC31E
};
/* Other bits have changed between versions */
enum chip_helper_gbl_misc_enum
{
CHIP_HELPER_GBL_MISC_SPI_STOP_OUT_EN_MASK = 0x0001,
CHIP_HELPER_GBL_MISC_MMU_INIT_DONE_MASK = 0x0004
};
/* Coex status register, contains interrupt status and reset pullup status.
* CHIP_HELPER_COEX_STATUS_RST_PULLS_MSB_MASK can be used to check
* for WAPI on R03 chips and later. */
enum chip_helper_coex_status_mask_enum
{
CHIP_HELPER_COEX_STATUS_RST_PULLS_LSB_MASK = 0x0001,
CHIP_HELPER_COEX_STATUS_RST_PULLS_MSB_MASK = 0x0008,
CHIP_HELPER_COEX_STATUS_WL_FEC_PINS_LSB_MASK = 0x0010,
CHIP_HELPER_COEX_STATUS_WL_FEC_PINS_MSB_MASK = 0x0080,
CHIP_HELPER_COEX_STATUS_INT_UART_MASK = 0x0100,
CHIP_HELPER_COEX_STATUS_INT_BT_LEG_MASK = 0x0200
};
/* How to select the different CPUs */
enum chip_helper_dbg_proc_sel_enum
{
CHIP_HELPER_DBG_PROC_SEL_MAC = 0,
CHIP_HELPER_DBG_PROC_SEL_PHY = 1,
CHIP_HELPER_DBG_PROC_SEL_BT = 2,
CHIP_HELPER_DBG_PROC_SEL_NONE = 2,
CHIP_HELPER_DBG_PROC_SEL_BOTH = 3
};
/* These are the only registers that we have to know the
address of before we know the chip version. */
enum chip_helper_fixed_registers
{
/* This is the address of GBL_CHIP_VERISON on BC7,
UF105x, UF60xx and
anything later than that. */
CHIP_HELPER_UNIFI_GBL_CHIP_VERSION = 0xFE81,
CHIP_HELPER_OLD_BLUECORE_GBL_CHIP_VERSION = 0xFF9A
/* This isn't used at the moment (but might be needed
to distinguish the BlueCore sub version?) */
/* CHIP_HELPER_OLD_BLUECORE_ANA_VERSION_ID = 0xFF7D */
};
/* Address-value pairs for defining initialisation values */
struct chip_helper_init_values
{
u16 addr;
u16 value;
};
/* A block of data that should be written to the device */
struct chip_helper_reset_values
{
u32 gp_address;
u32 len;
const u16 *data;
};
/*
* This is the C API.
*/
/* opaque type */
typedef const struct chip_device_desc_t ChipDescript;
/* Return a NULL descriptor */
ChipDescript* ChipHelper_Null(void);
/* This should get the correct version for any CSR chip.
The two parameters are what is read from addresses
0xFF9A and 0xFE81 (OLD_BLUECORE_GBL_CHIP_VERSION and
UNIFI_GBL_CHIP_VERSION). These should give a unique identity
for most (all?) chips.
FF9A is the old GBL_CHIP_VERSION register. If the high
eight bits are zero then the chip is a new (BC7 +) one
and FE81 is the _new_ GBL_CHIP_VERSION register. */
ChipDescript* ChipHelper_GetVersionAny(u16 from_FF9A, u16 from_FE81);
/* The chip is a UniFi, but we don't know which type
The parameter is the value of UNIFI_GBL_CHIP_VERSION (0xFE81) */
ChipDescript* ChipHelper_GetVersionUniFi(u16 version);
/* This gets the version from the SDIO device id. This only
gives quite a coarse grained version, so we should update once
we hav access to the function N registers. */
ChipDescript* ChipHelper_GetVersionSdio(u8 sdio_version);
/* The chip is some sort of BlueCore. If "age" is "pre_bc7" then
"version" is what was read from FF9A. If "age" is bc7_or_later
then "version" is read from FE81. If we don't know if we're pre
or post BC7 then we should use "GetVersionAny". */
ChipDescript* ChipHelper_GetVersionBlueCore(enum chip_helper_bluecore_age age,
u16 version);
/* The main functions of this class are built with an X macro. This
means we can generate the C and C++ versions from the same source
without the two diverging.
The DEF0 functions are simple and take no parameters. The first
parameter to the macro is the return type. The second parameter
is the function name and the third parameter is where to get the
info from (this is hidden from the user).
The DEF1 functions take one parameter. This time the third macro
parameter is the type of this parameter, and the fourth macro
parameter is the name of the parameter. The bodies of these
functions are hand written. */
#define CHIP_HELPER_LIST(m) \
CHIP_HELPER_DEF0(m, (const char *, FriendlyName, friendly_name)) \
CHIP_HELPER_DEF0(m, (const char *, MarketingName, marketing_name)) \
CHIP_HELPER_DEF0(m, (u16, DBG_EMU_CMD, regs->dbg_emu_cmd)) \
CHIP_HELPER_DEF0(m, (u16, DBG_HOST_PROC_SELECT, regs->host.dbg_proc_select)) \
CHIP_HELPER_DEF0(m, (u16, DBG_HOST_STOP_STATUS, regs->host.dbg_stop_status)) \
CHIP_HELPER_DEF0(m, (u16, HOST_WINDOW1_PAGE, regs->host.window1_page)) \
CHIP_HELPER_DEF0(m, (u16, HOST_WINDOW2_PAGE, regs->host.window2_page)) \
CHIP_HELPER_DEF0(m, (u16, HOST_WINDOW3_PAGE, regs->host.window3_page)) \
CHIP_HELPER_DEF0(m, (u16, HOST_IO_LOG_ADDR, regs->host.io_log_addr)) \
CHIP_HELPER_DEF0(m, (u16, DBG_SPI_PROC_SELECT, regs->spi.dbg_proc_select)) \
CHIP_HELPER_DEF0(m, (u16, DBG_SPI_STOP_STATUS, regs->spi.dbg_stop_status)) \
CHIP_HELPER_DEF0(m, (u16, SPI_WINDOW1_PAGE, regs->spi.window1_page)) \
CHIP_HELPER_DEF0(m, (u16, SPI_WINDOW2_PAGE, regs->spi.window2_page)) \
CHIP_HELPER_DEF0(m, (u16, SPI_WINDOW3_PAGE, regs->spi.window3_page)) \
CHIP_HELPER_DEF0(m, (u16, SPI_IO_LOG_ADDR, regs->spi.io_log_addr)) \
CHIP_HELPER_DEF0(m, (u16, DBG_RESET, regs->dbg_reset)) \
CHIP_HELPER_DEF0(m, (u16, DBG_RESET_VALUE, regs->dbg_reset_value)) \
CHIP_HELPER_DEF0(m, (u16, DBG_RESET_WARN, regs->dbg_reset_warn)) \
CHIP_HELPER_DEF0(m, (u16, DBG_RESET_WARN_VALUE, regs->dbg_reset_warn_value)) \
CHIP_HELPER_DEF0(m, (u16, DBG_RESET_RESULT, regs->dbg_reset_result)) \
CHIP_HELPER_DEF0(m, (u16, WATCHDOG_DISABLE, regs->watchdog_disable)) \
CHIP_HELPER_DEF0(m, (u16, PROC_PC_SNOOP, regs->proc_pc_snoop)) \
CHIP_HELPER_DEF0(m, (u16, GBL_CHIP_VERSION, regs->gbl_chip_version)) \
CHIP_HELPER_DEF0(m, (u16, GBL_MISC_ENABLES, regs->gbl_misc_enables)) \
CHIP_HELPER_DEF0(m, (u16, XAP_PCH, regs->xap_pch)) \
CHIP_HELPER_DEF0(m, (u16, XAP_PCL, regs->xap_pcl)) \
CHIP_HELPER_DEF0(m, (u16, MAILBOX0, regs->mailbox0)) \
CHIP_HELPER_DEF0(m, (u16, MAILBOX1, regs->mailbox1)) \
CHIP_HELPER_DEF0(m, (u16, MAILBOX2, regs->mailbox2)) \
CHIP_HELPER_DEF0(m, (u16, MAILBOX3, regs->mailbox3)) \
CHIP_HELPER_DEF0(m, (u16, SDIO_HIP_HANDSHAKE, regs->sdio_hip_handshake)) \
CHIP_HELPER_DEF0(m, (u16, SDIO_HOST_INT, regs->sdio_host_int)) \
CHIP_HELPER_DEF0(m, (u16, COEX_STATUS, regs->coex_status)) \
CHIP_HELPER_DEF0(m, (u16, SHARED_IO_INTERRUPT, regs->shared_io_interrupt)) \
CHIP_HELPER_DEF0(m, (u32, PROGRAM_MEMORY_RAM_OFFSET, prog_offset.ram)) \
CHIP_HELPER_DEF0(m, (u32, PROGRAM_MEMORY_ROM_OFFSET, prog_offset.rom)) \
CHIP_HELPER_DEF0(m, (u32, PROGRAM_MEMORY_FLASH_OFFSET, prog_offset.flash)) \
CHIP_HELPER_DEF0(m, (u32, PROGRAM_MEMORY_EXT_SRAM_OFFSET, prog_offset.ext_sram)) \
CHIP_HELPER_DEF0(m, (u16, DATA_MEMORY_RAM_OFFSET, data_offset.ram)) \
CHIP_HELPER_DEF0(m, (s32, HasFlash, bools.has_flash)) \
CHIP_HELPER_DEF0(m, (s32, HasExtSram, bools.has_ext_sram)) \
CHIP_HELPER_DEF0(m, (s32, HasRom, bools.has_rom)) \
CHIP_HELPER_DEF0(m, (s32, HasBt, bools.has_bt)) \
CHIP_HELPER_DEF0(m, (s32, HasWLan, bools.has_wlan)) \
CHIP_HELPER_DEF1(m, (u16, WINDOW_ADDRESS, enum chip_helper_window_index, window)) \
CHIP_HELPER_DEF1(m, (u16, WINDOW_SIZE, enum chip_helper_window_index, window)) \
CHIP_HELPER_DEF1(m, (u16, MapAddress_SPI2HOST, u16, addr)) \
CHIP_HELPER_DEF1(m, (u16, MapAddress_HOST2SPI, u16, addr)) \
CHIP_HELPER_DEF1(m, (u32, ClockStartupSequence, const struct chip_helper_init_values **, val)) \
CHIP_HELPER_DEF1(m, (u32, HostResetSequence, const struct chip_helper_reset_values **, val))
/* Some magic to help the expansion */
#define CHIP_HELPER_DEF0(a, b) \
CHIP_HELPER_DEF0_ ## a b
#define CHIP_HELPER_DEF1(a, b) \
CHIP_HELPER_DEF1_ ## a b
/* Macros so that when we expand the list we get "C" function prototypes. */
#define CHIP_HELPER_DEF0_C_DEC(ret_type, name, info) \
ret_type ChipHelper_ ## name(ChipDescript * chip_help);
#define CHIP_HELPER_DEF1_C_DEC(ret_type, name, type1, name1) \
ret_type ChipHelper_ ## name(ChipDescript * chip_help, type1 name1);
CHIP_HELPER_LIST(C_DEC)
/* FriendlyName
MarketingName
These two functions return human readable strings that describe
the chip. FriendlyName returns something that a software engineer
at CSR might understand. MarketingName returns something more like
an external name for a CSR chip.
*/
/* DBG_EMU_CMD
WATCHDOG_DISABLE
PROC_PC_SNOOP
GBL_CHIP_VERSION
XAP_PCH
XAP_PCL
These registers are used to control the XAPs.
*/
/* DBG_HOST_PROC_SELECT DBG_HOST_STOP_STATUS
HOST_WINDOW1_PAGE HOST_WINDOW2_PAGE HOST_WINDOW3_PAGE
HOST_IO_LOG_ADDR
DBG_SPI_PROC_SELECT DBG_SPI_STOP_STATUS
SPI_WINDOW1_PAGE SPI_WINDOW2_PAGE SPI_WINDOW3_PAGE
SPI_IO_LOG_ADDR
These register are used to control the XAPs and the memory
windows, normally while debugging the code on chip. There
are two versons of these registers, one for access via SPI
and another for access via the host interface.
*/
/* DBG_RESET
DBG_RESET_VALUE
DBG_RESET_WARN
DBG_RESET_WARN_VALUE
DBG_RESET_RESULT
These registers are used to reset the XAP. This can be
quite complex for some chips. If DBG_RESET_WARN is non
zero the DBG_RESET_WARN_VALUE should be written to address
DBG_RESET_WARN before the reset is perfeormed. DBG_RESET_VALUE
should then be written to DBG_RESET to make the reset happen.
The DBG_RESET_RESULT register should contain 0 if the reset
was successful.
*/
/* GBL_MISC_ENABLES
This register controls some special chip features. It
should be used with care is it changes quite a lot between
chip versions.
*/
/* MAILBOX0
MAILBOX1
MAILBOX2
MAILBOX3
The mailbox registers are for communication between the host
and the firmware. There use is described in part by the host
interface protcol specifcation.
*/
/* SDIO_HIP_HANDSHAKE
This is one of the more important SDIO HIP registers. On some
chips it has the same value as one of the mailbox registers
and on other chips it is different.
*/
/* SDIO_HOST_INT
SHARED_IO_INTERRUPT
These registers are used by some versions of the host interface
protocol specification. Their names should probably be changed
to hide the registers and to expose the functions more.
*/
/* COEX_STATUS
Coex status register, contains interrupt status and reset
pullup status. The latter is used to detect WAPI.
*/
/* PROGRAM_MEMORY_RAM_OFFSET
PROGRAM_MEMORY_ROM_OFFSET
PROGRAM_MEMORY_FLASH_OFFSET
PROGRAM_MEMORY_EXT_SRAM_OFFSET
DATA_MEMORY_RAM_OFFSET
These are constants that describe the offset of the different
memory types in the two different address spaces.
*/
/* HasFlash HasExtSram HasRom
HasBt HasWLan
These are a set of bools describing the chip.
*/
/* WINDOW_ADDRESS WINDOW_SIZE
These two functions return the size and address of the windows.
The address is the address of the lowest value in the address
map that is part of the window and the size is the number of
visible words.
Some of the windows have thier lowest portion covered by
registers. For these windows address is the first address
after the registers and size is the siave excluding the part
covered by registers.
*/
/* MapAddress_SPI2HOST
MapAddress_HOST2SPI
The debugging interface is duplicated on UniFi and later chips
so that there are two versions - one over the SPI interaface and
the other over the SDIO interface. These functions map the
registers between these two interfaces.
*/
/* ClockStartupSequence
This function returns the list of register value pairs that
should be forced into UniFi to enable SPI communication. This
set of registers is not needed if the firmware is running, but
will be needed if the device is being booted from cold. These
register writes enable the clocks and setup the PLL to a basic
working state. SPI access might be unreliable until these writes
have occured (And they may take mulitple goes).
*/
/* HostResetSequence
This returns a number of chunks of data and generic pointers.
All of the XAPs should be stopped. The data should be written
to the generic pointers. The instruction pointer for the MAC
should then be set to the start of program memory and then the
MAC should be "go"d. This will reset the chip in a reliable
and orderly manner without resetting the SDIO interface. It
is therefore not needed if the chip is being accessed by the
SPI interface (the DBG_RESET_ mechanism can be used instead).
*/
/* The Decode Window function is more complex. For the window
'window' it tries to return the address and page register
value needed to see offset 'offset' of memory type 'type'.
It return 1 on success and 0 on failure. 'page' is what
should be written to the page register. 'addr' is the
address in the XAPs 16 address map to read from. 'len'
is the length that we can read without having to change
the page registers. */
s32 ChipHelper_DecodeWindow(ChipDescript *chip_help,
enum chip_helper_window_index window,
enum chip_helper_window_type type,
u32 offset,
u16 *page, u16 *addr, u32 *len);
#ifdef __cplusplus
/* Close the extern "C" */
}
/*
* This is the C++ API.
*/
class ChipHelper
{
public:
/* If this constructor is used then a GetVersionXXX function
should be called next. */
ChipHelper();
/* copy constructor */
ChipHelper(ChipDescript * desc);
/* The default constructor assume a BC7 / UF105x series chip
and that the number given is the value of UNIFI_GBL_CHIP_VERSION
(0xFE81) */
ChipHelper(u16 version);
/* This returns the C interface magic token from a C++ instance. */
ChipDescript* GetDescript() const
{
return m_desc;
}
/* Clear out theis class (set it to the null token). */
void ClearVersion();
/* Load this class with data for a specific chip. */
void GetVersionAny(u16 from_FF9A, u16 from_FE81);
void GetVersionUniFi(u16 version);
void GetVersionBlueCore(chip_helper_bluecore_age age, u16 version);
void GetVersionSdio(u8 sdio_version);
/* Helpers to build the definitions of the member functions. */
#define CHIP_HELPER_DEF0_CPP_DEC(ret_type, name, info) \
ret_type name() const;
#define CHIP_HELPER_DEF1_CPP_DEC(ret_type, name, type1, name1) \
ret_type name(type1 name1) const;
CHIP_HELPER_LIST(CPP_DEC)
/* The DecodeWindow function, see the description of the C version. */
s32 DecodeWindow(chip_helper_window_index window,
chip_helper_window_type type,
u32 offset,
u16 &page, u16 &addr, u32 &
|