xref: /openbmc/linux/arch/powerpc/kernel/udbg_16550.c (revision 35cd8785)
135cd8785SDavid Gibson /*
235cd8785SDavid Gibson  * udbg for for NS16550 compatable serial ports
335cd8785SDavid Gibson  *
435cd8785SDavid Gibson  * Copyright (C) 2001-2005 PPC 64 Team, IBM Corp
535cd8785SDavid Gibson  *
635cd8785SDavid Gibson  *      This program is free software; you can redistribute it and/or
735cd8785SDavid Gibson  *      modify it under the terms of the GNU General Public License
835cd8785SDavid Gibson  *      as published by the Free Software Foundation; either version
935cd8785SDavid Gibson  *      2 of the License, or (at your option) any later version.
1035cd8785SDavid Gibson  */
1135cd8785SDavid Gibson #include <linux/config.h>
1235cd8785SDavid Gibson #include <linux/types.h>
1335cd8785SDavid Gibson #include <asm/udbg.h>
1435cd8785SDavid Gibson #include <asm/io.h>
1535cd8785SDavid Gibson 
1635cd8785SDavid Gibson extern u8 real_readb(volatile u8 __iomem  *addr);
1735cd8785SDavid Gibson extern void real_writeb(u8 data, volatile u8 __iomem *addr);
1835cd8785SDavid Gibson 
1935cd8785SDavid Gibson struct NS16550 {
2035cd8785SDavid Gibson 	/* this struct must be packed */
2135cd8785SDavid Gibson 	unsigned char rbr;  /* 0 */
2235cd8785SDavid Gibson 	unsigned char ier;  /* 1 */
2335cd8785SDavid Gibson 	unsigned char fcr;  /* 2 */
2435cd8785SDavid Gibson 	unsigned char lcr;  /* 3 */
2535cd8785SDavid Gibson 	unsigned char mcr;  /* 4 */
2635cd8785SDavid Gibson 	unsigned char lsr;  /* 5 */
2735cd8785SDavid Gibson 	unsigned char msr;  /* 6 */
2835cd8785SDavid Gibson 	unsigned char scr;  /* 7 */
2935cd8785SDavid Gibson };
3035cd8785SDavid Gibson 
3135cd8785SDavid Gibson #define thr rbr
3235cd8785SDavid Gibson #define iir fcr
3335cd8785SDavid Gibson #define dll rbr
3435cd8785SDavid Gibson #define dlm ier
3535cd8785SDavid Gibson #define dlab lcr
3635cd8785SDavid Gibson 
3735cd8785SDavid Gibson #define LSR_DR   0x01  /* Data ready */
3835cd8785SDavid Gibson #define LSR_OE   0x02  /* Overrun */
3935cd8785SDavid Gibson #define LSR_PE   0x04  /* Parity error */
4035cd8785SDavid Gibson #define LSR_FE   0x08  /* Framing error */
4135cd8785SDavid Gibson #define LSR_BI   0x10  /* Break */
4235cd8785SDavid Gibson #define LSR_THRE 0x20  /* Xmit holding register empty */
4335cd8785SDavid Gibson #define LSR_TEMT 0x40  /* Xmitter empty */
4435cd8785SDavid Gibson #define LSR_ERR  0x80  /* Error */
4535cd8785SDavid Gibson 
4635cd8785SDavid Gibson static volatile struct NS16550 __iomem *udbg_comport;
4735cd8785SDavid Gibson 
4835cd8785SDavid Gibson static void udbg_550_putc(unsigned char c)
4935cd8785SDavid Gibson {
5035cd8785SDavid Gibson 	if (udbg_comport) {
5135cd8785SDavid Gibson 		while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0)
5235cd8785SDavid Gibson 			/* wait for idle */;
5335cd8785SDavid Gibson 		out_8(&udbg_comport->thr, c);
5435cd8785SDavid Gibson 		if (c == '\n')
5535cd8785SDavid Gibson 			udbg_550_putc('\r');
5635cd8785SDavid Gibson 	}
5735cd8785SDavid Gibson }
5835cd8785SDavid Gibson 
5935cd8785SDavid Gibson static int udbg_550_getc_poll(void)
6035cd8785SDavid Gibson {
6135cd8785SDavid Gibson 	if (udbg_comport) {
6235cd8785SDavid Gibson 		if ((in_8(&udbg_comport->lsr) & LSR_DR) != 0)
6335cd8785SDavid Gibson 			return in_8(&udbg_comport->rbr);
6435cd8785SDavid Gibson 		else
6535cd8785SDavid Gibson 			return -1;
6635cd8785SDavid Gibson 	}
6735cd8785SDavid Gibson 	return -1;
6835cd8785SDavid Gibson }
6935cd8785SDavid Gibson 
7035cd8785SDavid Gibson static unsigned char udbg_550_getc(void)
7135cd8785SDavid Gibson {
7235cd8785SDavid Gibson 	if (udbg_comport) {
7335cd8785SDavid Gibson 		while ((in_8(&udbg_comport->lsr) & LSR_DR) == 0)
7435cd8785SDavid Gibson 			/* wait for char */;
7535cd8785SDavid Gibson 		return in_8(&udbg_comport->rbr);
7635cd8785SDavid Gibson 	}
7735cd8785SDavid Gibson 	return 0;
7835cd8785SDavid Gibson }
7935cd8785SDavid Gibson 
8035cd8785SDavid Gibson void udbg_init_uart(void __iomem *comport, unsigned int speed)
8135cd8785SDavid Gibson {
8235cd8785SDavid Gibson 	u16 dll = speed ? (115200 / speed) : 12;
8335cd8785SDavid Gibson 
8435cd8785SDavid Gibson 	if (comport) {
8535cd8785SDavid Gibson 		udbg_comport = (struct NS16550 __iomem *)comport;
8635cd8785SDavid Gibson 		out_8(&udbg_comport->lcr, 0x00);
8735cd8785SDavid Gibson 		out_8(&udbg_comport->ier, 0xff);
8835cd8785SDavid Gibson 		out_8(&udbg_comport->ier, 0x00);
8935cd8785SDavid Gibson 		out_8(&udbg_comport->lcr, 0x80);	/* Access baud rate */
9035cd8785SDavid Gibson 		out_8(&udbg_comport->dll, dll & 0xff);	/* 1 = 115200,  2 = 57600,
9135cd8785SDavid Gibson 							   3 = 38400, 12 = 9600 baud */
9235cd8785SDavid Gibson 		out_8(&udbg_comport->dlm, dll >> 8);	/* dll >> 8 which should be zero
9335cd8785SDavid Gibson 							   for fast rates; */
9435cd8785SDavid Gibson 		out_8(&udbg_comport->lcr, 0x03);	/* 8 data, 1 stop, no parity */
9535cd8785SDavid Gibson 		out_8(&udbg_comport->mcr, 0x03);	/* RTS/DTR */
9635cd8785SDavid Gibson 		out_8(&udbg_comport->fcr ,0x07);	/* Clear & enable FIFOs */
9735cd8785SDavid Gibson 		udbg_putc = udbg_550_putc;
9835cd8785SDavid Gibson 		udbg_getc = udbg_550_getc;
9935cd8785SDavid Gibson 		udbg_getc_poll = udbg_550_getc_poll;
10035cd8785SDavid Gibson 	}
10135cd8785SDavid Gibson }
10235cd8785SDavid Gibson 
10335cd8785SDavid Gibson #ifdef CONFIG_PPC_MAPLE
10435cd8785SDavid Gibson void udbg_maple_real_putc(unsigned char c)
10535cd8785SDavid Gibson {
10635cd8785SDavid Gibson 	if (udbg_comport) {
10735cd8785SDavid Gibson 		while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
10835cd8785SDavid Gibson 			/* wait for idle */;
10935cd8785SDavid Gibson 		real_writeb(c, &udbg_comport->thr); eieio();
11035cd8785SDavid Gibson 		if (c == '\n')
11135cd8785SDavid Gibson 			udbg_maple_real_putc('\r');
11235cd8785SDavid Gibson 	}
11335cd8785SDavid Gibson }
11435cd8785SDavid Gibson 
11535cd8785SDavid Gibson void udbg_init_maple_realmode(void)
11635cd8785SDavid Gibson {
11735cd8785SDavid Gibson 	udbg_comport = (volatile struct NS16550 __iomem *)0xf40003f8;
11835cd8785SDavid Gibson 
11935cd8785SDavid Gibson 	udbg_putc = udbg_maple_real_putc;
12035cd8785SDavid Gibson 	udbg_getc = NULL;
12135cd8785SDavid Gibson 	udbg_getc_poll = NULL;
12235cd8785SDavid Gibson }
12335cd8785SDavid Gibson #endif /* CONFIG_PPC_MAPLE */
124