blob: a0b8409063f1b380c99502b00f3dfcadd80a21b6 [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 Sprielaf35f552014-01-06 12:40:42 +010087/* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */
88static const struct sdiod_drive_str sdiod_drvstr_tab6_1v8[] = {
89 {3, 0x3},
90 {2, 0x2},
91 {1, 0x1},
92 {0, 0x0} };
93
Hante Meuleman979c2922013-04-11 13:28:55 +020094/* SDIO Drive Strength to sel value table for 43143 PMU Rev 17 (3.3V) */
95static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = {
96 {16, 0x7},
97 {12, 0x5},
98 {8, 0x3},
99 {4, 0x1}
100};
101
Franky Lin99ba15c2011-11-04 22:23:42 +0100102u8
103brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid)
104{
105 u8 idx;
106
107 for (idx = 0; idx < BRCMF_MAX_CORENUM; idx++)
108 if (coreid == ci->c_inf[idx].id)
109 return idx;
110
111 return BRCMF_MAX_CORENUM;
112}
113
Franky Lin454d2a82011-11-04 22:23:37 +0100114static u32
Franky Lin523894f2011-11-10 20:30:22 +0100115brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
116 struct chip_info *ci, u16 coreid)
Franky Lin454d2a82011-11-04 22:23:37 +0100117{
118 u32 regdata;
Franky Lin523894f2011-11-10 20:30:22 +0100119 u8 idx;
120
121 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin454d2a82011-11-04 22:23:37 +0100122
Arend van Spriela39be272013-12-12 11:58:58 +0100123 regdata = brcmf_sdiod_regrl(sdiodev,
124 CORE_SB(ci->c_inf[idx].base, sbidhigh),
125 NULL);
Franky Lin454d2a82011-11-04 22:23:37 +0100126 return SBCOREREV(regdata);
127}
128
Franky Lin523894f2011-11-10 20:30:22 +0100129static u32
130brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev,
131 struct chip_info *ci, u16 coreid)
132{
133 u8 idx;
134
135 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
136
137 return (ci->c_inf[idx].cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
138}
139
Franky Lin6ca687d2011-11-10 20:30:21 +0100140static bool
141brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
142 struct chip_info *ci, u16 coreid)
Franky Lind8f64a42011-11-04 22:23:36 +0100143{
144 u32 regdata;
Franky Lin6ca687d2011-11-10 20:30:21 +0100145 u8 idx;
146
147 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200148 if (idx == BRCMF_MAX_CORENUM)
149 return false;
Franky Lind8f64a42011-11-04 22:23:36 +0100150
Arend van Spriela39be272013-12-12 11:58:58 +0100151 regdata = brcmf_sdiod_regrl(sdiodev,
152 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
153 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100154 regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
155 SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
156 return (SSB_TMSLOW_CLOCK == regdata);
Franky Lind8f64a42011-11-04 22:23:36 +0100157}
158
Franky Lin6ca687d2011-11-10 20:30:21 +0100159static bool
160brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
161 struct chip_info *ci, u16 coreid)
162{
163 u32 regdata;
164 u8 idx;
165 bool ret;
166
167 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200168 if (idx == BRCMF_MAX_CORENUM)
169 return false;
Franky Lin6ca687d2011-11-10 20:30:21 +0100170
Arend van Spriela39be272013-12-12 11:58:58 +0100171 regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
172 NULL);
Franky Lin6ca687d2011-11-10 20:30:21 +0100173 ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
174
Arend van Spriela39be272013-12-12 11:58:58 +0100175 regdata = brcmf_sdiod_regrl(sdiodev,
176 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
177 NULL);
Franky Lin6ca687d2011-11-10 20:30:21 +0100178 ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
179
180 return ret;
181}
182
Franky Lin086a2e02011-11-10 20:30:23 +0100183static void
184brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
Franky Lin1640f282013-04-11 13:28:51 +0200185 struct chip_info *ci, u16 coreid, u32 core_bits)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100186{
Franky Lin79ae3952012-05-04 18:27:34 -0700187 u32 regdata, base;
Franky Lin086a2e02011-11-10 20:30:23 +0100188 u8 idx;
189
190 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin79ae3952012-05-04 18:27:34 -0700191 base = ci->c_inf[idx].base;
Franky Lin2d4a9af2011-11-04 22:23:31 +0100192
Arend van Spriela39be272013-12-12 11:58:58 +0100193 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100194 if (regdata & SSB_TMSLOW_RESET)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100195 return;
196
Arend van Spriela39be272013-12-12 11:58:58 +0100197 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100198 if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
Franky Lin2d4a9af2011-11-04 22:23:31 +0100199 /*
200 * set target reject and spin until busy is clear
201 * (preserve core-specific bits)
202 */
Arend van Spriela39be272013-12-12 11:58:58 +0100203 regdata = brcmf_sdiod_regrl(sdiodev,
204 CORE_SB(base, sbtmstatelow), NULL);
205 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
206 regdata | SSB_TMSLOW_REJECT, NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100207
Arend van Spriela39be272013-12-12 11:58:58 +0100208 regdata = brcmf_sdiod_regrl(sdiodev,
209 CORE_SB(base, sbtmstatelow), NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100210 udelay(1);
Arend van Spriela39be272013-12-12 11:58:58 +0100211 SPINWAIT((brcmf_sdiod_regrl(sdiodev,
212 CORE_SB(base, sbtmstatehigh),
213 NULL) &
214 SSB_TMSHIGH_BUSY), 100000);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100215
Arend van Spriela39be272013-12-12 11:58:58 +0100216 regdata = brcmf_sdiod_regrl(sdiodev,
217 CORE_SB(base, sbtmstatehigh),
218 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100219 if (regdata & SSB_TMSHIGH_BUSY)
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100220 brcmf_err("core state still busy\n");
Franky Lin2d4a9af2011-11-04 22:23:31 +0100221
Arend van Spriela39be272013-12-12 11:58:58 +0100222 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow),
223 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100224 if (regdata & SSB_IDLOW_INITIATOR) {
Arend van Spriela39be272013-12-12 11:58:58 +0100225 regdata = brcmf_sdiod_regrl(sdiodev,
226 CORE_SB(base, sbimstate),
227 NULL);
Franky Lin79ae3952012-05-04 18:27:34 -0700228 regdata |= SSB_IMSTATE_REJECT;
Arend van Spriela39be272013-12-12 11:58:58 +0100229 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate),
230 regdata, NULL);
231 regdata = brcmf_sdiod_regrl(sdiodev,
232 CORE_SB(base, sbimstate),
233 NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100234 udelay(1);
Arend van Spriela39be272013-12-12 11:58:58 +0100235 SPINWAIT((brcmf_sdiod_regrl(sdiodev,
236 CORE_SB(base, sbimstate),
237 NULL) &
238 SSB_IMSTATE_BUSY), 100000);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100239 }
240
241 /* set reset and reject while enabling the clocks */
Franky Line13ce262012-05-04 18:27:35 -0700242 regdata = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
243 SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET;
Arend van Spriela39be272013-12-12 11:58:58 +0100244 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
245 regdata, NULL);
246 regdata = brcmf_sdiod_regrl(sdiodev,
247 CORE_SB(base, sbtmstatelow), NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100248 udelay(10);
249
250 /* clear the initiator reject bit */
Arend van Spriela39be272013-12-12 11:58:58 +0100251 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow),
252 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100253 if (regdata & SSB_IDLOW_INITIATOR) {
Arend van Spriela39be272013-12-12 11:58:58 +0100254 regdata = brcmf_sdiod_regrl(sdiodev,
255 CORE_SB(base, sbimstate),
256 NULL);
Franky Lin79ae3952012-05-04 18:27:34 -0700257 regdata &= ~SSB_IMSTATE_REJECT;
Arend van Spriela39be272013-12-12 11:58:58 +0100258 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate),
259 regdata, NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100260 }
261 }
262
263 /* leave reset and reject asserted */
Arend van Spriela39be272013-12-12 11:58:58 +0100264 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
265 (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET), NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100266 udelay(1);
267}
268
Franky Lin086a2e02011-11-10 20:30:23 +0100269static void
270brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
Franky Lin1640f282013-04-11 13:28:51 +0200271 struct chip_info *ci, u16 coreid, u32 core_bits)
Franky Lin086a2e02011-11-10 20:30:23 +0100272{
273 u8 idx;
274 u32 regdata;
275
276 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200277 if (idx == BRCMF_MAX_CORENUM)
278 return;
Franky Lin086a2e02011-11-10 20:30:23 +0100279
280 /* if core is already in reset, just return */
Arend van Spriela39be272013-12-12 11:58:58 +0100281 regdata = brcmf_sdiod_regrl(sdiodev,
282 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
283 NULL);
Franky Lin086a2e02011-11-10 20:30:23 +0100284 if ((regdata & BCMA_RESET_CTL_RESET) != 0)
285 return;
286
Franky Lin1640f282013-04-11 13:28:51 +0200287 /* ensure no pending backplane operation
288 * 300uc should be sufficient for backplane ops to be finish
289 * extra 10ms is taken into account for firmware load stage
290 * after 10300us carry on disabling the core anyway
291 */
Arend van Spriela39be272013-12-12 11:58:58 +0100292 SPINWAIT(brcmf_sdiod_regrl(sdiodev,
Franky Lin1640f282013-04-11 13:28:51 +0200293 ci->c_inf[idx].wrapbase+BCMA_RESET_ST,
Arend van Spriela39be272013-12-12 11:58:58 +0100294 NULL), 10300);
295 regdata = brcmf_sdiod_regrl(sdiodev,
296 ci->c_inf[idx].wrapbase+BCMA_RESET_ST,
297 NULL);
Franky Lin1640f282013-04-11 13:28:51 +0200298 if (regdata)
299 brcmf_err("disabling core 0x%x with reset status %x\n",
300 coreid, regdata);
Franky Lin086a2e02011-11-10 20:30:23 +0100301
Arend van Spriela39be272013-12-12 11:58:58 +0100302 brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
303 BCMA_RESET_CTL_RESET, NULL);
Franky Lin086a2e02011-11-10 20:30:23 +0100304 udelay(1);
Franky Lin1640f282013-04-11 13:28:51 +0200305
Arend van Spriela39be272013-12-12 11:58:58 +0100306 brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
307 core_bits, NULL);
308 regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
309 NULL);
Franky Lin1640f282013-04-11 13:28:51 +0200310 usleep_range(10, 20);
311
Franky Lin086a2e02011-11-10 20:30:23 +0100312}
313
Franky Lind77e70f2011-11-10 20:30:24 +0100314static void
315brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
Franky Lin1640f282013-04-11 13:28:51 +0200316 struct chip_info *ci, u16 coreid, u32 core_bits)
Franky Lin2bc78e12011-11-04 22:23:38 +0100317{
318 u32 regdata;
Franky Lin086a2e02011-11-10 20:30:23 +0100319 u8 idx;
320
321 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200322 if (idx == BRCMF_MAX_CORENUM)
323 return;
Franky Lin2bc78e12011-11-04 22:23:38 +0100324
325 /*
326 * Must do the disable sequence first to work for
327 * arbitrary current core state.
328 */
Franky Lin1640f282013-04-11 13:28:51 +0200329 brcmf_sdio_sb_coredisable(sdiodev, ci, coreid, 0);
Franky Lin2bc78e12011-11-04 22:23:38 +0100330
331 /*
332 * Now do the initialization sequence.
333 * set reset while enabling the clock and
334 * forcing them on throughout the core
335 */
Arend van Spriela39be272013-12-12 11:58:58 +0100336 brcmf_sdiod_regwl(sdiodev,
337 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
338 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET,
339 NULL);
340 regdata = brcmf_sdiod_regrl(sdiodev,
341 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
342 NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100343 udelay(1);
344
Franky Lind77e70f2011-11-10 20:30:24 +0100345 /* clear any serror */
Arend van Spriela39be272013-12-12 11:58:58 +0100346 regdata = brcmf_sdiod_regrl(sdiodev,
347 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
348 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100349 if (regdata & SSB_TMSHIGH_SERR)
Arend van Spriela39be272013-12-12 11:58:58 +0100350 brcmf_sdiod_regwl(sdiodev,
351 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
352 0, NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100353
Arend van Spriela39be272013-12-12 11:58:58 +0100354 regdata = brcmf_sdiod_regrl(sdiodev,
355 CORE_SB(ci->c_inf[idx].base, sbimstate),
356 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100357 if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
Arend van Spriela39be272013-12-12 11:58:58 +0100358 brcmf_sdiod_regwl(sdiodev,
359 CORE_SB(ci->c_inf[idx].base, sbimstate),
360 regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO),
361 NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100362
363 /* clear reset and allow it to propagate throughout the core */
Arend van Spriela39be272013-12-12 11:58:58 +0100364 brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
365 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK, NULL);
366 regdata = brcmf_sdiod_regrl(sdiodev,
367 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
368 NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100369 udelay(1);
370
371 /* leave clock enabled */
Arend van Spriela39be272013-12-12 11:58:58 +0100372 brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
373 SSB_TMSLOW_CLOCK, NULL);
374 regdata = brcmf_sdiod_regrl(sdiodev,
375 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
376 NULL);
Franky Lind77e70f2011-11-10 20:30:24 +0100377 udelay(1);
378}
379
380static void
381brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
Franky Lin1640f282013-04-11 13:28:51 +0200382 struct chip_info *ci, u16 coreid, u32 core_bits)
Franky Lind77e70f2011-11-10 20:30:24 +0100383{
384 u8 idx;
385 u32 regdata;
386
387 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200388 if (idx == BRCMF_MAX_CORENUM)
389 return;
Franky Lind77e70f2011-11-10 20:30:24 +0100390
391 /* must disable first to work for arbitrary current core state */
Franky Lin1640f282013-04-11 13:28:51 +0200392 brcmf_sdio_ai_coredisable(sdiodev, ci, coreid, core_bits);
Franky Lind77e70f2011-11-10 20:30:24 +0100393
394 /* now do initialization sequence */
Arend van Spriela39be272013-12-12 11:58:58 +0100395 brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
396 core_bits | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
397 regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
398 NULL);
399 brcmf_sdiod_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
400 0, NULL);
401 regdata = brcmf_sdiod_regrl(sdiodev,
402 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
403 NULL);
Franky Lind77e70f2011-11-10 20:30:24 +0100404 udelay(1);
405
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_CLK, NULL);
408 regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
409 NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100410 udelay(1);
411}
412
Franky Lin1640f282013-04-11 13:28:51 +0200413#ifdef DEBUG
414/* safety check for chipinfo */
415static int brcmf_sdio_chip_cichk(struct chip_info *ci)
416{
417 u8 core_idx;
418
419 /* check RAM core presence for ARM CM3 core */
420 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
421 if (BRCMF_MAX_CORENUM != core_idx) {
422 core_idx = brcmf_sdio_chip_getinfidx(ci,
423 BCMA_CORE_INTERNAL_MEM);
424 if (BRCMF_MAX_CORENUM == core_idx) {
425 brcmf_err("RAM core not provided with ARM CM3 core\n");
426 return -ENODEV;
427 }
428 }
429
430 /* check RAM base for ARM CR4 core */
431 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CR4);
432 if (BRCMF_MAX_CORENUM != core_idx) {
433 if (ci->rambase == 0) {
434 brcmf_err("RAM base not provided with ARM CR4 core\n");
435 return -ENOMEM;
436 }
437 }
438
439 return 0;
440}
441#else /* DEBUG */
442static inline int brcmf_sdio_chip_cichk(struct chip_info *ci)
443{
444 return 0;
445}
446#endif
447
Franky Lina83369b2011-11-04 22:23:28 +0100448static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel4744d162013-12-12 11:58:55 +0100449 struct chip_info *ci)
Franky Lina83369b2011-11-04 22:23:28 +0100450{
451 u32 regdata;
Franky Lin1640f282013-04-11 13:28:51 +0200452 int ret;
Franky Lina83369b2011-11-04 22:23:28 +0100453
Franky Lin069eddd2013-04-11 13:28:48 +0200454 /* Get CC core rev
Franky Lina83369b2011-11-04 22:23:28 +0100455 * Chipid is assume to be at offset 0 from regs arg
456 * For different chiptypes or old sdio hosts w/o chipcommon,
457 * other ways of recognition should be added here.
458 */
Franky Lin99ba15c2011-11-04 22:23:42 +0100459 ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
Arend van Spriel4744d162013-12-12 11:58:55 +0100460 ci->c_inf[0].base = SI_ENUM_BASE;
Arend van Spriela39be272013-12-12 11:58:58 +0100461 regdata = brcmf_sdiod_regrl(sdiodev,
462 CORE_CC_REG(ci->c_inf[0].base, chipid),
463 NULL);
Franky Lina83369b2011-11-04 22:23:28 +0100464 ci->chip = regdata & CID_ID_MASK;
465 ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
Franky Linfe040152013-09-25 13:05:41 +0200466 if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 &&
467 ci->chiprev >= 2)
468 ci->chip = BCM4339_CHIP_ID;
Franky Lin6ca687d2011-11-10 20:30:21 +0100469 ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
Franky Lina83369b2011-11-04 22:23:28 +0100470
471 brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
472
473 /* Address of cores for new chips should be added here */
474 switch (ci->chip) {
Hante Meuleman369508c2013-04-11 13:28:54 +0200475 case BCM43143_CHIP_ID:
476 ci->c_inf[0].wrapbase = ci->c_inf[0].base + 0x00100000;
477 ci->c_inf[0].cib = 0x2b000000;
478 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
479 ci->c_inf[1].base = BCM43143_CORE_BUS_BASE;
480 ci->c_inf[1].wrapbase = ci->c_inf[1].base + 0x00100000;
481 ci->c_inf[1].cib = 0x18000000;
482 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
483 ci->c_inf[2].base = BCM43143_CORE_SOCRAM_BASE;
484 ci->c_inf[2].wrapbase = ci->c_inf[2].base + 0x00100000;
485 ci->c_inf[2].cib = 0x14000000;
486 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
487 ci->c_inf[3].base = BCM43143_CORE_ARM_BASE;
488 ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000;
489 ci->c_inf[3].cib = 0x07000000;
490 ci->ramsize = BCM43143_RAMSIZE;
491 break;
Franky Lin4a1c02c2012-08-30 19:42:59 +0200492 case BCM43241_CHIP_ID:
493 ci->c_inf[0].wrapbase = 0x18100000;
494 ci->c_inf[0].cib = 0x2a084411;
495 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
496 ci->c_inf[1].base = 0x18002000;
497 ci->c_inf[1].wrapbase = 0x18102000;
498 ci->c_inf[1].cib = 0x0e004211;
499 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
500 ci->c_inf[2].base = 0x18004000;
501 ci->c_inf[2].wrapbase = 0x18104000;
502 ci->c_inf[2].cib = 0x14080401;
503 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
504 ci->c_inf[3].base = 0x18003000;
505 ci->c_inf[3].wrapbase = 0x18103000;
506 ci->c_inf[3].cib = 0x07004211;
507 ci->ramsize = 0x90000;
508 break;
Franky Lina83369b2011-11-04 22:23:28 +0100509 case BCM4329_CHIP_ID:
Franky Lin99ba15c2011-11-04 22:23:42 +0100510 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
511 ci->c_inf[1].base = BCM4329_CORE_BUS_BASE;
512 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
513 ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE;
514 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
515 ci->c_inf[3].base = BCM4329_CORE_ARM_BASE;
Franky Lina83369b2011-11-04 22:23:28 +0100516 ci->ramsize = BCM4329_RAMSIZE;
517 break;
Franky Lince2d7d72011-12-08 15:06:39 -0800518 case BCM4330_CHIP_ID:
519 ci->c_inf[0].wrapbase = 0x18100000;
520 ci->c_inf[0].cib = 0x27004211;
521 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
522 ci->c_inf[1].base = 0x18002000;
523 ci->c_inf[1].wrapbase = 0x18102000;
524 ci->c_inf[1].cib = 0x07004211;
525 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
526 ci->c_inf[2].base = 0x18004000;
527 ci->c_inf[2].wrapbase = 0x18104000;
528 ci->c_inf[2].cib = 0x0d080401;
529 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
530 ci->c_inf[3].base = 0x18003000;
531 ci->c_inf[3].wrapbase = 0x18103000;
532 ci->c_inf[3].cib = 0x03004211;
533 ci->ramsize = 0x48000;
534 break;
Franky Lin85a4a1c2012-06-26 21:26:39 +0200535 case BCM4334_CHIP_ID:
536 ci->c_inf[0].wrapbase = 0x18100000;
537 ci->c_inf[0].cib = 0x29004211;
538 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
539 ci->c_inf[1].base = 0x18002000;
540 ci->c_inf[1].wrapbase = 0x18102000;
541 ci->c_inf[1].cib = 0x0d004211;
542 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
543 ci->c_inf[2].base = 0x18004000;
544 ci->c_inf[2].wrapbase = 0x18104000;
545 ci->c_inf[2].cib = 0x13080401;
546 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
547 ci->c_inf[3].base = 0x18003000;
548 ci->c_inf[3].wrapbase = 0x18103000;
549 ci->c_inf[3].cib = 0x07004211;
550 ci->ramsize = 0x80000;
551 break;
Franky Lin6a1c7482013-04-11 13:28:53 +0200552 case BCM4335_CHIP_ID:
553 ci->c_inf[0].wrapbase = 0x18100000;
554 ci->c_inf[0].cib = 0x2b084411;
555 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
556 ci->c_inf[1].base = 0x18005000;
557 ci->c_inf[1].wrapbase = 0x18105000;
558 ci->c_inf[1].cib = 0x0f004211;
559 ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
560 ci->c_inf[2].base = 0x18002000;
561 ci->c_inf[2].wrapbase = 0x18102000;
562 ci->c_inf[2].cib = 0x01084411;
563 ci->ramsize = 0xc0000;
564 ci->rambase = 0x180000;
565 break;
Franky Linfe040152013-09-25 13:05:41 +0200566 case BCM4339_CHIP_ID:
567 ci->c_inf[0].wrapbase = 0x18100000;
568 ci->c_inf[0].cib = 0x2e084411;
569 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
570 ci->c_inf[1].base = 0x18005000;
571 ci->c_inf[1].wrapbase = 0x18105000;
572 ci->c_inf[1].cib = 0x15004211;
573 ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
574 ci->c_inf[2].base = 0x18002000;
575 ci->c_inf[2].wrapbase = 0x18102000;
576 ci->c_inf[2].cib = 0x04084411;
577 ci->ramsize = 0xc0000;
578 ci->rambase = 0x180000;
579 break;
Franky Lina83369b2011-11-04 22:23:28 +0100580 default:
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100581 brcmf_err("chipid 0x%x is not supported\n", ci->chip);
Franky Lina83369b2011-11-04 22:23:28 +0100582 return -ENODEV;
583 }
584
Franky Lin1640f282013-04-11 13:28:51 +0200585 ret = brcmf_sdio_chip_cichk(ci);
586 if (ret)
587 return ret;
588
Franky Lin6ca687d2011-11-10 20:30:21 +0100589 switch (ci->socitype) {
590 case SOCI_SB:
591 ci->iscoreup = brcmf_sdio_sb_iscoreup;
Franky Lin523894f2011-11-10 20:30:22 +0100592 ci->corerev = brcmf_sdio_sb_corerev;
Franky Lin086a2e02011-11-10 20:30:23 +0100593 ci->coredisable = brcmf_sdio_sb_coredisable;
Franky Lind77e70f2011-11-10 20:30:24 +0100594 ci->resetcore = brcmf_sdio_sb_resetcore;
Franky Lin6ca687d2011-11-10 20:30:21 +0100595 break;
596 case SOCI_AI:
597 ci->iscoreup = brcmf_sdio_ai_iscoreup;
Franky Lin523894f2011-11-10 20:30:22 +0100598 ci->corerev = brcmf_sdio_ai_corerev;
Franky Lin086a2e02011-11-10 20:30:23 +0100599 ci->coredisable = brcmf_sdio_ai_coredisable;
Franky Lind77e70f2011-11-10 20:30:24 +0100600 ci->resetcore = brcmf_sdio_ai_resetcore;
Franky Lin6ca687d2011-11-10 20:30:21 +0100601 break;
602 default:
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100603 brcmf_err("socitype %u not supported\n", ci->socitype);
Franky Lin6ca687d2011-11-10 20:30:21 +0100604 return -ENODEV;
605 }
606
Franky Lina83369b2011-11-04 22:23:28 +0100607 return 0;
608}
609
Franky Line63ac6b2011-11-04 22:23:29 +0100610static int
611brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
612{
613 int err = 0;
614 u8 clkval, clkset;
615
616 /* Try forcing SDIO core to do ALPAvail request only */
617 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
Arend van Spriela39be272013-12-12 11:58:58 +0100618 brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
Franky Line63ac6b2011-11-04 22:23:29 +0100619 if (err) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100620 brcmf_err("error writing for HT off\n");
Franky Line63ac6b2011-11-04 22:23:29 +0100621 return err;
622 }
623
624 /* If register supported, wait for ALPAvail and then force ALP */
625 /* This may take up to 15 milliseconds */
Arend van Spriela39be272013-12-12 11:58:58 +0100626 clkval = brcmf_sdiod_regrb(sdiodev,
627 SBSDIO_FUNC1_CHIPCLKCSR, NULL);
Franky Line63ac6b2011-11-04 22:23:29 +0100628
629 if ((clkval & ~SBSDIO_AVBITS) != clkset) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100630 brcmf_err("ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
Franky Line63ac6b2011-11-04 22:23:29 +0100631 clkset, clkval);
632 return -EACCES;
633 }
634
Arend van Spriela39be272013-12-12 11:58:58 +0100635 SPINWAIT(((clkval = brcmf_sdiod_regrb(sdiodev,
636 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
Franky Line63ac6b2011-11-04 22:23:29 +0100637 !SBSDIO_ALPAV(clkval)),
638 PMU_MAX_TRANSITION_DLY);
639 if (!SBSDIO_ALPAV(clkval)) {
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100640 brcmf_err("timeout on ALPAV wait, clkval 0x%02x\n",
Franky Line63ac6b2011-11-04 22:23:29 +0100641 clkval);
642 return -EBUSY;
643 }
644
645 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
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 udelay(65);
648
649 /* Also, disable the extra SDIO pull-ups */
Arend van Spriela39be272013-12-12 11:58:58 +0100650 brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
Franky Line63ac6b2011-11-04 22:23:29 +0100651
652 return 0;
653}
654
Franky Lin5b45e542011-11-04 22:23:30 +0100655static void
656brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
657 struct chip_info *ci)
658{
Franky Lin79ae3952012-05-04 18:27:34 -0700659 u32 base = ci->c_inf[0].base;
660
Franky Lin5b45e542011-11-04 22:23:30 +0100661 /* get chipcommon rev */
Franky Lin523894f2011-11-10 20:30:22 +0100662 ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100663
664 /* get chipcommon capabilites */
Arend van Spriela39be272013-12-12 11:58:58 +0100665 ci->c_inf[0].caps = brcmf_sdiod_regrl(sdiodev,
666 CORE_CC_REG(base, capabilities),
667 NULL);
Franky Lin5b45e542011-11-04 22:23:30 +0100668
669 /* get pmu caps & rev */
Franky Lin99ba15c2011-11-04 22:23:42 +0100670 if (ci->c_inf[0].caps & CC_CAP_PMU) {
Franky Lin79ae3952012-05-04 18:27:34 -0700671 ci->pmucaps =
Arend van Spriela39be272013-12-12 11:58:58 +0100672 brcmf_sdiod_regrl(sdiodev,
673 CORE_CC_REG(base, pmucapabilities),
674 NULL);
Franky Lin5b45e542011-11-04 22:23:30 +0100675 ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
676 }
677
Franky Lin523894f2011-11-10 20:30:22 +0100678 ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100679
680 brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
Franky Lin99ba15c2011-11-04 22:23:42 +0100681 ci->c_inf[0].rev, ci->pmurev,
682 ci->c_inf[1].rev, ci->c_inf[1].id);
Franky Lin966414d2011-11-04 22:23:32 +0100683
684 /*
685 * Make sure any on-chip ARM is off (in case strapping is wrong),
686 * or downloaded code was already running.
687 */
Franky Lin1640f282013-04-11 13:28:51 +0200688 ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
Franky Lin5b45e542011-11-04 22:23:30 +0100689}
690
Franky Lina83369b2011-11-04 22:23:28 +0100691int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel4744d162013-12-12 11:58:55 +0100692 struct chip_info **ci_ptr)
Franky Lina83369b2011-11-04 22:23:28 +0100693{
Franky Lina97e4fc2011-11-04 22:23:35 +0100694 int ret;
695 struct chip_info *ci;
696
697 brcmf_dbg(TRACE, "Enter\n");
698
699 /* alloc chip_info_t */
700 ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
701 if (!ci)
702 return -ENOMEM;
Franky Lina83369b2011-11-04 22:23:28 +0100703
Franky Line63ac6b2011-11-04 22:23:29 +0100704 ret = brcmf_sdio_chip_buscoreprep(sdiodev);
705 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100706 goto err;
Franky Line63ac6b2011-11-04 22:23:29 +0100707
Arend van Spriel4744d162013-12-12 11:58:55 +0100708 ret = brcmf_sdio_chip_recognition(sdiodev, ci);
Franky Lina83369b2011-11-04 22:23:28 +0100709 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100710 goto err;
Franky Lina83369b2011-11-04 22:23:28 +0100711
Franky Lin5b45e542011-11-04 22:23:30 +0100712 brcmf_sdio_chip_buscoresetup(sdiodev, ci);
713
Arend van Spriela39be272013-12-12 11:58:58 +0100714 brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopullup),
715 0, NULL);
716 brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopulldown),
717 0, NULL);
Franky Lin960908d2011-11-04 22:23:33 +0100718
Franky Lina97e4fc2011-11-04 22:23:35 +0100719 *ci_ptr = ci;
720 return 0;
721
722err:
723 kfree(ci);
Franky Lina83369b2011-11-04 22:23:28 +0100724 return ret;
725}
Franky Lina8a6c042011-11-04 22:23:39 +0100726
727void
728brcmf_sdio_chip_detach(struct chip_info **ci_ptr)
729{
730 brcmf_dbg(TRACE, "Enter\n");
731
732 kfree(*ci_ptr);
733 *ci_ptr = NULL;
734}
Franky Line12afb62011-11-04 22:23:40 +0100735
736static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len)
737{
738 const char *fmt;
739
740 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
741 snprintf(buf, len, fmt, chipid);
742 return buf;
743}
744
745void
746brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
747 struct chip_info *ci, u32 drivestrength)
748{
Hante Meuleman979c2922013-04-11 13:28:55 +0200749 const struct sdiod_drive_str *str_tab = NULL;
750 u32 str_mask;
751 u32 str_shift;
Franky Line12afb62011-11-04 22:23:40 +0100752 char chn[8];
Franky Lin79ae3952012-05-04 18:27:34 -0700753 u32 base = ci->c_inf[0].base;
Hante Meuleman979c2922013-04-11 13:28:55 +0200754 u32 i;
755 u32 drivestrength_sel = 0;
756 u32 cc_data_temp;
757 u32 addr;
Franky Line12afb62011-11-04 22:23:40 +0100758
Franky Lin99ba15c2011-11-04 22:23:42 +0100759 if (!(ci->c_inf[0].caps & CC_CAP_PMU))
Franky Line12afb62011-11-04 22:23:40 +0100760 return;
761
762 switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
Franky Lince2d7d72011-12-08 15:06:39 -0800763 case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12):
Hante Meuleman979c2922013-04-11 13:28:55 +0200764 str_tab = sdiod_drvstr_tab1_1v8;
Franky Lince2d7d72011-12-08 15:06:39 -0800765 str_mask = 0x00003800;
766 str_shift = 11;
767 break;
Arend van Sprielaf35f552014-01-06 12:40:42 +0100768 case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17):
769 str_tab = sdiod_drvstr_tab6_1v8;
770 str_mask = 0x00001800;
771 str_shift = 11;
772 break;
Hante Meuleman979c2922013-04-11 13:28:55 +0200773 case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17):
774 /* note: 43143 does not support tristate */
775 i = ARRAY_SIZE(sdiod_drvstr_tab2_3v3) - 1;
776 if (drivestrength >= sdiod_drvstr_tab2_3v3[i].strength) {
777 str_tab = sdiod_drvstr_tab2_3v3;
778 str_mask = 0x00000007;
779 str_shift = 0;
780 } else
781 brcmf_err("Invalid SDIO Drive strength for chip %s, strength=%d\n",
782 brcmf_sdio_chip_name(ci->chip, chn, 8),
783 drivestrength);
784 break;
Franky Line12afb62011-11-04 22:23:40 +0100785 default:
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100786 brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
Franky Line12afb62011-11-04 22:23:40 +0100787 brcmf_sdio_chip_name(ci->chip, chn, 8),
788 ci->chiprev, ci->pmurev);
789 break;
790 }
791
792 if (str_tab != NULL) {
Franky Line12afb62011-11-04 22:23:40 +0100793 for (i = 0; str_tab[i].strength != 0; i++) {
794 if (drivestrength >= str_tab[i].strength) {
795 drivestrength_sel = str_tab[i].sel;
796 break;
797 }
798 }
Hante Meuleman979c2922013-04-11 13:28:55 +0200799 addr = CORE_CC_REG(base, chipcontrol_addr);
Arend van Spriela39be272013-12-12 11:58:58 +0100800 brcmf_sdiod_regwl(sdiodev, addr, 1, NULL);
801 cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL);
Franky Line12afb62011-11-04 22:23:40 +0100802 cc_data_temp &= ~str_mask;
803 drivestrength_sel <<= str_shift;
804 cc_data_temp |= drivestrength_sel;
Arend van Spriela39be272013-12-12 11:58:58 +0100805 brcmf_sdiod_regwl(sdiodev, addr, cc_data_temp, NULL);
Franky Line12afb62011-11-04 22:23:40 +0100806
Hante Meuleman979c2922013-04-11 13:28:55 +0200807 brcmf_dbg(INFO, "SDIO: %d mA (req=%d mA) drive strength selected, set to 0x%08x\n",
808 str_tab[i].strength, drivestrength, cc_data_temp);
Franky Line12afb62011-11-04 22:23:40 +0100809 }
810}
Franky Lin069eddd2013-04-11 13:28:48 +0200811
812#ifdef DEBUG
813static bool
814brcmf_sdio_chip_verifynvram(struct brcmf_sdio_dev *sdiodev, u32 nvram_addr,
815 char *nvram_dat, uint nvram_sz)
816{
817 char *nvram_ularray;
818 int err;
819 bool ret = true;
820
821 /* read back and verify */
822 brcmf_dbg(INFO, "Compare NVRAM dl & ul; size=%d\n", nvram_sz);
823 nvram_ularray = kmalloc(nvram_sz, GFP_KERNEL);
824 /* do not proceed while no memory but */
825 if (!nvram_ularray)
826 return true;
827
828 /* Upload image to verify downloaded contents. */
829 memset(nvram_ularray, 0xaa, nvram_sz);
830
831 /* Read the vars list to temp buffer for comparison */
Arend van Spriela39be272013-12-12 11:58:58 +0100832 err = brcmf_sdiod_ramrw(sdiodev, false, nvram_addr, nvram_ularray,
833 nvram_sz);
Franky Lin069eddd2013-04-11 13:28:48 +0200834 if (err) {
835 brcmf_err("error %d on reading %d nvram bytes at 0x%08x\n",
836 err, nvram_sz, nvram_addr);
837 } else if (memcmp(nvram_dat, nvram_ularray, nvram_sz)) {
838 brcmf_err("Downloaded NVRAM image is corrupted\n");
839 ret = false;
840 }
841 kfree(nvram_ularray);
842
843 return ret;
844}
845#else /* DEBUG */
846static inline bool
847brcmf_sdio_chip_verifynvram(struct brcmf_sdio_dev *sdiodev, u32 nvram_addr,
848 char *nvram_dat, uint nvram_sz)
849{
850 return true;
851}
852#endif /* DEBUG */
853
854static bool brcmf_sdio_chip_writenvram(struct brcmf_sdio_dev *sdiodev,
855 struct chip_info *ci,
856 char *nvram_dat, uint nvram_sz)
857{
858 int err;
859 u32 nvram_addr;
860 u32 token;
861 __le32 token_le;
862
Franky Lin1640f282013-04-11 13:28:51 +0200863 nvram_addr = (ci->ramsize - 4) - nvram_sz + ci->rambase;
Franky Lin069eddd2013-04-11 13:28:48 +0200864
865 /* Write the vars list */
Arend van Spriela39be272013-12-12 11:58:58 +0100866 err = brcmf_sdiod_ramrw(sdiodev, true, nvram_addr, nvram_dat, nvram_sz);
Franky Lin069eddd2013-04-11 13:28:48 +0200867 if (err) {
868 brcmf_err("error %d on writing %d nvram bytes at 0x%08x\n",
869 err, nvram_sz, nvram_addr);
870 return false;
871 }
872
873 if (!brcmf_sdio_chip_verifynvram(sdiodev, nvram_addr,
874 nvram_dat, nvram_sz))
875 return false;
876
877 /* generate token:
878 * nvram size, converted to words, in lower 16-bits, checksum
879 * in upper 16-bits.
880 */
881 token = nvram_sz / 4;
882 token = (~token << 16) | (token & 0x0000FFFF);
883 token_le = cpu_to_le32(token);
884
885 brcmf_dbg(INFO, "RAM size: %d\n", ci->ramsize);
886 brcmf_dbg(INFO, "nvram is placed at %d, size %d, token=0x%08x\n",
887 nvram_addr, nvram_sz, token);
888
889 /* Write the length token to the last word */
Arend van Spriela39be272013-12-12 11:58:58 +0100890 if (brcmf_sdiod_ramrw(sdiodev, true, (ci->ramsize - 4 + ci->rambase),
891 (u8 *)&token_le, 4))
Franky Lin069eddd2013-04-11 13:28:48 +0200892 return false;
893
894 return true;
895}
896
897static void
898brcmf_sdio_chip_cm3_enterdl(struct brcmf_sdio_dev *sdiodev,
899 struct chip_info *ci)
900{
901 u32 zeros = 0;
902
Franky Lin1640f282013-04-11 13:28:51 +0200903 ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
904 ci->resetcore(sdiodev, ci, BCMA_CORE_INTERNAL_MEM, 0);
Franky Lin069eddd2013-04-11 13:28:48 +0200905
906 /* clear length token */
Arend van Spriela39be272013-12-12 11:58:58 +0100907 brcmf_sdiod_ramrw(sdiodev, true, ci->ramsize - 4, (u8 *)&zeros, 4);
Franky Lin069eddd2013-04-11 13:28:48 +0200908}
909
910static bool
911brcmf_sdio_chip_cm3_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
912 char *nvram_dat, uint nvram_sz)
913{
914 u8 core_idx;
915 u32 reg_addr;
916
917 if (!ci->iscoreup(sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) {
918 brcmf_err("SOCRAM core is down after reset?\n");
919 return false;
920 }
921
922 if (!brcmf_sdio_chip_writenvram(sdiodev, ci, nvram_dat, nvram_sz))
923 return false;
924
925 /* clear all interrupts */
926 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
927 reg_addr = ci->c_inf[core_idx].base;
928 reg_addr += offsetof(struct sdpcmd_regs, intstatus);
Arend van Spriela39be272013-12-12 11:58:58 +0100929 brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
Franky Lin069eddd2013-04-11 13:28:48 +0200930
Franky Lin1640f282013-04-11 13:28:51 +0200931 ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CM3, 0);
932
933 return true;
934}
935
936static inline void
937brcmf_sdio_chip_cr4_enterdl(struct brcmf_sdio_dev *sdiodev,
938 struct chip_info *ci)
939{
940 ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4,
941 ARMCR4_BCMA_IOCTL_CPUHALT);
942}
943
944static bool
945brcmf_sdio_chip_cr4_exitdl(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
946 char *nvram_dat, uint nvram_sz)
947{
948 u8 core_idx;
949 u32 reg_addr;
950
951 if (!brcmf_sdio_chip_writenvram(sdiodev, ci, nvram_dat, nvram_sz))
952 return false;
953
954 /* clear all interrupts */
955 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
956 reg_addr = ci->c_inf[core_idx].base;
957 reg_addr += offsetof(struct sdpcmd_regs, intstatus);
Arend van Spriela39be272013-12-12 11:58:58 +0100958 brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
Franky Lin1640f282013-04-11 13:28:51 +0200959
960 /* Write reset vector to address 0 */
Arend van Spriela39be272013-12-12 11:58:58 +0100961 brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&ci->rst_vec,
962 sizeof(ci->rst_vec));
Franky Lin1640f282013-04-11 13:28:51 +0200963
964 /* restore ARM */
965 ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, 0);
Franky Lin069eddd2013-04-11 13:28:48 +0200966
967 return true;
968}
969
970void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev,
971 struct chip_info *ci)
972{
Franky Lin1640f282013-04-11 13:28:51 +0200973 u8 arm_core_idx;
974
975 arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
976 if (BRCMF_MAX_CORENUM != arm_core_idx) {
977 brcmf_sdio_chip_cm3_enterdl(sdiodev, ci);
978 return;
979 }
980
981 brcmf_sdio_chip_cr4_enterdl(sdiodev, ci);
Franky Lin069eddd2013-04-11 13:28:48 +0200982}
983
984bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev,
985 struct chip_info *ci, char *nvram_dat,
986 uint nvram_sz)
987{
Franky Lin1640f282013-04-11 13:28:51 +0200988 u8 arm_core_idx;
989
990 arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
991 if (BRCMF_MAX_CORENUM != arm_core_idx)
992 return brcmf_sdio_chip_cm3_exitdl(sdiodev, ci, nvram_dat,
993 nvram_sz);
994
995 return brcmf_sdio_chip_cr4_exitdl(sdiodev, ci, nvram_dat, nvram_sz);
Franky Lin069eddd2013-04-11 13:28:48 +0200996}