blob: d299059a2815e9eb92d5406543b1aeb19d725df0 [file] [log] [blame]
Franky Lina83369b2011-11-04 22:23:28 +01001/*
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>
Franky Lin61213be2011-11-04 22:23:41 +010021#include <linux/ssb/ssb_regs.h>
Franky Lin99ba15c2011-11-04 22:23:42 +010022#include <linux/bcma/bcma.h>
Franky Lin61213be2011-11-04 22:23:41 +010023
Franky Lina83369b2011-11-04 22:23:28 +010024#include <chipcommon.h>
25#include <brcm_hw_ids.h>
26#include <brcmu_wifi.h>
27#include <brcmu_utils.h>
Franky Lin2d4a9af2011-11-04 22:23:31 +010028#include <soc.h>
Franky Lina83369b2011-11-04 22:23:28 +010029#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
Franky Lina83369b2011-11-04 22:23:28 +010044#define SBCOREREV(sbidh) \
Franky Lin61213be2011-11-04 22:23:41 +010045 ((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \
46 ((sbidh) & SSB_IDHIGH_RCLO))
Franky Lina83369b2011-11-04 22:23:28 +010047
Franky Lin6ca687d2011-11-10 20:30:21 +010048/* SOC Interconnect types (aka chip types) */
49#define SOCI_SB 0
50#define SOCI_AI 1
51
Franky Lin523894f2011-11-10 20:30:22 +010052/* EROM CompIdentB */
53#define CIB_REV_MASK 0xff000000
54#define CIB_REV_SHIFT 24
55
Franky Line12afb62011-11-04 22:23:40 +010056#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
57/* SDIO Pad drive strength to select value mappings */
58struct sdiod_drive_str {
59 u8 strength; /* Pad Drive Strength in mA */
60 u8 sel; /* Chip-specific select value */
61};
62/* SDIO Drive Strength to sel value table for PMU Rev 1 */
63static const struct sdiod_drive_str sdiod_drive_strength_tab1[] = {
64 {
65 4, 0x2}, {
66 2, 0x3}, {
67 1, 0x0}, {
68 0, 0x0}
69 };
70/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
71static const struct sdiod_drive_str sdiod_drive_strength_tab2[] = {
72 {
73 12, 0x7}, {
74 10, 0x6}, {
75 8, 0x5}, {
76 6, 0x4}, {
77 4, 0x2}, {
78 2, 0x1}, {
79 0, 0x0}
80 };
81/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */
82static const struct sdiod_drive_str sdiod_drive_strength_tab3[] = {
83 {
84 32, 0x7}, {
85 26, 0x6}, {
86 22, 0x5}, {
87 16, 0x4}, {
88 12, 0x3}, {
89 8, 0x2}, {
90 4, 0x1}, {
91 0, 0x0}
92 };
93
Franky Lince2d7d72011-12-08 15:06:39 -080094/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8V) */
95static const struct sdiod_drive_str sdiod_drvstr_tab4_1v8[] = {
96 {32, 0x6},
97 {26, 0x7},
98 {22, 0x4},
99 {16, 0x5},
100 {12, 0x2},
101 {8, 0x3},
102 {4, 0x0},
103 {0, 0x1}
104};
105
Franky Lin99ba15c2011-11-04 22:23:42 +0100106u8
107brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid)
108{
109 u8 idx;
110
111 for (idx = 0; idx < BRCMF_MAX_CORENUM; idx++)
112 if (coreid == ci->c_inf[idx].id)
113 return idx;
114
115 return BRCMF_MAX_CORENUM;
116}
117
Franky Lin454d2a82011-11-04 22:23:37 +0100118static u32
Franky Lin523894f2011-11-10 20:30:22 +0100119brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
120 struct chip_info *ci, u16 coreid)
Franky Lin454d2a82011-11-04 22:23:37 +0100121{
122 u32 regdata;
Franky Lin523894f2011-11-10 20:30:22 +0100123 u8 idx;
124
125 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin454d2a82011-11-04 22:23:37 +0100126
127 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin523894f2011-11-10 20:30:22 +0100128 CORE_SB(ci->c_inf[idx].base, sbidhigh), 4);
Franky Lin454d2a82011-11-04 22:23:37 +0100129 return SBCOREREV(regdata);
130}
131
Franky Lin523894f2011-11-10 20:30:22 +0100132static u32
133brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev,
134 struct chip_info *ci, u16 coreid)
135{
136 u8 idx;
137
138 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
139
140 return (ci->c_inf[idx].cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
141}
142
Franky Lin6ca687d2011-11-10 20:30:21 +0100143static bool
144brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
145 struct chip_info *ci, u16 coreid)
Franky Lind8f64a42011-11-04 22:23:36 +0100146{
147 u32 regdata;
Franky Lin6ca687d2011-11-10 20:30:21 +0100148 u8 idx;
149
150 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lind8f64a42011-11-04 22:23:36 +0100151
152 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin6ca687d2011-11-10 20:30:21 +0100153 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100154 regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
155 SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
156 return (SSB_TMSLOW_CLOCK == regdata);
Franky Lind8f64a42011-11-04 22:23:36 +0100157}
158
Franky Lin6ca687d2011-11-10 20:30:21 +0100159static bool
160brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
161 struct chip_info *ci, u16 coreid)
162{
163 u32 regdata;
164 u8 idx;
165 bool ret;
166
167 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
168
169 regdata = brcmf_sdcard_reg_read(sdiodev,
170 ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
171 ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
172
173 regdata = brcmf_sdcard_reg_read(sdiodev,
174 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
175 4);
176 ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
177
178 return ret;
179}
180
Franky Lin086a2e02011-11-10 20:30:23 +0100181static void
182brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
183 struct chip_info *ci, u16 coreid)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100184{
185 u32 regdata;
Franky Lin086a2e02011-11-10 20:30:23 +0100186 u8 idx;
187
188 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100189
190 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100191 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100192 if (regdata & SSB_TMSLOW_RESET)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100193 return;
194
195 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100196 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100197 if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
Franky Lin2d4a9af2011-11-04 22:23:31 +0100198 /*
199 * set target reject and spin until busy is clear
200 * (preserve core-specific bits)
201 */
202 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100203 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
204 brcmf_sdcard_reg_write(sdiodev,
205 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
206 4, regdata | SSB_TMSLOW_REJECT);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100207
208 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100209 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100210 udelay(1);
211 SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100212 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4) &
Franky Lin61213be2011-11-04 22:23:41 +0100213 SSB_TMSHIGH_BUSY), 100000);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100214
215 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100216 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100217 if (regdata & SSB_TMSHIGH_BUSY)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100218 brcmf_dbg(ERROR, "core state still busy\n");
219
220 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100221 CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100222 if (regdata & SSB_IDLOW_INITIATOR) {
Franky Lin2d4a9af2011-11-04 22:23:31 +0100223 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100224 CORE_SB(ci->c_inf[idx].base, sbimstate), 4) |
Franky Lin61213be2011-11-04 22:23:41 +0100225 SSB_IMSTATE_REJECT;
Franky Lin2d4a9af2011-11-04 22:23:31 +0100226 brcmf_sdcard_reg_write(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100227 CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
Franky Lin2d4a9af2011-11-04 22:23:31 +0100228 regdata);
229 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100230 CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100231 udelay(1);
232 SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100233 CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
Franky Lin61213be2011-11-04 22:23:41 +0100234 SSB_IMSTATE_BUSY), 100000);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100235 }
236
237 /* set reset and reject while enabling the clocks */
238 brcmf_sdcard_reg_write(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100239 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
Franky Lin61213be2011-11-04 22:23:41 +0100240 (SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
241 SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
Franky Lin2d4a9af2011-11-04 22:23:31 +0100242 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100243 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100244 udelay(10);
245
246 /* clear the initiator reject bit */
247 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100248 CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100249 if (regdata & SSB_IDLOW_INITIATOR) {
Franky Lin2d4a9af2011-11-04 22:23:31 +0100250 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100251 CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
Franky Lin61213be2011-11-04 22:23:41 +0100252 ~SSB_IMSTATE_REJECT;
Franky Lin2d4a9af2011-11-04 22:23:31 +0100253 brcmf_sdcard_reg_write(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100254 CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
Franky Lin2d4a9af2011-11-04 22:23:31 +0100255 regdata);
256 }
257 }
258
259 /* leave reset and reject asserted */
Franky Lin086a2e02011-11-10 20:30:23 +0100260 brcmf_sdcard_reg_write(sdiodev,
261 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
Franky Lin61213be2011-11-04 22:23:41 +0100262 (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
Franky Lin2d4a9af2011-11-04 22:23:31 +0100263 udelay(1);
264}
265
Franky Lin086a2e02011-11-10 20:30:23 +0100266static void
267brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
268 struct chip_info *ci, u16 coreid)
269{
270 u8 idx;
271 u32 regdata;
272
273 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
274
275 /* if core is already in reset, just return */
276 regdata = brcmf_sdcard_reg_read(sdiodev,
277 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
278 4);
279 if ((regdata & BCMA_RESET_CTL_RESET) != 0)
280 return;
281
282 brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
283 4, 0);
284 regdata = brcmf_sdcard_reg_read(sdiodev,
285 ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
286 udelay(10);
287
288 brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
289 4, BCMA_RESET_CTL_RESET);
290 udelay(1);
291}
292
Franky Lind77e70f2011-11-10 20:30:24 +0100293static void
294brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
295 struct chip_info *ci, u16 coreid)
Franky Lin2bc78e12011-11-04 22:23:38 +0100296{
297 u32 regdata;
Franky Lin086a2e02011-11-10 20:30:23 +0100298 u8 idx;
299
300 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin2bc78e12011-11-04 22:23:38 +0100301
302 /*
303 * Must do the disable sequence first to work for
304 * arbitrary current core state.
305 */
Franky Lind77e70f2011-11-10 20:30:24 +0100306 brcmf_sdio_sb_coredisable(sdiodev, ci, coreid);
Franky Lin2bc78e12011-11-04 22:23:38 +0100307
308 /*
309 * Now do the initialization sequence.
310 * set reset while enabling the clock and
311 * forcing them on throughout the core
312 */
Franky Lin086a2e02011-11-10 20:30:23 +0100313 brcmf_sdcard_reg_write(sdiodev,
314 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
315 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET);
Franky Lind77e70f2011-11-10 20:30:24 +0100316 regdata = brcmf_sdcard_reg_read(sdiodev,
317 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
Franky Lin2bc78e12011-11-04 22:23:38 +0100318 udelay(1);
319
Franky Lind77e70f2011-11-10 20:30:24 +0100320 /* clear any serror */
Franky Lin2bc78e12011-11-04 22:23:38 +0100321 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100322 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100323 if (regdata & SSB_TMSHIGH_SERR)
Franky Lin2bc78e12011-11-04 22:23:38 +0100324 brcmf_sdcard_reg_write(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100325 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4, 0);
Franky Lin2bc78e12011-11-04 22:23:38 +0100326
327 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100328 CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100329 if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
Franky Lin086a2e02011-11-10 20:30:23 +0100330 brcmf_sdcard_reg_write(sdiodev,
331 CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
Franky Lin61213be2011-11-04 22:23:41 +0100332 regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO));
Franky Lin2bc78e12011-11-04 22:23:38 +0100333
334 /* clear reset and allow it to propagate throughout the core */
Franky Lin086a2e02011-11-10 20:30:23 +0100335 brcmf_sdcard_reg_write(sdiodev,
336 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
Franky Lin61213be2011-11-04 22:23:41 +0100337 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK);
Franky Lind77e70f2011-11-10 20:30:24 +0100338 regdata = brcmf_sdcard_reg_read(sdiodev,
339 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
Franky Lin2bc78e12011-11-04 22:23:38 +0100340 udelay(1);
341
342 /* leave clock enabled */
Franky Lin086a2e02011-11-10 20:30:23 +0100343 brcmf_sdcard_reg_write(sdiodev,
344 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
Franky Lin61213be2011-11-04 22:23:41 +0100345 4, SSB_TMSLOW_CLOCK);
Franky Lind77e70f2011-11-10 20:30:24 +0100346 regdata = brcmf_sdcard_reg_read(sdiodev,
347 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
348 udelay(1);
349}
350
351static void
352brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
353 struct chip_info *ci, u16 coreid)
354{
355 u8 idx;
356 u32 regdata;
357
358 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
359
360 /* must disable first to work for arbitrary current core state */
361 brcmf_sdio_ai_coredisable(sdiodev, ci, coreid);
362
363 /* now do initialization sequence */
364 brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
365 4, BCMA_IOCTL_FGC | BCMA_IOCTL_CLK);
366 regdata = brcmf_sdcard_reg_read(sdiodev,
367 ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
368 brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
369 4, 0);
370 udelay(1);
371
372 brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
373 4, BCMA_IOCTL_CLK);
374 regdata = brcmf_sdcard_reg_read(sdiodev,
375 ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
Franky Lin2bc78e12011-11-04 22:23:38 +0100376 udelay(1);
377}
378
Franky Lina83369b2011-11-04 22:23:28 +0100379static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
380 struct chip_info *ci, u32 regs)
381{
382 u32 regdata;
383
384 /*
385 * Get CC core rev
386 * Chipid is assume to be at offset 0 from regs arg
387 * For different chiptypes or old sdio hosts w/o chipcommon,
388 * other ways of recognition should be added here.
389 */
Franky Lin99ba15c2011-11-04 22:23:42 +0100390 ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
391 ci->c_inf[0].base = regs;
Franky Lina83369b2011-11-04 22:23:28 +0100392 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100393 CORE_CC_REG(ci->c_inf[0].base, chipid), 4);
Franky Lina83369b2011-11-04 22:23:28 +0100394 ci->chip = regdata & CID_ID_MASK;
395 ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
Franky Lin6ca687d2011-11-10 20:30:21 +0100396 ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
Franky Lina83369b2011-11-04 22:23:28 +0100397
398 brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
399
400 /* Address of cores for new chips should be added here */
401 switch (ci->chip) {
402 case BCM4329_CHIP_ID:
Franky Lin99ba15c2011-11-04 22:23:42 +0100403 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
404 ci->c_inf[1].base = BCM4329_CORE_BUS_BASE;
405 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
406 ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE;
407 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
408 ci->c_inf[3].base = BCM4329_CORE_ARM_BASE;
Franky Lina83369b2011-11-04 22:23:28 +0100409 ci->ramsize = BCM4329_RAMSIZE;
410 break;
Franky Lince2d7d72011-12-08 15:06:39 -0800411 case BCM4330_CHIP_ID:
412 ci->c_inf[0].wrapbase = 0x18100000;
413 ci->c_inf[0].cib = 0x27004211;
414 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
415 ci->c_inf[1].base = 0x18002000;
416 ci->c_inf[1].wrapbase = 0x18102000;
417 ci->c_inf[1].cib = 0x07004211;
418 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
419 ci->c_inf[2].base = 0x18004000;
420 ci->c_inf[2].wrapbase = 0x18104000;
421 ci->c_inf[2].cib = 0x0d080401;
422 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
423 ci->c_inf[3].base = 0x18003000;
424 ci->c_inf[3].wrapbase = 0x18103000;
425 ci->c_inf[3].cib = 0x03004211;
426 ci->ramsize = 0x48000;
427 break;
Franky Lina83369b2011-11-04 22:23:28 +0100428 default:
429 brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip);
430 return -ENODEV;
431 }
432
Franky Lin6ca687d2011-11-10 20:30:21 +0100433 switch (ci->socitype) {
434 case SOCI_SB:
435 ci->iscoreup = brcmf_sdio_sb_iscoreup;
Franky Lin523894f2011-11-10 20:30:22 +0100436 ci->corerev = brcmf_sdio_sb_corerev;
Franky Lin086a2e02011-11-10 20:30:23 +0100437 ci->coredisable = brcmf_sdio_sb_coredisable;
Franky Lind77e70f2011-11-10 20:30:24 +0100438 ci->resetcore = brcmf_sdio_sb_resetcore;
Franky Lin6ca687d2011-11-10 20:30:21 +0100439 break;
440 case SOCI_AI:
441 ci->iscoreup = brcmf_sdio_ai_iscoreup;
Franky Lin523894f2011-11-10 20:30:22 +0100442 ci->corerev = brcmf_sdio_ai_corerev;
Franky Lin086a2e02011-11-10 20:30:23 +0100443 ci->coredisable = brcmf_sdio_ai_coredisable;
Franky Lind77e70f2011-11-10 20:30:24 +0100444 ci->resetcore = brcmf_sdio_ai_resetcore;
Franky Lin6ca687d2011-11-10 20:30:21 +0100445 break;
446 default:
447 brcmf_dbg(ERROR, "socitype %u not supported\n", ci->socitype);
448 return -ENODEV;
449 }
450
Franky Lina83369b2011-11-04 22:23:28 +0100451 return 0;
452}
453
Franky Line63ac6b2011-11-04 22:23:29 +0100454static int
455brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
456{
457 int err = 0;
458 u8 clkval, clkset;
459
460 /* Try forcing SDIO core to do ALPAvail request only */
461 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
462 brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
463 SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
464 if (err) {
465 brcmf_dbg(ERROR, "error writing for HT off\n");
466 return err;
467 }
468
469 /* If register supported, wait for ALPAvail and then force ALP */
470 /* This may take up to 15 milliseconds */
471 clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
472 SBSDIO_FUNC1_CHIPCLKCSR, NULL);
473
474 if ((clkval & ~SBSDIO_AVBITS) != clkset) {
475 brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
476 clkset, clkval);
477 return -EACCES;
478 }
479
480 SPINWAIT(((clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
481 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
482 !SBSDIO_ALPAV(clkval)),
483 PMU_MAX_TRANSITION_DLY);
484 if (!SBSDIO_ALPAV(clkval)) {
485 brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n",
486 clkval);
487 return -EBUSY;
488 }
489
490 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
491 brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
492 SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
493 udelay(65);
494
495 /* Also, disable the extra SDIO pull-ups */
496 brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
497 SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
498
499 return 0;
500}
501
Franky Lin5b45e542011-11-04 22:23:30 +0100502static void
503brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
504 struct chip_info *ci)
505{
Franky Lin5b45e542011-11-04 22:23:30 +0100506 /* get chipcommon rev */
Franky Lin523894f2011-11-10 20:30:22 +0100507 ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100508
509 /* get chipcommon capabilites */
Franky Lin99ba15c2011-11-04 22:23:42 +0100510 ci->c_inf[0].caps =
511 brcmf_sdcard_reg_read(sdiodev,
512 CORE_CC_REG(ci->c_inf[0].base, capabilities), 4);
Franky Lin5b45e542011-11-04 22:23:30 +0100513
514 /* get pmu caps & rev */
Franky Lin99ba15c2011-11-04 22:23:42 +0100515 if (ci->c_inf[0].caps & CC_CAP_PMU) {
Franky Lin5b45e542011-11-04 22:23:30 +0100516 ci->pmucaps = brcmf_sdcard_reg_read(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100517 CORE_CC_REG(ci->c_inf[0].base, pmucapabilities), 4);
Franky Lin5b45e542011-11-04 22:23:30 +0100518 ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
519 }
520
Franky Lin523894f2011-11-10 20:30:22 +0100521 ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100522
523 brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
Franky Lin99ba15c2011-11-04 22:23:42 +0100524 ci->c_inf[0].rev, ci->pmurev,
525 ci->c_inf[1].rev, ci->c_inf[1].id);
Franky Lin966414d2011-11-04 22:23:32 +0100526
527 /*
528 * Make sure any on-chip ARM is off (in case strapping is wrong),
529 * or downloaded code was already running.
530 */
Franky Lin086a2e02011-11-10 20:30:23 +0100531 ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3);
Franky Lin5b45e542011-11-04 22:23:30 +0100532}
533
Franky Lina83369b2011-11-04 22:23:28 +0100534int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
Franky Lina97e4fc2011-11-04 22:23:35 +0100535 struct chip_info **ci_ptr, u32 regs)
Franky Lina83369b2011-11-04 22:23:28 +0100536{
Franky Lina97e4fc2011-11-04 22:23:35 +0100537 int ret;
538 struct chip_info *ci;
539
540 brcmf_dbg(TRACE, "Enter\n");
541
542 /* alloc chip_info_t */
543 ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
544 if (!ci)
545 return -ENOMEM;
Franky Lina83369b2011-11-04 22:23:28 +0100546
Franky Line63ac6b2011-11-04 22:23:29 +0100547 ret = brcmf_sdio_chip_buscoreprep(sdiodev);
548 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100549 goto err;
Franky Line63ac6b2011-11-04 22:23:29 +0100550
Franky Lina83369b2011-11-04 22:23:28 +0100551 ret = brcmf_sdio_chip_recognition(sdiodev, ci, regs);
552 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100553 goto err;
Franky Lina83369b2011-11-04 22:23:28 +0100554
Franky Lin5b45e542011-11-04 22:23:30 +0100555 brcmf_sdio_chip_buscoresetup(sdiodev, ci);
556
Franky Lin960908d2011-11-04 22:23:33 +0100557 brcmf_sdcard_reg_write(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100558 CORE_CC_REG(ci->c_inf[0].base, gpiopullup), 4, 0);
Franky Lin960908d2011-11-04 22:23:33 +0100559 brcmf_sdcard_reg_write(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100560 CORE_CC_REG(ci->c_inf[0].base, gpiopulldown), 4, 0);
Franky Lin960908d2011-11-04 22:23:33 +0100561
Franky Lina97e4fc2011-11-04 22:23:35 +0100562 *ci_ptr = ci;
563 return 0;
564
565err:
566 kfree(ci);
Franky Lina83369b2011-11-04 22:23:28 +0100567 return ret;
568}
Franky Lina8a6c042011-11-04 22:23:39 +0100569
570void
571brcmf_sdio_chip_detach(struct chip_info **ci_ptr)
572{
573 brcmf_dbg(TRACE, "Enter\n");
574
575 kfree(*ci_ptr);
576 *ci_ptr = NULL;
577}
Franky Line12afb62011-11-04 22:23:40 +0100578
579static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len)
580{
581 const char *fmt;
582
583 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
584 snprintf(buf, len, fmt, chipid);
585 return buf;
586}
587
588void
589brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
590 struct chip_info *ci, u32 drivestrength)
591{
592 struct sdiod_drive_str *str_tab = NULL;
593 u32 str_mask = 0;
594 u32 str_shift = 0;
595 char chn[8];
596
Franky Lin99ba15c2011-11-04 22:23:42 +0100597 if (!(ci->c_inf[0].caps & CC_CAP_PMU))
Franky Line12afb62011-11-04 22:23:40 +0100598 return;
599
600 switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
601 case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
602 str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab1;
603 str_mask = 0x30000000;
604 str_shift = 28;
605 break;
606 case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2):
607 case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3):
608 str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab2;
609 str_mask = 0x00003800;
610 str_shift = 11;
611 break;
612 case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8):
613 str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab3;
614 str_mask = 0x00003800;
615 str_shift = 11;
616 break;
Franky Lince2d7d72011-12-08 15:06:39 -0800617 case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12):
618 str_tab = (struct sdiod_drive_str *)&sdiod_drvstr_tab4_1v8;
619 str_mask = 0x00003800;
620 str_shift = 11;
621 break;
Franky Line12afb62011-11-04 22:23:40 +0100622 default:
623 brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
624 brcmf_sdio_chip_name(ci->chip, chn, 8),
625 ci->chiprev, ci->pmurev);
626 break;
627 }
628
629 if (str_tab != NULL) {
630 u32 drivestrength_sel = 0;
631 u32 cc_data_temp;
632 int i;
633
634 for (i = 0; str_tab[i].strength != 0; i++) {
635 if (drivestrength >= str_tab[i].strength) {
636 drivestrength_sel = str_tab[i].sel;
637 break;
638 }
639 }
640
641 brcmf_sdcard_reg_write(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100642 CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
Franky Line12afb62011-11-04 22:23:40 +0100643 4, 1);
644 cc_data_temp = brcmf_sdcard_reg_read(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100645 CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr), 4);
Franky Line12afb62011-11-04 22:23:40 +0100646 cc_data_temp &= ~str_mask;
647 drivestrength_sel <<= str_shift;
648 cc_data_temp |= drivestrength_sel;
649 brcmf_sdcard_reg_write(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100650 CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
Franky Line12afb62011-11-04 22:23:40 +0100651 4, cc_data_temp);
652
653 brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
654 drivestrength, cc_data_temp);
655 }
656}