Commit | Line | Data |
---|---|---|
cf2b4488 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 <pcicfg.h> | |
27 | #include <sbpcmcia.h> | |
28 | #include "siutils_priv.h" | |
29 | ||
30 | /* local prototypes */ | |
66cbd3ab GKH |
31 | static uint _sb_coreidx(si_info_t *sii, u32 sba); |
32 | static uint _sb_scan(si_info_t *sii, u32 sba, void *regs, uint bus, | |
33 | u32 sbba, uint ncores); | |
34 | static u32 _sb_coresba(si_info_t *sii); | |
cf2b4488 HP |
35 | static void *_sb_setcoreidx(si_info_t *sii, uint coreidx); |
36 | ||
37 | #define SET_SBREG(sii, r, mask, val) \ | |
38 | W_SBREG((sii), (r), ((R_SBREG((sii), (r)) & ~(mask)) | (val))) | |
562c8850 | 39 | #define REGS2SB(va) (sbconfig_t *) ((s8 *)(va) + SBCONFIGOFF) |
cf2b4488 HP |
40 | |
41 | /* sonicsrev */ | |
42 | #define SONICS_2_2 (SBIDL_RV_2_2 >> SBIDL_RV_SHIFT) | |
43 | #define SONICS_2_3 (SBIDL_RV_2_3 >> SBIDL_RV_SHIFT) | |
44 | ||
45 | #define R_SBREG(sii, sbr) sb_read_sbreg((sii), (sbr)) | |
46 | #define W_SBREG(sii, sbr, v) sb_write_sbreg((sii), (sbr), (v)) | |
47 | #define AND_SBREG(sii, sbr, v) \ | |
48 | W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) & (v))) | |
49 | #define OR_SBREG(sii, sbr, v) \ | |
50 | W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) | (v))) | |
51 | ||
66cbd3ab | 52 | static u32 sb_read_sbreg(si_info_t *sii, volatile u32 *sbr) |
cf2b4488 HP |
53 | { |
54 | return R_REG(sii->osh, sbr); | |
55 | } | |
56 | ||
66cbd3ab | 57 | static void sb_write_sbreg(si_info_t *sii, volatile u32 *sbr, u32 v) |
cf2b4488 HP |
58 | { |
59 | W_REG(sii->osh, sbr, v); | |
60 | } | |
61 | ||
62 | uint sb_coreid(si_t *sih) | |
63 | { | |
64 | si_info_t *sii; | |
65 | sbconfig_t *sb; | |
66 | ||
67 | sii = SI_INFO(sih); | |
68 | sb = REGS2SB(sii->curmap); | |
69 | ||
70 | return (R_SBREG(sii, &sb->sbidhigh) & SBIDH_CC_MASK) >> | |
71 | SBIDH_CC_SHIFT; | |
72 | } | |
73 | ||
74 | /* return core index of the core with address 'sba' */ | |
0d2f0724 | 75 | static uint _sb_coreidx(si_info_t *sii, u32 sba) |
cf2b4488 HP |
76 | { |
77 | uint i; | |
78 | ||
79 | for (i = 0; i < sii->numcores; i++) | |
80 | if (sba == sii->coresba[i]) | |
81 | return i; | |
82 | return BADIDX; | |
83 | } | |
84 | ||
85 | /* return core address of the current core */ | |
0d2f0724 | 86 | static u32 _sb_coresba(si_info_t *sii) |
cf2b4488 | 87 | { |
66cbd3ab | 88 | u32 sbaddr = 0; |
cf2b4488 HP |
89 | |
90 | switch (BUSTYPE(sii->pub.bustype)) { | |
91 | case SPI_BUS: | |
92 | case SDIO_BUS: | |
66cbd3ab | 93 | sbaddr = (u32) (uintptr) sii->curmap; |
cf2b4488 HP |
94 | break; |
95 | default: | |
96 | ASSERT(0); | |
97 | break; | |
98 | } | |
99 | ||
100 | return sbaddr; | |
101 | } | |
102 | ||
103 | uint sb_corerev(si_t *sih) | |
104 | { | |
105 | si_info_t *sii; | |
106 | sbconfig_t *sb; | |
107 | uint sbidh; | |
108 | ||
109 | sii = SI_INFO(sih); | |
110 | sb = REGS2SB(sii->curmap); | |
111 | sbidh = R_SBREG(sii, &sb->sbidhigh); | |
112 | ||
113 | return SBCOREREV(sbidh); | |
114 | } | |
115 | ||
116 | bool sb_iscoreup(si_t *sih) | |
117 | { | |
118 | si_info_t *sii; | |
119 | sbconfig_t *sb; | |
120 | ||
121 | sii = SI_INFO(sih); | |
122 | sb = REGS2SB(sii->curmap); | |
123 | ||
124 | return (R_SBREG(sii, &sb->sbtmstatelow) & | |
125 | (SBTML_RESET | SBTML_REJ_MASK | | |
126 | (SICF_CLOCK_EN << SBTML_SICF_SHIFT))) == | |
127 | (SICF_CLOCK_EN << SBTML_SICF_SHIFT); | |
128 | } | |
129 | ||
130 | /* | |
131 | * Switch to 'coreidx', issue a single arbitrary 32bit | |
132 | * register mask&set operation, | |
133 | * switch back to the original core, and return the new value. | |
134 | * | |
135 | * When using the silicon backplane, no fidleing with interrupts | |
136 | * or core switches are needed. | |
137 | * | |
138 | * Also, when using pci/pcie, we can optimize away the core switching | |
139 | * for pci registers | |
140 | * and (on newer pci cores) chipcommon registers. | |
141 | */ | |
142 | uint sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) | |
143 | { | |
144 | uint origidx = 0; | |
66cbd3ab | 145 | u32 *r = NULL; |
cf2b4488 HP |
146 | uint w; |
147 | uint intr_val = 0; | |
0965ae88 | 148 | bool fast = false; |
cf2b4488 HP |
149 | si_info_t *sii; |
150 | ||
151 | sii = SI_INFO(sih); | |
152 | ||
153 | ASSERT(GOODIDX(coreidx)); | |
154 | ASSERT(regoff < SI_CORE_SIZE); | |
155 | ASSERT((val & ~mask) == 0); | |
156 | ||
157 | if (coreidx >= SI_MAXCORES) | |
158 | return 0; | |
159 | ||
160 | if (!fast) { | |
161 | INTR_OFF(sii, intr_val); | |
162 | ||
163 | /* save current core index */ | |
164 | origidx = si_coreidx(&sii->pub); | |
165 | ||
166 | /* switch core */ | |
66cbd3ab | 167 | r = (u32 *) ((unsigned char *) sb_setcoreidx(&sii->pub, coreidx) + |
cf2b4488 HP |
168 | regoff); |
169 | } | |
170 | ASSERT(r != NULL); | |
171 | ||
172 | /* mask and set */ | |
173 | if (mask || val) { | |
174 | if (regoff >= SBCONFIGOFF) { | |
175 | w = (R_SBREG(sii, r) & ~mask) | val; | |
176 | W_SBREG(sii, r, w); | |
177 | } else { | |
178 | w = (R_REG(sii->osh, r) & ~mask) | val; | |
179 | W_REG(sii->osh, r, w); | |
180 | } | |
181 | } | |
182 | ||
183 | /* readback */ | |
184 | if (regoff >= SBCONFIGOFF) | |
185 | w = R_SBREG(sii, r); | |
186 | else | |
187 | w = R_REG(sii->osh, r); | |
188 | ||
189 | if (!fast) { | |
190 | /* restore core index */ | |
191 | if (origidx != coreidx) | |
192 | sb_setcoreidx(&sii->pub, origidx); | |
193 | ||
194 | INTR_RESTORE(sii, intr_val); | |
195 | } | |
196 | ||
197 | return w; | |
198 | } | |
199 | ||
200 | /* Scan the enumeration space to find all cores starting from the given | |
201 | * bus 'sbba'. Append coreid and other info to the lists in 'si'. 'sba' | |
202 | * is the default core address at chip POR time and 'regs' is the virtual | |
203 | * address that the default core is mapped at. 'ncores' is the number of | |
204 | * cores expected on bus 'sbba'. It returns the total number of cores | |
205 | * starting from bus 'sbba', inclusive. | |
206 | */ | |
207 | #define SB_MAXBUSES 2 | |
0d2f0724 GKH |
208 | static uint _sb_scan(si_info_t *sii, u32 sba, void *regs, uint bus, u32 sbba, |
209 | uint numcores) | |
210 | { | |
cf2b4488 HP |
211 | uint next; |
212 | uint ncc = 0; | |
213 | uint i; | |
214 | ||
215 | if (bus >= SB_MAXBUSES) { | |
216 | SI_ERROR(("_sb_scan: bus 0x%08x at level %d is too deep to " | |
217 | "scan\n", sbba, bus)); | |
218 | return 0; | |
219 | } | |
220 | SI_MSG(("_sb_scan: scan bus 0x%08x assume %u cores\n", | |
221 | sbba, numcores)); | |
222 | ||
223 | /* Scan all cores on the bus starting from core 0. | |
224 | * Core addresses must be contiguous on each bus. | |
225 | */ | |
226 | for (i = 0, next = sii->numcores; | |
227 | i < numcores && next < SB_BUS_MAXCORES; i++, next++) { | |
228 | sii->coresba[next] = sbba + (i * SI_CORE_SIZE); | |
229 | ||
230 | /* change core to 'next' and read its coreid */ | |
231 | sii->curmap = _sb_setcoreidx(sii, next); | |
232 | sii->curidx = next; | |
233 | ||
234 | sii->coreid[next] = sb_coreid(&sii->pub); | |
235 | ||
236 | /* core specific processing... */ | |
237 | /* chipc provides # cores */ | |
238 | if (sii->coreid[next] == CC_CORE_ID) { | |
239 | chipcregs_t *cc = (chipcregs_t *) sii->curmap; | |
66cbd3ab | 240 | u32 ccrev = sb_corerev(&sii->pub); |
cf2b4488 HP |
241 | |
242 | /* determine numcores - this is the | |
243 | total # cores in the chip */ | |
244 | if (((ccrev == 4) || (ccrev >= 6))) | |
245 | numcores = | |
246 | (R_REG(sii->osh, &cc->chipid) & CID_CC_MASK) | |
247 | >> CID_CC_SHIFT; | |
248 | else { | |
249 | /* Older chips */ | |
250 | SI_ERROR(("sb_chip2numcores: unsupported chip " | |
251 | "0x%x\n", CHIPID(sii->pub.chip))); | |
252 | ASSERT(0); | |
253 | numcores = 1; | |
254 | } | |
255 | ||
256 | SI_VMSG(("_sb_scan: %u cores in the chip %s\n", | |
257 | numcores, sii->pub.issim ? "QT" : "")); | |
258 | } | |
259 | /* scan bridged SB(s) and add results to the end of the list */ | |
260 | else if (sii->coreid[next] == OCP_CORE_ID) { | |
261 | sbconfig_t *sb = REGS2SB(sii->curmap); | |
66cbd3ab | 262 | u32 nsbba = R_SBREG(sii, &sb->sbadmatch1); |
cf2b4488 HP |
263 | uint nsbcc; |
264 | ||
265 | sii->numcores = next + 1; | |
266 | ||
267 | if ((nsbba & 0xfff00000) != SI_ENUM_BASE) | |
268 | continue; | |
269 | nsbba &= 0xfffff000; | |
270 | if (_sb_coreidx(sii, nsbba) != BADIDX) | |
271 | continue; | |
272 | ||
273 | nsbcc = | |
274 | (R_SBREG(sii, &sb->sbtmstatehigh) & 0x000f0000) >> | |
275 | 16; | |
276 | nsbcc = _sb_scan(sii, sba, regs, bus + 1, nsbba, nsbcc); | |
277 | if (sbba == SI_ENUM_BASE) | |
278 | numcores -= nsbcc; | |
279 | ncc += nsbcc; | |
280 | } | |
281 | } | |
282 | ||
283 | SI_MSG(("_sb_scan: found %u cores on bus 0x%08x\n", i, sbba)); | |
284 | ||
285 | sii->numcores = i + ncc; | |
286 | return sii->numcores; | |
287 | } | |
288 | ||
289 | /* scan the sb enumerated space to identify all cores */ | |
0d2f0724 | 290 | void sb_scan(si_t *sih, void *regs, uint devid) |
cf2b4488 HP |
291 | { |
292 | si_info_t *sii; | |
66cbd3ab | 293 | u32 origsba; |
cf2b4488 HP |
294 | sbconfig_t *sb; |
295 | ||
296 | sii = SI_INFO(sih); | |
297 | sb = REGS2SB(sii->curmap); | |
298 | ||
299 | sii->pub.socirev = | |
300 | (R_SBREG(sii, &sb->sbidlow) & SBIDL_RV_MASK) >> SBIDL_RV_SHIFT; | |
301 | ||
302 | /* Save the current core info and validate it later till we know | |
303 | * for sure what is good and what is bad. | |
304 | */ | |
305 | origsba = _sb_coresba(sii); | |
306 | ||
307 | /* scan all SB(s) starting from SI_ENUM_BASE */ | |
308 | sii->numcores = _sb_scan(sii, origsba, regs, 0, SI_ENUM_BASE, 1); | |
309 | } | |
310 | ||
311 | /* | |
312 | * This function changes logical "focus" to the indicated core; | |
313 | * must be called with interrupts off. | |
314 | * Moreover, callers should keep interrupts off during switching out of | |
315 | * and back to d11 core | |
316 | */ | |
317 | void *sb_setcoreidx(si_t *sih, uint coreidx) | |
318 | { | |
319 | si_info_t *sii; | |
320 | ||
321 | sii = SI_INFO(sih); | |
322 | ||
323 | if (coreidx >= sii->numcores) | |
324 | return NULL; | |
325 | ||
326 | /* | |
327 | * If the user has provided an interrupt mask enabled function, | |
328 | * then assert interrupts are disabled before switching the core. | |
329 | */ | |
330 | ASSERT((sii->intrsenabled_fn == NULL) | |
331 | || !(*(sii)->intrsenabled_fn) ((sii)->intr_arg)); | |
332 | ||
333 | sii->curmap = _sb_setcoreidx(sii, coreidx); | |
334 | sii->curidx = coreidx; | |
335 | ||
336 | return sii->curmap; | |
337 | } | |
338 | ||
339 | /* This function changes the logical "focus" to the indicated core. | |
340 | * Return the current core's virtual address. | |
341 | */ | |
342 | static void *_sb_setcoreidx(si_info_t *sii, uint coreidx) | |
343 | { | |
66cbd3ab | 344 | u32 sbaddr = sii->coresba[coreidx]; |
cf2b4488 HP |
345 | void *regs; |
346 | ||
347 | switch (BUSTYPE(sii->pub.bustype)) { | |
348 | #ifdef BCMSDIO | |
349 | case SPI_BUS: | |
350 | case SDIO_BUS: | |
351 | /* map new one */ | |
352 | if (!sii->regs[coreidx]) { | |
c03b63c1 | 353 | sii->regs[coreidx] = (void *)sbaddr; |
cf2b4488 HP |
354 | ASSERT(GOODREGS(sii->regs[coreidx])); |
355 | } | |
356 | regs = sii->regs[coreidx]; | |
357 | break; | |
358 | #endif /* BCMSDIO */ | |
359 | default: | |
360 | ASSERT(0); | |
361 | regs = NULL; | |
362 | break; | |
363 | } | |
364 | ||
365 | return regs; | |
366 | } | |
367 | ||
368 | /* traverse all cores to find and clear source of serror */ | |
369 | static void sb_serr_clear(si_info_t *sii) | |
370 | { | |
371 | sbconfig_t *sb; | |
372 | uint origidx; | |
373 | uint i, intr_val = 0; | |
374 | void *corereg = NULL; | |
375 | ||
376 | INTR_OFF(sii, intr_val); | |
377 | origidx = si_coreidx(&sii->pub); | |
378 | ||
379 | for (i = 0; i < sii->numcores; i++) { | |
380 | corereg = sb_setcoreidx(&sii->pub, i); | |
381 | if (NULL != corereg) { | |
382 | sb = REGS2SB(corereg); | |
383 | if ((R_SBREG(sii, &sb->sbtmstatehigh)) & SBTMH_SERR) { | |
384 | AND_SBREG(sii, &sb->sbtmstatehigh, ~SBTMH_SERR); | |
385 | SI_ERROR(("sb_serr_clear: SError core 0x%x\n", | |
386 | sb_coreid(&sii->pub))); | |
387 | } | |
388 | } | |
389 | } | |
390 | ||
391 | sb_setcoreidx(&sii->pub, origidx); | |
392 | INTR_RESTORE(sii, intr_val); | |
393 | } | |
394 | ||
395 | /* | |
396 | * Check if any inband, outband or timeout errors has happened and clear them. | |
397 | * Must be called with chip clk on ! | |
398 | */ | |
399 | bool sb_taclear(si_t *sih, bool details) | |
400 | { | |
401 | si_info_t *sii; | |
402 | sbconfig_t *sb; | |
403 | uint origidx; | |
404 | uint intr_val = 0; | |
0965ae88 | 405 | bool rc = false; |
66cbd3ab | 406 | u32 inband = 0, serror = 0, timeout = 0; |
cf2b4488 | 407 | void *corereg = NULL; |
66cbd3ab | 408 | volatile u32 imstate, tmstate; |
cf2b4488 HP |
409 | |
410 | sii = SI_INFO(sih); | |
411 | ||
412 | if ((BUSTYPE(sii->pub.bustype) == SDIO_BUS) || | |
413 | (BUSTYPE(sii->pub.bustype) == SPI_BUS)) { | |
414 | ||
415 | INTR_OFF(sii, intr_val); | |
416 | origidx = si_coreidx(sih); | |
417 | ||
418 | corereg = si_setcore(sih, PCMCIA_CORE_ID, 0); | |
419 | if (NULL == corereg) | |
420 | corereg = si_setcore(sih, SDIOD_CORE_ID, 0); | |
421 | if (NULL != corereg) { | |
422 | sb = REGS2SB(corereg); | |
423 | ||
424 | imstate = R_SBREG(sii, &sb->sbimstate); | |
425 | if ((imstate != 0xffffffff) | |
426 | && (imstate & (SBIM_IBE | SBIM_TO))) { | |
427 | AND_SBREG(sii, &sb->sbimstate, | |
428 | ~(SBIM_IBE | SBIM_TO)); | |
429 | /* inband = imstate & SBIM_IBE; cmd error */ | |
430 | timeout = imstate & SBIM_TO; | |
431 | } | |
432 | tmstate = R_SBREG(sii, &sb->sbtmstatehigh); | |
433 | if ((tmstate != 0xffffffff) | |
434 | && (tmstate & SBTMH_INT_STATUS)) { | |
435 | sb_serr_clear(sii); | |
436 | serror = 1; | |
437 | OR_SBREG(sii, &sb->sbtmstatelow, SBTML_INT_ACK); | |
438 | AND_SBREG(sii, &sb->sbtmstatelow, | |
439 | ~SBTML_INT_ACK); | |
440 | } | |
441 | } | |
442 | ||
443 | sb_setcoreidx(sih, origidx); | |
444 | INTR_RESTORE(sii, intr_val); | |
445 | } | |
446 | ||
447 | if (inband | timeout | serror) { | |
0f0881b0 | 448 | rc = true; |
cf2b4488 HP |
449 | SI_ERROR(("sb_taclear: inband 0x%x, serror 0x%x, timeout " |
450 | "0x%x!\n", inband, serror, timeout)); | |
451 | } | |
452 | ||
453 | return rc; | |
454 | } | |
455 | ||
66cbd3ab | 456 | void sb_core_disable(si_t *sih, u32 bits) |
cf2b4488 HP |
457 | { |
458 | si_info_t *sii; | |
66cbd3ab | 459 | volatile u32 dummy; |
cf2b4488 HP |
460 | sbconfig_t *sb; |
461 | ||
462 | sii = SI_INFO(sih); | |
463 | ||
464 | ASSERT(GOODREGS(sii->curmap)); | |
465 | sb = REGS2SB(sii->curmap); | |
466 | ||
467 | /* if core is already in reset, just return */ | |
468 | if (R_SBREG(sii, &sb->sbtmstatelow) & SBTML_RESET) | |
469 | return; | |
470 | ||
471 | /* if clocks are not enabled, put into reset and return */ | |
472 | if ((R_SBREG(sii, &sb->sbtmstatelow) & | |
473 | (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) == 0) | |
474 | goto disable; | |
475 | ||
476 | /* set target reject and spin until busy is clear | |
477 | (preserve core-specific bits) */ | |
478 | OR_SBREG(sii, &sb->sbtmstatelow, SBTML_REJ); | |
479 | dummy = R_SBREG(sii, &sb->sbtmstatelow); | |
480 | OSL_DELAY(1); | |
481 | SPINWAIT((R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY), 100000); | |
482 | if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY) | |
483 | SI_ERROR(("%s: target state still busy\n", __func__)); | |
484 | ||
485 | if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) { | |
486 | OR_SBREG(sii, &sb->sbimstate, SBIM_RJ); | |
487 | dummy = R_SBREG(sii, &sb->sbimstate); | |
488 | OSL_DELAY(1); | |
489 | SPINWAIT((R_SBREG(sii, &sb->sbimstate) & SBIM_BY), 100000); | |
490 | } | |
491 | ||
492 | /* set reset and reject while enabling the clocks */ | |
493 | W_SBREG(sii, &sb->sbtmstatelow, | |
494 | (((bits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | | |
495 | SBTML_REJ | SBTML_RESET)); | |
496 | dummy = R_SBREG(sii, &sb->sbtmstatelow); | |
497 | OSL_DELAY(10); | |
498 | ||
499 | /* don't forget to clear the initiator reject bit */ | |
500 | if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) | |
501 | AND_SBREG(sii, &sb->sbimstate, ~SBIM_RJ); | |
502 | ||
503 | disable: | |
504 | /* leave reset and reject asserted */ | |
505 | W_SBREG(sii, &sb->sbtmstatelow, | |
506 | ((bits << SBTML_SICF_SHIFT) | SBTML_REJ | SBTML_RESET)); | |
507 | OSL_DELAY(1); | |
508 | } | |
509 | ||
510 | /* reset and re-enable a core | |
511 | * inputs: | |
512 | * bits - core specific bits that are set during and after reset sequence | |
513 | * resetbits - core specific bits that are set only during reset sequence | |
514 | */ | |
66cbd3ab | 515 | void sb_core_reset(si_t *sih, u32 bits, u32 resetbits) |
cf2b4488 HP |
516 | { |
517 | si_info_t *sii; | |
518 | sbconfig_t *sb; | |
66cbd3ab | 519 | volatile u32 dummy; |
cf2b4488 HP |
520 | |
521 | sii = SI_INFO(sih); | |
522 | ASSERT(GOODREGS(sii->curmap)); | |
523 | sb = REGS2SB(sii->curmap); | |
524 | ||
525 | /* | |
526 | * Must do the disable sequence first to work for | |
527 | * arbitrary current core state. | |
528 | */ | |
529 | sb_core_disable(sih, (bits | resetbits)); | |
530 | ||
531 | /* | |
532 | * Now do the initialization sequence. | |
533 | */ | |
534 | ||
535 | /* set reset while enabling the clock and | |
536 | forcing them on throughout the core */ | |
537 | W_SBREG(sii, &sb->sbtmstatelow, | |
538 | (((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << | |
539 | SBTML_SICF_SHIFT) | SBTML_RESET)); | |
540 | dummy = R_SBREG(sii, &sb->sbtmstatelow); | |
541 | OSL_DELAY(1); | |
542 | ||
543 | if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_SERR) | |
544 | W_SBREG(sii, &sb->sbtmstatehigh, 0); | |
545 | ||
eb7f37b3 JC |
546 | dummy = R_SBREG(sii, &sb->sbimstate); |
547 | if (dummy & (SBIM_IBE | SBIM_TO)) | |
cf2b4488 HP |
548 | AND_SBREG(sii, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO)); |
549 | ||
550 | /* clear reset and allow it to propagate throughout the core */ | |
551 | W_SBREG(sii, &sb->sbtmstatelow, | |
552 | ((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << | |
553 | SBTML_SICF_SHIFT)); | |
554 | dummy = R_SBREG(sii, &sb->sbtmstatelow); | |
555 | OSL_DELAY(1); | |
556 | ||
557 | /* leave clock enabled */ | |
558 | W_SBREG(sii, &sb->sbtmstatelow, | |
559 | ((bits | SICF_CLOCK_EN) << SBTML_SICF_SHIFT)); | |
560 | dummy = R_SBREG(sii, &sb->sbtmstatelow); | |
561 | OSL_DELAY(1); | |
562 | } | |
563 | ||
66cbd3ab | 564 | u32 sb_base(u32 admatch) |
cf2b4488 | 565 | { |
66cbd3ab | 566 | u32 base; |
cf2b4488 HP |
567 | uint type; |
568 | ||
569 | type = admatch & SBAM_TYPE_MASK; | |
570 | ASSERT(type < 3); | |
571 | ||
572 | base = 0; | |
573 | ||
574 | if (type == 0) { | |
575 | base = admatch & SBAM_BASE0_MASK; | |
576 | } else if (type == 1) { | |
577 | ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ | |
578 | base = admatch & SBAM_BASE1_MASK; | |
579 | } else if (type == 2) { | |
580 | ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ | |
581 | base = admatch & SBAM_BASE2_MASK; | |
582 | } | |
583 | ||
584 | return base; | |
585 | } |