Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/uart/uart_dev_ns8250.c
Show All 33 Lines | |||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#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/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/tty.h> | |||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#ifdef FDT | #ifdef FDT | ||||
#include <dev/fdt/fdt_common.h> | #include <dev/fdt/fdt_common.h> | ||||
#include <dev/ofw/ofw_bus.h> | #include <dev/ofw/ofw_bus.h> | ||||
#include <dev/ofw/ofw_bus_subr.h> | #include <dev/ofw/ofw_bus_subr.h> | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | ns8250_divisor(int rclk, int baudrate) | ||||
/* enforce maximum error tolerance: */ | /* enforce maximum error tolerance: */ | ||||
if (error < -UART_DEV_TOLERANCE_PCT || error > UART_DEV_TOLERANCE_PCT) | if (error < -UART_DEV_TOLERANCE_PCT || error > UART_DEV_TOLERANCE_PCT) | ||||
return (0); | return (0); | ||||
return (divisor); | return (divisor); | ||||
} | } | ||||
/* | |||||
* As above, but takes a fractional baudrate. | |||||
* This one currently does NOT enforce a maximum deviation. | |||||
*/ | |||||
static int | static int | ||||
ns8250_fdivisor(int rclk, int baudrate_n, int baudrate_d) | |||||
{ | |||||
int divisor; | |||||
int divisor_n, divisor_d; | |||||
if (baudrate_n == 0 || baudrate_d == 0) | |||||
return (0); | |||||
divisor_n = rclk * baudrate_d; | |||||
divisor_d = baudrate_n; | |||||
divisor = (divisor_n / (divisor_d << 3) + 1) >> 1; | |||||
if (divisor <= 0 || divisor > 65535) | |||||
return (0); | |||||
/* TODO: Enforce max 3% error in actual baudrate */ | |||||
return (divisor); | |||||
} | |||||
static int | |||||
ns8250_drain(struct uart_bas *bas, int what) | ns8250_drain(struct uart_bas *bas, int what) | ||||
{ | { | ||||
int delay, limit; | int delay, limit; | ||||
delay = ns8250_delay(bas); | delay = ns8250_delay(bas); | ||||
if (what & UART_DRAIN_TRANSMITTER) { | if (what & UART_DRAIN_TRANSMITTER) { | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 466 Lines • ▼ Show 20 Lines | do { | ||||
SIGCHGSW(sig, msr, RI); | SIGCHGSW(sig, msr, RI); | ||||
} while (!atomic_cmpset_32(&sc->sc_hwsig, old, sig & ~SER_MASK_DELTA)); | } while (!atomic_cmpset_32(&sc->sc_hwsig, old, sig & ~SER_MASK_DELTA)); | ||||
return (sig); | return (sig); | ||||
} | } | ||||
int | int | ||||
ns8250_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) | ns8250_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) | ||||
{ | { | ||||
struct ns8250_softc *ns8250 = (struct ns8250_softc *)sc; | |||||
struct uart_bas *bas; | struct uart_bas *bas; | ||||
int baudrate, divisor, error; | int baudrate, divisor, error; | ||||
uint8_t efr, lcr; | uint8_t efr, lcr; | ||||
struct baud_fraction *bf; | |||||
bas = &sc->sc_bas; | bas = &sc->sc_bas; | ||||
error = 0; | error = 0; | ||||
uart_lock(sc->sc_hwmtx); | uart_lock(sc->sc_hwmtx); | ||||
switch (request) { | switch (request) { | ||||
case UART_IOCTL_BREAK: | case UART_IOCTL_BREAK: | ||||
lcr = uart_getreg(bas, REG_LCR); | lcr = uart_getreg(bas, REG_LCR); | ||||
if (data) | if (data) | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | case UART_IOCTL_BAUD: | ||||
uart_setreg(bas, REG_LCR, lcr); | uart_setreg(bas, REG_LCR, lcr); | ||||
uart_barrier(bas); | uart_barrier(bas); | ||||
baudrate = (divisor > 0) ? bas->rclk / divisor / 16 : 0; | baudrate = (divisor > 0) ? bas->rclk / divisor / 16 : 0; | ||||
if (baudrate > 0) | if (baudrate > 0) | ||||
*(int*)data = baudrate; | *(int*)data = baudrate; | ||||
else | else | ||||
error = ENXIO; | error = ENXIO; | ||||
break; | break; | ||||
case UART_IOCTL_SET_FBAUD: { | |||||
/* Set baudrate. */ | |||||
bf = (struct baud_fraction *)data; | |||||
divisor = ns8250_fdivisor(bas->rclk, bf->bf_numerator, bf->bf_denominator); | |||||
if (divisor == 0) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
lcr = uart_getreg(bas, REG_LCR); | |||||
uart_setreg(bas, REG_LCR, lcr | LCR_DLAB); | |||||
uart_barrier(bas); | |||||
uart_setreg(bas, REG_DLL, divisor & 0xff); | |||||
uart_setreg(bas, REG_DLH, (divisor >> 8) & 0xff); | |||||
uart_barrier(bas); | |||||
uart_setreg(bas, REG_LCR, lcr); | |||||
uart_barrier(bas); | |||||
ns8250->mcr = uart_getreg(bas, REG_MCR); | |||||
sc->sc_u.u_tty.tp->t_termios.c_ispeed = ((bas->rclk / (divisor << 3)) + 1) >> 1; | |||||
sc->sc_u.u_tty.tp->t_termios.c_ospeed = sc->sc_u.u_tty.tp->t_termios.c_ispeed; | |||||
break; | |||||
case UART_IOCTL_GET_FBAUD: { | |||||
bf = (struct baud_fraction *)data; | |||||
lcr = uart_getreg(bas, REG_LCR); | |||||
uart_setreg(bas, REG_LCR, lcr | LCR_DLAB); | |||||
uart_barrier(bas); | |||||
divisor = uart_getreg(bas, REG_DLL) | | |||||
(uart_getreg(bas, REG_DLH) << 8); | |||||
uart_barrier(bas); | |||||
uart_setreg(bas, REG_LCR, lcr); | |||||
uart_barrier(bas); | |||||
if (divisor <= 0) | |||||
error = ENXIO; | |||||
else { | |||||
bf->bf_numerator = bas->rclk; | |||||
bf->bf_denominator = divisor << 4; | |||||
} | |||||
break; | |||||
} | |||||
} | |||||
default: | default: | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
uart_unlock(sc->sc_hwmtx); | uart_unlock(sc->sc_hwmtx); | ||||
return (error); | return (error); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | if (ns8250->busy_detect != 0) { | ||||
if (limit <= 0) { | if (limit <= 0) { | ||||
/* UART appears to be stuck */ | /* UART appears to be stuck */ | ||||
uart_unlock(sc->sc_hwmtx); | uart_unlock(sc->sc_hwmtx); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
} | } | ||||
ns8250->mcr = uart_getreg(bas, REG_MCR); | |||||
error = ns8250_param(bas, baudrate, databits, stopbits, parity); | error = ns8250_param(bas, baudrate, databits, stopbits, parity); | ||||
uart_unlock(sc->sc_hwmtx); | uart_unlock(sc->sc_hwmtx); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
ns8250_bus_probe(struct uart_softc *sc) | ns8250_bus_probe(struct uart_softc *sc) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 295 Lines • Show Last 20 Lines |