aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcmdhd/siutils.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/net/wireless/bcmdhd/siutils.c
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/net/wireless/bcmdhd/siutils.c')
-rw-r--r--drivers/net/wireless/bcmdhd/siutils.c1720
1 files changed, 1720 insertions, 0 deletions
diff --git a/drivers/net/wireless/bcmdhd/siutils.c b/drivers/net/wireless/bcmdhd/siutils.c
new file mode 100644
index 00000000000..22aa4126576
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/siutils.c
@@ -0,0 +1,1720 @@
1/*
2 * Misc utility routines for accessing chip-specific features
3 * of the SiliconBackplane-based Broadcom chips.
4 *
5 * Copyright (C) 1999-2011, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 * $Id: siutils.c,v 1.813.2.36 2011-02-10 23:43:55 Exp $
26 */
27
28#include <typedefs.h>
29#include <bcmdefs.h>
30#include <osl.h>
31#include <bcmutils.h>
32#include <siutils.h>
33#include <bcmdevs.h>
34#include <hndsoc.h>
35#include <sbchipc.h>
36#include <pcicfg.h>
37#include <sbpcmcia.h>
38#include <sbsocram.h>
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#include <hndpmu.h>
46
47#include "siutils_priv.h"
48
49/* local prototypes */
50static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs,
51 uint bustype, void *sdh, char **vars, uint *varsz);
52static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh);
53static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin,
54 uint *origidx, void *regs);
55
56
57/* global variable to indicate reservation/release of gpio's */
58static uint32 si_gpioreservation = 0;
59
60/* global flag to prevent shared resources from being initialized multiple times in si_attach() */
61
62/*
63 * Allocate a si handle.
64 * devid - pci device id (used to determine chip#)
65 * osh - opaque OS handle
66 * regs - virtual address of initial core registers
67 * bustype - pci/pcmcia/sb/sdio/etc
68 * vars - pointer to a pointer area for "environment" variables
69 * varsz - pointer to int to return the size of the vars
70 */
71si_t *
72si_attach(uint devid, osl_t *osh, void *regs,
73 uint bustype, void *sdh, char **vars, uint *varsz)
74{
75 si_info_t *sii;
76
77 /* alloc si_info_t */
78 if ((sii = MALLOC(osh, sizeof (si_info_t))) == NULL) {
79 SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh)));
80 return (NULL);
81 }
82
83 if (si_doattach(sii, devid, osh, regs, bustype, sdh, vars, varsz) == NULL) {
84 MFREE(osh, sii, sizeof(si_info_t));
85 return (NULL);
86 }
87 sii->vars = vars ? *vars : NULL;
88 sii->varsz = varsz ? *varsz : 0;
89
90 return (si_t *)sii;
91}
92
93/* global kernel resource */
94static si_info_t ksii;
95
96static uint32 wd_msticks; /* watchdog timer ticks normalized to ms */
97
98/* generic kernel variant of si_attach() */
99si_t *
100si_kattach(osl_t *osh)
101{
102 static bool ksii_attached = FALSE;
103
104 if (!ksii_attached) {
105 void *regs;
106 regs = REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE);
107
108 if (si_doattach(&ksii, BCM4710_DEVICE_ID, osh, regs,
109 SI_BUS, NULL,
110 osh != SI_OSH ? &ksii.vars : NULL,
111 osh != SI_OSH ? &ksii.varsz : NULL) == NULL) {
112 SI_ERROR(("si_kattach: si_doattach failed\n"));
113 REG_UNMAP(regs);
114 return NULL;
115 }
116 REG_UNMAP(regs);
117
118 /* save ticks normalized to ms for si_watchdog_ms() */
119 if (PMUCTL_ENAB(&ksii.pub)) {
120 /* based on 32KHz ILP clock */
121 wd_msticks = 32;
122 } else {
123 wd_msticks = ALP_CLOCK / 1000;
124 }
125
126 ksii_attached = TRUE;
127 SI_MSG(("si_kattach done. ccrev = %d, wd_msticks = %d\n",
128 ksii.pub.ccrev, wd_msticks));
129 }
130
131 return &ksii.pub;
132}
133
134
135static bool
136si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh)
137{
138 /* need to set memseg flag for CF card first before any sb registers access */
139 if (BUSTYPE(bustype) == PCMCIA_BUS)
140 sii->memseg = TRUE;
141
142
143 if (BUSTYPE(bustype) == SDIO_BUS) {
144 int err;
145 uint8 clkset;
146
147 /* Try forcing SDIO core to do ALPAvail request only */
148 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
149 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
150 if (!err) {
151 uint8 clkval;
152
153 /* If register supported, wait for ALPAvail and then force ALP */
154 clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, NULL);
155 if ((clkval & ~SBSDIO_AVBITS) == clkset) {
156 SPINWAIT(((clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
157 SBSDIO_FUNC1_CHIPCLKCSR, NULL)), !SBSDIO_ALPAV(clkval)),
158 PMU_MAX_TRANSITION_DLY);
159 if (!SBSDIO_ALPAV(clkval)) {
160 SI_ERROR(("timeout on ALPAV wait, clkval 0x%02x\n",
161 clkval));
162 return FALSE;
163 }
164 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
165 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
166 clkset, &err);
167 OSL_DELAY(65);
168 }
169 }
170
171 /* Also, disable the extra SDIO pull-ups */
172 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
173 }
174
175
176 return TRUE;
177}
178
179static bool
180si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin,
181 uint *origidx, void *regs)
182{
183 bool pci, pcie;
184 uint i;
185 uint pciidx, pcieidx, pcirev, pcierev;
186
187 cc = si_setcoreidx(&sii->pub, SI_CC_IDX);
188 ASSERT((uintptr)cc);
189
190 /* get chipcommon rev */
191 sii->pub.ccrev = (int)si_corerev(&sii->pub);
192
193 /* get chipcommon chipstatus */
194 if (sii->pub.ccrev >= 11)
195 sii->pub.chipst = R_REG(sii->osh, &cc->chipstatus);
196
197 /* get chipcommon capabilites */
198 sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities);
199 /* get chipcommon extended capabilities */
200
201 if (sii->pub.ccrev >= 35)
202 sii->pub.cccaps_ext = R_REG(sii->osh, &cc->capabilities_ext);
203
204 /* get pmu rev and caps */
205 if (sii->pub.cccaps & CC_CAP_PMU) {
206 sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities);
207 sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK;
208 }
209
210 SI_MSG(("Chipc: rev %d, caps 0x%x, chipst 0x%x pmurev %d, pmucaps 0x%x\n",
211 sii->pub.ccrev, sii->pub.cccaps, sii->pub.chipst, sii->pub.pmurev,
212 sii->pub.pmucaps));
213
214 /* figure out bus/orignal core idx */
215 sii->pub.buscoretype = NODEV_CORE_ID;
216 sii->pub.buscorerev = NOREV;
217 sii->pub.buscoreidx = BADIDX;
218
219 pci = pcie = FALSE;
220 pcirev = pcierev = NOREV;
221 pciidx = pcieidx = BADIDX;
222
223 for (i = 0; i < sii->numcores; i++) {
224 uint cid, crev;
225
226 si_setcoreidx(&sii->pub, i);
227 cid = si_coreid(&sii->pub);
228 crev = si_corerev(&sii->pub);
229
230 /* Display cores found */
231 SI_VMSG(("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n",
232 i, cid, crev, sii->coresba[i], sii->regs[i]));
233
234 if (BUSTYPE(bustype) == PCI_BUS) {
235 if (cid == PCI_CORE_ID) {
236 pciidx = i;
237 pcirev = crev;
238 pci = TRUE;
239 } else if (cid == PCIE_CORE_ID) {
240 pcieidx = i;
241 pcierev = crev;
242 pcie = TRUE;
243 }
244 } else if ((BUSTYPE(bustype) == PCMCIA_BUS) &&
245 (cid == PCMCIA_CORE_ID)) {
246 sii->pub.buscorerev = crev;
247 sii->pub.buscoretype = cid;
248 sii->pub.buscoreidx = i;
249 }
250 else if (((BUSTYPE(bustype) == SDIO_BUS) ||
251 (BUSTYPE(bustype) == SPI_BUS)) &&
252 ((cid == PCMCIA_CORE_ID) ||
253 (cid == SDIOD_CORE_ID))) {
254 sii->pub.buscorerev = crev;
255 sii->pub.buscoretype = cid;
256 sii->pub.buscoreidx = i;
257 }
258
259 /* find the core idx before entering this func. */
260 if ((savewin && (savewin == sii->coresba[i])) ||
261 (regs == sii->regs[i]))
262 *origidx = i;
263 }
264
265 if (pci) {
266 sii->pub.buscoretype = PCI_CORE_ID;
267 sii->pub.buscorerev = pcirev;
268 sii->pub.buscoreidx = pciidx;
269 } else if (pcie) {
270 sii->pub.buscoretype = PCIE_CORE_ID;
271 sii->pub.buscorerev = pcierev;
272 sii->pub.buscoreidx = pcieidx;
273 }
274
275 SI_VMSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, sii->pub.buscoretype,
276 sii->pub.buscorerev));
277
278 if (BUSTYPE(sii->pub.bustype) == SI_BUS && (CHIPID(sii->pub.chip) == BCM4712_CHIP_ID) &&
279 (sii->pub.chippkg != BCM4712LARGE_PKG_ID) && (CHIPREV(sii->pub.chiprev) <= 3))
280 OR_REG(sii->osh, &cc->slow_clk_ctl, SCC_SS_XTAL);
281
282
283 /* Make sure any on-chip ARM is off (in case strapping is wrong), or downloaded code was
284 * already running.
285 */
286 if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) {
287 if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) ||
288 si_setcore(&sii->pub, ARMCM3_CORE_ID, 0))
289 si_core_disable(&sii->pub, 0);
290 }
291
292 /* return to the original core */
293 si_setcoreidx(&sii->pub, *origidx);
294
295 return TRUE;
296}
297
298
299
300static si_info_t *
301si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs,
302 uint bustype, void *sdh, char **vars, uint *varsz)
303{
304 struct si_pub *sih = &sii->pub;
305 uint32 w, savewin;
306 chipcregs_t *cc;
307 char *pvars = NULL;
308 uint origidx;
309
310 ASSERT(GOODREGS(regs));
311
312 bzero((uchar*)sii, sizeof(si_info_t));
313
314 savewin = 0;
315
316 sih->buscoreidx = BADIDX;
317
318 sii->curmap = regs;
319 sii->sdh = sdh;
320 sii->osh = osh;
321
322
323
324 /* find Chipcommon address */
325 if (bustype == PCI_BUS) {
326 savewin = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32));
327 if (!GOODCOREADDR(savewin, SI_ENUM_BASE))
328 savewin = SI_ENUM_BASE;
329 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, SI_ENUM_BASE);
330 cc = (chipcregs_t *)regs;
331 } else if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) {
332 cc = (chipcregs_t *)sii->curmap;
333 } else {
334 cc = (chipcregs_t *)REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE);
335 }
336
337 sih->bustype = bustype;
338 if (bustype != BUSTYPE(bustype)) {
339 SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n",
340 bustype, BUSTYPE(bustype)));
341 return NULL;
342 }
343
344 /* bus/core/clk setup for register access */
345 if (!si_buscore_prep(sii, bustype, devid, sdh)) {
346 SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", bustype));
347 return NULL;
348 }
349
350 /* ChipID recognition.
351 * We assume we can read chipid at offset 0 from the regs arg.
352 * If we add other chiptypes (or if we need to support old sdio hosts w/o chipcommon),
353 * some way of recognizing them needs to be added here.
354 */
355 w = R_REG(osh, &cc->chipid);
356 sih->socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
357 /* Might as wll fill in chip id rev & pkg */
358 sih->chip = w & CID_ID_MASK;
359 sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT;
360 sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT;
361 if (CHIPID(sih->chip) == BCM4322_CHIP_ID && (((sih->chipst & CST4322_SPROM_OTP_SEL_MASK)
362 >> CST4322_SPROM_OTP_SEL_SHIFT) == (CST4322_OTP_PRESENT |
363 CST4322_SPROM_PRESENT))) {
364 SI_ERROR(("%s: Invalid setting: both SPROM and OTP strapped.\n", __FUNCTION__));
365 return NULL;
366 }
367
368 if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chiprev == 0) &&
369 (sih->chippkg != BCM4329_289PIN_PKG_ID)) {
370 sih->chippkg = BCM4329_182PIN_PKG_ID;
371 }
372
373 sih->issim = IS_SIM(sih->chippkg);
374
375 /* scan for cores */
376 if (CHIPTYPE(sii->pub.socitype) == SOCI_SB) {
377 SI_MSG(("Found chip type SB (0x%08x)\n", w));
378 sb_scan(&sii->pub, regs, devid);
379 } else if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) {
380 SI_MSG(("Found chip type AI (0x%08x)\n", w));
381 /* pass chipc address instead of original core base */
382 ai_scan(&sii->pub, (void *)(uintptr)cc, devid);
383 } else if (CHIPTYPE(sii->pub.socitype) == SOCI_UBUS) {
384 SI_MSG(("Found chip type UBUS (0x%08x), chip id = 0x%4x\n", w, sih->chip));
385 /* pass chipc address instead of original core base */
386 ub_scan(&sii->pub, (void *)(uintptr)cc, devid);
387 } else {
388 SI_ERROR(("Found chip of unknown type (0x%08x)\n", w));
389 return NULL;
390 }
391 /* no cores found, bail out */
392 if (sii->numcores == 0) {
393 SI_ERROR(("si_doattach: could not find any cores\n"));
394 return NULL;
395 }
396 /* bus/core/clk setup */
397 origidx = SI_CC_IDX;
398 if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) {
399 SI_ERROR(("si_doattach: si_buscore_setup failed\n"));
400 goto exit;
401 }
402
403 /* assume current core is CC */
404 if ((sii->pub.ccrev == 0x25) && ((CHIPID(sih->chip) == BCM43236_CHIP_ID ||
405 CHIPID(sih->chip) == BCM43235_CHIP_ID ||
406 CHIPID(sih->chip) == BCM43238_CHIP_ID) &&
407 (CHIPREV(sii->pub.chiprev) == 0))) {
408
409 if ((cc->chipstatus & CST43236_BP_CLK) != 0) {
410 uint clkdiv;
411 clkdiv = R_REG(osh, &cc->clkdiv);
412 /* otp_clk_div is even number, 120/14 < 9mhz */
413 clkdiv = (clkdiv & ~CLKD_OTP) | (14 << CLKD_OTP_SHIFT);
414 W_REG(osh, &cc->clkdiv, clkdiv);
415 SI_ERROR(("%s: set clkdiv to %x\n", __FUNCTION__, clkdiv));
416 }
417 OSL_DELAY(10);
418 }
419
420
421 pvars = NULL;
422
423
424
425 if (sii->pub.ccrev >= 20) {
426 cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
427 ASSERT(cc != NULL);
428 W_REG(osh, &cc->gpiopullup, 0);
429 W_REG(osh, &cc->gpiopulldown, 0);
430 si_setcoreidx(sih, origidx);
431 }
432
433
434
435
436 return (sii);
437
438exit:
439
440 return NULL;
441}
442
443/* may be called with core in reset */
444void
445si_detach(si_t *sih)
446{
447 si_info_t *sii;
448 uint idx;
449
450
451 sii = SI_INFO(sih);
452
453 if (sii == NULL)
454 return;
455
456 if (BUSTYPE(sih->bustype) == SI_BUS)
457 for (idx = 0; idx < SI_MAXCORES; idx++)
458 if (sii->regs[idx]) {
459 REG_UNMAP(sii->regs[idx]);
460 sii->regs[idx] = NULL;
461 }
462
463
464
465#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS)
466 if (sii != &ksii)
467#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */
468 MFREE(sii->osh, sii, sizeof(si_info_t));
469}
470
471void *
472si_osh(si_t *sih)
473{
474 si_info_t *sii;
475
476 sii = SI_INFO(sih);
477 return sii->osh;
478}
479
480void
481si_setosh(si_t *sih, osl_t *osh)
482{
483 si_info_t *sii;
484
485 sii = SI_INFO(sih);
486 if (sii->osh != NULL) {
487 SI_ERROR(("osh is already set....\n"));
488 ASSERT(!sii->osh);
489 }
490 sii->osh = osh;
491}
492
493/* register driver interrupt disabling and restoring callback functions */
494void
495si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn,
496 void *intrsenabled_fn, void *intr_arg)
497{
498 si_info_t *sii;
499
500 sii = SI_INFO(sih);
501 sii->intr_arg = intr_arg;
502 sii->intrsoff_fn = (si_intrsoff_t)intrsoff_fn;
503 sii->intrsrestore_fn = (si_intrsrestore_t)intrsrestore_fn;
504 sii->intrsenabled_fn = (si_intrsenabled_t)intrsenabled_fn;
505 /* save current core id. when this function called, the current core
506 * must be the core which provides driver functions(il, et, wl, etc.)
507 */
508 sii->dev_coreid = sii->coreid[sii->curidx];
509}
510
511void
512si_deregister_intr_callback(si_t *sih)
513{
514 si_info_t *sii;
515
516 sii = SI_INFO(sih);
517 sii->intrsoff_fn = NULL;
518}
519
520uint
521si_intflag(si_t *sih)
522{
523 si_info_t *sii = SI_INFO(sih);
524
525 if (CHIPTYPE(sih->socitype) == SOCI_SB)
526 return sb_intflag(sih);
527 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
528 return R_REG(sii->osh, ((uint32 *)(uintptr)
529 (sii->oob_router + OOB_STATUSA)));
530 else {
531 ASSERT(0);
532 return 0;
533 }
534}
535
536uint
537si_flag(si_t *sih)
538{
539 if (CHIPTYPE(sih->socitype) == SOCI_SB)
540 return sb_flag(sih);
541 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
542 return ai_flag(sih);
543 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
544 return ub_flag(sih);
545 else {
546 ASSERT(0);
547 return 0;
548 }
549}
550
551void
552si_setint(si_t *sih, int siflag)
553{
554 if (CHIPTYPE(sih->socitype) == SOCI_SB)
555 sb_setint(sih, siflag);
556 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
557 ai_setint(sih, siflag);
558 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
559 ub_setint(sih, siflag);
560 else
561 ASSERT(0);
562}
563
564uint
565si_coreid(si_t *sih)
566{
567 si_info_t *sii;
568
569 sii = SI_INFO(sih);
570 return sii->coreid[sii->curidx];
571}
572
573uint
574si_coreidx(si_t *sih)
575{
576 si_info_t *sii;
577
578 sii = SI_INFO(sih);
579 return sii->curidx;
580}
581
582/* return the core-type instantiation # of the current core */
583uint
584si_coreunit(si_t *sih)
585{
586 si_info_t *sii;
587 uint idx;
588 uint coreid;
589 uint coreunit;
590 uint i;
591
592 sii = SI_INFO(sih);
593 coreunit = 0;
594
595 idx = sii->curidx;
596
597 ASSERT(GOODREGS(sii->curmap));
598 coreid = si_coreid(sih);
599
600 /* count the cores of our type */
601 for (i = 0; i < idx; i++)
602 if (sii->coreid[i] == coreid)
603 coreunit++;
604
605 return (coreunit);
606}
607
608uint
609si_corevendor(si_t *sih)
610{
611 if (CHIPTYPE(sih->socitype) == SOCI_SB)
612 return sb_corevendor(sih);
613 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
614 return ai_corevendor(sih);
615 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
616 return ub_corevendor(sih);
617 else {
618 ASSERT(0);
619 return 0;
620 }
621}
622
623bool
624si_backplane64(si_t *sih)
625{
626 return ((sih->cccaps & CC_CAP_BKPLN64) != 0);
627}
628
629uint
630si_corerev(si_t *sih)
631{
632 if (CHIPTYPE(sih->socitype) == SOCI_SB)
633 return sb_corerev(sih);
634 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
635 return ai_corerev(sih);
636 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
637 return ub_corerev(sih);
638 else {
639 ASSERT(0);
640 return 0;
641 }
642}
643
644/* return index of coreid or BADIDX if not found */
645uint
646si_findcoreidx(si_t *sih, uint coreid, uint coreunit)
647{
648 si_info_t *sii;
649 uint found;
650 uint i;
651
652 sii = SI_INFO(sih);
653
654 found = 0;
655
656 for (i = 0; i < sii->numcores; i++)
657 if (sii->coreid[i] == coreid) {
658 if (found == coreunit)
659 return (i);
660 found++;
661 }
662
663 return (BADIDX);
664}
665
666/* return list of found cores */
667uint
668si_corelist(si_t *sih, uint coreid[])
669{
670 si_info_t *sii;
671
672 sii = SI_INFO(sih);
673
674 bcopy((uchar*)sii->coreid, (uchar*)coreid, (sii->numcores * sizeof(uint)));
675 return (sii->numcores);
676}
677
678/* return current register mapping */
679void *
680si_coreregs(si_t *sih)
681{
682 si_info_t *sii;
683
684 sii = SI_INFO(sih);
685 ASSERT(GOODREGS(sii->curmap));
686
687 return (sii->curmap);
688}
689
690/*
691 * This function changes logical "focus" to the indicated core;
692 * must be called with interrupts off.
693 * Moreover, callers should keep interrupts off during switching out of and back to d11 core
694 */
695void *
696si_setcore(si_t *sih, uint coreid, uint coreunit)
697{
698 uint idx;
699
700 idx = si_findcoreidx(sih, coreid, coreunit);
701 if (!GOODIDX(idx))
702 return (NULL);
703
704 if (CHIPTYPE(sih->socitype) == SOCI_SB)
705 return sb_setcoreidx(sih, idx);
706 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
707 return ai_setcoreidx(sih, idx);
708 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
709 return ub_setcoreidx(sih, idx);
710 else {
711 ASSERT(0);
712 return NULL;
713 }
714}
715
716void *
717si_setcoreidx(si_t *sih, uint coreidx)
718{
719 if (CHIPTYPE(sih->socitype) == SOCI_SB)
720 return sb_setcoreidx(sih, coreidx);
721 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
722 return ai_setcoreidx(sih, coreidx);
723 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
724 return ub_setcoreidx(sih, coreidx);
725 else {
726 ASSERT(0);
727 return NULL;
728 }
729}
730
731/* Turn off interrupt as required by sb_setcore, before switch core */
732void *
733si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val)
734{
735 void *cc;
736 si_info_t *sii;
737
738 sii = SI_INFO(sih);
739
740 if (SI_FAST(sii)) {
741 /* Overloading the origidx variable to remember the coreid,
742 * this works because the core ids cannot be confused with
743 * core indices.
744 */
745 *origidx = coreid;
746 if (coreid == CC_CORE_ID)
747 return (void *)CCREGS_FAST(sii);
748 else if (coreid == sih->buscoretype)
749 return (void *)PCIEREGS(sii);
750 }
751 INTR_OFF(sii, *intr_val);
752 *origidx = sii->curidx;
753 cc = si_setcore(sih, coreid, 0);
754 ASSERT(cc != NULL);
755
756 return cc;
757}
758
759/* restore coreidx and restore interrupt */
760void
761si_restore_core(si_t *sih, uint coreid, uint intr_val)
762{
763 si_info_t *sii;
764
765 sii = SI_INFO(sih);
766 if (SI_FAST(sii) && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype)))
767 return;
768
769 si_setcoreidx(sih, coreid);
770 INTR_RESTORE(sii, intr_val);
771}
772
773int
774si_numaddrspaces(si_t *sih)
775{
776 if (CHIPTYPE(sih->socitype) == SOCI_SB)
777 return sb_numaddrspaces(sih);
778 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
779 return ai_numaddrspaces(sih);
780 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
781 return ub_numaddrspaces(sih);
782 else {
783 ASSERT(0);
784 return 0;
785 }
786}
787
788uint32
789si_addrspace(si_t *sih, uint asidx)
790{
791 if (CHIPTYPE(sih->socitype) == SOCI_SB)
792 return sb_addrspace(sih, asidx);
793 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
794 return ai_addrspace(sih, asidx);
795 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
796 return ub_addrspace(sih, asidx);
797 else {
798 ASSERT(0);
799 return 0;
800 }
801}
802
803uint32
804si_addrspacesize(si_t *sih, uint asidx)
805{
806 if (CHIPTYPE(sih->socitype) == SOCI_SB)
807 return sb_addrspacesize(sih, asidx);
808 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
809 return ai_addrspacesize(sih, asidx);
810 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
811 return ub_addrspacesize(sih, asidx);
812 else {
813 ASSERT(0);
814 return 0;
815 }
816}
817
818uint32
819si_core_cflags(si_t *sih, uint32 mask, uint32 val)
820{
821 if (CHIPTYPE(sih->socitype) == SOCI_SB)
822 return sb_core_cflags(sih, mask, val);
823 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
824 return ai_core_cflags(sih, mask, val);
825 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
826 return ub_core_cflags(sih, mask, val);
827 else {
828 ASSERT(0);
829 return 0;
830 }
831}
832
833void
834si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val)
835{
836 if (CHIPTYPE(sih->socitype) == SOCI_SB)
837 sb_core_cflags_wo(sih, mask, val);
838 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
839 ai_core_cflags_wo(sih, mask, val);
840 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
841 ub_core_cflags_wo(sih, mask, val);
842 else
843 ASSERT(0);
844}
845
846uint32
847si_core_sflags(si_t *sih, uint32 mask, uint32 val)
848{
849 if (CHIPTYPE(sih->socitype) == SOCI_SB)
850 return sb_core_sflags(sih, mask, val);
851 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
852 return ai_core_sflags(sih, mask, val);
853 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
854 return ub_core_sflags(sih, mask, val);
855 else {
856 ASSERT(0);
857 return 0;
858 }
859}
860
861bool
862si_iscoreup(si_t *sih)
863{
864 if (CHIPTYPE(sih->socitype) == SOCI_SB)
865 return sb_iscoreup(sih);
866 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
867 return ai_iscoreup(sih);
868 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
869 return ub_iscoreup(sih);
870 else {
871 ASSERT(0);
872 return FALSE;
873 }
874}
875
876uint
877si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val)
878{
879 /* only for AI back plane chips */
880 if (CHIPTYPE(sih->socitype) == SOCI_AI)
881 return (ai_wrap_reg(sih, offset, mask, val));
882 return 0;
883}
884
885uint
886si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
887{
888 if (CHIPTYPE(sih->socitype) == SOCI_SB)
889 return sb_corereg(sih, coreidx, regoff, mask, val);
890 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
891 return ai_corereg(sih, coreidx, regoff, mask, val);
892 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
893 return ub_corereg(sih, coreidx, regoff, mask, val);
894 else {
895 ASSERT(0);
896 return 0;
897 }
898}
899
900void
901si_core_disable(si_t *sih, uint32 bits)
902{
903 if (CHIPTYPE(sih->socitype) == SOCI_SB)
904 sb_core_disable(sih, bits);
905 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
906 ai_core_disable(sih, bits);
907 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
908 ub_core_disable(sih, bits);
909}
910
911void
912si_core_reset(si_t *sih, uint32 bits, uint32 resetbits)
913{
914 if (CHIPTYPE(sih->socitype) == SOCI_SB)
915 sb_core_reset(sih, bits, resetbits);
916 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
917 ai_core_reset(sih, bits, resetbits);
918 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
919 ub_core_reset(sih, bits, resetbits);
920}
921
922/* Run bist on current core. Caller needs to take care of core-specific bist hazards */
923int
924si_corebist(si_t *sih)
925{
926 uint32 cflags;
927 int result = 0;
928
929 /* Read core control flags */
930 cflags = si_core_cflags(sih, 0, 0);
931
932 /* Set bist & fgc */
933 si_core_cflags(sih, ~0, (SICF_BIST_EN | SICF_FGC));
934
935 /* Wait for bist done */
936 SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 100000);
937
938 if (si_core_sflags(sih, 0, 0) & SISF_BIST_ERROR)
939 result = BCME_ERROR;
940
941 /* Reset core control flags */
942 si_core_cflags(sih, 0xffff, cflags);
943
944 return result;
945}
946
947static uint32
948factor6(uint32 x)
949{
950 switch (x) {
951 case CC_F6_2: return 2;
952 case CC_F6_3: return 3;
953 case CC_F6_4: return 4;
954 case CC_F6_5: return 5;
955 case CC_F6_6: return 6;
956 case CC_F6_7: return 7;
957 default: return 0;
958 }
959}
960
961/* calculate the speed the SI would run at given a set of clockcontrol values */
962uint32
963si_clock_rate(uint32 pll_type, uint32 n, uint32 m)
964{
965 uint32 n1, n2, clock, m1, m2, m3, mc;
966
967 n1 = n & CN_N1_MASK;
968 n2 = (n & CN_N2_MASK) >> CN_N2_SHIFT;
969
970 if (pll_type == PLL_TYPE6) {
971 if (m & CC_T6_MMASK)
972 return CC_T6_M1;
973 else
974 return CC_T6_M0;
975 } else if ((pll_type == PLL_TYPE1) ||
976 (pll_type == PLL_TYPE3) ||
977 (pll_type == PLL_TYPE4) ||
978 (pll_type == PLL_TYPE7)) {
979 n1 = factor6(n1);
980 n2 += CC_F5_BIAS;
981 } else if (pll_type == PLL_TYPE2) {
982 n1 += CC_T2_BIAS;
983 n2 += CC_T2_BIAS;
984 ASSERT((n1 >= 2) && (n1 <= 7));
985 ASSERT((n2 >= 5) && (n2 <= 23));
986 } else if (pll_type == PLL_TYPE5) {
987 return (100000000);
988 } else
989 ASSERT(0);
990 /* PLL types 3 and 7 use BASE2 (25Mhz) */
991 if ((pll_type == PLL_TYPE3) ||
992 (pll_type == PLL_TYPE7)) {
993 clock = CC_CLOCK_BASE2 * n1 * n2;
994 } else
995 clock = CC_CLOCK_BASE1 * n1 * n2;
996
997 if (clock == 0)
998 return 0;
999
1000 m1 = m & CC_M1_MASK;
1001 m2 = (m & CC_M2_MASK) >> CC_M2_SHIFT;
1002 m3 = (m & CC_M3_MASK) >> CC_M3_SHIFT;
1003 mc = (m & CC_MC_MASK) >> CC_MC_SHIFT;
1004
1005 if ((pll_type == PLL_TYPE1) ||
1006 (pll_type == PLL_TYPE3) ||
1007 (pll_type == PLL_TYPE4) ||
1008 (pll_type == PLL_TYPE7)) {
1009 m1 = factor6(m1);
1010 if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3))
1011 m2 += CC_F5_BIAS;
1012 else
1013 m2 = factor6(m2);
1014 m3 = factor6(m3);
1015
1016 switch (mc) {
1017 case CC_MC_BYPASS: return (clock);
1018 case CC_MC_M1: return (clock / m1);
1019 case CC_MC_M1M2: return (clock / (m1 * m2));
1020 case CC_MC_M1M2M3: return (clock / (m1 * m2 * m3));
1021 case CC_MC_M1M3: return (clock / (m1 * m3));
1022 default: return (0);
1023 }
1024 } else {
1025 ASSERT(pll_type == PLL_TYPE2);
1026
1027 m1 += CC_T2_BIAS;
1028 m2 += CC_T2M2_BIAS;
1029 m3 += CC_T2_BIAS;
1030 ASSERT((m1 >= 2) && (m1 <= 7));
1031 ASSERT((m2 >= 3) && (m2 <= 10));
1032 ASSERT((m3 >= 2) && (m3 <= 7));
1033
1034 if ((mc & CC_T2MC_M1BYP) == 0)
1035 clock /= m1;
1036 if ((mc & CC_T2MC_M2BYP) == 0)
1037 clock /= m2;
1038 if ((mc & CC_T2MC_M3BYP) == 0)
1039 clock /= m3;
1040
1041 return (clock);
1042 }
1043}
1044
1045
1046/* set chip watchdog reset timer to fire in 'ticks' */
1047void
1048si_watchdog(si_t *sih, uint ticks)
1049{
1050 uint nb, maxt;
1051
1052 if (PMUCTL_ENAB(sih)) {
1053
1054 if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) &&
1055 (CHIPREV(sih->chiprev) == 0) && (ticks != 0)) {
1056 si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), ~0, 0x2);
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
1076 si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, pmuwatchdog), ~0, ticks);
1077 } else {
1078 maxt = (1 << 28) - 1;
1079 if (ticks > maxt)
1080 ticks = maxt;
1081
1082 si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, ticks);
1083 }
1084}
1085
1086/* trigger watchdog reset after ms milliseconds */
1087void
1088si_watchdog_ms(si_t *sih, uint32 ms)
1089{
1090 si_watchdog(sih, wd_msticks * ms);
1091}
1092
1093
1094
1095
1096/* change logical "focus" to the gpio core for optimized access */
1097void *
1098si_gpiosetcore(si_t *sih)
1099{
1100 return (si_setcoreidx(sih, SI_CC_IDX));
1101}
1102
1103/* mask&set gpiocontrol bits */
1104uint32
1105si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority)
1106{
1107 uint regoff;
1108
1109 regoff = 0;
1110
1111 /* gpios could be shared on router platforms
1112 * ignore reservation if it's high priority (e.g., test apps)
1113 */
1114 if ((priority != GPIO_HI_PRIORITY) &&
1115 (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
1116 mask = priority ? (si_gpioreservation & mask) :
1117 ((si_gpioreservation | mask) & ~(si_gpioreservation));
1118 val &= mask;
1119 }
1120
1121 regoff = OFFSETOF(chipcregs_t, gpiocontrol);
1122 return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
1123}
1124
1125/* mask&set gpio output enable bits */
1126uint32
1127si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority)
1128{
1129 uint regoff;
1130
1131 regoff = 0;
1132
1133 /* gpios could be shared on router platforms
1134 * ignore reservation if it's high priority (e.g., test apps)
1135 */
1136 if ((priority != GPIO_HI_PRIORITY) &&
1137 (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
1138 mask = priority ? (si_gpioreservation & mask) :
1139 ((si_gpioreservation | mask) & ~(si_gpioreservation));
1140 val &= mask;
1141 }
1142
1143 regoff = OFFSETOF(chipcregs_t, gpioouten);
1144 return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
1145}
1146
1147/* mask&set gpio output bits */
1148uint32
1149si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority)
1150{
1151 uint regoff;
1152
1153 regoff = 0;
1154
1155 /* gpios could be shared on router platforms
1156 * ignore reservation if it's high priority (e.g., test apps)
1157 */
1158 if ((priority != GPIO_HI_PRIORITY) &&
1159 (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
1160 mask = priority ? (si_gpioreservation & mask) :
1161 ((si_gpioreservation | mask) & ~(si_gpioreservation));
1162 val &= mask;
1163 }
1164
1165 regoff = OFFSETOF(chipcregs_t, gpioout);
1166 return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
1167}
1168
1169/* reserve one gpio */
1170uint32
1171si_gpioreserve(si_t *sih, uint32 gpio_bitmask, uint8 priority)
1172{
1173 si_info_t *sii;
1174
1175 sii = SI_INFO(sih);
1176
1177 /* only cores on SI_BUS share GPIO's and only applcation users need to
1178 * reserve/release GPIO
1179 */
1180 if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) {
1181 ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority));
1182 return 0xffffffff;
1183 }
1184 /* make sure only one bit is set */
1185 if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) {
1186 ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1)));
1187 return 0xffffffff;
1188 }
1189
1190 /* already reserved */
1191 if (si_gpioreservation & gpio_bitmask)
1192 return 0xffffffff;
1193 /* set reservation */
1194 si_gpioreservation |= gpio_bitmask;
1195
1196 return si_gpioreservation;
1197}
1198
1199/* release one gpio */
1200/*
1201 * releasing the gpio doesn't change the current value on the GPIO last write value
1202 * persists till some one overwrites it
1203 */
1204
1205uint32
1206si_gpiorelease(si_t *sih, uint32 gpio_bitmask, uint8 priority)
1207{
1208 si_info_t *sii;
1209
1210 sii = SI_INFO(sih);
1211
1212 /* only cores on SI_BUS share GPIO's and only applcation users need to
1213 * reserve/release GPIO
1214 */
1215 if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) {
1216 ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority));
1217 return 0xffffffff;
1218 }
1219 /* make sure only one bit is set */
1220 if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) {
1221 ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1)));
1222 return 0xffffffff;
1223 }
1224
1225 /* already released */
1226 if (!(si_gpioreservation & gpio_bitmask))
1227 return 0xffffffff;
1228
1229 /* clear reservation */
1230 si_gpioreservation &= ~gpio_bitmask;
1231
1232 return si_gpioreservation;
1233}
1234
1235/* return the current gpioin register value */
1236uint32
1237si_gpioin(si_t *sih)
1238{
1239 si_info_t *sii;
1240 uint regoff;
1241
1242 sii = SI_INFO(sih);
1243 regoff = 0;
1244
1245 regoff = OFFSETOF(chipcregs_t, gpioin);
1246 return (si_corereg(sih, SI_CC_IDX, regoff, 0, 0));
1247}
1248
1249/* mask&set gpio interrupt polarity bits */
1250uint32
1251si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority)
1252{
1253 si_info_t *sii;
1254 uint regoff;
1255
1256 sii = SI_INFO(sih);
1257 regoff = 0;
1258
1259 /* gpios could be shared on router platforms */
1260 if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
1261 mask = priority ? (si_gpioreservation & mask) :
1262 ((si_gpioreservation | mask) & ~(si_gpioreservation));
1263 val &= mask;
1264 }
1265
1266 regoff = OFFSETOF(chipcregs_t, gpiointpolarity);
1267 return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
1268}
1269
1270/* mask&set gpio interrupt mask bits */
1271uint32
1272si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority)
1273{
1274 si_info_t *sii;
1275 uint regoff;
1276
1277 sii = SI_INFO(sih);
1278 regoff = 0;
1279
1280 /* gpios could be shared on router platforms */
1281 if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
1282 mask = priority ? (si_gpioreservation & mask) :
1283 ((si_gpioreservation | mask) & ~(si_gpioreservation));
1284 val &= mask;
1285 }
1286
1287 regoff = OFFSETOF(chipcregs_t, gpiointmask);
1288 return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
1289}
1290
1291/* assign the gpio to an led */
1292uint32
1293si_gpioled(si_t *sih, uint32 mask, uint32 val)
1294{
1295 si_info_t *sii;
1296
1297 sii = SI_INFO(sih);
1298 if (sih->ccrev < 16)
1299 return 0xffffffff;
1300
1301 /* gpio led powersave reg */
1302 return (si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask, val));
1303}
1304
1305/* mask&set gpio timer val */
1306uint32
1307si_gpiotimerval(si_t *sih, uint32 mask, uint32 gpiotimerval)
1308{
1309 si_info_t *sii;
1310
1311 sii = SI_INFO(sih);
1312
1313 if (sih->ccrev < 16)
1314 return 0xffffffff;
1315
1316 return (si_corereg(sih, SI_CC_IDX,
1317 OFFSETOF(chipcregs_t, gpiotimerval), mask, gpiotimerval));
1318}
1319
1320uint32
1321si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val)
1322{
1323 si_info_t *sii;
1324 uint offs;
1325
1326 sii = SI_INFO(sih);
1327 if (sih->ccrev < 20)
1328 return 0xffffffff;
1329
1330 offs = (updown ? OFFSETOF(chipcregs_t, gpiopulldown) : OFFSETOF(chipcregs_t, gpiopullup));
1331 return (si_corereg(sih, SI_CC_IDX, offs, mask, val));
1332}
1333
1334uint32
1335si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val)
1336{
1337 si_info_t *sii;
1338 uint offs;
1339
1340 sii = SI_INFO(sih);
1341 if (sih->ccrev < 11)
1342 return 0xffffffff;
1343
1344 if (regtype == GPIO_REGEVT)
1345 offs = OFFSETOF(chipcregs_t, gpioevent);
1346 else if (regtype == GPIO_REGEVT_INTMSK)
1347 offs = OFFSETOF(chipcregs_t, gpioeventintmask);
1348 else if (regtype == GPIO_REGEVT_INTPOL)
1349 offs = OFFSETOF(chipcregs_t, gpioeventintpolarity);
1350 else
1351 return 0xffffffff;
1352
1353 return (si_corereg(sih, SI_CC_IDX, offs, mask, val));
1354}
1355
1356void *
1357si_gpio_handler_register(si_t *sih, uint32 event,
1358 bool level, gpio_handler_t cb, void *arg)
1359{
1360 si_info_t *sii;
1361 gpioh_item_t *gi;
1362
1363 ASSERT(event);
1364 ASSERT(cb != NULL);
1365
1366 sii = SI_INFO(sih);
1367 if (sih->ccrev < 11)
1368 return NULL;
1369
1370 if ((gi = MALLOC(sii->osh, sizeof(gpioh_item_t))) == NULL)
1371 return NULL;
1372
1373 bzero(gi, sizeof(gpioh_item_t));
1374 gi->event = event;
1375 gi->handler = cb;
1376 gi->arg = arg;
1377 gi->level = level;
1378
1379 gi->next = sii->gpioh_head;
1380 sii->gpioh_head = gi;
1381
1382 return (void *)(gi);
1383}
1384
1385void
1386si_gpio_handler_unregister(si_t *sih, void *gpioh)
1387{
1388 si_info_t *sii;
1389 gpioh_item_t *p, *n;
1390
1391 sii = SI_INFO(sih);
1392 if (sih->ccrev < 11)
1393 return;
1394
1395 ASSERT(sii->gpioh_head != NULL);
1396 if ((void*)sii->gpioh_head == gpioh) {
1397 sii->gpioh_head = sii->gpioh_head->next;
1398 MFREE(sii->osh, gpioh, sizeof(gpioh_item_t));
1399 return;
1400 } else {
1401 p = sii->gpioh_head;
1402 n = p->next;
1403 while (n) {
1404 if ((void*)n == gpioh) {
1405 p->next = n->next;
1406 MFREE(sii->osh, gpioh, sizeof(gpioh_item_t));
1407 return;
1408 }
1409 p = n;
1410 n = n->next;
1411 }
1412 }
1413
1414 ASSERT(0); /* Not found in list */
1415}
1416
1417void
1418si_gpio_handler_process(si_t *sih)
1419{
1420 si_info_t *sii;
1421 gpioh_item_t *h;
1422 uint32 level = si_gpioin(sih);
1423 uint32 levelp = si_gpiointpolarity(sih, 0, 0, 0);
1424 uint32 edge = si_gpioevent(sih, GPIO_REGEVT, 0, 0);
1425 uint32 edgep = si_gpioevent(sih, GPIO_REGEVT_INTPOL, 0, 0);
1426
1427 sii = SI_INFO(sih);
1428 for (h = sii->gpioh_head; h != NULL; h = h->next) {
1429 if (h->handler) {
1430 uint32 status = (h->level ? level : edge) & h->event;
1431 uint32 polarity = (h->level ? levelp : edgep) & h->event;
1432
1433 /* polarity bitval is opposite of status bitval */
1434 if (status ^ polarity)
1435 h->handler(status, h->arg);
1436 }
1437 }
1438
1439 si_gpioevent(sih, GPIO_REGEVT, edge, edge); /* clear edge-trigger status */
1440}
1441
1442uint32
1443si_gpio_int_enable(si_t *sih, bool enable)
1444{
1445 si_info_t *sii;
1446 uint offs;
1447
1448 sii = SI_INFO(sih);
1449 if (sih->ccrev < 11)
1450 return 0xffffffff;
1451
1452 offs = OFFSETOF(chipcregs_t, intmask);
1453 return (si_corereg(sih, SI_CC_IDX, offs, CI_GPIO, (enable ? CI_GPIO : 0)));
1454}
1455
1456
1457/* Return the size of the specified SOCRAM bank */
1458static uint
1459socram_banksize(si_info_t *sii, sbsocramregs_t *regs, uint8 index, uint8 mem_type)
1460{
1461 uint banksize, bankinfo;
1462 uint bankidx = index | (mem_type << SOCRAM_BANKIDX_MEMTYPE_SHIFT);
1463
1464 ASSERT(mem_type <= SOCRAM_MEMTYPE_DEVRAM);
1465
1466 W_REG(sii->osh, &regs->bankidx, bankidx);
1467 bankinfo = R_REG(sii->osh, &regs->bankinfo);
1468 banksize = SOCRAM_BANKINFO_SZBASE * ((bankinfo & SOCRAM_BANKINFO_SZMASK) + 1);
1469 return banksize;
1470}
1471
1472void
1473si_socdevram(si_t *sih, bool set, uint8 *enable, uint8 *protect)
1474{
1475 si_info_t *sii;
1476 uint origidx;
1477 uint intr_val = 0;
1478 sbsocramregs_t *regs;
1479 bool wasup;
1480 uint corerev;
1481
1482 sii = SI_INFO(sih);
1483
1484 /* Block ints and save current core */
1485 INTR_OFF(sii, intr_val);
1486 origidx = si_coreidx(sih);
1487
1488 if (!set)
1489 *enable = *protect = 0;
1490
1491 /* Switch to SOCRAM core */
1492 if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0)))
1493 goto done;
1494
1495 /* Get info for determining size */
1496 if (!(wasup = si_iscoreup(sih)))
1497 si_core_reset(sih, 0, 0);
1498
1499 corerev = si_corerev(sih);
1500 if (corerev >= 10) {
1501 uint32 extcinfo;
1502 uint8 nb;
1503 uint8 i;
1504 uint32 bankidx, bankinfo;
1505
1506 extcinfo = R_REG(sii->osh, &regs->extracoreinfo);
1507 nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT);
1508 for (i = 0; i < nb; i++) {
1509 bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT);
1510 W_REG(sii->osh, &regs->bankidx, bankidx);
1511 bankinfo = R_REG(sii->osh, &regs->bankinfo);
1512 if (set) {
1513 bankinfo &= ~SOCRAM_BANKINFO_DEVRAMSEL_MASK;
1514 bankinfo &= ~SOCRAM_BANKINFO_DEVRAMPRO_MASK;
1515 if (*enable) {
1516 bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMSEL_SHIFT);
1517 if (*protect)
1518 bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMPRO_SHIFT);
1519 }
1520 W_REG(sii->osh, &regs->bankinfo, bankinfo);
1521 }
1522 else if (i == 0) {
1523 if (bankinfo & SOCRAM_BANKINFO_DEVRAMSEL_MASK) {
1524 *enable = 1;
1525 if (bankinfo & SOCRAM_BANKINFO_DEVRAMPRO_MASK)
1526 *protect = 1;
1527 }
1528 }
1529 }
1530 }
1531
1532 /* Return to previous state and core */
1533 if (!wasup)
1534 si_core_disable(sih, 0);
1535 si_setcoreidx(sih, origidx);
1536
1537done:
1538 INTR_RESTORE(sii, intr_val);
1539}
1540
1541bool
1542si_socdevram_pkg(si_t *sih)
1543{
1544 if (si_socdevram_size(sih) > 0)
1545 return TRUE;
1546 else
1547 return FALSE;
1548}
1549
1550uint32
1551si_socdevram_size(si_t *sih)
1552{
1553 si_info_t *sii;
1554 uint origidx;
1555 uint intr_val = 0;
1556 uint32 memsize = 0;
1557 sbsocramregs_t *regs;
1558 bool wasup;
1559 uint corerev;
1560
1561 sii = SI_INFO(sih);
1562
1563 /* Block ints and save current core */
1564 INTR_OFF(sii, intr_val);
1565 origidx = si_coreidx(sih);
1566
1567 /* Switch to SOCRAM core */
1568 if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0)))
1569 goto done;
1570
1571 /* Get info for determining size */
1572 if (!(wasup = si_iscoreup(sih)))
1573 si_core_reset(sih, 0, 0);
1574
1575 corerev = si_corerev(sih);
1576 if (corerev >= 10) {
1577 uint32 extcinfo;
1578 uint8 nb;
1579 uint8 i;
1580
1581 extcinfo = R_REG(sii->osh, &regs->extracoreinfo);
1582 nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT));
1583 for (i = 0; i < nb; i++)
1584 memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM);
1585 }
1586
1587 /* Return to previous state and core */
1588 if (!wasup)
1589 si_core_disable(sih, 0);
1590 si_setcoreidx(sih, origidx);
1591
1592done:
1593 INTR_RESTORE(sii, intr_val);
1594
1595 return memsize;
1596}
1597
1598/* Return the RAM size of the SOCRAM core */
1599uint32
1600si_socram_size(si_t *sih)
1601{
1602 si_info_t *sii;
1603 uint origidx;
1604 uint intr_val = 0;
1605
1606 sbsocramregs_t *regs;
1607 bool wasup;
1608 uint corerev;
1609 uint32 coreinfo;
1610 uint memsize = 0;
1611
1612 sii = SI_INFO(sih);
1613
1614 /* Block ints and save current core */
1615 INTR_OFF(sii, intr_val);
1616 origidx = si_coreidx(sih);
1617
1618 /* Switch to SOCRAM core */
1619 if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0)))
1620 goto done;
1621
1622 /* Get info for determining size */
1623 if (!(wasup = si_iscoreup(sih)))
1624 si_core_reset(sih, 0, 0);
1625 corerev = si_corerev(sih);
1626 coreinfo = R_REG(sii->osh, &regs->coreinfo);
1627
1628 /* Calculate size from coreinfo based on rev */
1629 if (corerev == 0)
1630 memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK));
1631 else if (corerev < 3) {
1632 memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK));
1633 memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
1634 } else if ((corerev <= 7) || (corerev == 12)) {
1635 uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
1636 uint bsz = (coreinfo & SRCI_SRBSZ_MASK);
1637 uint lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT;
1638 if (lss != 0)
1639 nb --;
1640 memsize = nb * (1 << (bsz + SR_BSZ_BASE));
1641 if (lss != 0)
1642 memsize += (1 << ((lss - 1) + SR_BSZ_BASE));
1643 } else {
1644 uint8 i;
1645 uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
1646 for (i = 0; i < nb; i++)
1647 memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM);
1648 }
1649
1650 /* Return to previous state and core */
1651 if (!wasup)
1652 si_core_disable(sih, 0);
1653 si_setcoreidx(sih, origidx);
1654
1655done:
1656 INTR_RESTORE(sii, intr_val);
1657
1658 return memsize;
1659}
1660
1661
1662void
1663si_btcgpiowar(si_t *sih)
1664{
1665 si_info_t *sii;
1666 uint origidx;
1667 uint intr_val = 0;
1668 chipcregs_t *cc;
1669
1670 sii = SI_INFO(sih);
1671
1672 /* Make sure that there is ChipCommon core present &&
1673 * UART_TX is strapped to 1
1674 */
1675 if (!(sih->cccaps & CC_CAP_UARTGPIO))
1676 return;
1677
1678 /* si_corereg cannot be used as we have to guarantee 8-bit read/writes */
1679 INTR_OFF(sii, intr_val);
1680
1681 origidx = si_coreidx(sih);
1682
1683 cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
1684 ASSERT(cc != NULL);
1685
1686 W_REG(sii->osh, &cc->uart0mcr, R_REG(sii->osh, &cc->uart0mcr) | 0x04);
1687
1688 /* restore the original index */
1689 si_setcoreidx(sih, origidx);
1690
1691 INTR_RESTORE(sii, intr_val);
1692}
1693
1694uint
1695si_pll_reset(si_t *sih)
1696{
1697 uint err = 0;
1698
1699 return (err);
1700}
1701
1702/* check if the device is removed */
1703bool
1704si_deviceremoved(si_t *sih)
1705{
1706 uint32 w;
1707 si_info_t *sii;
1708
1709 sii = SI_INFO(sih);
1710
1711 switch (BUSTYPE(sih->bustype)) {
1712 case PCI_BUS:
1713 ASSERT(sii->osh != NULL);
1714 w = OSL_PCI_READ_CONFIG(sii->osh, PCI_CFG_VID, sizeof(uint32));
1715 if ((w & 0xFFFF) != VENDOR_BROADCOM)
1716 return TRUE;
1717 break;
1718 }
1719 return FALSE;
1720}