staging: brcm80211: Remove unneeded definitions and structures.
[deliverable/linux.git] / drivers / staging / brcm80211 / util / siutils.c
CommitLineData
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
17#include <typedefs.h>
18#include <bcmdefs.h>
19#include <osl.h>
20#include <bcmutils.h>
21#include <siutils.h>
22#include <bcmdevs.h>
23#include <hndsoc.h>
24#include <sbchipc.h>
25#include <pci_core.h>
26#include <pcie_core.h>
27#include <nicpci.h>
28#include <bcmnvram.h>
29#include <bcmsrom.h>
30#include <hndtcam.h>
31#include <pcicfg.h>
32#include <sbsocram.h>
33#ifdef BCMSDIO
34#include <bcmsdh.h>
35#include <sdio.h>
36#include <sbsdio.h>
37#include <sbhnddma.h>
38#include <sbsdpcmdev.h>
39#include <bcmsdpcm.h>
40#endif /* BCMSDIO */
41#include <hndpmu.h>
42
43/* this file now contains only definitions for sb functions, only necessary
44*for devices using Sonics backplanes (bcm4329)
45*/
46
47/* if an amba SDIO device is supported, please further restrict the inclusion
48 * of this file
49 */
50#ifdef BCMSDIO
51#include "siutils_priv.h"
52#endif
53
54/* local prototypes */
7cc4a4c0 55static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh,
a9533e7e 56 void *regs, uint bustype, void *sdh, char **vars,
7cc4a4c0
JC
57 uint *varsz);
58static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid,
a9533e7e 59 void *sdh);
7cc4a4c0
JC
60static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype,
61 uint32 savewin, uint *origidx, void *regs);
62static void si_nvram_process(si_info_t *sii, char *pvars);
a9533e7e
HP
63
64/* dev path concatenation util */
7cc4a4c0
JC
65static char *si_devpathvar(si_t *sih, char *var, int len, const char *name);
66static bool _si_clkctl_cc(si_info_t *sii, uint mode);
67static bool si_ispcie(si_info_t *sii);
68static uint BCMINITFN(socram_banksize) (si_info_t *sii, sbsocramregs_t *r,
a9533e7e
HP
69 uint8 idx, uint8 mtype);
70
71/* global variable to indicate reservation/release of gpio's */
7e85c729 72static uint32 si_gpioreservation;
a9533e7e
HP
73
74/* global flag to prevent shared resources from being initialized multiple times in si_attach() */
75
76/*
77 * Allocate a si handle.
78 * devid - pci device id (used to determine chip#)
79 * osh - opaque OS handle
80 * regs - virtual address of initial core registers
81 * bustype - pci/sb/sdio/etc
82 * vars - pointer to a pointer area for "environment" variables
83 * varsz - pointer to int to return the size of the vars
84 */
7cc4a4c0 85si_t *BCMATTACHFN(si_attach) (uint devid, osl_t *osh, void *regs,
a9533e7e 86 uint bustype, void *sdh, char **vars,
7cc4a4c0 87 uint *varsz) {
a9533e7e
HP
88 si_info_t *sii;
89
90 /* alloc si_info_t */
ca8c1e59
JC
91 sii = MALLOC(osh, sizeof(si_info_t));
92 if (sii == NULL) {
a9533e7e
HP
93 SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n",
94 MALLOCED(osh)));
90ea2296 95 return NULL;
a9533e7e
HP
96 }
97
98 if (si_doattach(sii, devid, osh, regs, bustype, sdh, vars, varsz) ==
99 NULL) {
100 MFREE(osh, sii, sizeof(si_info_t));
90ea2296 101 return NULL;
a9533e7e
HP
102 }
103 sii->vars = vars ? *vars : NULL;
104 sii->varsz = varsz ? *varsz : 0;
105
106 return (si_t *) sii;
107}
108
109/* global kernel resource */
110static si_info_t ksii;
111
112static uint32 wd_msticks; /* watchdog timer ticks normalized to ms */
113
114static bool
7cc4a4c0 115BCMATTACHFN(si_buscore_prep) (si_info_t *sii, uint bustype, uint devid,
a9533e7e
HP
116 void *sdh) {
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;
127 uint8 clkset;
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) {
134 uint8 clkval;
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));
149 return FALSE;
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);
157 OSL_DELAY(65);
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
167 return TRUE;
168}
169
170static bool
7cc4a4c0
JC
171BCMATTACHFN(si_buscore_setup) (si_info_t *sii, chipcregs_t *cc, uint bustype,
172 uint32 savewin, uint *origidx, void *regs) {
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);
178 ASSERT((uintptr) cc);
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
212 pci = pcie = FALSE;
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;
231 pci = TRUE;
232 } else if (cid == PCIE_CORE_ID) {
233 pcieidx = i;
234 pcierev = crev;
235 pcie = TRUE;
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))
270 pci = FALSE;
271 else
272 pcie = FALSE;
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
JC
290 if (!sii->pch) {
291 sii->pch = (void *)(uintptr)pcicore_init(
292 &sii->pub, sii->osh,
293 (void *)PCIEREGS(sii));
294 if (sii->pch == NULL)
295 return FALSE;
296 }
a9533e7e
HP
297 }
298 if (si_pci_fixcfg(&sii->pub)) {
299 SI_ERROR(("si_doattach: sb_pci_fixcfg failed\n"));
300 return FALSE;
301 }
302 }
cf2b4488 303#endif
a9533e7e
HP
304 /* return to the original core */
305 si_setcoreidx(&sii->pub, *origidx);
306
307 return TRUE;
308}
309
84b9fac2 310static __used void BCMATTACHFN(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 */
318 w = OSL_PCI_READ_CONFIG(sii->osh, PCI_CFG_SVID, sizeof(uint32));
319 /* Let nvram variables override subsystem Vend/ID */
ca8c1e59
JC
320 sii->pub.boardvendor = (uint16)si_getdevpathintvar(&sii->pub,
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));
ca8c1e59
JC
326 sii->pub.boardtype = (uint16)si_getdevpathintvar(&sii->pub,
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
7cc4a4c0
JC
371static si_info_t *BCMATTACHFN(si_doattach) (si_info_t *sii, uint devid,
372 osl_t *osh, void *regs,
a9533e7e 373 uint bustype, void *sdh,
7cc4a4c0 374 char **vars, uint *varsz) {
a9533e7e
HP
375 struct si_pub *sih = &sii->pub;
376 uint32 w, savewin;
377 chipcregs_t *cc;
378 char *pvars = NULL;
379 uint origidx;
380
381 ASSERT(GOODREGS(regs));
382
383 bzero((uchar *) sii, sizeof(si_info_t));
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)) {
475 uint32 xtalfreq;
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
HP
490 w = DEFAULT_GPIOTIMERVAL;
491 sb_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiotimerval), ~0, w);
492
493#ifdef BCMDBG
494 /* clear any previous epidiag-induced target abort */
495 sb_taclear(sih, FALSE);
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 */
7cc4a4c0
JC
506static si_info_t *BCMATTACHFN(si_doattach) (si_info_t *sii, uint devid,
507 osl_t *osh, void *regs,
a9533e7e 508 uint bustype, void *sdh,
7cc4a4c0 509 char **vars, uint *varsz) {
a9533e7e
HP
510 struct si_pub *sih = &sii->pub;
511 uint32 w, savewin;
512 chipcregs_t *cc;
513 char *pvars = NULL;
514 uint origidx;
515
516 ASSERT(GOODREGS(regs));
517
518 bzero((uchar *) sii, sizeof(si_info_t));
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 */
529 if ((bustype == PCI_BUS) &&
530 (OSL_PCI_READ_CONFIG(sii->osh, PCI_SPROM_CONTROL, sizeof(uint32)) ==
531 0xffffffff)) {
532 SI_ERROR(("%s: incoming bus is PCI but it's a lie, switching to SI " "devid:0x%x\n", __func__, devid));
533 bustype = SI_BUS;
534 }
535
536 /* find Chipcommon address */
537 if (bustype == PCI_BUS) {
538 savewin =
539 OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32));
540 if (!GOODCOREADDR(savewin, SI_ENUM_BASE))
541 savewin = SI_ENUM_BASE;
542 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, SI_ENUM_BASE);
543 cc = (chipcregs_t *) regs;
544 } else {
545 cc = (chipcregs_t *) REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE);
546 }
547
548 sih->bustype = bustype;
549 if (bustype != BUSTYPE(bustype)) {
550 SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n", bustype, BUSTYPE(bustype)));
551 return NULL;
552 }
553
554 /* bus/core/clk setup for register access */
555 if (!si_buscore_prep(sii, bustype, devid, sdh)) {
556 SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n",
557 bustype));
558 return NULL;
559 }
560
561 /* ChipID recognition.
562 * We assume we can read chipid at offset 0 from the regs arg.
563 * If we add other chiptypes (or if we need to support old sdio hosts w/o chipcommon),
564 * some way of recognizing them needs to be added here.
565 */
566 w = R_REG(osh, &cc->chipid);
567 sih->socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
568 /* Might as wll fill in chip id rev & pkg */
569 sih->chip = w & CID_ID_MASK;
570 sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT;
571 sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT;
572
573 sih->issim = IS_SIM(sih->chippkg);
574
575 /* scan for cores */
576 if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) {
577 SI_MSG(("Found chip type AI (0x%08x)\n", w));
578 /* pass chipc address instead of original core base */
579 ai_scan(&sii->pub, (void *)(uintptr) cc, devid);
580 } else {
581 SI_ERROR(("Found chip of unknown type (0x%08x)\n", w));
582 return NULL;
583 }
584 /* no cores found, bail out */
585 if (sii->numcores == 0) {
586 SI_ERROR(("si_doattach: could not find any cores\n"));
587 return NULL;
588 }
589 /* bus/core/clk setup */
590 origidx = SI_CC_IDX;
591 if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) {
592 SI_ERROR(("si_doattach: si_buscore_setup failed\n"));
593 goto exit;
594 }
595
596 /* assume current core is CC */
597 if ((sii->pub.ccrev == 0x25)
598 &&
599 ((CHIPID(sih->chip) == BCM43236_CHIP_ID
600 || CHIPID(sih->chip) == BCM43235_CHIP_ID
601 || CHIPID(sih->chip) == BCM43238_CHIP_ID)
602 && (CHIPREV(sii->pub.chiprev) <= 2))) {
603
604 if ((cc->chipstatus & CST43236_BP_CLK) != 0) {
605 uint clkdiv;
606 clkdiv = R_REG(osh, &cc->clkdiv);
607 /* otp_clk_div is even number, 120/14 < 9mhz */
608 clkdiv = (clkdiv & ~CLKD_OTP) | (14 << CLKD_OTP_SHIFT);
609 W_REG(osh, &cc->clkdiv, clkdiv);
610 SI_ERROR(("%s: set clkdiv to %x\n", __func__, clkdiv));
611 }
612 OSL_DELAY(10);
613 }
614
615 /* Init nvram from flash if it exists */
616 nvram_init((void *)&(sii->pub));
617
618 /* Init nvram from sprom/otp if they exist */
619 if (srom_var_init
620 (&sii->pub, BUSTYPE(bustype), regs, sii->osh, vars, varsz)) {
621 SI_ERROR(("si_doattach: srom_var_init failed: bad srom\n"));
622 goto exit;
623 }
624 pvars = vars ? *vars : NULL;
625 si_nvram_process(sii, pvars);
626
627 /* === NVRAM, clock is ready === */
628 cc = (chipcregs_t *) si_setcore(sih, CC_CORE_ID, 0);
629 W_REG(osh, &cc->gpiopullup, 0);
630 W_REG(osh, &cc->gpiopulldown, 0);
631 si_setcoreidx(sih, origidx);
632
633 /* PMU specific initializations */
634 if (PMUCTL_ENAB(sih)) {
635 uint32 xtalfreq;
636 si_pmu_init(sih, sii->osh);
637 si_pmu_chip_init(sih, sii->osh);
638 xtalfreq = getintvar(pvars, "xtalfreq");
639 /* If xtalfreq var not available, try to measure it */
640 if (xtalfreq == 0)
641 xtalfreq = si_pmu_measure_alpclk(sih, sii->osh);
642 si_pmu_pll_init(sih, sii->osh, xtalfreq);
643 si_pmu_res_init(sih, sii->osh);
644 si_pmu_swreg_init(sih, sii->osh);
645 }
646
647 /* setup the GPIO based LED powersave register */
ca8c1e59
JC
648 w = getintvar(pvars, "leddc");
649 if (w == 0)
a9533e7e
HP
650 w = DEFAULT_GPIOTIMERVAL;
651 si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiotimerval), ~0, w);
652
653 if (PCIE(sii)) {
654 ASSERT(sii->pch != NULL);
655 pcicore_attach(sii->pch, pvars, SI_DOATTACH);
656 }
657
658 if ((CHIPID(sih->chip) == BCM43224_CHIP_ID) ||
659 (CHIPID(sih->chip) == BCM43421_CHIP_ID)) {
660 /* enable 12 mA drive strenth for 43224 and set chipControl register bit 15 */
661 if (CHIPREV(sih->chiprev) == 0) {
662 SI_MSG(("Applying 43224A0 WARs\n"));
663 si_corereg(sih, SI_CC_IDX,
664 OFFSETOF(chipcregs_t, chipcontrol),
665 CCTRL43224_GPIO_TOGGLE,
666 CCTRL43224_GPIO_TOGGLE);
667 si_pmu_chipcontrol(sih, 0, CCTRL_43224A0_12MA_LED_DRIVE,
668 CCTRL_43224A0_12MA_LED_DRIVE);
669 }
670 if (CHIPREV(sih->chiprev) >= 1) {
671 SI_MSG(("Applying 43224B0+ WARs\n"));
672 si_pmu_chipcontrol(sih, 0, CCTRL_43224B0_12MA_LED_DRIVE,
673 CCTRL_43224B0_12MA_LED_DRIVE);
674 }
675 }
676
677 if (CHIPID(sih->chip) == BCM4313_CHIP_ID) {
678 /* enable 12 mA drive strenth for 4313 and set chipControl register bit 1 */
679 SI_MSG(("Applying 4313 WARs\n"));
680 si_pmu_chipcontrol(sih, 0, CCTRL_4313_12MA_LED_DRIVE,
681 CCTRL_4313_12MA_LED_DRIVE);
682 }
683
684 if (CHIPID(sih->chip) == BCM4331_CHIP_ID) {
685 /* Enable Ext PA lines depending on chip package option */
686 si_chipcontrl_epa4331(sih, TRUE);
687 }
688
90ea2296 689 return sii;
a9533e7e
HP
690 exit:
691 if (BUSTYPE(sih->bustype) == PCI_BUS) {
692 if (sii->pch)
693 pcicore_deinit(sii->pch);
694 sii->pch = NULL;
695 }
696
697 return NULL;
698}
699#endif /* BCMSDIO */
700
701/* may be called with core in reset */
a2627bc0
JC
702void BCMATTACHFN(si_detach) (si_t *sih)
703{
a9533e7e
HP
704 si_info_t *sii;
705 uint idx;
706
707 struct si_pub *si_local = NULL;
708 bcopy(&sih, &si_local, sizeof(si_t **));
709
710 sii = SI_INFO(sih);
711
712 if (sii == NULL)
713 return;
714
715 if (BUSTYPE(sih->bustype) == SI_BUS)
716 for (idx = 0; idx < SI_MAXCORES; idx++)
717 if (sii->regs[idx]) {
718 REG_UNMAP(sii->regs[idx]);
719 sii->regs[idx] = NULL;
720 }
721
cf2b4488 722#ifndef BRCM_FULLMAC
a9533e7e
HP
723 nvram_exit((void *)si_local); /* free up nvram buffers */
724
725 if (BUSTYPE(sih->bustype) == PCI_BUS) {
726 if (sii->pch)
727 pcicore_deinit(sii->pch);
728 sii->pch = NULL;
729 }
cf2b4488 730#endif
a9533e7e
HP
731#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS)
732 if (sii != &ksii)
733#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */
734 MFREE(sii->osh, sii, sizeof(si_info_t));
735}
736
7cc4a4c0 737void *si_osh(si_t *sih)
a9533e7e
HP
738{
739 si_info_t *sii;
740
741 sii = SI_INFO(sih);
742 return sii->osh;
743}
744
7cc4a4c0 745void si_setosh(si_t *sih, osl_t *osh)
a9533e7e
HP
746{
747 si_info_t *sii;
748
749 sii = SI_INFO(sih);
750 if (sii->osh != NULL) {
751 SI_ERROR(("osh is already set....\n"));
752 ASSERT(!sii->osh);
753 }
754 sii->osh = osh;
755}
756
757/* register driver interrupt disabling and restoring callback functions */
758void
7cc4a4c0 759si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn,
a9533e7e
HP
760 void *intrsenabled_fn, void *intr_arg)
761{
762 si_info_t *sii;
763
764 sii = SI_INFO(sih);
765 sii->intr_arg = intr_arg;
766 sii->intrsoff_fn = (si_intrsoff_t) intrsoff_fn;
767 sii->intrsrestore_fn = (si_intrsrestore_t) intrsrestore_fn;
768 sii->intrsenabled_fn = (si_intrsenabled_t) intrsenabled_fn;
769 /* save current core id. when this function called, the current core
770 * must be the core which provides driver functions(il, et, wl, etc.)
771 */
772 sii->dev_coreid = sii->coreid[sii->curidx];
773}
774
7cc4a4c0 775void si_deregister_intr_callback(si_t *sih)
a9533e7e
HP
776{
777 si_info_t *sii;
778
779 sii = SI_INFO(sih);
780 sii->intrsoff_fn = NULL;
781}
782
7cc4a4c0 783uint si_intflag(si_t *sih)
a9533e7e
HP
784{
785 si_info_t *sii = SI_INFO(sih);
786
787 if (CHIPTYPE(sih->socitype) == SOCI_AI)
788 return R_REG(sii->osh,
789 ((uint32 *) (uintptr) (sii->oob_router +
790 OOB_STATUSA)));
791 else {
792 ASSERT(0);
793 return 0;
794 }
795}
796
7cc4a4c0 797uint si_flag(si_t *sih)
a9533e7e
HP
798{
799 if (CHIPTYPE(sih->socitype) == SOCI_AI)
800 return ai_flag(sih);
801 else {
802 ASSERT(0);
803 return 0;
804 }
805}
806
7cc4a4c0 807void si_setint(si_t *sih, int siflag)
a9533e7e
HP
808{
809 if (CHIPTYPE(sih->socitype) == SOCI_AI)
810 ai_setint(sih, siflag);
811 else
812 ASSERT(0);
813}
814
815#ifndef BCMSDIO
7cc4a4c0 816uint si_coreid(si_t *sih)
a9533e7e
HP
817{
818 si_info_t *sii;
819
820 sii = SI_INFO(sih);
821 return sii->coreid[sii->curidx];
822}
823#endif
824
7cc4a4c0 825uint si_coreidx(si_t *sih)
a9533e7e
HP
826{
827 si_info_t *sii;
828
829 sii = SI_INFO(sih);
830 return sii->curidx;
831}
832
833/* return the core-type instantiation # of the current core */
7cc4a4c0 834uint si_coreunit(si_t *sih)
a9533e7e
HP
835{
836 si_info_t *sii;
837 uint idx;
838 uint coreid;
839 uint coreunit;
840 uint i;
841
842 sii = SI_INFO(sih);
843 coreunit = 0;
844
845 idx = sii->curidx;
846
847 ASSERT(GOODREGS(sii->curmap));
848 coreid = si_coreid(sih);
849
850 /* count the cores of our type */
851 for (i = 0; i < idx; i++)
852 if (sii->coreid[i] == coreid)
853 coreunit++;
854
90ea2296 855 return coreunit;
a9533e7e
HP
856}
857
7cc4a4c0 858uint si_corevendor(si_t *sih)
a9533e7e
HP
859{
860 if (CHIPTYPE(sih->socitype) == SOCI_AI)
861 return ai_corevendor(sih);
862 else {
863 ASSERT(0);
864 return 0;
865 }
866}
867
7cc4a4c0 868bool si_backplane64(si_t *sih)
a9533e7e 869{
90ea2296 870 return (sih->cccaps & CC_CAP_BKPLN64) != 0;
a9533e7e
HP
871}
872
873#ifndef BCMSDIO
7cc4a4c0 874uint si_corerev(si_t *sih)
a9533e7e
HP
875{
876 if (CHIPTYPE(sih->socitype) == SOCI_AI)
877 return ai_corerev(sih);
878 else {
879 ASSERT(0);
880 return 0;
881 }
882}
883#endif
884
885/* return index of coreid or BADIDX if not found */
7cc4a4c0 886uint si_findcoreidx(si_t *sih, uint coreid, uint coreunit)
a9533e7e
HP
887{
888 si_info_t *sii;
889 uint found;
890 uint i;
891
892 sii = SI_INFO(sih);
893
894 found = 0;
895
896 for (i = 0; i < sii->numcores; i++)
897 if (sii->coreid[i] == coreid) {
898 if (found == coreunit)
90ea2296 899 return i;
a9533e7e
HP
900 found++;
901 }
902
90ea2296 903 return BADIDX;
a9533e7e
HP
904}
905
906/* return list of found cores */
7cc4a4c0 907uint si_corelist(si_t *sih, uint coreid[])
a9533e7e
HP
908{
909 si_info_t *sii;
910
911 sii = SI_INFO(sih);
912
913 bcopy((uchar *) sii->coreid, (uchar *) coreid,
914 (sii->numcores * sizeof(uint)));
90ea2296 915 return sii->numcores;
a9533e7e
HP
916}
917
918/* return current register mapping */
7cc4a4c0 919void *si_coreregs(si_t *sih)
a9533e7e
HP
920{
921 si_info_t *sii;
922
923 sii = SI_INFO(sih);
924 ASSERT(GOODREGS(sii->curmap));
925
90ea2296 926 return sii->curmap;
a9533e7e
HP
927}
928
929/*
930 * This function changes logical "focus" to the indicated core;
931 * must be called with interrupts off.
932 * Moreover, callers should keep interrupts off during switching out of and back to d11 core
933 */
7cc4a4c0 934void *si_setcore(si_t *sih, uint coreid, uint coreunit)
a9533e7e
HP
935{
936 uint idx;
937
938 idx = si_findcoreidx(sih, coreid, coreunit);
939 if (!GOODIDX(idx))
90ea2296 940 return NULL;
a9533e7e
HP
941
942 if (CHIPTYPE(sih->socitype) == SOCI_AI)
943 return ai_setcoreidx(sih, idx);
944 else {
945#ifdef BCMSDIO
946 return sb_setcoreidx(sih, idx);
947#else
948 ASSERT(0);
949 return NULL;
950#endif
951 }
952}
953
954#ifndef BCMSDIO
7cc4a4c0 955void *si_setcoreidx(si_t *sih, uint coreidx)
a9533e7e
HP
956{
957 if (CHIPTYPE(sih->socitype) == SOCI_AI)
958 return ai_setcoreidx(sih, coreidx);
959 else {
960 ASSERT(0);
961 return NULL;
962 }
963}
964#endif
965
966/* Turn off interrupt as required by sb_setcore, before switch core */
7cc4a4c0 967void *si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val)
a9533e7e
HP
968{
969 void *cc;
970 si_info_t *sii;
971
972 sii = SI_INFO(sih);
973
974 if (SI_FAST(sii)) {
975 /* Overloading the origidx variable to remember the coreid,
976 * this works because the core ids cannot be confused with
977 * core indices.
978 */
979 *origidx = coreid;
980 if (coreid == CC_CORE_ID)
981 return (void *)CCREGS_FAST(sii);
982 else if (coreid == sih->buscoretype)
983 return (void *)PCIEREGS(sii);
984 }
985 INTR_OFF(sii, *intr_val);
986 *origidx = sii->curidx;
987 cc = si_setcore(sih, coreid, 0);
988 ASSERT(cc != NULL);
989
990 return cc;
991}
992
993/* restore coreidx and restore interrupt */
7cc4a4c0 994void si_restore_core(si_t *sih, uint coreid, uint intr_val)
a9533e7e
HP
995{
996 si_info_t *sii;
997
998 sii = SI_INFO(sih);
999 if (SI_FAST(sii)
1000 && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype)))
1001 return;
1002
1003 si_setcoreidx(sih, coreid);
1004 INTR_RESTORE(sii, intr_val);
1005}
1006
7cc4a4c0 1007int si_numaddrspaces(si_t *sih)
a9533e7e
HP
1008{
1009 if (CHIPTYPE(sih->socitype) == SOCI_AI)
1010 return ai_numaddrspaces(sih);
1011 else {
1012 ASSERT(0);
1013 return 0;
1014 }
1015}
1016
7cc4a4c0 1017uint32 si_addrspace(si_t *sih, uint asidx)
a9533e7e
HP
1018{
1019 if (CHIPTYPE(sih->socitype) == SOCI_AI)
1020 return ai_addrspace(sih, asidx);
1021 else {
1022 ASSERT(0);
1023 return 0;
1024 }
1025}
1026
7cc4a4c0 1027uint32 si_addrspacesize(si_t *sih, uint asidx)
a9533e7e
HP
1028{
1029 if (CHIPTYPE(sih->socitype) == SOCI_AI)
1030 return ai_addrspacesize(sih, asidx);
1031 else {
1032 ASSERT(0);
1033 return 0;
1034 }
1035}
1036
7cc4a4c0 1037uint32 si_core_cflags(si_t *sih, uint32 mask, uint32 val)
a9533e7e
HP
1038{
1039 if (CHIPTYPE(sih->socitype) == SOCI_AI)
1040 return ai_core_cflags(sih, mask, val);
1041 else {
1042 ASSERT(0);
1043 return 0;
1044 }
1045}
1046
7cc4a4c0 1047void si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val)
a9533e7e
HP
1048{
1049 if (CHIPTYPE(sih->socitype) == SOCI_AI)
1050 ai_core_cflags_wo(sih, mask, val);
1051 else
1052 ASSERT(0);
1053}
1054
7cc4a4c0 1055uint32 si_core_sflags(si_t *sih, uint32 mask, uint32 val)
a9533e7e
HP
1056{
1057 if (CHIPTYPE(sih->socitype) == SOCI_AI)
1058 return ai_core_sflags(sih, mask, val);
1059 else {
1060 ASSERT(0);
1061 return 0;
1062 }
1063}
1064
7cc4a4c0 1065bool si_iscoreup(si_t *sih)
a9533e7e
HP
1066{
1067 if (CHIPTYPE(sih->socitype) == SOCI_AI)
1068 return ai_iscoreup(sih);
1069 else {
1070#ifdef BCMSDIO
1071 return sb_iscoreup(sih);
1072#else
1073 ASSERT(0);
1074 return FALSE;
1075#endif
1076 }
1077}
1078
7cc4a4c0 1079void si_write_wrapperreg(si_t *sih, uint32 offset, uint32 val)
a9533e7e
HP
1080{
1081 /* only for 4319, no requirement for SOCI_SB */
1082 if (CHIPTYPE(sih->socitype) == SOCI_AI) {
1083 ai_write_wrap_reg(sih, offset, val);
1084 }
1085}
1086
7cc4a4c0 1087uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
a9533e7e
HP
1088{
1089
1090 if (CHIPTYPE(sih->socitype) == SOCI_AI)
1091 return ai_corereg(sih, coreidx, regoff, mask, val);
1092 else {
1093#ifdef BCMSDIO
1094 return sb_corereg(sih, coreidx, regoff, mask, val);
1095#else
1096 ASSERT(0);
1097 return 0;
1098#endif
1099 }
1100}
1101
7cc4a4c0 1102void si_core_disable(si_t *sih, uint32 bits)
a9533e7e
HP
1103{
1104
1105 if (CHIPTYPE(sih->socitype) == SOCI_AI)
1106 ai_core_disable(sih, bits);
1107#ifdef BCMSDIO
1108 else
1109 sb_core_disable(sih, bits);
1110#endif
1111}
1112
7cc4a4c0 1113void si_core_reset(si_t *sih, uint32 bits, uint32 resetbits)
a9533e7e
HP
1114{
1115 if (CHIPTYPE(sih->socitype) == SOCI_AI)
1116 ai_core_reset(sih, bits, resetbits);
1117#ifdef BCMSDIO
1118 else
1119 sb_core_reset(sih, bits, resetbits);
1120#endif
1121}
1122
1123/* Run bist on current core. Caller needs to take care of core-specific bist hazards */
7cc4a4c0 1124int si_corebist(si_t *sih)
a9533e7e
HP
1125{
1126 uint32 cflags;
1127 int result = 0;
1128
1129 /* Read core control flags */
1130 cflags = si_core_cflags(sih, 0, 0);
1131
1132 /* Set bist & fgc */
1133 si_core_cflags(sih, ~0, (SICF_BIST_EN | SICF_FGC));
1134
1135 /* Wait for bist done */
1136 SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 100000);
1137
1138 if (si_core_sflags(sih, 0, 0) & SISF_BIST_ERROR)
1139 result = BCME_ERROR;
1140
1141 /* Reset core control flags */
1142 si_core_cflags(sih, 0xffff, cflags);
1143
1144 return result;
1145}
1146
a2627bc0
JC
1147static uint32 BCMINITFN(factor6) (uint32 x)
1148{
a9533e7e
HP
1149 switch (x) {
1150 case CC_F6_2:
1151 return 2;
1152 case CC_F6_3:
1153 return 3;
1154 case CC_F6_4:
1155 return 4;
1156 case CC_F6_5:
1157 return 5;
1158 case CC_F6_6:
1159 return 6;
1160 case CC_F6_7:
1161 return 7;
1162 default:
1163 return 0;
1164 }
1165}
1166
1167/* calculate the speed the SI would run at given a set of clockcontrol values */
a2627bc0
JC
1168uint32 BCMINITFN(si_clock_rate) (uint32 pll_type, uint32 n, uint32 m)
1169{
a9533e7e
HP
1170 uint32 n1, n2, clock, m1, m2, m3, mc;
1171
1172 n1 = n & CN_N1_MASK;
1173 n2 = (n & CN_N2_MASK) >> CN_N2_SHIFT;
1174
1175 if (pll_type == PLL_TYPE6) {
1176 if (m & CC_T6_MMASK)
1177 return CC_T6_M1;
1178 else
1179 return CC_T6_M0;
1180 } else if ((pll_type == PLL_TYPE1) ||
1181 (pll_type == PLL_TYPE3) ||
1182 (pll_type == PLL_TYPE4) || (pll_type == PLL_TYPE7)) {
1183 n1 = factor6(n1);
1184 n2 += CC_F5_BIAS;
1185 } else if (pll_type == PLL_TYPE2) {
1186 n1 += CC_T2_BIAS;
1187 n2 += CC_T2_BIAS;
1188 ASSERT((n1 >= 2) && (n1 <= 7));
1189 ASSERT((n2 >= 5) && (n2 <= 23));
1190 } else if (pll_type == PLL_TYPE5) {
90ea2296 1191 return 100000000;
a9533e7e
HP
1192 } else
1193 ASSERT(0);
1194 /* PLL types 3 and 7 use BASE2 (25Mhz) */
1195 if ((pll_type == PLL_TYPE3) || (pll_type == PLL_TYPE7)) {
1196 clock = CC_CLOCK_BASE2 * n1 * n2;
1197 } else
1198 clock = CC_CLOCK_BASE1 * n1 * n2;
1199
1200 if (clock == 0)
1201 return 0;
1202
1203 m1 = m & CC_M1_MASK;
1204 m2 = (m & CC_M2_MASK) >> CC_M2_SHIFT;
1205 m3 = (m & CC_M3_MASK) >> CC_M3_SHIFT;
1206 mc = (m & CC_MC_MASK) >> CC_MC_SHIFT;
1207
1208 if ((pll_type == PLL_TYPE1) ||
1209 (pll_type == PLL_TYPE3) ||
1210 (pll_type == PLL_TYPE4) || (pll_type == PLL_TYPE7)) {
1211 m1 = factor6(m1);
1212 if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3))
1213 m2 += CC_F5_BIAS;
1214 else
1215 m2 = factor6(m2);
1216 m3 = factor6(m3);
1217
1218 switch (mc) {
1219 case CC_MC_BYPASS:
90ea2296 1220 return clock;
a9533e7e 1221 case CC_MC_M1:
90ea2296 1222 return clock / m1;
a9533e7e 1223 case CC_MC_M1M2:
90ea2296 1224 return clock / (m1 * m2);
a9533e7e 1225 case CC_MC_M1M2M3:
90ea2296 1226 return clock / (m1 * m2 * m3);
a9533e7e 1227 case CC_MC_M1M3:
90ea2296 1228 return clock / (m1 * m3);
a9533e7e 1229 default:
90ea2296 1230 return 0;
a9533e7e
HP
1231 }
1232 } else {
1233 ASSERT(pll_type == PLL_TYPE2);
1234
1235 m1 += CC_T2_BIAS;
1236 m2 += CC_T2M2_BIAS;
1237 m3 += CC_T2_BIAS;
1238 ASSERT((m1 >= 2) && (m1 <= 7));
1239 ASSERT((m2 >= 3) && (m2 <= 10));
1240 ASSERT((m3 >= 2) && (m3 <= 7));
1241
1242 if ((mc & CC_T2MC_M1BYP) == 0)
1243 clock /= m1;
1244 if ((mc & CC_T2MC_M2BYP) == 0)
1245 clock /= m2;
1246 if ((mc & CC_T2MC_M3BYP) == 0)
1247 clock /= m3;
1248
90ea2296 1249 return clock;
a9533e7e
HP
1250 }
1251}
1252
a2627bc0
JC
1253uint32 BCMINITFN(si_clock) (si_t *sih)
1254{
a9533e7e
HP
1255 si_info_t *sii;
1256 chipcregs_t *cc;
1257 uint32 n, m;
1258 uint idx;
1259 uint32 pll_type, rate;
1260 uint intr_val = 0;
1261
1262 sii = SI_INFO(sih);
1263 INTR_OFF(sii, intr_val);
1264 if (PMUCTL_ENAB(sih)) {
1265 rate = si_pmu_si_clock(sih, sii->osh);
1266 goto exit;
1267 }
1268
1269 idx = sii->curidx;
1270 cc = (chipcregs_t *) si_setcore(sih, CC_CORE_ID, 0);
1271 ASSERT(cc != NULL);
1272
1273 n = R_REG(sii->osh, &cc->clockcontrol_n);
1274 pll_type = sih->cccaps & CC_CAP_PLL_MASK;
1275 if (pll_type == PLL_TYPE6)
1276 m = R_REG(sii->osh, &cc->clockcontrol_m3);
1277 else if (pll_type == PLL_TYPE3)
1278 m = R_REG(sii->osh, &cc->clockcontrol_m2);
1279 else
1280 m = R_REG(sii->osh, &cc->clockcontrol_sb);
1281
1282 /* calculate rate */
1283 rate = si_clock_rate(pll_type, n, m);
1284
1285 if (pll_type == PLL_TYPE3)
1286 rate = rate / 2;
1287
1288 /* switch back to previous core */
1289 si_setcoreidx(sih, idx);
1290 exit:
1291 INTR_RESTORE(sii, intr_val);
1292
1293 return rate;
1294}
1295
a2627bc0
JC
1296uint32 BCMINITFN(si_alp_clock) (si_t *sih)
1297{
a9533e7e
HP
1298 if (PMUCTL_ENAB(sih))
1299 return si_pmu_alp_clock(sih, si_osh(sih));
1300
1301 return ALP_CLOCK;
1302}
1303
a2627bc0
JC
1304uint32 BCMINITFN(si_ilp_clock) (si_t *sih)
1305{
a9533e7e
HP
1306 if (PMUCTL_ENAB(sih))
1307 return si_pmu_ilp_clock(sih, si_osh(sih));
1308
1309 return ILP_CLOCK;
1310}
1311
1312/* set chip watchdog reset timer to fire in 'ticks' */
cf2b4488
HP
1313#ifdef BRCM_FULLMAC
1314void
1315si_watchdog(si_t *sih, uint ticks)
1316{
1317 if (PMUCTL_ENAB(sih)) {
1318
1319 if ((sih->chip == BCM4319_CHIP_ID) && (sih->chiprev == 0) &&
1320 (ticks != 0)) {
1321 si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t,
1322 clk_ctl_st), ~0, 0x2);
1323 si_setcore(sih, USB20D_CORE_ID, 0);
1324 si_core_disable(sih, 1);
1325 si_setcore(sih, CC_CORE_ID, 0);
1326 }
1327
1328 if (ticks == 1)
1329 ticks = 2;
1330 si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, pmuwatchdog),
1331 ~0, ticks);
1332 } else {
1333 /* instant NMI */
1334 si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog),
1335 ~0, ticks);
1336 }
1337}
1338#else
7cc4a4c0 1339void si_watchdog(si_t *sih, uint ticks)
a9533e7e
HP
1340{
1341 uint nb, maxt;
1342
1343 if (PMUCTL_ENAB(sih)) {
1344
1345 if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) &&
1346 (CHIPREV(sih->chiprev) == 0) && (ticks != 0)) {
1347 si_corereg(sih, SI_CC_IDX,
1348 OFFSETOF(chipcregs_t, clk_ctl_st), ~0, 0x2);
1349 si_setcore(sih, USB20D_CORE_ID, 0);
1350 si_core_disable(sih, 1);
1351 si_setcore(sih, CC_CORE_ID, 0);
1352 }
1353
1354 nb = (sih->ccrev < 26) ? 16 : ((sih->ccrev >= 37) ? 32 : 24);
1355 /* The mips compiler uses the sllv instruction,
1356 * so we specially handle the 32-bit case.
1357 */
1358 if (nb == 32)
1359 maxt = 0xffffffff;
1360 else
1361 maxt = ((1 << nb) - 1);
1362
1363 if (ticks == 1)
1364 ticks = 2;
1365 else if (ticks > maxt)
1366 ticks = maxt;
1367
1368 si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, pmuwatchdog),
1369 ~0, ticks);
1370 } else {
1371 /* make sure we come up in fast clock mode; or if clearing, clear clock */
1372 si_clkctl_cc(sih, ticks ? CLK_FAST : CLK_DYNAMIC);
1373 maxt = (1 << 28) - 1;
1374 if (ticks > maxt)
1375 ticks = maxt;
1376
1377 si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0,
1378 ticks);
1379 }
1380}
cf2b4488 1381#endif
a9533e7e
HP
1382
1383/* trigger watchdog reset after ms milliseconds */
7cc4a4c0 1384void si_watchdog_ms(si_t *sih, uint32 ms)
a9533e7e
HP
1385{
1386 si_watchdog(sih, wd_msticks * ms);
1387}
1388
a2627bc0
JC
1389uint16 BCMATTACHFN(si_d11_devid) (si_t *sih)
1390{
a9533e7e
HP
1391 si_info_t *sii = SI_INFO(sih);
1392 uint16 device;
1393
1394 /* normal case: nvram variable with devpath->devid->wl0id */
ca8c1e59
JC
1395 device = (uint16) si_getdevpathintvar(sih, "devid");
1396 if (device != 0)
1397 goto bail;
1398
a9533e7e 1399 /* Get devid from OTP/SPROM depending on where the SROM is read */
ca8c1e59
JC
1400 device = (uint16) getintvar(sii->vars, "devid");
1401 if (device != 0)
1402 goto bail;
1403
a9533e7e 1404 /* no longer support wl0id, but keep the code here for backward compatibility. */
ca8c1e59
JC
1405 device = (uint16) getintvar(sii->vars, "wl0id");
1406 if (device != 0)
1407 goto bail;
1408
1409 /* ignore it */
1410 device = 0xffff;
a9533e7e 1411
ca8c1e59 1412bail:
a9533e7e
HP
1413 return device;
1414}
1415
1416/* return the slow clock source - LPO, XTAL, or PCI */
7cc4a4c0 1417static uint si_slowclk_src(si_info_t *sii)
a9533e7e
HP
1418{
1419 chipcregs_t *cc;
1420
1421 ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID);
1422
1423 if (sii->pub.ccrev < 6) {
1424 if ((BUSTYPE(sii->pub.bustype) == PCI_BUS) &&
1425 (OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(uint32))
1426 & PCI_CFG_GPIO_SCS))
90ea2296 1427 return SCC_SS_PCI;
a9533e7e 1428 else
90ea2296 1429 return SCC_SS_XTAL;
a9533e7e
HP
1430 } else if (sii->pub.ccrev < 10) {
1431 cc = (chipcregs_t *) si_setcoreidx(&sii->pub, sii->curidx);
90ea2296 1432 return R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_SS_MASK;
a9533e7e 1433 } else /* Insta-clock */
90ea2296 1434 return SCC_SS_XTAL;
a9533e7e
HP
1435}
1436
1437/* return the ILP (slowclock) min or max frequency */
7cc4a4c0 1438static uint si_slowclk_freq(si_info_t *sii, bool max_freq, chipcregs_t *cc)
a9533e7e
HP
1439{
1440 uint32 slowclk;
1441 uint div;
1442
1443 ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID);
1444
1445 /* shouldn't be here unless we've established the chip has dynamic clk control */
1446 ASSERT(R_REG(sii->osh, &cc->capabilities) & CC_CAP_PWR_CTL);
1447
1448 slowclk = si_slowclk_src(sii);
1449 if (sii->pub.ccrev < 6) {
1450 if (slowclk == SCC_SS_PCI)
90ea2296
JC
1451 return max_freq ? (PCIMAXFREQ / 64)
1452 : (PCIMINFREQ / 64);
a9533e7e 1453 else
90ea2296
JC
1454 return max_freq ? (XTALMAXFREQ / 32)
1455 : (XTALMINFREQ / 32);
a9533e7e
HP
1456 } else if (sii->pub.ccrev < 10) {
1457 div = 4 *
1458 (((R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_CD_MASK) >>
1459 SCC_CD_SHIFT) + 1);
1460 if (slowclk == SCC_SS_LPO)
90ea2296 1461 return max_freq ? LPOMAXFREQ : LPOMINFREQ;
a9533e7e 1462 else if (slowclk == SCC_SS_XTAL)
90ea2296
JC
1463 return max_freq ? (XTALMAXFREQ / div)
1464 : (XTALMINFREQ / div);
a9533e7e 1465 else if (slowclk == SCC_SS_PCI)
90ea2296
JC
1466 return max_freq ? (PCIMAXFREQ / div)
1467 : (PCIMINFREQ / div);
a9533e7e
HP
1468 else
1469 ASSERT(0);
1470 } else {
1471 /* Chipc rev 10 is InstaClock */
1472 div = R_REG(sii->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT;
1473 div = 4 * (div + 1);
90ea2296 1474 return max_freq ? XTALMAXFREQ : (XTALMINFREQ / div);
a9533e7e 1475 }
90ea2296 1476 return 0;
a9533e7e
HP
1477}
1478
a2627bc0
JC
1479static void BCMINITFN(si_clkctl_setdelay) (si_info_t *sii, void *chipcregs)
1480{
a9533e7e
HP
1481 chipcregs_t *cc = (chipcregs_t *) chipcregs;
1482 uint slowmaxfreq, pll_delay, slowclk;
1483 uint pll_on_delay, fref_sel_delay;
1484
1485 pll_delay = PLL_DELAY;
1486
1487 /* If the slow clock is not sourced by the xtal then add the xtal_on_delay
1488 * since the xtal will also be powered down by dynamic clk control logic.
1489 */
1490
1491 slowclk = si_slowclk_src(sii);
1492 if (slowclk != SCC_SS_XTAL)
1493 pll_delay += XTAL_ON_DELAY;
1494
1495 /* Starting with 4318 it is ILP that is used for the delays */
1496 slowmaxfreq =
1497 si_slowclk_freq(sii, (sii->pub.ccrev >= 10) ? FALSE : TRUE, cc);
1498
1499 pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000;
1500 fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000;
1501
1502 W_REG(sii->osh, &cc->pll_on_delay, pll_on_delay);
1503 W_REG(sii->osh, &cc->fref_sel_delay, fref_sel_delay);
1504}
1505
1506/* initialize power control delay registers */
a2627bc0
JC
1507void BCMINITFN(si_clkctl_init) (si_t *sih)
1508{
a9533e7e
HP
1509 si_info_t *sii;
1510 uint origidx = 0;
1511 chipcregs_t *cc;
1512 bool fast;
1513
1514 if (!CCCTL_ENAB(sih))
1515 return;
1516
1517 sii = SI_INFO(sih);
1518 fast = SI_FAST(sii);
1519 if (!fast) {
1520 origidx = sii->curidx;
ca8c1e59
JC
1521 cc = (chipcregs_t *) si_setcore(sih, CC_CORE_ID, 0);
1522 if (cc == NULL)
a9533e7e 1523 return;
ca8c1e59
JC
1524 } else {
1525 cc = (chipcregs_t *) CCREGS_FAST(sii);
1526 if (cc == NULL)
1527 return;
1528 }
a9533e7e
HP
1529 ASSERT(cc != NULL);
1530
1531 /* set all Instaclk chip ILP to 1 MHz */
1532 if (sih->ccrev >= 10)
1533 SET_REG(sii->osh, &cc->system_clk_ctl, SYCC_CD_MASK,
1534 (ILP_DIV_1MHZ << SYCC_CD_SHIFT));
1535
1536 si_clkctl_setdelay(sii, (void *)(uintptr) cc);
1537
1538 if (!fast)
1539 si_setcoreidx(sih, origidx);
1540}
1541
1542/* return the value suitable for writing to the dot11 core FAST_PWRUP_DELAY register */
a2627bc0
JC
1543uint16 BCMINITFN(si_clkctl_fast_pwrup_delay) (si_t *sih)
1544{
a9533e7e
HP
1545 si_info_t *sii;
1546 uint origidx = 0;
1547 chipcregs_t *cc;
1548 uint slowminfreq;
1549 uint16 fpdelay;
1550 uint intr_val = 0;
1551 bool fast;
1552
1553 sii = SI_INFO(sih);
1554 if (PMUCTL_ENAB(sih)) {
1555 INTR_OFF(sii, intr_val);
1556 fpdelay = si_pmu_fast_pwrup_delay(sih, sii->osh);
1557 INTR_RESTORE(sii, intr_val);
1558 return fpdelay;
1559 }
1560
1561 if (!CCCTL_ENAB(sih))
1562 return 0;
1563
1564 fast = SI_FAST(sii);
1565 fpdelay = 0;
1566 if (!fast) {
1567 origidx = sii->curidx;
1568 INTR_OFF(sii, intr_val);
ca8c1e59
JC
1569 cc = (chipcregs_t *) si_setcore(sih, CC_CORE_ID, 0);
1570 if (cc == NULL)
a9533e7e 1571 goto done;
ca8c1e59
JC
1572 } else {
1573 cc = (chipcregs_t *) CCREGS_FAST(sii);
1574 if (cc == NULL)
1575 goto done;
1576 }
a9533e7e
HP
1577 ASSERT(cc != NULL);
1578
1579 slowminfreq = si_slowclk_freq(sii, FALSE, cc);
1580 fpdelay = (((R_REG(sii->osh, &cc->pll_on_delay) + 2) * 1000000) +
1581 (slowminfreq - 1)) / slowminfreq;
1582
1583 done:
1584 if (!fast) {
1585 si_setcoreidx(sih, origidx);
1586 INTR_RESTORE(sii, intr_val);
1587 }
1588 return fpdelay;
1589}
1590
1591/* turn primary xtal and/or pll off/on */
7cc4a4c0 1592int si_clkctl_xtal(si_t *sih, uint what, bool on)
a9533e7e
HP
1593{
1594 si_info_t *sii;
1595 uint32 in, out, outen;
1596
1597 sii = SI_INFO(sih);
1598
1599 switch (BUSTYPE(sih->bustype)) {
1600
1601#ifdef BCMSDIO
1602 case SDIO_BUS:
90ea2296 1603 return -1;
a9533e7e
HP
1604#endif /* BCMSDIO */
1605
1606 case PCI_BUS:
1607 /* pcie core doesn't have any mapping to control the xtal pu */
1608 if (PCIE(sii))
1609 return -1;
1610
1611 in = OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_IN, sizeof(uint32));
1612 out =
1613 OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(uint32));
1614 outen =
1615 OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUTEN,
1616 sizeof(uint32));
1617
1618 /*
1619 * Avoid glitching the clock if GPRS is already using it.
1620 * We can't actually read the state of the PLLPD so we infer it
1621 * by the value of XTAL_PU which *is* readable via gpioin.
1622 */
1623 if (on && (in & PCI_CFG_GPIO_XTAL))
90ea2296 1624 return 0;
a9533e7e
HP
1625
1626 if (what & XTAL)
1627 outen |= PCI_CFG_GPIO_XTAL;
1628 if (what & PLL)
1629 outen |= PCI_CFG_GPIO_PLL;
1630
1631 if (on) {
1632 /* turn primary xtal on */
1633 if (what & XTAL) {
1634 out |= PCI_CFG_GPIO_XTAL;
1635 if (what & PLL)
1636 out |= PCI_CFG_GPIO_PLL;
1637 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUT,
1638 sizeof(uint32), out);
1639 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUTEN,
1640 sizeof(uint32), outen);
1641 OSL_DELAY(XTAL_ON_DELAY);
1642 }
1643
1644 /* turn pll on */
1645 if (what & PLL) {
1646 out &= ~PCI_CFG_GPIO_PLL;
1647 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUT,
1648 sizeof(uint32), out);
1649 OSL_DELAY(2000);
1650 }
1651 } else {
1652 if (what & XTAL)
1653 out &= ~PCI_CFG_GPIO_XTAL;
1654 if (what & PLL)
1655 out |= PCI_CFG_GPIO_PLL;
1656 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUT,
1657 sizeof(uint32), out);
1658 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_GPIO_OUTEN,
1659 sizeof(uint32), outen);
1660 }
1661
1662 default:
90ea2296 1663 return -1;
a9533e7e
HP
1664 }
1665
90ea2296 1666 return 0;
a9533e7e
HP
1667}
1668
1669/*
1670 * clock control policy function throught chipcommon
1671 *
1672 * set dynamic clk control mode (forceslow, forcefast, dynamic)
1673 * returns true if we are forcing fast clock
1674 * this is a wrapper over the next internal function
1675 * to allow flexible policy settings for outside caller
1676 */
7cc4a4c0 1677bool si_clkctl_cc(si_t *sih, uint mode)
a9533e7e
HP
1678{
1679 si_info_t *sii;
1680
1681 sii = SI_INFO(sih);
1682
1683 /* chipcommon cores prior to rev6 don't support dynamic clock control */
1684 if (sih->ccrev < 6)
1685 return FALSE;
1686
1687 if (PCI_FORCEHT(sii))
90ea2296 1688 return mode == CLK_FAST;
a9533e7e
HP
1689
1690 return _si_clkctl_cc(sii, mode);
1691}
1692
1693/* clk control mechanism through chipcommon, no policy checking */
7cc4a4c0 1694static bool _si_clkctl_cc(si_info_t *sii, uint mode)
a9533e7e
HP
1695{
1696 uint origidx = 0;
1697 chipcregs_t *cc;
1698 uint32 scc;
1699 uint intr_val = 0;
1700 bool fast = SI_FAST(sii);
1701
1702 /* chipcommon cores prior to rev6 don't support dynamic clock control */
1703 if (sii->pub.ccrev < 6)
90ea2296 1704 return FALSE;
a9533e7e
HP
1705
1706 /* Chips with ccrev 10 are EOL and they don't have SYCC_HR which we use below */
1707 ASSERT(sii->pub.ccrev != 10);
1708
1709 if (!fast) {
1710 INTR_OFF(sii, intr_val);
1711 origidx = sii->curidx;
1712
1713 if ((BUSTYPE(sii->pub.bustype) == SI_BUS) &&
1714 si_setcore(&sii->pub, MIPS33_CORE_ID, 0) &&
1715 (si_corerev(&sii->pub) <= 7) && (sii->pub.ccrev >= 10))
1716 goto done;
1717
1718 cc = (chipcregs_t *) si_setcore(&sii->pub, CC_CORE_ID, 0);
ca8c1e59
JC
1719 } else {
1720 cc = (chipcregs_t *) CCREGS_FAST(sii);
1721 if (cc == NULL)
1722 goto done;
1723 }
a9533e7e
HP
1724 ASSERT(cc != NULL);
1725
1726 if (!CCCTL_ENAB(&sii->pub) && (sii->pub.ccrev < 20))
1727 goto done;
1728
1729 switch (mode) {
1730 case CLK_FAST: /* FORCEHT, fast (pll) clock */
1731 if (sii->pub.ccrev < 10) {
1732 /* don't forget to force xtal back on before we clear SCC_DYN_XTAL.. */
1733 si_clkctl_xtal(&sii->pub, XTAL, ON);
1734 SET_REG(sii->osh, &cc->slow_clk_ctl,
1735 (SCC_XC | SCC_FS | SCC_IP), SCC_IP);
1736 } else if (sii->pub.ccrev < 20) {
1737 OR_REG(sii->osh, &cc->system_clk_ctl, SYCC_HR);
1738 } else {
1739 OR_REG(sii->osh, &cc->clk_ctl_st, CCS_FORCEHT);
1740 }
1741
1742 /* wait for the PLL */
1743 if (PMUCTL_ENAB(&sii->pub)) {
1744 uint32 htavail = CCS_HTAVAIL;
1745 SPINWAIT(((R_REG(sii->osh, &cc->clk_ctl_st) & htavail)
1746 == 0), PMU_MAX_TRANSITION_DLY);
1747 ASSERT(R_REG(sii->osh, &cc->clk_ctl_st) & htavail);
1748 } else {
1749 OSL_DELAY(PLL_DELAY);
1750 }
1751 break;
1752
1753 case CLK_DYNAMIC: /* enable dynamic clock control */
1754 if (sii->pub.ccrev < 10) {
1755 scc = R_REG(sii->osh, &cc->slow_clk_ctl);
1756 scc &= ~(SCC_FS | SCC_IP | SCC_XC);
1757 if ((scc & SCC_SS_MASK) != SCC_SS_XTAL)
1758 scc |= SCC_XC;
1759 W_REG(sii->osh, &cc->slow_clk_ctl, scc);
1760
1761 /* for dynamic control, we have to release our xtal_pu "force on" */
1762 if (scc & SCC_XC)
1763 si_clkctl_xtal(&sii->pub, XTAL, OFF);
1764 } else if (sii->pub.ccrev < 20) {
1765 /* Instaclock */
1766 AND_REG(sii->osh, &cc->system_clk_ctl, ~SYCC_HR);
1767 } else {
1768 AND_REG(sii->osh, &cc->clk_ctl_st, ~CCS_FORCEHT);
1769 }
1770 break;
1771
1772 default:
1773 ASSERT(0);
1774 }
1775
1776 done:
1777 if (!fast) {
1778 si_setcoreidx(&sii->pub, origidx);
1779 INTR_RESTORE(sii, intr_val);
1780 }
90ea2296 1781 return mode == CLK_FAST;
a9533e7e
HP
1782}
1783
1784/* Build device path. Support SI, PCI, and JTAG for now. */
a2627bc0
JC
1785int BCMATTACHFN(si_devpath) (si_t *sih, char *path, int size)
1786{
a9533e7e
HP
1787 int slen;
1788
1789 ASSERT(path != NULL);
1790 ASSERT(size >= SI_DEVPATH_BUFSZ);
1791
1792 if (!path || size <= 0)
1793 return -1;
1794
1795 switch (BUSTYPE(sih->bustype)) {
1796 case SI_BUS:
1797 case JTAG_BUS:
1798 slen = snprintf(path, (size_t) size, "sb/%u/", si_coreidx(sih));
1799 break;
1800 case PCI_BUS:
1801 ASSERT((SI_INFO(sih))->osh != NULL);
1802 slen = snprintf(path, (size_t) size, "pci/%u/%u/",
1803 OSL_PCI_BUS((SI_INFO(sih))->osh),
1804 OSL_PCI_SLOT((SI_INFO(sih))->osh));
1805 break;
1806
1807#ifdef BCMSDIO
1808 case SDIO_BUS:
1809 SI_ERROR(("si_devpath: device 0 assumed\n"));
1810 slen = snprintf(path, (size_t) size, "sd/%u/", si_coreidx(sih));
1811 break;
1812#endif
1813 default:
1814 slen = -1;
1815 ASSERT(0);
1816 break;
1817 }
1818
1819 if (slen < 0 || slen >= size) {
1820 path[0] = '\0';
1821 return -1;
1822 }
1823
1824 return 0;
1825}
1826
1827/* Get a variable, but only if it has a devpath prefix */
a2627bc0
JC
1828char *BCMATTACHFN(si_getdevpathvar) (si_t *sih, const char *name)
1829{
a9533e7e
HP
1830 char varname[SI_DEVPATH_BUFSZ + 32];
1831
1832 si_devpathvar(sih, varname, sizeof(varname), name);
1833
90ea2296 1834 return getvar(NULL, varname);
a9533e7e
HP
1835}
1836
1837/* Get a variable, but only if it has a devpath prefix */
a2627bc0
JC
1838int BCMATTACHFN(si_getdevpathintvar) (si_t *sih, const char *name)
1839{
a9533e7e 1840#if defined(BCMBUSTYPE) && (BCMBUSTYPE == SI_BUS)
90ea2296 1841 return getintvar(NULL, name);
a9533e7e
HP
1842#else
1843 char varname[SI_DEVPATH_BUFSZ + 32];
1844
1845 si_devpathvar(sih, varname, sizeof(varname), name);
1846
90ea2296 1847 return getintvar(NULL, varname);
a9533e7e
HP
1848#endif
1849}
1850
7cc4a4c0 1851char *si_getnvramflvar(si_t *sih, const char *name)
a9533e7e 1852{
90ea2296 1853 return getvar(NULL, name);
a9533e7e
HP
1854}
1855
1856/* Concatenate the dev path with a varname into the given 'var' buffer
1857 * and return the 'var' pointer.
1858 * Nothing is done to the arguments if len == 0 or var is NULL, var is still returned.
1859 * On overflow, the first char will be set to '\0'.
1860 */
7cc4a4c0 1861static char *BCMATTACHFN(si_devpathvar) (si_t *sih, char *var, int len,
a9533e7e
HP
1862 const char *name) {
1863 uint path_len;
1864
1865 if (!var || len <= 0)
1866 return var;
1867
1868 if (si_devpath(sih, var, len) == 0) {
1869 path_len = strlen(var);
1870
1871 if (strlen(name) + 1 > (uint) (len - path_len))
1872 var[0] = '\0';
1873 else
1874 strncpy(var + path_len, name, len - path_len - 1);
1875 }
1876
1877 return var;
1878}
1879
7cc4a4c0 1880uint32 si_pciereg(si_t *sih, uint32 offset, uint32 mask, uint32 val, uint type)
a9533e7e
HP
1881{
1882 si_info_t *sii;
1883
1884 sii = SI_INFO(sih);
1885
1886 if (!PCIE(sii)) {
1887 SI_ERROR(("%s: Not a PCIE device\n", __func__));
1888 return 0;
1889 }
1890
1891 return pcicore_pciereg(sii->pch, offset, mask, val, type);
1892}
1893
1894uint32
7cc4a4c0 1895si_pcieserdesreg(si_t *sih, uint32 mdioslave, uint32 offset, uint32 mask,
a9533e7e
HP
1896 uint32 val)
1897{
1898 si_info_t *sii;
1899
1900 sii = SI_INFO(sih);
1901
1902 if (!PCIE(sii)) {
1903 SI_ERROR(("%s: Not a PCIE device\n", __func__));
1904 return 0;
1905 }
1906
1907 return pcicore_pcieserdesreg(sii->pch, mdioslave, offset, mask, val);
1908
1909}
1910
1911/* return TRUE if PCIE capability exists in the pci config space */
84b9fac2 1912static __used bool si_ispcie(si_info_t *sii)
a9533e7e
HP
1913{
1914 uint8 cap_ptr;
1915
1916 if (BUSTYPE(sii->pub.bustype) != PCI_BUS)
1917 return FALSE;
1918
1919 cap_ptr =
1920 pcicore_find_pci_capability(sii->osh, PCI_CAP_PCIECAP_ID, NULL,
1921 NULL);
1922 if (!cap_ptr)
1923 return FALSE;
1924
1925 return TRUE;
1926}
1927
1928/* Wake-on-wireless-LAN (WOWL) support functions */
1929/* Enable PME generation and disable clkreq */
7cc4a4c0 1930void si_pci_pmeen(si_t *sih)
a9533e7e
HP
1931{
1932 si_info_t *sii;
1933
1934 sii = SI_INFO(sih);
1935
1936 pcicore_pmeen(sii->pch);
1937}
1938
1939/* Return TRUE if PME status is set */
7cc4a4c0 1940bool si_pci_pmestat(si_t *sih)
a9533e7e
HP
1941{
1942 si_info_t *sii;
1943
1944 sii = SI_INFO(sih);
1945
1946 return pcicore_pmestat(sii->pch);
1947}
1948
1949/* Disable PME generation, clear the PME status bit if set */
7cc4a4c0 1950void si_pci_pmeclr(si_t *sih)
a9533e7e
HP
1951{
1952 si_info_t *sii;
1953
1954 sii = SI_INFO(sih);
1955
1956 pcicore_pmeclr(sii->pch);
1957}
1958
1959#ifdef BCMSDIO
1960/* initialize the sdio core */
7cc4a4c0 1961void si_sdio_init(si_t *sih)
a9533e7e
HP
1962{
1963 si_info_t *sii = SI_INFO(sih);
1964
1965 if (((sih->buscoretype == PCMCIA_CORE_ID) && (sih->buscorerev >= 8)) ||
1966 (sih->buscoretype == SDIOD_CORE_ID)) {
1967 uint idx;
1968 sdpcmd_regs_t *sdpregs;
1969
1970 /* get the current core index */
1971 idx = sii->curidx;
1972 ASSERT(idx == si_findcoreidx(sih, D11_CORE_ID, 0));
1973
1974 /* switch to sdio core */
ca8c1e59
JC
1975 sdpregs = (sdpcmd_regs_t *) si_setcore(sih, PCMCIA_CORE_ID, 0);
1976 if (!sdpregs)
a9533e7e
HP
1977 sdpregs =
1978 (sdpcmd_regs_t *) si_setcore(sih, SDIOD_CORE_ID, 0);
1979 ASSERT(sdpregs);
1980
1981 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));
1982
1983 /* enable backplane error and core interrupts */
1984 W_REG(sii->osh, &sdpregs->hostintmask, I_SBINT);
1985 W_REG(sii->osh, &sdpregs->sbintmask,
1986 (I_SB_SERR | I_SB_RESPERR | (1 << idx)));
1987
1988 /* switch back to previous core */
1989 si_setcoreidx(sih, idx);
1990 }
1991
1992 /* enable interrupts */
1993 bcmsdh_intr_enable(sii->sdh);
1994
1995}
1996#endif /* BCMSDIO */
1997
a2627bc0
JC
1998bool BCMATTACHFN(si_pci_war16165) (si_t *sih)
1999{
a9533e7e
HP
2000 si_info_t *sii;
2001
2002 sii = SI_INFO(sih);
2003
90ea2296 2004 return PCI(sii) && (sih->buscorerev <= 10);
a9533e7e
HP
2005}
2006
2007/* Disable pcie_war_ovr for some platforms (sigh!)
2008 * This is for boards that have BFL2_PCIEWAR_OVR set
2009 * but are in systems that still want the benefits of ASPM
2010 * Note that this should be done AFTER si_doattach
2011 */
7cc4a4c0 2012void si_pcie_war_ovr_update(si_t *sih, uint8 aspm)
a9533e7e
HP
2013{
2014 si_info_t *sii;
2015
2016 sii = SI_INFO(sih);
2017
2018 if (!PCIE(sii))
2019 return;
2020
2021 pcie_war_ovr_aspm_update(sii->pch, aspm);
2022}
2023
2024/* back door for other module to override chippkg */
7cc4a4c0 2025void si_chippkg_set(si_t *sih, uint val)
a9533e7e
HP
2026{
2027 si_info_t *sii;
2028
2029 sii = SI_INFO(sih);
2030
2031 sii->pub.chippkg = val;
2032}
2033
a2627bc0
JC
2034void BCMINITFN(si_pci_up) (si_t *sih)
2035{
a9533e7e
HP
2036 si_info_t *sii;
2037
2038 sii = SI_INFO(sih);
2039
2040 /* if not pci bus, we're done */
2041 if (BUSTYPE(sih->bustype) != PCI_BUS)
2042 return;
2043
2044 if (PCI_FORCEHT(sii))
2045 _si_clkctl_cc(sii, CLK_FAST);
2046
2047 if (PCIE(sii))
2048 pcicore_up(sii->pch, SI_PCIUP);
2049
2050}
2051
2052/* Unconfigure and/or apply various WARs when system is going to sleep mode */
a2627bc0
JC
2053void BCMUNINITFN(si_pci_sleep) (si_t *sih)
2054{
a9533e7e
HP
2055 si_info_t *sii;
2056
2057 sii = SI_INFO(sih);
2058
2059 pcicore_sleep(sii->pch);
2060}
2061
2062/* Unconfigure and/or apply various WARs when going down */
a2627bc0
JC
2063void BCMINITFN(si_pci_down) (si_t *sih)
2064{
a9533e7e
HP
2065 si_info_t *sii;
2066
2067 sii = SI_INFO(sih);
2068
2069 /* if not pci bus, we're done */
2070 if (BUSTYPE(sih->bustype) != PCI_BUS)
2071 return;
2072
2073 /* release FORCEHT since chip is going to "down" state */
2074 if (PCI_FORCEHT(sii))
2075 _si_clkctl_cc(sii, CLK_DYNAMIC);
2076
2077 pcicore_down(sii->pch, SI_PCIDOWN);
2078}
2079
2080/*
2081 * Configure the pci core for pci client (NIC) action
2082 * coremask is the bitvec of cores by index to be enabled.
2083 */
a2627bc0
JC
2084void BCMATTACHFN(si_pci_setup) (si_t *sih, uint coremask)
2085{
a9533e7e
HP
2086 si_info_t *sii;
2087 sbpciregs_t *pciregs = NULL;
2088 uint32 siflag = 0, w;
2089 uint idx = 0;
2090
2091 sii = SI_INFO(sih);
2092
2093 if (BUSTYPE(sii->pub.bustype) != PCI_BUS)
2094 return;
2095
2096 ASSERT(PCI(sii) || PCIE(sii));
2097 ASSERT(sii->pub.buscoreidx != BADIDX);
2098
2099 if (PCI(sii)) {
2100 /* get current core index */
2101 idx = sii->curidx;
2102
2103 /* we interrupt on this backplane flag number */
2104 siflag = si_flag(sih);
2105
2106 /* switch over to pci core */
2107 pciregs =
2108 (sbpciregs_t *) si_setcoreidx(sih, sii->pub.buscoreidx);
2109 }
2110
2111 /*
2112 * Enable sb->pci interrupts. Assume
2113 * PCI rev 2.3 support was added in pci core rev 6 and things changed..
2114 */
2115 if (PCIE(sii) || (PCI(sii) && ((sii->pub.buscorerev) >= 6))) {
2116 /* pci config write to set this core bit in PCIIntMask */
2117 w = OSL_PCI_READ_CONFIG(sii->osh, PCI_INT_MASK, sizeof(uint32));
2118 w |= (coremask << PCI_SBIM_SHIFT);
2119 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_INT_MASK, sizeof(uint32), w);
2120 } else {
2121 /* set sbintvec bit for our flag number */
2122 si_setint(sih, siflag);
2123 }
2124
2125 if (PCI(sii)) {
2126 OR_REG(sii->osh, &pciregs->sbtopci2,
2127 (SBTOPCI_PREF | SBTOPCI_BURST));
2128 if (sii->pub.buscorerev >= 11) {
2129 OR_REG(sii->osh, &pciregs->sbtopci2,
2130 SBTOPCI_RC_READMULTI);
2131 w = R_REG(sii->osh, &pciregs->clkrun);
2132 W_REG(sii->osh, &pciregs->clkrun,
2133 (w | PCI_CLKRUN_DSBL));
2134 w = R_REG(sii->osh, &pciregs->clkrun);
2135 }
2136
2137 /* switch back to previous core */
2138 si_setcoreidx(sih, idx);
2139 }
2140}
2141
7cc4a4c0 2142uint8 si_pcieclkreq(si_t *sih, uint32 mask, uint32 val)
a9533e7e
HP
2143{
2144 si_info_t *sii;
2145
2146 sii = SI_INFO(sih);
2147
2148 if (!(PCIE(sii)))
2149 return 0;
2150 return pcie_clkreq(sii->pch, mask, val);
2151}
2152
7cc4a4c0 2153uint32 si_pcielcreg(si_t *sih, uint32 mask, uint32 val)
a9533e7e
HP
2154{
2155 si_info_t *sii;
2156
2157 sii = SI_INFO(sih);
2158
2159 if (!PCIE(sii))
2160 return 0;
2161
2162 return pcie_lcreg(sii->pch, mask, val);
2163}
2164
2165/* indirect way to read pcie config regs */
2166uint si_pcie_readreg(void *sih, uint addrtype, uint offset)
2167{
2168 return pcie_readreg(((si_info_t *) sih)->osh,
2169 (sbpcieregs_t *) PCIEREGS(((si_info_t *) sih)),
2170 addrtype, offset);
2171}
2172
2173/*
2174 * Fixup SROMless PCI device's configuration.
2175 * The current core may be changed upon return.
2176 */
7cc4a4c0 2177int si_pci_fixcfg(si_t *sih)
a9533e7e
HP
2178{
2179 uint origidx, pciidx;
2180 sbpciregs_t *pciregs = NULL;
2181 sbpcieregs_t *pcieregs = NULL;
2182 void *regs = NULL;
2183 uint16 val16, *reg16 = NULL;
2184
2185 si_info_t *sii = SI_INFO(sih);
2186
2187 ASSERT(BUSTYPE(sii->pub.bustype) == PCI_BUS);
2188
2189 /* Fixup PI in SROM shadow area to enable the correct PCI core access */
2190 /* save the current index */
2191 origidx = si_coreidx(&sii->pub);
2192
2193 /* check 'pi' is correct and fix it if not */
2194 if (sii->pub.buscoretype == PCIE_CORE_ID) {
2195 pcieregs =
2196 (sbpcieregs_t *) si_setcore(&sii->pub, PCIE_CORE_ID, 0);
2197 regs = pcieregs;
2198 ASSERT(pcieregs != NULL);
2199 reg16 = &pcieregs->sprom[SRSH_PI_OFFSET];
2200 } else if (sii->pub.buscoretype == PCI_CORE_ID) {
2201 pciregs = (sbpciregs_t *) si_setcore(&sii->pub, PCI_CORE_ID, 0);
2202 regs = pciregs;
2203 ASSERT(pciregs != NULL);
2204 reg16 = &pciregs->sprom[SRSH_PI_OFFSET];
2205 }
2206 pciidx = si_coreidx(&sii->pub);
2207 val16 = R_REG(sii->osh, reg16);
2208 if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) != (uint16) pciidx) {
2209 val16 =
2210 (uint16) (pciidx << SRSH_PI_SHIFT) | (val16 &
2211 ~SRSH_PI_MASK);
2212 W_REG(sii->osh, reg16, val16);
2213 }
2214
2215 /* restore the original index */
2216 si_setcoreidx(&sii->pub, origidx);
2217
2218 pcicore_hwup(sii->pch);
2219 return 0;
2220}
2221
2222/* change logical "focus" to the gpio core for optimized access */
7cc4a4c0 2223void *si_gpiosetcore(si_t *sih)
a9533e7e 2224{
90ea2296 2225 return si_setcoreidx(sih, SI_CC_IDX);
a9533e7e
HP
2226}
2227
2228/* mask&set gpiocontrol bits */
7cc4a4c0 2229uint32 si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority)
a9533e7e
HP
2230{
2231 uint regoff;
2232
2233 regoff = 0;
2234
2235 /* gpios could be shared on router platforms
2236 * ignore reservation if it's high priority (e.g., test apps)
2237 */
2238 if ((priority != GPIO_HI_PRIORITY) &&
2239 (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
2240 mask = priority ? (si_gpioreservation & mask) :
2241 ((si_gpioreservation | mask) & ~(si_gpioreservation));
2242 val &= mask;
2243 }
2244
2245 regoff = OFFSETOF(chipcregs_t, gpiocontrol);
90ea2296 2246 return si_corereg(sih, SI_CC_IDX, regoff, mask, val);
a9533e7e
HP
2247}
2248
2249/* mask&set gpio output enable bits */
7cc4a4c0 2250uint32 si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority)
a9533e7e
HP
2251{
2252 uint regoff;
2253
2254 regoff = 0;
2255
2256 /* gpios could be shared on router platforms
2257 * ignore reservation if it's high priority (e.g., test apps)
2258 */
2259 if ((priority != GPIO_HI_PRIORITY) &&
2260 (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
2261 mask = priority ? (si_gpioreservation & mask) :
2262 ((si_gpioreservation | mask) & ~(si_gpioreservation));
2263 val &= mask;
2264 }
2265
2266 regoff = OFFSETOF(chipcregs_t, gpioouten);
90ea2296 2267 return si_corereg(sih, SI_CC_IDX, regoff, mask, val);
a9533e7e
HP
2268}
2269
2270/* mask&set gpio output bits */
7cc4a4c0 2271uint32 si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority)
a9533e7e
HP
2272{
2273 uint regoff;
2274
2275 regoff = 0;
2276
2277 /* gpios could be shared on router platforms
2278 * ignore reservation if it's high priority (e.g., test apps)
2279 */
2280 if ((priority != GPIO_HI_PRIORITY) &&
2281 (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
2282 mask = priority ? (si_gpioreservation & mask) :
2283 ((si_gpioreservation | mask) & ~(si_gpioreservation));
2284 val &= mask;
2285 }
2286
2287 regoff = OFFSETOF(chipcregs_t, gpioout);
90ea2296 2288 return si_corereg(sih, SI_CC_IDX, regoff, mask, val);
a9533e7e
HP
2289}
2290
2291/* reserve one gpio */
7cc4a4c0 2292uint32 si_gpioreserve(si_t *sih, uint32 gpio_bitmask, uint8 priority)
a9533e7e
HP
2293{
2294 si_info_t *sii;
2295
2296 sii = SI_INFO(sih);
2297
2298 /* only cores on SI_BUS share GPIO's and only applcation users need to
2299 * reserve/release GPIO
2300 */
2301 if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) {
2302 ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority));
2303 return 0xffffffff;
2304 }
2305 /* make sure only one bit is set */
2306 if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) {
2307 ASSERT((gpio_bitmask)
2308 && !((gpio_bitmask) & (gpio_bitmask - 1)));
2309 return 0xffffffff;
2310 }
2311
2312 /* already reserved */
2313 if (si_gpioreservation & gpio_bitmask)
2314 return 0xffffffff;
2315 /* set reservation */
2316 si_gpioreservation |= gpio_bitmask;
2317
2318 return si_gpioreservation;
2319}
2320
2321/* release one gpio */
2322/*
2323 * releasing the gpio doesn't change the current value on the GPIO last write value
2324 * persists till some one overwrites it
2325 */
2326
7cc4a4c0 2327uint32 si_gpiorelease(si_t *sih, uint32 gpio_bitmask, uint8 priority)
a9533e7e
HP
2328{
2329 si_info_t *sii;
2330
2331 sii = SI_INFO(sih);
2332
2333 /* only cores on SI_BUS share GPIO's and only applcation users need to
2334 * reserve/release GPIO
2335 */
2336 if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) {
2337 ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority));
2338 return 0xffffffff;
2339 }
2340 /* make sure only one bit is set */
2341 if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) {
2342 ASSERT((gpio_bitmask)
2343 && !((gpio_bitmask) & (gpio_bitmask - 1)));
2344 return 0xffffffff;
2345 }
2346
2347 /* already released */
2348 if (!(si_gpioreservation & gpio_bitmask))
2349 return 0xffffffff;
2350
2351 /* clear reservation */
2352 si_gpioreservation &= ~gpio_bitmask;
2353
2354 return si_gpioreservation;
2355}
2356
2357/* return the current gpioin register value */
7cc4a4c0 2358uint32 si_gpioin(si_t *sih)
a9533e7e
HP
2359{
2360 si_info_t *sii;
2361 uint regoff;
2362
2363 sii = SI_INFO(sih);
2364 regoff = 0;
2365
2366 regoff = OFFSETOF(chipcregs_t, gpioin);
90ea2296 2367 return si_corereg(sih, SI_CC_IDX, regoff, 0, 0);
a9533e7e
HP
2368}
2369
2370/* mask&set gpio interrupt polarity bits */
7cc4a4c0 2371uint32 si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority)
a9533e7e
HP
2372{
2373 si_info_t *sii;
2374 uint regoff;
2375
2376 sii = SI_INFO(sih);
2377 regoff = 0;
2378
2379 /* gpios could be shared on router platforms */
2380 if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
2381 mask = priority ? (si_gpioreservation & mask) :
2382 ((si_gpioreservation | mask) & ~(si_gpioreservation));
2383 val &= mask;
2384 }
2385
2386 regoff = OFFSETOF(chipcregs_t, gpiointpolarity);
90ea2296 2387 return si_corereg(sih, SI_CC_IDX, regoff, mask, val);
a9533e7e
HP
2388}
2389
2390/* mask&set gpio interrupt mask bits */
7cc4a4c0 2391uint32 si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority)
a9533e7e
HP
2392{
2393 si_info_t *sii;
2394 uint regoff;
2395
2396 sii = SI_INFO(sih);
2397 regoff = 0;
2398
2399 /* gpios could be shared on router platforms */
2400 if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
2401 mask = priority ? (si_gpioreservation & mask) :
2402 ((si_gpioreservation | mask) & ~(si_gpioreservation));
2403 val &= mask;
2404 }
2405
2406 regoff = OFFSETOF(chipcregs_t, gpiointmask);
90ea2296 2407 return si_corereg(sih, SI_CC_IDX, regoff, mask, val);
a9533e7e
HP
2408}
2409
2410/* assign the gpio to an led */
7cc4a4c0 2411uint32 si_gpioled(si_t *sih, uint32 mask, uint32 val)
a9533e7e
HP
2412{
2413 si_info_t *sii;
2414
2415 sii = SI_INFO(sih);
2416 if (sih->ccrev < 16)
2417 return 0xffffffff;
2418
2419 /* gpio led powersave reg */
90ea2296 2420 return si_corereg
a9533e7e 2421 (sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask,
90ea2296 2422 val);
a9533e7e
HP
2423}
2424
2425/* mask&set gpio timer val */
7cc4a4c0 2426uint32 si_gpiotimerval(si_t *sih, uint32 mask, uint32 gpiotimerval)
a9533e7e
HP
2427{
2428 si_info_t *sii;
2429
2430 sii = SI_INFO(sih);
2431
2432 if (sih->ccrev < 16)
2433 return 0xffffffff;
2434
90ea2296 2435 return si_corereg(sih, SI_CC_IDX,
a9533e7e 2436 OFFSETOF(chipcregs_t, gpiotimerval), mask,
90ea2296 2437 gpiotimerval);
a9533e7e
HP
2438}
2439
7cc4a4c0 2440uint32 si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val)
a9533e7e
HP
2441{
2442 si_info_t *sii;
2443 uint offs;
2444
2445 sii = SI_INFO(sih);
2446 if (sih->ccrev < 20)
2447 return 0xffffffff;
2448
2449 offs =
2450 (updown ? OFFSETOF(chipcregs_t, gpiopulldown) :
2451 OFFSETOF(chipcregs_t, gpiopullup));
90ea2296 2452 return si_corereg(sih, SI_CC_IDX, offs, mask, val);
a9533e7e
HP
2453}
2454
7cc4a4c0 2455uint32 si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val)
a9533e7e
HP
2456{
2457 si_info_t *sii;
2458 uint offs;
2459
2460 sii = SI_INFO(sih);
2461 if (sih->ccrev < 11)
2462 return 0xffffffff;
2463
2464 if (regtype == GPIO_REGEVT)
2465 offs = OFFSETOF(chipcregs_t, gpioevent);
2466 else if (regtype == GPIO_REGEVT_INTMSK)
2467 offs = OFFSETOF(chipcregs_t, gpioeventintmask);
2468 else if (regtype == GPIO_REGEVT_INTPOL)
2469 offs = OFFSETOF(chipcregs_t, gpioeventintpolarity);
2470 else
2471 return 0xffffffff;
2472
90ea2296 2473 return si_corereg(sih, SI_CC_IDX, offs, mask, val);
a9533e7e
HP
2474}
2475
7cc4a4c0 2476void *BCMATTACHFN(si_gpio_handler_register) (si_t *sih, uint32 event,
a9533e7e
HP
2477 bool level, gpio_handler_t cb,
2478 void *arg) {
2479 si_info_t *sii;
2480 gpioh_item_t *gi;
2481
2482 ASSERT(event);
2483 ASSERT(cb != NULL);
2484
2485 sii = SI_INFO(sih);
2486 if (sih->ccrev < 11)
2487 return NULL;
2488
ca8c1e59
JC
2489 gi = MALLOC(sii->osh, sizeof(gpioh_item_t));
2490 if (gi == NULL)
a9533e7e
HP
2491 return NULL;
2492
2493 bzero(gi, sizeof(gpioh_item_t));
2494 gi->event = event;
2495 gi->handler = cb;
2496 gi->arg = arg;
2497 gi->level = level;
2498
2499 gi->next = sii->gpioh_head;
2500 sii->gpioh_head = gi;
2501
2502 return (void *)(gi);
2503}
2504
a2627bc0
JC
2505void BCMATTACHFN(si_gpio_handler_unregister) (si_t *sih, void *gpioh)
2506{
a9533e7e
HP
2507 si_info_t *sii;
2508 gpioh_item_t *p, *n;
2509
2510 sii = SI_INFO(sih);
2511 if (sih->ccrev < 11)
2512 return;
2513
2514 ASSERT(sii->gpioh_head != NULL);
2515 if ((void *)sii->gpioh_head == gpioh) {
2516 sii->gpioh_head = sii->gpioh_head->next;
2517 MFREE(sii->osh, gpioh, sizeof(gpioh_item_t));
2518 return;
2519 } else {
2520 p = sii->gpioh_head;
2521 n = p->next;
2522 while (n) {
2523 if ((void *)n == gpioh) {
2524 p->next = n->next;
2525 MFREE(sii->osh, gpioh, sizeof(gpioh_item_t));
2526 return;
2527 }
2528 p = n;
2529 n = n->next;
2530 }
2531 }
2532
2533 ASSERT(0); /* Not found in list */
2534}
2535
7cc4a4c0 2536void si_gpio_handler_process(si_t *sih)
a9533e7e
HP
2537{
2538 si_info_t *sii;
2539 gpioh_item_t *h;
2540 uint32 status;
2541 uint32 level = si_gpioin(sih);
2542 uint32 edge = si_gpioevent(sih, GPIO_REGEVT, 0, 0);
2543
2544 sii = SI_INFO(sih);
2545 for (h = sii->gpioh_head; h != NULL; h = h->next) {
2546 if (h->handler) {
2547 status = (h->level ? level : edge);
2548
2549 if (status & h->event)
2550 h->handler(status, h->arg);
2551 }
2552 }
2553
2554 si_gpioevent(sih, GPIO_REGEVT, edge, edge); /* clear edge-trigger status */
2555}
2556
7cc4a4c0 2557uint32 si_gpio_int_enable(si_t *sih, bool enable)
a9533e7e
HP
2558{
2559 si_info_t *sii;
2560 uint offs;
2561
2562 sii = SI_INFO(sih);
2563 if (sih->ccrev < 11)
2564 return 0xffffffff;
2565
2566 offs = OFFSETOF(chipcregs_t, intmask);
90ea2296
JC
2567 return si_corereg
2568 (sih, SI_CC_IDX, offs, CI_GPIO, (enable ? CI_GPIO : 0));
a9533e7e
HP
2569}
2570
2571/* Return the size of the specified SOCRAM bank */
2572static uint
7cc4a4c0 2573socram_banksize(si_info_t *sii, sbsocramregs_t *regs, uint8 index,
a9533e7e
HP
2574 uint8 mem_type)
2575{
2576 uint banksize, bankinfo;
2577 uint bankidx = index | (mem_type << SOCRAM_BANKIDX_MEMTYPE_SHIFT);
2578
2579 ASSERT(mem_type <= SOCRAM_MEMTYPE_DEVRAM);
2580
2581 W_REG(sii->osh, &regs->bankidx, bankidx);
2582 bankinfo = R_REG(sii->osh, &regs->bankinfo);
2583 banksize =
2584 SOCRAM_BANKINFO_SZBASE * ((bankinfo & SOCRAM_BANKINFO_SZMASK) + 1);
2585 return banksize;
2586}
2587
7cc4a4c0 2588void si_socdevram(si_t *sih, bool set, uint8 *enable, uint8 *protect)
a9533e7e
HP
2589{
2590 si_info_t *sii;
2591 uint origidx;
2592 uint intr_val = 0;
2593 sbsocramregs_t *regs;
2594 bool wasup;
2595 uint corerev;
2596
2597 sii = SI_INFO(sih);
2598
2599 /* Block ints and save current core */
2600 INTR_OFF(sii, intr_val);
2601 origidx = si_coreidx(sih);
2602
2603 if (!set)
2604 *enable = *protect = 0;
2605
2606 /* Switch to SOCRAM core */
ca8c1e59
JC
2607 regs = si_setcore(sih, SOCRAM_CORE_ID, 0);
2608 if (!regs)
a9533e7e
HP
2609 goto done;
2610
2611 /* Get info for determining size */
ca8c1e59
JC
2612 wasup = si_iscoreup(sih);
2613 if (!wasup)
a9533e7e
HP
2614 si_core_reset(sih, 0, 0);
2615
2616 corerev = si_corerev(sih);
2617 if (corerev >= 10) {
2618 uint32 extcinfo;
2619 uint8 nb;
2620 uint8 i;
2621 uint32 bankidx, bankinfo;
2622
2623 extcinfo = R_REG(sii->osh, &regs->extracoreinfo);
2624 nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >>
2625 SOCRAM_DEVRAMBANK_SHIFT);
2626 for (i = 0; i < nb; i++) {
2627 bankidx =
2628 i | (SOCRAM_MEMTYPE_DEVRAM <<
2629 SOCRAM_BANKIDX_MEMTYPE_SHIFT);
2630 W_REG(sii->osh, &regs->bankidx, bankidx);
2631 bankinfo = R_REG(sii->osh, &regs->bankinfo);
2632 if (set) {
2633 bankinfo &= ~SOCRAM_BANKINFO_DEVRAMSEL_MASK;
2634 bankinfo &= ~SOCRAM_BANKINFO_DEVRAMPRO_MASK;
2635 if (*enable) {
2636 bankinfo |=
2637 (1 <<
2638 SOCRAM_BANKINFO_DEVRAMSEL_SHIFT);
2639 if (*protect)
2640 bankinfo |=
2641 (1 <<
2642 SOCRAM_BANKINFO_DEVRAMPRO_SHIFT);
2643 }
2644 W_REG(sii->osh, &regs->bankinfo, bankinfo);
2645 } else if (i == 0) {
2646 if (bankinfo & SOCRAM_BANKINFO_DEVRAMSEL_MASK) {
2647 *enable = 1;
2648 if (bankinfo &
2649 SOCRAM_BANKINFO_DEVRAMPRO_MASK)
2650 *protect = 1;
2651 }
2652 }
2653 }
2654 }
2655
2656 /* Return to previous state and core */
2657 if (!wasup)
2658 si_core_disable(sih, 0);
2659 si_setcoreidx(sih, origidx);
2660
2661 done:
2662 INTR_RESTORE(sii, intr_val);
2663}
2664
7cc4a4c0 2665bool si_socdevram_pkg(si_t *sih)
a9533e7e
HP
2666{
2667 if (si_socdevram_size(sih) > 0)
2668 return TRUE;
2669 else
2670 return FALSE;
2671}
2672
7cc4a4c0 2673uint32 si_socdevram_size(si_t *sih)
a9533e7e
HP
2674{
2675 si_info_t *sii;
2676 uint origidx;
2677 uint intr_val = 0;
2678 uint32 memsize = 0;
2679 sbsocramregs_t *regs;
2680 bool wasup;
2681 uint corerev;
2682
2683 sii = SI_INFO(sih);
2684
2685 /* Block ints and save current core */
2686 INTR_OFF(sii, intr_val);
2687 origidx = si_coreidx(sih);
2688
2689 /* Switch to SOCRAM core */
ca8c1e59
JC
2690 regs = si_setcore(sih, SOCRAM_CORE_ID, 0);
2691 if (!regs)
a9533e7e
HP
2692 goto done;
2693
2694 /* Get info for determining size */
ca8c1e59
JC
2695 wasup = si_iscoreup(sih);
2696 if (!wasup)
a9533e7e
HP
2697 si_core_reset(sih, 0, 0);
2698
2699 corerev = si_corerev(sih);
2700 if (corerev >= 10) {
2701 uint32 extcinfo;
2702 uint8 nb;
2703 uint8 i;
2704
2705 extcinfo = R_REG(sii->osh, &regs->extracoreinfo);
2706 nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >>
2707 SOCRAM_DEVRAMBANK_SHIFT));
2708 for (i = 0; i < nb; i++)
2709 memsize +=
2710 socram_banksize(sii, regs, i,
2711 SOCRAM_MEMTYPE_DEVRAM);
2712 }
2713
2714 /* Return to previous state and core */
2715 if (!wasup)
2716 si_core_disable(sih, 0);
2717 si_setcoreidx(sih, origidx);
2718
2719 done:
2720 INTR_RESTORE(sii, intr_val);
2721
2722 return memsize;
2723}
2724
2725/* Return the RAM size of the SOCRAM core */
7cc4a4c0 2726uint32 si_socram_size(si_t *sih)
a9533e7e
HP
2727{
2728 si_info_t *sii;
2729 uint origidx;
2730 uint intr_val = 0;
2731
2732 sbsocramregs_t *regs;
2733 bool wasup;
2734 uint corerev;
2735 uint32 coreinfo;
2736 uint memsize = 0;
2737
2738 sii = SI_INFO(sih);
2739
2740 /* Block ints and save current core */
2741 INTR_OFF(sii, intr_val);
2742 origidx = si_coreidx(sih);
2743
2744 /* Switch to SOCRAM core */
ca8c1e59
JC
2745 regs = si_setcore(sih, SOCRAM_CORE_ID, 0);
2746 if (!regs)
a9533e7e
HP
2747 goto done;
2748
2749 /* Get info for determining size */
ca8c1e59
JC
2750 wasup = si_iscoreup(sih);
2751 if (!wasup)
a9533e7e
HP
2752 si_core_reset(sih, 0, 0);
2753 corerev = si_corerev(sih);
2754 coreinfo = R_REG(sii->osh, &regs->coreinfo);
2755
2756 /* Calculate size from coreinfo based on rev */
2757 if (corerev == 0)
2758 memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK));
2759 else if (corerev < 3) {
2760 memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK));
2761 memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
2762 } else if ((corerev <= 7) || (corerev == 12)) {
2763 uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
2764 uint bsz = (coreinfo & SRCI_SRBSZ_MASK);
2765 uint lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT;
2766 if (lss != 0)
2767 nb--;
2768 memsize = nb * (1 << (bsz + SR_BSZ_BASE));
2769 if (lss != 0)
2770 memsize += (1 << ((lss - 1) + SR_BSZ_BASE));
2771 } else {
2772 uint8 i;
2773 uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
2774 for (i = 0; i < nb; i++)
2775 memsize +=
2776 socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM);
2777 }
2778
2779 /* Return to previous state and core */
2780 if (!wasup)
2781 si_core_disable(sih, 0);
2782 si_setcoreidx(sih, origidx);
2783
2784 done:
2785 INTR_RESTORE(sii, intr_val);
2786
2787 return memsize;
2788}
2789
7cc4a4c0 2790void si_chipcontrl_epa4331(si_t *sih, bool on)
a9533e7e
HP
2791{
2792 si_info_t *sii;
2793 chipcregs_t *cc;
2794 uint origidx;
2795 uint32 val;
2796
2797 sii = SI_INFO(sih);
2798 origidx = si_coreidx(sih);
2799
2800 cc = (chipcregs_t *) si_setcore(sih, CC_CORE_ID, 0);
2801
2802 val = R_REG(sii->osh, &cc->chipcontrol);
2803
2804 if (on) {
2805 if (sih->chippkg == 9 || sih->chippkg == 0xb) {
2806 /* Ext PA Controls for 4331 12x9 Package */
2807 W_REG(sii->osh, &cc->chipcontrol, val |
2808 (CCTRL4331_EXTPA_EN |
2809 CCTRL4331_EXTPA_ON_GPIO2_5));
2810 } else {
2811 /* Ext PA Controls for 4331 12x12 Package */
2812 W_REG(sii->osh, &cc->chipcontrol,
2813 val | (CCTRL4331_EXTPA_EN));
2814 }
2815 } else {
2816 val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5);
2817 W_REG(sii->osh, &cc->chipcontrol, val);
2818 }
2819
2820 si_setcoreidx(sih, origidx);
2821}
2822
2823/* Enable BT-COEX & Ex-PA for 4313 */
7cc4a4c0 2824void si_epa_4313war(si_t *sih)
a9533e7e
HP
2825{
2826 si_info_t *sii;
2827 chipcregs_t *cc;
2828 uint origidx;
2829
2830 sii = SI_INFO(sih);
2831 origidx = si_coreidx(sih);
2832
2833 cc = (chipcregs_t *) si_setcore(sih, CC_CORE_ID, 0);
2834
2835 /* EPA Fix */
2836 W_REG(sii->osh, &cc->gpiocontrol,
2837 R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_EPA_EN_MASK);
2838
2839 si_setcoreidx(sih, origidx);
2840}
2841
2842/* check if the device is removed */
7cc4a4c0 2843bool si_deviceremoved(si_t *sih)
a9533e7e
HP
2844{
2845 uint32 w;
2846 si_info_t *sii;
2847
2848 sii = SI_INFO(sih);
2849
2850 switch (BUSTYPE(sih->bustype)) {
2851 case PCI_BUS:
2852 ASSERT(sii->osh != NULL);
2853 w = OSL_PCI_READ_CONFIG(sii->osh, PCI_CFG_VID, sizeof(uint32));
2854 if ((w & 0xFFFF) != VENDOR_BROADCOM)
2855 return TRUE;
2856 break;
2857 }
2858 return FALSE;
2859}
2860
7cc4a4c0 2861bool si_is_sprom_available(si_t *sih)
a9533e7e
HP
2862{
2863 if (sih->ccrev >= 31) {
2864 si_info_t *sii;
2865 uint origidx;
2866 chipcregs_t *cc;
2867 uint32 sromctrl;
2868
2869 if ((sih->cccaps & CC_CAP_SROM) == 0)
2870 return FALSE;
2871
2872 sii = SI_INFO(sih);
2873 origidx = sii->curidx;
2874 cc = si_setcoreidx(sih, SI_CC_IDX);
2875 sromctrl = R_REG(sii->osh, &cc->sromcontrol);
2876 si_setcoreidx(sih, origidx);
90ea2296 2877 return sromctrl & SRC_PRESENT;
a9533e7e
HP
2878 }
2879
2880 switch (CHIPID(sih->chip)) {
2881 case BCM4329_CHIP_ID:
2882 return (sih->chipst & CST4329_SPROM_SEL) != 0;
2883 case BCM4319_CHIP_ID:
2884 return (sih->chipst & CST4319_SPROM_SEL) != 0;
2885 case BCM4336_CHIP_ID:
2886 return (sih->chipst & CST4336_SPROM_PRESENT) != 0;
2887 case BCM4330_CHIP_ID:
2888 return (sih->chipst & CST4330_SPROM_PRESENT) != 0;
2889 case BCM4313_CHIP_ID:
2890 return (sih->chipst & CST4313_SPROM_PRESENT) != 0;
2891 case BCM4331_CHIP_ID:
2892 return (sih->chipst & CST4331_SPROM_PRESENT) != 0;
2893 default:
2894 return TRUE;
2895 }
2896}
2897
7cc4a4c0 2898bool si_is_otp_disabled(si_t *sih)
a9533e7e
HP
2899{
2900 switch (CHIPID(sih->chip)) {
2901 case BCM4329_CHIP_ID:
2902 return (sih->chipst & CST4329_SPROM_OTP_SEL_MASK) ==
2903 CST4329_OTP_PWRDN;
2904 case BCM4319_CHIP_ID:
2905 return (sih->chipst & CST4319_SPROM_OTP_SEL_MASK) ==
2906 CST4319_OTP_PWRDN;
2907 case BCM4336_CHIP_ID:
90ea2296 2908 return (sih->chipst & CST4336_OTP_PRESENT) == 0;
a9533e7e 2909 case BCM4330_CHIP_ID:
90ea2296 2910 return (sih->chipst & CST4330_OTP_PRESENT) == 0;
a9533e7e
HP
2911 case BCM4313_CHIP_ID:
2912 return (sih->chipst & CST4313_OTP_PRESENT) == 0;
2913 /* These chips always have their OTP on */
2914 case BCM43224_CHIP_ID:
2915 case BCM43225_CHIP_ID:
2916 case BCM43421_CHIP_ID:
2917 case BCM43235_CHIP_ID:
2918 case BCM43236_CHIP_ID:
2919 case BCM43238_CHIP_ID:
2920 case BCM4331_CHIP_ID:
2921 default:
2922 return FALSE;
2923 }
2924}
2925
7cc4a4c0 2926bool si_is_otp_powered(si_t *sih)
a9533e7e
HP
2927{
2928 if (PMUCTL_ENAB(sih))
2929 return si_pmu_is_otp_powered(sih, si_osh(sih));
2930 return TRUE;
2931}
2932
7cc4a4c0 2933void si_otp_power(si_t *sih, bool on)
a9533e7e
HP
2934{
2935 if (PMUCTL_ENAB(sih))
2936 si_pmu_otp_power(sih, si_osh(sih), on);
2937 OSL_DELAY(1000);
2938}
2939
2940bool
2941#if defined(BCMDBG)
7cc4a4c0 2942si_is_sprom_enabled(si_t *sih)
a9533e7e 2943#else
7cc4a4c0 2944BCMATTACHFN(si_is_sprom_enabled) (si_t *sih)
a9533e7e
HP
2945#endif
2946{
2947
2948 return TRUE;
2949}
2950
2951void
2952#if defined(BCMDBG)
7cc4a4c0 2953si_sprom_enable(si_t *sih, bool enable)
a9533e7e 2954#else
7cc4a4c0 2955BCMATTACHFN(si_sprom_enable) (si_t *sih, bool enable)
a9533e7e
HP
2956#endif
2957{
2958 if (PMUCTL_ENAB(sih))
2959 si_pmu_sprom_enable(sih, si_osh(sih), enable);
2960}
2961
2962/* Return BCME_NOTFOUND if the card doesn't have CIS format nvram */
7cc4a4c0 2963int si_cis_source(si_t *sih)
a9533e7e
HP
2964{
2965 /* Many chips have the same mapping of their chipstatus field */
e5c4536f
JC
2966 static const uint cis_sel[] = {
2967 CIS_DEFAULT, CIS_SROM, CIS_OTP, CIS_SROM };
2968 static const uint cis_43236_sel[] = {
2969 CIS_DEFAULT, CIS_SROM, CIS_OTP, CIS_OTP };
a9533e7e
HP
2970
2971 /* PCI chips use SROM format instead of CIS */
2972 if (BUSTYPE(sih->bustype) == PCI_BUS)
2973 return BCME_NOTFOUND;
2974
2975 switch (CHIPID(sih->chip)) {
2976 case BCM43235_CHIP_ID:
2977 case BCM43236_CHIP_ID:
2978 case BCM43238_CHIP_ID:{
2979 uint8 strap =
2980 (sih->
2981 chipst & CST4322_SPROM_OTP_SEL_MASK) >>
2982 CST4322_SPROM_OTP_SEL_SHIFT;
2983 return ((strap >=
2984 sizeof(cis_sel)) ? CIS_DEFAULT :
2985 cis_43236_sel[strap]);
2986 }
2987
2988 case BCM4329_CHIP_ID:
2989 return ((sih->chipst & CST4329_SPROM_OTP_SEL_MASK) >=
2990 sizeof(cis_sel)) ? CIS_DEFAULT : cis_sel[(sih->
2991 chipst &
2992 CST4329_SPROM_OTP_SEL_MASK)];
2993 case BCM4319_CHIP_ID:{
2994 uint cis_sel4319 =
2995 ((sih->
2996 chipst & CST4319_SPROM_OTP_SEL_MASK) >>
2997 CST4319_SPROM_OTP_SEL_SHIFT);
2998 return (cis_sel4319 >=
2999 sizeof(cis_sel)) ? CIS_DEFAULT :
3000 cis_sel[cis_sel4319];
3001 }
3002 case BCM4336_CHIP_ID:{
3003 if (sih->chipst & CST4336_SPROM_PRESENT)
3004 return CIS_SROM;
3005 if (sih->chipst & CST4336_OTP_PRESENT)
3006 return CIS_OTP;
3007 return CIS_DEFAULT;
3008 }
3009 case BCM4330_CHIP_ID:{
3010 if (sih->chipst & CST4330_SPROM_PRESENT)
3011 return CIS_SROM;
3012 if (sih->chipst & CST4330_OTP_PRESENT)
3013 return CIS_OTP;
3014 return CIS_DEFAULT;
3015 }
3016 default:
3017 return CIS_DEFAULT;
3018 }
3019}
This page took 0.156931 seconds and 5 git commands to generate.