Commit | Line | Data |
---|---|---|
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 */ | |
71 | struct 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 | 76 | static 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) */ |
88 | static 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) */ |
99 | static 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) */ |
106 | static 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 |
113 | u8 |
114 | brcmf_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 | 125 | static u32 |
523894f2 FL |
126 | brcmf_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 |
140 | static u32 |
141 | brcmf_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 |
151 | static bool |
152 | brcmf_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 |
170 | static bool |
171 | brcmf_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 |
194 | static void |
195 | brcmf_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 |
280 | static void |
281 | brcmf_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 |
325 | static void |
326 | brcmf_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 | ||
391 | static void | |
392 | brcmf_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 */ | |
426 | static 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 */ | |
453 | static inline int brcmf_sdio_chip_cichk(struct chip_info *ci) | |
454 | { | |
455 | return 0; | |
456 | } | |
457 | #endif | |
458 | ||
a83369b6 | 459 | static 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 |
638 | static int |
639 | brcmf_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 |
683 | static void |
684 | brcmf_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 | 719 | int 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 | ||
750 | err: | |
751 | kfree(ci); | |
a83369b6 FL |
752 | return ret; |
753 | } | |
a8a6c045 FL |
754 | |
755 | void | |
756 | brcmf_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 | |
764 | static 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 | ||
773 | void | |
774 | brcmf_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 |
845 | static void |
846 | brcmf_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 | ||
853 | static bool | |
a74d036f | 854 | brcmf_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 | ||
875 | static inline void | |
876 | brcmf_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 | ||
883 | static bool | |
a74d036f | 884 | brcmf_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 | ||
905 | void 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 | ||
919 | bool 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 | } |