X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/7ed9009bbdf799be5f9f1446c264b8504f483beb..95316451cb8a4d8c63fb5cc7074912f497815f12:/target/linux/brcm-2.4/files/arch/mips/bcm947xx/hndchipc.c diff --git a/target/linux/brcm-2.4/files/arch/mips/bcm947xx/hndchipc.c b/target/linux/brcm-2.4/files/arch/mips/bcm947xx/hndchipc.c index 6502078de..1f1dc10ef 100644 --- a/target/linux/brcm-2.4/files/arch/mips/bcm947xx/hndchipc.c +++ b/target/linux/brcm-2.4/files/arch/mips/bcm947xx/hndchipc.c @@ -1,7 +1,7 @@ /* - * BCM47XX support code for some chipcommon (old extif) facilities (uart) + * BCM47XX support code for some chipcommon facilities (uart, jtagm) * - * Copyright 2006, Broadcom Corporation + * Copyright 2007, Broadcom Corporation * All Rights Reserved. * * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY @@ -9,28 +9,52 @@ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. * - * $Id: hndchipc.c,v 1.1.1.1 2006/02/27 03:43:16 honor Exp $ + * $Id$ */ #include #include #include -#include #include #include #include #include -#include #include +#include +#include #include -/* - * Returns TRUE if an external UART exists at the given base - * register. +/* debug/trace */ +#define CC_ERROR(args) + +#ifdef BCMDBG +#define CC_MSG(args) printf args +#else +#define CC_MSG(args) +#endif /* BCMDBG */ + +/* interested chipcommon interrupt source + * - GPIO + * - EXTIF + * - ECI + * - PMU + * - UART */ -static bool -BCMINITFN(serial_exists)(osl_t *osh, uint8 *regs) -{ +#define MAX_CC_INT_SOURCE 5 + +/* chipc secondary isr info */ +typedef struct { + uint intmask; /* int mask */ + cc_isr_fn isr; /* secondary isr handler */ + void *cbdata; /* pointer to private data */ +} cc_isr_info_t; + +static cc_isr_info_t cc_isr_desc[MAX_CC_INT_SOURCE]; + +/* chip common intmask */ +static uint32 cc_intmask = 0; + +static bool BCMINITFN(serial_exists) (osl_t * osh, uint8 * regs) { uint8 save_mcr, status1; save_mcr = R_REG(osh, ®s[UART_MCR]); @@ -41,118 +65,276 @@ BCMINITFN(serial_exists)(osl_t *osh, uint8 *regs) return (status1 == 0x90); } +static void __init sb_extif_serial_init(sb_t * sbh, void *regs, + sb_serial_init_fn add) +{ + osl_t *osh = sb_osh(sbh); + extifregs_t *eir = (extifregs_t *) regs; + sbconfig_t *sb; + ulong base; + uint irq; + int i, n; + + /* Determine external UART register base */ + sb = (sbconfig_t *) ((ulong) eir + SBCONFIGOFF); + base = EXTIF_CFGIF_BASE(sb_base(R_REG(osh, &sb->sbadmatch1))); + + /* Determine IRQ */ + irq = sb_irq(sbh); + + /* Disable GPIO interrupt initially */ + W_REG(osh, &eir->gpiointpolarity, 0); + W_REG(osh, &eir->gpiointmask, 0); + + /* Search for external UARTs */ + n = 2; + for (i = 0; i < 2; i++) { + regs = (void *)REG_MAP(base + (i * 8), 8); + if (serial_exists(osh, regs)) { + /* Set GPIO 1 to be the external UART IRQ */ + W_REG(osh, &eir->gpiointmask, 2); + /* XXXDetermine external UART clock */ + if (add) + add(regs, irq, 13500000, 0); + } + } + + /* Add internal UART if enabled */ + if (R_REG(osh, &eir->corecontrol) & CC_UE) + if (add) + add((void *)&eir->uartdata, irq, sb_clock(sbh), 2); +} + /* * Initializes UART access. The callback function will be called once * per found UART. */ -void -BCMINITFN(sb_serial_init)(sb_t *sbh, void (*add)(void *regs, uint irq, uint baud_base, - uint reg_shift)) -{ +void BCMINITFN(sb_serial_init) (sb_t * sbh, sb_serial_init_fn add) { osl_t *osh; void *regs; - ulong base; + chipcregs_t *cc; + uint32 rev, cap, pll, baud_base, div; uint irq; int i, n; osh = sb_osh(sbh); - if ((regs = sb_setcore(sbh, SB_EXTIF, 0))) { - extifregs_t *eir = (extifregs_t *) regs; - sbconfig_t *sb; - - /* Determine external UART register base */ - sb = (sbconfig_t *)((ulong) eir + SBCONFIGOFF); - base = EXTIF_CFGIF_BASE(sb_base(R_REG(osh, &sb->sbadmatch1))); - - /* Determine IRQ */ - irq = sb_irq(sbh); - - /* Disable GPIO interrupt initially */ - W_REG(osh, &eir->gpiointpolarity, 0); - W_REG(osh, &eir->gpiointmask, 0); - - /* Search for external UARTs */ - n = 2; - for (i = 0; i < 2; i++) { - regs = (void *) REG_MAP(base + (i * 8), 8); - if (serial_exists(osh, regs)) { - /* Set GPIO 1 to be the external UART IRQ */ - W_REG(osh, &eir->gpiointmask, 2); - /* XXXDetermine external UART clock */ - if (add) - add(regs, irq, 13500000, 0); - } - } + regs = sb_setcore(sbh, SB_EXTIF, 0); + if (regs) { + sb_extif_serial_init(sbh, regs, add); + return; + } - /* Add internal UART if enabled */ - if (R_REG(osh, &eir->corecontrol) & CC_UE) - if (add) - add((void *) &eir->uartdata, irq, sb_clock(sbh), 2); - } else if ((regs = sb_setcore(sbh, SB_CC, 0))) { - chipcregs_t *cc = (chipcregs_t *) regs; - uint32 rev, cap, pll, baud_base, div; + cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0); + ASSERT(cc); - /* Determine core revision and capabilities */ - rev = sb_corerev(sbh); - cap = R_REG(osh, &cc->capabilities); - pll = cap & CAP_PLL_MASK; + /* Determine core revision and capabilities */ + rev = sbh->ccrev; + cap = sbh->cccaps; + pll = cap & CC_CAP_PLL_MASK; - /* Determine IRQ */ - irq = sb_irq(sbh); + /* Determine IRQ */ + irq = sb_irq(sbh); - if (pll == PLL_TYPE1) { - /* PLL clock */ - baud_base = sb_clock_rate(pll, - R_REG(osh, &cc->clockcontrol_n), - R_REG(osh, &cc->clockcontrol_m2)); - div = 1; - } else { + if (pll == PLL_TYPE1) { + /* PLL clock */ + baud_base = sb_clock_rate(pll, + R_REG(osh, &cc->clockcontrol_n), + R_REG(osh, &cc->clockcontrol_m2)); + div = 1; + } else { + /* 5354 chip common uart uses a constant clock + * frequency of 25MHz */ + if (sb_corerev(sbh) == 20) { + /* Set the override bit so we don't divide it */ + W_REG(osh, &cc->corecontrol, CC_UARTCLKO); + baud_base = 25000000; + } else if (rev >= 11 && rev != 15) { /* Fixed ALP clock */ - if (rev >= 11 && rev != 15) { - baud_base = 20000000; - div = 1; - /* Set the override bit so we don't divide it */ - W_REG(osh, &cc->corecontrol, CC_UARTCLKO); - } + baud_base = sb_alp_clock(sbh); + div = 1; + /* Turn off UART clock before switching clock source */ + if (rev >= 21) + AND_REG(osh, &cc->corecontrol, ~CC_UARTCLKEN); + /* Set the override bit so we don't divide it */ + OR_REG(osh, &cc->corecontrol, CC_UARTCLKO); + if (rev >= 21) + OR_REG(osh, &cc->corecontrol, CC_UARTCLKEN); + } else if (rev >= 3) { /* Internal backplane clock */ - else if (rev >= 3) { - baud_base = sb_clock(sbh); - div = 2; /* Minimum divisor */ - W_REG(osh, &cc->clkdiv, - ((R_REG(osh, &cc->clkdiv) & ~CLKD_UART) | div)); - } + baud_base = sb_clock(sbh); + div = 2; /* Minimum divisor */ + W_REG(osh, &cc->clkdiv, + ((R_REG(osh, &cc->clkdiv) & ~CLKD_UART) | div)); + } else { /* Fixed internal backplane clock */ - else { - baud_base = 88000000; - div = 48; - } + baud_base = 88000000; + div = 48; + } - /* Clock source depends on strapping if UartClkOverride is unset */ - if ((rev > 0) && - ((R_REG(osh, &cc->corecontrol) & CC_UARTCLKO) == 0)) { - if ((cap & CAP_UCLKSEL) == CAP_UINTCLK) { - /* Internal divided backplane clock */ - baud_base /= div; - } else { - /* Assume external clock of 1.8432 MHz */ - baud_base = 1843200; - } + /* Clock source depends on strapping if UartClkOverride is unset */ + if ((rev > 0) + && ((R_REG(osh, &cc->corecontrol) & CC_UARTCLKO) == 0)) { + if ((cap & CC_CAP_UCLKSEL) == CC_CAP_UINTCLK) { + /* Internal divided backplane clock */ + baud_base /= div; + } else { + /* Assume external clock of 1.8432 MHz */ + baud_base = 1843200; } } + } - /* Add internal UARTs */ - n = cap & CAP_UARTS_MASK; - for (i = 0; i < n; i++) { - /* Register offset changed after revision 0 */ - if (rev) - regs = (void *)((ulong) &cc->uart0data + (i * 256)); - else - regs = (void *)((ulong) &cc->uart0data + (i * 8)); + /* Add internal UARTs */ + n = cap & CC_CAP_UARTS_MASK; + for (i = 0; i < n; i++) { + /* Register offset changed after revision 0 */ + if (rev) + regs = (void *)((ulong) & cc->uart0data + (i * 256)); + else + regs = (void *)((ulong) & cc->uart0data + (i * 8)); - if (add) - add(regs, irq, baud_base, 0); + if (add) + add(regs, irq, baud_base, 0); + } +} + +#if 0 +/* + * Initialize jtag master and return handle for + * jtag_rwreg. Returns NULL on failure. + */ +void *sb_jtagm_init(sb_t * sbh, uint clkd, bool exttap) +{ + void *regs; + + if ((regs = sb_setcore(sbh, SB_CC, 0)) != NULL) { + chipcregs_t *cc = (chipcregs_t *) regs; + uint32 tmp; + + /* + * Determine jtagm availability from + * core revision and capabilities. + */ + + /* + * Corerev 10 has jtagm, but the only chip + * with it does not have a mips, and + * the layout of the jtagcmd register is + * different. We'll only accept >= 11. + */ + if (sbh->ccrev < 11) + return (NULL); + + if ((sbh->cccaps & CC_CAP_JTAGP) == 0) + return (NULL); + + /* Set clock divider if requested */ + if (clkd != 0) { + tmp = R_REG(osh, &cc->clkdiv); + tmp = + (tmp & ~CLKD_JTAG) | ((clkd << CLKD_JTAG_SHIFT) & + CLKD_JTAG); + W_REG(osh, &cc->clkdiv, tmp); } + + /* Enable jtagm */ + tmp = JCTRL_EN | (exttap ? JCTRL_EXT_EN : 0); + W_REG(osh, &cc->jtagctrl, tmp); } + + return (regs); +} + +void sb_jtagm_disable(osl_t * osh, void *h) +{ + chipcregs_t *cc = (chipcregs_t *) h; + + W_REG(osh, &cc->jtagctrl, R_REG(osh, &cc->jtagctrl) & ~JCTRL_EN); } +/* + * Read/write a jtag register. Assumes a target with + * 8 bit IR and 32 bit DR. + */ +#define IRWIDTH 8 /* Default Instruction Register width */ +#define DRWIDTH 32 /* Default Data Register width */ + +uint32 jtag_rwreg(osl_t * osh, void *h, uint32 ir, uint32 dr) +{ + chipcregs_t *cc = (chipcregs_t *) h; + uint32 tmp; + + W_REG(osh, &cc->jtagir, ir); + W_REG(osh, &cc->jtagdr, dr); + tmp = JCMD_START | JCMD_ACC_IRDR | + ((IRWIDTH - 1) << JCMD_IRW_SHIFT) | (DRWIDTH - 1); + W_REG(osh, &cc->jtagcmd, tmp); + while (((tmp = R_REG(osh, &cc->jtagcmd)) & JCMD_BUSY) == JCMD_BUSY) { + /* OSL_DELAY(1); */ + } + + tmp = R_REG(osh, &cc->jtagdr); + return (tmp); +} +#endif + +/* + * Interface to register chipc secondary isr + */ +bool +BCMINITFN(sb_cc_register_isr) (sb_t * sbh, cc_isr_fn isr, uint32 ccintmask, + void *cbdata) { + bool done = FALSE; + chipcregs_t *regs; + uint origidx; + uint i; + + /* Save the current core index */ + origidx = sb_coreidx(sbh); + regs = sb_setcore(sbh, SB_CC, 0); + ASSERT(regs); + + for (i = 0; i < MAX_CC_INT_SOURCE; i++) { + if (cc_isr_desc[i].isr == NULL) { + cc_isr_desc[i].isr = isr; + cc_isr_desc[i].cbdata = cbdata; + cc_isr_desc[i].intmask = ccintmask; + done = TRUE; + break; + } + } + + if (done) { + cc_intmask = R_REG(sb_osh(sbh), ®s->intmask); + cc_intmask |= ccintmask; + W_REG(sb_osh(sbh), ®s->intmask, cc_intmask); + } + + /* restore original coreidx */ + sb_setcoreidx(sbh, origidx); + return done; +} + +/* + * chipc primary interrupt handler + */ +void sb_cc_isr(sb_t * sbh, chipcregs_t * regs) +{ + uint32 ccintstatus; + uint32 intstatus; + uint32 i; + + /* prior to rev 21 chipc interrupt means uart and gpio */ + if (sbh->ccrev >= 21) + ccintstatus = R_REG(sb_osh(sbh), ®s->intstatus) & cc_intmask; + else + ccintstatus = (CI_UART | CI_GPIO); + + for (i = 0; i < MAX_CC_INT_SOURCE; i++) { + if ((cc_isr_desc[i].isr != NULL) && + (intstatus = (cc_isr_desc[i].intmask & ccintstatus))) { + (cc_isr_desc[i].isr) (cc_isr_desc[i].cbdata, intstatus); + } + } +}