Merge branch develop-3.10-next
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rkwifi / bcmdhd / aiutils.c
1 /*
2  * Misc utility routines for accessing chip-specific features
3  * of the SiliconBackplane-based Broadcom chips.
4  *
5  * $Copyright Open Broadcom Corporation$
6  *
7  * $Id: aiutils.c 467150 2014-04-02 17:30:43Z $
8  */
9 #include <bcm_cfg.h>
10 #include <typedefs.h>
11 #include <bcmdefs.h>
12 #include <osl.h>
13 #include <bcmutils.h>
14 #include <siutils.h>
15 #include <hndsoc.h>
16 #include <sbchipc.h>
17 #include <pcicfg.h>
18
19 #include "siutils_priv.h"
20
21 #define BCM47162_DMP() (0)
22 #define BCM5357_DMP() (0)
23 #define BCM4707_DMP() (0)
24 #define PMU_DMP() (0)
25 #define remap_coreid(sih, coreid)       (coreid)
26 #define remap_corerev(sih, corerev)     (corerev)
27
28 /* EROM parsing */
29
30 static uint32
31 get_erom_ent(si_t *sih, uint32 **eromptr, uint32 mask, uint32 match)
32 {
33         uint32 ent;
34         uint inv = 0, nom = 0;
35
36         while (TRUE) {
37                 ent = R_REG(si_osh(sih), *eromptr);
38                 (*eromptr)++;
39
40                 if (mask == 0)
41                         break;
42
43                 if ((ent & ER_VALID) == 0) {
44                         inv++;
45                         continue;
46                 }
47
48                 if (ent == (ER_END | ER_VALID))
49                         break;
50
51                 if ((ent & mask) == match)
52                         break;
53
54                 nom++;
55         }
56
57         SI_VMSG(("%s: Returning ent 0x%08x\n", __FUNCTION__, ent));
58         if (inv + nom) {
59                 SI_VMSG(("  after %d invalid and %d non-matching entries\n", inv, nom));
60         }
61         return ent;
62 }
63
64 static uint32
65 get_asd(si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *addrl, uint32 *addrh,
66         uint32 *sizel, uint32 *sizeh)
67 {
68         uint32 asd, sz, szd;
69
70         asd = get_erom_ent(sih, eromptr, ER_VALID, ER_VALID);
71         if (((asd & ER_TAG1) != ER_ADD) ||
72             (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) ||
73             ((asd & AD_ST_MASK) != st)) {
74                 /* This is not what we want, "push" it back */
75                 (*eromptr)--;
76                 return 0;
77         }
78         *addrl = asd & AD_ADDR_MASK;
79         if (asd & AD_AG32)
80                 *addrh = get_erom_ent(sih, eromptr, 0, 0);
81         else
82                 *addrh = 0;
83         *sizeh = 0;
84         sz = asd & AD_SZ_MASK;
85         if (sz == AD_SZ_SZD) {
86                 szd = get_erom_ent(sih, eromptr, 0, 0);
87                 *sizel = szd & SD_SZ_MASK;
88                 if (szd & SD_SG32)
89                         *sizeh = get_erom_ent(sih, eromptr, 0, 0);
90         } else
91                 *sizel = AD_SZ_BASE << (sz >> AD_SZ_SHIFT);
92
93         SI_VMSG(("  SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n",
94                 sp, ad, st, *sizeh, *sizel, *addrh, *addrl));
95
96         return asd;
97 }
98
99 static void
100 ai_hwfixup(si_info_t *sii)
101 {
102 }
103
104
105 /* parse the enumeration rom to identify all cores */
106 void
107 ai_scan(si_t *sih, void *regs, uint devid)
108 {
109         si_info_t *sii = SI_INFO(sih);
110         si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
111         chipcregs_t *cc = (chipcregs_t *)regs;
112         uint32 erombase, *eromptr, *eromlim;
113
114         erombase = R_REG(sii->osh, &cc->eromptr);
115
116         switch (BUSTYPE(sih->bustype)) {
117         case SI_BUS:
118                 eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE);
119                 break;
120
121         case PCI_BUS:
122                 /* Set wrappers address */
123                 sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE);
124
125                 /* Now point the window at the erom */
126                 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase);
127                 eromptr = regs;
128                 break;
129
130 #ifdef BCMSDIO
131         case SPI_BUS:
132         case SDIO_BUS:
133                 eromptr = (uint32 *)(uintptr)erombase;
134                 break;
135 #endif  /* BCMSDIO */
136
137         case PCMCIA_BUS:
138         default:
139                 SI_ERROR(("Don't know how to do AXI enumertion on bus %d\n", sih->bustype));
140                 ASSERT(0);
141                 return;
142         }
143         eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32));
144
145         SI_VMSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n",
146                  regs, erombase, eromptr, eromlim));
147         while (eromptr < eromlim) {
148                 uint32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp;
149                 uint32 mpd, asd, addrl, addrh, sizel, sizeh;
150                 uint i, j, idx;
151                 bool br;
152
153                 br = FALSE;
154
155                 /* Grok a component */
156                 cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI);
157                 if (cia == (ER_END | ER_VALID)) {
158                         SI_VMSG(("Found END of erom after %d cores\n", sii->numcores));
159                         ai_hwfixup(sii);
160                         return;
161                 }
162
163                 cib = get_erom_ent(sih, &eromptr, 0, 0);
164
165                 if ((cib & ER_TAG) != ER_CI) {
166                         SI_ERROR(("CIA not followed by CIB\n"));
167                         goto error;
168                 }
169
170                 cid = (cia & CIA_CID_MASK) >> CIA_CID_SHIFT;
171                 mfg = (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT;
172                 crev = (cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
173                 nmw = (cib & CIB_NMW_MASK) >> CIB_NMW_SHIFT;
174                 nsw = (cib & CIB_NSW_MASK) >> CIB_NSW_SHIFT;
175                 nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT;
176                 nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT;
177
178 #ifdef BCMDBG_SI
179                 SI_VMSG(("Found component 0x%04x/0x%04x rev %d at erom addr 0x%p, with nmw = %d, "
180                          "nsw = %d, nmp = %d & nsp = %d\n",
181                          mfg, cid, crev, eromptr - 1, nmw, nsw, nmp, nsp));
182 #else
183                 BCM_REFERENCE(crev);
184 #endif
185
186                 if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0))
187                         continue;
188                 if ((nmw + nsw == 0)) {
189                         /* A component which is not a core */
190                         if (cid == OOB_ROUTER_CORE_ID) {
191                                 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE,
192                                         &addrl, &addrh, &sizel, &sizeh);
193                                 if (asd != 0) {
194                                         sii->oob_router = addrl;
195                                 }
196                         }
197                         if (cid != GMAC_COMMON_4706_CORE_ID && cid != NS_CCB_CORE_ID &&
198                                 cid != PMU_CORE_ID && cid != GCI_CORE_ID)
199                                 continue;
200                 }
201
202                 idx = sii->numcores;
203
204                 cores_info->cia[idx] = cia;
205                 cores_info->cib[idx] = cib;
206                 cores_info->coreid[idx] = remap_coreid(sih, cid);
207
208                 for (i = 0; i < nmp; i++) {
209                         mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID);
210                         if ((mpd & ER_TAG) != ER_MP) {
211                                 SI_ERROR(("Not enough MP entries for component 0x%x\n", cid));
212                                 goto error;
213                         }
214                         SI_VMSG(("  Master port %d, mp: %d id: %d\n", i,
215                                  (mpd & MPD_MP_MASK) >> MPD_MP_SHIFT,
216                                  (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT));
217                 }
218
219                 /* First Slave Address Descriptor should be port 0:
220                  * the main register space for the core
221                  */
222                 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh);
223                 if (asd == 0) {
224                         do {
225                         /* Try again to see if it is a bridge */
226                         asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh,
227                                       &sizel, &sizeh);
228                         if (asd != 0)
229                                 br = TRUE;
230                         else {
231                                         if (br == TRUE) {
232                                                 break;
233                                         }
234                                         else if ((addrh != 0) || (sizeh != 0) ||
235                                                 (sizel != SI_CORE_SIZE)) {
236                                                 SI_ERROR(("addrh = 0x%x\t sizeh = 0x%x\t size1 ="
237                                                         "0x%x\n", addrh, sizeh, sizel));
238                                                 SI_ERROR(("First Slave ASD for"
239                                                         "core 0x%04x malformed "
240                                                         "(0x%08x)\n", cid, asd));
241                                                 goto error;
242                                         }
243                                 }
244                         } while (1);
245                 }
246                 cores_info->coresba[idx] = addrl;
247                 cores_info->coresba_size[idx] = sizel;
248                 /* Get any more ASDs in port 0 */
249                 j = 1;
250                 do {
251                         asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh,
252                                       &sizel, &sizeh);
253                         if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE)) {
254                                 cores_info->coresba2[idx] = addrl;
255                                 cores_info->coresba2_size[idx] = sizel;
256                         }
257                         j++;
258                 } while (asd != 0);
259
260                 /* Go through the ASDs for other slave ports */
261                 for (i = 1; i < nsp; i++) {
262                         j = 0;
263                         do {
264                                 asd = get_asd(sih, &eromptr, i, j, AD_ST_SLAVE, &addrl, &addrh,
265                                               &sizel, &sizeh);
266
267                                 if (asd == 0)
268                                         break;
269                                 j++;
270                         } while (1);
271                         if (j == 0) {
272                                 SI_ERROR((" SP %d has no address descriptors\n", i));
273                                 goto error;
274                         }
275                 }
276
277                 /* Now get master wrappers */
278                 for (i = 0; i < nmw; i++) {
279                         asd = get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl, &addrh,
280                                       &sizel, &sizeh);
281                         if (asd == 0) {
282                                 SI_ERROR(("Missing descriptor for MW %d\n", i));
283                                 goto error;
284                         }
285                         if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) {
286                                 SI_ERROR(("Master wrapper %d is not 4KB\n", i));
287                                 goto error;
288                         }
289                         if (i == 0)
290                                 cores_info->wrapba[idx] = addrl;
291                 }
292
293                 /* And finally slave wrappers */
294                 for (i = 0; i < nsw; i++) {
295                         uint fwp = (nsp == 1) ? 0 : 1;
296                         asd = get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP, &addrl, &addrh,
297                                       &sizel, &sizeh);
298                         if (asd == 0) {
299                                 SI_ERROR(("Missing descriptor for SW %d\n", i));
300                                 goto error;
301                         }
302                         if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) {
303                                 SI_ERROR(("Slave wrapper %d is not 4KB\n", i));
304                                 goto error;
305                         }
306                         if ((nmw == 0) && (i == 0))
307                                 cores_info->wrapba[idx] = addrl;
308                 }
309
310
311                 /* Don't record bridges */
312                 if (br)
313                         continue;
314
315                 /* Done with core */
316                 sii->numcores++;
317         }
318
319         SI_ERROR(("Reached end of erom without finding END"));
320
321 error:
322         sii->numcores = 0;
323         return;
324 }
325
326 #define AI_SETCOREIDX_MAPSIZE(coreid) \
327         (((coreid) == NS_CCB_CORE_ID) ? 15 * SI_CORE_SIZE : SI_CORE_SIZE)
328
329 /* This function changes the logical "focus" to the indicated core.
330  * Return the current core's virtual address.
331  */
332 void *
333 ai_setcoreidx(si_t *sih, uint coreidx)
334 {
335         si_info_t *sii = SI_INFO(sih);
336         si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
337         uint32 addr, wrap;
338         void *regs;
339
340         if (coreidx >= MIN(sii->numcores, SI_MAXCORES))
341                 return (NULL);
342
343         addr = cores_info->coresba[coreidx];
344         wrap = cores_info->wrapba[coreidx];
345
346         /*
347          * If the user has provided an interrupt mask enabled function,
348          * then assert interrupts are disabled before switching the core.
349          */
350         ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg));
351
352         switch (BUSTYPE(sih->bustype)) {
353         case SI_BUS:
354                 /* map new one */
355                 if (!cores_info->regs[coreidx]) {
356                         cores_info->regs[coreidx] = REG_MAP(addr,
357                                 AI_SETCOREIDX_MAPSIZE(cores_info->coreid[coreidx]));
358                         ASSERT(GOODREGS(cores_info->regs[coreidx]));
359                 }
360                 sii->curmap = regs = cores_info->regs[coreidx];
361                 if (!cores_info->wrappers[coreidx] && (wrap != 0)) {
362                         cores_info->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE);
363                         ASSERT(GOODREGS(cores_info->wrappers[coreidx]));
364                 }
365                 sii->curwrap = cores_info->wrappers[coreidx];
366                 break;
367
368         case PCI_BUS:
369                 /* point bar0 window */
370                 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, addr);
371                 regs = sii->curmap;
372                 /* point bar0 2nd 4KB window to the primary wrapper */
373                 if (PCIE_GEN2(sii))
374                         OSL_PCI_WRITE_CONFIG(sii->osh, PCIE2_BAR0_WIN2, 4, wrap);
375                 else
376                         OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, wrap);
377                 break;
378
379 #ifdef BCMSDIO
380         case SPI_BUS:
381         case SDIO_BUS:
382                 sii->curmap = regs = (void *)((uintptr)addr);
383                 sii->curwrap = (void *)((uintptr)wrap);
384                 break;
385 #endif  /* BCMSDIO */
386
387         case PCMCIA_BUS:
388         default:
389                 ASSERT(0);
390                 regs = NULL;
391                 break;
392         }
393
394         sii->curmap = regs;
395         sii->curidx = coreidx;
396
397         return regs;
398 }
399
400
401 void
402 ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size)
403 {
404         si_info_t *sii = SI_INFO(sih);
405         si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
406         chipcregs_t *cc = NULL;
407         uint32 erombase, *eromptr, *eromlim;
408         uint i, j, cidx;
409         uint32 cia, cib, nmp, nsp;
410         uint32 asd, addrl, addrh, sizel, sizeh;
411
412         for (i = 0; i < sii->numcores; i++) {
413                 if (cores_info->coreid[i] == CC_CORE_ID) {
414                         cc = (chipcregs_t *)cores_info->regs[i];
415                         break;
416                 }
417         }
418         if (cc == NULL)
419                 goto error;
420
421         erombase = R_REG(sii->osh, &cc->eromptr);
422         eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE);
423         eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32));
424
425         cidx = sii->curidx;
426         cia = cores_info->cia[cidx];
427         cib = cores_info->cib[cidx];
428
429         nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT;
430         nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT;
431
432         /* scan for cores */
433         while (eromptr < eromlim) {
434                 if ((get_erom_ent(sih, &eromptr, ER_TAG, ER_CI) == cia) &&
435                         (get_erom_ent(sih, &eromptr, 0, 0) == cib)) {
436                         break;
437                 }
438         }
439
440         /* skip master ports */
441         for (i = 0; i < nmp; i++)
442                 get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID);
443
444         /* Skip ASDs in port 0 */
445         asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh);
446         if (asd == 0) {
447                 /* Try again to see if it is a bridge */
448                 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh,
449                               &sizel, &sizeh);
450         }
451
452         j = 1;
453         do {
454                 asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh,
455                               &sizel, &sizeh);
456                 j++;
457         } while (asd != 0);
458
459         /* Go through the ASDs for other slave ports */
460         for (i = 1; i < nsp; i++) {
461                 j = 0;
462                 do {
463                         asd = get_asd(sih, &eromptr, i, j, AD_ST_SLAVE, &addrl, &addrh,
464                                 &sizel, &sizeh);
465                         if (asd == 0)
466                                 break;
467
468                         if (!asidx--) {
469                                 *addr = addrl;
470                                 *size = sizel;
471                                 return;
472                         }
473                         j++;
474                 } while (1);
475
476                 if (j == 0) {
477                         SI_ERROR((" SP %d has no address descriptors\n", i));
478                         break;
479                 }
480         }
481
482 error:
483         *size = 0;
484         return;
485 }
486
487 /* Return the number of address spaces in current core */
488 int
489 ai_numaddrspaces(si_t *sih)
490 {
491         return 2;
492 }
493
494 /* Return the address of the nth address space in the current core */
495 uint32
496 ai_addrspace(si_t *sih, uint asidx)
497 {
498         si_info_t *sii = SI_INFO(sih);
499         si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
500         uint cidx;
501
502         cidx = sii->curidx;
503
504         if (asidx == 0)
505                 return cores_info->coresba[cidx];
506         else if (asidx == 1)
507                 return cores_info->coresba2[cidx];
508         else {
509                 SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n",
510                           __FUNCTION__, asidx));
511                 return 0;
512         }
513 }
514
515 /* Return the size of the nth address space in the current core */
516 uint32
517 ai_addrspacesize(si_t *sih, uint asidx)
518 {
519         si_info_t *sii = SI_INFO(sih);
520         si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
521         uint cidx;
522
523         cidx = sii->curidx;
524
525         if (asidx == 0)
526                 return cores_info->coresba_size[cidx];
527         else if (asidx == 1)
528                 return cores_info->coresba2_size[cidx];
529         else {
530                 SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n",
531                           __FUNCTION__, asidx));
532                 return 0;
533         }
534 }
535
536 uint
537 ai_flag(si_t *sih)
538 {
539         si_info_t *sii = SI_INFO(sih);
540         aidmp_t *ai;
541
542         if (BCM47162_DMP()) {
543                 SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__));
544                 return sii->curidx;
545         }
546         if (BCM5357_DMP()) {
547                 SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__));
548                 return sii->curidx;
549         }
550         if (BCM4707_DMP()) {
551                 SI_ERROR(("%s: Attempting to read CHIPCOMMONB DMP registers on 4707\n",
552                         __FUNCTION__));
553                 return sii->curidx;
554         }
555
556 #ifdef REROUTE_OOBINT
557         if (PMU_DMP()) {
558                 SI_ERROR(("%s: Attempting to read PMU DMP registers\n",
559                         __FUNCTION__));
560                 return PMU_OOB_BIT;
561         }
562 #endif /* REROUTE_OOBINT */
563
564         ai = sii->curwrap;
565         ASSERT(ai != NULL);
566
567         return (R_REG(sii->osh, &ai->oobselouta30) & 0x1f);
568 }
569
570 uint
571 ai_flag_alt(si_t *sih)
572 {
573         si_info_t *sii = SI_INFO(sih);
574         aidmp_t *ai;
575
576         if (BCM47162_DMP()) {
577                 SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__));
578                 return sii->curidx;
579         }
580         if (BCM5357_DMP()) {
581                 SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__));
582                 return sii->curidx;
583         }
584         if (BCM4707_DMP()) {
585                 SI_ERROR(("%s: Attempting to read CHIPCOMMONB DMP registers on 4707\n",
586                         __FUNCTION__));
587                 return sii->curidx;
588         }
589 #ifdef REROUTE_OOBINT
590         if (PMU_DMP()) {
591                 SI_ERROR(("%s: Attempting to read PMU DMP registers\n",
592                         __FUNCTION__));
593                 return PMU_OOB_BIT;
594         }
595 #endif /* REROUTE_OOBINT */
596
597         ai = sii->curwrap;
598
599         return ((R_REG(sii->osh, &ai->oobselouta30) >> AI_OOBSEL_1_SHIFT) & AI_OOBSEL_MASK);
600 }
601
602 void
603 ai_setint(si_t *sih, int siflag)
604 {
605 }
606
607 uint
608 ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val)
609 {
610         si_info_t *sii = SI_INFO(sih);
611         uint32 *map = (uint32 *) sii->curwrap;
612
613         if (mask || val) {
614                 uint32 w = R_REG(sii->osh, map+(offset/4));
615                 w &= ~mask;
616                 w |= val;
617                 W_REG(sii->osh, map+(offset/4), w);
618         }
619
620         return (R_REG(sii->osh, map+(offset/4)));
621 }
622
623 uint
624 ai_corevendor(si_t *sih)
625 {
626         si_info_t *sii = SI_INFO(sih);
627         si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
628         uint32 cia;
629
630         cia = cores_info->cia[sii->curidx];
631         return ((cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT);
632 }
633
634 uint
635 ai_corerev(si_t *sih)
636 {
637         si_info_t *sii = SI_INFO(sih);
638         si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
639         uint32 cib;
640
641
642         cib = cores_info->cib[sii->curidx];
643         return remap_corerev(sih, (cib & CIB_REV_MASK) >> CIB_REV_SHIFT);
644 }
645
646 bool
647 ai_iscoreup(si_t *sih)
648 {
649         si_info_t *sii = SI_INFO(sih);
650         aidmp_t *ai;
651
652         ai = sii->curwrap;
653
654         return (((R_REG(sii->osh, &ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == SICF_CLOCK_EN) &&
655                 ((R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) == 0));
656 }
657
658 /*
659  * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation,
660  * switch back to the original core, and return the new value.
661  *
662  * When using the silicon backplane, no fiddling with interrupts or core switches is needed.
663  *
664  * Also, when using pci/pcie, we can optimize away the core switching for pci registers
665  * and (on newer pci cores) chipcommon registers.
666  */
667 uint
668 ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
669 {
670         uint origidx = 0;
671         uint32 *r = NULL;
672         uint w;
673         uint intr_val = 0;
674         bool fast = FALSE;
675         si_info_t *sii = SI_INFO(sih);
676         si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
677
678
679         ASSERT(GOODIDX(coreidx));
680         ASSERT(regoff < SI_CORE_SIZE);
681         ASSERT((val & ~mask) == 0);
682
683         if (coreidx >= SI_MAXCORES)
684                 return 0;
685
686         if (BUSTYPE(sih->bustype) == SI_BUS) {
687                 /* If internal bus, we can always get at everything */
688                 fast = TRUE;
689                 /* map if does not exist */
690                 if (!cores_info->regs[coreidx]) {
691                         cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx],
692                                                     SI_CORE_SIZE);
693                         ASSERT(GOODREGS(cores_info->regs[coreidx]));
694                 }
695                 r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff);
696         } else if (BUSTYPE(sih->bustype) == PCI_BUS) {
697                 /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */
698
699                 if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) {
700                         /* Chipc registers are mapped at 12KB */
701
702                         fast = TRUE;
703                         r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff);
704                 } else if (sii->pub.buscoreidx == coreidx) {
705                         /* pci registers are at either in the last 2KB of an 8KB window
706                          * or, in pcie and pci rev 13 at 8KB
707                          */
708                         fast = TRUE;
709                         if (SI_FAST(sii))
710                                 r = (uint32 *)((char *)sii->curmap +
711                                                PCI_16KB0_PCIREGS_OFFSET + regoff);
712                         else
713                                 r = (uint32 *)((char *)sii->curmap +
714                                                ((regoff >= SBCONFIGOFF) ?
715                                                 PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) +
716                                                regoff);
717                 }
718         }
719
720         if (!fast) {
721                 INTR_OFF(sii, intr_val);
722
723                 /* save current core index */
724                 origidx = si_coreidx(&sii->pub);
725
726                 /* switch core */
727                 r = (uint32*) ((uchar*) ai_setcoreidx(&sii->pub, coreidx) + regoff);
728         }
729         ASSERT(r != NULL);
730
731         /* mask and set */
732         if (mask || val) {
733                 w = (R_REG(sii->osh, r) & ~mask) | val;
734                 W_REG(sii->osh, r, w);
735         }
736
737         /* readback */
738         w = R_REG(sii->osh, r);
739
740         if (!fast) {
741                 /* restore core index */
742                 if (origidx != coreidx)
743                         ai_setcoreidx(&sii->pub, origidx);
744
745                 INTR_RESTORE(sii, intr_val);
746         }
747
748         return (w);
749 }
750
751 /*
752  * If there is no need for fiddling with interrupts or core switches (typically silicon
753  * back plane registers, pci registers and chipcommon registers), this function
754  * returns the register offset on this core to a mapped address. This address can
755  * be used for W_REG/R_REG directly.
756  *
757  * For accessing registers that would need a core switch, this function will return
758  * NULL.
759  */
760 uint32 *
761 ai_corereg_addr(si_t *sih, uint coreidx, uint regoff)
762 {
763         uint32 *r = NULL;
764         bool fast = FALSE;
765         si_info_t *sii = SI_INFO(sih);
766         si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
767
768
769         ASSERT(GOODIDX(coreidx));
770         ASSERT(regoff < SI_CORE_SIZE);
771
772         if (coreidx >= SI_MAXCORES)
773                 return 0;
774
775         if (BUSTYPE(sih->bustype) == SI_BUS) {
776                 /* If internal bus, we can always get at everything */
777                 fast = TRUE;
778                 /* map if does not exist */
779                 if (!cores_info->regs[coreidx]) {
780                         cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx],
781                                                     SI_CORE_SIZE);
782                         ASSERT(GOODREGS(cores_info->regs[coreidx]));
783                 }
784                 r = (uint32 *)((uchar *)cores_info->regs[coreidx] + regoff);
785         } else if (BUSTYPE(sih->bustype) == PCI_BUS) {
786                 /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */
787
788                 if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) {
789                         /* Chipc registers are mapped at 12KB */
790
791                         fast = TRUE;
792                         r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff);
793                 } else if (sii->pub.buscoreidx == coreidx) {
794                         /* pci registers are at either in the last 2KB of an 8KB window
795                          * or, in pcie and pci rev 13 at 8KB
796                          */
797                         fast = TRUE;
798                         if (SI_FAST(sii))
799                                 r = (uint32 *)((char *)sii->curmap +
800                                                PCI_16KB0_PCIREGS_OFFSET + regoff);
801                         else
802                                 r = (uint32 *)((char *)sii->curmap +
803                                                ((regoff >= SBCONFIGOFF) ?
804                                                 PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) +
805                                                regoff);
806                 }
807         }
808
809         if (!fast)
810                 return 0;
811
812         return (r);
813 }
814
815 void
816 ai_core_disable(si_t *sih, uint32 bits)
817 {
818         si_info_t *sii = SI_INFO(sih);
819         volatile uint32 dummy;
820         uint32 status;
821         aidmp_t *ai;
822
823
824         ASSERT(GOODREGS(sii->curwrap));
825         ai = sii->curwrap;
826
827         /* if core is already in reset, just return */
828         if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET)
829                 return;
830
831         /* ensure there are no pending backplane operations */
832         SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 300);
833
834         /* if pending backplane ops still, try waiting longer */
835         if (status != 0) {
836                 /* 300usecs was sufficient to allow backplane ops to clear for big hammer */
837                 /* during driver load we may need more time */
838                 SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 10000);
839                 /* if still pending ops, continue on and try disable anyway */
840                 /* this is in big hammer path, so don't call wl_reinit in this case... */
841         }
842
843         W_REG(sii->osh, &ai->resetctrl, AIRC_RESET);
844         dummy = R_REG(sii->osh, &ai->resetctrl);
845         BCM_REFERENCE(dummy);
846         OSL_DELAY(1);
847
848         W_REG(sii->osh, &ai->ioctrl, bits);
849         dummy = R_REG(sii->osh, &ai->ioctrl);
850         BCM_REFERENCE(dummy);
851         OSL_DELAY(10);
852 }
853
854 /* reset and re-enable a core
855  * inputs:
856  * bits - core specific bits that are set during and after reset sequence
857  * resetbits - core specific bits that are set only during reset sequence
858  */
859 void
860 ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits)
861 {
862         si_info_t *sii = SI_INFO(sih);
863         aidmp_t *ai;
864         volatile uint32 dummy;
865         uint loop_counter = 10;
866
867         ASSERT(GOODREGS(sii->curwrap));
868         ai = sii->curwrap;
869
870         /* ensure there are no pending backplane operations */
871         SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300);
872
873
874         /* put core into reset state */
875         W_REG(sii->osh, &ai->resetctrl, AIRC_RESET);
876         OSL_DELAY(10);
877
878         /* ensure there are no pending backplane operations */
879         SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), 300);
880
881         W_REG(sii->osh, &ai->ioctrl, (bits | resetbits | SICF_FGC | SICF_CLOCK_EN));
882         dummy = R_REG(sii->osh, &ai->ioctrl);
883         BCM_REFERENCE(dummy);
884
885         /* ensure there are no pending backplane operations */
886         SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300);
887
888
889         while (R_REG(sii->osh, &ai->resetctrl) != 0 && --loop_counter != 0) {
890                 /* ensure there are no pending backplane operations */
891                 SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300);
892
893
894                 /* take core out of reset */
895                 W_REG(sii->osh, &ai->resetctrl, 0);
896
897                 /* ensure there are no pending backplane operations */
898                 SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), 300);
899         }
900
901
902         W_REG(sii->osh, &ai->ioctrl, (bits | SICF_CLOCK_EN));
903         dummy = R_REG(sii->osh, &ai->ioctrl);
904         BCM_REFERENCE(dummy);
905         OSL_DELAY(1);
906 }
907
908 void
909 ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val)
910 {
911         si_info_t *sii = SI_INFO(sih);
912         aidmp_t *ai;
913         uint32 w;
914
915
916         if (BCM47162_DMP()) {
917                 SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0",
918                           __FUNCTION__));
919                 return;
920         }
921         if (BCM5357_DMP()) {
922                 SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n",
923                           __FUNCTION__));
924                 return;
925         }
926         if (BCM4707_DMP()) {
927                 SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n",
928                         __FUNCTION__));
929                 return;
930         }
931         if (PMU_DMP()) {
932                 SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n",
933                         __FUNCTION__));
934                 return;
935         }
936
937         ASSERT(GOODREGS(sii->curwrap));
938         ai = sii->curwrap;
939
940         ASSERT((val & ~mask) == 0);
941
942         if (mask || val) {
943                 w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val);
944                 W_REG(sii->osh, &ai->ioctrl, w);
945         }
946 }
947
948 uint32
949 ai_core_cflags(si_t *sih, uint32 mask, uint32 val)
950 {
951         si_info_t *sii = SI_INFO(sih);
952         aidmp_t *ai;
953         uint32 w;
954
955         if (BCM47162_DMP()) {
956                 SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0",
957                           __FUNCTION__));
958                 return 0;
959         }
960         if (BCM5357_DMP()) {
961                 SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n",
962                           __FUNCTION__));
963                 return 0;
964         }
965         if (BCM4707_DMP()) {
966                 SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n",
967                         __FUNCTION__));
968                 return 0;
969         }
970
971         if (PMU_DMP()) {
972                 SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n",
973                         __FUNCTION__));
974                 return 0;
975         }
976         ASSERT(GOODREGS(sii->curwrap));
977         ai = sii->curwrap;
978
979         ASSERT((val & ~mask) == 0);
980
981         if (mask || val) {
982                 w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val);
983                 W_REG(sii->osh, &ai->ioctrl, w);
984         }
985
986         return R_REG(sii->osh, &ai->ioctrl);
987 }
988
989 uint32
990 ai_core_sflags(si_t *sih, uint32 mask, uint32 val)
991 {
992         si_info_t *sii = SI_INFO(sih);
993         aidmp_t *ai;
994         uint32 w;
995
996         if (BCM47162_DMP()) {
997                 SI_ERROR(("%s: Accessing MIPS DMP register (iostatus) on 47162a0",
998                           __FUNCTION__));
999                 return 0;
1000         }
1001         if (BCM5357_DMP()) {
1002                 SI_ERROR(("%s: Accessing USB20H DMP register (iostatus) on 5357\n",
1003                           __FUNCTION__));
1004                 return 0;
1005         }
1006         if (BCM4707_DMP()) {
1007                 SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n",
1008                         __FUNCTION__));
1009                 return 0;
1010         }
1011         if (PMU_DMP()) {
1012                 SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n",
1013                         __FUNCTION__));
1014                 return 0;
1015         }
1016
1017         ASSERT(GOODREGS(sii->curwrap));
1018         ai = sii->curwrap;
1019
1020         ASSERT((val & ~mask) == 0);
1021         ASSERT((mask & ~SISF_CORE_BITS) == 0);
1022
1023         if (mask || val) {
1024                 w = ((R_REG(sii->osh, &ai->iostatus) & ~mask) | val);
1025                 W_REG(sii->osh, &ai->iostatus, w);
1026         }
1027
1028         return R_REG(sii->osh, &ai->iostatus);
1029 }
1030
1031 #if defined(BCMDBG_PHYDUMP)
1032 /* print interesting aidmp registers */
1033 void
1034 ai_dumpregs(si_t *sih, struct bcmstrbuf *b)
1035 {
1036         si_info_t *sii = SI_INFO(sih);
1037         si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
1038         osl_t *osh;
1039         aidmp_t *ai;
1040         uint i;
1041
1042         osh = sii->osh;
1043
1044         for (i = 0; i < sii->numcores; i++) {
1045                 si_setcoreidx(&sii->pub, i);
1046                 ai = sii->curwrap;
1047
1048                 bcm_bprintf(b, "core 0x%x: \n", cores_info->coreid[i]);
1049                 if (BCM47162_DMP()) {
1050                         bcm_bprintf(b, "Skipping mips74k in 47162a0\n");
1051                         continue;
1052                 }
1053                 if (BCM5357_DMP()) {
1054                         bcm_bprintf(b, "Skipping usb20h in 5357\n");
1055                         continue;
1056                 }
1057                 if (BCM4707_DMP()) {
1058                         bcm_bprintf(b, "Skipping chipcommonb in 4707\n");
1059                         continue;
1060                 }
1061
1062                 if (PMU_DMP()) {
1063                         bcm_bprintf(b, "Skipping pmu core\n");
1064                         continue;
1065                 }
1066
1067                 bcm_bprintf(b, "ioctrlset 0x%x ioctrlclear 0x%x ioctrl 0x%x iostatus 0x%x"
1068                             "ioctrlwidth 0x%x iostatuswidth 0x%x\n"
1069                             "resetctrl 0x%x resetstatus 0x%x resetreadid 0x%x resetwriteid 0x%x\n"
1070                             "errlogctrl 0x%x errlogdone 0x%x errlogstatus 0x%x"
1071                             "errlogaddrlo 0x%x errlogaddrhi 0x%x\n"
1072                             "errlogid 0x%x errloguser 0x%x errlogflags 0x%x\n"
1073                             "intstatus 0x%x config 0x%x itcr 0x%x\n",
1074                             R_REG(osh, &ai->ioctrlset),
1075                             R_REG(osh, &ai->ioctrlclear),
1076                             R_REG(osh, &ai->ioctrl),
1077                             R_REG(osh, &ai->iostatus),
1078                             R_REG(osh, &ai->ioctrlwidth),
1079                             R_REG(osh, &ai->iostatuswidth),
1080                             R_REG(osh, &ai->resetctrl),
1081                             R_REG(osh, &ai->resetstatus),
1082                             R_REG(osh, &ai->resetreadid),
1083                             R_REG(osh, &ai->resetwriteid),
1084                             R_REG(osh, &ai->errlogctrl),
1085                             R_REG(osh, &ai->errlogdone),
1086                             R_REG(osh, &ai->errlogstatus),
1087                             R_REG(osh, &ai->errlogaddrlo),
1088                             R_REG(osh, &ai->errlogaddrhi),
1089                             R_REG(osh, &ai->errlogid),
1090                             R_REG(osh, &ai->errloguser),
1091                             R_REG(osh, &ai->errlogflags),
1092                             R_REG(osh, &ai->intstatus),
1093                             R_REG(osh, &ai->config),
1094                             R_REG(osh, &ai->itcr));
1095         }
1096 }
1097 #endif