Exemple #1
0
/*
 * 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);
	}
}
Exemple #2
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);
    }
}