blob: d1de037994cb139ab0581c25d2a368a9be7df219 [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 Linfe040152013-09-25 13:05:41 +020021#include <linux/mmc/sdio_func.h>
Arend van Spriel6e08d752014-01-06 12:40:50 +010022#include <linux/mmc/sdio_ids.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
Hante Meuleman369508c2013-04-11 13:28:54 +020045/* bcm43143 */
46/* SDIO device core */
47#define BCM43143_CORE_BUS_BASE 0x18002000
48/* internal memory core */
49#define BCM43143_CORE_SOCRAM_BASE 0x18004000
50/* ARM Cortex M3 core, ID 0x82a */
51#define BCM43143_CORE_ARM_BASE 0x18003000
52#define BCM43143_RAMSIZE 0x70000
53
Hante Meuleman53036262014-01-13 22:20:23 +010054/* All D11 cores, ID 0x812 */
55#define BCM43xx_CORE_D11_BASE 0x18001000
56
Franky Lina83369b2011-11-04 22:23:28 +010057#define SBCOREREV(sbidh) \
Franky Lin61213be2011-11-04 22:23:41 +010058 ((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \
59 ((sbidh) & SSB_IDHIGH_RCLO))
Franky Lina83369b2011-11-04 22:23:28 +010060
Franky Lin6ca687d2011-11-10 20:30:21 +010061/* SOC Interconnect types (aka chip types) */
62#define SOCI_SB 0
63#define SOCI_AI 1
64
Franky Lin523894f2011-11-10 20:30:22 +010065/* EROM CompIdentB */
66#define CIB_REV_MASK 0xff000000
67#define CIB_REV_SHIFT 24
68
Franky Lin1640f282013-04-11 13:28:51 +020069/* ARM CR4 core specific control flag bits */
70#define ARMCR4_BCMA_IOCTL_CPUHALT 0x0020
71
Hante Meuleman53036262014-01-13 22:20:23 +010072/* D11 core specific control flag bits */
73#define D11_BCMA_IOCTL_PHYCLOCKEN 0x0004
74#define D11_BCMA_IOCTL_PHYRESET 0x0008
75
Franky Line12afb62011-11-04 22:23:40 +010076#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
77/* SDIO Pad drive strength to select value mappings */
78struct sdiod_drive_str {
79 u8 strength; /* Pad Drive Strength in mA */
80 u8 sel; /* Chip-specific select value */
81};
Franky Lince2d7d72011-12-08 15:06:39 -080082/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8V) */
Franky Linffb27562011-12-08 15:06:40 -080083static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = {
Franky Lince2d7d72011-12-08 15:06:39 -080084 {32, 0x6},
85 {26, 0x7},
86 {22, 0x4},
87 {16, 0x5},
88 {12, 0x2},
89 {8, 0x3},
90 {4, 0x0},
91 {0, 0x1}
92};
93
Arend van Spriel11e69c32014-01-08 10:49:33 +010094/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */
95static const struct sdiod_drive_str sdiod_drive_strength_tab5_1v8[] = {
96 {6, 0x7},
97 {5, 0x6},
98 {4, 0x5},
99 {3, 0x4},
100 {2, 0x2},
101 {1, 0x1},
102 {0, 0x0}
103};
104
Arend van Sprielaf35f552014-01-06 12:40:42 +0100105/* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */
106static const struct sdiod_drive_str sdiod_drvstr_tab6_1v8[] = {
107 {3, 0x3},
108 {2, 0x2},
109 {1, 0x1},
110 {0, 0x0} };
111
Hante Meuleman979c2922013-04-11 13:28:55 +0200112/* SDIO Drive Strength to sel value table for 43143 PMU Rev 17 (3.3V) */
113static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = {
114 {16, 0x7},
115 {12, 0x5},
116 {8, 0x3},
117 {4, 0x1}
118};
119
Franky Lin99ba15c2011-11-04 22:23:42 +0100120u8
121brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid)
122{
123 u8 idx;
124
125 for (idx = 0; idx < BRCMF_MAX_CORENUM; idx++)
126 if (coreid == ci->c_inf[idx].id)
127 return idx;
128
129 return BRCMF_MAX_CORENUM;
130}
131
Franky Lin454d2a82011-11-04 22:23:37 +0100132static u32
Franky Lin523894f2011-11-10 20:30:22 +0100133brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
134 struct chip_info *ci, u16 coreid)
Franky Lin454d2a82011-11-04 22:23:37 +0100135{
136 u32 regdata;
Franky Lin523894f2011-11-10 20:30:22 +0100137 u8 idx;
138
139 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin454d2a82011-11-04 22:23:37 +0100140
Arend van Spriela39be272013-12-12 11:58:58 +0100141 regdata = brcmf_sdiod_regrl(sdiodev,
142 CORE_SB(ci->c_inf[idx].base, sbidhigh),
143 NULL);
Franky Lin454d2a82011-11-04 22:23:37 +0100144 return SBCOREREV(regdata);
145}
146
Franky Lin523894f2011-11-10 20:30:22 +0100147static u32
148brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev,
149 struct chip_info *ci, u16 coreid)
150{
151 u8 idx;
152
153 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
154
155 return (ci->c_inf[idx].cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
156}
157
Franky Lin6ca687d2011-11-10 20:30:21 +0100158static bool
159brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
160 struct chip_info *ci, u16 coreid)
Franky Lind8f64a42011-11-04 22:23:36 +0100161{
162 u32 regdata;
Franky Lin6ca687d2011-11-10 20:30:21 +0100163 u8 idx;
164
165 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200166 if (idx == BRCMF_MAX_CORENUM)
167 return false;
Franky Lind8f64a42011-11-04 22:23:36 +0100168
Arend van Spriela39be272013-12-12 11:58:58 +0100169 regdata = brcmf_sdiod_regrl(sdiodev,
170 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
171 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100172 regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
173 SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
174 return (SSB_TMSLOW_CLOCK == regdata);
Franky Lind8f64a42011-11-04 22:23:36 +0100175}
176
Franky Lin6ca687d2011-11-10 20:30:21 +0100177static bool
178brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
179 struct chip_info *ci, u16 coreid)
180{
181 u32 regdata;
182 u8 idx;
183 bool ret;
184
185 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200186 if (idx == BRCMF_MAX_CORENUM)
187 return false;
Franky Lin6ca687d2011-11-10 20:30:21 +0100188
Arend van Spriela39be272013-12-12 11:58:58 +0100189 regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
190 NULL);
Franky Lin6ca687d2011-11-10 20:30:21 +0100191 ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
192
Arend van Spriela39be272013-12-12 11:58:58 +0100193 regdata = brcmf_sdiod_regrl(sdiodev,
194 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
195 NULL);
Franky Lin6ca687d2011-11-10 20:30:21 +0100196 ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
197
198 return ret;
199}
200
Franky Lin086a2e02011-11-10 20:30:23 +0100201static void
202brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
Hante Meuleman53036262014-01-13 22:20:23 +0100203 struct chip_info *ci, u16 coreid, u32 pre_resetbits,
204 u32 in_resetbits)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100205{
Franky Lin79ae3952012-05-04 18:27:34 -0700206 u32 regdata, base;
Franky Lin086a2e02011-11-10 20:30:23 +0100207 u8 idx;
208
209 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin79ae3952012-05-04 18:27:34 -0700210 base = ci->c_inf[idx].base;
Franky Lin2d4a9af2011-11-04 22:23:31 +0100211
Arend van Spriela39be272013-12-12 11:58:58 +0100212 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100213 if (regdata & SSB_TMSLOW_RESET)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100214 return;
215
Arend van Spriela39be272013-12-12 11:58:58 +0100216 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100217 if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
Franky Lin2d4a9af2011-11-04 22:23:31 +0100218 /*
219 * set target reject and spin until busy is clear
220 * (preserve core-specific bits)
221 */
Arend van Spriela39be272013-12-12 11:58:58 +0100222 regdata = brcmf_sdiod_regrl(sdiodev,
223 CORE_SB(base, sbtmstatelow), NULL);
224 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
225 regdata | SSB_TMSLOW_REJECT, NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100226
Arend van Spriela39be272013-12-12 11:58:58 +0100227 regdata = brcmf_sdiod_regrl(sdiodev,
228 CORE_SB(base, sbtmstatelow), NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100229 udelay(1);
Arend van Spriela39be272013-12-12 11:58:58 +0100230 SPINWAIT((brcmf_sdiod_regrl(sdiodev,
231 CORE_SB(base, sbtmstatehigh),
232 NULL) &
233 SSB_TMSHIGH_BUSY), 100000);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100234
Arend van Spriela39be272013-12-12 11:58:58 +0100235 regdata = brcmf_sdiod_regrl(sdiodev,
236 CORE_SB(base, sbtmstatehigh),
237 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100238 if (regdata & SSB_TMSHIGH_BUSY)
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100239 brcmf_err("core state still busy\n");
Franky Lin2d4a9af2011-11-04 22:23:31 +0100240
Arend van Spriela39be272013-12-12 11:58:58 +0100241 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow),
242 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100243 if (regdata & SSB_IDLOW_INITIATOR) {
Arend van Spriela39be272013-12-12 11:58:58 +0100244 regdata = brcmf_sdiod_regrl(sdiodev,
245 CORE_SB(base, sbimstate),
246 NULL);
Franky Lin79ae3952012-05-04 18:27:34 -0700247 regdata |= SSB_IMSTATE_REJECT;
Arend van Spriela39be272013-12-12 11:58:58 +0100248 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate),
249 regdata, NULL);
250 regdata = brcmf_sdiod_regrl(sdiodev,
251 CORE_SB(base, sbimstate),
252 NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100253 udelay(1);
Arend van Spriela39be272013-12-12 11:58:58 +0100254 SPINWAIT((brcmf_sdiod_regrl(sdiodev,
255 CORE_SB(base, sbimstate),
256 NULL) &
257 SSB_IMSTATE_BUSY), 100000);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100258 }
259
260 /* set reset and reject while enabling the clocks */
Franky Line13ce262012-05-04 18:27:35 -0700261 regdata = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
262 SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET;
Arend van Spriela39be272013-12-12 11:58:58 +0100263 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
264 regdata, NULL);
265 regdata = brcmf_sdiod_regrl(sdiodev,
266 CORE_SB(base, sbtmstatelow), NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100267 udelay(10);
268
269 /* clear the initiator reject bit */
Arend van Spriela39be272013-12-12 11:58:58 +0100270 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow),
271 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100272 if (regdata & SSB_IDLOW_INITIATOR) {
Arend van Spriela39be272013-12-12 11:58:58 +0100273 regdata = brcmf_sdiod_regrl(sdiodev,
274 CORE_SB(base, sbimstate),
275 NULL);
Franky Lin79ae3952012-05-04 18:27:34 -0700276 regdata &= ~SSB_IMSTATE_REJECT;
Arend van Spriela39be272013-12-12 11:58:58 +0100277 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate),
278 regdata, NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100279 }
280 }
281
282 /* leave reset and reject asserted */
Arend van Spriela39be272013-12-12 11:58:58 +0100283 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
284 (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET), NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100285 udelay(1);
286}
287
Franky Lin086a2e02011-11-10 20:30:23 +0100288static void
289brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
Hante Meuleman53036262014-01-13 22:20:23 +0100290 struct chip_info *ci, u16 coreid, u32 pre_resetbits,
291 u32 in_resetbits)
Franky Lin086a2e02011-11-10 20:30:23 +0100292{
293 u8 idx;
294 u32 regdata;
Hante Meuleman53036262014-01-13 22:20:23 +0100295 u32 wrapbase;
Franky Lin086a2e02011-11-10 20:30:23 +0100296
297 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200298 if (idx == BRCMF_MAX_CORENUM)
299 return;
Franky Lin086a2e02011-11-10 20:30:23 +0100300
Hante Meuleman53036262014-01-13 22:20:23 +0100301 wrapbase = ci->c_inf[idx].wrapbase;
302
Franky Lin086a2e02011-11-10 20:30:23 +0100303 /* if core is already in reset, just return */
Hante Meuleman53036262014-01-13 22:20:23 +0100304 regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_RESET_CTL, NULL);
Franky Lin086a2e02011-11-10 20:30:23 +0100305 if ((regdata & BCMA_RESET_CTL_RESET) != 0)
306 return;
307
Hante Meuleman53036262014-01-13 22:20:23 +0100308 /* configure reset */
309 brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_IOCTL, pre_resetbits |
310 BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
311 regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL);
Franky Lin086a2e02011-11-10 20:30:23 +0100312
Hante Meuleman53036262014-01-13 22:20:23 +0100313 /* put in reset */
314 brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_RESET_CTL,
Arend van Spriela39be272013-12-12 11:58:58 +0100315 BCMA_RESET_CTL_RESET, NULL);
Franky Lin1640f282013-04-11 13:28:51 +0200316 usleep_range(10, 20);
317
Hante Meuleman53036262014-01-13 22:20:23 +0100318 /* wait till reset is 1 */
319 SPINWAIT(brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_RESET_CTL, NULL) !=
320 BCMA_RESET_CTL_RESET, 300);
321
322 /* post reset configure */
323 brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_IOCTL, pre_resetbits |
324 BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
325 regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL);
Franky Lin086a2e02011-11-10 20:30:23 +0100326}
327
Franky Lind77e70f2011-11-10 20:30:24 +0100328static void
329brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
Hante Meuleman53036262014-01-13 22:20:23 +0100330 struct chip_info *ci, u16 coreid, u32 pre_resetbits,
331 u32 in_resetbits, u32 post_resetbits)
Franky Lin2bc78e12011-11-04 22:23:38 +0100332{
333 u32 regdata;
Franky Lin086a2e02011-11-10 20:30:23 +0100334 u8 idx;
335
336 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200337 if (idx == BRCMF_MAX_CORENUM)
338 return;
Franky Lin2bc78e12011-11-04 22:23:38 +0100339
340 /*
341 * Must do the disable sequence first to work for
342 * arbitrary current core state.
343 */
Hante Meuleman53036262014-01-13 22:20:23 +0100344 brcmf_sdio_sb_coredisable(sdiodev, ci, coreid, pre_resetbits,
345 in_resetbits);
Franky Lin2bc78e12011-11-04 22:23:38 +0100346
347 /*
348 * Now do the initialization sequence.
349 * set reset while enabling the clock and
350 * forcing them on throughout the core
351 */
Arend van Spriela39be272013-12-12 11:58:58 +0100352 brcmf_sdiod_regwl(sdiodev,
353 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
354 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET,
355 NULL);
356 regdata = brcmf_sdiod_regrl(sdiodev,
357 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
358 NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100359 udelay(1);
360
Franky Lind77e70f2011-11-10 20:30:24 +0100361 /* clear any serror */
Arend van Spriela39be272013-12-12 11:58:58 +0100362 regdata = brcmf_sdiod_regrl(sdiodev,
363 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
364 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100365 if (regdata & SSB_TMSHIGH_SERR)
Arend van Spriela39be272013-12-12 11:58:58 +0100366 brcmf_sdiod_regwl(sdiodev,
367 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
368 0, NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100369
Arend van Spriela39be272013-12-12 11:58:58 +0100370 regdata = brcmf_sdiod_regrl(sdiodev,
371 CORE_SB(ci->c_inf[idx].base, sbimstate),
372 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100373 if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
Arend van Spriela39be272013-12-12 11:58:58 +0100374 brcmf_sdiod_regwl(sdiodev,
375 CORE_SB(ci->c_inf[idx].base, sbimstate),
376 regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO),
377 NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100378
379 /* clear reset and allow it to propagate throughout the core */
Arend van Spriela39be272013-12-12 11:58:58 +0100380 brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
381 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK, NULL);
382 regdata = brcmf_sdiod_regrl(sdiodev,
383 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
384 NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100385 udelay(1);
386
387 /* leave clock enabled */
Arend van Spriela39be272013-12-12 11:58:58 +0100388 brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
389 SSB_TMSLOW_CLOCK, NULL);
390 regdata = brcmf_sdiod_regrl(sdiodev,
391 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
392 NULL);
Franky Lind77e70f2011-11-10 20:30:24 +0100393 udelay(1);
394}
395
396static void
397brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
Hante Meuleman53036262014-01-13 22:20:23 +0100398 struct chip_info *ci, u16 coreid, u32 pre_resetbits,
399 u32 in_resetbits, u32 post_resetbits)
Franky Lind77e70f2011-11-10 20:30:24 +0100400{
401 u8 idx;
402 u32 regdata;
Hante Meuleman53036262014-01-13 22:20:23 +0100403 u32 wrapbase;
Franky Lind77e70f2011-11-10 20:30:24 +0100404
405 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200406 if (idx == BRCMF_MAX_CORENUM)
407 return;
Franky Lind77e70f2011-11-10 20:30:24 +0100408
Hante Meuleman53036262014-01-13 22:20:23 +0100409 wrapbase = ci->c_inf[idx].wrapbase;
410
Franky Lind77e70f2011-11-10 20:30:24 +0100411 /* must disable first to work for arbitrary current core state */
Hante Meuleman53036262014-01-13 22:20:23 +0100412 brcmf_sdio_ai_coredisable(sdiodev, ci, coreid, pre_resetbits,
413 in_resetbits);
Franky Lind77e70f2011-11-10 20:30:24 +0100414
Hante Meuleman53036262014-01-13 22:20:23 +0100415 while (brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_RESET_CTL, NULL) &
416 BCMA_RESET_CTL_RESET) {
417 brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_RESET_CTL, 0, NULL);
418 usleep_range(40, 60);
419 }
Franky Lind77e70f2011-11-10 20:30:24 +0100420
Hante Meuleman53036262014-01-13 22:20:23 +0100421 brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_IOCTL, post_resetbits |
422 BCMA_IOCTL_CLK, NULL);
423 regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100424}
425
Franky Lin1640f282013-04-11 13:28:51 +0200426#ifdef DEBUG
427/* safety check for chipinfo */
428static int brcmf_sdio_chip_cichk(struct chip_info *ci)
429{
430 u8 core_idx;
431
432 /* check RAM core presence for ARM CM3 core */
433 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
434 if (BRCMF_MAX_CORENUM != core_idx) {
435 core_idx = brcmf_sdio_chip_getinfidx(ci,
436 BCMA_CORE_INTERNAL_MEM);
437 if (BRCMF_MAX_CORENUM == core_idx) {
438 brcmf_err("RAM core not provided with ARM CM3 core\n");
439 return -ENODEV;
440 }
441 }
442
443 /* check RAM base for ARM CR4 core */
444 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CR4);
445 if (BRCMF_MAX_CORENUM != core_idx) {
446 if (ci->rambase == 0) {
447 brcmf_err("RAM base not provided with ARM CR4 core\n");
448 return -ENOMEM;
449 }
450 }
451
452 return 0;
453}
454#else /* DEBUG */
455static inline int brcmf_sdio_chip_cichk(struct chip_info *ci)
456{
457 return 0;
458}
459#endif
460
Franky Lina83369b2011-11-04 22:23:28 +0100461static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel4744d162013-12-12 11:58:55 +0100462 struct chip_info *ci)
Franky Lina83369b2011-11-04 22:23:28 +0100463{
464 u32 regdata;
Arend van Sprielc805eeb2014-01-13 22:20:26 +0100465 u32 socitype;
Franky Lina83369b2011-11-04 22:23:28 +0100466
Franky Lin069eddd2013-04-11 13:28:48 +0200467 /* Get CC core rev
Arend van Sprielc805eeb2014-01-13 22:20:26 +0100468 * Chipid is assume to be at offset 0 from SI_ENUM_BASE
Franky Lina83369b2011-11-04 22:23:28 +0100469 * For different chiptypes or old sdio hosts w/o chipcommon,
470 * other ways of recognition should be added here.
471 */
Arend van Spriela39be272013-12-12 11:58:58 +0100472 regdata = brcmf_sdiod_regrl(sdiodev,
Arend van Sprielc805eeb2014-01-13 22:20:26 +0100473 CORE_CC_REG(SI_ENUM_BASE, chipid),
Arend van Spriela39be272013-12-12 11:58:58 +0100474 NULL);
Franky Lina83369b2011-11-04 22:23:28 +0100475 ci->chip = regdata & CID_ID_MASK;
476 ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
Franky Linfe040152013-09-25 13:05:41 +0200477 if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 &&
478 ci->chiprev >= 2)
479 ci->chip = BCM4339_CHIP_ID;
Arend van Sprielc805eeb2014-01-13 22:20:26 +0100480 socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
Franky Lina83369b2011-11-04 22:23:28 +0100481
Arend van Sprielc805eeb2014-01-13 22:20:26 +0100482 brcmf_dbg(INFO, "found %s chip: id=0x%x, rev=%d\n",
483 socitype == SOCI_SB ? "SB" : "AXI", ci->chip, ci->chiprev);
Franky Lina83369b2011-11-04 22:23:28 +0100484
Arend van Sprielc805eeb2014-01-13 22:20:26 +0100485 if (socitype == SOCI_SB) {
486 if (ci->chip != BCM4329_CHIP_ID) {
487 brcmf_err("SB chip is not supported\n");
488 return -ENODEV;
489 }
490 ci->iscoreup = brcmf_sdio_sb_iscoreup;
491 ci->corerev = brcmf_sdio_sb_corerev;
492 ci->coredisable = brcmf_sdio_sb_coredisable;
493 ci->resetcore = brcmf_sdio_sb_resetcore;
494
495 ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
496 ci->c_inf[0].base = SI_ENUM_BASE;
Franky Lin99ba15c2011-11-04 22:23:42 +0100497 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
498 ci->c_inf[1].base = BCM4329_CORE_BUS_BASE;
499 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
500 ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE;
501 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
502 ci->c_inf[3].base = BCM4329_CORE_ARM_BASE;
Hante Meuleman53036262014-01-13 22:20:23 +0100503 ci->c_inf[4].id = BCMA_CORE_80211;
504 ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
Franky Lina83369b2011-11-04 22:23:28 +0100505 ci->ramsize = BCM4329_RAMSIZE;
Arend van Sprielc805eeb2014-01-13 22:20:26 +0100506 } else if (socitype == SOCI_AI) {
Franky Lin6ca687d2011-11-10 20:30:21 +0100507 ci->iscoreup = brcmf_sdio_ai_iscoreup;
Franky Lin523894f2011-11-10 20:30:22 +0100508 ci->corerev = brcmf_sdio_ai_corerev;
Franky Lin086a2e02011-11-10 20:30:23 +0100509 ci->coredisable = brcmf_sdio_ai_coredisable;
Franky Lind77e70f2011-11-10 20:30:24 +0100510 ci->resetcore = brcmf_sdio_ai_resetcore;
Arend van Sprielc805eeb2014-01-13 22:20:26 +0100511
512 ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
513 ci->c_inf[0].base = SI_ENUM_BASE;
514
515 /* Address of cores for new chips should be added here */
516 switch (ci->chip) {
517 case BCM43143_CHIP_ID:
518 ci->c_inf[0].wrapbase = ci->c_inf[0].base + 0x00100000;
519 ci->c_inf[0].cib = 0x2b000000;
520 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
521 ci->c_inf[1].base = BCM43143_CORE_BUS_BASE;
522 ci->c_inf[1].wrapbase = ci->c_inf[1].base + 0x00100000;
523 ci->c_inf[1].cib = 0x18000000;
524 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
525 ci->c_inf[2].base = BCM43143_CORE_SOCRAM_BASE;
526 ci->c_inf[2].wrapbase = ci->c_inf[2].base + 0x00100000;
527 ci->c_inf[2].cib = 0x14000000;
528 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
529 ci->c_inf[3].base = BCM43143_CORE_ARM_BASE;
530 ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000;
531 ci->c_inf[3].cib = 0x07000000;
532 ci->c_inf[4].id = BCMA_CORE_80211;
533 ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
534 ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
535 ci->ramsize = BCM43143_RAMSIZE;
536 break;
537 case BCM43241_CHIP_ID:
538 ci->c_inf[0].wrapbase = 0x18100000;
539 ci->c_inf[0].cib = 0x2a084411;
540 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
541 ci->c_inf[1].base = 0x18002000;
542 ci->c_inf[1].wrapbase = 0x18102000;
543 ci->c_inf[1].cib = 0x0e004211;
544 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
545 ci->c_inf[2].base = 0x18004000;
546 ci->c_inf[2].wrapbase = 0x18104000;
547 ci->c_inf[2].cib = 0x14080401;
548 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
549 ci->c_inf[3].base = 0x18003000;
550 ci->c_inf[3].wrapbase = 0x18103000;
551 ci->c_inf[3].cib = 0x07004211;
552 ci->c_inf[4].id = BCMA_CORE_80211;
553 ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
554 ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
555 ci->ramsize = 0x90000;
556 break;
557 case BCM4330_CHIP_ID:
558 ci->c_inf[0].wrapbase = 0x18100000;
559 ci->c_inf[0].cib = 0x27004211;
560 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
561 ci->c_inf[1].base = 0x18002000;
562 ci->c_inf[1].wrapbase = 0x18102000;
563 ci->c_inf[1].cib = 0x07004211;
564 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
565 ci->c_inf[2].base = 0x18004000;
566 ci->c_inf[2].wrapbase = 0x18104000;
567 ci->c_inf[2].cib = 0x0d080401;
568 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
569 ci->c_inf[3].base = 0x18003000;
570 ci->c_inf[3].wrapbase = 0x18103000;
571 ci->c_inf[3].cib = 0x03004211;
572 ci->c_inf[4].id = BCMA_CORE_80211;
573 ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
574 ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
575 ci->ramsize = 0x48000;
576 break;
577 case BCM4334_CHIP_ID:
578 ci->c_inf[0].wrapbase = 0x18100000;
579 ci->c_inf[0].cib = 0x29004211;
580 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
581 ci->c_inf[1].base = 0x18002000;
582 ci->c_inf[1].wrapbase = 0x18102000;
583 ci->c_inf[1].cib = 0x0d004211;
584 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
585 ci->c_inf[2].base = 0x18004000;
586 ci->c_inf[2].wrapbase = 0x18104000;
587 ci->c_inf[2].cib = 0x13080401;
588 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
589 ci->c_inf[3].base = 0x18003000;
590 ci->c_inf[3].wrapbase = 0x18103000;
591 ci->c_inf[3].cib = 0x07004211;
592 ci->c_inf[4].id = BCMA_CORE_80211;
593 ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
594 ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
595 ci->ramsize = 0x80000;
596 break;
597 case BCM4335_CHIP_ID:
598 ci->c_inf[0].wrapbase = 0x18100000;
599 ci->c_inf[0].cib = 0x2b084411;
600 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
601 ci->c_inf[1].base = 0x18005000;
602 ci->c_inf[1].wrapbase = 0x18105000;
603 ci->c_inf[1].cib = 0x0f004211;
604 ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
605 ci->c_inf[2].base = 0x18002000;
606 ci->c_inf[2].wrapbase = 0x18102000;
607 ci->c_inf[2].cib = 0x01084411;
608 ci->c_inf[3].id = BCMA_CORE_80211;
609 ci->c_inf[3].base = BCM43xx_CORE_D11_BASE;
610 ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000;
611 ci->ramsize = 0xc0000;
612 ci->rambase = 0x180000;
613 break;
614 case BCM43362_CHIP_ID:
615 ci->c_inf[0].wrapbase = 0x18100000;
616 ci->c_inf[0].cib = 0x27004211;
617 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
618 ci->c_inf[1].base = 0x18002000;
619 ci->c_inf[1].wrapbase = 0x18102000;
620 ci->c_inf[1].cib = 0x0a004211;
621 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
622 ci->c_inf[2].base = 0x18004000;
623 ci->c_inf[2].wrapbase = 0x18104000;
624 ci->c_inf[2].cib = 0x08080401;
625 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
626 ci->c_inf[3].base = 0x18003000;
627 ci->c_inf[3].wrapbase = 0x18103000;
628 ci->c_inf[3].cib = 0x03004211;
629 ci->c_inf[4].id = BCMA_CORE_80211;
630 ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
631 ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
632 ci->ramsize = 0x3C000;
633 break;
634 case BCM4339_CHIP_ID:
635 ci->c_inf[0].wrapbase = 0x18100000;
636 ci->c_inf[0].cib = 0x2e084411;
637 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
638 ci->c_inf[1].base = 0x18005000;
639 ci->c_inf[1].wrapbase = 0x18105000;
640 ci->c_inf[1].cib = 0x15004211;
641 ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
642 ci->c_inf[2].base = 0x18002000;
643 ci->c_inf[2].wrapbase = 0x18102000;
644 ci->c_inf[2].cib = 0x04084411;
645 ci->c_inf[3].id = BCMA_CORE_80211;
646 ci->c_inf[3].base = BCM43xx_CORE_D11_BASE;
647 ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000;
648 ci->ramsize = 0xc0000;
649 ci->rambase = 0x180000;
650 break;
651 default:
652 brcmf_err("AXI chip is not supported\n");
653 return -ENODEV;
654 }
655 } else {
656 brcmf_err("chip backplane type %u is not supported\n",
657 socitype);
Franky Lin6ca687d2011-11-10 20:30:21 +0100658 return -ENODEV;
659 }
660
Arend van Sprielc805eeb2014-01-13 22:20:26 +0100661 return brcmf_sdio_chip_cichk(ci);
Franky Lina83369b2011-11-04 22:23:28 +0100662}
663
Franky Line63ac6b2011-11-04 22:23:29 +0100664static int
665brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
666{
667 int err = 0;
668 u8 clkval, clkset;
669
670 /* Try forcing SDIO core to do ALPAvail request only */
671 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
Arend van Spriela39be272013-12-12 11:58:58 +0100672 brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
Franky Line63ac6b2011-11-04 22:23:29 +0100673 if (err) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100674 brcmf_err("error writing for HT off\n");
Franky Line63ac6b2011-11-04 22:23:29 +0100675 return err;
676 }
677
678 /* If register supported, wait for ALPAvail and then force ALP */
679 /* This may take up to 15 milliseconds */
Arend van Spriela39be272013-12-12 11:58:58 +0100680 clkval = brcmf_sdiod_regrb(sdiodev,
681 SBSDIO_FUNC1_CHIPCLKCSR, NULL);
Franky Line63ac6b2011-11-04 22:23:29 +0100682
683 if ((clkval & ~SBSDIO_AVBITS) != clkset) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100684 brcmf_err("ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
Franky Line63ac6b2011-11-04 22:23:29 +0100685 clkset, clkval);
686 return -EACCES;
687 }
688
Arend van Spriela39be272013-12-12 11:58:58 +0100689 SPINWAIT(((clkval = brcmf_sdiod_regrb(sdiodev,
690 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
Franky Line63ac6b2011-11-04 22:23:29 +0100691 !SBSDIO_ALPAV(clkval)),
692 PMU_MAX_TRANSITION_DLY);
693 if (!SBSDIO_ALPAV(clkval)) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100694 brcmf_err("timeout on ALPAV wait, clkval 0x%02x\n",
Franky Line63ac6b2011-11-04 22:23:29 +0100695 clkval);
696 return -EBUSY;
697 }
698
699 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
Arend van Spriela39be272013-12-12 11:58:58 +0100700 brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
Franky Line63ac6b2011-11-04 22:23:29 +0100701 udelay(65);
702
703 /* Also, disable the extra SDIO pull-ups */
Arend van Spriela39be272013-12-12 11:58:58 +0100704 brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
Franky Line63ac6b2011-11-04 22:23:29 +0100705
706 return 0;
707}
708
Franky Lin5b45e542011-11-04 22:23:30 +0100709static void
710brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
711 struct chip_info *ci)
712{
Franky Lin79ae3952012-05-04 18:27:34 -0700713 u32 base = ci->c_inf[0].base;
714
Franky Lin5b45e542011-11-04 22:23:30 +0100715 /* get chipcommon rev */
Franky Lin523894f2011-11-10 20:30:22 +0100716 ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100717
718 /* get chipcommon capabilites */
Arend van Spriela39be272013-12-12 11:58:58 +0100719 ci->c_inf[0].caps = brcmf_sdiod_regrl(sdiodev,
720 CORE_CC_REG(base, capabilities),
721 NULL);
Franky Lin5b45e542011-11-04 22:23:30 +0100722
723 /* get pmu caps & rev */
Franky Lin99ba15c2011-11-04 22:23:42 +0100724 if (ci->c_inf[0].caps & CC_CAP_PMU) {
Franky Lin79ae3952012-05-04 18:27:34 -0700725 ci->pmucaps =
Arend van Spriela39be272013-12-12 11:58:58 +0100726 brcmf_sdiod_regrl(sdiodev,
727 CORE_CC_REG(base, pmucapabilities),
728 NULL);
Franky Lin5b45e542011-11-04 22:23:30 +0100729 ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
730 }
731
Franky Lin523894f2011-11-10 20:30:22 +0100732 ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100733
734 brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
Franky Lin99ba15c2011-11-04 22:23:42 +0100735 ci->c_inf[0].rev, ci->pmurev,
736 ci->c_inf[1].rev, ci->c_inf[1].id);
Franky Lin966414d2011-11-04 22:23:32 +0100737
738 /*
739 * Make sure any on-chip ARM is off (in case strapping is wrong),
740 * or downloaded code was already running.
741 */
Hante Meuleman53036262014-01-13 22:20:23 +0100742 ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0, 0);
Franky Lin5b45e542011-11-04 22:23:30 +0100743}
744
Franky Lina83369b2011-11-04 22:23:28 +0100745int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel4744d162013-12-12 11:58:55 +0100746 struct chip_info **ci_ptr)
Franky Lina83369b2011-11-04 22:23:28 +0100747{
Franky Lina97e4fc2011-11-04 22:23:35 +0100748 int ret;
749 struct chip_info *ci;
750
751 brcmf_dbg(TRACE, "Enter\n");
752
753 /* alloc chip_info_t */
754 ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
755 if (!ci)
756 return -ENOMEM;
Franky Lina83369b2011-11-04 22:23:28 +0100757
Franky Line63ac6b2011-11-04 22:23:29 +0100758 ret = brcmf_sdio_chip_buscoreprep(sdiodev);
759 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100760 goto err;
Franky Line63ac6b2011-11-04 22:23:29 +0100761
Arend van Spriel4744d162013-12-12 11:58:55 +0100762 ret = brcmf_sdio_chip_recognition(sdiodev, ci);
Franky Lina83369b2011-11-04 22:23:28 +0100763 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100764 goto err;
Franky Lina83369b2011-11-04 22:23:28 +0100765
Franky Lin5b45e542011-11-04 22:23:30 +0100766 brcmf_sdio_chip_buscoresetup(sdiodev, ci);
767
Arend van Spriela39be272013-12-12 11:58:58 +0100768 brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopullup),
769 0, NULL);
770 brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopulldown),
771 0, NULL);
Franky Lin960908d2011-11-04 22:23:33 +0100772
Franky Lina97e4fc2011-11-04 22:23:35 +0100773 *ci_ptr = ci;
774 return 0;
775
776err:
777 kfree(ci);
Franky Lina83369b2011-11-04 22:23:28 +0100778 return ret;
779}
Franky Lina8a6c042011-11-04 22:23:39 +0100780
781void
782brcmf_sdio_chip_detach(struct chip_info **ci_ptr)
783{
784 brcmf_dbg(TRACE, "Enter\n");
785
786 kfree(*ci_ptr);
787 *ci_ptr = NULL;
788}
Franky Line12afb62011-11-04 22:23:40 +0100789
790static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len)
791{
792 const char *fmt;
793
794 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
795 snprintf(buf, len, fmt, chipid);
796 return buf;
797}
798
799void
800brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
801 struct chip_info *ci, u32 drivestrength)
802{
Hante Meuleman979c2922013-04-11 13:28:55 +0200803 const struct sdiod_drive_str *str_tab = NULL;
804 u32 str_mask;
805 u32 str_shift;
Franky Line12afb62011-11-04 22:23:40 +0100806 char chn[8];
Franky Lin79ae3952012-05-04 18:27:34 -0700807 u32 base = ci->c_inf[0].base;
Hante Meuleman979c2922013-04-11 13:28:55 +0200808 u32 i;
809 u32 drivestrength_sel = 0;
810 u32 cc_data_temp;
811 u32 addr;
Franky Line12afb62011-11-04 22:23:40 +0100812
Franky Lin99ba15c2011-11-04 22:23:42 +0100813 if (!(ci->c_inf[0].caps & CC_CAP_PMU))
Franky Line12afb62011-11-04 22:23:40 +0100814 return;
815
816 switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
Franky Lince2d7d72011-12-08 15:06:39 -0800817 case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12):
Hante Meuleman979c2922013-04-11 13:28:55 +0200818 str_tab = sdiod_drvstr_tab1_1v8;
Franky Lince2d7d72011-12-08 15:06:39 -0800819 str_mask = 0x00003800;
820 str_shift = 11;
821 break;
Arend van Sprielaf35f552014-01-06 12:40:42 +0100822 case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17):
823 str_tab = sdiod_drvstr_tab6_1v8;
824 str_mask = 0x00001800;
825 str_shift = 11;
826 break;
Hante Meuleman979c2922013-04-11 13:28:55 +0200827 case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17):
828 /* note: 43143 does not support tristate */
829 i = ARRAY_SIZE(sdiod_drvstr_tab2_3v3) - 1;
830 if (drivestrength >= sdiod_drvstr_tab2_3v3[i].strength) {
831 str_tab = sdiod_drvstr_tab2_3v3;
832 str_mask = 0x00000007;
833 str_shift = 0;
834 } else
835 brcmf_err("Invalid SDIO Drive strength for chip %s, strength=%d\n",
836 brcmf_sdio_chip_name(ci->chip, chn, 8),
837 drivestrength);
838 break;
Arend van Spriel11e69c32014-01-08 10:49:33 +0100839 case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13):
840 str_tab = sdiod_drive_strength_tab5_1v8;
841 str_mask = 0x00003800;
842 str_shift = 11;
843 break;
Franky Line12afb62011-11-04 22:23:40 +0100844 default:
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100845 brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
Franky Line12afb62011-11-04 22:23:40 +0100846 brcmf_sdio_chip_name(ci->chip, chn, 8),
847 ci->chiprev, ci->pmurev);
848 break;
849 }
850
851 if (str_tab != NULL) {
Franky Line12afb62011-11-04 22:23:40 +0100852 for (i = 0; str_tab[i].strength != 0; i++) {
853 if (drivestrength >= str_tab[i].strength) {
854 drivestrength_sel = str_tab[i].sel;
855 break;
856 }
857 }
Hante Meuleman979c2922013-04-11 13:28:55 +0200858 addr = CORE_CC_REG(base, chipcontrol_addr);
Arend van Spriela39be272013-12-12 11:58:58 +0100859 brcmf_sdiod_regwl(sdiodev, addr, 1, NULL);
860 cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL);
Franky Line12afb62011-11-04 22:23:40 +0100861 cc_data_temp &= ~str_mask;
862 drivestrength_sel <<= str_shift;
863 cc_data_temp |= drivestrength_sel;
Arend van Spriela39be272013-12-12 11:58:58 +0100864 brcmf_sdiod_regwl(sdiodev, addr, cc_data_temp, NULL);
Franky Line12afb62011-11-04 22:23:40 +0100865
Hante Meuleman979c2922013-04-11 13:28:55 +0200866 brcmf_dbg(INFO, "SDIO: %d mA (req=%d mA) drive strength selected, set to 0x%08x\n",
867 str_tab[i].strength, drivestrength, cc_data_temp);
Franky Line12afb62011-11-04 22:23:40 +0100868 }
869}
Franky Lin069eddd2013-04-11 13:28:48 +0200870
Franky Lin069eddd2013-04-11 13:28:48 +0200871static void
872brcmf_sdio_chip_cm3_enterdl(struct brcmf_sdio_dev *sdiodev,
873 struct chip_info *ci)
874{
Hante Meuleman53036262014-01-13 22:20:23 +0100875 ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0, 0);
876 ci->resetcore(sdiodev, ci, BCMA_CORE_80211,
877 D11_BCMA_IOCTL_PHYRESET | D11_BCMA_IOCTL_PHYCLOCKEN,
878 D11_BCMA_IOCTL_PHYCLOCKEN, D11_BCMA_IOCTL_PHYCLOCKEN);
879 ci->resetcore(sdiodev, ci, BCMA_CORE_INTERNAL_MEM, 0, 0, 0);
Franky Lin069eddd2013-04-11 13:28:48 +0200880}
881
882static bool
Hante Meulemana74d0362014-01-13 22:20:22 +0100883brcmf_sdio_chip_cm3_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci)
Franky Lin069eddd2013-04-11 13:28:48 +0200884{
885 u8 core_idx;
886 u32 reg_addr;
887
888 if (!ci->iscoreup(sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) {
889 brcmf_err("SOCRAM core is down after reset?\n");
890 return false;
891 }
892
Franky Lin069eddd2013-04-11 13:28:48 +0200893 /* clear all interrupts */
894 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
895 reg_addr = ci->c_inf[core_idx].base;
896 reg_addr += offsetof(struct sdpcmd_regs, intstatus);
Arend van Spriela39be272013-12-12 11:58:58 +0100897 brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
Franky Lin069eddd2013-04-11 13:28:48 +0200898
Hante Meuleman53036262014-01-13 22:20:23 +0100899 ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CM3, 0, 0, 0);
Franky Lin1640f282013-04-11 13:28:51 +0200900
901 return true;
902}
903
904static inline void
905brcmf_sdio_chip_cr4_enterdl(struct brcmf_sdio_dev *sdiodev,
906 struct chip_info *ci)
907{
Hante Meuleman53036262014-01-13 22:20:23 +0100908 u8 idx;
909 u32 regdata;
910 u32 wrapbase;
911 idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CR4);
912
913 if (idx == BRCMF_MAX_CORENUM)
914 return;
915
916 wrapbase = ci->c_inf[idx].wrapbase;
917 regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL);
918 regdata &= ARMCR4_BCMA_IOCTL_CPUHALT;
919 ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, regdata,
920 ARMCR4_BCMA_IOCTL_CPUHALT, ARMCR4_BCMA_IOCTL_CPUHALT);
921 ci->resetcore(sdiodev, ci, BCMA_CORE_80211,
922 D11_BCMA_IOCTL_PHYRESET | D11_BCMA_IOCTL_PHYCLOCKEN,
923 D11_BCMA_IOCTL_PHYCLOCKEN, D11_BCMA_IOCTL_PHYCLOCKEN);
Franky Lin1640f282013-04-11 13:28:51 +0200924}
925
926static bool
Arend van Spriel33556502014-01-13 22:20:25 +0100927brcmf_sdio_chip_cr4_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
928 u32 rstvec)
Franky Lin1640f282013-04-11 13:28:51 +0200929{
930 u8 core_idx;
931 u32 reg_addr;
932
Franky Lin1640f282013-04-11 13:28:51 +0200933 /* clear all interrupts */
934 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
935 reg_addr = ci->c_inf[core_idx].base;
936 reg_addr += offsetof(struct sdpcmd_regs, intstatus);
Arend van Spriela39be272013-12-12 11:58:58 +0100937 brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
Franky Lin1640f282013-04-11 13:28:51 +0200938
939 /* Write reset vector to address 0 */
Arend van Spriel33556502014-01-13 22:20:25 +0100940 brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&rstvec,
941 sizeof(rstvec));
Franky Lin1640f282013-04-11 13:28:51 +0200942
943 /* restore ARM */
Hante Meuleman53036262014-01-13 22:20:23 +0100944 ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, ARMCR4_BCMA_IOCTL_CPUHALT,
945 0, 0);
Franky Lin069eddd2013-04-11 13:28:48 +0200946
947 return true;
948}
949
950void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev,
951 struct chip_info *ci)
952{
Franky Lin1640f282013-04-11 13:28:51 +0200953 u8 arm_core_idx;
954
955 arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
956 if (BRCMF_MAX_CORENUM != arm_core_idx) {
957 brcmf_sdio_chip_cm3_enterdl(sdiodev, ci);
958 return;
959 }
960
961 brcmf_sdio_chip_cr4_enterdl(sdiodev, ci);
Franky Lin069eddd2013-04-11 13:28:48 +0200962}
963
964bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel33556502014-01-13 22:20:25 +0100965 struct chip_info *ci, u32 rstvec)
Franky Lin069eddd2013-04-11 13:28:48 +0200966{
Franky Lin1640f282013-04-11 13:28:51 +0200967 u8 arm_core_idx;
968
969 arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
970 if (BRCMF_MAX_CORENUM != arm_core_idx)
Hante Meulemana74d0362014-01-13 22:20:22 +0100971 return brcmf_sdio_chip_cm3_exitdl(sdiodev, ci);
Franky Lin1640f282013-04-11 13:28:51 +0200972
Arend van Spriel33556502014-01-13 22:20:25 +0100973 return brcmf_sdio_chip_cr4_exitdl(sdiodev, ci, rstvec);
Franky Lin069eddd2013-04-11 13:28:48 +0200974}