blob: 6aa6ba02b036dc1435cc46ad1814a24a5cbc3726 [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>
Franky Lin61213be2011-11-04 22:23:41 +010022#include <linux/ssb/ssb_regs.h>
Franky Lin99ba15c2011-11-04 22:23:42 +010023#include <linux/bcma/bcma.h>
Franky Lin61213be2011-11-04 22:23:41 +010024
Franky Lina83369b2011-11-04 22:23:28 +010025#include <chipcommon.h>
26#include <brcm_hw_ids.h>
27#include <brcmu_wifi.h>
28#include <brcmu_utils.h>
Franky Lin2d4a9af2011-11-04 22:23:31 +010029#include <soc.h>
Franky Lina83369b2011-11-04 22:23:28 +010030#include "dhd_dbg.h"
31#include "sdio_host.h"
32#include "sdio_chip.h"
33
34/* chip core base & ramsize */
35/* bcm4329 */
36/* SDIO device core, ID 0x829 */
37#define BCM4329_CORE_BUS_BASE 0x18011000
38/* internal memory core, ID 0x80e */
39#define BCM4329_CORE_SOCRAM_BASE 0x18003000
40/* ARM Cortex M3 core, ID 0x82a */
41#define BCM4329_CORE_ARM_BASE 0x18002000
42#define BCM4329_RAMSIZE 0x48000
43
Hante Meuleman369508c2013-04-11 13:28:54 +020044/* bcm43143 */
45/* SDIO device core */
46#define BCM43143_CORE_BUS_BASE 0x18002000
47/* internal memory core */
48#define BCM43143_CORE_SOCRAM_BASE 0x18004000
49/* ARM Cortex M3 core, ID 0x82a */
50#define BCM43143_CORE_ARM_BASE 0x18003000
51#define BCM43143_RAMSIZE 0x70000
52
Franky Lina83369b2011-11-04 22:23:28 +010053#define SBCOREREV(sbidh) \
Franky Lin61213be2011-11-04 22:23:41 +010054 ((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \
55 ((sbidh) & SSB_IDHIGH_RCLO))
Franky Lina83369b2011-11-04 22:23:28 +010056
Franky Lin6ca687d2011-11-10 20:30:21 +010057/* SOC Interconnect types (aka chip types) */
58#define SOCI_SB 0
59#define SOCI_AI 1
60
Franky Lin523894f2011-11-10 20:30:22 +010061/* EROM CompIdentB */
62#define CIB_REV_MASK 0xff000000
63#define CIB_REV_SHIFT 24
64
Franky Lin1640f282013-04-11 13:28:51 +020065/* ARM CR4 core specific control flag bits */
66#define ARMCR4_BCMA_IOCTL_CPUHALT 0x0020
67
Franky Line12afb62011-11-04 22:23:40 +010068#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
69/* SDIO Pad drive strength to select value mappings */
70struct sdiod_drive_str {
71 u8 strength; /* Pad Drive Strength in mA */
72 u8 sel; /* Chip-specific select value */
73};
Franky Lince2d7d72011-12-08 15:06:39 -080074/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8V) */
Franky Linffb27562011-12-08 15:06:40 -080075static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = {
Franky Lince2d7d72011-12-08 15:06:39 -080076 {32, 0x6},
77 {26, 0x7},
78 {22, 0x4},
79 {16, 0x5},
80 {12, 0x2},
81 {8, 0x3},
82 {4, 0x0},
83 {0, 0x1}
84};
85
Arend van Sprielaf35f552014-01-06 12:40:42 +010086/* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */
87static const struct sdiod_drive_str sdiod_drvstr_tab6_1v8[] = {
88 {3, 0x3},
89 {2, 0x2},
90 {1, 0x1},
91 {0, 0x0} };
92
Hante Meuleman979c2922013-04-11 13:28:55 +020093/* SDIO Drive Strength to sel value table for 43143 PMU Rev 17 (3.3V) */
94static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = {
95 {16, 0x7},
96 {12, 0x5},
97 {8, 0x3},
98 {4, 0x1}
99};
100
Franky Lin99ba15c2011-11-04 22:23:42 +0100101u8
102brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid)
103{
104 u8 idx;
105
106 for (idx = 0; idx < BRCMF_MAX_CORENUM; idx++)
107 if (coreid == ci->c_inf[idx].id)
108 return idx;
109
110 return BRCMF_MAX_CORENUM;
111}
112
Franky Lin454d2a82011-11-04 22:23:37 +0100113static u32
Franky Lin523894f2011-11-10 20:30:22 +0100114brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
115 struct chip_info *ci, u16 coreid)
Franky Lin454d2a82011-11-04 22:23:37 +0100116{
117 u32 regdata;
Franky Lin523894f2011-11-10 20:30:22 +0100118 u8 idx;
119
120 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin454d2a82011-11-04 22:23:37 +0100121
Arend van Spriela39be272013-12-12 11:58:58 +0100122 regdata = brcmf_sdiod_regrl(sdiodev,
123 CORE_SB(ci->c_inf[idx].base, sbidhigh),
124 NULL);
Franky Lin454d2a82011-11-04 22:23:37 +0100125 return SBCOREREV(regdata);
126}
127
Franky Lin523894f2011-11-10 20:30:22 +0100128static u32
129brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev,
130 struct chip_info *ci, u16 coreid)
131{
132 u8 idx;
133
134 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
135
136 return (ci->c_inf[idx].cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
137}
138
Franky Lin6ca687d2011-11-10 20:30:21 +0100139static bool
140brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
141 struct chip_info *ci, u16 coreid)
Franky Lind8f64a42011-11-04 22:23:36 +0100142{
143 u32 regdata;
Franky Lin6ca687d2011-11-10 20:30:21 +0100144 u8 idx;
145
146 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200147 if (idx == BRCMF_MAX_CORENUM)
148 return false;
Franky Lind8f64a42011-11-04 22:23:36 +0100149
Arend van Spriela39be272013-12-12 11:58:58 +0100150 regdata = brcmf_sdiod_regrl(sdiodev,
151 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
152 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100153 regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
154 SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
155 return (SSB_TMSLOW_CLOCK == regdata);
Franky Lind8f64a42011-11-04 22:23:36 +0100156}
157
Franky Lin6ca687d2011-11-10 20:30:21 +0100158static bool
159brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
160 struct chip_info *ci, u16 coreid)
161{
162 u32 regdata;
163 u8 idx;
164 bool ret;
165
166 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200167 if (idx == BRCMF_MAX_CORENUM)
168 return false;
Franky Lin6ca687d2011-11-10 20:30:21 +0100169
Arend van Spriela39be272013-12-12 11:58:58 +0100170 regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
171 NULL);
Franky Lin6ca687d2011-11-10 20:30:21 +0100172 ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
173
Arend van Spriela39be272013-12-12 11:58:58 +0100174 regdata = brcmf_sdiod_regrl(sdiodev,
175 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
176 NULL);
Franky Lin6ca687d2011-11-10 20:30:21 +0100177 ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
178
179 return ret;
180}
181
Franky Lin086a2e02011-11-10 20:30:23 +0100182static void
183brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
Franky Lin1640f282013-04-11 13:28:51 +0200184 struct chip_info *ci, u16 coreid, u32 core_bits)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100185{
Franky Lin79ae3952012-05-04 18:27:34 -0700186 u32 regdata, base;
Franky Lin086a2e02011-11-10 20:30:23 +0100187 u8 idx;
188
189 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin79ae3952012-05-04 18:27:34 -0700190 base = ci->c_inf[idx].base;
Franky Lin2d4a9af2011-11-04 22:23:31 +0100191
Arend van Spriela39be272013-12-12 11:58:58 +0100192 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100193 if (regdata & SSB_TMSLOW_RESET)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100194 return;
195
Arend van Spriela39be272013-12-12 11:58:58 +0100196 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100197 if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
Franky Lin2d4a9af2011-11-04 22:23:31 +0100198 /*
199 * set target reject and spin until busy is clear
200 * (preserve core-specific bits)
201 */
Arend van Spriela39be272013-12-12 11:58:58 +0100202 regdata = brcmf_sdiod_regrl(sdiodev,
203 CORE_SB(base, sbtmstatelow), NULL);
204 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
205 regdata | SSB_TMSLOW_REJECT, NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100206
Arend van Spriela39be272013-12-12 11:58:58 +0100207 regdata = brcmf_sdiod_regrl(sdiodev,
208 CORE_SB(base, sbtmstatelow), NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100209 udelay(1);
Arend van Spriela39be272013-12-12 11:58:58 +0100210 SPINWAIT((brcmf_sdiod_regrl(sdiodev,
211 CORE_SB(base, sbtmstatehigh),
212 NULL) &
213 SSB_TMSHIGH_BUSY), 100000);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100214
Arend van Spriela39be272013-12-12 11:58:58 +0100215 regdata = brcmf_sdiod_regrl(sdiodev,
216 CORE_SB(base, sbtmstatehigh),
217 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100218 if (regdata & SSB_TMSHIGH_BUSY)
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100219 brcmf_err("core state still busy\n");
Franky Lin2d4a9af2011-11-04 22:23:31 +0100220
Arend van Spriela39be272013-12-12 11:58:58 +0100221 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow),
222 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100223 if (regdata & SSB_IDLOW_INITIATOR) {
Arend van Spriela39be272013-12-12 11:58:58 +0100224 regdata = brcmf_sdiod_regrl(sdiodev,
225 CORE_SB(base, sbimstate),
226 NULL);
Franky Lin79ae3952012-05-04 18:27:34 -0700227 regdata |= SSB_IMSTATE_REJECT;
Arend van Spriela39be272013-12-12 11:58:58 +0100228 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate),
229 regdata, NULL);
230 regdata = brcmf_sdiod_regrl(sdiodev,
231 CORE_SB(base, sbimstate),
232 NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100233 udelay(1);
Arend van Spriela39be272013-12-12 11:58:58 +0100234 SPINWAIT((brcmf_sdiod_regrl(sdiodev,
235 CORE_SB(base, sbimstate),
236 NULL) &
237 SSB_IMSTATE_BUSY), 100000);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100238 }
239
240 /* set reset and reject while enabling the clocks */
Franky Line13ce262012-05-04 18:27:35 -0700241 regdata = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
242 SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET;
Arend van Spriela39be272013-12-12 11:58:58 +0100243 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
244 regdata, NULL);
245 regdata = brcmf_sdiod_regrl(sdiodev,
246 CORE_SB(base, sbtmstatelow), NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100247 udelay(10);
248
249 /* clear the initiator reject bit */
Arend van Spriela39be272013-12-12 11:58:58 +0100250 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow),
251 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100252 if (regdata & SSB_IDLOW_INITIATOR) {
Arend van Spriela39be272013-12-12 11:58:58 +0100253 regdata = brcmf_sdiod_regrl(sdiodev,
254 CORE_SB(base, sbimstate),
255 NULL);
Franky Lin79ae3952012-05-04 18:27:34 -0700256 regdata &= ~SSB_IMSTATE_REJECT;
Arend van Spriela39be272013-12-12 11:58:58 +0100257 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate),
258 regdata, NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100259 }
260 }
261
262 /* leave reset and reject asserted */
Arend van Spriela39be272013-12-12 11:58:58 +0100263 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
264 (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET), NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100265 udelay(1);
266}
267
Franky Lin086a2e02011-11-10 20:30:23 +0100268static void
269brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
Franky Lin1640f282013-04-11 13:28:51 +0200270 struct chip_info *ci, u16 coreid, u32 core_bits)
Franky Lin086a2e02011-11-10 20:30:23 +0100271{
272 u8 idx;
273 u32 regdata;
274
275 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200276 if (idx == BRCMF_MAX_CORENUM)
277 return;
Franky Lin086a2e02011-11-10 20:30:23 +0100278
279 /* if core is already in reset, just return */
Arend van Spriela39be272013-12-12 11:58:58 +0100280 regdata = brcmf_sdiod_regrl(sdiodev,
281 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
282 NULL);
Franky Lin086a2e02011-11-10 20:30:23 +0100283 if ((regdata & BCMA_RESET_CTL_RESET) != 0)
284 return;
285
Franky Lin1640f282013-04-11 13:28:51 +0200286 /* ensure no pending backplane operation
287 * 300uc should be sufficient for backplane ops to be finish
288 * extra 10ms is taken into account for firmware load stage
289 * after 10300us carry on disabling the core anyway
290 */
Arend van Spriela39be272013-12-12 11:58:58 +0100291 SPINWAIT(brcmf_sdiod_regrl(sdiodev,
Franky Lin1640f282013-04-11 13:28:51 +0200292 ci->c_inf[idx].wrapbase+BCMA_RESET_ST,
Arend van Spriela39be272013-12-12 11:58:58 +0100293 NULL), 10300);
294 regdata = brcmf_sdiod_regrl(sdiodev,
295 ci->c_inf[idx].wrapbase+BCMA_RESET_ST,
296 NULL);
Franky Lin1640f282013-04-11 13:28:51 +0200297 if (regdata)
298 brcmf_err("disabling core 0x%x with reset status %x\n",
299 coreid, regdata);
Franky Lin086a2e02011-11-10 20:30:23 +0100300
Arend van Spriela39be272013-12-12 11:58:58 +0100301 brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
302 BCMA_RESET_CTL_RESET, NULL);
Franky Lin086a2e02011-11-10 20:30:23 +0100303 udelay(1);
Franky Lin1640f282013-04-11 13:28:51 +0200304
Arend van Spriela39be272013-12-12 11:58:58 +0100305 brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
306 core_bits, NULL);
307 regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
308 NULL);
Franky Lin1640f282013-04-11 13:28:51 +0200309 usleep_range(10, 20);
310
Franky Lin086a2e02011-11-10 20:30:23 +0100311}
312
Franky Lind77e70f2011-11-10 20:30:24 +0100313static void
314brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
Franky Lin1640f282013-04-11 13:28:51 +0200315 struct chip_info *ci, u16 coreid, u32 core_bits)
Franky Lin2bc78e12011-11-04 22:23:38 +0100316{
317 u32 regdata;
Franky Lin086a2e02011-11-10 20:30:23 +0100318 u8 idx;
319
320 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200321 if (idx == BRCMF_MAX_CORENUM)
322 return;
Franky Lin2bc78e12011-11-04 22:23:38 +0100323
324 /*
325 * Must do the disable sequence first to work for
326 * arbitrary current core state.
327 */
Franky Lin1640f282013-04-11 13:28:51 +0200328 brcmf_sdio_sb_coredisable(sdiodev, ci, coreid, 0);
Franky Lin2bc78e12011-11-04 22:23:38 +0100329
330 /*
331 * Now do the initialization sequence.
332 * set reset while enabling the clock and
333 * forcing them on throughout the core
334 */
Arend van Spriela39be272013-12-12 11:58:58 +0100335 brcmf_sdiod_regwl(sdiodev,
336 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
337 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET,
338 NULL);
339 regdata = brcmf_sdiod_regrl(sdiodev,
340 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
341 NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100342 udelay(1);
343
Franky Lind77e70f2011-11-10 20:30:24 +0100344 /* clear any serror */
Arend van Spriela39be272013-12-12 11:58:58 +0100345 regdata = brcmf_sdiod_regrl(sdiodev,
346 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
347 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100348 if (regdata & SSB_TMSHIGH_SERR)
Arend van Spriela39be272013-12-12 11:58:58 +0100349 brcmf_sdiod_regwl(sdiodev,
350 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
351 0, NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100352
Arend van Spriela39be272013-12-12 11:58:58 +0100353 regdata = brcmf_sdiod_regrl(sdiodev,
354 CORE_SB(ci->c_inf[idx].base, sbimstate),
355 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100356 if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
Arend van Spriela39be272013-12-12 11:58:58 +0100357 brcmf_sdiod_regwl(sdiodev,
358 CORE_SB(ci->c_inf[idx].base, sbimstate),
359 regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO),
360 NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100361
362 /* clear reset and allow it to propagate throughout the core */
Arend van Spriela39be272013-12-12 11:58:58 +0100363 brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
364 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK, NULL);
365 regdata = brcmf_sdiod_regrl(sdiodev,
366 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
367 NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100368 udelay(1);
369
370 /* leave clock enabled */
Arend van Spriela39be272013-12-12 11:58:58 +0100371 brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
372 SSB_TMSLOW_CLOCK, NULL);
373 regdata = brcmf_sdiod_regrl(sdiodev,
374 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
375 NULL);
Franky Lind77e70f2011-11-10 20:30:24 +0100376 udelay(1);
377}
378
379static void
380brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
Franky Lin1640f282013-04-11 13:28:51 +0200381 struct chip_info *ci, u16 coreid, u32 core_bits)
Franky Lind77e70f2011-11-10 20:30:24 +0100382{
383 u8 idx;
384 u32 regdata;
385
386 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200387 if (idx == BRCMF_MAX_CORENUM)
388 return;
Franky Lind77e70f2011-11-10 20:30:24 +0100389
390 /* must disable first to work for arbitrary current core state */
Franky Lin1640f282013-04-11 13:28:51 +0200391 brcmf_sdio_ai_coredisable(sdiodev, ci, coreid, core_bits);
Franky Lind77e70f2011-11-10 20:30:24 +0100392
393 /* now do initialization sequence */
Arend van Spriela39be272013-12-12 11:58:58 +0100394 brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
395 core_bits | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
396 regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
397 NULL);
398 brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
399 0, NULL);
400 regdata = brcmf_sdiod_regrl(sdiodev,
401 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
402 NULL);
Franky Lind77e70f2011-11-10 20:30:24 +0100403 udelay(1);
404
Arend van Spriela39be272013-12-12 11:58:58 +0100405 brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
406 core_bits | BCMA_IOCTL_CLK, NULL);
407 regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
408 NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100409 udelay(1);
410}
411
Franky Lin1640f282013-04-11 13:28:51 +0200412#ifdef DEBUG
413/* safety check for chipinfo */
414static int brcmf_sdio_chip_cichk(struct chip_info *ci)
415{
416 u8 core_idx;
417
418 /* check RAM core presence for ARM CM3 core */
419 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
420 if (BRCMF_MAX_CORENUM != core_idx) {
421 core_idx = brcmf_sdio_chip_getinfidx(ci,
422 BCMA_CORE_INTERNAL_MEM);
423 if (BRCMF_MAX_CORENUM == core_idx) {
424 brcmf_err("RAM core not provided with ARM CM3 core\n");
425 return -ENODEV;
426 }
427 }
428
429 /* check RAM base for ARM CR4 core */
430 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CR4);
431 if (BRCMF_MAX_CORENUM != core_idx) {
432 if (ci->rambase == 0) {
433 brcmf_err("RAM base not provided with ARM CR4 core\n");
434 return -ENOMEM;
435 }
436 }
437
438 return 0;
439}
440#else /* DEBUG */
441static inline int brcmf_sdio_chip_cichk(struct chip_info *ci)
442{
443 return 0;
444}
445#endif
446
Franky Lina83369b2011-11-04 22:23:28 +0100447static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel4744d162013-12-12 11:58:55 +0100448 struct chip_info *ci)
Franky Lina83369b2011-11-04 22:23:28 +0100449{
450 u32 regdata;
Franky Lin1640f282013-04-11 13:28:51 +0200451 int ret;
Franky Lina83369b2011-11-04 22:23:28 +0100452
Franky Lin069eddd2013-04-11 13:28:48 +0200453 /* Get CC core rev
Franky Lina83369b2011-11-04 22:23:28 +0100454 * Chipid is assume to be at offset 0 from regs arg
455 * For different chiptypes or old sdio hosts w/o chipcommon,
456 * other ways of recognition should be added here.
457 */
Franky Lin99ba15c2011-11-04 22:23:42 +0100458 ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
Arend van Spriel4744d162013-12-12 11:58:55 +0100459 ci->c_inf[0].base = SI_ENUM_BASE;
Arend van Spriela39be272013-12-12 11:58:58 +0100460 regdata = brcmf_sdiod_regrl(sdiodev,
461 CORE_CC_REG(ci->c_inf[0].base, chipid),
462 NULL);
Franky Lina83369b2011-11-04 22:23:28 +0100463 ci->chip = regdata & CID_ID_MASK;
464 ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
Franky Linfe040152013-09-25 13:05:41 +0200465 if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 &&
466 ci->chiprev >= 2)
467 ci->chip = BCM4339_CHIP_ID;
Franky Lin6ca687d2011-11-10 20:30:21 +0100468 ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
Franky Lina83369b2011-11-04 22:23:28 +0100469
470 brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
471
472 /* Address of cores for new chips should be added here */
473 switch (ci->chip) {
Hante Meuleman369508c2013-04-11 13:28:54 +0200474 case BCM43143_CHIP_ID:
475 ci->c_inf[0].wrapbase = ci->c_inf[0].base + 0x00100000;
476 ci->c_inf[0].cib = 0x2b000000;
477 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
478 ci->c_inf[1].base = BCM43143_CORE_BUS_BASE;
479 ci->c_inf[1].wrapbase = ci->c_inf[1].base + 0x00100000;
480 ci->c_inf[1].cib = 0x18000000;
481 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
482 ci->c_inf[2].base = BCM43143_CORE_SOCRAM_BASE;
483 ci->c_inf[2].wrapbase = ci->c_inf[2].base + 0x00100000;
484 ci->c_inf[2].cib = 0x14000000;
485 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
486 ci->c_inf[3].base = BCM43143_CORE_ARM_BASE;
487 ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000;
488 ci->c_inf[3].cib = 0x07000000;
489 ci->ramsize = BCM43143_RAMSIZE;
490 break;
Franky Lin4a1c02c2012-08-30 19:42:59 +0200491 case BCM43241_CHIP_ID:
492 ci->c_inf[0].wrapbase = 0x18100000;
493 ci->c_inf[0].cib = 0x2a084411;
494 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
495 ci->c_inf[1].base = 0x18002000;
496 ci->c_inf[1].wrapbase = 0x18102000;
497 ci->c_inf[1].cib = 0x0e004211;
498 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
499 ci->c_inf[2].base = 0x18004000;
500 ci->c_inf[2].wrapbase = 0x18104000;
501 ci->c_inf[2].cib = 0x14080401;
502 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
503 ci->c_inf[3].base = 0x18003000;
504 ci->c_inf[3].wrapbase = 0x18103000;
505 ci->c_inf[3].cib = 0x07004211;
506 ci->ramsize = 0x90000;
507 break;
Franky Lina83369b2011-11-04 22:23:28 +0100508 case BCM4329_CHIP_ID:
Franky Lin99ba15c2011-11-04 22:23:42 +0100509 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
510 ci->c_inf[1].base = BCM4329_CORE_BUS_BASE;
511 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
512 ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE;
513 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
514 ci->c_inf[3].base = BCM4329_CORE_ARM_BASE;
Franky Lina83369b2011-11-04 22:23:28 +0100515 ci->ramsize = BCM4329_RAMSIZE;
516 break;
Franky Lince2d7d72011-12-08 15:06:39 -0800517 case BCM4330_CHIP_ID:
518 ci->c_inf[0].wrapbase = 0x18100000;
519 ci->c_inf[0].cib = 0x27004211;
520 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
521 ci->c_inf[1].base = 0x18002000;
522 ci->c_inf[1].wrapbase = 0x18102000;
523 ci->c_inf[1].cib = 0x07004211;
524 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
525 ci->c_inf[2].base = 0x18004000;
526 ci->c_inf[2].wrapbase = 0x18104000;
527 ci->c_inf[2].cib = 0x0d080401;
528 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
529 ci->c_inf[3].base = 0x18003000;
530 ci->c_inf[3].wrapbase = 0x18103000;
531 ci->c_inf[3].cib = 0x03004211;
532 ci->ramsize = 0x48000;
533 break;
Franky Lin85a4a1c2012-06-26 21:26:39 +0200534 case BCM4334_CHIP_ID:
535 ci->c_inf[0].wrapbase = 0x18100000;
536 ci->c_inf[0].cib = 0x29004211;
537 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
538 ci->c_inf[1].base = 0x18002000;
539 ci->c_inf[1].wrapbase = 0x18102000;
540 ci->c_inf[1].cib = 0x0d004211;
541 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
542 ci->c_inf[2].base = 0x18004000;
543 ci->c_inf[2].wrapbase = 0x18104000;
544 ci->c_inf[2].cib = 0x13080401;
545 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
546 ci->c_inf[3].base = 0x18003000;
547 ci->c_inf[3].wrapbase = 0x18103000;
548 ci->c_inf[3].cib = 0x07004211;
549 ci->ramsize = 0x80000;
550 break;
Franky Lin6a1c7482013-04-11 13:28:53 +0200551 case BCM4335_CHIP_ID:
552 ci->c_inf[0].wrapbase = 0x18100000;
553 ci->c_inf[0].cib = 0x2b084411;
554 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
555 ci->c_inf[1].base = 0x18005000;
556 ci->c_inf[1].wrapbase = 0x18105000;
557 ci->c_inf[1].cib = 0x0f004211;
558 ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
559 ci->c_inf[2].base = 0x18002000;
560 ci->c_inf[2].wrapbase = 0x18102000;
561 ci->c_inf[2].cib = 0x01084411;
562 ci->ramsize = 0xc0000;
563 ci->rambase = 0x180000;
564 break;
Franky Linfe040152013-09-25 13:05:41 +0200565 case BCM4339_CHIP_ID:
566 ci->c_inf[0].wrapbase = 0x18100000;
567 ci->c_inf[0].cib = 0x2e084411;
568 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
569 ci->c_inf[1].base = 0x18005000;
570 ci->c_inf[1].wrapbase = 0x18105000;
571 ci->c_inf[1].cib = 0x15004211;
572 ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
573 ci->c_inf[2].base = 0x18002000;
574 ci->c_inf[2].wrapbase = 0x18102000;
575 ci->c_inf[2].cib = 0x04084411;
576 ci->ramsize = 0xc0000;
577 ci->rambase = 0x180000;
578 break;
Franky Lina83369b2011-11-04 22:23:28 +0100579 default:
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100580 brcmf_err("chipid 0x%x is not supported\n", ci->chip);
Franky Lina83369b2011-11-04 22:23:28 +0100581 return -ENODEV;
582 }
583
Franky Lin1640f282013-04-11 13:28:51 +0200584 ret = brcmf_sdio_chip_cichk(ci);
585 if (ret)
586 return ret;
587
Franky Lin6ca687d2011-11-10 20:30:21 +0100588 switch (ci->socitype) {
589 case SOCI_SB:
590 ci->iscoreup = brcmf_sdio_sb_iscoreup;
Franky Lin523894f2011-11-10 20:30:22 +0100591 ci->corerev = brcmf_sdio_sb_corerev;
Franky Lin086a2e02011-11-10 20:30:23 +0100592 ci->coredisable = brcmf_sdio_sb_coredisable;
Franky Lind77e70f2011-11-10 20:30:24 +0100593 ci->resetcore = brcmf_sdio_sb_resetcore;
Franky Lin6ca687d2011-11-10 20:30:21 +0100594 break;
595 case SOCI_AI:
596 ci->iscoreup = brcmf_sdio_ai_iscoreup;
Franky Lin523894f2011-11-10 20:30:22 +0100597 ci->corerev = brcmf_sdio_ai_corerev;
Franky Lin086a2e02011-11-10 20:30:23 +0100598 ci->coredisable = brcmf_sdio_ai_coredisable;
Franky Lind77e70f2011-11-10 20:30:24 +0100599 ci->resetcore = brcmf_sdio_ai_resetcore;
Franky Lin6ca687d2011-11-10 20:30:21 +0100600 break;
601 default:
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100602 brcmf_err("socitype %u not supported\n", ci->socitype);
Franky Lin6ca687d2011-11-10 20:30:21 +0100603 return -ENODEV;
604 }
605
Franky Lina83369b2011-11-04 22:23:28 +0100606 return 0;
607}
608
Franky Line63ac6b2011-11-04 22:23:29 +0100609static int
610brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
611{
612 int err = 0;
613 u8 clkval, clkset;
614
615 /* Try forcing SDIO core to do ALPAvail request only */
616 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
Arend van Spriela39be272013-12-12 11:58:58 +0100617 brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
Franky Line63ac6b2011-11-04 22:23:29 +0100618 if (err) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100619 brcmf_err("error writing for HT off\n");
Franky Line63ac6b2011-11-04 22:23:29 +0100620 return err;
621 }
622
623 /* If register supported, wait for ALPAvail and then force ALP */
624 /* This may take up to 15 milliseconds */
Arend van Spriela39be272013-12-12 11:58:58 +0100625 clkval = brcmf_sdiod_regrb(sdiodev,
626 SBSDIO_FUNC1_CHIPCLKCSR, NULL);
Franky Line63ac6b2011-11-04 22:23:29 +0100627
628 if ((clkval & ~SBSDIO_AVBITS) != clkset) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100629 brcmf_err("ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
Franky Line63ac6b2011-11-04 22:23:29 +0100630 clkset, clkval);
631 return -EACCES;
632 }
633
Arend van Spriela39be272013-12-12 11:58:58 +0100634 SPINWAIT(((clkval = brcmf_sdiod_regrb(sdiodev,
635 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
Franky Line63ac6b2011-11-04 22:23:29 +0100636 !SBSDIO_ALPAV(clkval)),
637 PMU_MAX_TRANSITION_DLY);
638 if (!SBSDIO_ALPAV(clkval)) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100639 brcmf_err("timeout on ALPAV wait, clkval 0x%02x\n",
Franky Line63ac6b2011-11-04 22:23:29 +0100640 clkval);
641 return -EBUSY;
642 }
643
644 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
Arend van Spriela39be272013-12-12 11:58:58 +0100645 brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
Franky Line63ac6b2011-11-04 22:23:29 +0100646 udelay(65);
647
648 /* Also, disable the extra SDIO pull-ups */
Arend van Spriela39be272013-12-12 11:58:58 +0100649 brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
Franky Line63ac6b2011-11-04 22:23:29 +0100650
651 return 0;
652}
653
Franky Lin5b45e542011-11-04 22:23:30 +0100654static void
655brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
656 struct chip_info *ci)
657{
Franky Lin79ae3952012-05-04 18:27:34 -0700658 u32 base = ci->c_inf[0].base;
659
Franky Lin5b45e542011-11-04 22:23:30 +0100660 /* get chipcommon rev */
Franky Lin523894f2011-11-10 20:30:22 +0100661 ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100662
663 /* get chipcommon capabilites */
Arend van Spriela39be272013-12-12 11:58:58 +0100664 ci->c_inf[0].caps = brcmf_sdiod_regrl(sdiodev,
665 CORE_CC_REG(base, capabilities),
666 NULL);
Franky Lin5b45e542011-11-04 22:23:30 +0100667
668 /* get pmu caps & rev */
Franky Lin99ba15c2011-11-04 22:23:42 +0100669 if (ci->c_inf[0].caps & CC_CAP_PMU) {
Franky Lin79ae3952012-05-04 18:27:34 -0700670 ci->pmucaps =
Arend van Spriela39be272013-12-12 11:58:58 +0100671 brcmf_sdiod_regrl(sdiodev,
672 CORE_CC_REG(base, pmucapabilities),
673 NULL);
Franky Lin5b45e542011-11-04 22:23:30 +0100674 ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
675 }
676
Franky Lin523894f2011-11-10 20:30:22 +0100677 ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100678
679 brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
Franky Lin99ba15c2011-11-04 22:23:42 +0100680 ci->c_inf[0].rev, ci->pmurev,
681 ci->c_inf[1].rev, ci->c_inf[1].id);
Franky Lin966414d2011-11-04 22:23:32 +0100682
683 /*
684 * Make sure any on-chip ARM is off (in case strapping is wrong),
685 * or downloaded code was already running.
686 */
Franky Lin1640f282013-04-11 13:28:51 +0200687 ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
Franky Lin5b45e542011-11-04 22:23:30 +0100688}
689
Franky Lina83369b2011-11-04 22:23:28 +0100690int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel4744d162013-12-12 11:58:55 +0100691 struct chip_info **ci_ptr)
Franky Lina83369b2011-11-04 22:23:28 +0100692{
Franky Lina97e4fc2011-11-04 22:23:35 +0100693 int ret;
694 struct chip_info *ci;
695
696 brcmf_dbg(TRACE, "Enter\n");
697
698 /* alloc chip_info_t */
699 ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
700 if (!ci)
701 return -ENOMEM;
Franky Lina83369b2011-11-04 22:23:28 +0100702
Franky Line63ac6b2011-11-04 22:23:29 +0100703 ret = brcmf_sdio_chip_buscoreprep(sdiodev);
704 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100705 goto err;
Franky Line63ac6b2011-11-04 22:23:29 +0100706
Arend van Spriel4744d162013-12-12 11:58:55 +0100707 ret = brcmf_sdio_chip_recognition(sdiodev, ci);
Franky Lina83369b2011-11-04 22:23:28 +0100708 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100709 goto err;
Franky Lina83369b2011-11-04 22:23:28 +0100710
Franky Lin5b45e542011-11-04 22:23:30 +0100711 brcmf_sdio_chip_buscoresetup(sdiodev, ci);
712
Arend van Spriela39be272013-12-12 11:58:58 +0100713 brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopullup),
714 0, NULL);
715 brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopulldown),
716 0, NULL);
Franky Lin960908d2011-11-04 22:23:33 +0100717
Franky Lina97e4fc2011-11-04 22:23:35 +0100718 *ci_ptr = ci;
719 return 0;
720
721err:
722 kfree(ci);
Franky Lina83369b2011-11-04 22:23:28 +0100723 return ret;
724}
Franky Lina8a6c042011-11-04 22:23:39 +0100725
726void
727brcmf_sdio_chip_detach(struct chip_info **ci_ptr)
728{
729 brcmf_dbg(TRACE, "Enter\n");
730
731 kfree(*ci_ptr);
732 *ci_ptr = NULL;
733}
Franky Line12afb62011-11-04 22:23:40 +0100734
735static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len)
736{
737 const char *fmt;
738
739 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
740 snprintf(buf, len, fmt, chipid);
741 return buf;
742}
743
744void
745brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
746 struct chip_info *ci, u32 drivestrength)
747{
Hante Meuleman979c2922013-04-11 13:28:55 +0200748 const struct sdiod_drive_str *str_tab = NULL;
749 u32 str_mask;
750 u32 str_shift;
Franky Line12afb62011-11-04 22:23:40 +0100751 char chn[8];
Franky Lin79ae3952012-05-04 18:27:34 -0700752 u32 base = ci->c_inf[0].base;
Hante Meuleman979c2922013-04-11 13:28:55 +0200753 u32 i;
754 u32 drivestrength_sel = 0;
755 u32 cc_data_temp;
756 u32 addr;
Franky Line12afb62011-11-04 22:23:40 +0100757
Franky Lin99ba15c2011-11-04 22:23:42 +0100758 if (!(ci->c_inf[0].caps & CC_CAP_PMU))
Franky Line12afb62011-11-04 22:23:40 +0100759 return;
760
761 switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
Franky Lince2d7d72011-12-08 15:06:39 -0800762 case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12):
Hante Meuleman979c2922013-04-11 13:28:55 +0200763 str_tab = sdiod_drvstr_tab1_1v8;
Franky Lince2d7d72011-12-08 15:06:39 -0800764 str_mask = 0x00003800;
765 str_shift = 11;
766 break;
Arend van Sprielaf35f552014-01-06 12:40:42 +0100767 case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17):
768 str_tab = sdiod_drvstr_tab6_1v8;
769 str_mask = 0x00001800;
770 str_shift = 11;
771 break;
Hante Meuleman979c2922013-04-11 13:28:55 +0200772 case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17):
773 /* note: 43143 does not support tristate */
774 i = ARRAY_SIZE(sdiod_drvstr_tab2_3v3) - 1;
775 if (drivestrength >= sdiod_drvstr_tab2_3v3[i].strength) {
776 str_tab = sdiod_drvstr_tab2_3v3;
777 str_mask = 0x00000007;
778 str_shift = 0;
779 } else
780 brcmf_err("Invalid SDIO Drive strength for chip %s, strength=%d\n",
781 brcmf_sdio_chip_name(ci->chip, chn, 8),
782 drivestrength);
783 break;
Franky Line12afb62011-11-04 22:23:40 +0100784 default:
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100785 brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
Franky Line12afb62011-11-04 22:23:40 +0100786 brcmf_sdio_chip_name(ci->chip, chn, 8),
787 ci->chiprev, ci->pmurev);
788 break;
789 }
790
791 if (str_tab != NULL) {
Franky Line12afb62011-11-04 22:23:40 +0100792 for (i = 0; str_tab[i].strength != 0; i++) {
793 if (drivestrength >= str_tab[i].strength) {
794 drivestrength_sel = str_tab[i].sel;
795 break;
796 }
797 }
Hante Meuleman979c2922013-04-11 13:28:55 +0200798 addr = CORE_CC_REG(base, chipcontrol_addr);
Arend van Spriela39be272013-12-12 11:58:58 +0100799 brcmf_sdiod_regwl(sdiodev, addr, 1, NULL);
800 cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL);
Franky Line12afb62011-11-04 22:23:40 +0100801 cc_data_temp &= ~str_mask;
802 drivestrength_sel <<= str_shift;
803 cc_data_temp |= drivestrength_sel;
Arend van Spriela39be272013-12-12 11:58:58 +0100804 brcmf_sdiod_regwl(sdiodev, addr, cc_data_temp, NULL);
Franky Line12afb62011-11-04 22:23:40 +0100805
Hante Meuleman979c2922013-04-11 13:28:55 +0200806 brcmf_dbg(INFO, "SDIO: %d mA (req=%d mA) drive strength selected, set to 0x%08x\n",
807 str_tab[i].strength, drivestrength, cc_data_temp);
Franky Line12afb62011-11-04 22:23:40 +0100808 }
809}
Franky Lin069eddd2013-04-11 13:28:48 +0200810
811#ifdef DEBUG
812static bool
813brcmf_sdio_chip_verifynvram(struct brcmf_sdio_dev *sdiodev, u32 nvram_addr,
814 char *nvram_dat, uint nvram_sz)
815{
816 char *nvram_ularray;
817 int err;
818 bool ret = true;
819
820 /* read back and verify */
821 brcmf_dbg(INFO, "Compare NVRAM dl & ul; size=%d\n", nvram_sz);
822 nvram_ularray = kmalloc(nvram_sz, GFP_KERNEL);
823 /* do not proceed while no memory but */
824 if (!nvram_ularray)
825 return true;
826
827 /* Upload image to verify downloaded contents. */
828 memset(nvram_ularray, 0xaa, nvram_sz);
829
830 /* Read the vars list to temp buffer for comparison */
Arend van Spriela39be272013-12-12 11:58:58 +0100831 err = brcmf_sdiod_ramrw(sdiodev, false, nvram_addr, nvram_ularray,
832 nvram_sz);
Franky Lin069eddd2013-04-11 13:28:48 +0200833 if (err) {
834 brcmf_err("error %d on reading %d nvram bytes at 0x%08x\n",
835 err, nvram_sz, nvram_addr);
836 } else if (memcmp(nvram_dat, nvram_ularray, nvram_sz)) {
837 brcmf_err("Downloaded NVRAM image is corrupted\n");
838 ret = false;
839 }
840 kfree(nvram_ularray);
841
842 return ret;
843}
844#else /* DEBUG */
845static inline bool
846brcmf_sdio_chip_verifynvram(struct brcmf_sdio_dev *sdiodev, u32 nvram_addr,
847 char *nvram_dat, uint nvram_sz)
848{
849 return true;
850}
851#endif /* DEBUG */
852
853static bool brcmf_sdio_chip_writenvram(struct brcmf_sdio_dev *sdiodev,
854 struct chip_info *ci,
855 char *nvram_dat, uint nvram_sz)
856{
857 int err;
858 u32 nvram_addr;
859 u32 token;
860 __le32 token_le;
861
Franky Lin1640f282013-04-11 13:28:51 +0200862 nvram_addr = (ci->ramsize - 4) - nvram_sz + ci->rambase;
Franky Lin069eddd2013-04-11 13:28:48 +0200863
864 /* Write the vars list */
Arend van Spriela39be272013-12-12 11:58:58 +0100865 err = brcmf_sdiod_ramrw(sdiodev, true, nvram_addr, nvram_dat, nvram_sz);
Franky Lin069eddd2013-04-11 13:28:48 +0200866 if (err) {
867 brcmf_err("error %d on writing %d nvram bytes at 0x%08x\n",
868 err, nvram_sz, nvram_addr);
869 return false;
870 }
871
872 if (!brcmf_sdio_chip_verifynvram(sdiodev, nvram_addr,
873 nvram_dat, nvram_sz))
874 return false;
875
876 /* generate token:
877 * nvram size, converted to words, in lower 16-bits, checksum
878 * in upper 16-bits.
879 */
880 token = nvram_sz / 4;
881 token = (~token << 16) | (token & 0x0000FFFF);
882 token_le = cpu_to_le32(token);
883
884 brcmf_dbg(INFO, "RAM size: %d\n", ci->ramsize);
885 brcmf_dbg(INFO, "nvram is placed at %d, size %d, token=0x%08x\n",
886 nvram_addr, nvram_sz, token);
887
888 /* Write the length token to the last word */
Arend van Spriela39be272013-12-12 11:58:58 +0100889 if (brcmf_sdiod_ramrw(sdiodev, true, (ci->ramsize - 4 + ci->rambase),
890 (u8 *)&token_le, 4))
Franky Lin069eddd2013-04-11 13:28:48 +0200891 return false;
892
893 return true;
894}
895
896static void
897brcmf_sdio_chip_cm3_enterdl(struct brcmf_sdio_dev *sdiodev,
898 struct chip_info *ci)
899{
900 u32 zeros = 0;
901
Franky Lin1640f282013-04-11 13:28:51 +0200902 ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
903 ci->resetcore(sdiodev, ci, BCMA_CORE_INTERNAL_MEM, 0);
Franky Lin069eddd2013-04-11 13:28:48 +0200904
905 /* clear length token */
Arend van Spriela39be272013-12-12 11:58:58 +0100906 brcmf_sdiod_ramrw(sdiodev, true, ci->ramsize - 4, (u8 *)&zeros, 4);
Franky Lin069eddd2013-04-11 13:28:48 +0200907}
908
909static bool
910brcmf_sdio_chip_cm3_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
911 char *nvram_dat, uint nvram_sz)
912{
913 u8 core_idx;
914 u32 reg_addr;
915
916 if (!ci->iscoreup(sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) {
917 brcmf_err("SOCRAM core is down after reset?\n");
918 return false;
919 }
920
921 if (!brcmf_sdio_chip_writenvram(sdiodev, ci, nvram_dat, nvram_sz))
922 return false;
923
924 /* clear all interrupts */
925 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
926 reg_addr = ci->c_inf[core_idx].base;
927 reg_addr += offsetof(struct sdpcmd_regs, intstatus);
Arend van Spriela39be272013-12-12 11:58:58 +0100928 brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
Franky Lin069eddd2013-04-11 13:28:48 +0200929
Franky Lin1640f282013-04-11 13:28:51 +0200930 ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
931
932 return true;
933}
934
935static inline void
936brcmf_sdio_chip_cr4_enterdl(struct brcmf_sdio_dev *sdiodev,
937 struct chip_info *ci)
938{
939 ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4,
940 ARMCR4_BCMA_IOCTL_CPUHALT);
941}
942
943static bool
944brcmf_sdio_chip_cr4_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
945 char *nvram_dat, uint nvram_sz)
946{
947 u8 core_idx;
948 u32 reg_addr;
949
950 if (!brcmf_sdio_chip_writenvram(sdiodev, ci, nvram_dat, nvram_sz))
951 return false;
952
953 /* clear all interrupts */
954 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
955 reg_addr = ci->c_inf[core_idx].base;
956 reg_addr += offsetof(struct sdpcmd_regs, intstatus);
Arend van Spriela39be272013-12-12 11:58:58 +0100957 brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
Franky Lin1640f282013-04-11 13:28:51 +0200958
959 /* Write reset vector to address 0 */
Arend van Spriela39be272013-12-12 11:58:58 +0100960 brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&ci->rst_vec,
961 sizeof(ci->rst_vec));
Franky Lin1640f282013-04-11 13:28:51 +0200962
963 /* restore ARM */
964 ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, 0);
Franky Lin069eddd2013-04-11 13:28:48 +0200965
966 return true;
967}
968
969void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev,
970 struct chip_info *ci)
971{
Franky Lin1640f282013-04-11 13:28:51 +0200972 u8 arm_core_idx;
973
974 arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
975 if (BRCMF_MAX_CORENUM != arm_core_idx) {
976 brcmf_sdio_chip_cm3_enterdl(sdiodev, ci);
977 return;
978 }
979
980 brcmf_sdio_chip_cr4_enterdl(sdiodev, ci);
Franky Lin069eddd2013-04-11 13:28:48 +0200981}
982
983bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev,
984 struct chip_info *ci, char *nvram_dat,
985 uint nvram_sz)
986{
Franky Lin1640f282013-04-11 13:28:51 +0200987 u8 arm_core_idx;
988
989 arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
990 if (BRCMF_MAX_CORENUM != arm_core_idx)
991 return brcmf_sdio_chip_cm3_exitdl(sdiodev, ci, nvram_dat,
992 nvram_sz);
993
994 return brcmf_sdio_chip_cr4_exitdl(sdiodev, ci, nvram_dat, nvram_sz);
Franky Lin069eddd2013-04-11 13:28:48 +0200995}