blob: 654b7e032b273774b51cdd20e7f885c5232e6af7 [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;
428 brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
429 SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
430 if (err) {
431 brcmf_dbg(ERROR, "error writing for HT off\n");
432 return err;
433 }
434
435 /* If register supported, wait for ALPAvail and then force ALP */
436 /* This may take up to 15 milliseconds */
Franky Lin45db3392012-05-04 18:27:32 -0700437 clkval = brcmf_sdio_regrb(sdiodev,
438 SBSDIO_FUNC1_CHIPCLKCSR, NULL);
Franky Line63ac6b2011-11-04 22:23:29 +0100439
440 if ((clkval & ~SBSDIO_AVBITS) != clkset) {
441 brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
442 clkset, clkval);
443 return -EACCES;
444 }
445
Franky Lin45db3392012-05-04 18:27:32 -0700446 SPINWAIT(((clkval = brcmf_sdio_regrb(sdiodev,
447 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
Franky Line63ac6b2011-11-04 22:23:29 +0100448 !SBSDIO_ALPAV(clkval)),
449 PMU_MAX_TRANSITION_DLY);
450 if (!SBSDIO_ALPAV(clkval)) {
451 brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n",
452 clkval);
453 return -EBUSY;
454 }
455
456 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
457 brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
458 SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
459 udelay(65);
460
461 /* Also, disable the extra SDIO pull-ups */
462 brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
463 SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
464
465 return 0;
466}
467
Franky Lin5b45e542011-11-04 22:23:30 +0100468static void
469brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
470 struct chip_info *ci)
471{
Franky Lin5b45e542011-11-04 22:23:30 +0100472 /* get chipcommon rev */
Franky Lin523894f2011-11-10 20:30:22 +0100473 ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100474
475 /* get chipcommon capabilites */
Franky Lin99ba15c2011-11-04 22:23:42 +0100476 ci->c_inf[0].caps =
477 brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700478 CORE_CC_REG(ci->c_inf[0].base, capabilities));
Franky Lin5b45e542011-11-04 22:23:30 +0100479
480 /* get pmu caps & rev */
Franky Lin99ba15c2011-11-04 22:23:42 +0100481 if (ci->c_inf[0].caps & CC_CAP_PMU) {
Franky Lin5b45e542011-11-04 22:23:30 +0100482 ci->pmucaps = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700483 CORE_CC_REG(ci->c_inf[0].base, pmucapabilities));
Franky Lin5b45e542011-11-04 22:23:30 +0100484 ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
485 }
486
Franky Lin523894f2011-11-10 20:30:22 +0100487 ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100488
489 brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
Franky Lin99ba15c2011-11-04 22:23:42 +0100490 ci->c_inf[0].rev, ci->pmurev,
491 ci->c_inf[1].rev, ci->c_inf[1].id);
Franky Lin966414d2011-11-04 22:23:32 +0100492
493 /*
494 * Make sure any on-chip ARM is off (in case strapping is wrong),
495 * or downloaded code was already running.
496 */
Franky Lin086a2e02011-11-10 20:30:23 +0100497 ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3);
Franky Lin5b45e542011-11-04 22:23:30 +0100498}
499
Franky Lina83369b2011-11-04 22:23:28 +0100500int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
Franky Lina97e4fc2011-11-04 22:23:35 +0100501 struct chip_info **ci_ptr, u32 regs)
Franky Lina83369b2011-11-04 22:23:28 +0100502{
Franky Lina97e4fc2011-11-04 22:23:35 +0100503 int ret;
504 struct chip_info *ci;
505
506 brcmf_dbg(TRACE, "Enter\n");
507
508 /* alloc chip_info_t */
509 ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
510 if (!ci)
511 return -ENOMEM;
Franky Lina83369b2011-11-04 22:23:28 +0100512
Franky Line63ac6b2011-11-04 22:23:29 +0100513 ret = brcmf_sdio_chip_buscoreprep(sdiodev);
514 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100515 goto err;
Franky Line63ac6b2011-11-04 22:23:29 +0100516
Franky Lina83369b2011-11-04 22:23:28 +0100517 ret = brcmf_sdio_chip_recognition(sdiodev, ci, regs);
518 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100519 goto err;
Franky Lina83369b2011-11-04 22:23:28 +0100520
Franky Lin5b45e542011-11-04 22:23:30 +0100521 brcmf_sdio_chip_buscoresetup(sdiodev, ci);
522
Franky Lin960908d2011-11-04 22:23:33 +0100523 brcmf_sdcard_reg_write(sdiodev,
Franky Lince454e82012-05-04 18:27:29 -0700524 CORE_CC_REG(ci->c_inf[0].base, gpiopullup), 0);
Franky Lin960908d2011-11-04 22:23:33 +0100525 brcmf_sdcard_reg_write(sdiodev,
Franky Lince454e82012-05-04 18:27:29 -0700526 CORE_CC_REG(ci->c_inf[0].base, gpiopulldown), 0);
Franky Lin960908d2011-11-04 22:23:33 +0100527
Franky Lina97e4fc2011-11-04 22:23:35 +0100528 *ci_ptr = ci;
529 return 0;
530
531err:
532 kfree(ci);
Franky Lina83369b2011-11-04 22:23:28 +0100533 return ret;
534}
Franky Lina8a6c042011-11-04 22:23:39 +0100535
536void
537brcmf_sdio_chip_detach(struct chip_info **ci_ptr)
538{
539 brcmf_dbg(TRACE, "Enter\n");
540
541 kfree(*ci_ptr);
542 *ci_ptr = NULL;
543}
Franky Line12afb62011-11-04 22:23:40 +0100544
545static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len)
546{
547 const char *fmt;
548
549 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
550 snprintf(buf, len, fmt, chipid);
551 return buf;
552}
553
554void
555brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
556 struct chip_info *ci, u32 drivestrength)
557{
558 struct sdiod_drive_str *str_tab = NULL;
559 u32 str_mask = 0;
560 u32 str_shift = 0;
561 char chn[8];
562
Franky Lin99ba15c2011-11-04 22:23:42 +0100563 if (!(ci->c_inf[0].caps & CC_CAP_PMU))
Franky Line12afb62011-11-04 22:23:40 +0100564 return;
565
566 switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
Franky Lince2d7d72011-12-08 15:06:39 -0800567 case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12):
Franky Linffb27562011-12-08 15:06:40 -0800568 str_tab = (struct sdiod_drive_str *)&sdiod_drvstr_tab1_1v8;
Franky Lince2d7d72011-12-08 15:06:39 -0800569 str_mask = 0x00003800;
570 str_shift = 11;
571 break;
Franky Line12afb62011-11-04 22:23:40 +0100572 default:
573 brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
574 brcmf_sdio_chip_name(ci->chip, chn, 8),
575 ci->chiprev, ci->pmurev);
576 break;
577 }
578
579 if (str_tab != NULL) {
580 u32 drivestrength_sel = 0;
581 u32 cc_data_temp;
582 int i;
583
584 for (i = 0; str_tab[i].strength != 0; i++) {
585 if (drivestrength >= str_tab[i].strength) {
586 drivestrength_sel = str_tab[i].sel;
587 break;
588 }
589 }
590
591 brcmf_sdcard_reg_write(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100592 CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
Franky Lince454e82012-05-04 18:27:29 -0700593 1);
Franky Line12afb62011-11-04 22:23:40 +0100594 cc_data_temp = brcmf_sdcard_reg_read(sdiodev,
Franky Linabb7fbb2012-05-04 18:27:28 -0700595 CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr));
Franky Line12afb62011-11-04 22:23:40 +0100596 cc_data_temp &= ~str_mask;
597 drivestrength_sel <<= str_shift;
598 cc_data_temp |= drivestrength_sel;
599 brcmf_sdcard_reg_write(sdiodev,
Franky Lin99ba15c2011-11-04 22:23:42 +0100600 CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
Franky Lince454e82012-05-04 18:27:29 -0700601 cc_data_temp);
Franky Line12afb62011-11-04 22:23:40 +0100602
603 brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
604 drivestrength, cc_data_temp);
605 }
606}