From: Huiquan Zhong <huiquan.zhong@xxxxxxxxx> Intel Broxton contain 4 HSUART ports, Support for 16750 compatible Auto Flow Control with 64 FIFOs. Signed-off-by: Huiquan Zhong <huiquan.zhong@xxxxxxxxx> --- drivers/tty/serial/8250/8250_pci.c | 152 ++++++++++++++++++++++++++++++++----- 1 file changed, 135 insertions(+), 17 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 892eb32..824ca72 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1387,50 +1387,53 @@ ce4100_serial_setup(struct serial_private *priv, #define BYT_TX_OVF_INT 0x820 #define BYT_TX_OVF_INT_MASK (1 << 1) -static void -byt_set_termios(struct uart_port *p, struct ktermios *termios, - struct ktermios *old) +static inline void calc_for_prv_clk_div(struct uart_port *p, unsigned int baud, + unsigned int *m, unsigned int *n) { - unsigned int baud = tty_termios_baud_rate(termios); - unsigned int m, n; - u32 reg; - /* * For baud rates 0.5M, 1M, 1.5M, 2M, 2.5M, 3M, 3.5M and 4M the * dividers must be adjusted. * * uartclk = (m / n) * 100 MHz, where m <= n */ + *n = 100; switch (baud) { case 500000: case 1000000: case 2000000: case 4000000: - m = 64; - n = 100; + *m = 64; p->uartclk = 64000000; break; case 3500000: - m = 56; - n = 100; + *m = 56; p->uartclk = 56000000; break; case 1500000: case 3000000: - m = 48; - n = 100; + *m = 48; p->uartclk = 48000000; break; case 2500000: - m = 40; - n = 100; + *m = 40; p->uartclk = 40000000; break; default: - m = 2304; - n = 3125; + *m = 2304; + *n = 3125; p->uartclk = 73728000; } +} + +static void +byt_set_termios(struct uart_port *p, struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud = tty_termios_baud_rate(termios); + unsigned int m, n; + u32 reg; + + calc_for_prv_clk_div(p, baud, &m, &n); /* Reset the clock */ reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT); @@ -1525,6 +1528,71 @@ byt_serial_setup(struct serial_private *priv, return ret; } +#define PCI_DEVICE_ID_INTEL_BXT_UART0 0x0abc +#define PCI_DEVICE_ID_INTEL_BXT_UART1 0x0abe +#define PCI_DEVICE_ID_INTEL_BXT_UART2 0x0ac0 +#define PCI_DEVICE_ID_INTEL_BXT_UART3 0x0aee + +#define BXT_PRV_CLK 0x200 +#define BXT_PRV_CLK_EN (1 << 0) +#define BXT_PRV_CLK_M_VAL_SHIFT 1 +#define BXT_PRV_CLK_N_VAL_SHIFT 16 +#define BXT_PRV_CLK_UPDATE (1 << 31) + +#define BXT_UART_RESET 0x204 +#define BXT_UART_IDMA_RESET (1 << 2) +#define BXT_UART_HOST_RESET 0x3 + +#define BXT_UART_IC_CLOCK 0x238 +#define BXT_UART_IC_CLOCK_IDMA 0xc +#define BXT_UART_IC_CLOCK_UART 0x3 + +static void +bxt_set_termios(struct uart_port *p, struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud = tty_termios_baud_rate(termios); + unsigned int m, n; + u32 reg; + + calc_for_prv_clk_div(p, baud, &m, &n); + + /* Reset the clock */ + reg = (m << BXT_PRV_CLK_M_VAL_SHIFT) | (n << BXT_PRV_CLK_N_VAL_SHIFT); + writel(reg, p->membase + BXT_PRV_CLK); + reg |= BXT_PRV_CLK_EN | BXT_PRV_CLK_UPDATE; + writel(reg, p->membase + BXT_PRV_CLK); + + serial8250_do_set_termios(p, termios, old); +} + +static int +bxt_serial_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + int ret; + + ret = pci_default_setup(priv, board, port, idx); + port->port.iotype = UPIO_MEM; + port->port.type = PORT_16550A; + port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE); + port->port.set_termios = bxt_set_termios; + port->port.fifosize = 64; + port->tx_loadsz = 64; + port->capabilities = UART_CAP_FIFO | UART_CAP_AFE; + + /* Hw reset */ + writel(0, port->port.membase + BXT_UART_RESET); + writel(BXT_UART_IDMA_RESET | BXT_UART_HOST_RESET, + port->port.membase + BXT_UART_RESET); + /* clock not gate */ + writel(BXT_UART_IC_CLOCK_IDMA | BXT_UART_IC_CLOCK_UART, + port->port.membase + BXT_UART_IC_CLOCK); + + return ret; +} + static int pci_omegapci_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -2001,6 +2069,34 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = byt_serial_setup, }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_BXT_UART0, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = bxt_serial_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_BXT_UART1, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = bxt_serial_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_BXT_UART2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = bxt_serial_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_BXT_UART3, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = bxt_serial_setup, + }, /* * ITE */ @@ -2865,6 +2961,7 @@ enum pci_board_num_t { pbn_ce4100_1_115200, pbn_byt, pbn_qrk, + pbn_bxt, pbn_omegapci, pbn_NETMOS9900_2s_115200, pbn_brcm_trumanage, @@ -3636,6 +3733,12 @@ static struct pciserial_board pci_boards[] = { .base_baud = 2764800, .reg_shift = 2, }, + [pbn_bxt] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 2764800, + .reg_shift = 2, + }, [pbn_omegapci] = { .flags = FL_BASE0, .num_ports = 8, @@ -5368,6 +5471,21 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_UART, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_qrk }, + /* Intel Broxton */ + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT_UART0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_bxt }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT_UART1, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_bxt }, + + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT_UART2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_bxt }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT_UART3, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_bxt }, + /* * Cronyx Omega PCI */ -- 1.8.3.2 -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html