arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / arch / powerpc / kernel / udbg_16550.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * udbg for NS16550 compatible serial ports
4  *
5  * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp
6  */
7 #include <linux/types.h>
8 #include <asm/udbg.h>
9 #include <asm/io.h>
10 #include <asm/reg_a2.h>
11 #include <asm/early_ioremap.h>
12
13 extern u8 real_readb(volatile u8 __iomem  *addr);
14 extern void real_writeb(u8 data, volatile u8 __iomem *addr);
15 extern u8 real_205_readb(volatile u8 __iomem  *addr);
16 extern void real_205_writeb(u8 data, volatile u8 __iomem *addr);
17
18 #define UART_RBR        0
19 #define UART_IER        1
20 #define UART_FCR        2
21 #define UART_LCR        3
22 #define UART_MCR        4
23 #define UART_LSR        5
24 #define UART_MSR        6
25 #define UART_SCR        7
26 #define UART_THR        UART_RBR
27 #define UART_IIR        UART_FCR
28 #define UART_DLL        UART_RBR
29 #define UART_DLM        UART_IER
30 #define UART_DLAB       UART_LCR
31
32 #define LSR_DR   0x01  /* Data ready */
33 #define LSR_OE   0x02  /* Overrun */
34 #define LSR_PE   0x04  /* Parity error */
35 #define LSR_FE   0x08  /* Framing error */
36 #define LSR_BI   0x10  /* Break */
37 #define LSR_THRE 0x20  /* Xmit holding register empty */
38 #define LSR_TEMT 0x40  /* Xmitter empty */
39 #define LSR_ERR  0x80  /* Error */
40
41 #define LCR_DLAB 0x80
42
43 static u8 (*udbg_uart_in)(unsigned int reg);
44 static void (*udbg_uart_out)(unsigned int reg, u8 data);
45
46 static void udbg_uart_flush(void)
47 {
48         if (!udbg_uart_in)
49                 return;
50
51         /* wait for idle */
52         while ((udbg_uart_in(UART_LSR) & LSR_THRE) == 0)
53                 cpu_relax();
54 }
55
56 static void udbg_uart_putc(char c)
57 {
58         if (!udbg_uart_out)
59                 return;
60
61         if (c == '\n')
62                 udbg_uart_putc('\r');
63         udbg_uart_flush();
64         udbg_uart_out(UART_THR, c);
65 }
66
67 static int udbg_uart_getc_poll(void)
68 {
69         if (!udbg_uart_in)
70                 return -1;
71
72         if (!(udbg_uart_in(UART_LSR) & LSR_DR))
73                 return udbg_uart_in(UART_RBR);
74
75         return -1;
76 }
77
78 static int udbg_uart_getc(void)
79 {
80         if (!udbg_uart_in)
81                 return -1;
82         /* wait for char */
83         while (!(udbg_uart_in(UART_LSR) & LSR_DR))
84                 cpu_relax();
85         return udbg_uart_in(UART_RBR);
86 }
87
88 static void __init udbg_use_uart(void)
89 {
90         udbg_putc = udbg_uart_putc;
91         udbg_flush = udbg_uart_flush;
92         udbg_getc = udbg_uart_getc;
93         udbg_getc_poll = udbg_uart_getc_poll;
94 }
95
96 void __init udbg_uart_setup(unsigned int speed, unsigned int clock)
97 {
98         unsigned int dll, base_bauds;
99
100         if (!udbg_uart_out)
101                 return;
102
103         if (clock == 0)
104                 clock = 1843200;
105         if (speed == 0)
106                 speed = 9600;
107
108         base_bauds = clock / 16;
109         dll = base_bauds / speed;
110
111         udbg_uart_out(UART_LCR, 0x00);
112         udbg_uart_out(UART_IER, 0xff);
113         udbg_uart_out(UART_IER, 0x00);
114         udbg_uart_out(UART_LCR, LCR_DLAB);
115         udbg_uart_out(UART_DLL, dll & 0xff);
116         udbg_uart_out(UART_DLM, dll >> 8);
117         /* 8 data, 1 stop, no parity */
118         udbg_uart_out(UART_LCR, 0x3);
119         /* RTS/DTR */
120         udbg_uart_out(UART_MCR, 0x3);
121         /* Clear & enable FIFOs */
122         udbg_uart_out(UART_FCR, 0x7);
123 }
124
125 unsigned int __init udbg_probe_uart_speed(unsigned int clock)
126 {
127         unsigned int dll, dlm, divisor, prescaler, speed;
128         u8 old_lcr;
129
130         old_lcr = udbg_uart_in(UART_LCR);
131
132         /* select divisor latch registers.  */
133         udbg_uart_out(UART_LCR, old_lcr | LCR_DLAB);
134
135         /* now, read the divisor */
136         dll = udbg_uart_in(UART_DLL);
137         dlm = udbg_uart_in(UART_DLM);
138         divisor = dlm << 8 | dll;
139
140         /* check prescaling */
141         if (udbg_uart_in(UART_MCR) & 0x80)
142                 prescaler = 4;
143         else
144                 prescaler = 1;
145
146         /* restore the LCR */
147         udbg_uart_out(UART_LCR, old_lcr);
148
149         /* calculate speed */
150         speed = (clock / prescaler) / (divisor * 16);
151
152         /* sanity check */
153         if (speed > (clock / 16))
154                 speed = 9600;
155
156         return speed;
157 }
158
159 static union {
160         unsigned char __iomem *mmio_base;
161         unsigned long pio_base;
162 } udbg_uart;
163
164 static unsigned int udbg_uart_stride = 1;
165
166 static u8 udbg_uart_in_pio(unsigned int reg)
167 {
168         return inb(udbg_uart.pio_base + (reg * udbg_uart_stride));
169 }
170
171 static void udbg_uart_out_pio(unsigned int reg, u8 data)
172 {
173         outb(data, udbg_uart.pio_base + (reg * udbg_uart_stride));
174 }
175
176 void __init udbg_uart_init_pio(unsigned long port, unsigned int stride)
177 {
178         if (!port)
179                 return;
180         udbg_uart.pio_base = port;
181         udbg_uart_stride = stride;
182         udbg_uart_in = udbg_uart_in_pio;
183         udbg_uart_out = udbg_uart_out_pio;
184         udbg_use_uart();
185 }
186
187 static u8 udbg_uart_in_mmio(unsigned int reg)
188 {
189         return in_8(udbg_uart.mmio_base + (reg * udbg_uart_stride));
190 }
191
192 static void udbg_uart_out_mmio(unsigned int reg, u8 data)
193 {
194         out_8(udbg_uart.mmio_base + (reg * udbg_uart_stride), data);
195 }
196
197
198 void __init udbg_uart_init_mmio(void __iomem *addr, unsigned int stride)
199 {
200         if (!addr)
201                 return;
202         udbg_uart.mmio_base = addr;
203         udbg_uart_stride = stride;
204         udbg_uart_in = udbg_uart_in_mmio;
205         udbg_uart_out = udbg_uart_out_mmio;
206         udbg_use_uart();
207 }
208
209 #ifdef CONFIG_PPC_MAPLE
210
211 #define UDBG_UART_MAPLE_ADDR    ((void __iomem *)0xf40003f8)
212
213 static u8 udbg_uart_in_maple(unsigned int reg)
214 {
215         return real_readb(UDBG_UART_MAPLE_ADDR + reg);
216 }
217
218 static void udbg_uart_out_maple(unsigned int reg, u8 val)
219 {
220         real_writeb(val, UDBG_UART_MAPLE_ADDR + reg);
221 }
222
223 void __init udbg_init_maple_realmode(void)
224 {
225         udbg_uart_in = udbg_uart_in_maple;
226         udbg_uart_out = udbg_uart_out_maple;
227         udbg_use_uart();
228 }
229
230 #endif /* CONFIG_PPC_MAPLE */
231
232 #ifdef CONFIG_PPC_PASEMI
233
234 #define UDBG_UART_PAS_ADDR      ((void __iomem *)0xfcff03f8UL)
235
236 static u8 udbg_uart_in_pas(unsigned int reg)
237 {
238         return real_205_readb(UDBG_UART_PAS_ADDR + reg);
239 }
240
241 static void udbg_uart_out_pas(unsigned int reg, u8 val)
242 {
243         real_205_writeb(val, UDBG_UART_PAS_ADDR + reg);
244 }
245
246 void __init udbg_init_pas_realmode(void)
247 {
248         udbg_uart_in = udbg_uart_in_pas;
249         udbg_uart_out = udbg_uart_out_pas;
250         udbg_use_uart();
251 }
252
253 #endif /* CONFIG_PPC_PASEMI */
254
255 #ifdef CONFIG_PPC_EARLY_DEBUG_44x
256
257 #include <platforms/44x/44x.h>
258
259 static u8 udbg_uart_in_44x_as1(unsigned int reg)
260 {
261         return as1_readb((void __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR + reg);
262 }
263
264 static void udbg_uart_out_44x_as1(unsigned int reg, u8 val)
265 {
266         as1_writeb(val, (void __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR + reg);
267 }
268
269 void __init udbg_init_44x_as1(void)
270 {
271         udbg_uart_in = udbg_uart_in_44x_as1;
272         udbg_uart_out = udbg_uart_out_44x_as1;
273         udbg_use_uart();
274 }
275
276 #endif /* CONFIG_PPC_EARLY_DEBUG_44x */
277
278 #ifdef CONFIG_PPC_EARLY_DEBUG_40x
279
280 static u8 udbg_uart_in_40x(unsigned int reg)
281 {
282         return real_readb((void __iomem *)CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR
283                           + reg);
284 }
285
286 static void udbg_uart_out_40x(unsigned int reg, u8 val)
287 {
288         real_writeb(val, (void __iomem *)CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR
289                     + reg);
290 }
291
292 void __init udbg_init_40x_realmode(void)
293 {
294         udbg_uart_in = udbg_uart_in_40x;
295         udbg_uart_out = udbg_uart_out_40x;
296         udbg_use_uart();
297 }
298
299 #endif /* CONFIG_PPC_EARLY_DEBUG_40x */
300
301 #ifdef CONFIG_PPC_EARLY_DEBUG_16550
302
303 static void __iomem *udbg_uart_early_addr;
304
305 void __init udbg_init_debug_16550(void)
306 {
307         udbg_uart_early_addr = early_ioremap(CONFIG_PPC_EARLY_DEBUG_16550_PHYSADDR, 0x1000);
308         udbg_uart_init_mmio(udbg_uart_early_addr, CONFIG_PPC_EARLY_DEBUG_16550_STRIDE);
309 }
310
311 static int __init udbg_init_debug_16550_ioremap(void)
312 {
313         void __iomem *addr;
314
315         if (!udbg_uart_early_addr)
316                 return 0;
317
318         addr = ioremap(CONFIG_PPC_EARLY_DEBUG_16550_PHYSADDR, 0x1000);
319         if (WARN_ON(!addr))
320                 return -ENOMEM;
321
322         udbg_uart_init_mmio(addr, CONFIG_PPC_EARLY_DEBUG_16550_STRIDE);
323         early_iounmap(udbg_uart_early_addr, 0x1000);
324         udbg_uart_early_addr = NULL;
325
326         return 0;
327 }
328
329 early_initcall(udbg_init_debug_16550_ioremap);
330
331 #endif /* CONFIG_PPC_EARLY_DEBUG_16550 */