blob: d4b390c2acfde69c35756fc2e70866aa2c22b770 [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 Linabb7fbb2012-05-04 18:27:28 -070097 CORE_SB(ci->c_inf[idx].base, sbidhigh));
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 Linabb7fbb2012-05-04 18:27:28 -0700122 CORE_SB(ci->c_inf[idx].base, sbtmstatelow));
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,
Franky Linabb7fbb2012-05-04 18:27:28 -0700139 ci->c_inf[idx].wrapbase+BCMA_IOCTL);
Franky Lin6ca687d2011-11-10 20:30:21 +0100140 ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
141
142 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700143 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL);
Franky Lin6ca687d2011-11-10 20:30:21 +0100144 ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
145
146 return ret;
147}
148
Franky Lin086a2e02011-11-10 20:30:23 +0100149static void
150brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
151 struct chip_info *ci, u16 coreid)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100152{
153 u32 regdata;
Franky Lin086a2e02011-11-10 20:30:23 +0100154 u8 idx;
155
156 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100157
158 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700159 CORE_SB(ci->c_inf[idx].base, sbtmstatelow));
Franky Lin61213be2011-11-04 22:23:41 +0100160 if (regdata & SSB_TMSLOW_RESET)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100161 return;
162
163 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700164 CORE_SB(ci->c_inf[idx].base, sbtmstatelow));
Franky Lin61213be2011-11-04 22:23:41 +0100165 if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
Franky Lin2d4a9af2011-11-04 22:23:31 +0100166 /*
167 * set target reject and spin until busy is clear
168 * (preserve core-specific bits)
169 */
170 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700171 CORE_SB(ci->c_inf[idx].base, sbtmstatelow));
Franky Lin086a2e02011-11-10 20:30:23 +0100172 brcmf_sdcard_reg_write(sdiodev,
173 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
Franky Lince454e82012-05-04 18:27:29 -0700174 regdata | SSB_TMSLOW_REJECT);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100175
176 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700177 CORE_SB(ci->c_inf[idx].base, sbtmstatelow));
Franky Lin2d4a9af2011-11-04 22:23:31 +0100178 udelay(1);
179 SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700180 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh)) &
Franky Lin61213be2011-11-04 22:23:41 +0100181 SSB_TMSHIGH_BUSY), 100000);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100182
183 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700184 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh));
Franky Lin61213be2011-11-04 22:23:41 +0100185 if (regdata & SSB_TMSHIGH_BUSY)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100186 brcmf_dbg(ERROR, "core state still busy\n");
187
188 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700189 CORE_SB(ci->c_inf[idx].base, sbidlow));
Franky Lin61213be2011-11-04 22:23:41 +0100190 if (regdata & SSB_IDLOW_INITIATOR) {
Franky Lin2d4a9af2011-11-04 22:23:31 +0100191 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700192 CORE_SB(ci->c_inf[idx].base, sbimstate)) |
Franky Lin61213be2011-11-04 22:23:41 +0100193 SSB_IMSTATE_REJECT;
Franky Lin2d4a9af2011-11-04 22:23:31 +0100194 brcmf_sdcard_reg_write(sdiodev,
Franky Lince454e82012-05-04 18:27:29 -0700195 CORE_SB(ci->c_inf[idx].base, sbimstate),
Franky Lin2d4a9af2011-11-04 22:23:31 +0100196 regdata);
197 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700198 CORE_SB(ci->c_inf[idx].base, sbimstate));
Franky Lin2d4a9af2011-11-04 22:23:31 +0100199 udelay(1);
200 SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700201 CORE_SB(ci->c_inf[idx].base, sbimstate)) &
Franky Lin61213be2011-11-04 22:23:41 +0100202 SSB_IMSTATE_BUSY), 100000);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100203 }
204
205 /* set reset and reject while enabling the clocks */
206 brcmf_sdcard_reg_write(sdiodev,
Franky Lince454e82012-05-04 18:27:29 -0700207 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
Franky Lin61213be2011-11-04 22:23:41 +0100208 (SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
209 SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
Franky Lin2d4a9af2011-11-04 22:23:31 +0100210 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700211 CORE_SB(ci->c_inf[idx].base, sbtmstatelow));
Franky Lin2d4a9af2011-11-04 22:23:31 +0100212 udelay(10);
213
214 /* clear the initiator reject bit */
215 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700216 CORE_SB(ci->c_inf[idx].base, sbidlow));
Franky Lin61213be2011-11-04 22:23:41 +0100217 if (regdata & SSB_IDLOW_INITIATOR) {
Franky Lin2d4a9af2011-11-04 22:23:31 +0100218 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700219 CORE_SB(ci->c_inf[idx].base, sbimstate)) &
Franky Lin61213be2011-11-04 22:23:41 +0100220 ~SSB_IMSTATE_REJECT;
Franky Lin2d4a9af2011-11-04 22:23:31 +0100221 brcmf_sdcard_reg_write(sdiodev,
Franky Lince454e82012-05-04 18:27:29 -0700222 CORE_SB(ci->c_inf[idx].base, sbimstate),
Franky Lin2d4a9af2011-11-04 22:23:31 +0100223 regdata);
224 }
225 }
226
227 /* leave reset and reject asserted */
Franky Lin086a2e02011-11-10 20:30:23 +0100228 brcmf_sdcard_reg_write(sdiodev,
Franky Lince454e82012-05-04 18:27:29 -0700229 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
Franky Lin61213be2011-11-04 22:23:41 +0100230 (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
Franky Lin2d4a9af2011-11-04 22:23:31 +0100231 udelay(1);
232}
233
Franky Lin086a2e02011-11-10 20:30:23 +0100234static void
235brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
236 struct chip_info *ci, u16 coreid)
237{
238 u8 idx;
239 u32 regdata;
240
241 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
242
243 /* if core is already in reset, just return */
244 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700245 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL);
Franky Lin086a2e02011-11-10 20:30:23 +0100246 if ((regdata & BCMA_RESET_CTL_RESET) != 0)
247 return;
248
Franky Lince454e82012-05-04 18:27:29 -0700249 brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, 0);
Franky Lin086a2e02011-11-10 20:30:23 +0100250 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700251 ci->c_inf[idx].wrapbase+BCMA_IOCTL);
Franky Lin086a2e02011-11-10 20:30:23 +0100252 udelay(10);
253
254 brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
Franky Lince454e82012-05-04 18:27:29 -0700255 BCMA_RESET_CTL_RESET);
Franky Lin086a2e02011-11-10 20:30:23 +0100256 udelay(1);
257}
258
Franky Lind77e70f2011-11-10 20:30:24 +0100259static void
260brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
261 struct chip_info *ci, u16 coreid)
Franky Lin2bc78e12011-11-04 22:23:38 +0100262{
263 u32 regdata;
Franky Lin086a2e02011-11-10 20:30:23 +0100264 u8 idx;
265
266 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin2bc78e12011-11-04 22:23:38 +0100267
268 /*
269 * Must do the disable sequence first to work for
270 * arbitrary current core state.
271 */
Franky Lind77e70f2011-11-10 20:30:24 +0100272 brcmf_sdio_sb_coredisable(sdiodev, ci, coreid);
Franky Lin2bc78e12011-11-04 22:23:38 +0100273
274 /*
275 * Now do the initialization sequence.
276 * set reset while enabling the clock and
277 * forcing them on throughout the core
278 */
Franky Lin086a2e02011-11-10 20:30:23 +0100279 brcmf_sdcard_reg_write(sdiodev,
Franky Lince454e82012-05-04 18:27:29 -0700280 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
Franky Lin086a2e02011-11-10 20:30:23 +0100281 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET);
Franky Lind77e70f2011-11-10 20:30:24 +0100282 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700283 CORE_SB(ci->c_inf[idx].base, sbtmstatelow));
Franky Lin2bc78e12011-11-04 22:23:38 +0100284 udelay(1);
285
Franky Lind77e70f2011-11-10 20:30:24 +0100286 /* clear any serror */
Franky Lin2bc78e12011-11-04 22:23:38 +0100287 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700288 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh));
Franky Lin61213be2011-11-04 22:23:41 +0100289 if (regdata & SSB_TMSHIGH_SERR)
Franky Lin2bc78e12011-11-04 22:23:38 +0100290 brcmf_sdcard_reg_write(sdiodev,
Franky Lince454e82012-05-04 18:27:29 -0700291 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 0);
Franky Lin2bc78e12011-11-04 22:23:38 +0100292
293 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700294 CORE_SB(ci->c_inf[idx].base, sbimstate));
Franky Lin61213be2011-11-04 22:23:41 +0100295 if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
Franky Lin086a2e02011-11-10 20:30:23 +0100296 brcmf_sdcard_reg_write(sdiodev,
Franky Lince454e82012-05-04 18:27:29 -0700297 CORE_SB(ci->c_inf[idx].base, sbimstate),
Franky Lin61213be2011-11-04 22:23:41 +0100298 regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO));
Franky Lin2bc78e12011-11-04 22:23:38 +0100299
300 /* clear reset and allow it to propagate throughout the core */
Franky Lin086a2e02011-11-10 20:30:23 +0100301 brcmf_sdcard_reg_write(sdiodev,
Franky Lince454e82012-05-04 18:27:29 -0700302 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
Franky Lin61213be2011-11-04 22:23:41 +0100303 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK);
Franky Lind77e70f2011-11-10 20:30:24 +0100304 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700305 CORE_SB(ci->c_inf[idx].base, sbtmstatelow));
Franky Lin2bc78e12011-11-04 22:23:38 +0100306 udelay(1);
307
308 /* leave clock enabled */
Franky Lin086a2e02011-11-10 20:30:23 +0100309 brcmf_sdcard_reg_write(sdiodev,
310 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
Franky Lince454e82012-05-04 18:27:29 -0700311 SSB_TMSLOW_CLOCK);
Franky Lind77e70f2011-11-10 20:30:24 +0100312 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700313 CORE_SB(ci->c_inf[idx].base, sbtmstatelow));
Franky Lind77e70f2011-11-10 20:30:24 +0100314 udelay(1);
315}
316
317static void
318brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
319 struct chip_info *ci, u16 coreid)
320{
321 u8 idx;
322 u32 regdata;
323
324 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
325
326 /* must disable first to work for arbitrary current core state */
327 brcmf_sdio_ai_coredisable(sdiodev, ci, coreid);
328
329 /* now do initialization sequence */
330 brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
Franky Lince454e82012-05-04 18:27:29 -0700331 BCMA_IOCTL_FGC | BCMA_IOCTL_CLK);
Franky Lind77e70f2011-11-10 20:30:24 +0100332 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700333 ci->c_inf[idx].wrapbase+BCMA_IOCTL);
Franky Lind77e70f2011-11-10 20:30:24 +0100334 brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
Franky Lince454e82012-05-04 18:27:29 -0700335 0);
Franky Lind77e70f2011-11-10 20:30:24 +0100336 udelay(1);
337
338 brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
Franky Lince454e82012-05-04 18:27:29 -0700339 BCMA_IOCTL_CLK);
Franky Lind77e70f2011-11-10 20:30:24 +0100340 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700341 ci->c_inf[idx].wrapbase+BCMA_IOCTL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100342 udelay(1);
343}
344
Franky Lina83369b2011-11-04 22:23:28 +0100345static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
346 struct chip_info *ci, u32 regs)
347{
348 u32 regdata;
349
350 /*
351 * Get CC core rev
352 * Chipid is assume to be at offset 0 from regs arg
353 * For different chiptypes or old sdio hosts w/o chipcommon,
354 * other ways of recognition should be added here.
355 */
Franky Lin99ba15c2011-11-04 22:23:42 +0100356 ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
357 ci->c_inf[0].base = regs;
Franky Lina83369b2011-11-04 22:23:28 +0100358 regdata = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700359 CORE_CC_REG(ci->c_inf[0].base, chipid));
Franky Lina83369b2011-11-04 22:23:28 +0100360 ci->chip = regdata & CID_ID_MASK;
361 ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
Franky Lin6ca687d2011-11-10 20:30:21 +0100362 ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
Franky Lina83369b2011-11-04 22:23:28 +0100363
364 brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
365
366 /* Address of cores for new chips should be added here */
367 switch (ci->chip) {
368 case BCM4329_CHIP_ID:
Franky Lin99ba15c2011-11-04 22:23:42 +0100369 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
370 ci->c_inf[1].base = BCM4329_CORE_BUS_BASE;
371 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
372 ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE;
373 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
374 ci->c_inf[3].base = BCM4329_CORE_ARM_BASE;
Franky Lina83369b2011-11-04 22:23:28 +0100375 ci->ramsize = BCM4329_RAMSIZE;
376 break;
Franky Lince2d7d72011-12-08 15:06:39 -0800377 case BCM4330_CHIP_ID:
378 ci->c_inf[0].wrapbase = 0x18100000;
379 ci->c_inf[0].cib = 0x27004211;
380 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
381 ci->c_inf[1].base = 0x18002000;
382 ci->c_inf[1].wrapbase = 0x18102000;
383 ci->c_inf[1].cib = 0x07004211;
384 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
385 ci->c_inf[2].base = 0x18004000;
386 ci->c_inf[2].wrapbase = 0x18104000;
387 ci->c_inf[2].cib = 0x0d080401;
388 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
389 ci->c_inf[3].base = 0x18003000;
390 ci->c_inf[3].wrapbase = 0x18103000;
391 ci->c_inf[3].cib = 0x03004211;
392 ci->ramsize = 0x48000;
393 break;
Franky Lina83369b2011-11-04 22:23:28 +0100394 default:
395 brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip);
396 return -ENODEV;
397 }
398
Franky Lin6ca687d2011-11-10 20:30:21 +0100399 switch (ci->socitype) {
400 case SOCI_SB:
401 ci->iscoreup = brcmf_sdio_sb_iscoreup;
Franky Lin523894f2011-11-10 20:30:22 +0100402 ci->corerev = brcmf_sdio_sb_corerev;
Franky Lin086a2e02011-11-10 20:30:23 +0100403 ci->coredisable = brcmf_sdio_sb_coredisable;
Franky Lind77e70f2011-11-10 20:30:24 +0100404 ci->resetcore = brcmf_sdio_sb_resetcore;
Franky Lin6ca687d2011-11-10 20:30:21 +0100405 break;
406 case SOCI_AI:
407 ci->iscoreup = brcmf_sdio_ai_iscoreup;
Franky Lin523894f2011-11-10 20:30:22 +0100408 ci->corerev = brcmf_sdio_ai_corerev;
Franky Lin086a2e02011-11-10 20:30:23 +0100409 ci->coredisable = brcmf_sdio_ai_coredisable;
Franky Lind77e70f2011-11-10 20:30:24 +0100410 ci->resetcore = brcmf_sdio_ai_resetcore;
Franky Lin6ca687d2011-11-10 20:30:21 +0100411 break;
412 default:
413 brcmf_dbg(ERROR, "socitype %u not supported\n", ci->socitype);
414 return -ENODEV;
415 }
416
Franky Lina83369b2011-11-04 22:23:28 +0100417 return 0;
418}
419
Franky Line63ac6b2011-11-04 22:23:29 +0100420static int
421brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
422{
423 int err = 0;
424 u8 clkval, clkset;
425
426 /* Try forcing SDIO core to do ALPAvail request only */
427 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
Franky Lin3bba8292012-05-04 18:27:33 -0700428 brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
Franky Line63ac6b2011-11-04 22:23:29 +0100429 if (err) {
430 brcmf_dbg(ERROR, "error writing for HT off\n");
431 return err;
432 }
433
434 /* If register supported, wait for ALPAvail and then force ALP */
435 /* This may take up to 15 milliseconds */
Franky Lin45db3392012-05-04 18:27:32 -0700436 clkval = brcmf_sdio_regrb(sdiodev,
437 SBSDIO_FUNC1_CHIPCLKCSR, NULL);
Franky Line63ac6b2011-11-04 22:23:29 +0100438
439 if ((clkval & ~SBSDIO_AVBITS) != clkset) {
440 brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
441 clkset, clkval);
442 return -EACCES;
443 }
444
Franky Lin45db3392012-05-04 18:27:32 -0700445 SPINWAIT(((clkval = brcmf_sdio_regrb(sdiodev,
446 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
Franky Line63ac6b2011-11-04 22:23:29 +0100447 !SBSDIO_ALPAV(clkval)),
448 PMU_MAX_TRANSITION_DLY);
449 if (!SBSDIO_ALPAV(clkval)) {
450 brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n",
451 clkval);
452 return -EBUSY;
453 }
454
455 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
Franky Lin3bba8292012-05-04 18:27:33 -0700456 brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
Franky Line63ac6b2011-11-04 22:23:29 +0100457 udelay(65);
458
459 /* Also, disable the extra SDIO pull-ups */
Franky Lin3bba8292012-05-04 18:27:33 -0700460 brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
Franky Line63ac6b2011-11-04 22:23:29 +0100461
462 return 0;
463}
464
Franky Lin5b45e542011-11-04 22:23:30 +0100465static void
466brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
467 struct chip_info *ci)
468{
Franky Lin5b45e542011-11-04 22:23:30 +0100469 /* get chipcommon rev */
Franky Lin523894f2011-11-10 20:30:22 +0100470 ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100471
472 /* get chipcommon capabilites */
Franky Lin99ba15c2011-11-04 22:23:42 +0100473 ci->c_inf[0].caps =
474 brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700475 CORE_CC_REG(ci->c_inf[0].base, capabilities));
Franky Lin5b45e542011-11-04 22:23:30 +0100476
477 /* get pmu caps & rev */
Franky Lin99ba15c2011-11-04 22:23:42 +0100478 if (ci->c_inf[0].caps & CC_CAP_PMU) {
Franky Lin5b45e542011-11-04 22:23:30 +0100479 ci->pmucaps = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700480 CORE_CC_REG(ci->c_inf[0].base, pmucapabilities));
Franky Lin5b45e542011-11-04 22:23:30 +0100481 ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
482 }
483
Franky Lin523894f2011-11-10 20:30:22 +0100484 ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100485
486 brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
Franky Lin99ba15c2011-11-04 22:23:42 +0100487 ci->c_inf[0].rev, ci->pmurev,
488 ci->c_inf[1].rev, ci->c_inf[1].id);
Franky Lin966414d2011-11-04 22:23:32 +0100489
490 /*
491 * Make sure any on-chip ARM is off (in case strapping is wrong),
492 * or downloaded code was already running.
493 */
Franky Lin086a2e02011-11-10 20:30:23 +0100494 ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3);
Franky Lin5b45e542011-11-04 22:23:30 +0100495}
496
Franky Lina83369b2011-11-04 22:23:28 +0100497int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
Franky Lina97e4fc2011-11-04 22:23:35 +0100498 struct chip_info **ci_ptr, u32 regs)
Franky Lina83369b2011-11-04 22:23:28 +0100499{
Franky Lina97e4fc2011-11-04 22:23:35 +0100500 int ret;
501 struct chip_info *ci;
502
503 brcmf_dbg(TRACE, "Enter\n");
504
505 /* alloc chip_info_t */
506 ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
507 if (!ci)
508 return -ENOMEM;
Franky Lina83369b2011-11-04 22:23:28 +0100509
Franky Line63ac6b2011-11-04 22:23:29 +0100510 ret = brcmf_sdio_chip_buscoreprep(sdiodev);
511 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100512 goto err;
Franky Line63ac6b2011-11-04 22:23:29 +0100513
Franky Lina83369b2011-11-04 22:23:28 +0100514 ret = brcmf_sdio_chip_recognition(sdiodev, ci, regs);
515 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100516 goto err;
Franky Lina83369b2011-11-04 22:23:28 +0100517
Franky Lin5b45e542011-11-04 22:23:30 +0100518 brcmf_sdio_chip_buscoresetup(sdiodev, ci);
519
Franky Lin960908d2011-11-04 22:23:33 +0100520 brcmf_sdcard_reg_write(sdiodev,
Franky Lince454e82012-05-04 18:27:29 -0700521 CORE_CC_REG(ci->c_inf[0].base, gpiopullup), 0);
Franky Lin960908d2011-11-04 22:23:33 +0100522 brcmf_sdcard_reg_write(sdiodev,
Franky Lince454e82012-05-04 18:27:29 -0700523 CORE_CC_REG(ci->c_inf[0].base, gpiopulldown), 0);
Franky Lin960908d2011-11-04 22:23:33 +0100524
Franky Lina97e4fc2011-11-04 22:23:35 +0100525 *ci_ptr = ci;
526 return 0;
527
528err:
529 kfree(ci);
Franky Lina83369b2011-11-04 22:23:28 +0100530 return ret;
531}
Franky Lina8a6c042011-11-04 22:23:39 +0100532
533void
534brcmf_sdio_chip_detach(struct chip_info **ci_ptr)
535{
536 brcmf_dbg(TRACE, "Enter\n");
537
538 kfree(*ci_ptr);
539 *ci_ptr = NULL;
540}
Franky Line12afb62011-11-04 22:23:40 +0100541
542static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len)
543{
544 const char *fmt;
545
546 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
547 snprintf(buf, len, fmt, chipid);
548 return buf;
549}
550
551void
552brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
553 struct chip_info *ci, u32 drivestrength)
554{
555 struct sdiod_drive_str *str_tab = NULL;
556 u32 str_mask = 0;
557 u32 str_shift = 0;
558 char chn[8];
559
Franky Lin99ba15c2011-11-04 22:23:42 +0100560 if (!(ci->c_inf[0].caps & CC_CAP_PMU))
Franky Line12afb62011-11-04 22:23:40 +0100561 return;
562
563 switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
Franky Lince2d7d72011-12-08 15:06:39 -0800564 case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12):
Franky Linffb27562011-12-08 15:06:40 -0800565 str_tab = (struct sdiod_drive_str *)&sdiod_drvstr_tab1_1v8;
Franky Lince2d7d72011-12-08 15:06:39 -0800566 str_mask = 0x00003800;
567 str_shift = 11;
568 break;
Franky Line12afb62011-11-04 22:23:40 +0100569 default:
570 brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
571 brcmf_sdio_chip_name(ci->chip, chn, 8),
572 ci->chiprev, ci->pmurev);
573 break;
574 }
575
576 if (str_tab != NULL) {
577 u32 drivestrength_sel = 0;
578 u32 cc_data_temp;
579 int i;
580
581 for (i = 0; str_tab[i].strength != 0; i++) {
582 if (drivestrength >= str_tab[i].strength) {
583 drivestrength_sel = str_tab[i].sel;
584 break;
585 }
586 }
587
588 brcmf_sdcard_reg_write(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100589 CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
Franky Lince454e82012-05-04 18:27:29 -0700590 1);
Franky Line12afb62011-11-04 22:23:40 +0100591 cc_data_temp = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700592 CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr));
Franky Line12afb62011-11-04 22:23:40 +0100593 cc_data_temp &= ~str_mask;
594 drivestrength_sel <<= str_shift;
595 cc_data_temp |= drivestrength_sel;
596 brcmf_sdcard_reg_write(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100597 CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
Franky Lince454e82012-05-04 18:27:29 -0700598 cc_data_temp);
Franky Line12afb62011-11-04 22:23:40 +0100599
600 brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
601 drivestrength, cc_data_temp);
602 }
603}