]>
Commit | Line | Data |
---|---|---|
03de305e TR |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* | |
3 | * (C) Copyright 2022 - Analog Devices, Inc. | |
4 | * | |
5 | * Written and/or maintained by Timesys Corporation | |
6 | * | |
7 | * Converted to driver model by Nathan Barrett-Morrison | |
8 | * | |
9 | * Contact: Nathan Barrett-Morrison <[email protected]> | |
10 | * Contact: Greg Malysa <[email protected]> | |
11 | * | |
12 | */ | |
13 | ||
14 | #include <clk.h> | |
15 | #include <dm.h> | |
16 | #include <serial.h> | |
17 | #include <asm/io.h> | |
18 | #include <dm/device_compat.h> | |
19 | #include <linux/bitops.h> | |
20 | ||
21 | /* | |
22 | * UART4 Masks | |
23 | */ | |
24 | ||
25 | /* UART_CONTROL */ | |
26 | #define UEN BIT(0) | |
27 | #define LOOP_ENA BIT(1) | |
28 | #define UMOD (3 << 4) | |
29 | #define UMOD_UART (0 << 4) | |
30 | #define UMOD_MDB BIT(4) | |
31 | #define UMOD_IRDA BIT(4) | |
32 | #define WLS (3 << 8) | |
33 | #define WLS_5 (0 << 8) | |
34 | #define WLS_6 BIT(8) | |
35 | #define WLS_7 (2 << 8) | |
36 | #define WLS_8 (3 << 8) | |
37 | #define STB BIT(12) | |
38 | #define STBH BIT(13) | |
39 | #define PEN BIT(14) | |
40 | #define EPS BIT(15) | |
41 | #define STP BIT(16) | |
42 | #define FPE BIT(17) | |
43 | #define FFE BIT(18) | |
44 | #define SB BIT(19) | |
45 | #define FCPOL BIT(22) | |
46 | #define RPOLC BIT(23) | |
47 | #define TPOLC BIT(24) | |
48 | #define MRTS BIT(25) | |
49 | #define XOFF BIT(26) | |
50 | #define ARTS BIT(27) | |
51 | #define ACTS BIT(28) | |
52 | #define RFIT BIT(29) | |
53 | #define RFRT BIT(30) | |
54 | ||
55 | /* UART_STATUS */ | |
56 | #define DR BIT(0) | |
57 | #define OE BIT(1) | |
58 | #define PE BIT(2) | |
59 | #define FE BIT(3) | |
60 | #define BI BIT(4) | |
61 | #define THRE BIT(5) | |
62 | #define TEMT BIT(7) | |
63 | #define TFI BIT(8) | |
64 | #define ASTKY BIT(9) | |
65 | #define ADDR BIT(10) | |
66 | #define RO BIT(11) | |
67 | #define SCTS BIT(12) | |
68 | #define CTS BIT(16) | |
69 | #define RFCS BIT(17) | |
70 | ||
71 | /* UART_EMASK */ | |
72 | #define ERBFI BIT(0) | |
73 | #define ETBEI BIT(1) | |
74 | #define ELSI BIT(2) | |
75 | #define EDSSI BIT(3) | |
76 | #define EDTPTI BIT(4) | |
77 | #define ETFI BIT(5) | |
78 | #define ERFCI BIT(6) | |
79 | #define EAWI BIT(7) | |
80 | #define ERXS BIT(8) | |
81 | #define ETXS BIT(9) | |
82 | ||
83 | DECLARE_GLOBAL_DATA_PTR; | |
84 | ||
85 | struct uart4_reg { | |
86 | u32 revid; | |
87 | u32 control; | |
88 | u32 status; | |
89 | u32 scr; | |
90 | u32 clock; | |
91 | u32 emask; | |
92 | u32 emaskst; | |
93 | u32 emaskcl; | |
94 | u32 rbr; | |
95 | u32 thr; | |
96 | u32 taip; | |
97 | u32 tsr; | |
98 | u32 rsr; | |
99 | u32 txdiv_cnt; | |
100 | u32 rxdiv_cnt; | |
101 | }; | |
102 | ||
103 | struct adi_uart4_platdata { | |
104 | // Hardware registers | |
105 | struct uart4_reg *regs; | |
106 | ||
107 | // Enable divide-by-one baud rate setting | |
108 | bool edbo; | |
109 | }; | |
110 | ||
111 | static int adi_uart4_set_brg(struct udevice *dev, int baudrate) | |
112 | { | |
113 | struct adi_uart4_platdata *plat = dev_get_plat(dev); | |
114 | struct uart4_reg *regs = plat->regs; | |
115 | u32 divisor, uart_base_clk_rate; | |
116 | struct clk uart_base_clk; | |
117 | ||
118 | if (clk_get_by_index(dev, 0, &uart_base_clk)) { | |
119 | dev_err(dev, "Could not get UART base clock\n"); | |
120 | return -1; | |
121 | } | |
122 | ||
123 | uart_base_clk_rate = clk_get_rate(&uart_base_clk); | |
124 | ||
125 | if (plat->edbo) { | |
126 | u16 divisor16 = (uart_base_clk_rate + (baudrate / 2)) / baudrate; | |
127 | ||
128 | divisor = divisor16 | BIT(31); | |
129 | } else { | |
130 | // Divisor is only 16 bits | |
131 | divisor = 0x0000ffff & ((uart_base_clk_rate + (baudrate * 8)) / (baudrate * 16)); | |
132 | } | |
133 | ||
134 | writel(divisor, ®s->clock); | |
135 | return 0; | |
136 | } | |
137 | ||
138 | static int adi_uart4_pending(struct udevice *dev, bool input) | |
139 | { | |
140 | struct adi_uart4_platdata *plat = dev_get_plat(dev); | |
141 | struct uart4_reg *regs = plat->regs; | |
142 | ||
143 | if (input) | |
144 | return (readl(®s->status) & DR) ? 1 : 0; | |
145 | else | |
146 | return (readl(®s->status) & THRE) ? 0 : 1; | |
147 | } | |
148 | ||
149 | static int adi_uart4_getc(struct udevice *dev) | |
150 | { | |
151 | struct adi_uart4_platdata *plat = dev_get_plat(dev); | |
152 | struct uart4_reg *regs = plat->regs; | |
153 | int uart_rbr_val; | |
154 | ||
155 | if (!adi_uart4_pending(dev, true)) | |
156 | return -EAGAIN; | |
157 | ||
158 | uart_rbr_val = readl(®s->rbr); | |
159 | writel(-1, ®s->status); | |
160 | ||
161 | return uart_rbr_val; | |
162 | } | |
163 | ||
164 | static int adi_uart4_putc(struct udevice *dev, const char ch) | |
165 | { | |
166 | struct adi_uart4_platdata *plat = dev_get_plat(dev); | |
167 | struct uart4_reg *regs = plat->regs; | |
168 | ||
169 | if (adi_uart4_pending(dev, false)) | |
170 | return -EAGAIN; | |
171 | ||
172 | writel(ch, ®s->thr); | |
173 | return 0; | |
174 | } | |
175 | ||
176 | static const struct dm_serial_ops adi_uart4_serial_ops = { | |
177 | .setbrg = adi_uart4_set_brg, | |
178 | .getc = adi_uart4_getc, | |
179 | .putc = adi_uart4_putc, | |
180 | .pending = adi_uart4_pending, | |
181 | }; | |
182 | ||
183 | static int adi_uart4_of_to_plat(struct udevice *dev) | |
184 | { | |
185 | struct adi_uart4_platdata *plat = dev_get_plat(dev); | |
186 | fdt_addr_t addr; | |
187 | ||
188 | addr = dev_read_addr(dev); | |
189 | if (addr == FDT_ADDR_T_NONE) | |
190 | return -EINVAL; | |
191 | ||
192 | plat->regs = (struct uart4_reg *)addr; | |
193 | plat->edbo = dev_read_bool(dev, "adi,enable-edbo"); | |
194 | ||
195 | return 0; | |
196 | } | |
197 | ||
198 | static int adi_uart4_probe(struct udevice *dev) | |
199 | { | |
200 | struct adi_uart4_platdata *plat = dev_get_plat(dev); | |
201 | struct uart4_reg *regs = plat->regs; | |
202 | ||
203 | /* always enable UART to 8-bit mode */ | |
204 | writel(UEN | UMOD_UART | WLS_8, ®s->control); | |
205 | ||
206 | writel(-1, ®s->status); | |
207 | ||
208 | return 0; | |
209 | } | |
210 | ||
211 | static const struct udevice_id adi_uart4_serial_ids[] = { | |
212 | { .compatible = "adi,uart4" }, | |
213 | { } | |
214 | }; | |
215 | ||
216 | U_BOOT_DRIVER(serial_adi_uart4) = { | |
217 | .name = "serial_adi_uart4", | |
218 | .id = UCLASS_SERIAL, | |
219 | .of_match = adi_uart4_serial_ids, | |
220 | .of_to_plat = adi_uart4_of_to_plat, | |
221 | .plat_auto = sizeof(struct adi_uart4_platdata), | |
222 | .probe = adi_uart4_probe, | |
223 | .ops = &adi_uart4_serial_ops, | |
224 | .flags = DM_FLAG_PRE_RELOC, | |
225 | }; |