blob: d2cf8c6811d918f39c3d842fa893b1baa9d26a8e [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 Lin99ba15c2011-11-04 22:23:42 +010094u8
95brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid)
96{
97 u8 idx;
98
99 for (idx = 0; idx < BRCMF_MAX_CORENUM; idx++)
100 if (coreid == ci->c_inf[idx].id)
101 return idx;
102
103 return BRCMF_MAX_CORENUM;
104}
105
Franky Lin454d2a82011-11-04 22:23:37 +0100106static u32
Franky Lin523894f2011-11-10 20:30:22 +0100107brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
108 struct chip_info *ci, u16 coreid)
Franky Lin454d2a82011-11-04 22:23:37 +0100109{
110 u32 regdata;
Franky Lin523894f2011-11-10 20:30:22 +0100111 u8 idx;
112
113 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin454d2a82011-11-04 22:23:37 +0100114
115 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin523894f2011-11-10 20:30:22 +0100116 CORE_SB(ci->c_inf[idx].base, sbidhigh), 4);
Franky Lin454d2a82011-11-04 22:23:37 +0100117 return SBCOREREV(regdata);
118}
119
Franky Lin523894f2011-11-10 20:30:22 +0100120static u32
121brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev,
122 struct chip_info *ci, u16 coreid)
123{
124 u8 idx;
125
126 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
127
128 return (ci->c_inf[idx].cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
129}
130
Franky Lin6ca687d2011-11-10 20:30:21 +0100131static bool
132brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
133 struct chip_info *ci, u16 coreid)
Franky Lind8f64a42011-11-04 22:23:36 +0100134{
135 u32 regdata;
Franky Lin6ca687d2011-11-10 20:30:21 +0100136 u8 idx;
137
138 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lind8f64a42011-11-04 22:23:36 +0100139
140 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin6ca687d2011-11-10 20:30:21 +0100141 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100142 regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
143 SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
144 return (SSB_TMSLOW_CLOCK == regdata);
Franky Lind8f64a42011-11-04 22:23:36 +0100145}
146
Franky Lin6ca687d2011-11-10 20:30:21 +0100147static bool
148brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
149 struct chip_info *ci, u16 coreid)
150{
151 u32 regdata;
152 u8 idx;
153 bool ret;
154
155 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
156
157 regdata = brcmf_sdcard_reg_read(sdiodev,
158 ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
159 ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
160
161 regdata = brcmf_sdcard_reg_read(sdiodev,
162 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
163 4);
164 ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
165
166 return ret;
167}
168
Franky Lin086a2e02011-11-10 20:30:23 +0100169static void
170brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
171 struct chip_info *ci, u16 coreid)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100172{
173 u32 regdata;
Franky Lin086a2e02011-11-10 20:30:23 +0100174 u8 idx;
175
176 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100177
178 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100179 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100180 if (regdata & SSB_TMSLOW_RESET)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100181 return;
182
183 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100184 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100185 if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
Franky Lin2d4a9af2011-11-04 22:23:31 +0100186 /*
187 * set target reject and spin until busy is clear
188 * (preserve core-specific bits)
189 */
190 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100191 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
192 brcmf_sdcard_reg_write(sdiodev,
193 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
194 4, regdata | SSB_TMSLOW_REJECT);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100195
196 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100197 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100198 udelay(1);
199 SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100200 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4) &
Franky Lin61213be2011-11-04 22:23:41 +0100201 SSB_TMSHIGH_BUSY), 100000);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100202
203 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100204 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100205 if (regdata & SSB_TMSHIGH_BUSY)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100206 brcmf_dbg(ERROR, "core state still busy\n");
207
208 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100209 CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100210 if (regdata & SSB_IDLOW_INITIATOR) {
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, sbimstate), 4) |
Franky Lin61213be2011-11-04 22:23:41 +0100213 SSB_IMSTATE_REJECT;
Franky Lin2d4a9af2011-11-04 22:23:31 +0100214 brcmf_sdcard_reg_write(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100215 CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
Franky Lin2d4a9af2011-11-04 22:23:31 +0100216 regdata);
217 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100218 CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100219 udelay(1);
220 SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100221 CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
Franky Lin61213be2011-11-04 22:23:41 +0100222 SSB_IMSTATE_BUSY), 100000);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100223 }
224
225 /* set reset and reject while enabling the clocks */
226 brcmf_sdcard_reg_write(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100227 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
Franky Lin61213be2011-11-04 22:23:41 +0100228 (SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
229 SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
Franky Lin2d4a9af2011-11-04 22:23:31 +0100230 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100231 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100232 udelay(10);
233
234 /* clear the initiator reject bit */
235 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100236 CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100237 if (regdata & SSB_IDLOW_INITIATOR) {
Franky Lin2d4a9af2011-11-04 22:23:31 +0100238 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100239 CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
Franky Lin61213be2011-11-04 22:23:41 +0100240 ~SSB_IMSTATE_REJECT;
Franky Lin2d4a9af2011-11-04 22:23:31 +0100241 brcmf_sdcard_reg_write(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100242 CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
Franky Lin2d4a9af2011-11-04 22:23:31 +0100243 regdata);
244 }
245 }
246
247 /* leave reset and reject asserted */
Franky Lin086a2e02011-11-10 20:30:23 +0100248 brcmf_sdcard_reg_write(sdiodev,
249 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
Franky Lin61213be2011-11-04 22:23:41 +0100250 (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
Franky Lin2d4a9af2011-11-04 22:23:31 +0100251 udelay(1);
252}
253
Franky Lin086a2e02011-11-10 20:30:23 +0100254static void
255brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
256 struct chip_info *ci, u16 coreid)
257{
258 u8 idx;
259 u32 regdata;
260
261 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
262
263 /* if core is already in reset, just return */
264 regdata = brcmf_sdcard_reg_read(sdiodev,
265 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
266 4);
267 if ((regdata & BCMA_RESET_CTL_RESET) != 0)
268 return;
269
270 brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
271 4, 0);
272 regdata = brcmf_sdcard_reg_read(sdiodev,
273 ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
274 udelay(10);
275
276 brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
277 4, BCMA_RESET_CTL_RESET);
278 udelay(1);
279}
280
Franky Lin2bc78e12011-11-04 22:23:38 +0100281void
Franky Lin086a2e02011-11-10 20:30:23 +0100282brcmf_sdio_chip_resetcore(struct brcmf_sdio_dev *sdiodev,
283 struct chip_info *ci, u16 coreid)
Franky Lin2bc78e12011-11-04 22:23:38 +0100284{
285 u32 regdata;
Franky Lin086a2e02011-11-10 20:30:23 +0100286 u8 idx;
287
288 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin2bc78e12011-11-04 22:23:38 +0100289
290 /*
291 * Must do the disable sequence first to work for
292 * arbitrary current core state.
293 */
Franky Lin086a2e02011-11-10 20:30:23 +0100294 ci->coredisable(sdiodev, ci, coreid);
Franky Lin2bc78e12011-11-04 22:23:38 +0100295
296 /*
297 * Now do the initialization sequence.
298 * set reset while enabling the clock and
299 * forcing them on throughout the core
300 */
Franky Lin086a2e02011-11-10 20:30:23 +0100301 brcmf_sdcard_reg_write(sdiodev,
302 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
303 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET);
Franky Lin2bc78e12011-11-04 22:23:38 +0100304 udelay(1);
305
306 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100307 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100308 if (regdata & SSB_TMSHIGH_SERR)
Franky Lin2bc78e12011-11-04 22:23:38 +0100309 brcmf_sdcard_reg_write(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100310 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4, 0);
Franky Lin2bc78e12011-11-04 22:23:38 +0100311
312 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin086a2e02011-11-10 20:30:23 +0100313 CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
Franky Lin61213be2011-11-04 22:23:41 +0100314 if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
Franky Lin086a2e02011-11-10 20:30:23 +0100315 brcmf_sdcard_reg_write(sdiodev,
316 CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
Franky Lin61213be2011-11-04 22:23:41 +0100317 regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO));
Franky Lin2bc78e12011-11-04 22:23:38 +0100318
319 /* clear reset and allow it to propagate throughout the core */
Franky Lin086a2e02011-11-10 20:30:23 +0100320 brcmf_sdcard_reg_write(sdiodev,
321 CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
Franky Lin61213be2011-11-04 22:23:41 +0100322 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK);
Franky Lin2bc78e12011-11-04 22:23:38 +0100323 udelay(1);
324
325 /* leave clock enabled */
Franky Lin086a2e02011-11-10 20:30:23 +0100326 brcmf_sdcard_reg_write(sdiodev,
327 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
Franky Lin61213be2011-11-04 22:23:41 +0100328 4, SSB_TMSLOW_CLOCK);
Franky Lin2bc78e12011-11-04 22:23:38 +0100329 udelay(1);
330}
331
Franky Lina83369b2011-11-04 22:23:28 +0100332static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
333 struct chip_info *ci, u32 regs)
334{
335 u32 regdata;
336
337 /*
338 * Get CC core rev
339 * Chipid is assume to be at offset 0 from regs arg
340 * For different chiptypes or old sdio hosts w/o chipcommon,
341 * other ways of recognition should be added here.
342 */
Franky Lin99ba15c2011-11-04 22:23:42 +0100343 ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
344 ci->c_inf[0].base = regs;
Franky Lina83369b2011-11-04 22:23:28 +0100345 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100346 CORE_CC_REG(ci->c_inf[0].base, chipid), 4);
Franky Lina83369b2011-11-04 22:23:28 +0100347 ci->chip = regdata & CID_ID_MASK;
348 ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
Franky Lin6ca687d2011-11-10 20:30:21 +0100349 ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
Franky Lina83369b2011-11-04 22:23:28 +0100350
351 brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
352
353 /* Address of cores for new chips should be added here */
354 switch (ci->chip) {
355 case BCM4329_CHIP_ID:
Franky Lin99ba15c2011-11-04 22:23:42 +0100356 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
357 ci->c_inf[1].base = BCM4329_CORE_BUS_BASE;
358 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
359 ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE;
360 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
361 ci->c_inf[3].base = BCM4329_CORE_ARM_BASE;
Franky Lina83369b2011-11-04 22:23:28 +0100362 ci->ramsize = BCM4329_RAMSIZE;
363 break;
364 default:
365 brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip);
366 return -ENODEV;
367 }
368
Franky Lin6ca687d2011-11-10 20:30:21 +0100369 switch (ci->socitype) {
370 case SOCI_SB:
371 ci->iscoreup = brcmf_sdio_sb_iscoreup;
Franky Lin523894f2011-11-10 20:30:22 +0100372 ci->corerev = brcmf_sdio_sb_corerev;
Franky Lin086a2e02011-11-10 20:30:23 +0100373 ci->coredisable = brcmf_sdio_sb_coredisable;
Franky Lin6ca687d2011-11-10 20:30:21 +0100374 break;
375 case SOCI_AI:
376 ci->iscoreup = brcmf_sdio_ai_iscoreup;
Franky Lin523894f2011-11-10 20:30:22 +0100377 ci->corerev = brcmf_sdio_ai_corerev;
Franky Lin086a2e02011-11-10 20:30:23 +0100378 ci->coredisable = brcmf_sdio_ai_coredisable;
Franky Lin6ca687d2011-11-10 20:30:21 +0100379 break;
380 default:
381 brcmf_dbg(ERROR, "socitype %u not supported\n", ci->socitype);
382 return -ENODEV;
383 }
384
Franky Lina83369b2011-11-04 22:23:28 +0100385 return 0;
386}
387
Franky Line63ac6b2011-11-04 22:23:29 +0100388static int
389brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
390{
391 int err = 0;
392 u8 clkval, clkset;
393
394 /* Try forcing SDIO core to do ALPAvail request only */
395 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
396 brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
397 SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
398 if (err) {
399 brcmf_dbg(ERROR, "error writing for HT off\n");
400 return err;
401 }
402
403 /* If register supported, wait for ALPAvail and then force ALP */
404 /* This may take up to 15 milliseconds */
405 clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
406 SBSDIO_FUNC1_CHIPCLKCSR, NULL);
407
408 if ((clkval & ~SBSDIO_AVBITS) != clkset) {
409 brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
410 clkset, clkval);
411 return -EACCES;
412 }
413
414 SPINWAIT(((clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
415 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
416 !SBSDIO_ALPAV(clkval)),
417 PMU_MAX_TRANSITION_DLY);
418 if (!SBSDIO_ALPAV(clkval)) {
419 brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n",
420 clkval);
421 return -EBUSY;
422 }
423
424 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
425 brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
426 SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
427 udelay(65);
428
429 /* Also, disable the extra SDIO pull-ups */
430 brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
431 SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
432
433 return 0;
434}
435
Franky Lin5b45e542011-11-04 22:23:30 +0100436static void
437brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
438 struct chip_info *ci)
439{
440 u32 regdata;
441
442 /* get chipcommon rev */
Franky Lin523894f2011-11-10 20:30:22 +0100443 ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100444
445 /* get chipcommon capabilites */
Franky Lin99ba15c2011-11-04 22:23:42 +0100446 ci->c_inf[0].caps =
447 brcmf_sdcard_reg_read(sdiodev,
448 CORE_CC_REG(ci->c_inf[0].base, capabilities), 4);
Franky Lin5b45e542011-11-04 22:23:30 +0100449
450 /* get pmu caps & rev */
Franky Lin99ba15c2011-11-04 22:23:42 +0100451 if (ci->c_inf[0].caps & CC_CAP_PMU) {
Franky Lin5b45e542011-11-04 22:23:30 +0100452 ci->pmucaps = brcmf_sdcard_reg_read(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100453 CORE_CC_REG(ci->c_inf[0].base, pmucapabilities), 4);
Franky Lin5b45e542011-11-04 22:23:30 +0100454 ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
455 }
456
Franky Lin523894f2011-11-10 20:30:22 +0100457 ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100458 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100459 CORE_SB(ci->c_inf[1].base, sbidhigh), 4);
460 ci->c_inf[1].id = (regdata & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
Franky Lin5b45e542011-11-04 22:23:30 +0100461
462 brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
Franky Lin99ba15c2011-11-04 22:23:42 +0100463 ci->c_inf[0].rev, ci->pmurev,
464 ci->c_inf[1].rev, ci->c_inf[1].id);
Franky Lin966414d2011-11-04 22:23:32 +0100465
466 /*
467 * Make sure any on-chip ARM is off (in case strapping is wrong),
468 * or downloaded code was already running.
469 */
Franky Lin086a2e02011-11-10 20:30:23 +0100470 ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3);
Franky Lin5b45e542011-11-04 22:23:30 +0100471}
472
Franky Lina83369b2011-11-04 22:23:28 +0100473int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
Franky Lina97e4fc2011-11-04 22:23:35 +0100474 struct chip_info **ci_ptr, u32 regs)
Franky Lina83369b2011-11-04 22:23:28 +0100475{
Franky Lina97e4fc2011-11-04 22:23:35 +0100476 int ret;
477 struct chip_info *ci;
478
479 brcmf_dbg(TRACE, "Enter\n");
480
481 /* alloc chip_info_t */
482 ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
483 if (!ci)
484 return -ENOMEM;
Franky Lina83369b2011-11-04 22:23:28 +0100485
Franky Line63ac6b2011-11-04 22:23:29 +0100486 ret = brcmf_sdio_chip_buscoreprep(sdiodev);
487 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100488 goto err;
Franky Line63ac6b2011-11-04 22:23:29 +0100489
Franky Lina83369b2011-11-04 22:23:28 +0100490 ret = brcmf_sdio_chip_recognition(sdiodev, ci, regs);
491 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100492 goto err;
Franky Lina83369b2011-11-04 22:23:28 +0100493
Franky Lin5b45e542011-11-04 22:23:30 +0100494 brcmf_sdio_chip_buscoresetup(sdiodev, ci);
495
Franky Lin960908d2011-11-04 22:23:33 +0100496 brcmf_sdcard_reg_write(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100497 CORE_CC_REG(ci->c_inf[0].base, gpiopullup), 4, 0);
Franky Lin960908d2011-11-04 22:23:33 +0100498 brcmf_sdcard_reg_write(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100499 CORE_CC_REG(ci->c_inf[0].base, gpiopulldown), 4, 0);
Franky Lin960908d2011-11-04 22:23:33 +0100500
Franky Lina97e4fc2011-11-04 22:23:35 +0100501 *ci_ptr = ci;
502 return 0;
503
504err:
505 kfree(ci);
Franky Lina83369b2011-11-04 22:23:28 +0100506 return ret;
507}
Franky Lina8a6c042011-11-04 22:23:39 +0100508
509void
510brcmf_sdio_chip_detach(struct chip_info **ci_ptr)
511{
512 brcmf_dbg(TRACE, "Enter\n");
513
514 kfree(*ci_ptr);
515 *ci_ptr = NULL;
516}
Franky Line12afb62011-11-04 22:23:40 +0100517
518static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len)
519{
520 const char *fmt;
521
522 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
523 snprintf(buf, len, fmt, chipid);
524 return buf;
525}
526
527void
528brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
529 struct chip_info *ci, u32 drivestrength)
530{
531 struct sdiod_drive_str *str_tab = NULL;
532 u32 str_mask = 0;
533 u32 str_shift = 0;
534 char chn[8];
535
Franky Lin99ba15c2011-11-04 22:23:42 +0100536 if (!(ci->c_inf[0].caps & CC_CAP_PMU))
Franky Line12afb62011-11-04 22:23:40 +0100537 return;
538
539 switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
540 case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
541 str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab1;
542 str_mask = 0x30000000;
543 str_shift = 28;
544 break;
545 case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2):
546 case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3):
547 str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab2;
548 str_mask = 0x00003800;
549 str_shift = 11;
550 break;
551 case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8):
552 str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab3;
553 str_mask = 0x00003800;
554 str_shift = 11;
555 break;
556 default:
557 brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
558 brcmf_sdio_chip_name(ci->chip, chn, 8),
559 ci->chiprev, ci->pmurev);
560 break;
561 }
562
563 if (str_tab != NULL) {
564 u32 drivestrength_sel = 0;
565 u32 cc_data_temp;
566 int i;
567
568 for (i = 0; str_tab[i].strength != 0; i++) {
569 if (drivestrength >= str_tab[i].strength) {
570 drivestrength_sel = str_tab[i].sel;
571 break;
572 }
573 }
574
575 brcmf_sdcard_reg_write(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100576 CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
Franky Line12afb62011-11-04 22:23:40 +0100577 4, 1);
578 cc_data_temp = brcmf_sdcard_reg_read(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100579 CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr), 4);
Franky Line12afb62011-11-04 22:23:40 +0100580 cc_data_temp &= ~str_mask;
581 drivestrength_sel <<= str_shift;
582 cc_data_temp |= drivestrength_sel;
583 brcmf_sdcard_reg_write(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100584 CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
Franky Line12afb62011-11-04 22:23:40 +0100585 4, cc_data_temp);
586
587 brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
588 drivestrength, cc_data_temp);
589 }
590}