Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * udbg for NS16550 compatible serial ports
0004  *
0005  * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp
0006  */
0007 #include <linux/types.h>
0008 #include <asm/udbg.h>
0009 #include <asm/io.h>
0010 #include <asm/reg_a2.h>
0011 
0012 extern u8 real_readb(volatile u8 __iomem  *addr);
0013 extern void real_writeb(u8 data, volatile u8 __iomem *addr);
0014 extern u8 real_205_readb(volatile u8 __iomem  *addr);
0015 extern void real_205_writeb(u8 data, volatile u8 __iomem *addr);
0016 
0017 #define UART_RBR    0
0018 #define UART_IER    1
0019 #define UART_FCR    2
0020 #define UART_LCR    3
0021 #define UART_MCR    4
0022 #define UART_LSR    5
0023 #define UART_MSR    6
0024 #define UART_SCR    7
0025 #define UART_THR    UART_RBR
0026 #define UART_IIR    UART_FCR
0027 #define UART_DLL    UART_RBR
0028 #define UART_DLM    UART_IER
0029 #define UART_DLAB   UART_LCR
0030 
0031 #define LSR_DR   0x01  /* Data ready */
0032 #define LSR_OE   0x02  /* Overrun */
0033 #define LSR_PE   0x04  /* Parity error */
0034 #define LSR_FE   0x08  /* Framing error */
0035 #define LSR_BI   0x10  /* Break */
0036 #define LSR_THRE 0x20  /* Xmit holding register empty */
0037 #define LSR_TEMT 0x40  /* Xmitter empty */
0038 #define LSR_ERR  0x80  /* Error */
0039 
0040 #define LCR_DLAB 0x80
0041 
0042 static u8 (*udbg_uart_in)(unsigned int reg);
0043 static void (*udbg_uart_out)(unsigned int reg, u8 data);
0044 
0045 static void udbg_uart_flush(void)
0046 {
0047     if (!udbg_uart_in)
0048         return;
0049 
0050     /* wait for idle */
0051     while ((udbg_uart_in(UART_LSR) & LSR_THRE) == 0)
0052         cpu_relax();
0053 }
0054 
0055 static void udbg_uart_putc(char c)
0056 {
0057     if (!udbg_uart_out)
0058         return;
0059 
0060     if (c == '\n')
0061         udbg_uart_putc('\r');
0062     udbg_uart_flush();
0063     udbg_uart_out(UART_THR, c);
0064 }
0065 
0066 static int udbg_uart_getc_poll(void)
0067 {
0068     if (!udbg_uart_in)
0069         return -1;
0070 
0071     if (!(udbg_uart_in(UART_LSR) & LSR_DR))
0072         return udbg_uart_in(UART_RBR);
0073 
0074     return -1;
0075 }
0076 
0077 static int udbg_uart_getc(void)
0078 {
0079     if (!udbg_uart_in)
0080         return -1;
0081     /* wait for char */
0082     while (!(udbg_uart_in(UART_LSR) & LSR_DR))
0083         cpu_relax();
0084     return udbg_uart_in(UART_RBR);
0085 }
0086 
0087 static void __init udbg_use_uart(void)
0088 {
0089     udbg_putc = udbg_uart_putc;
0090     udbg_flush = udbg_uart_flush;
0091     udbg_getc = udbg_uart_getc;
0092     udbg_getc_poll = udbg_uart_getc_poll;
0093 }
0094 
0095 void __init udbg_uart_setup(unsigned int speed, unsigned int clock)
0096 {
0097     unsigned int dll, base_bauds;
0098 
0099     if (!udbg_uart_out)
0100         return;
0101 
0102     if (clock == 0)
0103         clock = 1843200;
0104     if (speed == 0)
0105         speed = 9600;
0106 
0107     base_bauds = clock / 16;
0108     dll = base_bauds / speed;
0109 
0110     udbg_uart_out(UART_LCR, 0x00);
0111     udbg_uart_out(UART_IER, 0xff);
0112     udbg_uart_out(UART_IER, 0x00);
0113     udbg_uart_out(UART_LCR, LCR_DLAB);
0114     udbg_uart_out(UART_DLL, dll & 0xff);
0115     udbg_uart_out(UART_DLM, dll >> 8);
0116     /* 8 data, 1 stop, no parity */
0117     udbg_uart_out(UART_LCR, 0x3);
0118     /* RTS/DTR */
0119     udbg_uart_out(UART_MCR, 0x3);
0120     /* Clear & enable FIFOs */
0121     udbg_uart_out(UART_FCR, 0x7);
0122 }
0123 
0124 unsigned int __init udbg_probe_uart_speed(unsigned int clock)
0125 {
0126     unsigned int dll, dlm, divisor, prescaler, speed;
0127     u8 old_lcr;
0128 
0129     old_lcr = udbg_uart_in(UART_LCR);
0130 
0131     /* select divisor latch registers.  */
0132     udbg_uart_out(UART_LCR, old_lcr | LCR_DLAB);
0133 
0134     /* now, read the divisor */
0135     dll = udbg_uart_in(UART_DLL);
0136     dlm = udbg_uart_in(UART_DLM);
0137     divisor = dlm << 8 | dll;
0138 
0139     /* check prescaling */
0140     if (udbg_uart_in(UART_MCR) & 0x80)
0141         prescaler = 4;
0142     else
0143         prescaler = 1;
0144 
0145     /* restore the LCR */
0146     udbg_uart_out(UART_LCR, old_lcr);
0147 
0148     /* calculate speed */
0149     speed = (clock / prescaler) / (divisor * 16);
0150 
0151     /* sanity check */
0152     if (speed > (clock / 16))
0153         speed = 9600;
0154 
0155     return speed;
0156 }
0157 
0158 static union {
0159     unsigned char __iomem *mmio_base;
0160     unsigned long pio_base;
0161 } udbg_uart;
0162 
0163 static unsigned int udbg_uart_stride = 1;
0164 
0165 static u8 udbg_uart_in_pio(unsigned int reg)
0166 {
0167     return inb(udbg_uart.pio_base + (reg * udbg_uart_stride));
0168 }
0169 
0170 static void udbg_uart_out_pio(unsigned int reg, u8 data)
0171 {
0172     outb(data, udbg_uart.pio_base + (reg * udbg_uart_stride));
0173 }
0174 
0175 void __init udbg_uart_init_pio(unsigned long port, unsigned int stride)
0176 {
0177     if (!port)
0178         return;
0179     udbg_uart.pio_base = port;
0180     udbg_uart_stride = stride;
0181     udbg_uart_in = udbg_uart_in_pio;
0182     udbg_uart_out = udbg_uart_out_pio;
0183     udbg_use_uart();
0184 }
0185 
0186 static u8 udbg_uart_in_mmio(unsigned int reg)
0187 {
0188     return in_8(udbg_uart.mmio_base + (reg * udbg_uart_stride));
0189 }
0190 
0191 static void udbg_uart_out_mmio(unsigned int reg, u8 data)
0192 {
0193     out_8(udbg_uart.mmio_base + (reg * udbg_uart_stride), data);
0194 }
0195 
0196 
0197 void __init udbg_uart_init_mmio(void __iomem *addr, unsigned int stride)
0198 {
0199     if (!addr)
0200         return;
0201     udbg_uart.mmio_base = addr;
0202     udbg_uart_stride = stride;
0203     udbg_uart_in = udbg_uart_in_mmio;
0204     udbg_uart_out = udbg_uart_out_mmio;
0205     udbg_use_uart();
0206 }
0207 
0208 #ifdef CONFIG_PPC_MAPLE
0209 
0210 #define UDBG_UART_MAPLE_ADDR    ((void __iomem *)0xf40003f8)
0211 
0212 static u8 udbg_uart_in_maple(unsigned int reg)
0213 {
0214     return real_readb(UDBG_UART_MAPLE_ADDR + reg);
0215 }
0216 
0217 static void udbg_uart_out_maple(unsigned int reg, u8 val)
0218 {
0219     real_writeb(val, UDBG_UART_MAPLE_ADDR + reg);
0220 }
0221 
0222 void __init udbg_init_maple_realmode(void)
0223 {
0224     udbg_uart_in = udbg_uart_in_maple;
0225     udbg_uart_out = udbg_uart_out_maple;
0226     udbg_use_uart();
0227 }
0228 
0229 #endif /* CONFIG_PPC_MAPLE */
0230 
0231 #ifdef CONFIG_PPC_PASEMI
0232 
0233 #define UDBG_UART_PAS_ADDR  ((void __iomem *)0xfcff03f8UL)
0234 
0235 static u8 udbg_uart_in_pas(unsigned int reg)
0236 {
0237     return real_205_readb(UDBG_UART_PAS_ADDR + reg);
0238 }
0239 
0240 static void udbg_uart_out_pas(unsigned int reg, u8 val)
0241 {
0242     real_205_writeb(val, UDBG_UART_PAS_ADDR + reg);
0243 }
0244 
0245 void __init udbg_init_pas_realmode(void)
0246 {
0247     udbg_uart_in = udbg_uart_in_pas;
0248     udbg_uart_out = udbg_uart_out_pas;
0249     udbg_use_uart();
0250 }
0251 
0252 #endif /* CONFIG_PPC_PASEMI */
0253 
0254 #ifdef CONFIG_PPC_EARLY_DEBUG_44x
0255 
0256 #include <platforms/44x/44x.h>
0257 
0258 static u8 udbg_uart_in_44x_as1(unsigned int reg)
0259 {
0260     return as1_readb((void __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR + reg);
0261 }
0262 
0263 static void udbg_uart_out_44x_as1(unsigned int reg, u8 val)
0264 {
0265     as1_writeb(val, (void __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR + reg);
0266 }
0267 
0268 void __init udbg_init_44x_as1(void)
0269 {
0270     udbg_uart_in = udbg_uart_in_44x_as1;
0271     udbg_uart_out = udbg_uart_out_44x_as1;
0272     udbg_use_uart();
0273 }
0274 
0275 #endif /* CONFIG_PPC_EARLY_DEBUG_44x */
0276 
0277 #ifdef CONFIG_PPC_EARLY_DEBUG_40x
0278 
0279 static u8 udbg_uart_in_40x(unsigned int reg)
0280 {
0281     return real_readb((void __iomem *)CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR
0282               + reg);
0283 }
0284 
0285 static void udbg_uart_out_40x(unsigned int reg, u8 val)
0286 {
0287     real_writeb(val, (void __iomem *)CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR
0288             + reg);
0289 }
0290 
0291 void __init udbg_init_40x_realmode(void)
0292 {
0293     udbg_uart_in = udbg_uart_in_40x;
0294     udbg_uart_out = udbg_uart_out_40x;
0295     udbg_use_uart();
0296 }
0297 
0298 #endif /* CONFIG_PPC_EARLY_DEBUG_40x */
0299 
0300 #ifdef CONFIG_PPC_EARLY_DEBUG_MICROWATT
0301 
0302 #define UDBG_UART_MW_ADDR   ((void __iomem *)0xc0002000)
0303 
0304 static u8 udbg_uart_in_isa300_rm(unsigned int reg)
0305 {
0306     uint64_t msr = mfmsr();
0307     uint8_t  c;
0308 
0309     mtmsr(msr & ~(MSR_EE|MSR_DR));
0310     isync();
0311     eieio();
0312     c = __raw_rm_readb(UDBG_UART_MW_ADDR + (reg << 2));
0313     mtmsr(msr);
0314     isync();
0315     return c;
0316 }
0317 
0318 static void udbg_uart_out_isa300_rm(unsigned int reg, u8 val)
0319 {
0320     uint64_t msr = mfmsr();
0321 
0322     mtmsr(msr & ~(MSR_EE|MSR_DR));
0323     isync();
0324     eieio();
0325     __raw_rm_writeb(val, UDBG_UART_MW_ADDR + (reg << 2));
0326     mtmsr(msr);
0327     isync();
0328 }
0329 
0330 void __init udbg_init_debug_microwatt(void)
0331 {
0332     udbg_uart_in = udbg_uart_in_isa300_rm;
0333     udbg_uart_out = udbg_uart_out_isa300_rm;
0334     udbg_use_uart();
0335 }
0336 
0337 #endif /* CONFIG_PPC_EARLY_DEBUG_MICROWATT */