brcmfmac: Create common nvram parsing routines.
[deliverable/linux.git] / drivers / net / wireless / brcm80211 / brcmfmac / sdio_chip.c
CommitLineData
a83369b6
FL
1/*
2 * Copyright (c) 2011 Broadcom Corporation
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16/* ***** SDIO interface chip backplane handle functions ***** */
17
18#include <linux/types.h>
19#include <linux/netdevice.h>
20#include <linux/mmc/card.h>
fe040158 21#include <linux/mmc/sdio_func.h>
6e08d757 22#include <linux/mmc/sdio_ids.h>
61213be4 23#include <linux/ssb/ssb_regs.h>
99ba15cd 24#include <linux/bcma/bcma.h>
61213be4 25
a83369b6
FL
26#include <chipcommon.h>
27#include <brcm_hw_ids.h>
28#include <brcmu_wifi.h>
29#include <brcmu_utils.h>
2d4a9af1 30#include <soc.h>
a83369b6
FL
31#include "dhd_dbg.h"
32#include "sdio_host.h"
33#include "sdio_chip.h"
34
35/* chip core base & ramsize */
36/* bcm4329 */
37/* SDIO device core, ID 0x829 */
38#define BCM4329_CORE_BUS_BASE 0x18011000
39/* internal memory core, ID 0x80e */
40#define BCM4329_CORE_SOCRAM_BASE 0x18003000
41/* ARM Cortex M3 core, ID 0x82a */
42#define BCM4329_CORE_ARM_BASE 0x18002000
43#define BCM4329_RAMSIZE 0x48000
44
369508c5
HM
45/* bcm43143 */
46/* SDIO device core */
47#define BCM43143_CORE_BUS_BASE 0x18002000
48/* internal memory core */
49#define BCM43143_CORE_SOCRAM_BASE 0x18004000
50/* ARM Cortex M3 core, ID 0x82a */
51#define BCM43143_CORE_ARM_BASE 0x18003000
52#define BCM43143_RAMSIZE 0x70000
53
a83369b6 54#define SBCOREREV(sbidh) \
61213be4
FL
55 ((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \
56 ((sbidh) & SSB_IDHIGH_RCLO))
a83369b6 57
6ca687d9
FL
58/* SOC Interconnect types (aka chip types) */
59#define SOCI_SB 0
60#define SOCI_AI 1
61
523894f2
FL
62/* EROM CompIdentB */
63#define CIB_REV_MASK 0xff000000
64#define CIB_REV_SHIFT 24
65
1640f28f
FL
66/* ARM CR4 core specific control flag bits */
67#define ARMCR4_BCMA_IOCTL_CPUHALT 0x0020
68
e12afb6c
FL
69#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
70/* SDIO Pad drive strength to select value mappings */
71struct sdiod_drive_str {
72 u8 strength; /* Pad Drive Strength in mA */
73 u8 sel; /* Chip-specific select value */
74};
ce2d7d7e 75/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8V) */
ffb27565 76static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = {
ce2d7d7e
FL
77 {32, 0x6},
78 {26, 0x7},
79 {22, 0x4},
80 {16, 0x5},
81 {12, 0x2},
82 {8, 0x3},
83 {4, 0x0},
84 {0, 0x1}
85};
86
11e69c36
AS
87/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */
88static const struct sdiod_drive_str sdiod_drive_strength_tab5_1v8[] = {
89 {6, 0x7},
90 {5, 0x6},
91 {4, 0x5},
92 {3, 0x4},
93 {2, 0x2},
94 {1, 0x1},
95 {0, 0x0}
96};
97
af35f55f
AS
98/* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */
99static const struct sdiod_drive_str sdiod_drvstr_tab6_1v8[] = {
100 {3, 0x3},
101 {2, 0x2},
102 {1, 0x1},
103 {0, 0x0} };
104
979c2920
HM
105/* SDIO Drive Strength to sel value table for 43143 PMU Rev 17 (3.3V) */
106static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = {
107 {16, 0x7},
108 {12, 0x5},
109 {8, 0x3},
110 {4, 0x1}
111};
112
99ba15cd
FL
113u8
114brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid)
115{
116 u8 idx;
117
118 for (idx = 0; idx < BRCMF_MAX_CORENUM; idx++)
119 if (coreid == ci->c_inf[idx].id)
120 return idx;
121
122 return BRCMF_MAX_CORENUM;
123}
124
454d2a88 125static u32
523894f2
FL
126brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
127 struct chip_info *ci, u16 coreid)
454d2a88
FL
128{
129 u32 regdata;
523894f2
FL
130 u8 idx;
131
132 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
454d2a88 133
a39be27b
AS
134 regdata = brcmf_sdiod_regrl(sdiodev,
135 CORE_SB(ci->c_inf[idx].base, sbidhigh),
136 NULL);
454d2a88
FL
137 return SBCOREREV(regdata);
138}
139
523894f2
FL
140static u32
141brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev,
142 struct chip_info *ci, u16 coreid)
143{
144 u8 idx;
145
146 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
147
148 return (ci->c_inf[idx].cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
149}
150
6ca687d9
FL
151static bool
152brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
153 struct chip_info *ci, u16 coreid)
d8f64a42
FL
154{
155 u32 regdata;
6ca687d9
FL
156 u8 idx;
157
158 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
74347856
FL
159 if (idx == BRCMF_MAX_CORENUM)
160 return false;
d8f64a42 161
a39be27b
AS
162 regdata = brcmf_sdiod_regrl(sdiodev,
163 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
164 NULL);
61213be4
FL
165 regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
166 SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
167 return (SSB_TMSLOW_CLOCK == regdata);
d8f64a42
FL
168}
169
6ca687d9
FL
170static bool
171brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
172 struct chip_info *ci, u16 coreid)
173{
174 u32 regdata;
175 u8 idx;
176 bool ret;
177
178 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
74347856
FL
179 if (idx == BRCMF_MAX_CORENUM)
180 return false;
6ca687d9 181
a39be27b
AS
182 regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
183 NULL);
6ca687d9
FL
184 ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
185
a39be27b
AS
186 regdata = brcmf_sdiod_regrl(sdiodev,
187 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
188 NULL);
6ca687d9
FL
189 ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
190
191 return ret;
192}
193
086a2e0a
FL
194static void
195brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
1640f28f 196 struct chip_info *ci, u16 coreid, u32 core_bits)
2d4a9af1 197{
79ae3957 198 u32 regdata, base;
086a2e0a
FL
199 u8 idx;
200
201 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
79ae3957 202 base = ci->c_inf[idx].base;
2d4a9af1 203
a39be27b 204 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
61213be4 205 if (regdata & SSB_TMSLOW_RESET)
2d4a9af1
FL
206 return;
207
a39be27b 208 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
61213be4 209 if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
2d4a9af1
FL
210 /*
211 * set target reject and spin until busy is clear
212 * (preserve core-specific bits)
213 */
a39be27b
AS
214 regdata = brcmf_sdiod_regrl(sdiodev,
215 CORE_SB(base, sbtmstatelow), NULL);
216 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
217 regdata | SSB_TMSLOW_REJECT, NULL);
2d4a9af1 218
a39be27b
AS
219 regdata = brcmf_sdiod_regrl(sdiodev,
220 CORE_SB(base, sbtmstatelow), NULL);
2d4a9af1 221 udelay(1);
a39be27b
AS
222 SPINWAIT((brcmf_sdiod_regrl(sdiodev,
223 CORE_SB(base, sbtmstatehigh),
224 NULL) &
225 SSB_TMSHIGH_BUSY), 100000);
226
227 regdata = brcmf_sdiod_regrl(sdiodev,
228 CORE_SB(base, sbtmstatehigh),
229 NULL);
61213be4 230 if (regdata & SSB_TMSHIGH_BUSY)
5e8149f5 231 brcmf_err("core state still busy\n");
2d4a9af1 232
a39be27b
AS
233 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow),
234 NULL);
61213be4 235 if (regdata & SSB_IDLOW_INITIATOR) {
a39be27b
AS
236 regdata = brcmf_sdiod_regrl(sdiodev,
237 CORE_SB(base, sbimstate),
238 NULL);
79ae3957 239 regdata |= SSB_IMSTATE_REJECT;
a39be27b
AS
240 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate),
241 regdata, NULL);
242 regdata = brcmf_sdiod_regrl(sdiodev,
243 CORE_SB(base, sbimstate),
244 NULL);
2d4a9af1 245 udelay(1);
a39be27b
AS
246 SPINWAIT((brcmf_sdiod_regrl(sdiodev,
247 CORE_SB(base, sbimstate),
248 NULL) &
249 SSB_IMSTATE_BUSY), 100000);
2d4a9af1
FL
250 }
251
252 /* set reset and reject while enabling the clocks */
e13ce26b
FL
253 regdata = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
254 SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET;
a39be27b
AS
255 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
256 regdata, NULL);
257 regdata = brcmf_sdiod_regrl(sdiodev,
258 CORE_SB(base, sbtmstatelow), NULL);
2d4a9af1
FL
259 udelay(10);
260
261 /* clear the initiator reject bit */
a39be27b
AS
262 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow),
263 NULL);
61213be4 264 if (regdata & SSB_IDLOW_INITIATOR) {
a39be27b
AS
265 regdata = brcmf_sdiod_regrl(sdiodev,
266 CORE_SB(base, sbimstate),
267 NULL);
79ae3957 268 regdata &= ~SSB_IMSTATE_REJECT;
a39be27b
AS
269 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate),
270 regdata, NULL);
2d4a9af1
FL
271 }
272 }
273
274 /* leave reset and reject asserted */
a39be27b
AS
275 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
276 (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET), NULL);
2d4a9af1
FL
277 udelay(1);
278}
279
086a2e0a
FL
280static void
281brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
1640f28f 282 struct chip_info *ci, u16 coreid, u32 core_bits)
086a2e0a
FL
283{
284 u8 idx;
285 u32 regdata;
286
287 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
74347856
FL
288 if (idx == BRCMF_MAX_CORENUM)
289 return;
086a2e0a
FL
290
291 /* if core is already in reset, just return */
a39be27b
AS
292 regdata = brcmf_sdiod_regrl(sdiodev,
293 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
294 NULL);
086a2e0a
FL
295 if ((regdata & BCMA_RESET_CTL_RESET) != 0)
296 return;
297
1640f28f
FL
298 /* ensure no pending backplane operation
299 * 300uc should be sufficient for backplane ops to be finish
300 * extra 10ms is taken into account for firmware load stage
301 * after 10300us carry on disabling the core anyway
302 */
a39be27b 303 SPINWAIT(brcmf_sdiod_regrl(sdiodev,
1640f28f 304 ci->c_inf[idx].wrapbase+BCMA_RESET_ST,
a39be27b
AS
305 NULL), 10300);
306 regdata = brcmf_sdiod_regrl(sdiodev,
307 ci->c_inf[idx].wrapbase+BCMA_RESET_ST,
308 NULL);
1640f28f
FL
309 if (regdata)
310 brcmf_err("disabling core 0x%x with reset status %x\n",
311 coreid, regdata);
086a2e0a 312
a39be27b
AS
313 brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
314 BCMA_RESET_CTL_RESET, NULL);
086a2e0a 315 udelay(1);
1640f28f 316
a39be27b
AS
317 brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
318 core_bits, NULL);
319 regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
320 NULL);
1640f28f
FL
321 usleep_range(10, 20);
322
086a2e0a
FL
323}
324
d77e70ff
FL
325static void
326brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
1640f28f 327 struct chip_info *ci, u16 coreid, u32 core_bits)
2bc78e10
FL
328{
329 u32 regdata;
086a2e0a
FL
330 u8 idx;
331
332 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
74347856
FL
333 if (idx == BRCMF_MAX_CORENUM)
334 return;
2bc78e10
FL
335
336 /*
337 * Must do the disable sequence first to work for
338 * arbitrary current core state.
339 */
1640f28f 340 brcmf_sdio_sb_coredisable(sdiodev, ci, coreid, 0);
2bc78e10
FL
341
342 /*
343 * Now do the initialization sequence.
344 * set reset while enabling the clock and
345 * forcing them on throughout the core
346 */
a39be27b
AS
347 brcmf_sdiod_regwl(sdiodev,
348 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
349 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET,
350 NULL);
351 regdata = brcmf_sdiod_regrl(sdiodev,
352 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
353 NULL);
2bc78e10
FL
354 udelay(1);
355
d77e70ff 356 /* clear any serror */
a39be27b
AS
357 regdata = brcmf_sdiod_regrl(sdiodev,
358 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
359 NULL);
61213be4 360 if (regdata & SSB_TMSHIGH_SERR)
a39be27b
AS
361 brcmf_sdiod_regwl(sdiodev,
362 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
363 0, NULL);
2bc78e10 364
a39be27b
AS
365 regdata = brcmf_sdiod_regrl(sdiodev,
366 CORE_SB(ci->c_inf[idx].base, sbimstate),
367 NULL);
61213be4 368 if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
a39be27b
AS
369 brcmf_sdiod_regwl(sdiodev,
370 CORE_SB(ci->c_inf[idx].base, sbimstate),
371 regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO),
372 NULL);
2bc78e10
FL
373
374 /* clear reset and allow it to propagate throughout the core */
a39be27b
AS
375 brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
376 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK, NULL);
377 regdata = brcmf_sdiod_regrl(sdiodev,
378 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
379 NULL);
2bc78e10
FL
380 udelay(1);
381
382 /* leave clock enabled */
a39be27b
AS
383 brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
384 SSB_TMSLOW_CLOCK, NULL);
385 regdata = brcmf_sdiod_regrl(sdiodev,
386 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
387 NULL);
d77e70ff
FL
388 udelay(1);
389}
390
391static void
392brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
1640f28f 393 struct chip_info *ci, u16 coreid, u32 core_bits)
d77e70ff
FL
394{
395 u8 idx;
396 u32 regdata;
397
398 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
74347856
FL
399 if (idx == BRCMF_MAX_CORENUM)
400 return;
d77e70ff
FL
401
402 /* must disable first to work for arbitrary current core state */
1640f28f 403 brcmf_sdio_ai_coredisable(sdiodev, ci, coreid, core_bits);
d77e70ff
FL
404
405 /* now do initialization sequence */
a39be27b
AS
406 brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
407 core_bits | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
408 regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
409 NULL);
410 brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
411 0, NULL);
412 regdata = brcmf_sdiod_regrl(sdiodev,
413 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
414 NULL);
d77e70ff
FL
415 udelay(1);
416
a39be27b
AS
417 brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
418 core_bits | BCMA_IOCTL_CLK, NULL);
419 regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
420 NULL);
2bc78e10
FL
421 udelay(1);
422}
423
1640f28f
FL
424#ifdef DEBUG
425/* safety check for chipinfo */
426static int brcmf_sdio_chip_cichk(struct chip_info *ci)
427{
428 u8 core_idx;
429
430 /* check RAM core presence for ARM CM3 core */
431 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
432 if (BRCMF_MAX_CORENUM != core_idx) {
433 core_idx = brcmf_sdio_chip_getinfidx(ci,
434 BCMA_CORE_INTERNAL_MEM);
435 if (BRCMF_MAX_CORENUM == core_idx) {
436 brcmf_err("RAM core not provided with ARM CM3 core\n");
437 return -ENODEV;
438 }
439 }
440
441 /* check RAM base for ARM CR4 core */
442 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CR4);
443 if (BRCMF_MAX_CORENUM != core_idx) {
444 if (ci->rambase == 0) {
445 brcmf_err("RAM base not provided with ARM CR4 core\n");
446 return -ENOMEM;
447 }
448 }
449
450 return 0;
451}
452#else /* DEBUG */
453static inline int brcmf_sdio_chip_cichk(struct chip_info *ci)
454{
455 return 0;
456}
457#endif
458
a83369b6 459static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
4744d164 460 struct chip_info *ci)
a83369b6
FL
461{
462 u32 regdata;
1640f28f 463 int ret;
a83369b6 464
069eddd9 465 /* Get CC core rev
a83369b6
FL
466 * Chipid is assume to be at offset 0 from regs arg
467 * For different chiptypes or old sdio hosts w/o chipcommon,
468 * other ways of recognition should be added here.
469 */
99ba15cd 470 ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
4744d164 471 ci->c_inf[0].base = SI_ENUM_BASE;
a39be27b
AS
472 regdata = brcmf_sdiod_regrl(sdiodev,
473 CORE_CC_REG(ci->c_inf[0].base, chipid),
474 NULL);
a83369b6
FL
475 ci->chip = regdata & CID_ID_MASK;
476 ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
fe040158
FL
477 if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 &&
478 ci->chiprev >= 2)
479 ci->chip = BCM4339_CHIP_ID;
6ca687d9 480 ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
a83369b6
FL
481
482 brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
483
484 /* Address of cores for new chips should be added here */
485 switch (ci->chip) {
369508c5
HM
486 case BCM43143_CHIP_ID:
487 ci->c_inf[0].wrapbase = ci->c_inf[0].base + 0x00100000;
488 ci->c_inf[0].cib = 0x2b000000;
489 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
490 ci->c_inf[1].base = BCM43143_CORE_BUS_BASE;
491 ci->c_inf[1].wrapbase = ci->c_inf[1].base + 0x00100000;
492 ci->c_inf[1].cib = 0x18000000;
493 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
494 ci->c_inf[2].base = BCM43143_CORE_SOCRAM_BASE;
495 ci->c_inf[2].wrapbase = ci->c_inf[2].base + 0x00100000;
496 ci->c_inf[2].cib = 0x14000000;
497 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
498 ci->c_inf[3].base = BCM43143_CORE_ARM_BASE;
499 ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000;
500 ci->c_inf[3].cib = 0x07000000;
501 ci->ramsize = BCM43143_RAMSIZE;
502 break;
4a1c02ce
FL
503 case BCM43241_CHIP_ID:
504 ci->c_inf[0].wrapbase = 0x18100000;
505 ci->c_inf[0].cib = 0x2a084411;
506 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
507 ci->c_inf[1].base = 0x18002000;
508 ci->c_inf[1].wrapbase = 0x18102000;
509 ci->c_inf[1].cib = 0x0e004211;
510 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
511 ci->c_inf[2].base = 0x18004000;
512 ci->c_inf[2].wrapbase = 0x18104000;
513 ci->c_inf[2].cib = 0x14080401;
514 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
515 ci->c_inf[3].base = 0x18003000;
516 ci->c_inf[3].wrapbase = 0x18103000;
517 ci->c_inf[3].cib = 0x07004211;
518 ci->ramsize = 0x90000;
519 break;
a83369b6 520 case BCM4329_CHIP_ID:
99ba15cd
FL
521 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
522 ci->c_inf[1].base = BCM4329_CORE_BUS_BASE;
523 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
524 ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE;
525 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
526 ci->c_inf[3].base = BCM4329_CORE_ARM_BASE;
a83369b6
FL
527 ci->ramsize = BCM4329_RAMSIZE;
528 break;
ce2d7d7e
FL
529 case BCM4330_CHIP_ID:
530 ci->c_inf[0].wrapbase = 0x18100000;
531 ci->c_inf[0].cib = 0x27004211;
532 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
533 ci->c_inf[1].base = 0x18002000;
534 ci->c_inf[1].wrapbase = 0x18102000;
535 ci->c_inf[1].cib = 0x07004211;
536 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
537 ci->c_inf[2].base = 0x18004000;
538 ci->c_inf[2].wrapbase = 0x18104000;
539 ci->c_inf[2].cib = 0x0d080401;
540 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
541 ci->c_inf[3].base = 0x18003000;
542 ci->c_inf[3].wrapbase = 0x18103000;
543 ci->c_inf[3].cib = 0x03004211;
544 ci->ramsize = 0x48000;
545 break;
85a4a1c3
FL
546 case BCM4334_CHIP_ID:
547 ci->c_inf[0].wrapbase = 0x18100000;
548 ci->c_inf[0].cib = 0x29004211;
549 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
550 ci->c_inf[1].base = 0x18002000;
551 ci->c_inf[1].wrapbase = 0x18102000;
552 ci->c_inf[1].cib = 0x0d004211;
553 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
554 ci->c_inf[2].base = 0x18004000;
555 ci->c_inf[2].wrapbase = 0x18104000;
556 ci->c_inf[2].cib = 0x13080401;
557 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
558 ci->c_inf[3].base = 0x18003000;
559 ci->c_inf[3].wrapbase = 0x18103000;
560 ci->c_inf[3].cib = 0x07004211;
561 ci->ramsize = 0x80000;
562 break;
6a1c7483
FL
563 case BCM4335_CHIP_ID:
564 ci->c_inf[0].wrapbase = 0x18100000;
565 ci->c_inf[0].cib = 0x2b084411;
566 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
567 ci->c_inf[1].base = 0x18005000;
568 ci->c_inf[1].wrapbase = 0x18105000;
569 ci->c_inf[1].cib = 0x0f004211;
570 ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
571 ci->c_inf[2].base = 0x18002000;
572 ci->c_inf[2].wrapbase = 0x18102000;
573 ci->c_inf[2].cib = 0x01084411;
574 ci->ramsize = 0xc0000;
575 ci->rambase = 0x180000;
576 break;
fe040158
FL
577 case BCM4339_CHIP_ID:
578 ci->c_inf[0].wrapbase = 0x18100000;
579 ci->c_inf[0].cib = 0x2e084411;
580 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
581 ci->c_inf[1].base = 0x18005000;
582 ci->c_inf[1].wrapbase = 0x18105000;
583 ci->c_inf[1].cib = 0x15004211;
584 ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
585 ci->c_inf[2].base = 0x18002000;
586 ci->c_inf[2].wrapbase = 0x18102000;
587 ci->c_inf[2].cib = 0x04084411;
588 ci->ramsize = 0xc0000;
589 ci->rambase = 0x180000;
590 break;
11e69c36
AS
591 case BCM43362_CHIP_ID:
592 ci->c_inf[0].wrapbase = 0x18100000;
593 ci->c_inf[0].cib = 0x27004211;
594 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
595 ci->c_inf[1].base = 0x18002000;
596 ci->c_inf[1].wrapbase = 0x18102000;
597 ci->c_inf[1].cib = 0x0a004211;
598 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
599 ci->c_inf[2].base = 0x18004000;
600 ci->c_inf[2].wrapbase = 0x18104000;
601 ci->c_inf[2].cib = 0x08080401;
602 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
603 ci->c_inf[3].base = 0x18003000;
604 ci->c_inf[3].wrapbase = 0x18103000;
605 ci->c_inf[3].cib = 0x03004211;
606 ci->ramsize = 0x3C000;
607 break;
a83369b6 608 default:
5e8149f5 609 brcmf_err("chipid 0x%x is not supported\n", ci->chip);
a83369b6
FL
610 return -ENODEV;
611 }
612
1640f28f
FL
613 ret = brcmf_sdio_chip_cichk(ci);
614 if (ret)
615 return ret;
616
6ca687d9
FL
617 switch (ci->socitype) {
618 case SOCI_SB:
619 ci->iscoreup = brcmf_sdio_sb_iscoreup;
523894f2 620 ci->corerev = brcmf_sdio_sb_corerev;
086a2e0a 621 ci->coredisable = brcmf_sdio_sb_coredisable;
d77e70ff 622 ci->resetcore = brcmf_sdio_sb_resetcore;
6ca687d9
FL
623 break;
624 case SOCI_AI:
625 ci->iscoreup = brcmf_sdio_ai_iscoreup;
523894f2 626 ci->corerev = brcmf_sdio_ai_corerev;
086a2e0a 627 ci->coredisable = brcmf_sdio_ai_coredisable;
d77e70ff 628 ci->resetcore = brcmf_sdio_ai_resetcore;
6ca687d9
FL
629 break;
630 default:
5e8149f5 631 brcmf_err("socitype %u not supported\n", ci->socitype);
6ca687d9
FL
632 return -ENODEV;
633 }
634
a83369b6
FL
635 return 0;
636}
637
e63ac6b8
FL
638static int
639brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
640{
641 int err = 0;
642 u8 clkval, clkset;
643
644 /* Try forcing SDIO core to do ALPAvail request only */
645 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
a39be27b 646 brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
e63ac6b8 647 if (err) {
5e8149f5 648 brcmf_err("error writing for HT off\n");
e63ac6b8
FL
649 return err;
650 }
651
652 /* If register supported, wait for ALPAvail and then force ALP */
653 /* This may take up to 15 milliseconds */
a39be27b
AS
654 clkval = brcmf_sdiod_regrb(sdiodev,
655 SBSDIO_FUNC1_CHIPCLKCSR, NULL);
e63ac6b8
FL
656
657 if ((clkval & ~SBSDIO_AVBITS) != clkset) {
5e8149f5 658 brcmf_err("ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
e63ac6b8
FL
659 clkset, clkval);
660 return -EACCES;
661 }
662
a39be27b
AS
663 SPINWAIT(((clkval = brcmf_sdiod_regrb(sdiodev,
664 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
e63ac6b8
FL
665 !SBSDIO_ALPAV(clkval)),
666 PMU_MAX_TRANSITION_DLY);
667 if (!SBSDIO_ALPAV(clkval)) {
5e8149f5 668 brcmf_err("timeout on ALPAV wait, clkval 0x%02x\n",
e63ac6b8
FL
669 clkval);
670 return -EBUSY;
671 }
672
673 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
a39be27b 674 brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
e63ac6b8
FL
675 udelay(65);
676
677 /* Also, disable the extra SDIO pull-ups */
a39be27b 678 brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
e63ac6b8
FL
679
680 return 0;
681}
682
5b45e54e
FL
683static void
684brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
685 struct chip_info *ci)
686{
79ae3957
FL
687 u32 base = ci->c_inf[0].base;
688
5b45e54e 689 /* get chipcommon rev */
523894f2 690 ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
5b45e54e
FL
691
692 /* get chipcommon capabilites */
a39be27b
AS
693 ci->c_inf[0].caps = brcmf_sdiod_regrl(sdiodev,
694 CORE_CC_REG(base, capabilities),
695 NULL);
5b45e54e
FL
696
697 /* get pmu caps & rev */
99ba15cd 698 if (ci->c_inf[0].caps & CC_CAP_PMU) {
79ae3957 699 ci->pmucaps =
a39be27b
AS
700 brcmf_sdiod_regrl(sdiodev,
701 CORE_CC_REG(base, pmucapabilities),
702 NULL);
5b45e54e
FL
703 ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
704 }
705
523894f2 706 ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id);
5b45e54e
FL
707
708 brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
99ba15cd
FL
709 ci->c_inf[0].rev, ci->pmurev,
710 ci->c_inf[1].rev, ci->c_inf[1].id);
966414da
FL
711
712 /*
713 * Make sure any on-chip ARM is off (in case strapping is wrong),
714 * or downloaded code was already running.
715 */
1640f28f 716 ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
5b45e54e
FL
717}
718
a83369b6 719int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
4744d164 720 struct chip_info **ci_ptr)
a83369b6 721{
a97e4fc5
FL
722 int ret;
723 struct chip_info *ci;
724
725 brcmf_dbg(TRACE, "Enter\n");
726
727 /* alloc chip_info_t */
728 ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
729 if (!ci)
730 return -ENOMEM;
a83369b6 731
e63ac6b8
FL
732 ret = brcmf_sdio_chip_buscoreprep(sdiodev);
733 if (ret != 0)
a97e4fc5 734 goto err;
e63ac6b8 735
4744d164 736 ret = brcmf_sdio_chip_recognition(sdiodev, ci);
a83369b6 737 if (ret != 0)
a97e4fc5 738 goto err;
a83369b6 739
5b45e54e
FL
740 brcmf_sdio_chip_buscoresetup(sdiodev, ci);
741
a39be27b
AS
742 brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopullup),
743 0, NULL);
744 brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopulldown),
745 0, NULL);
960908dc 746
a97e4fc5
FL
747 *ci_ptr = ci;
748 return 0;
749
750err:
751 kfree(ci);
a83369b6
FL
752 return ret;
753}
a8a6c045
FL
754
755void
756brcmf_sdio_chip_detach(struct chip_info **ci_ptr)
757{
758 brcmf_dbg(TRACE, "Enter\n");
759
760 kfree(*ci_ptr);
761 *ci_ptr = NULL;
762}
e12afb6c
FL
763
764static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len)
765{
766 const char *fmt;
767
768 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
769 snprintf(buf, len, fmt, chipid);
770 return buf;
771}
772
773void
774brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
775 struct chip_info *ci, u32 drivestrength)
776{
979c2920
HM
777 const struct sdiod_drive_str *str_tab = NULL;
778 u32 str_mask;
779 u32 str_shift;
e12afb6c 780 char chn[8];
79ae3957 781 u32 base = ci->c_inf[0].base;
979c2920
HM
782 u32 i;
783 u32 drivestrength_sel = 0;
784 u32 cc_data_temp;
785 u32 addr;
e12afb6c 786
99ba15cd 787 if (!(ci->c_inf[0].caps & CC_CAP_PMU))
e12afb6c
FL
788 return;
789
790 switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
ce2d7d7e 791 case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12):
979c2920 792 str_tab = sdiod_drvstr_tab1_1v8;
ce2d7d7e
FL
793 str_mask = 0x00003800;
794 str_shift = 11;
795 break;
af35f55f
AS
796 case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17):
797 str_tab = sdiod_drvstr_tab6_1v8;
798 str_mask = 0x00001800;
799 str_shift = 11;
800 break;
979c2920
HM
801 case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17):
802 /* note: 43143 does not support tristate */
803 i = ARRAY_SIZE(sdiod_drvstr_tab2_3v3) - 1;
804 if (drivestrength >= sdiod_drvstr_tab2_3v3[i].strength) {
805 str_tab = sdiod_drvstr_tab2_3v3;
806 str_mask = 0x00000007;
807 str_shift = 0;
808 } else
809 brcmf_err("Invalid SDIO Drive strength for chip %s, strength=%d\n",
810 brcmf_sdio_chip_name(ci->chip, chn, 8),
811 drivestrength);
812 break;
11e69c36
AS
813 case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13):
814 str_tab = sdiod_drive_strength_tab5_1v8;
815 str_mask = 0x00003800;
816 str_shift = 11;
817 break;
e12afb6c 818 default:
5e8149f5 819 brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
e12afb6c
FL
820 brcmf_sdio_chip_name(ci->chip, chn, 8),
821 ci->chiprev, ci->pmurev);
822 break;
823 }
824
825 if (str_tab != NULL) {
e12afb6c
FL
826 for (i = 0; str_tab[i].strength != 0; i++) {
827 if (drivestrength >= str_tab[i].strength) {
828 drivestrength_sel = str_tab[i].sel;
829 break;
830 }
831 }
979c2920 832 addr = CORE_CC_REG(base, chipcontrol_addr);
a39be27b
AS
833 brcmf_sdiod_regwl(sdiodev, addr, 1, NULL);
834 cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL);
e12afb6c
FL
835 cc_data_temp &= ~str_mask;
836 drivestrength_sel <<= str_shift;
837 cc_data_temp |= drivestrength_sel;
a39be27b 838 brcmf_sdiod_regwl(sdiodev, addr, cc_data_temp, NULL);
e12afb6c 839
979c2920
HM
840 brcmf_dbg(INFO, "SDIO: %d mA (req=%d mA) drive strength selected, set to 0x%08x\n",
841 str_tab[i].strength, drivestrength, cc_data_temp);
e12afb6c
FL
842 }
843}
069eddd9 844
069eddd9
FL
845static void
846brcmf_sdio_chip_cm3_enterdl(struct brcmf_sdio_dev *sdiodev,
847 struct chip_info *ci)
848{
1640f28f
FL
849 ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
850 ci->resetcore(sdiodev, ci, BCMA_CORE_INTERNAL_MEM, 0);
069eddd9
FL
851}
852
853static bool
a74d036f 854brcmf_sdio_chip_cm3_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci)
069eddd9
FL
855{
856 u8 core_idx;
857 u32 reg_addr;
858
859 if (!ci->iscoreup(sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) {
860 brcmf_err("SOCRAM core is down after reset?\n");
861 return false;
862 }
863
069eddd9
FL
864 /* clear all interrupts */
865 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
866 reg_addr = ci->c_inf[core_idx].base;
867 reg_addr += offsetof(struct sdpcmd_regs, intstatus);
a39be27b 868 brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
069eddd9 869
1640f28f
FL
870 ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
871
872 return true;
873}
874
875static inline void
876brcmf_sdio_chip_cr4_enterdl(struct brcmf_sdio_dev *sdiodev,
877 struct chip_info *ci)
878{
879 ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4,
880 ARMCR4_BCMA_IOCTL_CPUHALT);
881}
882
883static bool
a74d036f 884brcmf_sdio_chip_cr4_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci)
1640f28f
FL
885{
886 u8 core_idx;
887 u32 reg_addr;
888
1640f28f
FL
889 /* clear all interrupts */
890 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
891 reg_addr = ci->c_inf[core_idx].base;
892 reg_addr += offsetof(struct sdpcmd_regs, intstatus);
a39be27b 893 brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
1640f28f
FL
894
895 /* Write reset vector to address 0 */
a39be27b
AS
896 brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&ci->rst_vec,
897 sizeof(ci->rst_vec));
1640f28f
FL
898
899 /* restore ARM */
900 ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, 0);
069eddd9
FL
901
902 return true;
903}
904
905void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev,
906 struct chip_info *ci)
907{
1640f28f
FL
908 u8 arm_core_idx;
909
910 arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
911 if (BRCMF_MAX_CORENUM != arm_core_idx) {
912 brcmf_sdio_chip_cm3_enterdl(sdiodev, ci);
913 return;
914 }
915
916 brcmf_sdio_chip_cr4_enterdl(sdiodev, ci);
069eddd9
FL
917}
918
919bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev,
a74d036f 920 struct chip_info *ci)
069eddd9 921{
1640f28f
FL
922 u8 arm_core_idx;
923
924 arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
925 if (BRCMF_MAX_CORENUM != arm_core_idx)
a74d036f 926 return brcmf_sdio_chip_cm3_exitdl(sdiodev, ci);
1640f28f 927
a74d036f 928 return brcmf_sdio_chip_cr4_exitdl(sdiodev, ci);
069eddd9 929}
This page took 0.270056 seconds and 5 git commands to generate.