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> | |
61213be4 | 21 | #include <linux/ssb/ssb_regs.h> |
99ba15cd | 22 | #include <linux/bcma/bcma.h> |
61213be4 | 23 | |
a83369b6 FL |
24 | #include <chipcommon.h> |
25 | #include <brcm_hw_ids.h> | |
26 | #include <brcmu_wifi.h> | |
27 | #include <brcmu_utils.h> | |
2d4a9af1 | 28 | #include <soc.h> |
a83369b6 FL |
29 | #include "dhd.h" |
30 | #include "dhd_dbg.h" | |
31 | #include "sdio_host.h" | |
32 | #include "sdio_chip.h" | |
33 | ||
34 | /* chip core base & ramsize */ | |
35 | /* bcm4329 */ | |
36 | /* SDIO device core, ID 0x829 */ | |
37 | #define BCM4329_CORE_BUS_BASE 0x18011000 | |
38 | /* internal memory core, ID 0x80e */ | |
39 | #define BCM4329_CORE_SOCRAM_BASE 0x18003000 | |
40 | /* ARM Cortex M3 core, ID 0x82a */ | |
41 | #define BCM4329_CORE_ARM_BASE 0x18002000 | |
42 | #define BCM4329_RAMSIZE 0x48000 | |
43 | ||
a83369b6 | 44 | #define SBCOREREV(sbidh) \ |
61213be4 FL |
45 | ((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \ |
46 | ((sbidh) & SSB_IDHIGH_RCLO)) | |
a83369b6 | 47 | |
e12afb6c FL |
48 | #define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) |
49 | /* SDIO Pad drive strength to select value mappings */ | |
50 | struct sdiod_drive_str { | |
51 | u8 strength; /* Pad Drive Strength in mA */ | |
52 | u8 sel; /* Chip-specific select value */ | |
53 | }; | |
54 | /* SDIO Drive Strength to sel value table for PMU Rev 1 */ | |
55 | static const struct sdiod_drive_str sdiod_drive_strength_tab1[] = { | |
56 | { | |
57 | 4, 0x2}, { | |
58 | 2, 0x3}, { | |
59 | 1, 0x0}, { | |
60 | 0, 0x0} | |
61 | }; | |
62 | /* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */ | |
63 | static const struct sdiod_drive_str sdiod_drive_strength_tab2[] = { | |
64 | { | |
65 | 12, 0x7}, { | |
66 | 10, 0x6}, { | |
67 | 8, 0x5}, { | |
68 | 6, 0x4}, { | |
69 | 4, 0x2}, { | |
70 | 2, 0x1}, { | |
71 | 0, 0x0} | |
72 | }; | |
73 | /* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */ | |
74 | static const struct sdiod_drive_str sdiod_drive_strength_tab3[] = { | |
75 | { | |
76 | 32, 0x7}, { | |
77 | 26, 0x6}, { | |
78 | 22, 0x5}, { | |
79 | 16, 0x4}, { | |
80 | 12, 0x3}, { | |
81 | 8, 0x2}, { | |
82 | 4, 0x1}, { | |
83 | 0, 0x0} | |
84 | }; | |
85 | ||
99ba15cd FL |
86 | u8 |
87 | brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid) | |
88 | { | |
89 | u8 idx; | |
90 | ||
91 | for (idx = 0; idx < BRCMF_MAX_CORENUM; idx++) | |
92 | if (coreid == ci->c_inf[idx].id) | |
93 | return idx; | |
94 | ||
95 | return BRCMF_MAX_CORENUM; | |
96 | } | |
97 | ||
454d2a88 FL |
98 | static u32 |
99 | brcmf_sdio_chip_corerev(struct brcmf_sdio_dev *sdiodev, | |
100 | u32 corebase) | |
101 | { | |
102 | u32 regdata; | |
103 | ||
104 | regdata = brcmf_sdcard_reg_read(sdiodev, | |
105 | CORE_SB(corebase, sbidhigh), 4); | |
106 | return SBCOREREV(regdata); | |
107 | } | |
108 | ||
d8f64a42 FL |
109 | bool |
110 | brcmf_sdio_chip_iscoreup(struct brcmf_sdio_dev *sdiodev, | |
111 | u32 corebase) | |
112 | { | |
113 | u32 regdata; | |
114 | ||
115 | regdata = brcmf_sdcard_reg_read(sdiodev, | |
116 | CORE_SB(corebase, sbtmstatelow), 4); | |
61213be4 FL |
117 | regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT | |
118 | SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK); | |
119 | return (SSB_TMSLOW_CLOCK == regdata); | |
d8f64a42 FL |
120 | } |
121 | ||
2d4a9af1 FL |
122 | void |
123 | brcmf_sdio_chip_coredisable(struct brcmf_sdio_dev *sdiodev, u32 corebase) | |
124 | { | |
125 | u32 regdata; | |
126 | ||
127 | regdata = brcmf_sdcard_reg_read(sdiodev, | |
128 | CORE_SB(corebase, sbtmstatelow), 4); | |
61213be4 | 129 | if (regdata & SSB_TMSLOW_RESET) |
2d4a9af1 FL |
130 | return; |
131 | ||
132 | regdata = brcmf_sdcard_reg_read(sdiodev, | |
133 | CORE_SB(corebase, sbtmstatelow), 4); | |
61213be4 | 134 | if ((regdata & SSB_TMSLOW_CLOCK) != 0) { |
2d4a9af1 FL |
135 | /* |
136 | * set target reject and spin until busy is clear | |
137 | * (preserve core-specific bits) | |
138 | */ | |
139 | regdata = brcmf_sdcard_reg_read(sdiodev, | |
140 | CORE_SB(corebase, sbtmstatelow), 4); | |
141 | brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), | |
61213be4 | 142 | 4, regdata | SSB_TMSLOW_REJECT); |
2d4a9af1 FL |
143 | |
144 | regdata = brcmf_sdcard_reg_read(sdiodev, | |
145 | CORE_SB(corebase, sbtmstatelow), 4); | |
146 | udelay(1); | |
147 | SPINWAIT((brcmf_sdcard_reg_read(sdiodev, | |
148 | CORE_SB(corebase, sbtmstatehigh), 4) & | |
61213be4 | 149 | SSB_TMSHIGH_BUSY), 100000); |
2d4a9af1 FL |
150 | |
151 | regdata = brcmf_sdcard_reg_read(sdiodev, | |
152 | CORE_SB(corebase, sbtmstatehigh), 4); | |
61213be4 | 153 | if (regdata & SSB_TMSHIGH_BUSY) |
2d4a9af1 FL |
154 | brcmf_dbg(ERROR, "core state still busy\n"); |
155 | ||
156 | regdata = brcmf_sdcard_reg_read(sdiodev, | |
157 | CORE_SB(corebase, sbidlow), 4); | |
61213be4 | 158 | if (regdata & SSB_IDLOW_INITIATOR) { |
2d4a9af1 FL |
159 | regdata = brcmf_sdcard_reg_read(sdiodev, |
160 | CORE_SB(corebase, sbimstate), 4) | | |
61213be4 | 161 | SSB_IMSTATE_REJECT; |
2d4a9af1 FL |
162 | brcmf_sdcard_reg_write(sdiodev, |
163 | CORE_SB(corebase, sbimstate), 4, | |
164 | regdata); | |
165 | regdata = brcmf_sdcard_reg_read(sdiodev, | |
166 | CORE_SB(corebase, sbimstate), 4); | |
167 | udelay(1); | |
168 | SPINWAIT((brcmf_sdcard_reg_read(sdiodev, | |
169 | CORE_SB(corebase, sbimstate), 4) & | |
61213be4 | 170 | SSB_IMSTATE_BUSY), 100000); |
2d4a9af1 FL |
171 | } |
172 | ||
173 | /* set reset and reject while enabling the clocks */ | |
174 | brcmf_sdcard_reg_write(sdiodev, | |
175 | CORE_SB(corebase, sbtmstatelow), 4, | |
61213be4 FL |
176 | (SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | |
177 | SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET)); | |
2d4a9af1 FL |
178 | regdata = brcmf_sdcard_reg_read(sdiodev, |
179 | CORE_SB(corebase, sbtmstatelow), 4); | |
180 | udelay(10); | |
181 | ||
182 | /* clear the initiator reject bit */ | |
183 | regdata = brcmf_sdcard_reg_read(sdiodev, | |
184 | CORE_SB(corebase, sbidlow), 4); | |
61213be4 | 185 | if (regdata & SSB_IDLOW_INITIATOR) { |
2d4a9af1 FL |
186 | regdata = brcmf_sdcard_reg_read(sdiodev, |
187 | CORE_SB(corebase, sbimstate), 4) & | |
61213be4 | 188 | ~SSB_IMSTATE_REJECT; |
2d4a9af1 FL |
189 | brcmf_sdcard_reg_write(sdiodev, |
190 | CORE_SB(corebase, sbimstate), 4, | |
191 | regdata); | |
192 | } | |
193 | } | |
194 | ||
195 | /* leave reset and reject asserted */ | |
196 | brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4, | |
61213be4 | 197 | (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET)); |
2d4a9af1 FL |
198 | udelay(1); |
199 | } | |
200 | ||
2bc78e10 FL |
201 | void |
202 | brcmf_sdio_chip_resetcore(struct brcmf_sdio_dev *sdiodev, u32 corebase) | |
203 | { | |
204 | u32 regdata; | |
205 | ||
206 | /* | |
207 | * Must do the disable sequence first to work for | |
208 | * arbitrary current core state. | |
209 | */ | |
210 | brcmf_sdio_chip_coredisable(sdiodev, corebase); | |
211 | ||
212 | /* | |
213 | * Now do the initialization sequence. | |
214 | * set reset while enabling the clock and | |
215 | * forcing them on throughout the core | |
216 | */ | |
217 | brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4, | |
61213be4 | 218 | SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET); |
2bc78e10 FL |
219 | udelay(1); |
220 | ||
221 | regdata = brcmf_sdcard_reg_read(sdiodev, | |
222 | CORE_SB(corebase, sbtmstatehigh), 4); | |
61213be4 | 223 | if (regdata & SSB_TMSHIGH_SERR) |
2bc78e10 FL |
224 | brcmf_sdcard_reg_write(sdiodev, |
225 | CORE_SB(corebase, sbtmstatehigh), 4, 0); | |
226 | ||
227 | regdata = brcmf_sdcard_reg_read(sdiodev, | |
228 | CORE_SB(corebase, sbimstate), 4); | |
61213be4 | 229 | if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO)) |
2bc78e10 | 230 | brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbimstate), 4, |
61213be4 | 231 | regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO)); |
2bc78e10 FL |
232 | |
233 | /* clear reset and allow it to propagate throughout the core */ | |
234 | brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4, | |
61213be4 | 235 | SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK); |
2bc78e10 FL |
236 | udelay(1); |
237 | ||
238 | /* leave clock enabled */ | |
61213be4 FL |
239 | brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), |
240 | 4, SSB_TMSLOW_CLOCK); | |
2bc78e10 FL |
241 | udelay(1); |
242 | } | |
243 | ||
a83369b6 FL |
244 | static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev, |
245 | struct chip_info *ci, u32 regs) | |
246 | { | |
247 | u32 regdata; | |
248 | ||
249 | /* | |
250 | * Get CC core rev | |
251 | * Chipid is assume to be at offset 0 from regs arg | |
252 | * For different chiptypes or old sdio hosts w/o chipcommon, | |
253 | * other ways of recognition should be added here. | |
254 | */ | |
99ba15cd FL |
255 | ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON; |
256 | ci->c_inf[0].base = regs; | |
a83369b6 | 257 | regdata = brcmf_sdcard_reg_read(sdiodev, |
99ba15cd | 258 | CORE_CC_REG(ci->c_inf[0].base, chipid), 4); |
a83369b6 FL |
259 | ci->chip = regdata & CID_ID_MASK; |
260 | ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT; | |
261 | ||
262 | brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev); | |
263 | ||
264 | /* Address of cores for new chips should be added here */ | |
265 | switch (ci->chip) { | |
266 | case BCM4329_CHIP_ID: | |
99ba15cd FL |
267 | ci->c_inf[1].id = BCMA_CORE_SDIO_DEV; |
268 | ci->c_inf[1].base = BCM4329_CORE_BUS_BASE; | |
269 | ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM; | |
270 | ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE; | |
271 | ci->c_inf[3].id = BCMA_CORE_ARM_CM3; | |
272 | ci->c_inf[3].base = BCM4329_CORE_ARM_BASE; | |
a83369b6 FL |
273 | ci->ramsize = BCM4329_RAMSIZE; |
274 | break; | |
275 | default: | |
276 | brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip); | |
277 | return -ENODEV; | |
278 | } | |
279 | ||
a83369b6 FL |
280 | return 0; |
281 | } | |
282 | ||
e63ac6b8 FL |
283 | static int |
284 | brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev) | |
285 | { | |
286 | int err = 0; | |
287 | u8 clkval, clkset; | |
288 | ||
289 | /* Try forcing SDIO core to do ALPAvail request only */ | |
290 | clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; | |
291 | brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, | |
292 | SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); | |
293 | if (err) { | |
294 | brcmf_dbg(ERROR, "error writing for HT off\n"); | |
295 | return err; | |
296 | } | |
297 | ||
298 | /* If register supported, wait for ALPAvail and then force ALP */ | |
299 | /* This may take up to 15 milliseconds */ | |
300 | clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1, | |
301 | SBSDIO_FUNC1_CHIPCLKCSR, NULL); | |
302 | ||
303 | if ((clkval & ~SBSDIO_AVBITS) != clkset) { | |
304 | brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n", | |
305 | clkset, clkval); | |
306 | return -EACCES; | |
307 | } | |
308 | ||
309 | SPINWAIT(((clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1, | |
310 | SBSDIO_FUNC1_CHIPCLKCSR, NULL)), | |
311 | !SBSDIO_ALPAV(clkval)), | |
312 | PMU_MAX_TRANSITION_DLY); | |
313 | if (!SBSDIO_ALPAV(clkval)) { | |
314 | brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n", | |
315 | clkval); | |
316 | return -EBUSY; | |
317 | } | |
318 | ||
319 | clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP; | |
320 | brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, | |
321 | SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); | |
322 | udelay(65); | |
323 | ||
324 | /* Also, disable the extra SDIO pull-ups */ | |
325 | brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, | |
326 | SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); | |
327 | ||
328 | return 0; | |
329 | } | |
330 | ||
5b45e54e FL |
331 | static void |
332 | brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev, | |
333 | struct chip_info *ci) | |
334 | { | |
335 | u32 regdata; | |
99ba15cd | 336 | u8 idx; |
5b45e54e FL |
337 | |
338 | /* get chipcommon rev */ | |
99ba15cd FL |
339 | ci->c_inf[0].rev = |
340 | brcmf_sdio_chip_corerev(sdiodev, ci->c_inf[0].base); | |
5b45e54e FL |
341 | |
342 | /* get chipcommon capabilites */ | |
99ba15cd FL |
343 | ci->c_inf[0].caps = |
344 | brcmf_sdcard_reg_read(sdiodev, | |
345 | CORE_CC_REG(ci->c_inf[0].base, capabilities), 4); | |
5b45e54e FL |
346 | |
347 | /* get pmu caps & rev */ | |
99ba15cd | 348 | if (ci->c_inf[0].caps & CC_CAP_PMU) { |
5b45e54e | 349 | ci->pmucaps = brcmf_sdcard_reg_read(sdiodev, |
99ba15cd | 350 | CORE_CC_REG(ci->c_inf[0].base, pmucapabilities), 4); |
5b45e54e FL |
351 | ci->pmurev = ci->pmucaps & PCAP_REV_MASK; |
352 | } | |
353 | ||
99ba15cd | 354 | ci->c_inf[1].rev = brcmf_sdio_chip_corerev(sdiodev, ci->c_inf[1].base); |
5b45e54e | 355 | regdata = brcmf_sdcard_reg_read(sdiodev, |
99ba15cd FL |
356 | CORE_SB(ci->c_inf[1].base, sbidhigh), 4); |
357 | ci->c_inf[1].id = (regdata & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT; | |
5b45e54e FL |
358 | |
359 | brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n", | |
99ba15cd FL |
360 | ci->c_inf[0].rev, ci->pmurev, |
361 | ci->c_inf[1].rev, ci->c_inf[1].id); | |
966414da FL |
362 | |
363 | /* | |
364 | * Make sure any on-chip ARM is off (in case strapping is wrong), | |
365 | * or downloaded code was already running. | |
366 | */ | |
99ba15cd FL |
367 | idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3); |
368 | brcmf_sdio_chip_coredisable(sdiodev, ci->c_inf[idx].base); | |
5b45e54e FL |
369 | } |
370 | ||
a83369b6 | 371 | int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev, |
a97e4fc5 | 372 | struct chip_info **ci_ptr, u32 regs) |
a83369b6 | 373 | { |
a97e4fc5 FL |
374 | int ret; |
375 | struct chip_info *ci; | |
376 | ||
377 | brcmf_dbg(TRACE, "Enter\n"); | |
378 | ||
379 | /* alloc chip_info_t */ | |
380 | ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC); | |
381 | if (!ci) | |
382 | return -ENOMEM; | |
a83369b6 | 383 | |
e63ac6b8 FL |
384 | ret = brcmf_sdio_chip_buscoreprep(sdiodev); |
385 | if (ret != 0) | |
a97e4fc5 | 386 | goto err; |
e63ac6b8 | 387 | |
a83369b6 FL |
388 | ret = brcmf_sdio_chip_recognition(sdiodev, ci, regs); |
389 | if (ret != 0) | |
a97e4fc5 | 390 | goto err; |
a83369b6 | 391 | |
5b45e54e FL |
392 | brcmf_sdio_chip_buscoresetup(sdiodev, ci); |
393 | ||
960908dc | 394 | brcmf_sdcard_reg_write(sdiodev, |
99ba15cd | 395 | CORE_CC_REG(ci->c_inf[0].base, gpiopullup), 4, 0); |
960908dc | 396 | brcmf_sdcard_reg_write(sdiodev, |
99ba15cd | 397 | CORE_CC_REG(ci->c_inf[0].base, gpiopulldown), 4, 0); |
960908dc | 398 | |
a97e4fc5 FL |
399 | *ci_ptr = ci; |
400 | return 0; | |
401 | ||
402 | err: | |
403 | kfree(ci); | |
a83369b6 FL |
404 | return ret; |
405 | } | |
a8a6c045 FL |
406 | |
407 | void | |
408 | brcmf_sdio_chip_detach(struct chip_info **ci_ptr) | |
409 | { | |
410 | brcmf_dbg(TRACE, "Enter\n"); | |
411 | ||
412 | kfree(*ci_ptr); | |
413 | *ci_ptr = NULL; | |
414 | } | |
e12afb6c FL |
415 | |
416 | static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len) | |
417 | { | |
418 | const char *fmt; | |
419 | ||
420 | fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; | |
421 | snprintf(buf, len, fmt, chipid); | |
422 | return buf; | |
423 | } | |
424 | ||
425 | void | |
426 | brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev, | |
427 | struct chip_info *ci, u32 drivestrength) | |
428 | { | |
429 | struct sdiod_drive_str *str_tab = NULL; | |
430 | u32 str_mask = 0; | |
431 | u32 str_shift = 0; | |
432 | char chn[8]; | |
433 | ||
99ba15cd | 434 | if (!(ci->c_inf[0].caps & CC_CAP_PMU)) |
e12afb6c FL |
435 | return; |
436 | ||
437 | switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) { | |
438 | case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1): | |
439 | str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab1; | |
440 | str_mask = 0x30000000; | |
441 | str_shift = 28; | |
442 | break; | |
443 | case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2): | |
444 | case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3): | |
445 | str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab2; | |
446 | str_mask = 0x00003800; | |
447 | str_shift = 11; | |
448 | break; | |
449 | case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): | |
450 | str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab3; | |
451 | str_mask = 0x00003800; | |
452 | str_shift = 11; | |
453 | break; | |
454 | default: | |
455 | brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", | |
456 | brcmf_sdio_chip_name(ci->chip, chn, 8), | |
457 | ci->chiprev, ci->pmurev); | |
458 | break; | |
459 | } | |
460 | ||
461 | if (str_tab != NULL) { | |
462 | u32 drivestrength_sel = 0; | |
463 | u32 cc_data_temp; | |
464 | int i; | |
465 | ||
466 | for (i = 0; str_tab[i].strength != 0; i++) { | |
467 | if (drivestrength >= str_tab[i].strength) { | |
468 | drivestrength_sel = str_tab[i].sel; | |
469 | break; | |
470 | } | |
471 | } | |
472 | ||
473 | brcmf_sdcard_reg_write(sdiodev, | |
99ba15cd | 474 | CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr), |
e12afb6c FL |
475 | 4, 1); |
476 | cc_data_temp = brcmf_sdcard_reg_read(sdiodev, | |
99ba15cd | 477 | CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr), 4); |
e12afb6c FL |
478 | cc_data_temp &= ~str_mask; |
479 | drivestrength_sel <<= str_shift; | |
480 | cc_data_temp |= drivestrength_sel; | |
481 | brcmf_sdcard_reg_write(sdiodev, | |
99ba15cd | 482 | CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr), |
e12afb6c FL |
483 | 4, cc_data_temp); |
484 | ||
485 | brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n", | |
486 | drivestrength, cc_data_temp); | |
487 | } | |
488 | } |