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