blob: 1534efc21631482e5b7902e88511b48964a15568 [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
Joe Perches02f77192012-01-15 00:38:44 -080018#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19
Franky Lina83369b2011-11-04 22:23:28 +010020#include <linux/types.h>
21#include <linux/netdevice.h>
22#include <linux/mmc/card.h>
Franky Lin61213be2011-11-04 22:23:41 +010023#include <linux/ssb/ssb_regs.h>
Franky Lin99ba15c2011-11-04 22:23:42 +010024#include <linux/bcma/bcma.h>
Franky Lin61213be2011-11-04 22:23:41 +010025
Franky Lina83369b2011-11-04 22:23:28 +010026#include <chipcommon.h>
27#include <brcm_hw_ids.h>
28#include <brcmu_wifi.h>
29#include <brcmu_utils.h>
Franky Lin2d4a9af2011-11-04 22:23:31 +010030#include <soc.h>
Franky Lina83369b2011-11-04 22:23:28 +010031#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
Franky Lina83369b2011-11-04 22:23:28 +010045#define SBCOREREV(sbidh) \
Franky Lin61213be2011-11-04 22:23:41 +010046 ((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \
47 ((sbidh) & SSB_IDHIGH_RCLO))
Franky Lina83369b2011-11-04 22:23:28 +010048
Franky Lin6ca687d2011-11-10 20:30:21 +010049/* SOC Interconnect types (aka chip types) */
50#define SOCI_SB 0
51#define SOCI_AI 1
52
Franky Lin523894f2011-11-10 20:30:22 +010053/* EROM CompIdentB */
54#define CIB_REV_MASK 0xff000000
55#define CIB_REV_SHIFT 24
56
Franky Line12afb62011-11-04 22:23:40 +010057#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
58/* SDIO Pad drive strength to select value mappings */
59struct sdiod_drive_str {
60 u8 strength; /* Pad Drive Strength in mA */
61 u8 sel; /* Chip-specific select value */
62};
Franky Lince2d7d72011-12-08 15:06:39 -080063/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8V) */
Franky Linffb27562011-12-08 15:06:40 -080064static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = {
Franky Lince2d7d72011-12-08 15:06:39 -080065 {32, 0x6},
66 {26, 0x7},
67 {22, 0x4},
68 {16, 0x5},
69 {12, 0x2},
70 {8, 0x3},
71 {4, 0x0},
72 {0, 0x1}
73};
74
Franky Lin99ba15c2011-11-04 22:23:42 +010075u8
76brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid)
77{
78 u8 idx;
79
80 for (idx = 0; idx < BRCMF_MAX_CORENUM; idx++)
81 if (coreid == ci->c_inf[idx].id)
82 return idx;
83
84 return BRCMF_MAX_CORENUM;
85}
86
Franky Lin454d2a82011-11-04 22:23:37 +010087static u32
Franky Lin523894f2011-11-10 20:30:22 +010088brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
89 struct chip_info *ci, u16 coreid)
Franky Lin454d2a82011-11-04 22:23:37 +010090{
91 u32 regdata;
Franky Lin523894f2011-11-10 20:30:22 +010092 u8 idx;
93
94 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin454d2a82011-11-04 22:23:37 +010095
96 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin523894f2011-11-10 20:30:22 +010097 CORE_SB(ci->c_inf[idx].base, sbidhigh), 4);
Franky Lin454d2a82011-11-04 22:23:37 +010098 return SBCOREREV(regdata);
99}
100
Franky Lin523894f2011-11-10 20:30:22 +0100101static u32
102brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev,
103 struct chip_info *ci, u16 coreid)
104{
105 u8 idx;
106
107 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
108
109 return (ci->c_inf[idx].cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
110}
111
Franky Lin6ca687d2011-11-10 20:30:21 +0100112static bool
113brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
114 struct chip_info *ci, u16 coreid)
Franky Lind8f64a42011-11-04 22:23:36 +0100115{
116 u32 regdata;
Franky Lin6ca687d2011-11-10 20:30:21 +0100117 u8 idx;
118
119 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lind8f64a42011-11-04 22:23:36 +0100120
121 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin6ca687d2011-11-10 20:30:21 +0100122 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100123 regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
124 SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
125 return (SSB_TMSLOW_CLOCK == regdata);
Franky Lind8f64a42011-11-04 22:23:36 +0100126}
127
Franky Lin6ca687d2011-11-10 20:30:21 +0100128static bool
129brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
130 struct chip_info *ci, u16 coreid)
131{
132 u32 regdata;
133 u8 idx;
134 bool ret;
135
136 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
137
138 regdata = brcmf_sdcard_reg_read(sdiodev,
139 ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
140 ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
141
142 regdata = brcmf_sdcard_reg_read(sdiodev,
143 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
144 4);
145 ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
146
147 return ret;
148}
149
Franky Lin086a2e02011-11-10 20:30:23 +0100150static void
151brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
152 struct chip_info *ci, u16 coreid)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100153{
154 u32 regdata;
Franky Lin086a2e02011-11-10 20:30:23 +0100155 u8 idx;
156
157 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100158
159 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100160 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100161 if (regdata & SSB_TMSLOW_RESET)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100162 return;
163
164 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100165 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100166 if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
Franky Lin2d4a9af2011-11-04 22:23:31 +0100167 /*
168 * set target reject and spin until busy is clear
169 * (preserve core-specific bits)
170 */
171 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100172 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
173 brcmf_sdcard_reg_write(sdiodev,
174 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
175 4, regdata | SSB_TMSLOW_REJECT);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100176
177 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100178 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100179 udelay(1);
180 SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100181 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4) &
Franky Lin61213be2011-11-04 22:23:41 +0100182 SSB_TMSHIGH_BUSY), 100000);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100183
184 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100185 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100186 if (regdata & SSB_TMSHIGH_BUSY)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100187 brcmf_dbg(ERROR, "core state still busy\n");
188
189 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100190 CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100191 if (regdata & SSB_IDLOW_INITIATOR) {
Franky Lin2d4a9af2011-11-04 22:23:31 +0100192 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100193 CORE_SB(ci->c_inf[idx].base, sbimstate), 4) |
Franky Lin61213be2011-11-04 22:23:41 +0100194 SSB_IMSTATE_REJECT;
Franky Lin2d4a9af2011-11-04 22:23:31 +0100195 brcmf_sdcard_reg_write(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100196 CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
Franky Lin2d4a9af2011-11-04 22:23:31 +0100197 regdata);
198 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100199 CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100200 udelay(1);
201 SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100202 CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
Franky Lin61213be2011-11-04 22:23:41 +0100203 SSB_IMSTATE_BUSY), 100000);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100204 }
205
206 /* set reset and reject while enabling the clocks */
207 brcmf_sdcard_reg_write(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100208 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
Franky Lin61213be2011-11-04 22:23:41 +0100209 (SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
210 SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
Franky Lin2d4a9af2011-11-04 22:23:31 +0100211 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100212 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100213 udelay(10);
214
215 /* clear the initiator reject bit */
216 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100217 CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100218 if (regdata & SSB_IDLOW_INITIATOR) {
Franky Lin2d4a9af2011-11-04 22:23:31 +0100219 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100220 CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
Franky Lin61213be2011-11-04 22:23:41 +0100221 ~SSB_IMSTATE_REJECT;
Franky Lin2d4a9af2011-11-04 22:23:31 +0100222 brcmf_sdcard_reg_write(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100223 CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
Franky Lin2d4a9af2011-11-04 22:23:31 +0100224 regdata);
225 }
226 }
227
228 /* leave reset and reject asserted */
Franky Lin086a2e02011-11-10 20:30:23 +0100229 brcmf_sdcard_reg_write(sdiodev,
230 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
Franky Lin61213be2011-11-04 22:23:41 +0100231 (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
Franky Lin2d4a9af2011-11-04 22:23:31 +0100232 udelay(1);
233}
234
Franky Lin086a2e02011-11-10 20:30:23 +0100235static void
236brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
237 struct chip_info *ci, u16 coreid)
238{
239 u8 idx;
240 u32 regdata;
241
242 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
243
244 /* if core is already in reset, just return */
245 regdata = brcmf_sdcard_reg_read(sdiodev,
246 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
247 4);
248 if ((regdata & BCMA_RESET_CTL_RESET) != 0)
249 return;
250
251 brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
252 4, 0);
253 regdata = brcmf_sdcard_reg_read(sdiodev,
254 ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
255 udelay(10);
256
257 brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
258 4, BCMA_RESET_CTL_RESET);
259 udelay(1);
260}
261
Franky Lind77e70f2011-11-10 20:30:24 +0100262static void
263brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
264 struct chip_info *ci, u16 coreid)
Franky Lin2bc78e12011-11-04 22:23:38 +0100265{
266 u32 regdata;
Franky Lin086a2e02011-11-10 20:30:23 +0100267 u8 idx;
268
269 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin2bc78e12011-11-04 22:23:38 +0100270
271 /*
272 * Must do the disable sequence first to work for
273 * arbitrary current core state.
274 */
Franky Lind77e70f2011-11-10 20:30:24 +0100275 brcmf_sdio_sb_coredisable(sdiodev, ci, coreid);
Franky Lin2bc78e12011-11-04 22:23:38 +0100276
277 /*
278 * Now do the initialization sequence.
279 * set reset while enabling the clock and
280 * forcing them on throughout the core
281 */
Franky Lin086a2e02011-11-10 20:30:23 +0100282 brcmf_sdcard_reg_write(sdiodev,
283 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
284 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET);
Franky Lind77e70f2011-11-10 20:30:24 +0100285 regdata = brcmf_sdcard_reg_read(sdiodev,
286 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
Franky Lin2bc78e12011-11-04 22:23:38 +0100287 udelay(1);
288
Franky Lind77e70f2011-11-10 20:30:24 +0100289 /* clear any serror */
Franky Lin2bc78e12011-11-04 22:23:38 +0100290 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100291 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100292 if (regdata & SSB_TMSHIGH_SERR)
Franky Lin2bc78e12011-11-04 22:23:38 +0100293 brcmf_sdcard_reg_write(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100294 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4, 0);
Franky Lin2bc78e12011-11-04 22:23:38 +0100295
296 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100297 CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100298 if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
Franky Lin086a2e02011-11-10 20:30:23 +0100299 brcmf_sdcard_reg_write(sdiodev,
300 CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
Franky Lin61213be2011-11-04 22:23:41 +0100301 regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO));
Franky Lin2bc78e12011-11-04 22:23:38 +0100302
303 /* clear reset and allow it to propagate throughout the core */
Franky Lin086a2e02011-11-10 20:30:23 +0100304 brcmf_sdcard_reg_write(sdiodev,
305 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
Franky Lin61213be2011-11-04 22:23:41 +0100306 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK);
Franky Lind77e70f2011-11-10 20:30:24 +0100307 regdata = brcmf_sdcard_reg_read(sdiodev,
308 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
Franky Lin2bc78e12011-11-04 22:23:38 +0100309 udelay(1);
310
311 /* leave clock enabled */
Franky Lin086a2e02011-11-10 20:30:23 +0100312 brcmf_sdcard_reg_write(sdiodev,
313 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
Franky Lin61213be2011-11-04 22:23:41 +0100314 4, SSB_TMSLOW_CLOCK);
Franky Lind77e70f2011-11-10 20:30:24 +0100315 regdata = brcmf_sdcard_reg_read(sdiodev,
316 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
317 udelay(1);
318}
319
320static void
321brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
322 struct chip_info *ci, u16 coreid)
323{
324 u8 idx;
325 u32 regdata;
326
327 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
328
329 /* must disable first to work for arbitrary current core state */
330 brcmf_sdio_ai_coredisable(sdiodev, ci, coreid);
331
332 /* now do initialization sequence */
333 brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
334 4, BCMA_IOCTL_FGC | BCMA_IOCTL_CLK);
335 regdata = brcmf_sdcard_reg_read(sdiodev,
336 ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
337 brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
338 4, 0);
339 udelay(1);
340
341 brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
342 4, BCMA_IOCTL_CLK);
343 regdata = brcmf_sdcard_reg_read(sdiodev,
344 ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
Franky Lin2bc78e12011-11-04 22:23:38 +0100345 udelay(1);
346}
347
Franky Lina83369b2011-11-04 22:23:28 +0100348static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
349 struct chip_info *ci, u32 regs)
350{
351 u32 regdata;
352
353 /*
354 * Get CC core rev
355 * Chipid is assume to be at offset 0 from regs arg
356 * For different chiptypes or old sdio hosts w/o chipcommon,
357 * other ways of recognition should be added here.
358 */
Franky Lin99ba15c2011-11-04 22:23:42 +0100359 ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
360 ci->c_inf[0].base = regs;
Franky Lina83369b2011-11-04 22:23:28 +0100361 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100362 CORE_CC_REG(ci->c_inf[0].base, chipid), 4);
Franky Lina83369b2011-11-04 22:23:28 +0100363 ci->chip = regdata & CID_ID_MASK;
364 ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
Franky Lin6ca687d2011-11-10 20:30:21 +0100365 ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
Franky Lina83369b2011-11-04 22:23:28 +0100366
367 brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
368
369 /* Address of cores for new chips should be added here */
370 switch (ci->chip) {
371 case BCM4329_CHIP_ID:
Franky Lin99ba15c2011-11-04 22:23:42 +0100372 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
373 ci->c_inf[1].base = BCM4329_CORE_BUS_BASE;
374 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
375 ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE;
376 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
377 ci->c_inf[3].base = BCM4329_CORE_ARM_BASE;
Franky Lina83369b2011-11-04 22:23:28 +0100378 ci->ramsize = BCM4329_RAMSIZE;
379 break;
Franky Lince2d7d72011-12-08 15:06:39 -0800380 case BCM4330_CHIP_ID:
381 ci->c_inf[0].wrapbase = 0x18100000;
382 ci->c_inf[0].cib = 0x27004211;
383 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
384 ci->c_inf[1].base = 0x18002000;
385 ci->c_inf[1].wrapbase = 0x18102000;
386 ci->c_inf[1].cib = 0x07004211;
387 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
388 ci->c_inf[2].base = 0x18004000;
389 ci->c_inf[2].wrapbase = 0x18104000;
390 ci->c_inf[2].cib = 0x0d080401;
391 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
392 ci->c_inf[3].base = 0x18003000;
393 ci->c_inf[3].wrapbase = 0x18103000;
394 ci->c_inf[3].cib = 0x03004211;
395 ci->ramsize = 0x48000;
396 break;
Franky Lina83369b2011-11-04 22:23:28 +0100397 default:
398 brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip);
399 return -ENODEV;
400 }
401
Franky Lin6ca687d2011-11-10 20:30:21 +0100402 switch (ci->socitype) {
403 case SOCI_SB:
404 ci->iscoreup = brcmf_sdio_sb_iscoreup;
Franky Lin523894f2011-11-10 20:30:22 +0100405 ci->corerev = brcmf_sdio_sb_corerev;
Franky Lin086a2e02011-11-10 20:30:23 +0100406 ci->coredisable = brcmf_sdio_sb_coredisable;
Franky Lind77e70f2011-11-10 20:30:24 +0100407 ci->resetcore = brcmf_sdio_sb_resetcore;
Franky Lin6ca687d2011-11-10 20:30:21 +0100408 break;
409 case SOCI_AI:
410 ci->iscoreup = brcmf_sdio_ai_iscoreup;
Franky Lin523894f2011-11-10 20:30:22 +0100411 ci->corerev = brcmf_sdio_ai_corerev;
Franky Lin086a2e02011-11-10 20:30:23 +0100412 ci->coredisable = brcmf_sdio_ai_coredisable;
Franky Lind77e70f2011-11-10 20:30:24 +0100413 ci->resetcore = brcmf_sdio_ai_resetcore;
Franky Lin6ca687d2011-11-10 20:30:21 +0100414 break;
415 default:
416 brcmf_dbg(ERROR, "socitype %u not supported\n", ci->socitype);
417 return -ENODEV;
418 }
419
Franky Lina83369b2011-11-04 22:23:28 +0100420 return 0;
421}
422
Franky Line63ac6b2011-11-04 22:23:29 +0100423static int
424brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
425{
426 int err = 0;
427 u8 clkval, clkset;
428
429 /* Try forcing SDIO core to do ALPAvail request only */
430 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
431 brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
432 SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
433 if (err) {
434 brcmf_dbg(ERROR, "error writing for HT off\n");
435 return err;
436 }
437
438 /* If register supported, wait for ALPAvail and then force ALP */
439 /* This may take up to 15 milliseconds */
440 clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
441 SBSDIO_FUNC1_CHIPCLKCSR, NULL);
442
443 if ((clkval & ~SBSDIO_AVBITS) != clkset) {
444 brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
445 clkset, clkval);
446 return -EACCES;
447 }
448
449 SPINWAIT(((clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
450 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
451 !SBSDIO_ALPAV(clkval)),
452 PMU_MAX_TRANSITION_DLY);
453 if (!SBSDIO_ALPAV(clkval)) {
454 brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n",
455 clkval);
456 return -EBUSY;
457 }
458
459 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
460 brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
461 SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
462 udelay(65);
463
464 /* Also, disable the extra SDIO pull-ups */
465 brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
466 SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
467
468 return 0;
469}
470
Franky Lin5b45e542011-11-04 22:23:30 +0100471static void
472brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
473 struct chip_info *ci)
474{
Franky Lin5b45e542011-11-04 22:23:30 +0100475 /* get chipcommon rev */
Franky Lin523894f2011-11-10 20:30:22 +0100476 ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100477
478 /* get chipcommon capabilites */
Franky Lin99ba15c2011-11-04 22:23:42 +0100479 ci->c_inf[0].caps =
480 brcmf_sdcard_reg_read(sdiodev,
481 CORE_CC_REG(ci->c_inf[0].base, capabilities), 4);
Franky Lin5b45e542011-11-04 22:23:30 +0100482
483 /* get pmu caps & rev */
Franky Lin99ba15c2011-11-04 22:23:42 +0100484 if (ci->c_inf[0].caps & CC_CAP_PMU) {
Franky Lin5b45e542011-11-04 22:23:30 +0100485 ci->pmucaps = brcmf_sdcard_reg_read(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100486 CORE_CC_REG(ci->c_inf[0].base, pmucapabilities), 4);
Franky Lin5b45e542011-11-04 22:23:30 +0100487 ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
488 }
489
Franky Lin523894f2011-11-10 20:30:22 +0100490 ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100491
492 brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
Franky Lin99ba15c2011-11-04 22:23:42 +0100493 ci->c_inf[0].rev, ci->pmurev,
494 ci->c_inf[1].rev, ci->c_inf[1].id);
Franky Lin966414d2011-11-04 22:23:32 +0100495
496 /*
497 * Make sure any on-chip ARM is off (in case strapping is wrong),
498 * or downloaded code was already running.
499 */
Franky Lin086a2e02011-11-10 20:30:23 +0100500 ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3);
Franky Lin5b45e542011-11-04 22:23:30 +0100501}
502
Franky Lina83369b2011-11-04 22:23:28 +0100503int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
Franky Lina97e4fc2011-11-04 22:23:35 +0100504 struct chip_info **ci_ptr, u32 regs)
Franky Lina83369b2011-11-04 22:23:28 +0100505{
Franky Lina97e4fc2011-11-04 22:23:35 +0100506 int ret;
507 struct chip_info *ci;
508
509 brcmf_dbg(TRACE, "Enter\n");
510
511 /* alloc chip_info_t */
512 ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
513 if (!ci)
514 return -ENOMEM;
Franky Lina83369b2011-11-04 22:23:28 +0100515
Franky Line63ac6b2011-11-04 22:23:29 +0100516 ret = brcmf_sdio_chip_buscoreprep(sdiodev);
517 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100518 goto err;
Franky Line63ac6b2011-11-04 22:23:29 +0100519
Franky Lina83369b2011-11-04 22:23:28 +0100520 ret = brcmf_sdio_chip_recognition(sdiodev, ci, regs);
521 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100522 goto err;
Franky Lina83369b2011-11-04 22:23:28 +0100523
Franky Lin5b45e542011-11-04 22:23:30 +0100524 brcmf_sdio_chip_buscoresetup(sdiodev, ci);
525
Franky Lin960908d2011-11-04 22:23:33 +0100526 brcmf_sdcard_reg_write(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100527 CORE_CC_REG(ci->c_inf[0].base, gpiopullup), 4, 0);
Franky Lin960908d2011-11-04 22:23:33 +0100528 brcmf_sdcard_reg_write(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100529 CORE_CC_REG(ci->c_inf[0].base, gpiopulldown), 4, 0);
Franky Lin960908d2011-11-04 22:23:33 +0100530
Franky Lina97e4fc2011-11-04 22:23:35 +0100531 *ci_ptr = ci;
532 return 0;
533
534err:
535 kfree(ci);
Franky Lina83369b2011-11-04 22:23:28 +0100536 return ret;
537}
Franky Lina8a6c042011-11-04 22:23:39 +0100538
539void
540brcmf_sdio_chip_detach(struct chip_info **ci_ptr)
541{
542 brcmf_dbg(TRACE, "Enter\n");
543
544 kfree(*ci_ptr);
545 *ci_ptr = NULL;
546}
Franky Line12afb62011-11-04 22:23:40 +0100547
548static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len)
549{
550 const char *fmt;
551
552 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
553 snprintf(buf, len, fmt, chipid);
554 return buf;
555}
556
557void
558brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
559 struct chip_info *ci, u32 drivestrength)
560{
561 struct sdiod_drive_str *str_tab = NULL;
562 u32 str_mask = 0;
563 u32 str_shift = 0;
564 char chn[8];
565
Franky Lin99ba15c2011-11-04 22:23:42 +0100566 if (!(ci->c_inf[0].caps & CC_CAP_PMU))
Franky Line12afb62011-11-04 22:23:40 +0100567 return;
568
569 switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
Franky Lince2d7d72011-12-08 15:06:39 -0800570 case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12):
Franky Linffb27562011-12-08 15:06:40 -0800571 str_tab = (struct sdiod_drive_str *)&sdiod_drvstr_tab1_1v8;
Franky Lince2d7d72011-12-08 15:06:39 -0800572 str_mask = 0x00003800;
573 str_shift = 11;
574 break;
Franky Line12afb62011-11-04 22:23:40 +0100575 default:
576 brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
577 brcmf_sdio_chip_name(ci->chip, chn, 8),
578 ci->chiprev, ci->pmurev);
579 break;
580 }
581
582 if (str_tab != NULL) {
583 u32 drivestrength_sel = 0;
584 u32 cc_data_temp;
585 int i;
586
587 for (i = 0; str_tab[i].strength != 0; i++) {
588 if (drivestrength >= str_tab[i].strength) {
589 drivestrength_sel = str_tab[i].sel;
590 break;
591 }
592 }
593
594 brcmf_sdcard_reg_write(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100595 CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
Franky Line12afb62011-11-04 22:23:40 +0100596 4, 1);
597 cc_data_temp = brcmf_sdcard_reg_read(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100598 CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr), 4);
Franky Line12afb62011-11-04 22:23:40 +0100599 cc_data_temp &= ~str_mask;
600 drivestrength_sel <<= str_shift;
601 cc_data_temp |= drivestrength_sel;
602 brcmf_sdcard_reg_write(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100603 CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
Franky Line12afb62011-11-04 22:23:40 +0100604 4, cc_data_temp);
605
606 brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
607 drivestrength, cc_data_temp);
608 }
609}