2 * Copyright (c) 2011 Broadcom Corporation
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.
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.
16 /* ***** SDIO interface chip backplane handle functions ***** */
18 #include <linux/types.h>
19 #include <linux/netdevice.h>
20 #include <linux/mmc/card.h>
21 #include <chipcommon.h>
22 #include <brcm_hw_ids.h>
23 #include <brcmu_wifi.h>
24 #include <brcmu_utils.h>
28 #include "sdio_host.h"
29 #include "sdio_chip.h"
31 /* chip core base & ramsize */
33 /* SDIO device core, ID 0x829 */
34 #define BCM4329_CORE_BUS_BASE 0x18011000
35 /* internal memory core, ID 0x80e */
36 #define BCM4329_CORE_SOCRAM_BASE 0x18003000
37 /* ARM Cortex M3 core, ID 0x82a */
38 #define BCM4329_CORE_ARM_BASE 0x18002000
39 #define BCM4329_RAMSIZE 0x48000
44 #define SBIDH_RC_MASK 0x000f /* revision code */
45 #define SBIDH_RCE_MASK 0x7000 /* revision code extension field */
46 #define SBIDH_RCE_SHIFT 8
47 #define SBCOREREV(sbidh) \
48 ((((sbidh) & SBIDH_RCE_MASK) >> SBIDH_RCE_SHIFT) | \
49 ((sbidh) & SBIDH_RC_MASK))
50 #define SBIDH_CC_MASK 0x8ff0 /* core code */
51 #define SBIDH_CC_SHIFT 4
52 #define SBIDH_VC_MASK 0xffff0000 /* vendor code */
53 #define SBIDH_VC_SHIFT 16
56 brcmf_sdio_chip_iscoreup(struct brcmf_sdio_dev
*sdiodev
,
61 regdata
= brcmf_sdcard_reg_read(sdiodev
,
62 CORE_SB(corebase
, sbtmstatelow
), 4);
63 regdata
&= (SBTML_RESET
| SBTML_REJ_MASK
|
64 (SICF_CLOCK_EN
<< SBTML_SICF_SHIFT
));
65 return ((SICF_CLOCK_EN
<< SBTML_SICF_SHIFT
) == regdata
);
69 brcmf_sdio_chip_coredisable(struct brcmf_sdio_dev
*sdiodev
, u32 corebase
)
73 regdata
= brcmf_sdcard_reg_read(sdiodev
,
74 CORE_SB(corebase
, sbtmstatelow
), 4);
75 if (regdata
& SBTML_RESET
)
78 regdata
= brcmf_sdcard_reg_read(sdiodev
,
79 CORE_SB(corebase
, sbtmstatelow
), 4);
80 if ((regdata
& (SICF_CLOCK_EN
<< SBTML_SICF_SHIFT
)) != 0) {
82 * set target reject and spin until busy is clear
83 * (preserve core-specific bits)
85 regdata
= brcmf_sdcard_reg_read(sdiodev
,
86 CORE_SB(corebase
, sbtmstatelow
), 4);
87 brcmf_sdcard_reg_write(sdiodev
, CORE_SB(corebase
, sbtmstatelow
),
88 4, regdata
| SBTML_REJ
);
90 regdata
= brcmf_sdcard_reg_read(sdiodev
,
91 CORE_SB(corebase
, sbtmstatelow
), 4);
93 SPINWAIT((brcmf_sdcard_reg_read(sdiodev
,
94 CORE_SB(corebase
, sbtmstatehigh
), 4) &
97 regdata
= brcmf_sdcard_reg_read(sdiodev
,
98 CORE_SB(corebase
, sbtmstatehigh
), 4);
99 if (regdata
& SBTMH_BUSY
)
100 brcmf_dbg(ERROR
, "core state still busy\n");
102 regdata
= brcmf_sdcard_reg_read(sdiodev
,
103 CORE_SB(corebase
, sbidlow
), 4);
104 if (regdata
& SBIDL_INIT
) {
105 regdata
= brcmf_sdcard_reg_read(sdiodev
,
106 CORE_SB(corebase
, sbimstate
), 4) |
108 brcmf_sdcard_reg_write(sdiodev
,
109 CORE_SB(corebase
, sbimstate
), 4,
111 regdata
= brcmf_sdcard_reg_read(sdiodev
,
112 CORE_SB(corebase
, sbimstate
), 4);
114 SPINWAIT((brcmf_sdcard_reg_read(sdiodev
,
115 CORE_SB(corebase
, sbimstate
), 4) &
119 /* set reset and reject while enabling the clocks */
120 brcmf_sdcard_reg_write(sdiodev
,
121 CORE_SB(corebase
, sbtmstatelow
), 4,
122 (((SICF_FGC
| SICF_CLOCK_EN
) << SBTML_SICF_SHIFT
) |
123 SBTML_REJ
| SBTML_RESET
));
124 regdata
= brcmf_sdcard_reg_read(sdiodev
,
125 CORE_SB(corebase
, sbtmstatelow
), 4);
128 /* clear the initiator reject bit */
129 regdata
= brcmf_sdcard_reg_read(sdiodev
,
130 CORE_SB(corebase
, sbidlow
), 4);
131 if (regdata
& SBIDL_INIT
) {
132 regdata
= brcmf_sdcard_reg_read(sdiodev
,
133 CORE_SB(corebase
, sbimstate
), 4) &
135 brcmf_sdcard_reg_write(sdiodev
,
136 CORE_SB(corebase
, sbimstate
), 4,
141 /* leave reset and reject asserted */
142 brcmf_sdcard_reg_write(sdiodev
, CORE_SB(corebase
, sbtmstatelow
), 4,
143 (SBTML_REJ
| SBTML_RESET
));
147 static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev
*sdiodev
,
148 struct chip_info
*ci
, u32 regs
)
154 * Chipid is assume to be at offset 0 from regs arg
155 * For different chiptypes or old sdio hosts w/o chipcommon,
156 * other ways of recognition should be added here.
158 ci
->cccorebase
= regs
;
159 regdata
= brcmf_sdcard_reg_read(sdiodev
,
160 CORE_CC_REG(ci
->cccorebase
, chipid
), 4);
161 ci
->chip
= regdata
& CID_ID_MASK
;
162 ci
->chiprev
= (regdata
& CID_REV_MASK
) >> CID_REV_SHIFT
;
164 brcmf_dbg(INFO
, "chipid=0x%x chiprev=%d\n", ci
->chip
, ci
->chiprev
);
166 /* Address of cores for new chips should be added here */
168 case BCM4329_CHIP_ID
:
169 ci
->buscorebase
= BCM4329_CORE_BUS_BASE
;
170 ci
->ramcorebase
= BCM4329_CORE_SOCRAM_BASE
;
171 ci
->armcorebase
= BCM4329_CORE_ARM_BASE
;
172 ci
->ramsize
= BCM4329_RAMSIZE
;
175 brcmf_dbg(ERROR
, "chipid 0x%x is not supported\n", ci
->chip
);
183 brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev
*sdiodev
)
188 /* Try forcing SDIO core to do ALPAvail request only */
189 clkset
= SBSDIO_FORCE_HW_CLKREQ_OFF
| SBSDIO_ALP_AVAIL_REQ
;
190 brcmf_sdcard_cfg_write(sdiodev
, SDIO_FUNC_1
,
191 SBSDIO_FUNC1_CHIPCLKCSR
, clkset
, &err
);
193 brcmf_dbg(ERROR
, "error writing for HT off\n");
197 /* If register supported, wait for ALPAvail and then force ALP */
198 /* This may take up to 15 milliseconds */
199 clkval
= brcmf_sdcard_cfg_read(sdiodev
, SDIO_FUNC_1
,
200 SBSDIO_FUNC1_CHIPCLKCSR
, NULL
);
202 if ((clkval
& ~SBSDIO_AVBITS
) != clkset
) {
203 brcmf_dbg(ERROR
, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
208 SPINWAIT(((clkval
= brcmf_sdcard_cfg_read(sdiodev
, SDIO_FUNC_1
,
209 SBSDIO_FUNC1_CHIPCLKCSR
, NULL
)),
210 !SBSDIO_ALPAV(clkval
)),
211 PMU_MAX_TRANSITION_DLY
);
212 if (!SBSDIO_ALPAV(clkval
)) {
213 brcmf_dbg(ERROR
, "timeout on ALPAV wait, clkval 0x%02x\n",
218 clkset
= SBSDIO_FORCE_HW_CLKREQ_OFF
| SBSDIO_FORCE_ALP
;
219 brcmf_sdcard_cfg_write(sdiodev
, SDIO_FUNC_1
,
220 SBSDIO_FUNC1_CHIPCLKCSR
, clkset
, &err
);
223 /* Also, disable the extra SDIO pull-ups */
224 brcmf_sdcard_cfg_write(sdiodev
, SDIO_FUNC_1
,
225 SBSDIO_FUNC1_SDIOPULLUP
, 0, NULL
);
231 brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev
*sdiodev
,
232 struct chip_info
*ci
)
236 /* get chipcommon rev */
237 regdata
= brcmf_sdcard_reg_read(sdiodev
,
238 CORE_SB(ci
->cccorebase
, sbidhigh
), 4);
239 ci
->ccrev
= SBCOREREV(regdata
);
241 /* get chipcommon capabilites */
242 ci
->cccaps
= brcmf_sdcard_reg_read(sdiodev
,
243 CORE_CC_REG(ci
->cccorebase
, capabilities
), 4);
245 /* get pmu caps & rev */
246 if (ci
->cccaps
& CC_CAP_PMU
) {
247 ci
->pmucaps
= brcmf_sdcard_reg_read(sdiodev
,
248 CORE_CC_REG(ci
->cccorebase
, pmucapabilities
), 4);
249 ci
->pmurev
= ci
->pmucaps
& PCAP_REV_MASK
;
252 regdata
= brcmf_sdcard_reg_read(sdiodev
,
253 CORE_SB(ci
->buscorebase
, sbidhigh
), 4);
254 ci
->buscorerev
= SBCOREREV(regdata
);
255 ci
->buscoretype
= (regdata
& SBIDH_CC_MASK
) >> SBIDH_CC_SHIFT
;
257 brcmf_dbg(INFO
, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
258 ci
->ccrev
, ci
->pmurev
, ci
->buscorerev
, ci
->buscoretype
);
261 * Make sure any on-chip ARM is off (in case strapping is wrong),
262 * or downloaded code was already running.
264 brcmf_sdio_chip_coredisable(sdiodev
, ci
->armcorebase
);
267 int brcmf_sdio_chip_attach(struct brcmf_sdio_dev
*sdiodev
,
268 struct chip_info
**ci_ptr
, u32 regs
)
271 struct chip_info
*ci
;
273 brcmf_dbg(TRACE
, "Enter\n");
275 /* alloc chip_info_t */
276 ci
= kzalloc(sizeof(struct chip_info
), GFP_ATOMIC
);
280 ret
= brcmf_sdio_chip_buscoreprep(sdiodev
);
284 ret
= brcmf_sdio_chip_recognition(sdiodev
, ci
, regs
);
288 brcmf_sdio_chip_buscoresetup(sdiodev
, ci
);
290 brcmf_sdcard_reg_write(sdiodev
,
291 CORE_CC_REG(ci
->cccorebase
, gpiopullup
), 4, 0);
292 brcmf_sdcard_reg_write(sdiodev
,
293 CORE_CC_REG(ci
->cccorebase
, gpiopulldown
), 4, 0);