in driver_chipcommon.c [601:696]
int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
struct ssb_serial_port *ports)
{
struct ssb_bus *bus = cc->dev->bus;
int nr_ports = 0;
u32 plltype;
unsigned int irq;
u32 baud_base, div;
u32 i, n;
unsigned int ccrev = cc->dev->id.revision;
plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
irq = ssb_mips_irq(cc->dev);
if (plltype == SSB_PLLTYPE_1) {
/* PLL clock */
baud_base = ssb_calc_clock_rate(plltype,
chipco_read32(cc, SSB_CHIPCO_CLOCK_N),
chipco_read32(cc, SSB_CHIPCO_CLOCK_M2));
div = 1;
} else {
if (ccrev == 20) {
/* BCM5354 uses constant 25MHz clock */
baud_base = 25000000;
div = 48;
/* Set the override bit so we don't divide it */
chipco_write32(cc, SSB_CHIPCO_CORECTL,
chipco_read32(cc, SSB_CHIPCO_CORECTL)
| SSB_CHIPCO_CORECTL_UARTCLK0);
} else if ((ccrev >= 11) && (ccrev != 15)) {
baud_base = ssb_chipco_alp_clock(cc);
div = 1;
if (ccrev >= 21) {
/* Turn off UART clock before switching clocksource. */
chipco_write32(cc, SSB_CHIPCO_CORECTL,
chipco_read32(cc, SSB_CHIPCO_CORECTL)
& ~SSB_CHIPCO_CORECTL_UARTCLKEN);
}
/* Set the override bit so we don't divide it */
chipco_write32(cc, SSB_CHIPCO_CORECTL,
chipco_read32(cc, SSB_CHIPCO_CORECTL)
| SSB_CHIPCO_CORECTL_UARTCLK0);
if (ccrev >= 21) {
/* Re-enable the UART clock. */
chipco_write32(cc, SSB_CHIPCO_CORECTL,
chipco_read32(cc, SSB_CHIPCO_CORECTL)
| SSB_CHIPCO_CORECTL_UARTCLKEN);
}
} else if (ccrev >= 3) {
/* Internal backplane clock */
baud_base = ssb_clockspeed(bus);
div = chipco_read32(cc, SSB_CHIPCO_CLKDIV)
& SSB_CHIPCO_CLKDIV_UART;
} else {
/* Fixed internal backplane clock */
baud_base = 88000000;
div = 48;
}
/* Clock source depends on strapping if UartClkOverride is unset */
if ((ccrev > 0) &&
!(chipco_read32(cc, SSB_CHIPCO_CORECTL) & SSB_CHIPCO_CORECTL_UARTCLK0)) {
if ((cc->capabilities & SSB_CHIPCO_CAP_UARTCLK) ==
SSB_CHIPCO_CAP_UARTCLK_INT) {
/* Internal divided backplane clock */
baud_base /= div;
} else {
/* Assume external clock of 1.8432 MHz */
baud_base = 1843200;
}
}
}
/* Determine the registers of the UARTs */
n = (cc->capabilities & SSB_CHIPCO_CAP_NRUART);
for (i = 0; i < n; i++) {
void __iomem *cc_mmio;
void __iomem *uart_regs;
cc_mmio = cc->dev->bus->mmio + (cc->dev->core_index * SSB_CORE_SIZE);
uart_regs = cc_mmio + SSB_CHIPCO_UART0_DATA;
/* Offset changed at after rev 0 */
if (ccrev == 0)
uart_regs += (i * 8);
else
uart_regs += (i * 256);
nr_ports++;
ports[i].regs = uart_regs;
ports[i].irq = irq;
ports[i].baud_base = baud_base;
ports[i].reg_shift = 0;
}
return nr_ports;
}