1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2016, Linaro Limited
4  */
5 #include <assert.h>
6 #include <drivers/hi16xx_uart.h>
7 #include <io.h>
8 #include <keep.h>
9 #include <mm/core_mmu.h>
10 #include <util.h>
11 
12 /* Register offsets */
13 
14 #define UART_RBR	0x00	/* RX data buffer register */
15 #define UART_THR	0x00	/* TX data buffer register */
16 #define UART_DLL	0x00	/* Lower-bit frequency divider register */
17 
18 #define UART_IEL	0x04	/* Interrupt enable register */
19 #define UART_DLH	0x04	/* Upper-bit frequency divider register */
20 
21 #define UART_FCR	0x08	/* FIFO control register */
22 
23 #define UART_LCR	0x0C	/* Line control register */
24 
25 #define UART_LSR	0x14	/* Line status register */
26 
27 #define UART_USR	0x7C	/* Status register */
28 
29 /*
30  * Line control register
31  */
32 
33 /* Data length selection */
34 #define UART_LCR_DLS5	0x0	/* 5 bits */
35 #define UART_LCR_DLS6	0x1	/* 6 bits */
36 #define UART_LCR_DLS7	0x2	/* 7 bits */
37 #define UART_LCR_DLS8	0x3	/* 8 bits */
38 
39 /* Enable access to UART_DLL and UART_DLH */
40 #define UART_LCR_DLAB	0x80
41 
42 /*
43  * FIFO control register
44  */
45 
46 #define UART_FCR_FIFO_EN	0x1	/* Enable FIFO (depth: 32 bytes) */
47 #define UART_FCR_RX_FIFO_RST	0x2	/* Clear receive FIFO (auto reset) */
48 #define UART_FCR_TX_FIFO_RST	0x4	/* Clear send FIFO (auto reset) */
49 
50 
51 /*
52  * Status register
53  */
54 
55 #define UART_USR_BUSY_BIT	0	/* 0: idle/non-activated, 1: busy */
56 #define UART_USR_TFNF_BIT	1	/* Transmit FIFO not full bit */
57 #define UART_USR_TFE_BIT	2	/* Transmit FIFO empty bit */
58 #define UART_USR_RFNE_BIT	3	/* Receive FIFO not empty bit */
59 #define UART_USR_RFF_BIT	4	/* Receive FIFO full bit */
60 
chip_to_base(struct serial_chip * chip)61 static vaddr_t chip_to_base(struct serial_chip *chip)
62 {
63 	struct hi16xx_uart_data *pd =
64 		container_of(chip, struct hi16xx_uart_data, chip);
65 
66 	return io_pa_or_va(&pd->base, HI16XX_UART_REG_SIZE);
67 }
68 
hi16xx_uart_flush(struct serial_chip * chip)69 static void hi16xx_uart_flush(struct serial_chip *chip)
70 {
71 	vaddr_t base = chip_to_base(chip);
72 
73 	while (!(io_read32(base + UART_USR) & UART_USR_TFE_BIT))
74 		;
75 }
76 
hi16xx_uart_putc(struct serial_chip * chip,int ch)77 static void hi16xx_uart_putc(struct serial_chip *chip, int ch)
78 {
79 	vaddr_t base = chip_to_base(chip);
80 
81 	/* Wait until TX FIFO is empty */
82 	while (!(io_read32(base + UART_USR) & UART_USR_TFE_BIT))
83 		;
84 
85 	/* Put character into TX FIFO */
86 	io_write32(base + UART_THR, ch & 0xFF);
87 }
88 
hi16xx_uart_have_rx_data(struct serial_chip * chip)89 static bool hi16xx_uart_have_rx_data(struct serial_chip *chip)
90 {
91 	vaddr_t base = chip_to_base(chip);
92 
93 	return (io_read32(base + UART_USR) & UART_USR_RFNE_BIT);
94 }
95 
hi16xx_uart_getchar(struct serial_chip * chip)96 static int hi16xx_uart_getchar(struct serial_chip *chip)
97 {
98 	vaddr_t base = chip_to_base(chip);
99 
100 	while (!hi16xx_uart_have_rx_data(chip))
101 		;
102 	return io_read32(base + UART_RBR) & 0xFF;
103 }
104 
105 static const struct serial_ops hi16xx_uart_ops = {
106 	.flush = hi16xx_uart_flush,
107 	.getchar = hi16xx_uart_getchar,
108 	.have_rx_data = hi16xx_uart_have_rx_data,
109 	.putc = hi16xx_uart_putc,
110 };
111 DECLARE_KEEP_PAGER(hi16xx_uart_ops);
112 
hi16xx_uart_init(struct hi16xx_uart_data * pd,paddr_t base,uint32_t uart_clk,uint32_t baud_rate)113 void hi16xx_uart_init(struct hi16xx_uart_data *pd, paddr_t base,
114 		      uint32_t uart_clk, uint32_t baud_rate)
115 {
116 	uint16_t freq_div = uart_clk / (16 * baud_rate);
117 
118 	pd->base.pa = base;
119 	pd->chip.ops = &hi16xx_uart_ops;
120 
121 	/* Enable (and clear) FIFOs */
122 	io_write32(base + UART_FCR, UART_FCR_FIFO_EN);
123 
124 	/* Enable access to _DLL and _DLH */
125 	io_write32(base + UART_LCR, UART_LCR_DLAB);
126 
127 	/* Calculate and set UART_DLL */
128 	io_write32(base + UART_DLL, freq_div & 0xFF);
129 
130 	/* Calculate and set UART_DLH */
131 	io_write32(base + UART_DLH, (freq_div >> 8) & 0xFF);
132 
133 	/* Clear _DLL/_DLH access bit, set data size (8 bits), parity etc. */
134 	io_write32(base + UART_LCR, UART_LCR_DLS8);
135 
136 	/* Disable interrupt mode */
137 	io_write32(base + UART_IEL, 0);
138 
139 	hi16xx_uart_flush(&pd->chip);
140 }
141 
142