1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * udbg for NS16550 compatible serial ports
5 * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp
7 #include <linux/types.h>
10 #include <asm/early_ioremap.h>
12 extern u8
real_readb(volatile u8 __iomem
*addr
);
13 extern void real_writeb(u8 data
, volatile u8 __iomem
*addr
);
14 extern u8
real_205_readb(volatile u8 __iomem
*addr
);
15 extern void real_205_writeb(u8 data
, volatile u8 __iomem
*addr
);
25 #define UART_THR UART_RBR
26 #define UART_IIR UART_FCR
27 #define UART_DLL UART_RBR
28 #define UART_DLM UART_IER
29 #define UART_DLAB UART_LCR
31 #define LSR_DR 0x01 /* Data ready */
32 #define LSR_OE 0x02 /* Overrun */
33 #define LSR_PE 0x04 /* Parity error */
34 #define LSR_FE 0x08 /* Framing error */
35 #define LSR_BI 0x10 /* Break */
36 #define LSR_THRE 0x20 /* Xmit holding register empty */
37 #define LSR_TEMT 0x40 /* Xmitter empty */
38 #define LSR_ERR 0x80 /* Error */
42 static u8 (*udbg_uart_in
)(unsigned int reg
);
43 static void (*udbg_uart_out
)(unsigned int reg
, u8 data
);
45 static void udbg_uart_flush(void)
51 while ((udbg_uart_in(UART_LSR
) & LSR_THRE
) == 0)
55 static void udbg_uart_putc(char c
)
63 udbg_uart_out(UART_THR
, c
);
66 static int udbg_uart_getc_poll(void)
71 if (!(udbg_uart_in(UART_LSR
) & LSR_DR
))
72 return udbg_uart_in(UART_RBR
);
77 static int udbg_uart_getc(void)
82 while (!(udbg_uart_in(UART_LSR
) & LSR_DR
))
84 return udbg_uart_in(UART_RBR
);
87 static void __init
udbg_use_uart(void)
89 udbg_putc
= udbg_uart_putc
;
90 udbg_flush
= udbg_uart_flush
;
91 udbg_getc
= udbg_uart_getc
;
92 udbg_getc_poll
= udbg_uart_getc_poll
;
95 void __init
udbg_uart_setup(unsigned int speed
, unsigned int clock
)
97 unsigned int dll
, base_bauds
;
107 base_bauds
= clock
/ 16;
108 dll
= base_bauds
/ speed
;
110 udbg_uart_out(UART_LCR
, 0x00);
111 udbg_uart_out(UART_IER
, 0xff);
112 udbg_uart_out(UART_IER
, 0x00);
113 udbg_uart_out(UART_LCR
, LCR_DLAB
);
114 udbg_uart_out(UART_DLL
, dll
& 0xff);
115 udbg_uart_out(UART_DLM
, dll
>> 8);
116 /* 8 data, 1 stop, no parity */
117 udbg_uart_out(UART_LCR
, 0x3);
119 udbg_uart_out(UART_MCR
, 0x3);
120 /* Clear & enable FIFOs */
121 udbg_uart_out(UART_FCR
, 0x7);
124 unsigned int __init
udbg_probe_uart_speed(unsigned int clock
)
126 unsigned int dll
, dlm
, divisor
, prescaler
, speed
;
129 old_lcr
= udbg_uart_in(UART_LCR
);
131 /* select divisor latch registers. */
132 udbg_uart_out(UART_LCR
, old_lcr
| LCR_DLAB
);
134 /* now, read the divisor */
135 dll
= udbg_uart_in(UART_DLL
);
136 dlm
= udbg_uart_in(UART_DLM
);
137 divisor
= dlm
<< 8 | dll
;
139 /* check prescaling */
140 if (udbg_uart_in(UART_MCR
) & 0x80)
145 /* restore the LCR */
146 udbg_uart_out(UART_LCR
, old_lcr
);
148 /* calculate speed */
149 speed
= (clock
/ prescaler
) / (divisor
* 16);
152 if (speed
> (clock
/ 16))
159 unsigned char __iomem
*mmio_base
;
160 unsigned long pio_base
;
163 static unsigned int udbg_uart_stride
= 1;
165 static u8
udbg_uart_in_pio(unsigned int reg
)
167 return inb(udbg_uart
.pio_base
+ (reg
* udbg_uart_stride
));
170 static void udbg_uart_out_pio(unsigned int reg
, u8 data
)
172 outb(data
, udbg_uart
.pio_base
+ (reg
* udbg_uart_stride
));
175 void __init
udbg_uart_init_pio(unsigned long port
, unsigned int stride
)
179 udbg_uart
.pio_base
= port
;
180 udbg_uart_stride
= stride
;
181 udbg_uart_in
= udbg_uart_in_pio
;
182 udbg_uart_out
= udbg_uart_out_pio
;
186 static u8
udbg_uart_in_mmio(unsigned int reg
)
188 return in_8(udbg_uart
.mmio_base
+ (reg
* udbg_uart_stride
));
191 static void udbg_uart_out_mmio(unsigned int reg
, u8 data
)
193 out_8(udbg_uart
.mmio_base
+ (reg
* udbg_uart_stride
), data
);
197 void __init
udbg_uart_init_mmio(void __iomem
*addr
, unsigned int stride
)
201 udbg_uart
.mmio_base
= addr
;
202 udbg_uart_stride
= stride
;
203 udbg_uart_in
= udbg_uart_in_mmio
;
204 udbg_uart_out
= udbg_uart_out_mmio
;
208 #ifdef CONFIG_PPC_PASEMI
210 #define UDBG_UART_PAS_ADDR ((void __iomem *)0xfcff03f8UL)
212 static u8
udbg_uart_in_pas(unsigned int reg
)
214 return real_205_readb(UDBG_UART_PAS_ADDR
+ reg
);
217 static void udbg_uart_out_pas(unsigned int reg
, u8 val
)
219 real_205_writeb(val
, UDBG_UART_PAS_ADDR
+ reg
);
222 void __init
udbg_init_pas_realmode(void)
224 udbg_uart_in
= udbg_uart_in_pas
;
225 udbg_uart_out
= udbg_uart_out_pas
;
229 #endif /* CONFIG_PPC_PASEMI */
231 #ifdef CONFIG_PPC_EARLY_DEBUG_44x
233 #include <platforms/44x/44x.h>
235 static u8
udbg_uart_in_44x_as1(unsigned int reg
)
237 return as1_readb((void __iomem
*)PPC44x_EARLY_DEBUG_VIRTADDR
+ reg
);
240 static void udbg_uart_out_44x_as1(unsigned int reg
, u8 val
)
242 as1_writeb(val
, (void __iomem
*)PPC44x_EARLY_DEBUG_VIRTADDR
+ reg
);
245 void __init
udbg_init_44x_as1(void)
247 udbg_uart_in
= udbg_uart_in_44x_as1
;
248 udbg_uart_out
= udbg_uart_out_44x_as1
;
252 #endif /* CONFIG_PPC_EARLY_DEBUG_44x */
254 #ifdef CONFIG_PPC_EARLY_DEBUG_16550
256 static void __iomem
*udbg_uart_early_addr
;
258 void __init
udbg_init_debug_16550(void)
260 udbg_uart_early_addr
= early_ioremap(CONFIG_PPC_EARLY_DEBUG_16550_PHYSADDR
, 0x1000);
261 udbg_uart_init_mmio(udbg_uart_early_addr
, CONFIG_PPC_EARLY_DEBUG_16550_STRIDE
);
264 static int __init
udbg_init_debug_16550_ioremap(void)
268 if (!udbg_uart_early_addr
)
271 addr
= ioremap(CONFIG_PPC_EARLY_DEBUG_16550_PHYSADDR
, 0x1000);
275 udbg_uart_init_mmio(addr
, CONFIG_PPC_EARLY_DEBUG_16550_STRIDE
);
276 early_iounmap(udbg_uart_early_addr
, 0x1000);
277 udbg_uart_early_addr
= NULL
;
282 early_initcall(udbg_init_debug_16550_ioremap
);
284 #endif /* CONFIG_PPC_EARLY_DEBUG_16550 */