4e58bf18abd689180823d9eb18b53b74c8f3e2b4
[openwrt/openwrt.git] / target / linux / brcm-2.4 / files / arch / mips / bcm947xx / hndchipc.c
1 /*
2 * BCM47XX support code for some chipcommon facilities (uart, jtagm)
3 *
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.
11 *
12 */
13
14 #include <typedefs.h>
15 #include <bcmdefs.h>
16 #include <osl.h>
17 #include <sbutils.h>
18 #include <bcmdevs.h>
19 #include <bcmnvram.h>
20 #include <sbconfig.h>
21 #include <sbchipc.h>
22 #include <sbextif.h>
23 #include <hndchipc.h>
24 #include <hndcpu.h>
25
26 /* debug/trace */
27 #define CC_ERROR(args)
28
29 #ifdef BCMDBG
30 #define CC_MSG(args) printf args
31 #else
32 #define CC_MSG(args)
33 #endif /* BCMDBG */
34
35 /* interested chipcommon interrupt source
36 * - GPIO
37 * - EXTIF
38 * - ECI
39 * - PMU
40 * - UART
41 */
42 #define MAX_CC_INT_SOURCE 5
43
44 /* chipc secondary isr info */
45 typedef struct {
46 uint intmask; /* int mask */
47 cc_isr_fn isr; /* secondary isr handler */
48 void *cbdata; /* pointer to private data */
49 } cc_isr_info_t;
50
51 static cc_isr_info_t cc_isr_desc[MAX_CC_INT_SOURCE];
52
53 /* chip common intmask */
54 static uint32 cc_intmask = 0;
55
56 static bool BCMINITFN(serial_exists) (osl_t * osh, uint8 * regs) {
57 uint8 save_mcr, status1;
58
59 save_mcr = R_REG(osh, &regs[UART_MCR]);
60 W_REG(osh, &regs[UART_MCR], UART_MCR_LOOP | 0x0a);
61 status1 = R_REG(osh, &regs[UART_MSR]) & 0xf0;
62 W_REG(osh, &regs[UART_MCR], save_mcr);
63
64 return (status1 == 0x90);
65 }
66
67 static void __init sb_extif_serial_init(sb_t * sbh, void *regs,
68 sb_serial_init_fn add)
69 {
70 osl_t *osh = sb_osh(sbh);
71 extifregs_t *eir = (extifregs_t *) regs;
72 sbconfig_t *sb;
73 ulong base;
74 uint irq;
75 int i, n;
76
77 /* Determine external UART register base */
78 sb = (sbconfig_t *) ((ulong) eir + SBCONFIGOFF);
79 base = EXTIF_CFGIF_BASE(sb_base(R_REG(osh, &sb->sbadmatch1)));
80
81 /* Determine IRQ */
82 irq = sb_irq(sbh);
83
84 /* Disable GPIO interrupt initially */
85 W_REG(osh, &eir->gpiointpolarity, 0);
86 W_REG(osh, &eir->gpiointmask, 0);
87
88 /* Search for external UARTs */
89 n = 2;
90 for (i = 0; i < 2; i++) {
91 regs = (void *)REG_MAP(base + (i * 8), 8);
92 if (serial_exists(osh, regs)) {
93 /* Set GPIO 1 to be the external UART IRQ */
94 W_REG(osh, &eir->gpiointmask, 2);
95 /* XXXDetermine external UART clock */
96 if (add)
97 add(regs, irq, 13500000, 0);
98 }
99 }
100
101 /* Add internal UART if enabled */
102 if (R_REG(osh, &eir->corecontrol) & CC_UE)
103 if (add)
104 add((void *)&eir->uartdata, irq, sb_clock(sbh), 2);
105 }
106
107 /*
108 * Initializes UART access. The callback function will be called once
109 * per found UART.
110 */
111 void BCMINITFN(sb_serial_init) (sb_t * sbh, sb_serial_init_fn add) {
112 osl_t *osh;
113 void *regs;
114 chipcregs_t *cc;
115 uint32 rev, cap, pll, baud_base, div;
116 uint irq;
117 int i, n;
118
119 osh = sb_osh(sbh);
120
121 regs = sb_setcore(sbh, SB_EXTIF, 0);
122 if (regs) {
123 sb_extif_serial_init(sbh, regs, add);
124 return;
125 }
126
127 cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0);
128 ASSERT(cc);
129
130 /* Determine core revision and capabilities */
131 rev = sbh->ccrev;
132 cap = sbh->cccaps;
133 pll = cap & CC_CAP_PLL_MASK;
134
135 /* Determine IRQ */
136 irq = sb_irq(sbh);
137
138 if (pll == PLL_TYPE1) {
139 /* PLL clock */
140 baud_base = sb_clock_rate(pll,
141 R_REG(osh, &cc->clockcontrol_n),
142 R_REG(osh, &cc->clockcontrol_m2));
143 div = 1;
144 } else {
145 /* 5354 chip common uart uses a constant clock
146 * frequency of 25MHz */
147 if (sb_corerev(sbh) == 20) {
148 /* Set the override bit so we don't divide it */
149 W_REG(osh, &cc->corecontrol, CC_UARTCLKO);
150 baud_base = 25000000;
151 } else if (rev >= 11 && rev != 15) {
152 /* Fixed ALP clock */
153 baud_base = sb_alp_clock(sbh);
154 div = 1;
155 /* Turn off UART clock before switching clock source */
156 if (rev >= 21)
157 AND_REG(osh, &cc->corecontrol, ~CC_UARTCLKEN);
158 /* Set the override bit so we don't divide it */
159 OR_REG(osh, &cc->corecontrol, CC_UARTCLKO);
160 if (rev >= 21)
161 OR_REG(osh, &cc->corecontrol, CC_UARTCLKEN);
162 } else if (rev >= 3) {
163 /* Internal backplane clock */
164 baud_base = sb_clock(sbh);
165 div = 2; /* Minimum divisor */
166 W_REG(osh, &cc->clkdiv,
167 ((R_REG(osh, &cc->clkdiv) & ~CLKD_UART) | div));
168 } else {
169 /* Fixed internal backplane clock */
170 baud_base = 88000000;
171 div = 48;
172 }
173
174 /* Clock source depends on strapping if UartClkOverride is unset */
175 if ((rev > 0)
176 && ((R_REG(osh, &cc->corecontrol) & CC_UARTCLKO) == 0)) {
177 if ((cap & CC_CAP_UCLKSEL) == CC_CAP_UINTCLK) {
178 /* Internal divided backplane clock */
179 baud_base /= div;
180 } else {
181 /* Assume external clock of 1.8432 MHz */
182 baud_base = 1843200;
183 }
184 }
185 }
186
187 /* Add internal UARTs */
188 n = cap & CC_CAP_UARTS_MASK;
189 for (i = 0; i < n; i++) {
190 /* Register offset changed after revision 0 */
191 if (rev)
192 regs = (void *)((ulong) & cc->uart0data + (i * 256));
193 else
194 regs = (void *)((ulong) & cc->uart0data + (i * 8));
195
196 if (add)
197 add(regs, irq, baud_base, 0);
198 }
199 }
200
201 #if 0
202 /*
203 * Initialize jtag master and return handle for
204 * jtag_rwreg. Returns NULL on failure.
205 */
206 void *sb_jtagm_init(sb_t * sbh, uint clkd, bool exttap)
207 {
208 void *regs;
209
210 if ((regs = sb_setcore(sbh, SB_CC, 0)) != NULL) {
211 chipcregs_t *cc = (chipcregs_t *) regs;
212 uint32 tmp;
213
214 /*
215 * Determine jtagm availability from
216 * core revision and capabilities.
217 */
218
219 /*
220 * Corerev 10 has jtagm, but the only chip
221 * with it does not have a mips, and
222 * the layout of the jtagcmd register is
223 * different. We'll only accept >= 11.
224 */
225 if (sbh->ccrev < 11)
226 return (NULL);
227
228 if ((sbh->cccaps & CC_CAP_JTAGP) == 0)
229 return (NULL);
230
231 /* Set clock divider if requested */
232 if (clkd != 0) {
233 tmp = R_REG(osh, &cc->clkdiv);
234 tmp =
235 (tmp & ~CLKD_JTAG) | ((clkd << CLKD_JTAG_SHIFT) &
236 CLKD_JTAG);
237 W_REG(osh, &cc->clkdiv, tmp);
238 }
239
240 /* Enable jtagm */
241 tmp = JCTRL_EN | (exttap ? JCTRL_EXT_EN : 0);
242 W_REG(osh, &cc->jtagctrl, tmp);
243 }
244
245 return (regs);
246 }
247
248 void sb_jtagm_disable(osl_t * osh, void *h)
249 {
250 chipcregs_t *cc = (chipcregs_t *) h;
251
252 W_REG(osh, &cc->jtagctrl, R_REG(osh, &cc->jtagctrl) & ~JCTRL_EN);
253 }
254
255 /*
256 * Read/write a jtag register. Assumes a target with
257 * 8 bit IR and 32 bit DR.
258 */
259 #define IRWIDTH 8 /* Default Instruction Register width */
260 #define DRWIDTH 32 /* Default Data Register width */
261
262 uint32 jtag_rwreg(osl_t * osh, void *h, uint32 ir, uint32 dr)
263 {
264 chipcregs_t *cc = (chipcregs_t *) h;
265 uint32 tmp;
266
267 W_REG(osh, &cc->jtagir, ir);
268 W_REG(osh, &cc->jtagdr, dr);
269 tmp = JCMD_START | JCMD_ACC_IRDR |
270 ((IRWIDTH - 1) << JCMD_IRW_SHIFT) | (DRWIDTH - 1);
271 W_REG(osh, &cc->jtagcmd, tmp);
272 while (((tmp = R_REG(osh, &cc->jtagcmd)) & JCMD_BUSY) == JCMD_BUSY) {
273 /* OSL_DELAY(1); */
274 }
275
276 tmp = R_REG(osh, &cc->jtagdr);
277 return (tmp);
278 }
279 #endif
280
281 /*
282 * Interface to register chipc secondary isr
283 */
284 bool
285 BCMINITFN(sb_cc_register_isr) (sb_t * sbh, cc_isr_fn isr, uint32 ccintmask,
286 void *cbdata) {
287 bool done = FALSE;
288 chipcregs_t *regs;
289 uint origidx;
290 uint i;
291
292 /* Save the current core index */
293 origidx = sb_coreidx(sbh);
294 regs = sb_setcore(sbh, SB_CC, 0);
295 ASSERT(regs);
296
297 for (i = 0; i < MAX_CC_INT_SOURCE; i++) {
298 if (cc_isr_desc[i].isr == NULL) {
299 cc_isr_desc[i].isr = isr;
300 cc_isr_desc[i].cbdata = cbdata;
301 cc_isr_desc[i].intmask = ccintmask;
302 done = TRUE;
303 break;
304 }
305 }
306
307 if (done) {
308 cc_intmask = R_REG(sb_osh(sbh), &regs->intmask);
309 cc_intmask |= ccintmask;
310 W_REG(sb_osh(sbh), &regs->intmask, cc_intmask);
311 }
312
313 /* restore original coreidx */
314 sb_setcoreidx(sbh, origidx);
315 return done;
316 }
317
318 /*
319 * chipc primary interrupt handler
320 */
321 void sb_cc_isr(sb_t * sbh, chipcregs_t * regs)
322 {
323 uint32 ccintstatus;
324 uint32 intstatus;
325 uint32 i;
326
327 /* prior to rev 21 chipc interrupt means uart and gpio */
328 if (sbh->ccrev >= 21)
329 ccintstatus = R_REG(sb_osh(sbh), &regs->intstatus) & cc_intmask;
330 else
331 ccintstatus = (CI_UART | CI_GPIO);
332
333 for (i = 0; i < MAX_CC_INT_SOURCE; i++) {
334 if ((cc_isr_desc[i].isr != NULL) &&
335 (intstatus = (cc_isr_desc[i].intmask & ccintstatus))) {
336 (cc_isr_desc[i].isr) (cc_isr_desc[i].cbdata, intstatus);
337 }
338 }
339 }