Root/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 */
45typedef 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
51static cc_isr_info_t cc_isr_desc[MAX_CC_INT_SOURCE];
52
53/* chip common intmask */
54static uint32 cc_intmask = 0;
55
56static 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
67static 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 */
111void 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 */
206void *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
248void 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
262uint32 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 */
284bool
285BCMINITFN(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 */
321void 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}
340

Archive Download this file



interactive