blob: a74a3d1c3e00f7561906ed042edd084173380c14 [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
Franky Lina83369b2011-11-04 22:23:28 +010054#define SBCOREREV(sbidh) \
Franky Lin61213be2011-11-04 22:23:41 +010055 ((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \
56 ((sbidh) & SSB_IDHIGH_RCLO))
Franky Lina83369b2011-11-04 22:23:28 +010057
Franky Lin6ca687d2011-11-10 20:30:21 +010058/* SOC Interconnect types (aka chip types) */
59#define SOCI_SB 0
60#define SOCI_AI 1
61
Franky Lin523894f2011-11-10 20:30:22 +010062/* EROM CompIdentB */
63#define CIB_REV_MASK 0xff000000
64#define CIB_REV_SHIFT 24
65
Franky Lin1640f282013-04-11 13:28:51 +020066/* ARM CR4 core specific control flag bits */
67#define ARMCR4_BCMA_IOCTL_CPUHALT 0x0020
68
Franky Line12afb62011-11-04 22:23:40 +010069#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
70/* SDIO Pad drive strength to select value mappings */
71struct sdiod_drive_str {
72 u8 strength; /* Pad Drive Strength in mA */
73 u8 sel; /* Chip-specific select value */
74};
Franky Lince2d7d72011-12-08 15:06:39 -080075/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8V) */
Franky Linffb27562011-12-08 15:06:40 -080076static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = {
Franky Lince2d7d72011-12-08 15:06:39 -080077 {32, 0x6},
78 {26, 0x7},
79 {22, 0x4},
80 {16, 0x5},
81 {12, 0x2},
82 {8, 0x3},
83 {4, 0x0},
84 {0, 0x1}
85};
86
Arend van Spriel11e69c32014-01-08 10:49:33 +010087/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */
88static const struct sdiod_drive_str sdiod_drive_strength_tab5_1v8[] = {
89 {6, 0x7},
90 {5, 0x6},
91 {4, 0x5},
92 {3, 0x4},
93 {2, 0x2},
94 {1, 0x1},
95 {0, 0x0}
96};
97
Arend van Sprielaf35f552014-01-06 12:40:42 +010098/* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */
99static const struct sdiod_drive_str sdiod_drvstr_tab6_1v8[] = {
100 {3, 0x3},
101 {2, 0x2},
102 {1, 0x1},
103 {0, 0x0} };
104
Hante Meuleman979c2922013-04-11 13:28:55 +0200105/* SDIO Drive Strength to sel value table for 43143 PMU Rev 17 (3.3V) */
106static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = {
107 {16, 0x7},
108 {12, 0x5},
109 {8, 0x3},
110 {4, 0x1}
111};
112
Franky Lin99ba15c2011-11-04 22:23:42 +0100113u8
114brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid)
115{
116 u8 idx;
117
118 for (idx = 0; idx < BRCMF_MAX_CORENUM; idx++)
119 if (coreid == ci->c_inf[idx].id)
120 return idx;
121
122 return BRCMF_MAX_CORENUM;
123}
124
Franky Lin454d2a82011-11-04 22:23:37 +0100125static u32
Franky Lin523894f2011-11-10 20:30:22 +0100126brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
127 struct chip_info *ci, u16 coreid)
Franky Lin454d2a82011-11-04 22:23:37 +0100128{
129 u32 regdata;
Franky Lin523894f2011-11-10 20:30:22 +0100130 u8 idx;
131
132 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin454d2a82011-11-04 22:23:37 +0100133
Arend van Spriela39be272013-12-12 11:58:58 +0100134 regdata = brcmf_sdiod_regrl(sdiodev,
135 CORE_SB(ci->c_inf[idx].base, sbidhigh),
136 NULL);
Franky Lin454d2a82011-11-04 22:23:37 +0100137 return SBCOREREV(regdata);
138}
139
Franky Lin523894f2011-11-10 20:30:22 +0100140static u32
141brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev,
142 struct chip_info *ci, u16 coreid)
143{
144 u8 idx;
145
146 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
147
148 return (ci->c_inf[idx].cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
149}
150
Franky Lin6ca687d2011-11-10 20:30:21 +0100151static bool
152brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
153 struct chip_info *ci, u16 coreid)
Franky Lind8f64a42011-11-04 22:23:36 +0100154{
155 u32 regdata;
Franky Lin6ca687d2011-11-10 20:30:21 +0100156 u8 idx;
157
158 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200159 if (idx == BRCMF_MAX_CORENUM)
160 return false;
Franky Lind8f64a42011-11-04 22:23:36 +0100161
Arend van Spriela39be272013-12-12 11:58:58 +0100162 regdata = brcmf_sdiod_regrl(sdiodev,
163 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
164 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100165 regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
166 SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
167 return (SSB_TMSLOW_CLOCK == regdata);
Franky Lind8f64a42011-11-04 22:23:36 +0100168}
169
Franky Lin6ca687d2011-11-10 20:30:21 +0100170static bool
171brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
172 struct chip_info *ci, u16 coreid)
173{
174 u32 regdata;
175 u8 idx;
176 bool ret;
177
178 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200179 if (idx == BRCMF_MAX_CORENUM)
180 return false;
Franky Lin6ca687d2011-11-10 20:30:21 +0100181
Arend van Spriela39be272013-12-12 11:58:58 +0100182 regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
183 NULL);
Franky Lin6ca687d2011-11-10 20:30:21 +0100184 ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
185
Arend van Spriela39be272013-12-12 11:58:58 +0100186 regdata = brcmf_sdiod_regrl(sdiodev,
187 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
188 NULL);
Franky Lin6ca687d2011-11-10 20:30:21 +0100189 ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
190
191 return ret;
192}
193
Franky Lin086a2e02011-11-10 20:30:23 +0100194static void
195brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
Franky Lin1640f282013-04-11 13:28:51 +0200196 struct chip_info *ci, u16 coreid, u32 core_bits)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100197{
Franky Lin79ae3952012-05-04 18:27:34 -0700198 u32 regdata, base;
Franky Lin086a2e02011-11-10 20:30:23 +0100199 u8 idx;
200
201 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin79ae3952012-05-04 18:27:34 -0700202 base = ci->c_inf[idx].base;
Franky Lin2d4a9af2011-11-04 22:23:31 +0100203
Arend van Spriela39be272013-12-12 11:58:58 +0100204 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100205 if (regdata & SSB_TMSLOW_RESET)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100206 return;
207
Arend van Spriela39be272013-12-12 11:58:58 +0100208 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100209 if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
Franky Lin2d4a9af2011-11-04 22:23:31 +0100210 /*
211 * set target reject and spin until busy is clear
212 * (preserve core-specific bits)
213 */
Arend van Spriela39be272013-12-12 11:58:58 +0100214 regdata = brcmf_sdiod_regrl(sdiodev,
215 CORE_SB(base, sbtmstatelow), NULL);
216 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
217 regdata | SSB_TMSLOW_REJECT, NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100218
Arend van Spriela39be272013-12-12 11:58:58 +0100219 regdata = brcmf_sdiod_regrl(sdiodev,
220 CORE_SB(base, sbtmstatelow), NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100221 udelay(1);
Arend van Spriela39be272013-12-12 11:58:58 +0100222 SPINWAIT((brcmf_sdiod_regrl(sdiodev,
223 CORE_SB(base, sbtmstatehigh),
224 NULL) &
225 SSB_TMSHIGH_BUSY), 100000);
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, sbtmstatehigh),
229 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100230 if (regdata & SSB_TMSHIGH_BUSY)
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100231 brcmf_err("core state still busy\n");
Franky Lin2d4a9af2011-11-04 22:23:31 +0100232
Arend van Spriela39be272013-12-12 11:58:58 +0100233 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow),
234 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100235 if (regdata & SSB_IDLOW_INITIATOR) {
Arend van Spriela39be272013-12-12 11:58:58 +0100236 regdata = brcmf_sdiod_regrl(sdiodev,
237 CORE_SB(base, sbimstate),
238 NULL);
Franky Lin79ae3952012-05-04 18:27:34 -0700239 regdata |= SSB_IMSTATE_REJECT;
Arend van Spriela39be272013-12-12 11:58:58 +0100240 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate),
241 regdata, NULL);
242 regdata = brcmf_sdiod_regrl(sdiodev,
243 CORE_SB(base, sbimstate),
244 NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100245 udelay(1);
Arend van Spriela39be272013-12-12 11:58:58 +0100246 SPINWAIT((brcmf_sdiod_regrl(sdiodev,
247 CORE_SB(base, sbimstate),
248 NULL) &
249 SSB_IMSTATE_BUSY), 100000);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100250 }
251
252 /* set reset and reject while enabling the clocks */
Franky Line13ce262012-05-04 18:27:35 -0700253 regdata = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
254 SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET;
Arend van Spriela39be272013-12-12 11:58:58 +0100255 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
256 regdata, NULL);
257 regdata = brcmf_sdiod_regrl(sdiodev,
258 CORE_SB(base, sbtmstatelow), NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100259 udelay(10);
260
261 /* clear the initiator reject bit */
Arend van Spriela39be272013-12-12 11:58:58 +0100262 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow),
263 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100264 if (regdata & SSB_IDLOW_INITIATOR) {
Arend van Spriela39be272013-12-12 11:58:58 +0100265 regdata = brcmf_sdiod_regrl(sdiodev,
266 CORE_SB(base, sbimstate),
267 NULL);
Franky Lin79ae3952012-05-04 18:27:34 -0700268 regdata &= ~SSB_IMSTATE_REJECT;
Arend van Spriela39be272013-12-12 11:58:58 +0100269 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate),
270 regdata, NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100271 }
272 }
273
274 /* leave reset and reject asserted */
Arend van Spriela39be272013-12-12 11:58:58 +0100275 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
276 (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET), NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100277 udelay(1);
278}
279
Franky Lin086a2e02011-11-10 20:30:23 +0100280static void
281brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
Franky Lin1640f282013-04-11 13:28:51 +0200282 struct chip_info *ci, u16 coreid, u32 core_bits)
Franky Lin086a2e02011-11-10 20:30:23 +0100283{
284 u8 idx;
285 u32 regdata;
286
287 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200288 if (idx == BRCMF_MAX_CORENUM)
289 return;
Franky Lin086a2e02011-11-10 20:30:23 +0100290
291 /* if core is already in reset, just return */
Arend van Spriela39be272013-12-12 11:58:58 +0100292 regdata = brcmf_sdiod_regrl(sdiodev,
293 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
294 NULL);
Franky Lin086a2e02011-11-10 20:30:23 +0100295 if ((regdata & BCMA_RESET_CTL_RESET) != 0)
296 return;
297
Franky Lin1640f282013-04-11 13:28:51 +0200298 /* ensure no pending backplane operation
299 * 300uc should be sufficient for backplane ops to be finish
300 * extra 10ms is taken into account for firmware load stage
301 * after 10300us carry on disabling the core anyway
302 */
Arend van Spriela39be272013-12-12 11:58:58 +0100303 SPINWAIT(brcmf_sdiod_regrl(sdiodev,
Franky Lin1640f282013-04-11 13:28:51 +0200304 ci->c_inf[idx].wrapbase+BCMA_RESET_ST,
Arend van Spriela39be272013-12-12 11:58:58 +0100305 NULL), 10300);
306 regdata = brcmf_sdiod_regrl(sdiodev,
307 ci->c_inf[idx].wrapbase+BCMA_RESET_ST,
308 NULL);
Franky Lin1640f282013-04-11 13:28:51 +0200309 if (regdata)
310 brcmf_err("disabling core 0x%x with reset status %x\n",
311 coreid, regdata);
Franky Lin086a2e02011-11-10 20:30:23 +0100312
Arend van Spriela39be272013-12-12 11:58:58 +0100313 brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
314 BCMA_RESET_CTL_RESET, NULL);
Franky Lin086a2e02011-11-10 20:30:23 +0100315 udelay(1);
Franky Lin1640f282013-04-11 13:28:51 +0200316
Arend van Spriela39be272013-12-12 11:58:58 +0100317 brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
318 core_bits, NULL);
319 regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
320 NULL);
Franky Lin1640f282013-04-11 13:28:51 +0200321 usleep_range(10, 20);
322
Franky Lin086a2e02011-11-10 20:30:23 +0100323}
324
Franky Lind77e70f2011-11-10 20:30:24 +0100325static void
326brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
Franky Lin1640f282013-04-11 13:28:51 +0200327 struct chip_info *ci, u16 coreid, u32 core_bits)
Franky Lin2bc78e12011-11-04 22:23:38 +0100328{
329 u32 regdata;
Franky Lin086a2e02011-11-10 20:30:23 +0100330 u8 idx;
331
332 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200333 if (idx == BRCMF_MAX_CORENUM)
334 return;
Franky Lin2bc78e12011-11-04 22:23:38 +0100335
336 /*
337 * Must do the disable sequence first to work for
338 * arbitrary current core state.
339 */
Franky Lin1640f282013-04-11 13:28:51 +0200340 brcmf_sdio_sb_coredisable(sdiodev, ci, coreid, 0);
Franky Lin2bc78e12011-11-04 22:23:38 +0100341
342 /*
343 * Now do the initialization sequence.
344 * set reset while enabling the clock and
345 * forcing them on throughout the core
346 */
Arend van Spriela39be272013-12-12 11:58:58 +0100347 brcmf_sdiod_regwl(sdiodev,
348 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
349 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET,
350 NULL);
351 regdata = brcmf_sdiod_regrl(sdiodev,
352 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
353 NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100354 udelay(1);
355
Franky Lind77e70f2011-11-10 20:30:24 +0100356 /* clear any serror */
Arend van Spriela39be272013-12-12 11:58:58 +0100357 regdata = brcmf_sdiod_regrl(sdiodev,
358 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
359 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100360 if (regdata & SSB_TMSHIGH_SERR)
Arend van Spriela39be272013-12-12 11:58:58 +0100361 brcmf_sdiod_regwl(sdiodev,
362 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
363 0, NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100364
Arend van Spriela39be272013-12-12 11:58:58 +0100365 regdata = brcmf_sdiod_regrl(sdiodev,
366 CORE_SB(ci->c_inf[idx].base, sbimstate),
367 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100368 if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
Arend van Spriela39be272013-12-12 11:58:58 +0100369 brcmf_sdiod_regwl(sdiodev,
370 CORE_SB(ci->c_inf[idx].base, sbimstate),
371 regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO),
372 NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100373
374 /* clear reset and allow it to propagate throughout the core */
Arend van Spriela39be272013-12-12 11:58:58 +0100375 brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
376 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK, NULL);
377 regdata = brcmf_sdiod_regrl(sdiodev,
378 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
379 NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100380 udelay(1);
381
382 /* leave clock enabled */
Arend van Spriela39be272013-12-12 11:58:58 +0100383 brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
384 SSB_TMSLOW_CLOCK, NULL);
385 regdata = brcmf_sdiod_regrl(sdiodev,
386 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
387 NULL);
Franky Lind77e70f2011-11-10 20:30:24 +0100388 udelay(1);
389}
390
391static void
392brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
Franky Lin1640f282013-04-11 13:28:51 +0200393 struct chip_info *ci, u16 coreid, u32 core_bits)
Franky Lind77e70f2011-11-10 20:30:24 +0100394{
395 u8 idx;
396 u32 regdata;
397
398 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200399 if (idx == BRCMF_MAX_CORENUM)
400 return;
Franky Lind77e70f2011-11-10 20:30:24 +0100401
402 /* must disable first to work for arbitrary current core state */
Franky Lin1640f282013-04-11 13:28:51 +0200403 brcmf_sdio_ai_coredisable(sdiodev, ci, coreid, core_bits);
Franky Lind77e70f2011-11-10 20:30:24 +0100404
405 /* now do initialization sequence */
Arend van Spriela39be272013-12-12 11:58:58 +0100406 brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
407 core_bits | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
408 regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
409 NULL);
410 brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
411 0, NULL);
412 regdata = brcmf_sdiod_regrl(sdiodev,
413 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
414 NULL);
Franky Lind77e70f2011-11-10 20:30:24 +0100415 udelay(1);
416
Arend van Spriela39be272013-12-12 11:58:58 +0100417 brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
418 core_bits | BCMA_IOCTL_CLK, NULL);
419 regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
420 NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100421 udelay(1);
422}
423
Franky Lin1640f282013-04-11 13:28:51 +0200424#ifdef DEBUG
425/* safety check for chipinfo */
426static int brcmf_sdio_chip_cichk(struct chip_info *ci)
427{
428 u8 core_idx;
429
430 /* check RAM core presence for ARM CM3 core */
431 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
432 if (BRCMF_MAX_CORENUM != core_idx) {
433 core_idx = brcmf_sdio_chip_getinfidx(ci,
434 BCMA_CORE_INTERNAL_MEM);
435 if (BRCMF_MAX_CORENUM == core_idx) {
436 brcmf_err("RAM core not provided with ARM CM3 core\n");
437 return -ENODEV;
438 }
439 }
440
441 /* check RAM base for ARM CR4 core */
442 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CR4);
443 if (BRCMF_MAX_CORENUM != core_idx) {
444 if (ci->rambase == 0) {
445 brcmf_err("RAM base not provided with ARM CR4 core\n");
446 return -ENOMEM;
447 }
448 }
449
450 return 0;
451}
452#else /* DEBUG */
453static inline int brcmf_sdio_chip_cichk(struct chip_info *ci)
454{
455 return 0;
456}
457#endif
458
Franky Lina83369b2011-11-04 22:23:28 +0100459static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel4744d162013-12-12 11:58:55 +0100460 struct chip_info *ci)
Franky Lina83369b2011-11-04 22:23:28 +0100461{
462 u32 regdata;
Franky Lin1640f282013-04-11 13:28:51 +0200463 int ret;
Franky Lina83369b2011-11-04 22:23:28 +0100464
Franky Lin069eddd2013-04-11 13:28:48 +0200465 /* Get CC core rev
Franky Lina83369b2011-11-04 22:23:28 +0100466 * Chipid is assume to be at offset 0 from regs arg
467 * For different chiptypes or old sdio hosts w/o chipcommon,
468 * other ways of recognition should be added here.
469 */
Franky Lin99ba15c2011-11-04 22:23:42 +0100470 ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
Arend van Spriel4744d162013-12-12 11:58:55 +0100471 ci->c_inf[0].base = SI_ENUM_BASE;
Arend van Spriela39be272013-12-12 11:58:58 +0100472 regdata = brcmf_sdiod_regrl(sdiodev,
473 CORE_CC_REG(ci->c_inf[0].base, chipid),
474 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;
Franky Lin6ca687d2011-11-10 20:30:21 +0100480 ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
Franky Lina83369b2011-11-04 22:23:28 +0100481
482 brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
483
484 /* Address of cores for new chips should be added here */
485 switch (ci->chip) {
Hante Meuleman369508c2013-04-11 13:28:54 +0200486 case BCM43143_CHIP_ID:
487 ci->c_inf[0].wrapbase = ci->c_inf[0].base + 0x00100000;
488 ci->c_inf[0].cib = 0x2b000000;
489 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
490 ci->c_inf[1].base = BCM43143_CORE_BUS_BASE;
491 ci->c_inf[1].wrapbase = ci->c_inf[1].base + 0x00100000;
492 ci->c_inf[1].cib = 0x18000000;
493 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
494 ci->c_inf[2].base = BCM43143_CORE_SOCRAM_BASE;
495 ci->c_inf[2].wrapbase = ci->c_inf[2].base + 0x00100000;
496 ci->c_inf[2].cib = 0x14000000;
497 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
498 ci->c_inf[3].base = BCM43143_CORE_ARM_BASE;
499 ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000;
500 ci->c_inf[3].cib = 0x07000000;
501 ci->ramsize = BCM43143_RAMSIZE;
502 break;
Franky Lin4a1c02c2012-08-30 19:42:59 +0200503 case BCM43241_CHIP_ID:
504 ci->c_inf[0].wrapbase = 0x18100000;
505 ci->c_inf[0].cib = 0x2a084411;
506 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
507 ci->c_inf[1].base = 0x18002000;
508 ci->c_inf[1].wrapbase = 0x18102000;
509 ci->c_inf[1].cib = 0x0e004211;
510 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
511 ci->c_inf[2].base = 0x18004000;
512 ci->c_inf[2].wrapbase = 0x18104000;
513 ci->c_inf[2].cib = 0x14080401;
514 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
515 ci->c_inf[3].base = 0x18003000;
516 ci->c_inf[3].wrapbase = 0x18103000;
517 ci->c_inf[3].cib = 0x07004211;
518 ci->ramsize = 0x90000;
519 break;
Franky Lina83369b2011-11-04 22:23:28 +0100520 case BCM4329_CHIP_ID:
Franky Lin99ba15c2011-11-04 22:23:42 +0100521 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
522 ci->c_inf[1].base = BCM4329_CORE_BUS_BASE;
523 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
524 ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE;
525 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
526 ci->c_inf[3].base = BCM4329_CORE_ARM_BASE;
Franky Lina83369b2011-11-04 22:23:28 +0100527 ci->ramsize = BCM4329_RAMSIZE;
528 break;
Franky Lince2d7d72011-12-08 15:06:39 -0800529 case BCM4330_CHIP_ID:
530 ci->c_inf[0].wrapbase = 0x18100000;
531 ci->c_inf[0].cib = 0x27004211;
532 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
533 ci->c_inf[1].base = 0x18002000;
534 ci->c_inf[1].wrapbase = 0x18102000;
535 ci->c_inf[1].cib = 0x07004211;
536 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
537 ci->c_inf[2].base = 0x18004000;
538 ci->c_inf[2].wrapbase = 0x18104000;
539 ci->c_inf[2].cib = 0x0d080401;
540 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
541 ci->c_inf[3].base = 0x18003000;
542 ci->c_inf[3].wrapbase = 0x18103000;
543 ci->c_inf[3].cib = 0x03004211;
544 ci->ramsize = 0x48000;
545 break;
Franky Lin85a4a1c2012-06-26 21:26:39 +0200546 case BCM4334_CHIP_ID:
547 ci->c_inf[0].wrapbase = 0x18100000;
548 ci->c_inf[0].cib = 0x29004211;
549 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
550 ci->c_inf[1].base = 0x18002000;
551 ci->c_inf[1].wrapbase = 0x18102000;
552 ci->c_inf[1].cib = 0x0d004211;
553 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
554 ci->c_inf[2].base = 0x18004000;
555 ci->c_inf[2].wrapbase = 0x18104000;
556 ci->c_inf[2].cib = 0x13080401;
557 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
558 ci->c_inf[3].base = 0x18003000;
559 ci->c_inf[3].wrapbase = 0x18103000;
560 ci->c_inf[3].cib = 0x07004211;
561 ci->ramsize = 0x80000;
562 break;
Franky Lin6a1c7482013-04-11 13:28:53 +0200563 case BCM4335_CHIP_ID:
564 ci->c_inf[0].wrapbase = 0x18100000;
565 ci->c_inf[0].cib = 0x2b084411;
566 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
567 ci->c_inf[1].base = 0x18005000;
568 ci->c_inf[1].wrapbase = 0x18105000;
569 ci->c_inf[1].cib = 0x0f004211;
570 ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
571 ci->c_inf[2].base = 0x18002000;
572 ci->c_inf[2].wrapbase = 0x18102000;
573 ci->c_inf[2].cib = 0x01084411;
574 ci->ramsize = 0xc0000;
575 ci->rambase = 0x180000;
576 break;
Franky Linfe040152013-09-25 13:05:41 +0200577 case BCM4339_CHIP_ID:
578 ci->c_inf[0].wrapbase = 0x18100000;
579 ci->c_inf[0].cib = 0x2e084411;
580 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
581 ci->c_inf[1].base = 0x18005000;
582 ci->c_inf[1].wrapbase = 0x18105000;
583 ci->c_inf[1].cib = 0x15004211;
584 ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
585 ci->c_inf[2].base = 0x18002000;
586 ci->c_inf[2].wrapbase = 0x18102000;
587 ci->c_inf[2].cib = 0x04084411;
588 ci->ramsize = 0xc0000;
589 ci->rambase = 0x180000;
590 break;
Arend van Spriel11e69c32014-01-08 10:49:33 +0100591 case BCM43362_CHIP_ID:
592 ci->c_inf[0].wrapbase = 0x18100000;
593 ci->c_inf[0].cib = 0x27004211;
594 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
595 ci->c_inf[1].base = 0x18002000;
596 ci->c_inf[1].wrapbase = 0x18102000;
597 ci->c_inf[1].cib = 0x0a004211;
598 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
599 ci->c_inf[2].base = 0x18004000;
600 ci->c_inf[2].wrapbase = 0x18104000;
601 ci->c_inf[2].cib = 0x08080401;
602 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
603 ci->c_inf[3].base = 0x18003000;
604 ci->c_inf[3].wrapbase = 0x18103000;
605 ci->c_inf[3].cib = 0x03004211;
606 ci->ramsize = 0x3C000;
607 break;
Franky Lina83369b2011-11-04 22:23:28 +0100608 default:
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100609 brcmf_err("chipid 0x%x is not supported\n", ci->chip);
Franky Lina83369b2011-11-04 22:23:28 +0100610 return -ENODEV;
611 }
612
Franky Lin1640f282013-04-11 13:28:51 +0200613 ret = brcmf_sdio_chip_cichk(ci);
614 if (ret)
615 return ret;
616
Franky Lin6ca687d2011-11-10 20:30:21 +0100617 switch (ci->socitype) {
618 case SOCI_SB:
619 ci->iscoreup = brcmf_sdio_sb_iscoreup;
Franky Lin523894f2011-11-10 20:30:22 +0100620 ci->corerev = brcmf_sdio_sb_corerev;
Franky Lin086a2e02011-11-10 20:30:23 +0100621 ci->coredisable = brcmf_sdio_sb_coredisable;
Franky Lind77e70f2011-11-10 20:30:24 +0100622 ci->resetcore = brcmf_sdio_sb_resetcore;
Franky Lin6ca687d2011-11-10 20:30:21 +0100623 break;
624 case SOCI_AI:
625 ci->iscoreup = brcmf_sdio_ai_iscoreup;
Franky Lin523894f2011-11-10 20:30:22 +0100626 ci->corerev = brcmf_sdio_ai_corerev;
Franky Lin086a2e02011-11-10 20:30:23 +0100627 ci->coredisable = brcmf_sdio_ai_coredisable;
Franky Lind77e70f2011-11-10 20:30:24 +0100628 ci->resetcore = brcmf_sdio_ai_resetcore;
Franky Lin6ca687d2011-11-10 20:30:21 +0100629 break;
630 default:
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100631 brcmf_err("socitype %u not supported\n", ci->socitype);
Franky Lin6ca687d2011-11-10 20:30:21 +0100632 return -ENODEV;
633 }
634
Franky Lina83369b2011-11-04 22:23:28 +0100635 return 0;
636}
637
Franky Line63ac6b2011-11-04 22:23:29 +0100638static int
639brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
640{
641 int err = 0;
642 u8 clkval, clkset;
643
644 /* Try forcing SDIO core to do ALPAvail request only */
645 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
Arend van Spriela39be272013-12-12 11:58:58 +0100646 brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
Franky Line63ac6b2011-11-04 22:23:29 +0100647 if (err) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100648 brcmf_err("error writing for HT off\n");
Franky Line63ac6b2011-11-04 22:23:29 +0100649 return err;
650 }
651
652 /* If register supported, wait for ALPAvail and then force ALP */
653 /* This may take up to 15 milliseconds */
Arend van Spriela39be272013-12-12 11:58:58 +0100654 clkval = brcmf_sdiod_regrb(sdiodev,
655 SBSDIO_FUNC1_CHIPCLKCSR, NULL);
Franky Line63ac6b2011-11-04 22:23:29 +0100656
657 if ((clkval & ~SBSDIO_AVBITS) != clkset) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100658 brcmf_err("ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
Franky Line63ac6b2011-11-04 22:23:29 +0100659 clkset, clkval);
660 return -EACCES;
661 }
662
Arend van Spriela39be272013-12-12 11:58:58 +0100663 SPINWAIT(((clkval = brcmf_sdiod_regrb(sdiodev,
664 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
Franky Line63ac6b2011-11-04 22:23:29 +0100665 !SBSDIO_ALPAV(clkval)),
666 PMU_MAX_TRANSITION_DLY);
667 if (!SBSDIO_ALPAV(clkval)) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100668 brcmf_err("timeout on ALPAV wait, clkval 0x%02x\n",
Franky Line63ac6b2011-11-04 22:23:29 +0100669 clkval);
670 return -EBUSY;
671 }
672
673 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
Arend van Spriela39be272013-12-12 11:58:58 +0100674 brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
Franky Line63ac6b2011-11-04 22:23:29 +0100675 udelay(65);
676
677 /* Also, disable the extra SDIO pull-ups */
Arend van Spriela39be272013-12-12 11:58:58 +0100678 brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
Franky Line63ac6b2011-11-04 22:23:29 +0100679
680 return 0;
681}
682
Franky Lin5b45e542011-11-04 22:23:30 +0100683static void
684brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
685 struct chip_info *ci)
686{
Franky Lin79ae3952012-05-04 18:27:34 -0700687 u32 base = ci->c_inf[0].base;
688
Franky Lin5b45e542011-11-04 22:23:30 +0100689 /* get chipcommon rev */
Franky Lin523894f2011-11-10 20:30:22 +0100690 ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100691
692 /* get chipcommon capabilites */
Arend van Spriela39be272013-12-12 11:58:58 +0100693 ci->c_inf[0].caps = brcmf_sdiod_regrl(sdiodev,
694 CORE_CC_REG(base, capabilities),
695 NULL);
Franky Lin5b45e542011-11-04 22:23:30 +0100696
697 /* get pmu caps & rev */
Franky Lin99ba15c2011-11-04 22:23:42 +0100698 if (ci->c_inf[0].caps & CC_CAP_PMU) {
Franky Lin79ae3952012-05-04 18:27:34 -0700699 ci->pmucaps =
Arend van Spriela39be272013-12-12 11:58:58 +0100700 brcmf_sdiod_regrl(sdiodev,
701 CORE_CC_REG(base, pmucapabilities),
702 NULL);
Franky Lin5b45e542011-11-04 22:23:30 +0100703 ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
704 }
705
Franky Lin523894f2011-11-10 20:30:22 +0100706 ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100707
708 brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
Franky Lin99ba15c2011-11-04 22:23:42 +0100709 ci->c_inf[0].rev, ci->pmurev,
710 ci->c_inf[1].rev, ci->c_inf[1].id);
Franky Lin966414d2011-11-04 22:23:32 +0100711
712 /*
713 * Make sure any on-chip ARM is off (in case strapping is wrong),
714 * or downloaded code was already running.
715 */
Franky Lin1640f282013-04-11 13:28:51 +0200716 ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
Franky Lin5b45e542011-11-04 22:23:30 +0100717}
718
Franky Lina83369b2011-11-04 22:23:28 +0100719int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel4744d162013-12-12 11:58:55 +0100720 struct chip_info **ci_ptr)
Franky Lina83369b2011-11-04 22:23:28 +0100721{
Franky Lina97e4fc2011-11-04 22:23:35 +0100722 int ret;
723 struct chip_info *ci;
724
725 brcmf_dbg(TRACE, "Enter\n");
726
727 /* alloc chip_info_t */
728 ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
729 if (!ci)
730 return -ENOMEM;
Franky Lina83369b2011-11-04 22:23:28 +0100731
Franky Line63ac6b2011-11-04 22:23:29 +0100732 ret = brcmf_sdio_chip_buscoreprep(sdiodev);
733 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100734 goto err;
Franky Line63ac6b2011-11-04 22:23:29 +0100735
Arend van Spriel4744d162013-12-12 11:58:55 +0100736 ret = brcmf_sdio_chip_recognition(sdiodev, ci);
Franky Lina83369b2011-11-04 22:23:28 +0100737 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100738 goto err;
Franky Lina83369b2011-11-04 22:23:28 +0100739
Franky Lin5b45e542011-11-04 22:23:30 +0100740 brcmf_sdio_chip_buscoresetup(sdiodev, ci);
741
Arend van Spriela39be272013-12-12 11:58:58 +0100742 brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopullup),
743 0, NULL);
744 brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopulldown),
745 0, NULL);
Franky Lin960908d2011-11-04 22:23:33 +0100746
Franky Lina97e4fc2011-11-04 22:23:35 +0100747 *ci_ptr = ci;
748 return 0;
749
750err:
751 kfree(ci);
Franky Lina83369b2011-11-04 22:23:28 +0100752 return ret;
753}
Franky Lina8a6c042011-11-04 22:23:39 +0100754
755void
756brcmf_sdio_chip_detach(struct chip_info **ci_ptr)
757{
758 brcmf_dbg(TRACE, "Enter\n");
759
760 kfree(*ci_ptr);
761 *ci_ptr = NULL;
762}
Franky Line12afb62011-11-04 22:23:40 +0100763
764static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len)
765{
766 const char *fmt;
767
768 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
769 snprintf(buf, len, fmt, chipid);
770 return buf;
771}
772
773void
774brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
775 struct chip_info *ci, u32 drivestrength)
776{
Hante Meuleman979c2922013-04-11 13:28:55 +0200777 const struct sdiod_drive_str *str_tab = NULL;
778 u32 str_mask;
779 u32 str_shift;
Franky Line12afb62011-11-04 22:23:40 +0100780 char chn[8];
Franky Lin79ae3952012-05-04 18:27:34 -0700781 u32 base = ci->c_inf[0].base;
Hante Meuleman979c2922013-04-11 13:28:55 +0200782 u32 i;
783 u32 drivestrength_sel = 0;
784 u32 cc_data_temp;
785 u32 addr;
Franky Line12afb62011-11-04 22:23:40 +0100786
Franky Lin99ba15c2011-11-04 22:23:42 +0100787 if (!(ci->c_inf[0].caps & CC_CAP_PMU))
Franky Line12afb62011-11-04 22:23:40 +0100788 return;
789
790 switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
Franky Lince2d7d72011-12-08 15:06:39 -0800791 case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12):
Hante Meuleman979c2922013-04-11 13:28:55 +0200792 str_tab = sdiod_drvstr_tab1_1v8;
Franky Lince2d7d72011-12-08 15:06:39 -0800793 str_mask = 0x00003800;
794 str_shift = 11;
795 break;
Arend van Sprielaf35f552014-01-06 12:40:42 +0100796 case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17):
797 str_tab = sdiod_drvstr_tab6_1v8;
798 str_mask = 0x00001800;
799 str_shift = 11;
800 break;
Hante Meuleman979c2922013-04-11 13:28:55 +0200801 case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17):
802 /* note: 43143 does not support tristate */
803 i = ARRAY_SIZE(sdiod_drvstr_tab2_3v3) - 1;
804 if (drivestrength >= sdiod_drvstr_tab2_3v3[i].strength) {
805 str_tab = sdiod_drvstr_tab2_3v3;
806 str_mask = 0x00000007;
807 str_shift = 0;
808 } else
809 brcmf_err("Invalid SDIO Drive strength for chip %s, strength=%d\n",
810 brcmf_sdio_chip_name(ci->chip, chn, 8),
811 drivestrength);
812 break;
Arend van Spriel11e69c32014-01-08 10:49:33 +0100813 case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13):
814 str_tab = sdiod_drive_strength_tab5_1v8;
815 str_mask = 0x00003800;
816 str_shift = 11;
817 break;
Franky Line12afb62011-11-04 22:23:40 +0100818 default:
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100819 brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
Franky Line12afb62011-11-04 22:23:40 +0100820 brcmf_sdio_chip_name(ci->chip, chn, 8),
821 ci->chiprev, ci->pmurev);
822 break;
823 }
824
825 if (str_tab != NULL) {
Franky Line12afb62011-11-04 22:23:40 +0100826 for (i = 0; str_tab[i].strength != 0; i++) {
827 if (drivestrength >= str_tab[i].strength) {
828 drivestrength_sel = str_tab[i].sel;
829 break;
830 }
831 }
Hante Meuleman979c2922013-04-11 13:28:55 +0200832 addr = CORE_CC_REG(base, chipcontrol_addr);
Arend van Spriela39be272013-12-12 11:58:58 +0100833 brcmf_sdiod_regwl(sdiodev, addr, 1, NULL);
834 cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL);
Franky Line12afb62011-11-04 22:23:40 +0100835 cc_data_temp &= ~str_mask;
836 drivestrength_sel <<= str_shift;
837 cc_data_temp |= drivestrength_sel;
Arend van Spriela39be272013-12-12 11:58:58 +0100838 brcmf_sdiod_regwl(sdiodev, addr, cc_data_temp, NULL);
Franky Line12afb62011-11-04 22:23:40 +0100839
Hante Meuleman979c2922013-04-11 13:28:55 +0200840 brcmf_dbg(INFO, "SDIO: %d mA (req=%d mA) drive strength selected, set to 0x%08x\n",
841 str_tab[i].strength, drivestrength, cc_data_temp);
Franky Line12afb62011-11-04 22:23:40 +0100842 }
843}
Franky Lin069eddd2013-04-11 13:28:48 +0200844
Franky Lin069eddd2013-04-11 13:28:48 +0200845static void
846brcmf_sdio_chip_cm3_enterdl(struct brcmf_sdio_dev *sdiodev,
847 struct chip_info *ci)
848{
Franky Lin1640f282013-04-11 13:28:51 +0200849 ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
850 ci->resetcore(sdiodev, ci, BCMA_CORE_INTERNAL_MEM, 0);
Franky Lin069eddd2013-04-11 13:28:48 +0200851}
852
853static bool
Hante Meulemana74d0362014-01-13 22:20:22 +0100854brcmf_sdio_chip_cm3_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci)
Franky Lin069eddd2013-04-11 13:28:48 +0200855{
856 u8 core_idx;
857 u32 reg_addr;
858
859 if (!ci->iscoreup(sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) {
860 brcmf_err("SOCRAM core is down after reset?\n");
861 return false;
862 }
863
Franky Lin069eddd2013-04-11 13:28:48 +0200864 /* clear all interrupts */
865 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
866 reg_addr = ci->c_inf[core_idx].base;
867 reg_addr += offsetof(struct sdpcmd_regs, intstatus);
Arend van Spriela39be272013-12-12 11:58:58 +0100868 brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
Franky Lin069eddd2013-04-11 13:28:48 +0200869
Franky Lin1640f282013-04-11 13:28:51 +0200870 ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
871
872 return true;
873}
874
875static inline void
876brcmf_sdio_chip_cr4_enterdl(struct brcmf_sdio_dev *sdiodev,
877 struct chip_info *ci)
878{
879 ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4,
880 ARMCR4_BCMA_IOCTL_CPUHALT);
881}
882
883static bool
Hante Meulemana74d0362014-01-13 22:20:22 +0100884brcmf_sdio_chip_cr4_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci)
Franky Lin1640f282013-04-11 13:28:51 +0200885{
886 u8 core_idx;
887 u32 reg_addr;
888
Franky Lin1640f282013-04-11 13:28:51 +0200889 /* clear all interrupts */
890 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
891 reg_addr = ci->c_inf[core_idx].base;
892 reg_addr += offsetof(struct sdpcmd_regs, intstatus);
Arend van Spriela39be272013-12-12 11:58:58 +0100893 brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
Franky Lin1640f282013-04-11 13:28:51 +0200894
895 /* Write reset vector to address 0 */
Arend van Spriela39be272013-12-12 11:58:58 +0100896 brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&ci->rst_vec,
897 sizeof(ci->rst_vec));
Franky Lin1640f282013-04-11 13:28:51 +0200898
899 /* restore ARM */
900 ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, 0);
Franky Lin069eddd2013-04-11 13:28:48 +0200901
902 return true;
903}
904
905void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev,
906 struct chip_info *ci)
907{
Franky Lin1640f282013-04-11 13:28:51 +0200908 u8 arm_core_idx;
909
910 arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
911 if (BRCMF_MAX_CORENUM != arm_core_idx) {
912 brcmf_sdio_chip_cm3_enterdl(sdiodev, ci);
913 return;
914 }
915
916 brcmf_sdio_chip_cr4_enterdl(sdiodev, ci);
Franky Lin069eddd2013-04-11 13:28:48 +0200917}
918
919bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev,
Hante Meulemana74d0362014-01-13 22:20:22 +0100920 struct chip_info *ci)
Franky Lin069eddd2013-04-11 13:28:48 +0200921{
Franky Lin1640f282013-04-11 13:28:51 +0200922 u8 arm_core_idx;
923
924 arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
925 if (BRCMF_MAX_CORENUM != arm_core_idx)
Hante Meulemana74d0362014-01-13 22:20:22 +0100926 return brcmf_sdio_chip_cm3_exitdl(sdiodev, ci);
Franky Lin1640f282013-04-11 13:28:51 +0200927
Hante Meulemana74d0362014-01-13 22:20:22 +0100928 return brcmf_sdio_chip_cr4_exitdl(sdiodev, ci);
Franky Lin069eddd2013-04-11 13:28:48 +0200929}