17cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa/*
27cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa *  8250/16550-type serial ports prom_putchar()
37cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa *
47cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa *  Copyright (C) 2010  Yoichi Yuasa <yuasa@linux-mips.org>
57cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa *
67cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa *  This program is free software; you can redistribute it and/or modify
77cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa *  it under the terms of the GNU General Public License as published by
87cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa *  the Free Software Foundation; either version 2 of the License, or
97cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa *  (at your option) any later version.
107cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa *
117cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa *  This program is distributed in the hope that it will be useful,
127cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa *  but WITHOUT ANY WARRANTY; without even the implied warranty of
137cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
147cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa *  GNU General Public License for more details.
157cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa *
167cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa *  You should have received a copy of the GNU General Public License
177cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa *  along with this program; if not, write to the Free Software
187cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
197cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa */
207cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa#include <linux/io.h>
217cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa#include <linux/serial_core.h>
227cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa#include <linux/serial_reg.h>
237cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa
247cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasastatic void __iomem *serial8250_base;
257cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasastatic unsigned int serial8250_reg_shift;
267cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasastatic unsigned int serial8250_tx_timeout;
277cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa
287cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasavoid setup_8250_early_printk_port(unsigned long base, unsigned int reg_shift,
297cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa				  unsigned int timeout)
307cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa{
317cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa	serial8250_base = (void __iomem *)base;
327cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa	serial8250_reg_shift = reg_shift;
337cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa	serial8250_tx_timeout = timeout;
347cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa}
357cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa
367cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasastatic inline u8 serial_in(int offset)
377cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa{
387cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa	return readb(serial8250_base + (offset << serial8250_reg_shift));
397cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa}
407cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa
417cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasastatic inline void serial_out(int offset, char value)
427cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa{
437cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa	writeb(value, serial8250_base + (offset << serial8250_reg_shift));
447cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa}
457cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa
467cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasavoid prom_putchar(char c)
477cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa{
487cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa	unsigned int timeout;
497cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa	int status, bits;
507cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa
517cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa	if (!serial8250_base)
527cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa		return;
537cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa
547cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa	timeout = serial8250_tx_timeout;
557cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa	bits = UART_LSR_TEMT | UART_LSR_THRE;
567cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa
577cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa	do {
587cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa		status = serial_in(UART_LSR);
597cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa
607cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa		if (--timeout == 0)
617cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa			break;
627cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa	} while ((status & bits) != bits);
637cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa
647cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa	if (timeout)
657cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa		serial_out(UART_TX, c);
667cd93b893567906d9c9e9e1121667600b4cebbafYoichi Yuasa}
67