1 // SPDX-License-Identifier: GPL-2.0+ 2 /* Synopsys DesignWare 8250 library. */ 3 4 #include <linux/bitops.h> 5 #include <linux/device.h> 6 #include <linux/io.h> 7 #include <linux/kernel.h> 8 #include <linux/serial_8250.h> 9 #include <linux/serial_core.h> 10 11 #include "8250_dwlib.h" 12 13 /* Offsets for the DesignWare specific registers */ 14 #define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */ 15 #define DW_UART_CPR 0xf4 /* Component Parameter Register */ 16 #define DW_UART_UCV 0xf8 /* UART Component Version */ 17 18 /* Component Parameter Register bits */ 19 #define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0) 20 #define DW_UART_CPR_AFCE_MODE (1 << 4) 21 #define DW_UART_CPR_THRE_MODE (1 << 5) 22 #define DW_UART_CPR_SIR_MODE (1 << 6) 23 #define DW_UART_CPR_SIR_LP_MODE (1 << 7) 24 #define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8) 25 #define DW_UART_CPR_FIFO_ACCESS (1 << 9) 26 #define DW_UART_CPR_FIFO_STAT (1 << 10) 27 #define DW_UART_CPR_SHADOW (1 << 11) 28 #define DW_UART_CPR_ENCODED_PARMS (1 << 12) 29 #define DW_UART_CPR_DMA_EXTRA (1 << 13) 30 #define DW_UART_CPR_FIFO_MODE (0xff << 16) 31 32 /* Helper for FIFO size calculation */ 33 #define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16) 34 35 static inline u32 dw8250_readl_ext(struct uart_port *p, int offset) 36 { 37 if (p->iotype == UPIO_MEM32BE) 38 return ioread32be(p->membase + offset); 39 return readl(p->membase + offset); 40 } 41 42 static inline void dw8250_writel_ext(struct uart_port *p, int offset, u32 reg) 43 { 44 if (p->iotype == UPIO_MEM32BE) 45 iowrite32be(reg, p->membase + offset); 46 else 47 writel(reg, p->membase + offset); 48 } 49 50 /* 51 * divisor = div(I) + div(F) 52 * "I" means integer, "F" means fractional 53 * quot = div(I) = clk / (16 * baud) 54 * frac = div(F) * 2^dlf_size 55 * 56 * let rem = clk % (16 * baud) 57 * we have: div(F) * (16 * baud) = rem 58 * so frac = 2^dlf_size * rem / (16 * baud) = (rem << dlf_size) / (16 * baud) 59 */ 60 static unsigned int dw8250_get_divisor(struct uart_port *p, unsigned int baud, 61 unsigned int *frac) 62 { 63 unsigned int quot, rem, base_baud = baud * 16; 64 struct dw8250_port_data *d = p->private_data; 65 66 quot = p->uartclk / base_baud; 67 rem = p->uartclk % base_baud; 68 *frac = DIV_ROUND_CLOSEST(rem << d->dlf_size, base_baud); 69 70 return quot; 71 } 72 73 static void dw8250_set_divisor(struct uart_port *p, unsigned int baud, 74 unsigned int quot, unsigned int quot_frac) 75 { 76 dw8250_writel_ext(p, DW_UART_DLF, quot_frac); 77 serial8250_do_set_divisor(p, baud, quot, quot_frac); 78 } 79 80 void dw8250_setup_port(struct uart_port *p) 81 { 82 struct uart_8250_port *up = up_to_u8250p(p); 83 u32 reg; 84 85 /* 86 * If the Component Version Register returns zero, we know that 87 * ADDITIONAL_FEATURES are not enabled. No need to go any further. 88 */ 89 reg = dw8250_readl_ext(p, DW_UART_UCV); 90 if (!reg) 91 return; 92 93 dev_dbg(p->dev, "Designware UART version %c.%c%c\n", 94 (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); 95 96 dw8250_writel_ext(p, DW_UART_DLF, ~0U); 97 reg = dw8250_readl_ext(p, DW_UART_DLF); 98 dw8250_writel_ext(p, DW_UART_DLF, 0); 99 100 if (reg) { 101 struct dw8250_port_data *d = p->private_data; 102 103 d->dlf_size = fls(reg); 104 p->get_divisor = dw8250_get_divisor; 105 p->set_divisor = dw8250_set_divisor; 106 } 107 108 reg = dw8250_readl_ext(p, DW_UART_CPR); 109 if (!reg) 110 return; 111 112 /* Select the type based on FIFO */ 113 if (reg & DW_UART_CPR_FIFO_MODE) { 114 p->type = PORT_16550A; 115 p->flags |= UPF_FIXED_TYPE; 116 p->fifosize = DW_UART_CPR_FIFO_SIZE(reg); 117 up->capabilities = UART_CAP_FIFO; 118 } 119 120 if (reg & DW_UART_CPR_AFCE_MODE) 121 up->capabilities |= UART_CAP_AFE; 122 123 if (reg & DW_UART_CPR_SIR_MODE) 124 up->capabilities |= UART_CAP_IRDA; 125 } 126 EXPORT_SYMBOL_GPL(dw8250_setup_port); 127