1f1dc10efaa279ef3620ea1dcf900933562ee09f
[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 }