Commit | Line | Data |
---|---|---|
a9533e7e HP |
1 | /* |
2 | * Copyright (c) 2010 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 | ||
3327989a BR |
17 | #include <linux/kernel.h> |
18 | #include <linux/string.h> | |
a1c16ed2 | 19 | #include <bcmdefs.h> |
c6ac24e9 BR |
20 | #ifdef BRCM_FULLMAC |
21 | #include <linux/netdevice.h> | |
22 | #endif | |
a1c16ed2 | 23 | #include <osl.h> |
c6ac24e9 BR |
24 | #include <linux/module.h> |
25 | #include <linux/pci.h> | |
a9533e7e HP |
26 | #include <bcmutils.h> |
27 | #include <siutils.h> | |
28 | #include <bcmdevs.h> | |
29 | #include <hndsoc.h> | |
30 | #include <sbchipc.h> | |
31 | #include <pci_core.h> | |
32 | #include <pcie_core.h> | |
33 | #include <nicpci.h> | |
34 | #include <bcmnvram.h> | |
35 | #include <bcmsrom.h> | |
a9533e7e HP |
36 | #include <pcicfg.h> |
37 | #include <sbsocram.h> | |
38 | #ifdef BCMSDIO | |
39 | #include <bcmsdh.h> | |
40 | #include <sdio.h> | |
41 | #include <sbsdio.h> | |
42 | #include <sbhnddma.h> | |
43 | #include <sbsdpcmdev.h> | |
44 | #include <bcmsdpcm.h> | |
45 | #endif /* BCMSDIO */ | |
46 | #include <hndpmu.h> | |
47 | ||
48 | /* this file now contains only definitions for sb functions, only necessary | |
49 | *for devices using Sonics backplanes (bcm4329) | |
50 | */ | |
51 | ||
52 | /* if an amba SDIO device is supported, please further restrict the inclusion | |
53 | * of this file | |
54 | */ | |
55 | #ifdef BCMSDIO | |
56 | #include "siutils_priv.h" | |
57 | #endif | |
58 | ||
59 | /* local prototypes */ | |
e69284f2 | 60 | static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, |
a9533e7e | 61 | void *regs, uint bustype, void *sdh, char **vars, |
7cc4a4c0 JC |
62 | uint *varsz); |
63 | static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, | |
a9533e7e | 64 | void *sdh); |
7cc4a4c0 | 65 | static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, |
66cbd3ab | 66 | u32 savewin, uint *origidx, void *regs); |
7cc4a4c0 | 67 | static void si_nvram_process(si_info_t *sii, char *pvars); |
a9533e7e HP |
68 | |
69 | /* dev path concatenation util */ | |
7cc4a4c0 JC |
70 | static char *si_devpathvar(si_t *sih, char *var, int len, const char *name); |
71 | static bool _si_clkctl_cc(si_info_t *sii, uint mode); | |
72 | static bool si_ispcie(si_info_t *sii); | |
b4f790ee | 73 | static uint socram_banksize(si_info_t *sii, sbsocramregs_t *r, |
36ef9a1e | 74 | u8 idx, u8 mtype); |
a9533e7e HP |
75 | |
76 | /* global variable to indicate reservation/release of gpio's */ | |
66cbd3ab | 77 | static u32 si_gpioreservation; |
a9533e7e | 78 | |
a9533e7e HP |
79 | /* |
80 | * Allocate a si handle. | |
81 | * devid - pci device id (used to determine chip#) | |
82 | * osh - opaque OS handle | |
83 | * regs - virtual address of initial core registers | |
84 | * bustype - pci/sb/sdio/etc | |
85 | * vars - pointer to a pointer area for "environment" variables | |
86 | * varsz - pointer to int to return the size of the vars | |
87 | */ | |
e69284f2 BR |
88 | si_t *si_attach(uint devid, struct osl_info *osh, void *regs, uint bustype, |
89 | void *sdh, char **vars, uint *varsz) | |
0d2f0724 | 90 | { |
a9533e7e HP |
91 | si_info_t *sii; |
92 | ||
93 | /* alloc si_info_t */ | |
5fcc1fcb | 94 | sii = kmalloc(sizeof(si_info_t), GFP_ATOMIC); |
ca8c1e59 | 95 | if (sii == NULL) { |
97e17d0e | 96 | SI_ERROR(("si_attach: malloc failed!\n")); |
90ea2296 | 97 | return NULL; |
a9533e7e HP |
98 | } |
99 | ||
100 | if (si_doattach(sii, devid, osh, regs, bustype, sdh, vars, varsz) == | |
101 | NULL) { | |
182acb3c | 102 | kfree(sii); |
90ea2296 | 103 | return NULL; |
a9533e7e HP |
104 | } |
105 | sii->vars = vars ? *vars : NULL; | |
106 | sii->varsz = varsz ? *varsz : 0; | |
107 | ||
108 | return (si_t *) sii; | |
109 | } | |
110 | ||
111 | /* global kernel resource */ | |
112 | static si_info_t ksii; | |
113 | ||
0d2f0724 GKH |
114 | static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, |
115 | void *sdh) | |
116 | { | |
a9533e7e | 117 | |
cf2b4488 | 118 | #ifndef BRCM_FULLMAC |
a9533e7e HP |
119 | /* kludge to enable the clock on the 4306 which lacks a slowclock */ |
120 | if (BUSTYPE(bustype) == PCI_BUS && !si_ispcie(sii)) | |
121 | si_clkctl_xtal(&sii->pub, XTAL | PLL, ON); | |
cf2b4488 | 122 | #endif |
a9533e7e HP |
123 | |
124 | #if defined(BCMSDIO) | |
125 | if (BUSTYPE(bustype) == SDIO_BUS) { | |
126 | int err; | |
36ef9a1e | 127 | u8 clkset; |
a9533e7e HP |
128 | |
129 | /* Try forcing SDIO core to do ALPAvail request only */ | |
130 | clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; | |
131 | bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, | |
132 | clkset, &err); | |
133 | if (!err) { | |
36ef9a1e | 134 | u8 clkval; |
a9533e7e HP |
135 | |
136 | /* If register supported, wait for ALPAvail and then force ALP */ | |
137 | clkval = | |
138 | bcmsdh_cfg_read(sdh, SDIO_FUNC_1, | |
139 | SBSDIO_FUNC1_CHIPCLKCSR, NULL); | |
140 | if ((clkval & ~SBSDIO_AVBITS) == clkset) { | |
141 | SPINWAIT(((clkval = | |
142 | bcmsdh_cfg_read(sdh, SDIO_FUNC_1, | |
143 | SBSDIO_FUNC1_CHIPCLKCSR, | |
144 | NULL)), | |
145 | !SBSDIO_ALPAV(clkval)), | |
146 | PMU_MAX_TRANSITION_DLY); | |
147 | if (!SBSDIO_ALPAV(clkval)) { | |
148 | SI_ERROR(("timeout on ALPAV wait, clkval 0x%02x\n", clkval)); | |
0965ae88 | 149 | return false; |
a9533e7e HP |
150 | } |
151 | clkset = | |
152 | SBSDIO_FORCE_HW_CLKREQ_OFF | | |
153 | SBSDIO_FORCE_ALP; | |
154 | bcmsdh_cfg_write(sdh, SDIO_FUNC_1, | |
155 | SBSDIO_FUNC1_CHIPCLKCSR, | |
156 | clkset, &err); | |
7383141b | 157 | udelay(65); |
a9533e7e HP |
158 | } |
159 | } | |
160 | ||
161 | /* Also, disable the extra SDIO pull-ups */ | |
162 | bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, | |
163 | NULL); | |
164 | } | |
165 | #endif /* defined(BCMSDIO) */ | |
166 | ||
0f0881b0 | 167 | return true; |
a9533e7e HP |
168 | } |
169 | ||
0d2f0724 GKH |
170 | static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, |
171 | u32 savewin, uint *origidx, void *regs) | |
172 | { | |
a9533e7e HP |
173 | bool pci, pcie; |
174 | uint i; | |
175 | uint pciidx, pcieidx, pcirev, pcierev; | |
176 | ||
177 | cc = si_setcoreidx(&sii->pub, SI_CC_IDX); | |
c03b63c1 | 178 | ASSERT(cc); |
a9533e7e HP |
179 | |
180 | /* get chipcommon rev */ | |
181 | sii->pub.ccrev = (int)si_corerev(&sii->pub); | |
182 | ||
183 | /* get chipcommon chipstatus */ | |
184 | if (sii->pub.ccrev >= 11) | |
185 | sii->pub.chipst = R_REG(sii->osh, &cc->chipstatus); | |
186 | ||
187 | /* get chipcommon capabilites */ | |
188 | sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities); | |
189 | /* get chipcommon extended capabilities */ | |
190 | ||
cf2b4488 | 191 | #ifndef BRCM_FULLMAC |
a9533e7e HP |
192 | if (sii->pub.ccrev >= 35) |
193 | sii->pub.cccaps_ext = R_REG(sii->osh, &cc->capabilities_ext); | |
cf2b4488 | 194 | #endif |
a9533e7e HP |
195 | /* get pmu rev and caps */ |
196 | if (sii->pub.cccaps & CC_CAP_PMU) { | |
197 | sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities); | |
198 | sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; | |
199 | } | |
200 | ||
201 | /* | |
202 | SI_MSG(("Chipc: rev %d, caps 0x%x, chipst 0x%x pmurev %d, pmucaps 0x%x\n", | |
203 | sii->pub.ccrev, sii->pub.cccaps, sii->pub.chipst, sii->pub.pmurev, | |
204 | sii->pub.pmucaps)); | |
205 | */ | |
206 | ||
207 | /* figure out bus/orignal core idx */ | |
208 | sii->pub.buscoretype = NODEV_CORE_ID; | |
209 | sii->pub.buscorerev = NOREV; | |
210 | sii->pub.buscoreidx = BADIDX; | |
211 | ||
0965ae88 | 212 | pci = pcie = false; |
a9533e7e HP |
213 | pcirev = pcierev = NOREV; |
214 | pciidx = pcieidx = BADIDX; | |
215 | ||
216 | for (i = 0; i < sii->numcores; i++) { | |
217 | uint cid, crev; | |
218 | ||
219 | si_setcoreidx(&sii->pub, i); | |
220 | cid = si_coreid(&sii->pub); | |
221 | crev = si_corerev(&sii->pub); | |
222 | ||
223 | /* Display cores found */ | |
224 | SI_VMSG(("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n", | |
225 | i, cid, crev, sii->coresba[i], sii->regs[i])); | |
226 | ||
227 | if (BUSTYPE(bustype) == PCI_BUS) { | |
228 | if (cid == PCI_CORE_ID) { | |
229 | pciidx = i; | |
230 | pcirev = crev; | |
0f0881b0 | 231 | pci = true; |
a9533e7e HP |
232 | } else if (cid == PCIE_CORE_ID) { |
233 | pcieidx = i; | |
234 | pcierev = crev; | |
0f0881b0 | 235 | pcie = true; |
a9533e7e HP |
236 | } |
237 | } | |
238 | #ifdef BCMSDIO | |
239 | else if (((BUSTYPE(bustype) == SDIO_BUS) || | |
240 | (BUSTYPE(bustype) == SPI_BUS)) && | |
241 | ((cid == PCMCIA_CORE_ID) || (cid == SDIOD_CORE_ID))) { | |
242 | sii->pub.buscorerev = crev; | |
243 | sii->pub.buscoretype = cid; | |
244 | sii->pub.buscoreidx = i; | |
245 | } | |
246 | #endif /* BCMSDIO */ | |
247 | ||
248 | /* find the core idx before entering this func. */ | |
249 | if ((savewin && (savewin == sii->coresba[i])) || | |
250 | (regs == sii->regs[i])) | |
251 | *origidx = i; | |
252 | } | |
253 | ||
cf2b4488 HP |
254 | #ifdef BRCM_FULLMAC |
255 | SI_MSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, | |
256 | sii->pub.buscoretype, sii->pub.buscorerev)); | |
257 | ||
258 | /* Make sure any on-chip ARM is off (in case strapping is wrong), | |
259 | * or downloaded code was | |
260 | * already running. | |
261 | */ | |
262 | if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) { | |
263 | if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) || | |
264 | si_setcore(&sii->pub, ARMCM3_CORE_ID, 0)) | |
265 | si_core_disable(&sii->pub, 0); | |
266 | } | |
267 | #else | |
a9533e7e HP |
268 | if (pci && pcie) { |
269 | if (si_ispcie(sii)) | |
0965ae88 | 270 | pci = false; |
a9533e7e | 271 | else |
0965ae88 | 272 | pcie = false; |
a9533e7e HP |
273 | } |
274 | if (pci) { | |
275 | sii->pub.buscoretype = PCI_CORE_ID; | |
276 | sii->pub.buscorerev = pcirev; | |
277 | sii->pub.buscoreidx = pciidx; | |
278 | } else if (pcie) { | |
279 | sii->pub.buscoretype = PCIE_CORE_ID; | |
280 | sii->pub.buscorerev = pcierev; | |
281 | sii->pub.buscoreidx = pcieidx; | |
282 | } | |
283 | ||
284 | SI_VMSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, | |
285 | sii->pub.buscoretype, sii->pub.buscorerev)); | |
286 | ||
287 | /* fixup necessary chip/core configurations */ | |
288 | if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { | |
289 | if (SI_FAST(sii)) { | |
ca8c1e59 | 290 | if (!sii->pch) { |
c03b63c1 | 291 | sii->pch = (void *)pcicore_init( |
ca8c1e59 JC |
292 | &sii->pub, sii->osh, |
293 | (void *)PCIEREGS(sii)); | |
294 | if (sii->pch == NULL) | |
0965ae88 | 295 | return false; |
ca8c1e59 | 296 | } |
a9533e7e HP |
297 | } |
298 | if (si_pci_fixcfg(&sii->pub)) { | |
299 | SI_ERROR(("si_doattach: sb_pci_fixcfg failed\n")); | |
0965ae88 | 300 | return false; |
a9533e7e HP |
301 | } |
302 | } | |
cf2b4488 | 303 | #endif |
a9533e7e HP |
304 | /* return to the original core */ |
305 | si_setcoreidx(&sii->pub, *origidx); | |
306 | ||
0f0881b0 | 307 | return true; |
a9533e7e HP |
308 | } |
309 | ||
0d2f0724 | 310 | static __used void si_nvram_process(si_info_t *sii, char *pvars) |
a2627bc0 | 311 | { |
a9533e7e HP |
312 | uint w = 0; |
313 | ||
314 | /* get boardtype and boardrev */ | |
315 | switch (BUSTYPE(sii->pub.bustype)) { | |
316 | case PCI_BUS: | |
317 | /* do a pci config read to get subsystem id and subvendor id */ | |
57d8cd23 | 318 | pci_read_config_dword(sii->osh->pdev, PCI_CFG_SVID, &w); |
a9533e7e | 319 | /* Let nvram variables override subsystem Vend/ID */ |
7d4df48e | 320 | sii->pub.boardvendor = (u16)si_getdevpathintvar(&sii->pub, |
ca8c1e59 JC |
321 | "boardvendor"); |
322 | if (sii->pub.boardvendor == 0) | |
a9533e7e HP |
323 | sii->pub.boardvendor = w & 0xffff; |
324 | else | |
325 | SI_ERROR(("Overriding boardvendor: 0x%x instead of 0x%x\n", sii->pub.boardvendor, w & 0xffff)); | |
7d4df48e | 326 | sii->pub.boardtype = (u16)si_getdevpathintvar(&sii->pub, |
ca8c1e59 JC |
327 | "boardtype"); |
328 | if (sii->pub.boardtype == 0) | |
a9533e7e HP |
329 | sii->pub.boardtype = (w >> 16) & 0xffff; |
330 | else | |
331 | SI_ERROR(("Overriding boardtype: 0x%x instead of 0x%x\n", sii->pub.boardtype, (w >> 16) & 0xffff)); | |
332 | break; | |
333 | ||
334 | #ifdef BCMSDIO | |
335 | case SDIO_BUS: | |
336 | #endif | |
337 | sii->pub.boardvendor = getintvar(pvars, "manfid"); | |
338 | sii->pub.boardtype = getintvar(pvars, "prodid"); | |
339 | break; | |
340 | ||
341 | #ifdef BCMSDIO | |
342 | case SPI_BUS: | |
343 | sii->pub.boardvendor = VENDOR_BROADCOM; | |
344 | sii->pub.boardtype = SPI_BOARD; | |
345 | break; | |
346 | #endif | |
347 | ||
348 | case SI_BUS: | |
349 | case JTAG_BUS: | |
350 | sii->pub.boardvendor = VENDOR_BROADCOM; | |
ca8c1e59 JC |
351 | sii->pub.boardtype = getintvar(pvars, "prodid"); |
352 | if (pvars == NULL || (sii->pub.boardtype == 0)) { | |
353 | sii->pub.boardtype = getintvar(NULL, "boardtype"); | |
354 | if (sii->pub.boardtype == 0) | |
a9533e7e | 355 | sii->pub.boardtype = 0xffff; |
ca8c1e59 | 356 | } |
a9533e7e HP |
357 | break; |
358 | } | |
359 | ||
360 | if (sii->pub.boardtype == 0) { | |
361 | SI_ERROR(("si_doattach: unknown board type\n")); | |
362 | ASSERT(sii->pub.boardtype); | |
363 | } | |
364 | ||
365 | sii->pub.boardflags = getintvar(pvars, "boardflags"); | |
366 | } | |
367 | ||
368 | /* this is will make Sonics calls directly, since Sonics is no longer supported in the Si abstraction */ | |
369 | /* this has been customized for the bcm 4329 ONLY */ | |
370 | #ifdef BCMSDIO | |
e69284f2 | 371 | static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, |
0d2f0724 GKH |
372 | void *regs, uint bustype, void *sdh, |
373 | char **vars, uint *varsz) | |
374 | { | |
a9533e7e | 375 | struct si_pub *sih = &sii->pub; |
66cbd3ab | 376 | u32 w, savewin; |
a9533e7e HP |
377 | chipcregs_t *cc; |
378 | char *pvars = NULL; | |
379 | uint origidx; | |
380 | ||
381 | ASSERT(GOODREGS(regs)); | |
382 | ||
580a0bd9 | 383 | bzero((unsigned char *) sii, sizeof(si_info_t)); |
a9533e7e HP |
384 | |
385 | savewin = 0; | |
386 | ||
387 | sih->buscoreidx = BADIDX; | |
388 | ||
389 | sii->curmap = regs; | |
390 | sii->sdh = sdh; | |
391 | sii->osh = osh; | |
392 | ||
393 | /* find Chipcommon address */ | |
394 | cc = (chipcregs_t *) sii->curmap; | |
395 | sih->bustype = bustype; | |
396 | ||
397 | if (bustype != BUSTYPE(bustype)) { | |
398 | SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", bustype, BUSTYPE(bustype))); | |
399 | return NULL; | |
400 | } | |
401 | ||
402 | /* bus/core/clk setup for register access */ | |
403 | if (!si_buscore_prep(sii, bustype, devid, sdh)) { | |
404 | SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", | |
405 | bustype)); | |
406 | return NULL; | |
407 | } | |
408 | ||
409 | /* ChipID recognition. | |
410 | * We assume we can read chipid at offset 0 from the regs arg. | |
411 | * If we add other chiptypes (or if we need to support old sdio hosts w/o chipcommon), | |
412 | * some way of recognizing them needs to be added here. | |
413 | */ | |
414 | w = R_REG(osh, &cc->chipid); | |
415 | sih->socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT; | |
416 | /* Might as wll fill in chip id rev & pkg */ | |
417 | sih->chip = w & CID_ID_MASK; | |
418 | sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT; | |
419 | sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT; | |
420 | ||
cf2b4488 HP |
421 | if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && |
422 | (sih->chippkg != BCM4329_289PIN_PKG_ID)) | |
423 | sih->chippkg = BCM4329_182PIN_PKG_ID; | |
424 | ||
a9533e7e HP |
425 | sih->issim = IS_SIM(sih->chippkg); |
426 | ||
427 | /* scan for cores */ | |
428 | /* SI_MSG(("Found chip type SB (0x%08x)\n", w)); */ | |
429 | sb_scan(&sii->pub, regs, devid); | |
430 | ||
431 | /* no cores found, bail out */ | |
432 | if (sii->numcores == 0) { | |
433 | SI_ERROR(("si_doattach: could not find any cores\n")); | |
434 | return NULL; | |
435 | } | |
436 | /* bus/core/clk setup */ | |
437 | origidx = SI_CC_IDX; | |
438 | if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) { | |
439 | SI_ERROR(("si_doattach: si_buscore_setup failed\n")); | |
440 | goto exit; | |
441 | } | |
442 | ||
cf2b4488 HP |
443 | #ifdef BRCM_FULLMAC |
444 | pvars = NULL; | |
445 | #else | |
a9533e7e HP |
446 | /* Init nvram from flash if it exists */ |
447 | nvram_init((void *)&(sii->pub)); | |
448 | ||
449 | /* Init nvram from sprom/otp if they exist */ | |
450 | if (srom_var_init | |
451 | (&sii->pub, BUSTYPE(bustype), regs, sii->osh, vars, varsz)) { | |
452 | SI_ERROR(("si_doattach: srom_var_init failed: bad srom\n")); | |
453 | goto exit; | |
454 | } | |
455 | pvars = vars ? *vars : NULL; | |
456 | si_nvram_process(sii, pvars); | |
cf2b4488 | 457 | #endif |
a9533e7e HP |
458 | |
459 | /* === NVRAM, clock is ready === */ | |
460 | ||
cf2b4488 HP |
461 | #ifdef BRCM_FULLMAC |
462 | if (sii->pub.ccrev >= 20) { | |
463 | #endif | |
a9533e7e HP |
464 | cc = (chipcregs_t *) si_setcore(sih, CC_CORE_ID, 0); |
465 | W_REG(osh, &cc->gpiopullup, 0); | |
466 | W_REG(osh, &cc->gpiopulldown, 0); | |
467 | sb_setcoreidx(sih, origidx); | |
cf2b4488 HP |
468 | #ifdef BRCM_FULLMAC |
469 | } | |
470 | #endif | |
a9533e7e | 471 | |
cf2b4488 | 472 | #ifndef BRCM_FULLMAC |
a9533e7e HP |
473 | /* PMU specific initializations */ |
474 | if (PMUCTL_ENAB(sih)) { | |
66cbd3ab | 475 | u32 xtalfreq; |
a9533e7e HP |
476 | si_pmu_init(sih, sii->osh); |
477 | si_pmu_chip_init(sih, sii->osh); | |
478 | xtalfreq = getintvar(pvars, "xtalfreq"); | |
479 | /* If xtalfreq var not available, try to measure it */ | |
480 | if (xtalfreq == 0) | |
481 | xtalfreq = si_pmu_measure_alpclk(sih, sii->osh); | |
482 | si_pmu_pll_init(sih, sii->osh, xtalfreq); | |
483 | si_pmu_res_init(sih, sii->osh); | |
484 | si_pmu_swreg_init(sih, sii->osh); | |
485 | } | |
486 | ||
487 | /* setup the GPIO based LED powersave register */ | |
ca8c1e59 JC |
488 | w = getintvar(pvars, "leddc"); |
489 | if (w == 0) | |
a9533e7e | 490 | w = DEFAULT_GPIOTIMERVAL; |
ce0f1b8c | 491 | sb_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, gpiotimerval), ~0, w); |
a9533e7e HP |
492 | |
493 | #ifdef BCMDBG | |
494 | /* clear any previous epidiag-induced target abort */ | |
0965ae88 | 495 | sb_taclear(sih, false); |
a9533e7e | 496 | #endif /* BCMDBG */ |
cf2b4488 | 497 | #endif |
a9533e7e | 498 | |
90ea2296 | 499 | return sii; |
a9533e7e HP |
500 | |
501 | exit: | |
502 | return NULL; | |
503 | } | |
504 | ||
505 | #else /* BCMSDIO */ | |
e69284f2 | 506 | static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh, |
0d2f0724 GKH |
507 | void *regs, uint bustype, void *sdh, |
508 | char **vars, uint *varsz) | |
509 | { | |
a9533e7e | 510 | struct si_pub *sih = &sii->pub; |
66cbd3ab | 511 | u32 w, savewin; |
a9533e7e HP |
512 | chipcregs_t *cc; |
513 | char *pvars = NULL; | |
514 | uint origidx; | |
515 | ||
516 | ASSERT(GOODREGS(regs)); | |
517 | ||
580a0bd9 | 518 | bzero((unsigned char *) sii, sizeof(si_info_t)); |
a9533e7e HP |
519 | |
520 | savewin = 0; | |
521 | ||
522 | sih->buscoreidx = BADIDX; | |
523 | ||
524 | sii->curmap = regs; | |
525 | sii->sdh = sdh; | |
526 | sii->osh = osh; | |
527 | ||
528 | /* check to see if we are a si core mimic'ing a pci core */ | |
57d8cd23 BR |
529 | if (bustype == PCI_BUS) { |
530 | pci_read_config_dword(sii->osh->pdev, PCI_SPROM_CONTROL, &w); | |
531 | if (w == 0xffffffff) { | |
532 | SI_ERROR(("%s: incoming bus is PCI but it's a lie, " | |
533 | " switching to SI devid:0x%x\n", | |
534 | __func__, devid)); | |
535 | bustype = SI_BUS; | |
536 | } | |
a9533e7e HP |
537 | } |
538 | ||
539 | /* find Chipcommon address */ | |
540 | if (bustype == PCI_BUS) { | |
57d8cd23 | 541 | pci_read_config_dword(sii->osh->pdev, PCI_BAR0_WIN, &savewin); |
a9533e7e HP |
542 | if (!GOODCOREADDR(savewin, SI_ENUM_BASE)) |
543 | savewin = SI_ENUM_BASE; | |
57d8cd23 BR |
544 | pci_write_config_dword(sii->osh->pdev, PCI_BAR0_WIN, |
545 | SI_ENUM_BASE); | |
a9533e7e HP |
546 | cc = (chipcregs_t *) regs; |
547 | } else { | |
548 | cc = (chipcregs_t *) REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE); | |
549 | } | |
550 | ||
551 | sih->bustype = bustype; | |
552 | if (bustype != BUSTYPE(bustype)) { | |
553 | SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", bustype, BUSTYPE(bustype))); | |
554 | return NULL; | |
555 | } | |
556 | ||
557 | /* bus/core/clk setup for register access */ | |
558 | if (!si_buscore_prep(sii, bustype, devid, sdh)) { | |
559 | SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", | |
560 | bustype)); | |
561 | return NULL; | |
562 | } | |
563 | ||
564 | /* ChipID recognition. | |
565 | * We assume we can read chipid at offset 0 from the regs arg. | |
566 | * If we add other chiptypes (or if we need to support old sdio hosts w/o chipcommon), | |
567 | * some way of recognizing them needs to be added here. | |
568 | */ | |
569 | w = R_REG(osh, &cc->chipid); | |
570 | sih->socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT; | |
571 | /* Might as wll fill in chip id rev & pkg */ | |
572 | sih->chip = w & CID_ID_MASK; | |
573 | sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT; | |
574 | sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT; | |
575 | ||
576 | sih->issim = IS_SIM(sih->chippkg); | |
577 | ||
578 | /* scan for cores */ | |
579 | if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) { | |
580 | SI_MSG(("Found chip type AI (0x%08x)\n", w)); | |
581 | /* pass chipc address instead of original core base */ | |
c03b63c1 | 582 | ai_scan(&sii->pub, (void *)cc, devid); |
a9533e7e HP |
583 | } else { |
584 | SI_ERROR(("Found chip of unknown type (0x%08x)\n", w)); | |
585 | return NULL; | |
586 | } | |
587 | /* no cores found, bail out */ | |
588 | if (sii->numcores == 0) { | |
589 | SI_ERROR(("si_doattach: could not find any cores\n")); | |
590 | return NULL; | |
591 | } | |
592 | /* bus/core/clk setup */ | |
593 | origidx = SI_CC_IDX; | |
594 | if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) { | |
595 | SI_ERROR(("si_doattach: si_buscore_setup failed\n")); | |
596 | goto exit; | |
597 | } | |
598 | ||
599 | /* assume current core is CC */ | |
600 | if ((sii->pub.ccrev == 0x25) | |
601 | && | |
602 | ((CHIPID(sih->chip) == BCM43236_CHIP_ID | |
603 | || CHIPID(sih->chip) == BCM43235_CHIP_ID | |
604 | || CHIPID(sih->chip) == BCM43238_CHIP_ID) | |
605 | && (CHIPREV(sii->pub.chiprev) <= 2))) { | |
606 | ||
607 | if ((cc->chipstatus & CST43236_BP_CLK) != 0) { | |
608 | uint clkdiv; | |
609 | clkdiv = R_REG(osh, &cc->clkdiv); | |
610 | /* otp_clk_div is even number, 120/14 < 9mhz */ | |
611 | clkdiv = (clkdiv & ~CLKD_OTP) | (14 << CLKD_OTP_SHIFT); | |
612 | W_REG(osh, &cc->clkdiv, clkdiv); | |
613 | SI_ERROR(("%s: set clkdiv to %x\n", __func__, clkdiv)); | |
614 | } | |
7383141b | 615 | udelay(10); |
a9533e7e HP |
616 | } |
617 | ||
618 | /* Init nvram from flash if it exists */ | |
619 | nvram_init((void *)&(sii->pub)); | |
620 | ||
621 | /* Init nvram from sprom/otp if they exist */ | |
622 | if (srom_var_init | |
623 | (&sii->pub, BUSTYPE(bustype), regs, sii->osh, vars, varsz)) { | |
624 | SI_ERROR(("si_doattach: srom_var_init failed: bad srom\n")); | |
625 | goto exit; | |
626 | } | |
627 | pvars = vars ? *vars : NULL; | |
628 | si_nvram_process(sii, pvars); | |
629 | ||
630 | /* === NVRAM, clock is ready === */ | |
631 | cc = (chipcregs_t *) si_setcore(sih, CC_CORE_ID, 0); | |
632 | W_REG(osh, &cc->gpiopullup, 0); | |
633 | W_REG(osh, &cc->gpiopulldown, 0); | |
634 | si_setcoreidx(sih, origidx); | |
635 | ||
636 | /* PMU specific initializations */ | |
637 | if (PMUCTL_ENAB(sih)) { | |
66cbd3ab | 638 | u32 xtalfreq; |
a9533e7e HP |
639 | si_pmu_init(sih, sii->osh); |
640 | si_pmu_chip_init(sih, sii->osh); | |
641 | xtalfreq = getintvar(pvars, "xtalfreq"); | |
642 | /* If xtalfreq var not available, try to measure it */ | |
643 | if (xtalfreq == 0) | |
644 | xtalfreq = si_pmu_measure_alpclk(sih, sii->osh); | |
645 | si_pmu_pll_init(sih, sii->osh, xtalfreq); | |
646 | si_pmu_res_init(sih, sii->osh); | |
647 | si_pmu_swreg_init(sih, sii->osh); | |
648 | } | |
649 | ||
650 | /* setup the GPIO based LED powersave register */ | |
ca8c1e59 JC |
651 | w = getintvar(pvars, "leddc"); |
652 | if (w == 0) | |
a9533e7e | 653 | w = DEFAULT_GPIOTIMERVAL; |
ce0f1b8c | 654 | si_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, gpiotimerval), ~0, w); |
a9533e7e HP |
655 | |
656 | if (PCIE(sii)) { | |
657 | ASSERT(sii->pch != NULL); | |
658 | pcicore_attach(sii->pch, pvars, SI_DOATTACH); | |
659 | } | |
660 | ||
661 | if ((CHIPID(sih->chip) == BCM43224_CHIP_ID) || | |
662 | (CHIPID(sih->chip) == BCM43421_CHIP_ID)) { | |
663 | /* enable 12 mA drive strenth for 43224 and set chipControl register bit 15 */ | |
664 | if (CHIPREV(sih->chiprev) == 0) { | |
665 | SI_MSG(("Applying 43224A0 WARs\n")); | |
666 | si_corereg(sih, SI_CC_IDX, | |
ce0f1b8c | 667 | offsetof(chipcregs_t, chipcontrol), |
a9533e7e HP |
668 | CCTRL43224_GPIO_TOGGLE, |
669 | CCTRL43224_GPIO_TOGGLE); | |
670 | si_pmu_chipcontrol(sih, 0, CCTRL_43224A0_12MA_LED_DRIVE, | |
671 | CCTRL_43224A0_12MA_LED_DRIVE); | |
672 | } | |
673 | if (CHIPREV(sih->chiprev) >= 1) { | |
674 | SI_MSG(("Applying 43224B0+ WARs\n")); | |
675 | si_pmu_chipcontrol(sih, 0, CCTRL_43224B0_12MA_LED_DRIVE, | |
676 | CCTRL_43224B0_12MA_LED_DRIVE); | |
677 | } | |
678 | } | |
679 | ||
680 | if (CHIPID(sih->chip) == BCM4313_CHIP_ID) { | |
681 | /* enable 12 mA drive strenth for 4313 and set chipControl register bit 1 */ | |
682 | SI_MSG(("Applying 4313 WARs\n")); | |
683 | si_pmu_chipcontrol(sih, 0, CCTRL_4313_12MA_LED_DRIVE, | |
684 | CCTRL_4313_12MA_LED_DRIVE); | |
685 | } | |
686 | ||
687 | if (CHIPID(sih->chip) == BCM4331_CHIP_ID) { | |
688 | /* Enable Ext PA lines depending on chip package option */ | |
0f0881b0 | 689 | si_chipcontrl_epa4331(sih, true); |
a9533e7e HP |
690 | } |
691 | ||
90ea2296 | 692 | return sii; |
a9533e7e HP |
693 | exit: |
694 | if (BUSTYPE(sih->bustype) == PCI_BUS) { | |
695 | if (sii->pch) | |
696 | pcicore_deinit(sii->pch); | |
697 | sii->pch = NULL; | |
698 | } | |
699 | ||
700 | return NULL; | |
701 | } | |
702 | #endif /* BCMSDIO */ | |
703 | ||
704 | /* may be called with core in reset */ | |
0d2f0724 | 705 | void si_detach(si_t *sih) |
a2627bc0 | 706 | { |
a9533e7e HP |
707 | si_info_t *sii; |
708 | uint idx; | |
709 | ||
710 | struct si_pub *si_local = NULL; | |
711 | bcopy(&sih, &si_local, sizeof(si_t **)); | |
712 | ||
713 | sii = SI_INFO(sih); | |
714 | ||
715 | if (sii == NULL) | |
716 | return; | |
717 | ||
718 | if (BUSTYPE(sih->bustype) == SI_BUS) | |
719 | for (idx = 0; idx < SI_MAXCORES; idx++) | |
720 | if (sii->regs[idx]) { | |
721 | REG_UNMAP(sii->regs[idx]); | |
722 | sii->regs[idx] = NULL; | |
723 | } | |
724 | ||
cf2b4488 | 725 | #ifndef BRCM_FULLMAC |
a9533e7e HP |
726 | nvram_exit((void *)si_local); /* free up nvram buffers */ |
727 | ||
728 | if (BUSTYPE(sih->bustype) == PCI_BUS) { | |
729 | if (sii->pch) | |
730 | pcicore_deinit(sii->pch); | |
731 | sii->pch = NULL; | |
732 | } | |
cf2b4488 | 733 | #endif |
a9533e7e HP |
734 | #if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS) |
735 | if (sii != &ksii) | |
736 | #endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */ | |
182acb3c | 737 | kfree(sii); |
a9533e7e HP |
738 | } |
739 | ||
7cc4a4c0 | 740 | void *si_osh(si_t *sih) |
a9533e7e HP |
741 | { |
742 | si_info_t *sii; | |
743 | ||
744 | sii = SI_INFO(sih); | |
745 | return sii->osh; | |
746 | } | |
747 | ||
a9533e7e HP |
748 | /* register driver interrupt disabling and restoring callback functions */ |
749 | void | |
7cc4a4c0 | 750 | si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, |
a9533e7e HP |
751 | void *intrsenabled_fn, void *intr_arg) |
752 | { | |
753 | si_info_t *sii; | |
754 | ||
755 | sii = SI_INFO(sih); | |
756 | sii->intr_arg = intr_arg; | |
757 | sii->intrsoff_fn = (si_intrsoff_t) intrsoff_fn; | |
758 | sii->intrsrestore_fn = (si_intrsrestore_t) intrsrestore_fn; | |
759 | sii->intrsenabled_fn = (si_intrsenabled_t) intrsenabled_fn; | |
760 | /* save current core id. when this function called, the current core | |
761 | * must be the core which provides driver functions(il, et, wl, etc.) | |
762 | */ | |
763 | sii->dev_coreid = sii->coreid[sii->curidx]; | |
764 | } | |
765 | ||
7cc4a4c0 | 766 | void si_deregister_intr_callback(si_t *sih) |
a9533e7e HP |
767 | { |
768 | si_info_t *sii; | |
769 | ||
770 | sii = SI_INFO(sih); | |
771 | sii->intrsoff_fn = NULL; | |
772 | } | |
773 | ||
7cc4a4c0 | 774 | uint si_flag(si_t *sih) |
a9533e7e HP |
775 | { |
776 | if (CHIPTYPE(sih->socitype) == SOCI_AI) | |
777 | return ai_flag(sih); | |
778 | else { | |
779 | ASSERT(0); | |
780 | return 0; | |
781 | } | |
782 | } | |
783 | ||
7cc4a4c0 | 784 | void si_setint(si_t *sih, int siflag) |
a9533e7e HP |
785 | { |
786 | if (CHIPTYPE(sih->socitype) == SOCI_AI) | |
787 | ai_setint(sih, siflag); | |
788 | else | |
789 | ASSERT(0); | |
790 | } | |
791 | ||
792 | #ifndef BCMSDIO | |
7cc4a4c0 | 793 | uint si_coreid(si_t *sih) |
a9533e7e HP |
794 | { |
795 | si_info_t *sii; | |
796 | ||
797 | sii = SI_INFO(sih); | |
798 | return sii->coreid[sii->curidx]; | |
799 | } | |
800 | #endif | |
801 | ||
7cc4a4c0 | 802 | uint si_coreidx(si_t *sih) |
a9533e7e HP |
803 | { |
804 | si_info_t *sii; | |
805 | ||
806 | sii = SI_INFO(sih); | |
807 | return sii->curidx; | |
808 | } | |
809 | ||
7cc4a4c0 | 810 | bool si_backplane64(si_t *sih) |
a9533e7e | 811 | { |
90ea2296 | 812 | return (sih->cccaps & CC_CAP_BKPLN64) != 0; |
a9533e7e HP |
813 | } |
814 | ||
815 | #ifndef BCMSDIO | |
7cc4a4c0 | 816 | uint si_corerev(si_t *sih) |
a9533e7e HP |
817 | { |
818 | if (CHIPTYPE(sih->socitype) == SOCI_AI) | |
819 | return ai_corerev(sih); | |
820 | else { | |
821 | ASSERT(0); | |
822 | return 0; | |
823 | } | |
824 | } | |
825 | #endif | |
826 | ||
827 | /* return index of coreid or BADIDX if not found */ | |
7cc4a4c0 | 828 | uint si_findcoreidx(si_t *sih, uint coreid, uint coreunit) |
a9533e7e HP |
829 | { |
830 | si_info_t *sii; | |
831 | uint found; | |
832 | uint i; | |
833 | ||
834 | sii = SI_INFO(sih); | |
835 | ||
836 | found = 0; | |
837 | ||
838 | for (i = 0; i < sii->numcores; i++) | |
839 | if (sii->coreid[i] == coreid) { | |
840 | if (found == coreunit) | |
90ea2296 | 841 | return i; |
a9533e7e HP |
842 | found++; |
843 | } | |
844 | ||
90ea2296 | 845 | return BADIDX; |
a9533e7e HP |
846 | } |
847 | ||
a9533e7e HP |
848 | /* |
849 | * This function changes logical "focus" to the indicated core; | |
850 | * must be called with interrupts off. | |
851 | * Moreover, callers should keep interrupts off during switching out of and back to d11 core | |
852 | */ | |
7cc4a4c0 | 853 | void *si_setcore(si_t *sih, uint coreid, uint coreunit) |
a9533e7e HP |
854 | { |
855 | uint idx; | |
856 | ||
857 | idx = si_findcoreidx(sih, coreid, coreunit); | |
858 | if (!GOODIDX(idx)) | |
90ea2296 | 859 | return NULL; |
a9533e7e HP |
860 | |
861 | if (CHIPTYPE(sih->socitype) == SOCI_AI) | |
862 | return ai_setcoreidx(sih, idx); | |
863 | else { | |
864 | #ifdef BCMSDIO | |
865 | return sb_setcoreidx(sih, idx); | |
866 | #else | |
867 | ASSERT(0); | |
868 | return NULL; | |
869 | #endif | |
870 | } | |
871 | } | |
872 | ||
873 | #ifndef BCMSDIO | |
7cc4a4c0 | 874 | void *si_setcoreidx(si_t *sih, uint coreidx) |
a9533e7e HP |
875 | { |
876 | if (CHIPTYPE(sih->socitype) == SOCI_AI) | |
877 | return ai_setcoreidx(sih, coreidx); | |
878 | else { | |
879 | ASSERT(0); | |
880 | return NULL; | |
881 | } | |
882 | } | |
883 | #endif | |
884 | ||
885 | /* Turn off interrupt as required by sb_setcore, before switch core */ | |
7cc4a4c0 | 886 | void *si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val) |
a9533e7e HP |
887 | { |
888 | void *cc; | |
889 | si_info_t *sii; | |
890 | ||
891 | sii = SI_INFO(sih); | |
892 | ||
893 | if (SI_FAST(sii)) { | |
894 | /* Overloading the origidx variable to remember the coreid, | |
895 | * this works because the core ids cannot be confused with | |
896 | * core indices. | |
897 | */ | |
898 | *origidx = coreid; | |
899 | if (coreid == CC_CORE_ID) | |
900 | return (void *)CCREGS_FAST(sii); | |
901 | else if (coreid == sih->buscoretype) | |
902 | return (void *)PCIEREGS(sii); | |
903 | } | |
904 | INTR_OFF(sii, *intr_val); | |
905 | *origidx = sii->curidx; | |
906 | cc = si_setcore(sih, coreid, 0); | |
907 | ASSERT(cc != NULL); | |
908 | ||
909 | return cc; | |
910 | } | |
911 | ||
912 | /* restore coreidx and restore interrupt */ | |
7cc4a4c0 | 913 | void si_restore_core(si_t *sih, uint coreid, uint intr_val) |
a9533e7e HP |
914 | { |
915 | si_info_t *sii; | |
916 | ||
917 | sii = SI_INFO(sih); | |
918 | if (SI_FAST(sii) | |
919 | && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype))) | |
920 | return; | |
921 | ||
922 | si_setcoreidx(sih, coreid); | |
923 | INTR_RESTORE(sii, intr_val); | |
924 | } | |
925 | ||
66cbd3ab | 926 | u32 si_core_cflags(si_t *sih, u32 mask, u32 val) |
a9533e7e HP |
927 | { |
928 | if (CHIPTYPE(sih->socitype) == SOCI_AI) | |
929 | return ai_core_cflags(sih, mask, val); | |
930 | else { | |
931 | ASSERT(0); | |
932 | return 0; | |
933 | } | |
934 | } | |
935 | ||
66cbd3ab | 936 | u32 si_core_sflags(si_t *sih, u32 mask, u32 val) |
a9533e7e HP |
937 | { |
938 | if (CHIPTYPE(sih->socitype) == SOCI_AI) | |
939 | return ai_core_sflags(sih, mask, val); | |
940 | else { | |
941 | ASSERT(0); | |
942 | return 0; | |
943 | } | |
944 | } | |
945 | ||
7cc4a4c0 | 946 | bool si_iscoreup(si_t *sih) |
a9533e7e HP |
947 | { |
948 | if (CHIPTYPE(sih->socitype) == SOCI_AI) | |
949 | return ai_iscoreup(sih); | |
950 | else { | |
951 | #ifdef BCMSDIO | |
952 | return sb_iscoreup(sih); | |
953 | #else | |
954 | ASSERT(0); | |
0965ae88 | 955 | return false; |
a9533e7e HP |
956 | #endif |
957 | } | |
958 | } | |
959 | ||
66cbd3ab | 960 | void si_write_wrapperreg(si_t *sih, u32 offset, u32 val) |
a9533e7e HP |
961 | { |
962 | /* only for 4319, no requirement for SOCI_SB */ | |
963 | if (CHIPTYPE(sih->socitype) == SOCI_AI) { | |
964 | ai_write_wrap_reg(sih, offset, val); | |
965 | } | |
966 | } | |
967 | ||
7cc4a4c0 | 968 | uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) |
a9533e7e HP |
969 | { |
970 | ||
971 | if (CHIPTYPE(sih->socitype) == SOCI_AI) | |
972 | return ai_corereg(sih, coreidx, regoff, mask, val); | |
973 | else { | |
974 | #ifdef BCMSDIO | |
975 | return sb_corereg(sih, coreidx, regoff, mask, val); | |
976 | #else | |
977 | ASSERT(0); | |
978 | return 0; | |
979 | #endif | |
980 | } | |
981 | } | |
982 | ||
66cbd3ab | 983 | void si_core_disable(si_t *sih, u32 bits) |
a9533e7e HP |
984 | { |
985 | ||
986 | if (CHIPTYPE(sih->socitype) == SOCI_AI) | |
987 | ai_core_disable(sih, bits); | |
988 | #ifdef BCMSDIO | |
989 | else | |
990 | sb_core_disable(sih, bits); | |
991 | #endif | |
992 | } | |
993 | ||
66cbd3ab | 994 | void si_core_reset(si_t *sih, u32 bits, u32 resetbits) |
a9533e7e HP |
995 | { |
996 | if (CHIPTYPE(sih->socitype) == SOCI_AI) | |
997 | ai_core_reset(sih, bits, resetbits); | |
998 | #ifdef BCMSDIO | |
999 | else | |
1000 | sb_core_reset(sih, bits, resetbits); | |
1001 | #endif | |
1002 | } | |
1003 | ||
b4f790ee | 1004 | u32 si_alp_clock(si_t *sih) |
a2627bc0 | 1005 | { |
a9533e7e HP |
1006 | if (PMUCTL_ENAB(sih)) |
1007 | return si_pmu_alp_clock(sih, si_osh(sih)); | |
1008 | ||
1009 | return ALP_CLOCK; | |
1010 | } | |
1011 | ||
b4f790ee | 1012 | u32 si_ilp_clock(si_t *sih) |
a2627bc0 | 1013 | { |
a9533e7e HP |
1014 | if (PMUCTL_ENAB(sih)) |
1015 | return si_pmu_ilp_clock(sih, si_osh(sih)); | |
1016 | ||
1017 | return ILP_CLOCK; | |
1018 | } | |
1019 | ||
1020 | /* set chip watchdog reset timer to fire in 'ticks' */ | |
cf2b4488 HP |
1021 | #ifdef BRCM_FULLMAC |
1022 | void | |
1023 | si_watchdog(si_t *sih, uint ticks) | |
1024 | { | |
1025 | if (PMUCTL_ENAB(sih)) { | |
1026 | ||
1027 | if ((sih->chip == BCM4319_CHIP_ID) && (sih->chiprev == 0) && | |
1028 | (ticks != 0)) { | |
ce0f1b8c | 1029 | si_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, |
cf2b4488 HP |
1030 | clk_ctl_st), ~0, 0x2); |
1031 | si_setcore(sih, USB20D_CORE_ID, 0); | |
1032 | si_core_disable(sih, 1); | |
1033 | si_setcore(sih, CC_CORE_ID, 0); | |
1034 | } | |
1035 | ||
1036 | if (ticks == 1) | |
1037 | ticks = 2; | |
ce0f1b8c | 1038 | si_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, pmuwatchdog), |
cf2b4488 HP |
1039 | ~0, ticks); |
1040 | } else { | |
1041 | /* instant NMI */ | |
ce0f1b8c | 1042 | si_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, watchdog), |
cf2b4488 HP |
1043 | ~0, ticks); |
1044 | } | |
1045 | } | |
1046 | #else | |
7cc4a4c0 | 1047 | void si_watchdog(si_t *sih, uint ticks) |
a9533e7e HP |
1048 | { |
1049 | uint nb, maxt; | |
1050 | ||
1051 | if (PMUCTL_ENAB(sih)) { | |
1052 | ||
1053 | if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) && | |
1054 | (CHIPREV(sih->chiprev) == 0) && (ticks != 0)) { | |
1055 | si_corereg(sih, SI_CC_IDX, | |
ce0f1b8c | 1056 | offsetof(chipcregs_t, clk_ctl_st), ~0, 0x2); |
a9533e7e HP |
1057 | si_setcore(sih, USB20D_CORE_ID, 0); |
1058 | si_core_disable(sih, 1); | |
1059 | si_setcore(sih, CC_CORE_ID, 0); | |
1060 | } | |
1061 | ||
1062 | nb = (sih->ccrev < 26) ? 16 : ((sih->ccrev >= 37) ? 32 : 24); | |
1063 | /* The mips compiler uses the sllv instruction, | |
1064 | * so we specially handle the 32-bit case. | |
1065 | */ | |
1066 | if (nb == 32) | |
1067 | maxt = 0xffffffff; | |
1068 | else | |
1069 | maxt = ((1 << nb) - 1); | |
1070 | ||
1071 | if (ticks == 1) | |
1072 | ticks = 2; | |
1073 | else if (ticks > maxt) | |
1074 | ticks = maxt; | |
1075 | ||
ce0f1b8c | 1076 | si_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, pmuwatchdog), |
a9533e7e HP |
1077 | ~0, ticks); |
1078 | } else { | |
1079 | /* make sure we come up in fast clock mode; or if clearing, clear clock */ | |
1080 | si_clkctl_cc(sih, ticks ? CLK_FAST : CLK_DYNAMIC); | |
1081 | maxt = (1 << 28) - 1; | |
1082 | if (ticks > maxt) | |
1083 | ticks = maxt; | |
1084 | ||
ce0f1b8c | 1085 | si_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, watchdog), ~0, |
a9533e7e HP |
1086 | ticks); |
1087 | } | |
1088 | } | |
cf2b4488 | 1089 | #endif |
a9533e7e | 1090 | |
a9533e7e | 1091 | /* return the slow clock source - LPO, XTAL, or PCI */ |
7cc4a4c0 | 1092 | static uint si_slowclk_src(si_info_t *sii) |
a9533e7e HP |
1093 | { |
1094 | chipcregs_t *cc; | |
57d8cd23 | 1095 | u32 val; |
a9533e7e HP |
1096 | |
1097 | ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); | |
1098 | ||
1099 | if (sii->pub.ccrev < 6) { | |
57d8cd23 BR |
1100 | if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { |
1101 | pci_read_config_dword(sii->osh->pdev, PCI_GPIO_OUT, | |
1102 | &val); | |
1103 | if (val & PCI_CFG_GPIO_SCS) | |
1104 | return SCC_SS_PCI; | |
1105 | } | |
1106 | return SCC_SS_XTAL; | |
a9533e7e HP |
1107 | } else if (sii->pub.ccrev < 10) { |
1108 | cc = (chipcregs_t *) si_setcoreidx(&sii->pub, sii->curidx); | |
90ea2296 | 1109 | return R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_SS_MASK; |
a9533e7e | 1110 | } else /* Insta-clock */ |
90ea2296 | 1111 | return SCC_SS_XTAL; |
a9533e7e HP |
1112 | } |
1113 | ||
1114 | /* return the ILP (slowclock) min or max frequency */ | |
7cc4a4c0 | 1115 | static uint si_slowclk_freq(si_info_t *sii, bool max_freq, chipcregs_t *cc) |
a9533e7e | 1116 | { |
66cbd3ab | 1117 | u32 slowclk; |
a9533e7e HP |
1118 | uint div; |
1119 | ||
1120 | ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); | |
1121 | ||
1122 | /* shouldn't be here unless we've established the chip has dynamic clk control */ | |
1123 | ASSERT(R_REG(sii->osh, &cc->capabilities) & CC_CAP_PWR_CTL); | |
1124 | ||
1125 | slowclk = si_slowclk_src(sii); | |
1126 | if (sii->pub.ccrev < 6) { | |
1127 | if (slowclk == SCC_SS_PCI) | |
90ea2296 JC |
1128 | return max_freq ? (PCIMAXFREQ / 64) |
1129 | : (PCIMINFREQ / 64); | |
a9533e7e | 1130 | else |
90ea2296 JC |
1131 | return max_freq ? (XTALMAXFREQ / 32) |
1132 | : (XTALMINFREQ / 32); | |
a9533e7e HP |
1133 | } else if (sii->pub.ccrev < 10) { |
1134 | div = 4 * | |
1135 | (((R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_CD_MASK) >> | |
1136 | SCC_CD_SHIFT) + 1); | |
1137 | if (slowclk == SCC_SS_LPO) | |
90ea2296 | 1138 | return max_freq ? LPOMAXFREQ : LPOMINFREQ; |
a9533e7e | 1139 | else if (slowclk == SCC_SS_XTAL) |
90ea2296 JC |
1140 | return max_freq ? (XTALMAXFREQ / div) |
1141 | : (XTALMINFREQ / div); | |
a9533e7e | 1142 | else if (slowclk == SCC_SS_PCI) |
90ea2296 JC |
1143 | return max_freq ? (PCIMAXFREQ / div) |
1144 | : (PCIMINFREQ / div); | |
a9533e7e HP |
1145 | else |
1146 | ASSERT(0); | |
1147 | } else { | |
1148 | /* Chipc rev 10 is InstaClock */ | |
1149 | div = R_REG(sii->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT; | |
1150 | div = 4 * (div + 1); | |
90ea2296 | 1151 | return max_freq ? XTALMAXFREQ : (XTALMINFREQ / div); |
a9533e7e | 1152 | } |
90ea2296 | 1153 | return 0; |
a9533e7e HP |
1154 | } |
1155 | ||
b4f790ee | 1156 | static void si_clkctl_setdelay(si_info_t *sii, void *chipcregs) |
a2627bc0 | 1157 | { |
a9533e7e HP |
1158 | chipcregs_t *cc = (chipcregs_t *) chipcregs; |
1159 | uint slowmaxfreq, pll_delay, slowclk; | |
1160 | uint pll_on_delay, fref_sel_delay; | |
1161 | ||
1162 | pll_delay = PLL_DELAY; | |
1163 | ||
1164 | /* If the slow clock is not sourced by the xtal then add the xtal_on_delay | |
1165 | * since the xtal will also be powered down by dynamic clk control logic. | |
1166 | */ | |
1167 | ||
1168 | slowclk = si_slowclk_src(sii); | |
1169 | if (slowclk != SCC_SS_XTAL) | |
1170 | pll_delay += XTAL_ON_DELAY; | |
1171 | ||
1172 | /* Starting with 4318 it is ILP that is used for the delays */ | |
1173 | slowmaxfreq = | |
0965ae88 | 1174 | si_slowclk_freq(sii, (sii->pub.ccrev >= 10) ? false : true, cc); |
a9533e7e HP |
1175 | |
1176 | pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000; | |
1177 | fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000; | |
1178 | ||
1179 | W_REG(sii->osh, &cc->pll_on_delay, pll_on_delay); | |
1180 | W_REG(sii->osh, &cc->fref_sel_delay, fref_sel_delay); | |
1181 | } | |
1182 | ||
1183 | /* initialize power control delay registers */ | |
b4f790ee | 1184 | void si_clkctl_init(si_t *sih) |
a2627bc0 | 1185 | { |
a9533e7e HP |
1186 | si_info_t *sii; |
1187 | uint origidx = 0; | |
1188 | chipcregs_t *cc; | |
1189 | bool fast; | |
1190 | ||
1191 | if (!CCCTL_ENAB(sih)) | |
1192 | return; | |
1193 | ||
1194 | sii = SI_INFO(sih); | |
1195 | fast = SI_FAST(sii); | |
1196 | if (!fast) { | |
1197 | origidx = sii->curidx; | |
ca8c1e59 JC |
1198 | cc = (chipcregs_t *) si_setcore(sih, CC_CORE_ID, 0); |
1199 | if (cc == NULL) | |
a9533e7e | 1200 | return; |
ca8c1e59 JC |
1201 | } else { |
1202 | cc = (chipcregs_t *) CCREGS_FAST(sii); | |
1203 | if (cc == NULL) | |
1204 | return; | |
1205 | } | |
a9533e7e HP |
1206 | ASSERT(cc != NULL); |
1207 | ||
1208 | /* set all Instaclk chip ILP to 1 MHz */ | |
1209 | if (sih->ccrev >= 10) | |
1210 | SET_REG(sii->osh, &cc->system_clk_ctl, SYCC_CD_MASK, | |
1211 | (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); | |
1212 | ||
c03b63c1 | 1213 | si_clkctl_setdelay(sii, (void *)cc); |
a9533e7e HP |
1214 | |
1215 | if (!fast) | |
1216 | si_setcoreidx(sih, origidx); | |
1217 | } | |
1218 | ||
1219 | /* return the value suitable for writing to the dot11 core FAST_PWRUP_DELAY register */ | |
b4f790ee | 1220 | u16 si_clkctl_fast_pwrup_delay(si_t *sih) |
a2627bc0 | 1221 | { |
a9533e7e HP |
1222 | si_info_t *sii; |
1223 | uint origidx = 0; | |
1224 | chipcregs_t *cc; | |
1225 | uint slowminfreq; | |
7d4df48e | 1226 | u16 fpdelay; |
a9533e7e HP |
1227 | uint intr_val = 0; |
1228 | bool fast; | |
1229 | ||
1230 | sii = SI_INFO(sih); | |
1231 | if (PMUCTL_ENAB(sih)) { | |
1232 | INTR_OFF(sii, intr_val); | |
1233 | fpdelay = si_pmu_fast_pwrup_delay(sih, sii->osh); | |
1234 | INTR_RESTORE(sii, intr_val); | |
1235 | return fpdelay; | |
1236 | } | |
1237 | ||
1238 | if (!CCCTL_ENAB(sih)) | |
1239 | return 0; | |
1240 | ||
1241 | fast = SI_FAST(sii); | |
1242 | fpdelay = 0; | |
1243 | if (!fast) { | |
1244 | origidx = sii->curidx; | |
1245 | INTR_OFF(sii, intr_val); | |
ca8c1e59 JC |
1246 | cc = (chipcregs_t *) si_setcore(sih, CC_CORE_ID, 0); |
1247 | if (cc == NULL) | |
a9533e7e | 1248 | goto done; |
ca8c1e59 JC |
1249 | } else { |
1250 | cc = (chipcregs_t *) CCREGS_FAST(sii); | |
1251 | if (cc == NULL) | |
1252 | goto done; | |
1253 | } | |
a9533e7e HP |
1254 | ASSERT(cc != NULL); |
1255 | ||
0965ae88 | 1256 | slowminfreq = si_slowclk_freq(sii, false, cc); |
a9533e7e HP |
1257 | fpdelay = (((R_REG(sii->osh, &cc->pll_on_delay) + 2) * 1000000) + |
1258 | (slowminfreq - 1)) / slowminfreq; | |
1259 | ||
1260 | done: | |
1261 | if (!fast) { | |
1262 | si_setcoreidx(sih, origidx); | |
1263 | INTR_RESTORE(sii, intr_val); | |
1264 | } | |
1265 | return fpdelay; | |
1266 | } | |
1267 | ||
1268 | /* turn primary xtal and/or pll off/on */ | |
7cc4a4c0 | 1269 | int si_clkctl_xtal(si_t *sih, uint what, bool on) |
a9533e7e HP |
1270 | { |
1271 | si_info_t *sii; | |
66cbd3ab | 1272 | u32 in, out, outen; |
a9533e7e HP |
1273 | |
1274 | sii = SI_INFO(sih); | |
1275 | ||
1276 | switch (BUSTYPE(sih->bustype)) { | |
1277 | ||
1278 | #ifdef BCMSDIO | |
1279 | case SDIO_BUS: | |
90ea2296 | 1280 | return -1; |
a9533e7e HP |
1281 | #endif /* BCMSDIO */ |
1282 | ||
1283 | case PCI_BUS: | |
1284 | /* pcie core doesn't have any mapping to control the xtal pu */ | |
1285 | if (PCIE(sii)) | |
1286 | return -1; | |
1287 | ||
57d8cd23 BR |
1288 | pci_read_config_dword(sii->osh->pdev, PCI_GPIO_IN, &in); |
1289 | pci_read_config_dword(sii->osh->pdev, PCI_GPIO_OUT, &out); | |
1290 | pci_read_config_dword(sii->osh->pdev, PCI_GPIO_OUTEN, &outen); | |
a9533e7e HP |
1291 | |
1292 | /* | |
1293 | * Avoid glitching the clock if GPRS is already using it. | |
1294 | * We can't actually read the state of the PLLPD so we infer it | |
1295 | * by the value of XTAL_PU which *is* readable via gpioin. | |
1296 | */ | |
1297 | if (on && (in & PCI_CFG_GPIO_XTAL)) | |
90ea2296 | 1298 | return 0; |
a9533e7e HP |
1299 | |
1300 | if (what & XTAL) | |
1301 | outen |= PCI_CFG_GPIO_XTAL; | |
1302 | if (what & PLL) | |
1303 | outen |= PCI_CFG_GPIO_PLL; | |
1304 | ||
1305 | if (on) { | |
1306 | /* turn primary xtal on */ | |
1307 | if (what & XTAL) { | |
1308 | out |= PCI_CFG_GPIO_XTAL; | |
1309 | if (what & PLL) | |
1310 | out |= PCI_CFG_GPIO_PLL; | |
57d8cd23 BR |
1311 | pci_write_config_dword(sii->osh->pdev, |
1312 | PCI_GPIO_OUT, out); | |
1313 | pci_write_config_dword(sii->osh->pdev, | |
1314 | PCI_GPIO_OUTEN, outen); | |
7383141b | 1315 | udelay(XTAL_ON_DELAY); |
a9533e7e HP |
1316 | } |
1317 | ||
1318 | /* turn pll on */ | |
1319 | if (what & PLL) { | |
1320 | out &= ~PCI_CFG_GPIO_PLL; | |
57d8cd23 BR |
1321 | pci_write_config_dword(sii->osh->pdev, |
1322 | PCI_GPIO_OUT, out); | |
7383141b | 1323 | mdelay(2); |
a9533e7e HP |
1324 | } |
1325 | } else { | |
1326 | if (what & XTAL) | |
1327 | out &= ~PCI_CFG_GPIO_XTAL; | |
1328 | if (what & PLL) | |
1329 | out |= PCI_CFG_GPIO_PLL; | |
57d8cd23 BR |
1330 | pci_write_config_dword(sii->osh->pdev, |
1331 | PCI_GPIO_OUT, out); | |
1332 | pci_write_config_dword(sii->osh->pdev, | |
1333 | PCI_GPIO_OUTEN, outen); | |
a9533e7e HP |
1334 | } |
1335 | ||
1336 | default: | |
90ea2296 | 1337 | return -1; |
a9533e7e HP |
1338 | } |
1339 | ||
90ea2296 | 1340 | return 0; |
a9533e7e HP |
1341 | } |
1342 | ||
1343 | /* | |
1344 | * clock control policy function throught chipcommon | |
1345 | * | |
1346 | * set dynamic clk control mode (forceslow, forcefast, dynamic) | |
1347 | * returns true if we are forcing fast clock | |
1348 | * this is a wrapper over the next internal function | |
1349 | * to allow flexible policy settings for outside caller | |
1350 | */ | |
7cc4a4c0 | 1351 | bool si_clkctl_cc(si_t *sih, uint mode) |
a9533e7e HP |
1352 | { |
1353 | si_info_t *sii; | |
1354 | ||
1355 | sii = SI_INFO(sih); | |
1356 | ||
1357 | /* chipcommon cores prior to rev6 don't support dynamic clock control */ | |
1358 | if (sih->ccrev < 6) | |
0965ae88 | 1359 | return false; |
a9533e7e HP |
1360 | |
1361 | if (PCI_FORCEHT(sii)) | |
90ea2296 | 1362 | return mode == CLK_FAST; |
a9533e7e HP |
1363 | |
1364 | return _si_clkctl_cc(sii, mode); | |
1365 | } | |
1366 | ||
1367 | /* clk control mechanism through chipcommon, no policy checking */ | |
7cc4a4c0 | 1368 | static bool _si_clkctl_cc(si_info_t *sii, uint mode) |
a9533e7e HP |
1369 | { |
1370 | uint origidx = 0; | |
1371 | chipcregs_t *cc; | |
66cbd3ab | 1372 | u32 scc; |
a9533e7e HP |
1373 | uint intr_val = 0; |
1374 | bool fast = SI_FAST(sii); | |
1375 | ||
1376 | /* chipcommon cores prior to rev6 don't support dynamic clock control */ | |
1377 | if (sii->pub.ccrev < 6) | |
0965ae88 | 1378 | return false; |
a9533e7e HP |
1379 | |
1380 | /* Chips with ccrev 10 are EOL and they don't have SYCC_HR which we use below */ | |
1381 | ASSERT(sii->pub.ccrev != 10); | |
1382 | ||
1383 | if (!fast) { | |
1384 | INTR_OFF(sii, intr_val); | |
1385 | origidx = sii->curidx; | |
1386 | ||
1387 | if ((BUSTYPE(sii->pub.bustype) == SI_BUS) && | |
1388 | si_setcore(&sii->pub, MIPS33_CORE_ID, 0) && | |
1389 | (si_corerev(&sii->pub) <= 7) && (sii->pub.ccrev >= 10)) | |
1390 | goto done; | |
1391 | ||
1392 | cc = (chipcregs_t *) si_setcore(&sii->pub, CC_CORE_ID, 0); | |
ca8c1e59 JC |
1393 | } else { |
1394 | cc = (chipcregs_t *) CCREGS_FAST(sii); | |
1395 | if (cc == NULL) | |
1396 | goto done; | |
1397 | } | |
a9533e7e HP |
1398 | ASSERT(cc != NULL); |
1399 | ||
1400 | if (!CCCTL_ENAB(&sii->pub) && (sii->pub.ccrev < 20)) | |
1401 | goto done; | |
1402 | ||
1403 | switch (mode) { | |
1404 | case CLK_FAST: /* FORCEHT, fast (pll) clock */ | |
1405 | if (sii->pub.ccrev < 10) { | |
1406 | /* don't forget to force xtal back on before we clear SCC_DYN_XTAL.. */ | |
1407 | si_clkctl_xtal(&sii->pub, XTAL, ON); | |
1408 | SET_REG(sii->osh, &cc->slow_clk_ctl, | |
1409 | (SCC_XC | SCC_FS | SCC_IP), SCC_IP); | |
1410 | } else if (sii->pub.ccrev < 20) { | |
1411 | OR_REG(sii->osh, &cc->system_clk_ctl, SYCC_HR); | |
1412 | } else { | |
1413 | OR_REG(sii->osh, &cc->clk_ctl_st, CCS_FORCEHT); | |
1414 | } | |
1415 | ||
1416 | /* wait for the PLL */ | |
1417 | if (PMUCTL_ENAB(&sii->pub)) { | |
66cbd3ab | 1418 | u32 htavail = CCS_HTAVAIL; |
a9533e7e HP |
1419 | SPINWAIT(((R_REG(sii->osh, &cc->clk_ctl_st) & htavail) |
1420 | == 0), PMU_MAX_TRANSITION_DLY); | |
1421 | ASSERT(R_REG(sii->osh, &cc->clk_ctl_st) & htavail); | |
1422 | } else { | |
7383141b | 1423 | udelay(PLL_DELAY); |
a9533e7e HP |
1424 | } |
1425 | break; | |
1426 | ||
1427 | case CLK_DYNAMIC: /* enable dynamic clock control */ | |
1428 | if (sii->pub.ccrev < 10) { | |
1429 | scc = R_REG(sii->osh, &cc->slow_clk_ctl); | |
1430 | scc &= ~(SCC_FS | SCC_IP | SCC_XC); | |
1431 | if ((scc & SCC_SS_MASK) != SCC_SS_XTAL) | |
1432 | scc |= SCC_XC; | |
1433 | W_REG(sii->osh, &cc->slow_clk_ctl, scc); | |
1434 | ||
1435 | /* for dynamic control, we have to release our xtal_pu "force on" */ | |
1436 | if (scc & SCC_XC) | |
1437 | si_clkctl_xtal(&sii->pub, XTAL, OFF); | |
1438 | } else if (sii->pub.ccrev < 20) { | |
1439 | /* Instaclock */ | |
1440 | AND_REG(sii->osh, &cc->system_clk_ctl, ~SYCC_HR); | |
1441 | } else { | |
1442 | AND_REG(sii->osh, &cc->clk_ctl_st, ~CCS_FORCEHT); | |
1443 | } | |
1444 | break; | |
1445 | ||
1446 | default: | |
1447 | ASSERT(0); | |
1448 | } | |
1449 | ||
1450 | done: | |
1451 | if (!fast) { | |
1452 | si_setcoreidx(&sii->pub, origidx); | |
1453 | INTR_RESTORE(sii, intr_val); | |
1454 | } | |
90ea2296 | 1455 | return mode == CLK_FAST; |
a9533e7e HP |
1456 | } |
1457 | ||
1458 | /* Build device path. Support SI, PCI, and JTAG for now. */ | |
0d2f0724 | 1459 | int si_devpath(si_t *sih, char *path, int size) |
a2627bc0 | 1460 | { |
a9533e7e HP |
1461 | int slen; |
1462 | ||
1463 | ASSERT(path != NULL); | |
1464 | ASSERT(size >= SI_DEVPATH_BUFSZ); | |
1465 | ||
1466 | if (!path || size <= 0) | |
1467 | return -1; | |
1468 | ||
1469 | switch (BUSTYPE(sih->bustype)) { | |
1470 | case SI_BUS: | |
1471 | case JTAG_BUS: | |
1472 | slen = snprintf(path, (size_t) size, "sb/%u/", si_coreidx(sih)); | |
1473 | break; | |
1474 | case PCI_BUS: | |
1475 | ASSERT((SI_INFO(sih))->osh != NULL); | |
1476 | slen = snprintf(path, (size_t) size, "pci/%u/%u/", | |
1477 | OSL_PCI_BUS((SI_INFO(sih))->osh), | |
1478 | OSL_PCI_SLOT((SI_INFO(sih))->osh)); | |
1479 | break; | |
1480 | ||
1481 | #ifdef BCMSDIO | |
1482 | case SDIO_BUS: | |
1483 | SI_ERROR(("si_devpath: device 0 assumed\n")); | |
1484 | slen = snprintf(path, (size_t) size, "sd/%u/", si_coreidx(sih)); | |
1485 | break; | |
1486 | #endif | |
1487 | default: | |
1488 | slen = -1; | |
1489 | ASSERT(0); | |
1490 | break; | |
1491 | } | |
1492 | ||
1493 | if (slen < 0 || slen >= size) { | |
1494 | path[0] = '\0'; | |
1495 | return -1; | |
1496 | } | |
1497 | ||
1498 | return 0; | |
1499 | } | |
1500 | ||
1501 | /* Get a variable, but only if it has a devpath prefix */ | |
0d2f0724 | 1502 | char *si_getdevpathvar(si_t *sih, const char *name) |
a2627bc0 | 1503 | { |
a9533e7e HP |
1504 | char varname[SI_DEVPATH_BUFSZ + 32]; |
1505 | ||
1506 | si_devpathvar(sih, varname, sizeof(varname), name); | |
1507 | ||
90ea2296 | 1508 | return getvar(NULL, varname); |
a9533e7e HP |
1509 | } |
1510 | ||
1511 | /* Get a variable, but only if it has a devpath prefix */ | |
0d2f0724 | 1512 | int si_getdevpathintvar(si_t *sih, const char *name) |
a2627bc0 | 1513 | { |
a9533e7e | 1514 | #if defined(BCMBUSTYPE) && (BCMBUSTYPE == SI_BUS) |
90ea2296 | 1515 | return getintvar(NULL, name); |
a9533e7e HP |
1516 | #else |
1517 | char varname[SI_DEVPATH_BUFSZ + 32]; | |
1518 | ||
1519 | si_devpathvar(sih, varname, sizeof(varname), name); | |
1520 | ||
90ea2296 | 1521 | return getintvar(NULL, varname); |
a9533e7e HP |
1522 | #endif |
1523 | } | |
1524 | ||
7cc4a4c0 | 1525 | char *si_getnvramflvar(si_t *sih, const char *name) |
a9533e7e | 1526 | { |
90ea2296 | 1527 | return getvar(NULL, name); |
a9533e7e HP |
1528 | } |
1529 | ||
1530 | /* Concatenate the dev path with a varname into the given 'var' buffer | |
1531 | * and return the 'var' pointer. | |
1532 | * Nothing is done to the arguments if len == 0 or var is NULL, var is still returned. | |
1533 | * On overflow, the first char will be set to '\0'. | |
1534 | */ | |
0d2f0724 GKH |
1535 | static char *si_devpathvar(si_t *sih, char *var, int len, const char *name) |
1536 | { | |
a9533e7e HP |
1537 | uint path_len; |
1538 | ||
1539 | if (!var || len <= 0) | |
1540 | return var; | |
1541 | ||
1542 | if (si_devpath(sih, var, len) == 0) { | |
1543 | path_len = strlen(var); | |
1544 | ||
1545 | if (strlen(name) + 1 > (uint) (len - path_len)) | |
1546 | var[0] = '\0'; | |
1547 | else | |
1548 | strncpy(var + path_len, name, len - path_len - 1); | |
1549 | } | |
1550 | ||
1551 | return var; | |
1552 | } | |
1553 | ||
0f0881b0 | 1554 | /* return true if PCIE capability exists in the pci config space */ |
84b9fac2 | 1555 | static __used bool si_ispcie(si_info_t *sii) |
a9533e7e | 1556 | { |
36ef9a1e | 1557 | u8 cap_ptr; |
a9533e7e HP |
1558 | |
1559 | if (BUSTYPE(sii->pub.bustype) != PCI_BUS) | |
0965ae88 | 1560 | return false; |
a9533e7e HP |
1561 | |
1562 | cap_ptr = | |
1563 | pcicore_find_pci_capability(sii->osh, PCI_CAP_PCIECAP_ID, NULL, | |
1564 | NULL); | |
1565 | if (!cap_ptr) | |
0965ae88 | 1566 | return false; |
a9533e7e | 1567 | |
0f0881b0 | 1568 | return true; |
a9533e7e HP |
1569 | } |
1570 | ||
a9533e7e HP |
1571 | #ifdef BCMSDIO |
1572 | /* initialize the sdio core */ | |
7cc4a4c0 | 1573 | void si_sdio_init(si_t *sih) |
a9533e7e HP |
1574 | { |
1575 | si_info_t *sii = SI_INFO(sih); | |
1576 | ||
1577 | if (((sih->buscoretype == PCMCIA_CORE_ID) && (sih->buscorerev >= 8)) || | |
1578 | (sih->buscoretype == SDIOD_CORE_ID)) { | |
1579 | uint idx; | |
1580 | sdpcmd_regs_t *sdpregs; | |
1581 | ||
1582 | /* get the current core index */ | |
1583 | idx = sii->curidx; | |
1584 | ASSERT(idx == si_findcoreidx(sih, D11_CORE_ID, 0)); | |
1585 | ||
1586 | /* switch to sdio core */ | |
ca8c1e59 JC |
1587 | sdpregs = (sdpcmd_regs_t *) si_setcore(sih, PCMCIA_CORE_ID, 0); |
1588 | if (!sdpregs) | |
a9533e7e HP |
1589 | sdpregs = |
1590 | (sdpcmd_regs_t *) si_setcore(sih, SDIOD_CORE_ID, 0); | |
1591 | ASSERT(sdpregs); | |
1592 | ||
1593 | SI_MSG(("si_sdio_init: For PCMCIA/SDIO Corerev %d, enable ints from core %d " "through SD core %d (%p)\n", sih->buscorerev, idx, sii->curidx, sdpregs)); | |
1594 | ||
1595 | /* enable backplane error and core interrupts */ | |
1596 | W_REG(sii->osh, &sdpregs->hostintmask, I_SBINT); | |
1597 | W_REG(sii->osh, &sdpregs->sbintmask, | |
1598 | (I_SB_SERR | I_SB_RESPERR | (1 << idx))); | |
1599 | ||
1600 | /* switch back to previous core */ | |
1601 | si_setcoreidx(sih, idx); | |
1602 | } | |
1603 | ||
1604 | /* enable interrupts */ | |
1605 | bcmsdh_intr_enable(sii->sdh); | |
1606 | ||
1607 | } | |
1608 | #endif /* BCMSDIO */ | |
1609 | ||
0d2f0724 | 1610 | bool si_pci_war16165(si_t *sih) |
a2627bc0 | 1611 | { |
a9533e7e HP |
1612 | si_info_t *sii; |
1613 | ||
1614 | sii = SI_INFO(sih); | |
1615 | ||
90ea2296 | 1616 | return PCI(sii) && (sih->buscorerev <= 10); |
a9533e7e HP |
1617 | } |
1618 | ||
b4f790ee | 1619 | void si_pci_up(si_t *sih) |
a2627bc0 | 1620 | { |
a9533e7e HP |
1621 | si_info_t *sii; |
1622 | ||
1623 | sii = SI_INFO(sih); | |
1624 | ||
1625 | /* if not pci bus, we're done */ | |
1626 | if (BUSTYPE(sih->bustype) != PCI_BUS) | |
1627 | return; | |
1628 | ||
1629 | if (PCI_FORCEHT(sii)) | |
1630 | _si_clkctl_cc(sii, CLK_FAST); | |
1631 | ||
1632 | if (PCIE(sii)) | |
1633 | pcicore_up(sii->pch, SI_PCIUP); | |
1634 | ||
1635 | } | |
1636 | ||
1637 | /* Unconfigure and/or apply various WARs when system is going to sleep mode */ | |
9927fc2e | 1638 | void si_pci_sleep(si_t *sih) |
a2627bc0 | 1639 | { |
a9533e7e HP |
1640 | si_info_t *sii; |
1641 | ||
1642 | sii = SI_INFO(sih); | |
1643 | ||
1644 | pcicore_sleep(sii->pch); | |
1645 | } | |
1646 | ||
1647 | /* Unconfigure and/or apply various WARs when going down */ | |
b4f790ee | 1648 | void si_pci_down(si_t *sih) |
a2627bc0 | 1649 | { |
a9533e7e HP |
1650 | si_info_t *sii; |
1651 | ||
1652 | sii = SI_INFO(sih); | |
1653 | ||
1654 | /* if not pci bus, we're done */ | |
1655 | if (BUSTYPE(sih->bustype) != PCI_BUS) | |
1656 | return; | |
1657 | ||
1658 | /* release FORCEHT since chip is going to "down" state */ | |
1659 | if (PCI_FORCEHT(sii)) | |
1660 | _si_clkctl_cc(sii, CLK_DYNAMIC); | |
1661 | ||
1662 | pcicore_down(sii->pch, SI_PCIDOWN); | |
1663 | } | |
1664 | ||
1665 | /* | |
1666 | * Configure the pci core for pci client (NIC) action | |
1667 | * coremask is the bitvec of cores by index to be enabled. | |
1668 | */ | |
0d2f0724 | 1669 | void si_pci_setup(si_t *sih, uint coremask) |
a2627bc0 | 1670 | { |
a9533e7e | 1671 | si_info_t *sii; |
c11b0ef8 | 1672 | struct sbpciregs *pciregs = NULL; |
66cbd3ab | 1673 | u32 siflag = 0, w; |
a9533e7e HP |
1674 | uint idx = 0; |
1675 | ||
1676 | sii = SI_INFO(sih); | |
1677 | ||
1678 | if (BUSTYPE(sii->pub.bustype) != PCI_BUS) | |
1679 | return; | |
1680 | ||
1681 | ASSERT(PCI(sii) || PCIE(sii)); | |
1682 | ASSERT(sii->pub.buscoreidx != BADIDX); | |
1683 | ||
1684 | if (PCI(sii)) { | |
1685 | /* get current core index */ | |
1686 | idx = sii->curidx; | |
1687 | ||
1688 | /* we interrupt on this backplane flag number */ | |
1689 | siflag = si_flag(sih); | |
1690 | ||
1691 | /* switch over to pci core */ | |
c11b0ef8 | 1692 | pciregs = (struct sbpciregs *)si_setcoreidx(sih, sii->pub.buscoreidx); |
a9533e7e HP |
1693 | } |
1694 | ||
1695 | /* | |
1696 | * Enable sb->pci interrupts. Assume | |
1697 | * PCI rev 2.3 support was added in pci core rev 6 and things changed.. | |
1698 | */ | |
1699 | if (PCIE(sii) || (PCI(sii) && ((sii->pub.buscorerev) >= 6))) { | |
1700 | /* pci config write to set this core bit in PCIIntMask */ | |
57d8cd23 | 1701 | pci_read_config_dword(sii->osh->pdev, PCI_INT_MASK, &w); |
a9533e7e | 1702 | w |= (coremask << PCI_SBIM_SHIFT); |
57d8cd23 | 1703 | pci_write_config_dword(sii->osh->pdev, PCI_INT_MASK, w); |
a9533e7e HP |
1704 | } else { |
1705 | /* set sbintvec bit for our flag number */ | |
1706 | si_setint(sih, siflag); | |
1707 | } | |
1708 | ||
1709 | if (PCI(sii)) { | |
1710 | OR_REG(sii->osh, &pciregs->sbtopci2, | |
1711 | (SBTOPCI_PREF | SBTOPCI_BURST)); | |
1712 | if (sii->pub.buscorerev >= 11) { | |
1713 | OR_REG(sii->osh, &pciregs->sbtopci2, | |
1714 | SBTOPCI_RC_READMULTI); | |
1715 | w = R_REG(sii->osh, &pciregs->clkrun); | |
1716 | W_REG(sii->osh, &pciregs->clkrun, | |
1717 | (w | PCI_CLKRUN_DSBL)); | |
1718 | w = R_REG(sii->osh, &pciregs->clkrun); | |
1719 | } | |
1720 | ||
1721 | /* switch back to previous core */ | |
1722 | si_setcoreidx(sih, idx); | |
1723 | } | |
1724 | } | |
1725 | ||
a9533e7e HP |
1726 | /* |
1727 | * Fixup SROMless PCI device's configuration. | |
1728 | * The current core may be changed upon return. | |
1729 | */ | |
7cc4a4c0 | 1730 | int si_pci_fixcfg(si_t *sih) |
a9533e7e HP |
1731 | { |
1732 | uint origidx, pciidx; | |
c11b0ef8 | 1733 | struct sbpciregs *pciregs = NULL; |
a9533e7e HP |
1734 | sbpcieregs_t *pcieregs = NULL; |
1735 | void *regs = NULL; | |
7d4df48e | 1736 | u16 val16, *reg16 = NULL; |
a9533e7e HP |
1737 | |
1738 | si_info_t *sii = SI_INFO(sih); | |
1739 | ||
1740 | ASSERT(BUSTYPE(sii->pub.bustype) == PCI_BUS); | |
1741 | ||
1742 | /* Fixup PI in SROM shadow area to enable the correct PCI core access */ | |
1743 | /* save the current index */ | |
1744 | origidx = si_coreidx(&sii->pub); | |
1745 | ||
1746 | /* check 'pi' is correct and fix it if not */ | |
1747 | if (sii->pub.buscoretype == PCIE_CORE_ID) { | |
1748 | pcieregs = | |
1749 | (sbpcieregs_t *) si_setcore(&sii->pub, PCIE_CORE_ID, 0); | |
1750 | regs = pcieregs; | |
1751 | ASSERT(pcieregs != NULL); | |
1752 | reg16 = &pcieregs->sprom[SRSH_PI_OFFSET]; | |
1753 | } else if (sii->pub.buscoretype == PCI_CORE_ID) { | |
c11b0ef8 | 1754 | pciregs = (struct sbpciregs *)si_setcore(&sii->pub, PCI_CORE_ID, 0); |
a9533e7e HP |
1755 | regs = pciregs; |
1756 | ASSERT(pciregs != NULL); | |
1757 | reg16 = &pciregs->sprom[SRSH_PI_OFFSET]; | |
1758 | } | |
1759 | pciidx = si_coreidx(&sii->pub); | |
1760 | val16 = R_REG(sii->osh, reg16); | |
7d4df48e | 1761 | if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) != (u16) pciidx) { |
a9533e7e | 1762 | val16 = |
7d4df48e | 1763 | (u16) (pciidx << SRSH_PI_SHIFT) | (val16 & |
a9533e7e HP |
1764 | ~SRSH_PI_MASK); |
1765 | W_REG(sii->osh, reg16, val16); | |
1766 | } | |
1767 | ||
1768 | /* restore the original index */ | |
1769 | si_setcoreidx(&sii->pub, origidx); | |
1770 | ||
1771 | pcicore_hwup(sii->pch); | |
1772 | return 0; | |
1773 | } | |
1774 | ||
a9533e7e | 1775 | /* mask&set gpiocontrol bits */ |
66cbd3ab | 1776 | u32 si_gpiocontrol(si_t *sih, u32 mask, u32 val, u8 priority) |
a9533e7e HP |
1777 | { |
1778 | uint regoff; | |
1779 | ||
1780 | regoff = 0; | |
1781 | ||
1782 | /* gpios could be shared on router platforms | |
1783 | * ignore reservation if it's high priority (e.g., test apps) | |
1784 | */ | |
1785 | if ((priority != GPIO_HI_PRIORITY) && | |
1786 | (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) { | |
1787 | mask = priority ? (si_gpioreservation & mask) : | |
1788 | ((si_gpioreservation | mask) & ~(si_gpioreservation)); | |
1789 | val &= mask; | |
1790 | } | |
1791 | ||
ce0f1b8c | 1792 | regoff = offsetof(chipcregs_t, gpiocontrol); |
90ea2296 | 1793 | return si_corereg(sih, SI_CC_IDX, regoff, mask, val); |
a9533e7e HP |
1794 | } |
1795 | ||
1e3950b8 HP |
1796 | /* Return the size of the specified SOCRAM bank */ |
1797 | static uint | |
1798 | socram_banksize(si_info_t *sii, sbsocramregs_t *regs, u8 index, | |
1799 | u8 mem_type) | |
a9533e7e | 1800 | { |
1e3950b8 HP |
1801 | uint banksize, bankinfo; |
1802 | uint bankidx = index | (mem_type << SOCRAM_BANKIDX_MEMTYPE_SHIFT); | |
a9533e7e | 1803 | |
1e3950b8 | 1804 | ASSERT(mem_type <= SOCRAM_MEMTYPE_DEVRAM); |
a9533e7e HP |
1805 | |
1806 | W_REG(sii->osh, ®s->bankidx, bankidx); | |
1807 | bankinfo = R_REG(sii->osh, ®s->bankinfo); | |
1808 | banksize = | |
1809 | SOCRAM_BANKINFO_SZBASE * ((bankinfo & SOCRAM_BANKINFO_SZMASK) + 1); | |
1810 | return banksize; | |
1811 | } | |
1812 | ||
a9533e7e | 1813 | /* Return the RAM size of the SOCRAM core */ |
66cbd3ab | 1814 | u32 si_socram_size(si_t *sih) |
a9533e7e HP |
1815 | { |
1816 | si_info_t *sii; | |
1817 | uint origidx; | |
1818 | uint intr_val = 0; | |
1819 | ||
1820 | sbsocramregs_t *regs; | |
1821 | bool wasup; | |
1822 | uint corerev; | |
66cbd3ab | 1823 | u32 coreinfo; |
a9533e7e HP |
1824 | uint memsize = 0; |
1825 | ||
1826 | sii = SI_INFO(sih); | |
1827 | ||
1828 | /* Block ints and save current core */ | |
1829 | INTR_OFF(sii, intr_val); | |
1830 | origidx = si_coreidx(sih); | |
1831 | ||
1832 | /* Switch to SOCRAM core */ | |
ca8c1e59 JC |
1833 | regs = si_setcore(sih, SOCRAM_CORE_ID, 0); |
1834 | if (!regs) | |
a9533e7e HP |
1835 | goto done; |
1836 | ||
1837 | /* Get info for determining size */ | |
ca8c1e59 JC |
1838 | wasup = si_iscoreup(sih); |
1839 | if (!wasup) | |
a9533e7e HP |
1840 | si_core_reset(sih, 0, 0); |
1841 | corerev = si_corerev(sih); | |
1842 | coreinfo = R_REG(sii->osh, ®s->coreinfo); | |
1843 | ||
1844 | /* Calculate size from coreinfo based on rev */ | |
1845 | if (corerev == 0) | |
1846 | memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK)); | |
1847 | else if (corerev < 3) { | |
1848 | memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK)); | |
1849 | memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; | |
1850 | } else if ((corerev <= 7) || (corerev == 12)) { | |
1851 | uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; | |
1852 | uint bsz = (coreinfo & SRCI_SRBSZ_MASK); | |
1853 | uint lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT; | |
1854 | if (lss != 0) | |
1855 | nb--; | |
1856 | memsize = nb * (1 << (bsz + SR_BSZ_BASE)); | |
1857 | if (lss != 0) | |
1858 | memsize += (1 << ((lss - 1) + SR_BSZ_BASE)); | |
1859 | } else { | |
36ef9a1e | 1860 | u8 i; |
a9533e7e HP |
1861 | uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT; |
1862 | for (i = 0; i < nb; i++) | |
1863 | memsize += | |
1864 | socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM); | |
1865 | } | |
1866 | ||
1867 | /* Return to previous state and core */ | |
1868 | if (!wasup) | |
1869 | si_core_disable(sih, 0); | |
1870 | si_setcoreidx(sih, origidx); | |
1871 | ||
1872 | done: | |
1873 | INTR_RESTORE(sii, intr_val); | |
1874 | ||
1875 | return memsize; | |
1876 | } | |
1877 | ||
7cc4a4c0 | 1878 | void si_chipcontrl_epa4331(si_t *sih, bool on) |
a9533e7e HP |
1879 | { |
1880 | si_info_t *sii; | |
1881 | chipcregs_t *cc; | |
1882 | uint origidx; | |
66cbd3ab | 1883 | u32 val; |
a9533e7e HP |
1884 | |
1885 | sii = SI_INFO(sih); | |
1886 | origidx = si_coreidx(sih); | |
1887 | ||
1888 | cc = (chipcregs_t *) si_setcore(sih, CC_CORE_ID, 0); | |
1889 | ||
1890 | val = R_REG(sii->osh, &cc->chipcontrol); | |
1891 | ||
1892 | if (on) { | |
1893 | if (sih->chippkg == 9 || sih->chippkg == 0xb) { | |
1894 | /* Ext PA Controls for 4331 12x9 Package */ | |
1895 | W_REG(sii->osh, &cc->chipcontrol, val | | |
1896 | (CCTRL4331_EXTPA_EN | | |
1897 | CCTRL4331_EXTPA_ON_GPIO2_5)); | |
1898 | } else { | |
1899 | /* Ext PA Controls for 4331 12x12 Package */ | |
1900 | W_REG(sii->osh, &cc->chipcontrol, | |
1901 | val | (CCTRL4331_EXTPA_EN)); | |
1902 | } | |
1903 | } else { | |
1904 | val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); | |
1905 | W_REG(sii->osh, &cc->chipcontrol, val); | |
1906 | } | |
1907 | ||
1908 | si_setcoreidx(sih, origidx); | |
1909 | } | |
1910 | ||
1911 | /* Enable BT-COEX & Ex-PA for 4313 */ | |
7cc4a4c0 | 1912 | void si_epa_4313war(si_t *sih) |
a9533e7e HP |
1913 | { |
1914 | si_info_t *sii; | |
1915 | chipcregs_t *cc; | |
1916 | uint origidx; | |
1917 | ||
1918 | sii = SI_INFO(sih); | |
1919 | origidx = si_coreidx(sih); | |
1920 | ||
1921 | cc = (chipcregs_t *) si_setcore(sih, CC_CORE_ID, 0); | |
1922 | ||
1923 | /* EPA Fix */ | |
1924 | W_REG(sii->osh, &cc->gpiocontrol, | |
1925 | R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_EPA_EN_MASK); | |
1926 | ||
1927 | si_setcoreidx(sih, origidx); | |
1928 | } | |
1929 | ||
1930 | /* check if the device is removed */ | |
7cc4a4c0 | 1931 | bool si_deviceremoved(si_t *sih) |
a9533e7e | 1932 | { |
66cbd3ab | 1933 | u32 w; |
a9533e7e HP |
1934 | si_info_t *sii; |
1935 | ||
1936 | sii = SI_INFO(sih); | |
1937 | ||
1938 | switch (BUSTYPE(sih->bustype)) { | |
1939 | case PCI_BUS: | |
1940 | ASSERT(sii->osh != NULL); | |
57d8cd23 | 1941 | pci_read_config_dword(sii->osh->pdev, PCI_CFG_VID, &w); |
a9533e7e | 1942 | if ((w & 0xFFFF) != VENDOR_BROADCOM) |
0f0881b0 | 1943 | return true; |
a9533e7e HP |
1944 | break; |
1945 | } | |
0965ae88 | 1946 | return false; |
a9533e7e HP |
1947 | } |
1948 | ||
7cc4a4c0 | 1949 | bool si_is_sprom_available(si_t *sih) |
a9533e7e HP |
1950 | { |
1951 | if (sih->ccrev >= 31) { | |
1952 | si_info_t *sii; | |
1953 | uint origidx; | |
1954 | chipcregs_t *cc; | |
66cbd3ab | 1955 | u32 sromctrl; |
a9533e7e HP |
1956 | |
1957 | if ((sih->cccaps & CC_CAP_SROM) == 0) | |
0965ae88 | 1958 | return false; |
a9533e7e HP |
1959 | |
1960 | sii = SI_INFO(sih); | |
1961 | origidx = sii->curidx; | |
1962 | cc = si_setcoreidx(sih, SI_CC_IDX); | |
1963 | sromctrl = R_REG(sii->osh, &cc->sromcontrol); | |
1964 | si_setcoreidx(sih, origidx); | |
90ea2296 | 1965 | return sromctrl & SRC_PRESENT; |
a9533e7e HP |
1966 | } |
1967 | ||
1968 | switch (CHIPID(sih->chip)) { | |
1969 | case BCM4329_CHIP_ID: | |
1970 | return (sih->chipst & CST4329_SPROM_SEL) != 0; | |
1971 | case BCM4319_CHIP_ID: | |
1972 | return (sih->chipst & CST4319_SPROM_SEL) != 0; | |
1973 | case BCM4336_CHIP_ID: | |
1974 | return (sih->chipst & CST4336_SPROM_PRESENT) != 0; | |
1975 | case BCM4330_CHIP_ID: | |
1976 | return (sih->chipst & CST4330_SPROM_PRESENT) != 0; | |
1977 | case BCM4313_CHIP_ID: | |
1978 | return (sih->chipst & CST4313_SPROM_PRESENT) != 0; | |
1979 | case BCM4331_CHIP_ID: | |
1980 | return (sih->chipst & CST4331_SPROM_PRESENT) != 0; | |
1981 | default: | |
0f0881b0 | 1982 | return true; |
a9533e7e HP |
1983 | } |
1984 | } | |
1985 | ||
7cc4a4c0 | 1986 | bool si_is_otp_disabled(si_t *sih) |
a9533e7e HP |
1987 | { |
1988 | switch (CHIPID(sih->chip)) { | |
1989 | case BCM4329_CHIP_ID: | |
1990 | return (sih->chipst & CST4329_SPROM_OTP_SEL_MASK) == | |
1991 | CST4329_OTP_PWRDN; | |
1992 | case BCM4319_CHIP_ID: | |
1993 | return (sih->chipst & CST4319_SPROM_OTP_SEL_MASK) == | |
1994 | CST4319_OTP_PWRDN; | |
1995 | case BCM4336_CHIP_ID: | |
90ea2296 | 1996 | return (sih->chipst & CST4336_OTP_PRESENT) == 0; |
a9533e7e | 1997 | case BCM4330_CHIP_ID: |
90ea2296 | 1998 | return (sih->chipst & CST4330_OTP_PRESENT) == 0; |
a9533e7e HP |
1999 | case BCM4313_CHIP_ID: |
2000 | return (sih->chipst & CST4313_OTP_PRESENT) == 0; | |
2001 | /* These chips always have their OTP on */ | |
2002 | case BCM43224_CHIP_ID: | |
2003 | case BCM43225_CHIP_ID: | |
2004 | case BCM43421_CHIP_ID: | |
2005 | case BCM43235_CHIP_ID: | |
2006 | case BCM43236_CHIP_ID: | |
2007 | case BCM43238_CHIP_ID: | |
2008 | case BCM4331_CHIP_ID: | |
2009 | default: | |
0965ae88 | 2010 | return false; |
a9533e7e HP |
2011 | } |
2012 | } | |
2013 | ||
7cc4a4c0 | 2014 | bool si_is_otp_powered(si_t *sih) |
a9533e7e HP |
2015 | { |
2016 | if (PMUCTL_ENAB(sih)) | |
2017 | return si_pmu_is_otp_powered(sih, si_osh(sih)); | |
0f0881b0 | 2018 | return true; |
a9533e7e HP |
2019 | } |
2020 | ||
7cc4a4c0 | 2021 | void si_otp_power(si_t *sih, bool on) |
a9533e7e HP |
2022 | { |
2023 | if (PMUCTL_ENAB(sih)) | |
2024 | si_pmu_otp_power(sih, si_osh(sih), on); | |
7383141b | 2025 | udelay(1000); |
a9533e7e HP |
2026 | } |
2027 |