get rid of $Id$ - it has never helped us and it has broken too many patches ;)
[oweals/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 }