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)) { osl_t *osh; void *regs; ulong base; 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); } } /* 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; /* Default value */ div = 48; /* Determine core revision and capabilities */ rev = sb_corerev(sbh); cap = R_REG(osh, &cc->capabilities); pll = cap & CAP_PLL_MASK; /* 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 { /* 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 */ baud_base = sb_alp_clock(sbh); div = 1; /* Set the override bit so we don't divide it */ W_REG(osh, &cc->corecontrol, CC_UARTCLKO); } else if (rev >= 3) { /* Internal backplane clock */ 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 */ 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; } } } /* 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)); if (add) add(regs, irq, baud_base, 0); } } }
/* * Initializes UART access. The callback function will be called once * per found UART. */ void BCMINITFN(sb_serial_init) (sb_t * sbh, sb_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 = sb_osh(sbh); regs = sb_setcore(sbh, SB_EXTIF, 0); if (regs) { sb_extif_serial_init(sbh, regs, add); return; } cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0); ASSERT(cc); /* Determine core revision and capabilities */ rev = sbh->ccrev; cap = sbh->cccaps; pll = cap & CC_CAP_PLL_MASK; /* 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 { /* 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 */ 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 */ 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 */ 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); } }