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