Index: sys/arm/amlogic/aml8726/aml8726_uart.h =================================================================== --- sys/arm/amlogic/aml8726/aml8726_uart.h +++ sys/arm/amlogic/aml8726/aml8726_uart.h @@ -94,4 +94,14 @@ #define AML_UART_MISC_RECV_IRQ_CNT_MASK 0xff #define AML_UART_MISC_RECV_IRQ_CNT_SHIFT 0 +/* + * The new baud rate register is available on the + * aml8726-m6 and later. + */ +#define AML_UART_NEW_BAUD_REG 20 +#define AML_UART_NEW_BAUD_USE_XTAL_CLK (1 << 24) +#define AML_UART_NEW_BAUD_RATE_EN (1 << 23) +#define AML_UART_NEW_BAUD_RATE_MASK (0x7fffff << 0) +#define AML_UART_NEW_BAUD_RATE_SHIFT 0 + #endif /* _ARM_AMLOGIC_AML8726_UART_H */ Index: sys/arm/amlogic/aml8726/uart_dev_aml8726.c =================================================================== --- sys/arm/amlogic/aml8726/uart_dev_aml8726.c +++ sys/arm/amlogic/aml8726/uart_dev_aml8726.c @@ -31,8 +31,8 @@ * uarts. For example ... though UART A as a 128 byte FIFO, the * others only have a 64 byte FIFO. * - * Also, it's assumed that register 5 (the new baud rate register - * present on the aml8726-m6) has not been activated. + * Also, it's assumed that the USE_XTAL_CLK feature (available on + * the aml8726-m6 and later) has not been activated. */ #include @@ -57,6 +57,7 @@ #include #include +#include #include #include "uart_if.h" @@ -89,7 +90,7 @@ /* integer version of (rclk / baudrate + .5) */ divisor = ((rclk << 1) + baudrate) / (baudrate << 1); - if (divisor == 0 || divisor >= 65536) + if (divisor == 0) return (0); actual_baud = rclk / divisor; @@ -109,6 +110,7 @@ { uint32_t cr; uint32_t mr; + uint32_t nbr; int divisor; cr = uart_getreg(bas, AML_UART_CONTROL_REG); @@ -147,9 +149,30 @@ /* Set baudrate. */ if (baudrate > 0 && bas->rclk != 0) { divisor = aml8726_uart_divisor(bas->rclk / 4, baudrate) - 1; - if (divisor > 0xffff) - return (EINVAL); + switch (aml8726_soc_hw_rev) { + case AML_SOC_HW_REV_M6: + case AML_SOC_HW_REV_M8: + case AML_SOC_HW_REV_M8B: + if (divisor > (AML_UART_NEW_BAUD_RATE_MASK >> + AML_UART_NEW_BAUD_RATE_SHIFT)) + return (EINVAL); + + nbr = uart_getreg(bas, AML_UART_NEW_BAUD_REG); + nbr &= ~(AML_UART_NEW_BAUD_USE_XTAL_CLK | + AML_UART_NEW_BAUD_RATE_MASK); + nbr |= AML_UART_NEW_BAUD_RATE_EN | + (divisor << AML_UART_NEW_BAUD_RATE_SHIFT); + uart_setreg(bas, AML_UART_NEW_BAUD_REG, nbr); + + divisor = 0; + break; + default: + if (divisor > 0xffff) + return (EINVAL); + break; + } + cr &= ~AML_UART_CONTROL_BAUD_MASK; cr |= (divisor & AML_UART_CONTROL_BAUD_MASK); @@ -187,7 +210,7 @@ uint32_t cr; uint32_t mr; - aml8726_uart_param(bas, baudrate, databits, stopbits, parity); + (void)aml8726_uart_param(bas, baudrate, databits, stopbits, parity); cr = uart_getreg(bas, AML_UART_CONTROL_REG); /* Disable all interrupt sources. */ @@ -466,7 +489,7 @@ { struct uart_bas *bas; int baudrate, divisor, error; - uint32_t cr, mr; + uint32_t cr, mr, nbr; bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); @@ -483,6 +506,20 @@ divisor = ((mr >> AML_UART_MISC_BAUD_EXT_SHIFT) << AML_UART_CONTROL_BAUD_WIDTH) | cr; + switch (aml8726_soc_hw_rev) { + case AML_SOC_HW_REV_M6: + case AML_SOC_HW_REV_M8: + case AML_SOC_HW_REV_M8B: + nbr = uart_getreg(bas, AML_UART_NEW_BAUD_REG); + if ((nbr & AML_UART_NEW_BAUD_RATE_EN) != 0) { + divisor = (nbr & AML_UART_NEW_BAUD_RATE_MASK) >> + AML_UART_NEW_BAUD_RATE_SHIFT; + } + break; + default: + break; + } + baudrate = bas->rclk / 4 / (divisor + 1); if (baudrate > 0) *(int*)data = baudrate;