blob: e0c22c4b8df97c0e618f1c0b1870fd50880a402c [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>
21#include <chipcommon.h>
22#include <brcm_hw_ids.h>
23#include <brcmu_wifi.h>
24#include <brcmu_utils.h>
Franky Lin2d4a9af2011-11-04 22:23:31 +010025#include <soc.h>
Franky Lina83369b2011-11-04 22:23:28 +010026#include "dhd.h"
27#include "dhd_dbg.h"
28#include "sdio_host.h"
29#include "sdio_chip.h"
30
31/* chip core base & ramsize */
32/* bcm4329 */
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
40
41
42/* SB regs */
43/* sbidhigh */
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
54
Franky Lind8f64a42011-11-04 22:23:36 +010055bool
56brcmf_sdio_chip_iscoreup(struct brcmf_sdio_dev *sdiodev,
57 u32 corebase)
58{
59 u32 regdata;
60
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);
66}
67
Franky Lin2d4a9af2011-11-04 22:23:31 +010068void
69brcmf_sdio_chip_coredisable(struct brcmf_sdio_dev *sdiodev, u32 corebase)
70{
71 u32 regdata;
72
73 regdata = brcmf_sdcard_reg_read(sdiodev,
74 CORE_SB(corebase, sbtmstatelow), 4);
75 if (regdata & SBTML_RESET)
76 return;
77
78 regdata = brcmf_sdcard_reg_read(sdiodev,
79 CORE_SB(corebase, sbtmstatelow), 4);
80 if ((regdata & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) != 0) {
81 /*
82 * set target reject and spin until busy is clear
83 * (preserve core-specific bits)
84 */
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);
89
90 regdata = brcmf_sdcard_reg_read(sdiodev,
91 CORE_SB(corebase, sbtmstatelow), 4);
92 udelay(1);
93 SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
94 CORE_SB(corebase, sbtmstatehigh), 4) &
95 SBTMH_BUSY), 100000);
96
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");
101
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) |
107 SBIM_RJ;
108 brcmf_sdcard_reg_write(sdiodev,
109 CORE_SB(corebase, sbimstate), 4,
110 regdata);
111 regdata = brcmf_sdcard_reg_read(sdiodev,
112 CORE_SB(corebase, sbimstate), 4);
113 udelay(1);
114 SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
115 CORE_SB(corebase, sbimstate), 4) &
116 SBIM_BY), 100000);
117 }
118
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);
126 udelay(10);
127
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) &
134 ~SBIM_RJ;
135 brcmf_sdcard_reg_write(sdiodev,
136 CORE_SB(corebase, sbimstate), 4,
137 regdata);
138 }
139 }
140
141 /* leave reset and reject asserted */
142 brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
143 (SBTML_REJ | SBTML_RESET));
144 udelay(1);
145}
146
Franky Lina83369b2011-11-04 22:23:28 +0100147static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
148 struct chip_info *ci, u32 regs)
149{
150 u32 regdata;
151
152 /*
153 * Get CC core rev
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.
157 */
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;
163
164 brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
165
166 /* Address of cores for new chips should be added here */
167 switch (ci->chip) {
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;
173 break;
174 default:
175 brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip);
176 return -ENODEV;
177 }
178
Franky Lina83369b2011-11-04 22:23:28 +0100179 return 0;
180}
181
Franky Line63ac6b2011-11-04 22:23:29 +0100182static int
183brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
184{
185 int err = 0;
186 u8 clkval, clkset;
187
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);
192 if (err) {
193 brcmf_dbg(ERROR, "error writing for HT off\n");
194 return err;
195 }
196
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);
201
202 if ((clkval & ~SBSDIO_AVBITS) != clkset) {
203 brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
204 clkset, clkval);
205 return -EACCES;
206 }
207
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",
214 clkval);
215 return -EBUSY;
216 }
217
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);
221 udelay(65);
222
223 /* Also, disable the extra SDIO pull-ups */
224 brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
225 SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
226
227 return 0;
228}
229
Franky Lin5b45e542011-11-04 22:23:30 +0100230static void
231brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
232 struct chip_info *ci)
233{
234 u32 regdata;
235
236 /* get chipcommon rev */
237 regdata = brcmf_sdcard_reg_read(sdiodev,
238 CORE_SB(ci->cccorebase, sbidhigh), 4);
239 ci->ccrev = SBCOREREV(regdata);
240
241 /* get chipcommon capabilites */
242 ci->cccaps = brcmf_sdcard_reg_read(sdiodev,
243 CORE_CC_REG(ci->cccorebase, capabilities), 4);
244
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;
250 }
251
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;
256
257 brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
258 ci->ccrev, ci->pmurev, ci->buscorerev, ci->buscoretype);
Franky Lin966414d2011-11-04 22:23:32 +0100259
260 /*
261 * Make sure any on-chip ARM is off (in case strapping is wrong),
262 * or downloaded code was already running.
263 */
264 brcmf_sdio_chip_coredisable(sdiodev, ci->armcorebase);
Franky Lin5b45e542011-11-04 22:23:30 +0100265}
266
Franky Lina83369b2011-11-04 22:23:28 +0100267int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
Franky Lina97e4fc2011-11-04 22:23:35 +0100268 struct chip_info **ci_ptr, u32 regs)
Franky Lina83369b2011-11-04 22:23:28 +0100269{
Franky Lina97e4fc2011-11-04 22:23:35 +0100270 int ret;
271 struct chip_info *ci;
272
273 brcmf_dbg(TRACE, "Enter\n");
274
275 /* alloc chip_info_t */
276 ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
277 if (!ci)
278 return -ENOMEM;
Franky Lina83369b2011-11-04 22:23:28 +0100279
Franky Line63ac6b2011-11-04 22:23:29 +0100280 ret = brcmf_sdio_chip_buscoreprep(sdiodev);
281 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100282 goto err;
Franky Line63ac6b2011-11-04 22:23:29 +0100283
Franky Lina83369b2011-11-04 22:23:28 +0100284 ret = brcmf_sdio_chip_recognition(sdiodev, ci, regs);
285 if (ret != 0)
Franky Lina97e4fc2011-11-04 22:23:35 +0100286 goto err;
Franky Lina83369b2011-11-04 22:23:28 +0100287
Franky Lin5b45e542011-11-04 22:23:30 +0100288 brcmf_sdio_chip_buscoresetup(sdiodev, ci);
289
Franky Lin960908d2011-11-04 22:23:33 +0100290 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);
294
Franky Lina97e4fc2011-11-04 22:23:35 +0100295 *ci_ptr = ci;
296 return 0;
297
298err:
299 kfree(ci);
Franky Lina83369b2011-11-04 22:23:28 +0100300 return ret;
301}