blob: 37fd44a3483a84fb0119e79bc4e64e9afca104de [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"
Arend van Spriel20c9c9b2014-01-29 15:32:15 +010033#include "chip.h"
Franky Lina83369b2011-11-04 22:23:28 +010034
35/* chip core base & ramsize */
36/* bcm4329 */
37/* SDIO device core, ID 0x829 */
38#define BCM4329_CORE_BUS_BASE 0x18011000
39/* internal memory core, ID 0x80e */
40#define BCM4329_CORE_SOCRAM_BASE 0x18003000
41/* ARM Cortex M3 core, ID 0x82a */
42#define BCM4329_CORE_ARM_BASE 0x18002000
43#define BCM4329_RAMSIZE 0x48000
44
Hante Meuleman369508c2013-04-11 13:28:54 +020045/* bcm43143 */
46/* SDIO device core */
47#define BCM43143_CORE_BUS_BASE 0x18002000
48/* internal memory core */
49#define BCM43143_CORE_SOCRAM_BASE 0x18004000
50/* ARM Cortex M3 core, ID 0x82a */
51#define BCM43143_CORE_ARM_BASE 0x18003000
52#define BCM43143_RAMSIZE 0x70000
53
Hante Meuleman53036262014-01-13 22:20:23 +010054/* All D11 cores, ID 0x812 */
55#define BCM43xx_CORE_D11_BASE 0x18001000
56
Franky Lina83369b2011-11-04 22:23:28 +010057#define SBCOREREV(sbidh) \
Franky Lin61213be2011-11-04 22:23:41 +010058 ((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \
59 ((sbidh) & SSB_IDHIGH_RCLO))
Franky Lina83369b2011-11-04 22:23:28 +010060
Franky Lin6ca687d2011-11-10 20:30:21 +010061/* SOC Interconnect types (aka chip types) */
62#define SOCI_SB 0
63#define SOCI_AI 1
64
Franky Lin523894f2011-11-10 20:30:22 +010065/* EROM CompIdentB */
66#define CIB_REV_MASK 0xff000000
67#define CIB_REV_SHIFT 24
68
Franky Lin1640f282013-04-11 13:28:51 +020069/* ARM CR4 core specific control flag bits */
70#define ARMCR4_BCMA_IOCTL_CPUHALT 0x0020
71
Hante Meuleman53036262014-01-13 22:20:23 +010072/* D11 core specific control flag bits */
73#define D11_BCMA_IOCTL_PHYCLOCKEN 0x0004
74#define D11_BCMA_IOCTL_PHYRESET 0x0008
75
Franky Lin99ba15c2011-11-04 22:23:42 +010076u8
Arend van Spriel9cf218f2014-01-13 22:20:27 +010077brcmf_sdio_chip_getinfidx(struct brcmf_chip *ci, u16 coreid)
Franky Lin99ba15c2011-11-04 22:23:42 +010078{
79 u8 idx;
80
81 for (idx = 0; idx < BRCMF_MAX_CORENUM; idx++)
82 if (coreid == ci->c_inf[idx].id)
83 return idx;
84
85 return BRCMF_MAX_CORENUM;
86}
87
Franky Lin454d2a82011-11-04 22:23:37 +010088static u32
Franky Lin523894f2011-11-10 20:30:22 +010089brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel9cf218f2014-01-13 22:20:27 +010090 struct brcmf_chip *ci, u16 coreid)
Franky Lin454d2a82011-11-04 22:23:37 +010091{
92 u32 regdata;
Franky Lin523894f2011-11-10 20:30:22 +010093 u8 idx;
94
95 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin454d2a82011-11-04 22:23:37 +010096
Arend van Spriela39be272013-12-12 11:58:58 +010097 regdata = brcmf_sdiod_regrl(sdiodev,
98 CORE_SB(ci->c_inf[idx].base, sbidhigh),
99 NULL);
Franky Lin454d2a82011-11-04 22:23:37 +0100100 return SBCOREREV(regdata);
101}
102
Franky Lin523894f2011-11-10 20:30:22 +0100103static u32
104brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100105 struct brcmf_chip *ci, u16 coreid)
Franky Lin523894f2011-11-10 20:30:22 +0100106{
107 u8 idx;
108
109 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
110
111 return (ci->c_inf[idx].cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
112}
113
Franky Lin6ca687d2011-11-10 20:30:21 +0100114static bool
115brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100116 struct brcmf_chip *ci, u16 coreid)
Franky Lind8f64a42011-11-04 22:23:36 +0100117{
118 u32 regdata;
Franky Lin6ca687d2011-11-10 20:30:21 +0100119 u8 idx;
120
121 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200122 if (idx == BRCMF_MAX_CORENUM)
123 return false;
Franky Lind8f64a42011-11-04 22:23:36 +0100124
Arend van Spriela39be272013-12-12 11:58:58 +0100125 regdata = brcmf_sdiod_regrl(sdiodev,
126 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
127 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100128 regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
129 SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
Arend van Spriel20c9c9b2014-01-29 15:32:15 +0100130 return SSB_TMSLOW_CLOCK == regdata;
Franky Lind8f64a42011-11-04 22:23:36 +0100131}
132
Franky Lin6ca687d2011-11-10 20:30:21 +0100133static bool
134brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100135 struct brcmf_chip *ci, u16 coreid)
Franky Lin6ca687d2011-11-10 20:30:21 +0100136{
137 u32 regdata;
138 u8 idx;
139 bool ret;
140
141 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200142 if (idx == BRCMF_MAX_CORENUM)
143 return false;
Franky Lin6ca687d2011-11-10 20:30:21 +0100144
Arend van Spriela39be272013-12-12 11:58:58 +0100145 regdata = brcmf_sdiod_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
146 NULL);
Franky Lin6ca687d2011-11-10 20:30:21 +0100147 ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
148
Arend van Spriela39be272013-12-12 11:58:58 +0100149 regdata = brcmf_sdiod_regrl(sdiodev,
150 ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
151 NULL);
Franky Lin6ca687d2011-11-10 20:30:21 +0100152 ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
153
154 return ret;
155}
156
Franky Lin086a2e02011-11-10 20:30:23 +0100157static void
158brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100159 struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits,
Hante Meuleman53036262014-01-13 22:20:23 +0100160 u32 in_resetbits)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100161{
Franky Lin79ae3952012-05-04 18:27:34 -0700162 u32 regdata, base;
Franky Lin086a2e02011-11-10 20:30:23 +0100163 u8 idx;
164
165 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin79ae3952012-05-04 18:27:34 -0700166 base = ci->c_inf[idx].base;
Franky Lin2d4a9af2011-11-04 22:23:31 +0100167
Arend van Spriela39be272013-12-12 11:58:58 +0100168 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100169 if (regdata & SSB_TMSLOW_RESET)
Franky Lin2d4a9af2011-11-04 22:23:31 +0100170 return;
171
Arend van Spriela39be272013-12-12 11:58:58 +0100172 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100173 if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
Franky Lin2d4a9af2011-11-04 22:23:31 +0100174 /*
175 * set target reject and spin until busy is clear
176 * (preserve core-specific bits)
177 */
Arend van Spriela39be272013-12-12 11:58:58 +0100178 regdata = brcmf_sdiod_regrl(sdiodev,
179 CORE_SB(base, sbtmstatelow), NULL);
180 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
181 regdata | SSB_TMSLOW_REJECT, NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100182
Arend van Spriela39be272013-12-12 11:58:58 +0100183 regdata = brcmf_sdiod_regrl(sdiodev,
184 CORE_SB(base, sbtmstatelow), NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100185 udelay(1);
Arend van Spriela39be272013-12-12 11:58:58 +0100186 SPINWAIT((brcmf_sdiod_regrl(sdiodev,
187 CORE_SB(base, sbtmstatehigh),
188 NULL) &
189 SSB_TMSHIGH_BUSY), 100000);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100190
Arend van Spriela39be272013-12-12 11:58:58 +0100191 regdata = brcmf_sdiod_regrl(sdiodev,
192 CORE_SB(base, sbtmstatehigh),
193 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100194 if (regdata & SSB_TMSHIGH_BUSY)
Arend van Spriel5e8149f2012-12-07 10:49:57 +0100195 brcmf_err("core state still busy\n");
Franky Lin2d4a9af2011-11-04 22:23:31 +0100196
Arend van Spriela39be272013-12-12 11:58:58 +0100197 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow),
198 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100199 if (regdata & SSB_IDLOW_INITIATOR) {
Arend van Spriela39be272013-12-12 11:58:58 +0100200 regdata = brcmf_sdiod_regrl(sdiodev,
201 CORE_SB(base, sbimstate),
202 NULL);
Franky Lin79ae3952012-05-04 18:27:34 -0700203 regdata |= SSB_IMSTATE_REJECT;
Arend van Spriela39be272013-12-12 11:58:58 +0100204 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate),
205 regdata, NULL);
206 regdata = brcmf_sdiod_regrl(sdiodev,
207 CORE_SB(base, sbimstate),
208 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, sbimstate),
212 NULL) &
213 SSB_IMSTATE_BUSY), 100000);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100214 }
215
216 /* set reset and reject while enabling the clocks */
Franky Line13ce262012-05-04 18:27:35 -0700217 regdata = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
218 SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET;
Arend van Spriela39be272013-12-12 11:58:58 +0100219 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
220 regdata, NULL);
221 regdata = brcmf_sdiod_regrl(sdiodev,
222 CORE_SB(base, sbtmstatelow), NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100223 udelay(10);
224
225 /* clear the initiator reject bit */
Arend van Spriela39be272013-12-12 11:58:58 +0100226 regdata = brcmf_sdiod_regrl(sdiodev, CORE_SB(base, sbidlow),
227 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100228 if (regdata & SSB_IDLOW_INITIATOR) {
Arend van Spriela39be272013-12-12 11:58:58 +0100229 regdata = brcmf_sdiod_regrl(sdiodev,
230 CORE_SB(base, sbimstate),
231 NULL);
Franky Lin79ae3952012-05-04 18:27:34 -0700232 regdata &= ~SSB_IMSTATE_REJECT;
Arend van Spriela39be272013-12-12 11:58:58 +0100233 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbimstate),
234 regdata, NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100235 }
236 }
237
238 /* leave reset and reject asserted */
Arend van Spriela39be272013-12-12 11:58:58 +0100239 brcmf_sdiod_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
240 (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET), NULL);
Franky Lin2d4a9af2011-11-04 22:23:31 +0100241 udelay(1);
242}
243
Franky Lin086a2e02011-11-10 20:30:23 +0100244static void
245brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100246 struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits,
Hante Meuleman53036262014-01-13 22:20:23 +0100247 u32 in_resetbits)
Franky Lin086a2e02011-11-10 20:30:23 +0100248{
249 u8 idx;
250 u32 regdata;
Hante Meuleman53036262014-01-13 22:20:23 +0100251 u32 wrapbase;
Franky Lin086a2e02011-11-10 20:30:23 +0100252
253 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200254 if (idx == BRCMF_MAX_CORENUM)
255 return;
Franky Lin086a2e02011-11-10 20:30:23 +0100256
Hante Meuleman53036262014-01-13 22:20:23 +0100257 wrapbase = ci->c_inf[idx].wrapbase;
258
Franky Lin086a2e02011-11-10 20:30:23 +0100259 /* if core is already in reset, just return */
Hante Meuleman53036262014-01-13 22:20:23 +0100260 regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_RESET_CTL, NULL);
Franky Lin086a2e02011-11-10 20:30:23 +0100261 if ((regdata & BCMA_RESET_CTL_RESET) != 0)
262 return;
263
Hante Meuleman53036262014-01-13 22:20:23 +0100264 /* configure reset */
265 brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_IOCTL, pre_resetbits |
266 BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
267 regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL);
Franky Lin086a2e02011-11-10 20:30:23 +0100268
Hante Meuleman53036262014-01-13 22:20:23 +0100269 /* put in reset */
270 brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_RESET_CTL,
Arend van Spriela39be272013-12-12 11:58:58 +0100271 BCMA_RESET_CTL_RESET, NULL);
Franky Lin1640f282013-04-11 13:28:51 +0200272 usleep_range(10, 20);
273
Hante Meuleman53036262014-01-13 22:20:23 +0100274 /* wait till reset is 1 */
275 SPINWAIT(brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_RESET_CTL, NULL) !=
276 BCMA_RESET_CTL_RESET, 300);
277
278 /* post reset configure */
279 brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_IOCTL, pre_resetbits |
280 BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
281 regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL);
Franky Lin086a2e02011-11-10 20:30:23 +0100282}
283
Franky Lind77e70f2011-11-10 20:30:24 +0100284static void
285brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100286 struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits,
Hante Meuleman53036262014-01-13 22:20:23 +0100287 u32 in_resetbits, u32 post_resetbits)
Franky Lin2bc78e12011-11-04 22:23:38 +0100288{
289 u32 regdata;
Franky Lin086a2e02011-11-10 20:30:23 +0100290 u8 idx;
291
292 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200293 if (idx == BRCMF_MAX_CORENUM)
294 return;
Franky Lin2bc78e12011-11-04 22:23:38 +0100295
296 /*
297 * Must do the disable sequence first to work for
298 * arbitrary current core state.
299 */
Hante Meuleman53036262014-01-13 22:20:23 +0100300 brcmf_sdio_sb_coredisable(sdiodev, ci, coreid, pre_resetbits,
301 in_resetbits);
Franky Lin2bc78e12011-11-04 22:23:38 +0100302
303 /*
304 * Now do the initialization sequence.
305 * set reset while enabling the clock and
306 * forcing them on throughout the core
307 */
Arend van Spriela39be272013-12-12 11:58:58 +0100308 brcmf_sdiod_regwl(sdiodev,
309 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
310 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET,
311 NULL);
312 regdata = brcmf_sdiod_regrl(sdiodev,
313 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
314 NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100315 udelay(1);
316
Franky Lind77e70f2011-11-10 20:30:24 +0100317 /* clear any serror */
Arend van Spriela39be272013-12-12 11:58:58 +0100318 regdata = brcmf_sdiod_regrl(sdiodev,
319 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
320 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100321 if (regdata & SSB_TMSHIGH_SERR)
Arend van Spriela39be272013-12-12 11:58:58 +0100322 brcmf_sdiod_regwl(sdiodev,
323 CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
324 0, NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100325
Arend van Spriela39be272013-12-12 11:58:58 +0100326 regdata = brcmf_sdiod_regrl(sdiodev,
327 CORE_SB(ci->c_inf[idx].base, sbimstate),
328 NULL);
Franky Lin61213be2011-11-04 22:23:41 +0100329 if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
Arend van Spriela39be272013-12-12 11:58:58 +0100330 brcmf_sdiod_regwl(sdiodev,
331 CORE_SB(ci->c_inf[idx].base, sbimstate),
332 regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO),
333 NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100334
335 /* clear reset and allow it to propagate throughout the core */
Arend van Spriela39be272013-12-12 11:58:58 +0100336 brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
337 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK, NULL);
338 regdata = brcmf_sdiod_regrl(sdiodev,
339 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
340 NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100341 udelay(1);
342
343 /* leave clock enabled */
Arend van Spriela39be272013-12-12 11:58:58 +0100344 brcmf_sdiod_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
345 SSB_TMSLOW_CLOCK, NULL);
346 regdata = brcmf_sdiod_regrl(sdiodev,
347 CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
348 NULL);
Franky Lind77e70f2011-11-10 20:30:24 +0100349 udelay(1);
350}
351
352static void
353brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100354 struct brcmf_chip *ci, u16 coreid, u32 pre_resetbits,
Hante Meuleman53036262014-01-13 22:20:23 +0100355 u32 in_resetbits, u32 post_resetbits)
Franky Lind77e70f2011-11-10 20:30:24 +0100356{
357 u8 idx;
358 u32 regdata;
Hante Meuleman53036262014-01-13 22:20:23 +0100359 u32 wrapbase;
Franky Lind77e70f2011-11-10 20:30:24 +0100360
361 idx = brcmf_sdio_chip_getinfidx(ci, coreid);
Franky Lin74347852013-09-25 13:05:42 +0200362 if (idx == BRCMF_MAX_CORENUM)
363 return;
Franky Lind77e70f2011-11-10 20:30:24 +0100364
Hante Meuleman53036262014-01-13 22:20:23 +0100365 wrapbase = ci->c_inf[idx].wrapbase;
366
Franky Lind77e70f2011-11-10 20:30:24 +0100367 /* must disable first to work for arbitrary current core state */
Hante Meuleman53036262014-01-13 22:20:23 +0100368 brcmf_sdio_ai_coredisable(sdiodev, ci, coreid, pre_resetbits,
369 in_resetbits);
Franky Lind77e70f2011-11-10 20:30:24 +0100370
Hante Meuleman53036262014-01-13 22:20:23 +0100371 while (brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_RESET_CTL, NULL) &
372 BCMA_RESET_CTL_RESET) {
373 brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_RESET_CTL, 0, NULL);
374 usleep_range(40, 60);
375 }
Franky Lind77e70f2011-11-10 20:30:24 +0100376
Hante Meuleman53036262014-01-13 22:20:23 +0100377 brcmf_sdiod_regwl(sdiodev, wrapbase + BCMA_IOCTL, post_resetbits |
378 BCMA_IOCTL_CLK, NULL);
379 regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL);
Franky Lin2bc78e12011-11-04 22:23:38 +0100380}
381
Franky Lin1640f282013-04-11 13:28:51 +0200382#ifdef DEBUG
383/* safety check for chipinfo */
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100384static int brcmf_sdio_chip_cichk(struct brcmf_chip *ci)
Franky Lin1640f282013-04-11 13:28:51 +0200385{
386 u8 core_idx;
387
388 /* check RAM core presence for ARM CM3 core */
389 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
390 if (BRCMF_MAX_CORENUM != core_idx) {
391 core_idx = brcmf_sdio_chip_getinfidx(ci,
392 BCMA_CORE_INTERNAL_MEM);
393 if (BRCMF_MAX_CORENUM == core_idx) {
394 brcmf_err("RAM core not provided with ARM CM3 core\n");
395 return -ENODEV;
396 }
397 }
398
399 /* check RAM base for ARM CR4 core */
400 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CR4);
401 if (BRCMF_MAX_CORENUM != core_idx) {
402 if (ci->rambase == 0) {
403 brcmf_err("RAM base not provided with ARM CR4 core\n");
404 return -ENOMEM;
405 }
406 }
407
408 return 0;
409}
410#else /* DEBUG */
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100411static inline int brcmf_sdio_chip_cichk(struct brcmf_chip *ci)
Franky Lin1640f282013-04-11 13:28:51 +0200412{
413 return 0;
414}
415#endif
416
Franky Lina83369b2011-11-04 22:23:28 +0100417static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100418 struct brcmf_chip *ci)
Franky Lina83369b2011-11-04 22:23:28 +0100419{
420 u32 regdata;
Arend van Sprielc805eeb2014-01-13 22:20:26 +0100421 u32 socitype;
Franky Lina83369b2011-11-04 22:23:28 +0100422
Franky Lin069eddd2013-04-11 13:28:48 +0200423 /* Get CC core rev
Arend van Sprielc805eeb2014-01-13 22:20:26 +0100424 * Chipid is assume to be at offset 0 from SI_ENUM_BASE
Franky Lina83369b2011-11-04 22:23:28 +0100425 * For different chiptypes or old sdio hosts w/o chipcommon,
426 * other ways of recognition should be added here.
427 */
Arend van Spriela39be272013-12-12 11:58:58 +0100428 regdata = brcmf_sdiod_regrl(sdiodev,
Arend van Sprielc805eeb2014-01-13 22:20:26 +0100429 CORE_CC_REG(SI_ENUM_BASE, chipid),
Arend van Spriela39be272013-12-12 11:58:58 +0100430 NULL);
Franky Lina83369b2011-11-04 22:23:28 +0100431 ci->chip = regdata & CID_ID_MASK;
432 ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
Franky Linfe040152013-09-25 13:05:41 +0200433 if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 &&
434 ci->chiprev >= 2)
435 ci->chip = BCM4339_CHIP_ID;
Arend van Sprielc805eeb2014-01-13 22:20:26 +0100436 socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
Franky Lina83369b2011-11-04 22:23:28 +0100437
Arend van Sprielc805eeb2014-01-13 22:20:26 +0100438 brcmf_dbg(INFO, "found %s chip: id=0x%x, rev=%d\n",
439 socitype == SOCI_SB ? "SB" : "AXI", ci->chip, ci->chiprev);
Franky Lina83369b2011-11-04 22:23:28 +0100440
Arend van Sprielc805eeb2014-01-13 22:20:26 +0100441 if (socitype == SOCI_SB) {
442 if (ci->chip != BCM4329_CHIP_ID) {
443 brcmf_err("SB chip is not supported\n");
444 return -ENODEV;
445 }
446 ci->iscoreup = brcmf_sdio_sb_iscoreup;
447 ci->corerev = brcmf_sdio_sb_corerev;
448 ci->coredisable = brcmf_sdio_sb_coredisable;
449 ci->resetcore = brcmf_sdio_sb_resetcore;
450
451 ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
452 ci->c_inf[0].base = SI_ENUM_BASE;
Franky Lin99ba15c2011-11-04 22:23:42 +0100453 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
454 ci->c_inf[1].base = BCM4329_CORE_BUS_BASE;
455 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
456 ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE;
457 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
458 ci->c_inf[3].base = BCM4329_CORE_ARM_BASE;
Hante Meuleman53036262014-01-13 22:20:23 +0100459 ci->c_inf[4].id = BCMA_CORE_80211;
460 ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
Franky Lina83369b2011-11-04 22:23:28 +0100461 ci->ramsize = BCM4329_RAMSIZE;
Arend van Sprielc805eeb2014-01-13 22:20:26 +0100462 } else if (socitype == SOCI_AI) {
Franky Lin6ca687d2011-11-10 20:30:21 +0100463 ci->iscoreup = brcmf_sdio_ai_iscoreup;
Franky Lin523894f2011-11-10 20:30:22 +0100464 ci->corerev = brcmf_sdio_ai_corerev;
Franky Lin086a2e02011-11-10 20:30:23 +0100465 ci->coredisable = brcmf_sdio_ai_coredisable;
Franky Lind77e70f2011-11-10 20:30:24 +0100466 ci->resetcore = brcmf_sdio_ai_resetcore;
Arend van Sprielc805eeb2014-01-13 22:20:26 +0100467
468 ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
469 ci->c_inf[0].base = SI_ENUM_BASE;
470
471 /* Address of cores for new chips should be added here */
472 switch (ci->chip) {
473 case BCM43143_CHIP_ID:
474 ci->c_inf[0].wrapbase = ci->c_inf[0].base + 0x00100000;
475 ci->c_inf[0].cib = 0x2b000000;
476 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
477 ci->c_inf[1].base = BCM43143_CORE_BUS_BASE;
478 ci->c_inf[1].wrapbase = ci->c_inf[1].base + 0x00100000;
479 ci->c_inf[1].cib = 0x18000000;
480 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
481 ci->c_inf[2].base = BCM43143_CORE_SOCRAM_BASE;
482 ci->c_inf[2].wrapbase = ci->c_inf[2].base + 0x00100000;
483 ci->c_inf[2].cib = 0x14000000;
484 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
485 ci->c_inf[3].base = BCM43143_CORE_ARM_BASE;
486 ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000;
487 ci->c_inf[3].cib = 0x07000000;
488 ci->c_inf[4].id = BCMA_CORE_80211;
489 ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
490 ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
491 ci->ramsize = BCM43143_RAMSIZE;
492 break;
493 case BCM43241_CHIP_ID:
494 ci->c_inf[0].wrapbase = 0x18100000;
495 ci->c_inf[0].cib = 0x2a084411;
496 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
497 ci->c_inf[1].base = 0x18002000;
498 ci->c_inf[1].wrapbase = 0x18102000;
499 ci->c_inf[1].cib = 0x0e004211;
500 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
501 ci->c_inf[2].base = 0x18004000;
502 ci->c_inf[2].wrapbase = 0x18104000;
503 ci->c_inf[2].cib = 0x14080401;
504 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
505 ci->c_inf[3].base = 0x18003000;
506 ci->c_inf[3].wrapbase = 0x18103000;
507 ci->c_inf[3].cib = 0x07004211;
508 ci->c_inf[4].id = BCMA_CORE_80211;
509 ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
510 ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
511 ci->ramsize = 0x90000;
512 break;
513 case BCM4330_CHIP_ID:
514 ci->c_inf[0].wrapbase = 0x18100000;
515 ci->c_inf[0].cib = 0x27004211;
516 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
517 ci->c_inf[1].base = 0x18002000;
518 ci->c_inf[1].wrapbase = 0x18102000;
519 ci->c_inf[1].cib = 0x07004211;
520 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
521 ci->c_inf[2].base = 0x18004000;
522 ci->c_inf[2].wrapbase = 0x18104000;
523 ci->c_inf[2].cib = 0x0d080401;
524 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
525 ci->c_inf[3].base = 0x18003000;
526 ci->c_inf[3].wrapbase = 0x18103000;
527 ci->c_inf[3].cib = 0x03004211;
528 ci->c_inf[4].id = BCMA_CORE_80211;
529 ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
530 ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
531 ci->ramsize = 0x48000;
532 break;
533 case BCM4334_CHIP_ID:
534 ci->c_inf[0].wrapbase = 0x18100000;
535 ci->c_inf[0].cib = 0x29004211;
536 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
537 ci->c_inf[1].base = 0x18002000;
538 ci->c_inf[1].wrapbase = 0x18102000;
539 ci->c_inf[1].cib = 0x0d004211;
540 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
541 ci->c_inf[2].base = 0x18004000;
542 ci->c_inf[2].wrapbase = 0x18104000;
543 ci->c_inf[2].cib = 0x13080401;
544 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
545 ci->c_inf[3].base = 0x18003000;
546 ci->c_inf[3].wrapbase = 0x18103000;
547 ci->c_inf[3].cib = 0x07004211;
548 ci->c_inf[4].id = BCMA_CORE_80211;
549 ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
550 ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
551 ci->ramsize = 0x80000;
552 break;
553 case BCM4335_CHIP_ID:
554 ci->c_inf[0].wrapbase = 0x18100000;
555 ci->c_inf[0].cib = 0x2b084411;
556 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
557 ci->c_inf[1].base = 0x18005000;
558 ci->c_inf[1].wrapbase = 0x18105000;
559 ci->c_inf[1].cib = 0x0f004211;
560 ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
561 ci->c_inf[2].base = 0x18002000;
562 ci->c_inf[2].wrapbase = 0x18102000;
563 ci->c_inf[2].cib = 0x01084411;
564 ci->c_inf[3].id = BCMA_CORE_80211;
565 ci->c_inf[3].base = BCM43xx_CORE_D11_BASE;
566 ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000;
567 ci->ramsize = 0xc0000;
568 ci->rambase = 0x180000;
569 break;
570 case BCM43362_CHIP_ID:
571 ci->c_inf[0].wrapbase = 0x18100000;
572 ci->c_inf[0].cib = 0x27004211;
573 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
574 ci->c_inf[1].base = 0x18002000;
575 ci->c_inf[1].wrapbase = 0x18102000;
576 ci->c_inf[1].cib = 0x0a004211;
577 ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
578 ci->c_inf[2].base = 0x18004000;
579 ci->c_inf[2].wrapbase = 0x18104000;
580 ci->c_inf[2].cib = 0x08080401;
581 ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
582 ci->c_inf[3].base = 0x18003000;
583 ci->c_inf[3].wrapbase = 0x18103000;
584 ci->c_inf[3].cib = 0x03004211;
585 ci->c_inf[4].id = BCMA_CORE_80211;
586 ci->c_inf[4].base = BCM43xx_CORE_D11_BASE;
587 ci->c_inf[4].wrapbase = ci->c_inf[4].base + 0x00100000;
588 ci->ramsize = 0x3C000;
589 break;
590 case BCM4339_CHIP_ID:
591 ci->c_inf[0].wrapbase = 0x18100000;
592 ci->c_inf[0].cib = 0x2e084411;
593 ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
594 ci->c_inf[1].base = 0x18005000;
595 ci->c_inf[1].wrapbase = 0x18105000;
596 ci->c_inf[1].cib = 0x15004211;
597 ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
598 ci->c_inf[2].base = 0x18002000;
599 ci->c_inf[2].wrapbase = 0x18102000;
600 ci->c_inf[2].cib = 0x04084411;
601 ci->c_inf[3].id = BCMA_CORE_80211;
602 ci->c_inf[3].base = BCM43xx_CORE_D11_BASE;
603 ci->c_inf[3].wrapbase = ci->c_inf[3].base + 0x00100000;
604 ci->ramsize = 0xc0000;
605 ci->rambase = 0x180000;
606 break;
607 default:
608 brcmf_err("AXI chip is not supported\n");
609 return -ENODEV;
610 }
611 } else {
612 brcmf_err("chip backplane type %u is not supported\n",
613 socitype);
Franky Lin6ca687d2011-11-10 20:30:21 +0100614 return -ENODEV;
615 }
616
Arend van Sprielc805eeb2014-01-13 22:20:26 +0100617 return brcmf_sdio_chip_cichk(ci);
Franky Lina83369b2011-11-04 22:23:28 +0100618}
619
Franky Lin5b45e542011-11-04 22:23:30 +0100620static void
621brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100622 struct brcmf_chip *ci)
Franky Lin5b45e542011-11-04 22:23:30 +0100623{
Franky Lin79ae3952012-05-04 18:27:34 -0700624 u32 base = ci->c_inf[0].base;
625
Franky Lin5b45e542011-11-04 22:23:30 +0100626 /* get chipcommon rev */
Franky Lin523894f2011-11-10 20:30:22 +0100627 ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100628
629 /* get chipcommon capabilites */
Arend van Spriela39be272013-12-12 11:58:58 +0100630 ci->c_inf[0].caps = brcmf_sdiod_regrl(sdiodev,
631 CORE_CC_REG(base, capabilities),
632 NULL);
Franky Lin5b45e542011-11-04 22:23:30 +0100633
634 /* get pmu caps & rev */
Franky Lin99ba15c2011-11-04 22:23:42 +0100635 if (ci->c_inf[0].caps & CC_CAP_PMU) {
Franky Lin79ae3952012-05-04 18:27:34 -0700636 ci->pmucaps =
Arend van Spriela39be272013-12-12 11:58:58 +0100637 brcmf_sdiod_regrl(sdiodev,
638 CORE_CC_REG(base, pmucapabilities),
639 NULL);
Franky Lin5b45e542011-11-04 22:23:30 +0100640 ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
641 }
642
Franky Lin523894f2011-11-10 20:30:22 +0100643 ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id);
Franky Lin5b45e542011-11-04 22:23:30 +0100644
645 brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
Franky Lin99ba15c2011-11-04 22:23:42 +0100646 ci->c_inf[0].rev, ci->pmurev,
647 ci->c_inf[1].rev, ci->c_inf[1].id);
Franky Lin966414d2011-11-04 22:23:32 +0100648
649 /*
650 * Make sure any on-chip ARM is off (in case strapping is wrong),
651 * or downloaded code was already running.
652 */
Hante Meuleman53036262014-01-13 22:20:23 +0100653 ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0, 0);
Franky Lin5b45e542011-11-04 22:23:30 +0100654}
655
Franky Lina83369b2011-11-04 22:23:28 +0100656int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100657 struct brcmf_chip **ci_ptr)
Franky Lina83369b2011-11-04 22:23:28 +0100658{
Franky Lina97e4fc2011-11-04 22:23:35 +0100659 int ret;
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100660 struct brcmf_chip *ci;
Franky Lina97e4fc2011-11-04 22:23:35 +0100661
662 brcmf_dbg(TRACE, "Enter\n");
663
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100664 ci = kzalloc(sizeof(*ci), GFP_ATOMIC);
Franky Lina97e4fc2011-11-04 22:23:35 +0100665 if (!ci)
666 return -ENOMEM;
Franky Lina83369b2011-11-04 22:23:28 +0100667
Arend van Spriel65d80d02014-01-29 15:32:14 +0100668 ret = brcmf_sdio_buscoreprep(sdiodev);
Franky Line63ac6b2011-11-04 22:23:29 +0100669 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100670 goto err;
Franky Line63ac6b2011-11-04 22:23:29 +0100671
Arend van Spriel4744d162013-12-12 11:58:55 +0100672 ret = brcmf_sdio_chip_recognition(sdiodev, ci);
Franky Lina83369b2011-11-04 22:23:28 +0100673 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100674 goto err;
Franky Lina83369b2011-11-04 22:23:28 +0100675
Franky Lin5b45e542011-11-04 22:23:30 +0100676 brcmf_sdio_chip_buscoresetup(sdiodev, ci);
677
Arend van Spriela39be272013-12-12 11:58:58 +0100678 brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopullup),
679 0, NULL);
680 brcmf_sdiod_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopulldown),
681 0, NULL);
Franky Lin960908d2011-11-04 22:23:33 +0100682
Franky Lina97e4fc2011-11-04 22:23:35 +0100683 *ci_ptr = ci;
684 return 0;
685
686err:
687 kfree(ci);
Franky Lina83369b2011-11-04 22:23:28 +0100688 return ret;
689}
Franky Lina8a6c042011-11-04 22:23:39 +0100690
691void
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100692brcmf_sdio_chip_detach(struct brcmf_chip **ci_ptr)
Franky Lina8a6c042011-11-04 22:23:39 +0100693{
694 brcmf_dbg(TRACE, "Enter\n");
695
696 kfree(*ci_ptr);
697 *ci_ptr = NULL;
698}
Franky Line12afb62011-11-04 22:23:40 +0100699
Franky Lin069eddd2013-04-11 13:28:48 +0200700static void
701brcmf_sdio_chip_cm3_enterdl(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100702 struct brcmf_chip *ci)
Franky Lin069eddd2013-04-11 13:28:48 +0200703{
Hante Meuleman53036262014-01-13 22:20:23 +0100704 ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3, 0, 0);
705 ci->resetcore(sdiodev, ci, BCMA_CORE_80211,
706 D11_BCMA_IOCTL_PHYRESET | D11_BCMA_IOCTL_PHYCLOCKEN,
707 D11_BCMA_IOCTL_PHYCLOCKEN, D11_BCMA_IOCTL_PHYCLOCKEN);
708 ci->resetcore(sdiodev, ci, BCMA_CORE_INTERNAL_MEM, 0, 0, 0);
Franky Lin069eddd2013-04-11 13:28:48 +0200709}
710
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100711static bool brcmf_sdio_chip_cm3_exitdl(struct brcmf_sdio_dev *sdiodev,
712 struct brcmf_chip *ci)
Franky Lin069eddd2013-04-11 13:28:48 +0200713{
714 u8 core_idx;
715 u32 reg_addr;
716
717 if (!ci->iscoreup(sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) {
718 brcmf_err("SOCRAM core is down after reset?\n");
719 return false;
720 }
721
Franky Lin069eddd2013-04-11 13:28:48 +0200722 /* clear all interrupts */
723 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
724 reg_addr = ci->c_inf[core_idx].base;
725 reg_addr += offsetof(struct sdpcmd_regs, intstatus);
Arend van Spriela39be272013-12-12 11:58:58 +0100726 brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
Franky Lin069eddd2013-04-11 13:28:48 +0200727
Hante Meuleman53036262014-01-13 22:20:23 +0100728 ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CM3, 0, 0, 0);
Franky Lin1640f282013-04-11 13:28:51 +0200729
730 return true;
731}
732
733static inline void
734brcmf_sdio_chip_cr4_enterdl(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100735 struct brcmf_chip *ci)
Franky Lin1640f282013-04-11 13:28:51 +0200736{
Hante Meuleman53036262014-01-13 22:20:23 +0100737 u8 idx;
738 u32 regdata;
739 u32 wrapbase;
740 idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CR4);
741
742 if (idx == BRCMF_MAX_CORENUM)
743 return;
744
745 wrapbase = ci->c_inf[idx].wrapbase;
746 regdata = brcmf_sdiod_regrl(sdiodev, wrapbase + BCMA_IOCTL, NULL);
747 regdata &= ARMCR4_BCMA_IOCTL_CPUHALT;
748 ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, regdata,
749 ARMCR4_BCMA_IOCTL_CPUHALT, ARMCR4_BCMA_IOCTL_CPUHALT);
750 ci->resetcore(sdiodev, ci, BCMA_CORE_80211,
751 D11_BCMA_IOCTL_PHYRESET | D11_BCMA_IOCTL_PHYCLOCKEN,
752 D11_BCMA_IOCTL_PHYCLOCKEN, D11_BCMA_IOCTL_PHYCLOCKEN);
Franky Lin1640f282013-04-11 13:28:51 +0200753}
754
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100755static bool brcmf_sdio_chip_cr4_exitdl(struct brcmf_sdio_dev *sdiodev,
756 struct brcmf_chip *ci, u32 rstvec)
Franky Lin1640f282013-04-11 13:28:51 +0200757{
758 u8 core_idx;
759 u32 reg_addr;
760
Franky Lin1640f282013-04-11 13:28:51 +0200761 /* clear all interrupts */
762 core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_SDIO_DEV);
763 reg_addr = ci->c_inf[core_idx].base;
764 reg_addr += offsetof(struct sdpcmd_regs, intstatus);
Arend van Spriela39be272013-12-12 11:58:58 +0100765 brcmf_sdiod_regwl(sdiodev, reg_addr, 0xFFFFFFFF, NULL);
Franky Lin1640f282013-04-11 13:28:51 +0200766
767 /* Write reset vector to address 0 */
Arend van Spriel33556502014-01-13 22:20:25 +0100768 brcmf_sdiod_ramrw(sdiodev, true, 0, (void *)&rstvec,
769 sizeof(rstvec));
Franky Lin1640f282013-04-11 13:28:51 +0200770
771 /* restore ARM */
Hante Meuleman53036262014-01-13 22:20:23 +0100772 ci->resetcore(sdiodev, ci, BCMA_CORE_ARM_CR4, ARMCR4_BCMA_IOCTL_CPUHALT,
773 0, 0);
Franky Lin069eddd2013-04-11 13:28:48 +0200774
775 return true;
776}
777
778void brcmf_sdio_chip_enter_download(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100779 struct brcmf_chip *ci)
Franky Lin069eddd2013-04-11 13:28:48 +0200780{
Franky Lin1640f282013-04-11 13:28:51 +0200781 u8 arm_core_idx;
782
783 arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
784 if (BRCMF_MAX_CORENUM != arm_core_idx) {
785 brcmf_sdio_chip_cm3_enterdl(sdiodev, ci);
786 return;
787 }
788
789 brcmf_sdio_chip_cr4_enterdl(sdiodev, ci);
Franky Lin069eddd2013-04-11 13:28:48 +0200790}
791
792bool brcmf_sdio_chip_exit_download(struct brcmf_sdio_dev *sdiodev,
Arend van Spriel9cf218f2014-01-13 22:20:27 +0100793 struct brcmf_chip *ci, u32 rstvec)
Franky Lin069eddd2013-04-11 13:28:48 +0200794{
Franky Lin1640f282013-04-11 13:28:51 +0200795 u8 arm_core_idx;
796
797 arm_core_idx = brcmf_sdio_chip_getinfidx(ci, BCMA_CORE_ARM_CM3);
798 if (BRCMF_MAX_CORENUM != arm_core_idx)
Hante Meulemana74d0362014-01-13 22:20:22 +0100799 return brcmf_sdio_chip_cm3_exitdl(sdiodev, ci);
Franky Lin1640f282013-04-11 13:28:51 +0200800
Arend van Spriel33556502014-01-13 22:20:25 +0100801 return brcmf_sdio_chip_cr4_exitdl(sdiodev, ci, rstvec);
Franky Lin069eddd2013-04-11 13:28:48 +0200802}