Changes for kernel and Busybox
[tomato.git] / release / src / shared / hndchipc.c
blob1ec96d386aec5c112fed4255008f184b3db2822e
1 /*
2 * BCM47XX support code for some chipcommon facilities (uart, jtagm)
4 * Copyright 2007, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
12 * $Id$
15 #include <typedefs.h>
16 #include <bcmdefs.h>
17 #include <osl.h>
18 #include <bcmutils.h>
19 #include <sbutils.h>
20 #include <bcmdevs.h>
21 #include <bcmnvram.h>
22 #include <sbconfig.h>
23 #include <sbchipc.h>
24 #include <hndchipc.h>
25 #include <hndcpu.h>
27 /* debug/trace */
28 #define CC_ERROR(args)
30 #define CC_MSG(args)
32 /* interested chipcommon interrupt source
33 * - GPIO
34 * - EXTIF
35 * - ECI
36 * - PMU
37 * - UART
39 #define MAX_CC_INT_SOURCE 5
41 /* chipc secondary isr info */
42 typedef struct {
43 uint intmask; /* int mask */
44 cc_isr_fn isr; /* secondary isr handler */
45 void *cbdata; /* pointer to private data */
46 } cc_isr_info_t;
48 static cc_isr_info_t cc_isr_desc[MAX_CC_INT_SOURCE];
50 /* chip common intmask */
51 static uint32 cc_intmask = 0;
54 * Initializes UART access. The callback function will be called once
55 * per found UART.
57 void
58 BCMINITFN(sb_serial_init)(sb_t *sbh, sb_serial_init_fn add)
60 osl_t *osh;
61 void *regs;
62 chipcregs_t *cc;
63 uint32 rev, cap, pll, baud_base, div;
64 uint irq;
65 int i, n;
67 osh = sb_osh(sbh);
69 cc = (chipcregs_t *)sb_setcore(sbh, SB_CC, 0);
70 ASSERT(cc);
72 /* Default value */
73 div = 48;
75 /* Determine core revision and capabilities */
76 rev = sbh->ccrev;
77 cap = sbh->cccaps;
78 pll = cap & CC_CAP_PLL_MASK;
80 /* Determine IRQ */
81 irq = sb_irq(sbh);
83 if (pll == PLL_TYPE1) {
84 /* PLL clock */
85 baud_base = sb_clock_rate(pll,
86 R_REG(osh, &cc->clockcontrol_n),
87 R_REG(osh, &cc->clockcontrol_m2));
88 div = 1;
89 } else {
90 /* 5354 chip common uart uses a constant clock
91 * frequency of 25MHz */
92 if (sb_corerev(sbh) == 20) {
93 /* Set the override bit so we don't divide it */
94 W_REG(osh, &cc->corecontrol, CC_UARTCLKO);
95 baud_base = 25000000;
96 } else if (rev >= 11 && rev != 15) {
97 /* Fixed ALP clock */
98 baud_base = sb_alp_clock(sbh);
99 div = 1;
100 /* Turn off UART clock before switching clock source */
101 if (rev >= 21)
102 AND_REG(osh, &cc->corecontrol, ~CC_UARTCLKEN);
103 /* Set the override bit so we don't divide it */
104 OR_REG(osh, &cc->corecontrol, CC_UARTCLKO);
105 if (rev >= 21)
106 OR_REG(osh, &cc->corecontrol, CC_UARTCLKEN);
107 } else if (rev >= 3) {
108 /* Internal backplane clock */
109 baud_base = sb_clock(sbh);
110 div = 2; /* Minimum divisor */
111 W_REG(osh, &cc->clkdiv,
112 ((R_REG(osh, &cc->clkdiv) & ~CLKD_UART) | div));
113 } else {
114 /* Fixed internal backplane clock */
115 baud_base = 88000000;
116 div = 48;
119 /* Clock source depends on strapping if UartClkOverride is unset */
120 if ((rev > 0) &&
121 ((R_REG(osh, &cc->corecontrol) & CC_UARTCLKO) == 0)) {
122 if ((cap & CC_CAP_UCLKSEL) == CC_CAP_UINTCLK) {
123 /* Internal divided backplane clock */
124 baud_base /= div;
125 } else {
126 /* Assume external clock of 1.8432 MHz */
127 baud_base = 1843200;
132 /* Add internal UARTs */
133 n = cap & CC_CAP_UARTS_MASK;
134 for (i = 0; i < n; i++) {
135 /* Register offset changed after revision 0 */
136 if (rev)
137 regs = (void *)((ulong) &cc->uart0data + (i * 256));
138 else
139 regs = (void *)((ulong) &cc->uart0data + (i * 8));
141 if (add)
142 add(regs, irq, baud_base, 0);
147 * Initialize jtag master and return handle for
148 * jtag_rwreg. Returns NULL on failure.
150 void *
151 sb_jtagm_init(sb_t *sbh, uint clkd, bool exttap)
153 void *regs;
155 if ((regs = sb_setcore(sbh, SB_CC, 0)) != NULL) {
156 chipcregs_t *cc = (chipcregs_t *) regs;
157 uint32 tmp;
160 * Determine jtagm availability from
161 * core revision and capabilities.
165 * Corerev 10 has jtagm, but the only chip
166 * with it does not have a mips, and
167 * the layout of the jtagcmd register is
168 * different. We'll only accept >= 11.
170 if (sbh->ccrev < 11)
171 return (NULL);
173 if ((sbh->cccaps & CC_CAP_JTAGP) == 0)
174 return (NULL);
176 /* Set clock divider if requested */
177 if (clkd != 0) {
178 tmp = R_REG(osh, &cc->clkdiv);
179 tmp = (tmp & ~CLKD_JTAG) |
180 ((clkd << CLKD_JTAG_SHIFT) & CLKD_JTAG);
181 W_REG(osh, &cc->clkdiv, tmp);
184 /* Enable jtagm */
185 tmp = JCTRL_EN | (exttap ? JCTRL_EXT_EN : 0);
186 W_REG(osh, &cc->jtagctrl, tmp);
189 return (regs);
192 void
193 sb_jtagm_disable(osl_t *osh, void *h)
195 chipcregs_t *cc = (chipcregs_t *)h;
197 W_REG(osh, &cc->jtagctrl, R_REG(osh, &cc->jtagctrl) & ~JCTRL_EN);
201 * Read/write a jtag register. Assumes a target with
202 * 8 bit IR and 32 bit DR.
204 #define IRWIDTH 8 /* Default Instruction Register width */
205 #define DRWIDTH 32 /* Default Data Register width */
207 uint32
208 jtag_rwreg(osl_t *osh, void *h, uint32 ir, uint32 dr)
210 chipcregs_t *cc = (chipcregs_t *) h;
211 uint32 tmp;
213 W_REG(osh, &cc->jtagir, ir);
214 W_REG(osh, &cc->jtagdr, dr);
215 tmp = JCMD_START | JCMD_ACC_IRDR |
216 ((IRWIDTH - 1) << JCMD_IRW_SHIFT) |
217 (DRWIDTH - 1);
218 W_REG(osh, &cc->jtagcmd, tmp);
219 while (((tmp = R_REG(osh, &cc->jtagcmd)) & JCMD_BUSY) == JCMD_BUSY) {
220 /* OSL_DELAY(1); */
223 tmp = R_REG(osh, &cc->jtagdr);
224 return (tmp);
229 * Interface to register chipc secondary isr
232 bool
233 BCMINITFN(sb_cc_register_isr)(sb_t *sbh, cc_isr_fn isr, uint32 ccintmask, void *cbdata)
235 bool done = FALSE;
236 chipcregs_t *regs;
237 uint origidx;
238 uint i;
240 /* Save the current core index */
241 origidx = sb_coreidx(sbh);
242 regs = sb_setcore(sbh, SB_CC, 0);
243 ASSERT(regs);
245 for (i = 0; i < MAX_CC_INT_SOURCE; i++) {
246 if (cc_isr_desc[i].isr == NULL) {
247 cc_isr_desc[i].isr = isr;
248 cc_isr_desc[i].cbdata = cbdata;
249 cc_isr_desc[i].intmask = ccintmask;
250 done = TRUE;
251 break;
255 if (done) {
256 cc_intmask = R_REG(sb_osh(sbh), &regs->intmask);
257 cc_intmask |= ccintmask;
258 W_REG(sb_osh(sbh), &regs->intmask, cc_intmask);
261 /* restore original coreidx */
262 sb_setcoreidx(sbh, origidx);
263 return done;
267 * chipc primary interrupt handler
271 void
272 sb_cc_isr(sb_t *sbh, chipcregs_t *regs)
274 uint32 ccintstatus;
275 uint32 intstatus;
276 uint32 i;
278 /* prior to rev 21 chipc interrupt means uart and gpio */
279 if (sbh->ccrev >= 21)
280 ccintstatus = R_REG(sb_osh(sbh), &regs->intstatus) & cc_intmask;
281 else
282 ccintstatus = (CI_UART | CI_GPIO);
284 for (i = 0; i < MAX_CC_INT_SOURCE; i ++) {
285 if ((cc_isr_desc[i].isr != NULL) &&
286 (intstatus = (cc_isr_desc[i].intmask & ccintstatus))) {
287 (cc_isr_desc[i].isr)(cc_isr_desc[i].cbdata, intstatus);