RT-AC66 3.0.0.4.374.130 core
[tomato.git] / release / src-rt-6.x / shared / hndchipc.c
blob6da3c15c673535d86010bbfe5d30012f49f44c46
1 /*
2 * BCM47XX support code for some chipcommon facilities (uart, jtagm)
4 * Copyright (C) 2010, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 * $Id: hndchipc.c,v 1.26 2010-01-05 19:11:24 Exp $
21 #include <typedefs.h>
22 #include <bcmdefs.h>
23 #include <osl.h>
24 #include <bcmutils.h>
25 #include <siutils.h>
26 #include <bcmnvram.h>
27 #include <hndsoc.h>
28 #include <sbchipc.h>
29 #include <hndchipc.h>
30 #include <hndcpu.h>
32 /* debug/trace */
33 #ifdef BCMDBG_ERR
34 #define CC_ERROR(args) printf args
35 #else
36 #define CC_ERROR(args)
37 #endif /* BCMDBG_ERR */
39 #ifdef BCMDBG
40 #define CC_MSG(args) printf args
41 #else
42 #define CC_MSG(args)
43 #endif /* BCMDBG */
45 /* interested chipcommon interrupt source
46 * - GPIO
47 * - EXTIF
48 * - ECI
49 * - PMU
50 * - UART
52 #define MAX_CC_INT_SOURCE 5
54 /* chipc secondary isr info */
55 typedef struct {
56 uint intmask; /* int mask */
57 cc_isr_fn isr; /* secondary isr handler */
58 void *cbdata; /* pointer to private data */
59 } cc_isr_info_t;
61 static cc_isr_info_t cc_isr_desc[MAX_CC_INT_SOURCE];
63 /* chip common intmask */
64 static uint32 cc_intmask = 0;
67 * Initializes UART access. The callback function will be called once
68 * per found UART.
70 void
71 BCMATTACHFN(si_serial_init)(si_t *sih, si_serial_init_fn add)
73 osl_t *osh;
74 void *regs;
75 chipcregs_t *cc;
76 uint32 rev, cap, pll, baud_base, div;
77 uint irq;
78 int i, n;
80 osh = si_osh(sih);
82 cc = (chipcregs_t *)si_setcoreidx(sih, SI_CC_IDX);
83 ASSERT(cc);
85 /* Default value */
86 div = 48;
88 /* Determine core revision and capabilities */
89 rev = sih->ccrev;
90 cap = sih->cccaps;
91 pll = cap & CC_CAP_PLL_MASK;
93 /* Determine IRQ */
94 irq = si_irq(sih);
96 if (CCPLL_ENAB(sih) && pll == PLL_TYPE1) {
97 /* PLL clock */
98 baud_base = si_clock_rate(pll,
99 R_REG(osh, &cc->clockcontrol_n),
100 R_REG(osh, &cc->clockcontrol_m2));
101 div = 1;
102 } else {
103 /* 5354 chip common uart uses a constant clock
104 * frequency of 25MHz */
105 if (rev == 20) {
106 /* Set the override bit so we don't divide it */
107 W_REG(osh, &cc->corecontrol, CC_UARTCLKO);
108 baud_base = 25000000;
109 } else if (rev >= 11 && rev != 15) {
110 /* Fixed ALP clock */
111 baud_base = si_alp_clock(sih);
112 div = 1;
113 /* Turn off UART clock before switching clock source */
114 if (rev >= 21)
115 AND_REG(osh, &cc->corecontrol, ~CC_UARTCLKEN);
116 /* Set the override bit so we don't divide it */
117 OR_REG(osh, &cc->corecontrol, CC_UARTCLKO);
118 if (rev >= 21)
119 OR_REG(osh, &cc->corecontrol, CC_UARTCLKEN);
120 } else if (rev >= 3) {
121 /* Internal backplane clock */
122 baud_base = si_clock(sih);
123 div = 2; /* Minimum divisor */
124 W_REG(osh, &cc->clkdiv,
125 ((R_REG(osh, &cc->clkdiv) & ~CLKD_UART) | div));
126 } else {
127 /* Fixed internal backplane clock */
128 baud_base = 88000000;
129 div = 48;
132 /* Clock source depends on strapping if UartClkOverride is unset */
133 if ((R_REG(osh, &cc->corecontrol) & CC_UARTCLKO) == 0) {
134 if ((cap & CC_CAP_UCLKSEL) == CC_CAP_UINTCLK) {
135 /* Internal divided backplane clock */
136 baud_base /= div;
137 } else {
138 /* Assume external clock of 1.8432 MHz */
139 baud_base = 1843200;
144 /* Add internal UARTs */
145 n = cap & CC_CAP_UARTS_MASK;
146 for (i = 0; i < n; i++) {
147 regs = (void *)((ulong) &cc->uart0data + (i * 256));
148 if (add)
149 add(regs, irq, baud_base, 0);
153 #define JTAG_RETRIES 10000
156 * Initialize jtag master and return handle for
157 * jtag_rwreg. Returns NULL on failure.
159 void *
160 hnd_jtagm_init(si_t *sih, uint clkd, bool exttap)
162 void *regs;
164 if ((regs = si_setcoreidx(sih, SI_CC_IDX)) != NULL) {
165 chipcregs_t *cc = (chipcregs_t *) regs;
166 uint32 tmp;
169 * Determine jtagm availability from
170 * core revision and capabilities.
174 * Corerev 10 has jtagm, but the only chip
175 * with it does not have a mips, and
176 * the layout of the jtagcmd register is
177 * different. We'll only accept >= 11.
179 if (sih->ccrev < 11)
180 return (NULL);
182 if ((sih->cccaps & CC_CAP_JTAGP) == 0)
183 return (NULL);
185 /* Set clock divider if requested */
186 if (clkd != 0) {
187 tmp = R_REG(NULL, &cc->clkdiv);
188 tmp = (tmp & ~CLKD_JTAG) |
189 ((clkd << CLKD_JTAG_SHIFT) & CLKD_JTAG);
190 W_REG(NULL, &cc->clkdiv, tmp);
193 /* Enable jtagm */
194 tmp = JCTRL_EN | (exttap ? JCTRL_EXT_EN : 0);
195 W_REG(NULL, &cc->jtagctrl, tmp);
198 return (regs);
201 void
202 hnd_jtagm_disable(si_t *sih, void *h)
204 chipcregs_t *cc = (chipcregs_t *)h;
206 W_REG(NULL, &cc->jtagctrl, R_REG(NULL, &cc->jtagctrl) & ~JCTRL_EN);
210 static uint32
211 jtm_wait(chipcregs_t *cc, bool readdr)
213 uint i;
215 i = 0;
216 while (((R_REG(NULL, &cc->jtagcmd) & JCMD_BUSY) == JCMD_BUSY) &&
217 (i < JTAG_RETRIES)) {
218 i++;
221 if (i >= JTAG_RETRIES)
222 return 0xbadbad03;
224 if (readdr)
225 return R_REG(NULL, &cc->jtagdr);
226 else
227 return 0xffffffff;
230 /* Read/write a jtag register. Assumes both ir and dr <= 64bits. */
232 uint32
233 jtag_scan(si_t *sih, void *h, uint irsz, uint32 ir0, uint32 ir1,
234 uint drsz, uint32 dr0, uint32 *dr1, bool rti)
236 chipcregs_t *cc = (chipcregs_t *) h;
237 uint32 acc_dr, acc_irdr;
238 uint32 tmp;
240 if ((irsz > 64) || (drsz > 64)) {
241 return 0xbadbad00;
243 if (rti) {
244 if (sih->ccrev < 28)
245 return 0xbadbad01;
246 acc_irdr = JCMD_ACC_IRDR_I;
247 acc_dr = JCMD_ACC_DR_I;
248 } else {
249 acc_irdr = JCMD_ACC_IRDR;
250 acc_dr = JCMD_ACC_DR;
252 if (irsz == 0) {
253 /* scan in the first (or only) DR word with a dr-only command */
254 W_REG(NULL, &cc->jtagdr, dr0);
255 if (drsz > 32) {
256 W_REG(NULL, &cc->jtagcmd, JCMD_START | JCMD_ACC_PDR | 31);
257 drsz -= 32;
258 } else
259 W_REG(NULL, &cc->jtagcmd, JCMD_START | acc_dr | (drsz - 1));
260 } else {
261 W_REG(NULL, &cc->jtagir, ir0);
262 if (irsz > 32) {
263 /* Use Partial IR for first IR word */
264 W_REG(NULL, &cc->jtagcmd, JCMD_START | JCMD_ACC_PIR |
265 (31 << JCMD_IRW_SHIFT));
266 jtm_wait(cc, FALSE);
267 W_REG(NULL, &cc->jtagir, ir1);
268 irsz -= 32;
270 if (drsz == 0) {
271 /* If drsz is 0, do an IR-only scan and that's it */
272 W_REG(NULL, &cc->jtagcmd, JCMD_START | JCMD_ACC_IR |
273 ((irsz - 1) << JCMD_IRW_SHIFT));
274 return jtm_wait(cc, FALSE);
276 /* Now scan in the IR word and the first (or only) DR word */
277 W_REG(NULL, &cc->jtagdr, dr0);
278 if (drsz <= 32)
279 W_REG(NULL, &cc->jtagcmd, JCMD_START | acc_irdr |
280 ((irsz - 1) << JCMD_IRW_SHIFT) | (drsz - 1));
281 else
282 W_REG(NULL, &cc->jtagcmd, JCMD_START | JCMD_ACC_IRPDR |
283 ((irsz - 1) << JCMD_IRW_SHIFT) | 31);
285 /* Now scan out the DR and scan in & out the second DR word if needed */
286 tmp = jtm_wait(cc, TRUE);
287 if (drsz > 32) {
288 if (dr1 == NULL)
289 return 0xbadbad04;
290 W_REG(NULL, &cc->jtagdr, *dr1);
291 W_REG(NULL, &cc->jtagcmd, JCMD_START | acc_dr | (drsz - 33));
292 *dr1 = jtm_wait(cc, TRUE);
294 return (tmp);
299 * Interface to register chipc secondary isr
302 bool
303 BCMATTACHFN(si_cc_register_isr)(si_t *sih, cc_isr_fn isr, uint32 ccintmask, void *cbdata)
305 bool done = FALSE;
306 chipcregs_t *regs;
307 uint origidx;
308 uint i;
310 /* Save the current core index */
311 origidx = si_coreidx(sih);
312 regs = si_setcoreidx(sih, SI_CC_IDX);
313 ASSERT(regs);
315 for (i = 0; i < MAX_CC_INT_SOURCE; i++) {
316 if (cc_isr_desc[i].isr == NULL) {
317 cc_isr_desc[i].isr = isr;
318 cc_isr_desc[i].cbdata = cbdata;
319 cc_isr_desc[i].intmask = ccintmask;
320 done = TRUE;
321 break;
325 if (done) {
326 cc_intmask = R_REG(si_osh(sih), &regs->intmask);
327 cc_intmask |= ccintmask;
328 W_REG(si_osh(sih), &regs->intmask, cc_intmask);
331 /* restore original coreidx */
332 si_setcoreidx(sih, origidx);
333 return done;
337 * chipc primary interrupt handler
341 void
342 si_cc_isr(si_t *sih, chipcregs_t *regs)
344 uint32 ccintstatus;
345 uint32 intstatus;
346 uint32 i;
348 /* prior to rev 21 chipc interrupt means uart and gpio */
349 if (sih->ccrev >= 21)
350 ccintstatus = R_REG(si_osh(sih), &regs->intstatus) & cc_intmask;
351 else
352 ccintstatus = (CI_UART | CI_GPIO);
354 for (i = 0; i < MAX_CC_INT_SOURCE; i ++) {
355 if ((cc_isr_desc[i].isr != NULL) &&
356 (intstatus = (cc_isr_desc[i].intmask & ccintstatus))) {
357 (cc_isr_desc[i].isr)(cc_isr_desc[i].cbdata, intstatus);