/* * We utilize chipcommon configuration register SBFlagSt to implement a * smart shared IRQ handling machenism through which only ISRs registered * for the SB cores that raised the interrupt are invoked. This machenism * relies on the SBFlagSt register's reliable recording of the SB cores * that raised the interrupt. */ void __init arch_init_irq(void) { int i; uint32 coreidx, mips_core_id; void *regs; if (BCM330X(current_cpu_data.processor_id)) mips_core_id = MIPS33_CORE_ID; else if (MIPS74K(current_cpu_data.processor_id)) mips_core_id = MIPS74K_CORE_ID; else { printk(KERN_ERR "MIPS CPU type %x unknown", current_cpu_data.processor_id); return; } /* Cache chipc and mips33 config registers */ ASSERT(bcm947xx_sih); coreidx = si_coreidx(bcm947xx_sih); regs = si_setcore(bcm947xx_sih, mips_core_id, 0); mipsirq = si_irq(bcm947xx_sih); if (bcm947xx_sih->socitype == SOCI_SB) { if (regs) mipssbr = (sbconfig_t *)((ulong)regs + SBCONFIGOFF); if ((regs = si_setcore(bcm947xx_sih, CC_CORE_ID, 0))) ccsbr = (sbconfig_t *)((ulong)regs + SBCONFIGOFF); } si_setcoreidx(bcm947xx_sih, coreidx); if (BCM330X(current_cpu_data.processor_id)) { /* Cache mips33 sbintvec register */ if (mipssbr) shints = R_REG(NULL, &mipssbr->sbintvec); } else { uint32 *intmask; /* Use intmask5 register to route the timer interrupt */ intmask = (uint32 *) &((mips74kregs_t *)regs)->intmask[5]; W_REG(NULL, intmask, 1 << 31); intmask = (uint32 *) &((mips74kregs_t *)regs)->intmask[0]; shints = R_REG(NULL, intmask); /* Save the pointer to mips core registers */ mips_corereg = regs; } /* Install interrupt controllers */ for (i = 0; i < NR_IRQS; i++) { set_irq_chip(i, (i < SBMIPS_NUMIRQS ? &brcm_irq_type : &brcm_irq2_type)); } }
/* * Initializes UART access. The callback function will be called once * per found UART. */ void BCMATTACHFN(si_serial_init)(si_t *sih, si_serial_init_fn add) { osl_t *osh; void *regs; chipcregs_t *cc; uint32 rev, cap, pll, baud_base, div; uint irq; int i, n; osh = si_osh(sih); cc = (chipcregs_t *)si_setcoreidx(sih, SI_CC_IDX); ASSERT(cc); /* Determine core revision and capabilities */ rev = sih->ccrev; cap = sih->cccaps; pll = cap & CC_CAP_PLL_MASK; /* Determine IRQ */ irq = si_irq(sih); if (CCPLL_ENAB(sih) && pll == PLL_TYPE1) { /* PLL clock */ baud_base = si_clock_rate(pll, R_REG(osh, &cc->clockcontrol_n), R_REG(osh, &cc->clockcontrol_m2)); div = 1; } else { /* Fixed ALP clock */ if (rev >= 11 && rev != 15) { baud_base = si_alp_clock(sih); 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 */ baud_base = si_clock(sih); div = 2; /* Minimum divisor */ W_REG(osh, &cc->clkdiv, ((R_REG(osh, &cc->clkdiv) & ~CLKD_UART) | div)); } else { /* Fixed internal backplane clock */ baud_base = 88000000; div = 48; } /* Clock source depends on strapping if UartClkOverride is unset */ if ((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 & CC_CAP_UARTS_MASK; for (i = 0; i < n; i++) { regs = (void *)((ulong) &cc->uart0data + (i * 256)); if (add) add(regs, irq, baud_base, 0); } }
/* * Initializes UART access. The callback function will be called once * per found UART. */ void BCMINITFN(si_serial_init)(si_t *sih, si_serial_init_fn add, uint32 baudrate) { osl_t *osh; void *regs; chipcregs_t *cc; uint32 rev, cap, pll, baud_base, div; uint irq; int i, n; osh = si_osh(sih); cc = (chipcregs_t *)si_setcoreidx(sih, SI_CC_IDX); ASSERT(cc); /* Determine core revision and capabilities */ rev = sih->ccrev; cap = sih->cccaps; pll = cap & CC_CAP_PLL_MASK; /* Determine IRQ */ irq = si_irq(sih); if (CCPLL_ENAB(sih) && pll == PLL_TYPE1) { /* PLL clock */ baud_base = si_clock_rate(pll, R_REG(osh, &cc->clockcontrol_n), R_REG(osh, &cc->clockcontrol_m2)); div = 1; } else { /* Fixed ALP clock */ /* XXX rev. 15 in 4785 breaks the rule! */ if (rev >= 11 && rev != 15) { baud_base = si_alp_clock(sih); div = 1; /* * If baudrate parameter is given with a non-zero value, * UART clock will be divided for the given baud rate before * feeding into UART module. * Note: UART driver could also adjust UART module's divider for * clock fine tunning. */ if (baudrate) { /* Turn off UART clock before switching clock source */ if (rev >= 21) AND_REG(osh, &cc->corecontrol, ~CC_UARTCLKEN); /* Don't set the override bit so we divide it */ AND_REG(osh, &cc->corecontrol, ~CC_UARTCLKO); div = baud_base / (baudrate * 16); div = (div + 1) & ~0x1; AND_REG(osh, &cc->clkdiv, ~CLKD_UART); OR_REG(osh, &cc->clkdiv, div); /* Turn back UART clock on */ if (rev >= 21) OR_REG(osh, &cc->corecontrol, CC_UARTCLKEN); } else { /* Turn off UART clock before switching clock source */ if (rev >= 21) AND_REG(osh, &cc->corecontrol, ~CC_UARTCLKEN); OR_REG(osh, &cc->corecontrol, CC_UARTCLKO); /* Turn back UART clock on */ if (rev >= 21) OR_REG(osh, &cc->corecontrol, CC_UARTCLKEN); } if (CONSOLE_TTY == 1) { /* Use UART1, enable "UART1 use GPIO" bit */ OR_REG(osh, &cc->corecontrol, 0x80); } } else if (rev >= 3) { /* Internal backplane clock */ baud_base = si_clock(sih); div = 2; /* Minimum divisor */ W_REG(osh, &cc->clkdiv, ((R_REG(osh, &cc->clkdiv) & ~CLKD_UART) | div)); } else { /* Fixed internal backplane clock */ 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 & 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 & 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); } }