Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/uart/uart_dev_imx.c
Show All 34 Lines | |||||
#include "opt_ddb.h" | #include "opt_ddb.h" | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/conf.h> | #include <sys/conf.h> | ||||
#include <sys/kdb.h> | #include <sys/kdb.h> | ||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <machine/fdt.h> | |||||
#include <dev/uart/uart.h> | #include <dev/uart/uart.h> | ||||
#include <dev/uart/uart_cpu.h> | #include <dev/uart/uart_cpu.h> | ||||
#include <dev/uart/uart_cpu_fdt.h> | #include <dev/uart/uart_cpu_fdt.h> | ||||
#include <dev/uart/uart_bus.h> | #include <dev/uart/uart_bus.h> | ||||
#include <dev/uart/uart_dev_imx.h> | #include <dev/uart/uart_dev_imx.h> | ||||
#if defined(EXT_RESOURCES) && defined(__aarch64__) | |||||
#define IMX_ENABLE_CLOCKS | |||||
#endif | |||||
#ifdef IMX_ENABLE_CLOCKS | |||||
#include <dev/extres/clk/clk.h> | |||||
#endif | |||||
#include "uart_if.h" | #include "uart_if.h" | ||||
#include <arm/freescale/imx/imx_ccmvar.h> | #include <arm/freescale/imx/imx_ccmvar.h> | ||||
/* | /* | ||||
* The hardare FIFOs are 32 bytes. We want an interrupt when there are 24 bytes | * The hardare FIFOs are 32 bytes. We want an interrupt when there are 24 bytes | ||||
* available to read or space for 24 more bytes to write. While 8 bytes of | * available to read or space for 24 more bytes to write. While 8 bytes of | ||||
* slack before over/underrun might seem excessive, the hardware can run at | * slack before over/underrun might seem excessive, the hardware can run at | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | imx_uart_getbaud(struct uart_bas *bas) | ||||
* actual rate the hardware is programmed for. It's more comforting to | * actual rate the hardware is programmed for. It's more comforting to | ||||
* see that your console is running at 115200 than 114942. Note that | * see that your console is running at 115200 than 114942. Note that | ||||
* here we cannot make a simplifying assumption that the predivider and | * here we cannot make a simplifying assumption that the predivider and | ||||
* numerator are 1 (like we do when setting the baud rate), because we | * numerator are 1 (like we do when setting the baud rate), because we | ||||
* don't know what u-boot might have set up. | * don't know what u-boot might have set up. | ||||
*/ | */ | ||||
i = (GETREG(bas, REG(UFCR)) & IMXUART_UFCR_RFDIV_MASK) >> | i = (GETREG(bas, REG(UFCR)) & IMXUART_UFCR_RFDIV_MASK) >> | ||||
IMXUART_UFCR_RFDIV_SHIFT; | IMXUART_UFCR_RFDIV_SHIFT; | ||||
rate = imx_ccm_uart_hz() / predivs[i]; | rate = bas->rclk / predivs[i]; | ||||
ubir = GETREG(bas, REG(UBIR)) + 1; | ubir = GETREG(bas, REG(UBIR)) + 1; | ||||
ubmr = GETREG(bas, REG(UBMR)) + 1; | ubmr = GETREG(bas, REG(UBMR)) + 1; | ||||
baud = ((rate / 16 ) * ubir) / ubmr; | baud = ((rate / 16 ) * ubir) / ubmr; | ||||
blo = (baud * 100) / 103; | blo = (baud * 100) / 103; | ||||
bhi = (baud * 100) / 97; | bhi = (baud * 100) / 97; | ||||
for (i = 0; i < nitems(std_rates); i++) { | for (i = 0; i < nitems(std_rates); i++) { | ||||
rate = std_rates[i]; | rate = std_rates[i]; | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | imx_uart_init(struct uart_bas *bas, int baudrate, int databits, | ||||
* workable pair of numbers by assuming a pre-divider and numerator of | * workable pair of numbers by assuming a pre-divider and numerator of | ||||
* one because our base clock is so fast we can reach virtually any | * one because our base clock is so fast we can reach virtually any | ||||
* reasonable speed with a simple divisor. The numerator value actually | * reasonable speed with a simple divisor. The numerator value actually | ||||
* includes the 16x over-sampling (so a value of 16 means divide by 1); | * includes the 16x over-sampling (so a value of 16 means divide by 1); | ||||
* the register value is the numerator-1, so we have a hard-coded 15. | * the register value is the numerator-1, so we have a hard-coded 15. | ||||
* Note that a quirk of the hardware requires that both UBIR and UBMR be | * Note that a quirk of the hardware requires that both UBIR and UBMR be | ||||
* set back to back in order for the change to take effect. | * set back to back in order for the change to take effect. | ||||
*/ | */ | ||||
if (baudrate > 0) { | if ((baudrate > 0) && (bas->rclk != 0)) { | ||||
baseclk = imx_ccm_uart_hz(); | baseclk = bas->rclk; | ||||
reg = GETREG(bas, REG(UFCR)); | reg = GETREG(bas, REG(UFCR)); | ||||
reg = (reg & ~IMXUART_UFCR_RFDIV_MASK) | IMXUART_UFCR_RFDIV_DIV1; | reg = (reg & ~IMXUART_UFCR_RFDIV_MASK) | IMXUART_UFCR_RFDIV_DIV1; | ||||
SETREG(bas, REG(UFCR), reg); | SETREG(bas, REG(UFCR), reg); | ||||
SETREG(bas, REG(UBIR), 15); | SETREG(bas, REG(UBIR), 15); | ||||
SETREG(bas, REG(UBMR), (baseclk / baudrate) - 1); | SETREG(bas, REG(UBMR), (baseclk / baudrate) - 1); | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | |||||
#define SIGCHG(c, i, s, d) \ | #define SIGCHG(c, i, s, d) \ | ||||
if (c) { \ | if (c) { \ | ||||
i |= (i & s) ? s : s | d; \ | i |= (i & s) ? s : s | d; \ | ||||
} else { \ | } else { \ | ||||
i = (i & s) ? (i & ~s) | d : i; \ | i = (i & s) ? (i & ~s) | d : i; \ | ||||
} | } | ||||
#ifdef IMX_ENABLE_CLOCKS | |||||
static int | static int | ||||
imx_uart_setup_clocks(struct uart_softc *sc) | |||||
{ | |||||
struct uart_bas *bas; | |||||
clk_t ipgclk, perclk; | |||||
uint64_t freq; | |||||
int error; | |||||
bas = &sc->sc_bas; | |||||
if (clk_get_by_ofw_name(sc->sc_dev, 0, "ipg", &ipgclk) != 0) | |||||
return (ENOENT); | |||||
if (clk_get_by_ofw_name(sc->sc_dev, 0, "per", &perclk) != 0) { | |||||
return (ENOENT); | |||||
} | |||||
error = clk_enable(ipgclk); | |||||
if (error != 0) { | |||||
device_printf(sc->sc_dev, "cannot enable ipg clock\n"); | |||||
return (error); | |||||
} | |||||
error = clk_get_freq(perclk, &freq); | |||||
if (error != 0) { | |||||
device_printf(sc->sc_dev, "cannot get frequency\n"); | |||||
return (error); | |||||
} | |||||
bas->rclk = (uint32_t)freq; | |||||
return (0); | |||||
} | |||||
#endif | |||||
static int | |||||
imx_uart_bus_attach(struct uart_softc *sc) | imx_uart_bus_attach(struct uart_softc *sc) | ||||
{ | { | ||||
struct uart_bas *bas; | struct uart_bas *bas; | ||||
struct uart_devinfo *di; | struct uart_devinfo *di; | ||||
bas = &sc->sc_bas; | bas = &sc->sc_bas; | ||||
#ifdef IMX_ENABLE_CLOCKS | |||||
int error = imx_uart_setup_clocks(sc); | |||||
if (error) | |||||
return (error); | |||||
#else | |||||
bas->rclk = imx_ccm_uart_hz(); | |||||
#endif | |||||
if (sc->sc_sysdev != NULL) { | if (sc->sc_sysdev != NULL) { | ||||
di = sc->sc_sysdev; | di = sc->sc_sysdev; | ||||
imx_uart_init(bas, di->baudrate, di->databits, di->stopbits, | imx_uart_init(bas, di->baudrate, di->databits, di->stopbits, | ||||
di->parity); | di->parity); | ||||
} else { | } else { | ||||
imx_uart_init(bas, 115200, 8, 1, 0); | imx_uart_init(bas, 115200, 8, 1, 0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 280 Lines • Show Last 20 Lines |