1d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos/*
20bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos *  Atheros AR7XXX/AR9XXX SoC early printk support
3d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos *
40bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
5d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
6d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos *
7d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos *  This program is free software; you can redistribute it and/or modify it
8d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos *  under the terms of the GNU General Public License version 2 as published
9d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos *  by the Free Software Foundation.
10d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos */
11d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos
12d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos#include <linux/io.h>
130bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos#include <linux/errno.h>
14d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos#include <linux/serial_reg.h>
15d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos#include <asm/addrspace.h>
16d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos
170bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos#include <asm/mach-ath79/ath79.h>
18d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos#include <asm/mach-ath79/ar71xx_regs.h>
190bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos#include <asm/mach-ath79/ar933x_uart.h>
20d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos
210bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhosstatic void (*_prom_putchar) (unsigned char);
220bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos
230bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhosstatic inline void prom_putchar_wait(void __iomem *reg, u32 mask, u32 val)
24d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos{
250bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	u32 t;
26d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos
27d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos	do {
280bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos		t = __raw_readl(reg);
290bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos		if ((t & mask) == val)
30d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos			break;
31d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos	} while (1);
32d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos}
33d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos
340bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhosstatic void prom_putchar_ar71xx(unsigned char ch)
35d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos{
36d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos	void __iomem *base = (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE));
37d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos
380bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE);
39d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos	__raw_writel(ch, base + UART_TX * 4);
400bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE);
410bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos}
420bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos
430bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhosstatic void prom_putchar_ar933x(unsigned char ch)
440bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos{
450bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	void __iomem *base = (void __iomem *)(KSEG1ADDR(AR933X_UART_BASE));
460bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos
470bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	prom_putchar_wait(base + AR933X_UART_DATA_REG, AR933X_UART_DATA_TX_CSR,
480bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos			  AR933X_UART_DATA_TX_CSR);
490bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	__raw_writel(AR933X_UART_DATA_TX_CSR | ch, base + AR933X_UART_DATA_REG);
500bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	prom_putchar_wait(base + AR933X_UART_DATA_REG, AR933X_UART_DATA_TX_CSR,
510bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos			  AR933X_UART_DATA_TX_CSR);
520bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos}
530bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos
540bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhosstatic void prom_putchar_dummy(unsigned char ch)
550bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos{
560bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	/* nothing to do */
570bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos}
580bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos
590bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhosstatic void prom_putchar_init(void)
600bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos{
610bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	void __iomem *base;
620bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	u32 id;
630bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos
640bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	base = (void __iomem *)(KSEG1ADDR(AR71XX_RESET_BASE));
650bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	id = __raw_readl(base + AR71XX_RESET_REG_REV_ID);
660bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	id &= REV_ID_MAJOR_MASK;
670bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos
680bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	switch (id) {
690bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	case REV_ID_MAJOR_AR71XX:
700bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	case REV_ID_MAJOR_AR7240:
710bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	case REV_ID_MAJOR_AR7241:
720bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	case REV_ID_MAJOR_AR7242:
730bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	case REV_ID_MAJOR_AR913X:
74703327ddcc736a054f4e2c132235a8370d2f7870Gabor Juhos	case REV_ID_MAJOR_AR9341:
75703327ddcc736a054f4e2c132235a8370d2f7870Gabor Juhos	case REV_ID_MAJOR_AR9342:
76703327ddcc736a054f4e2c132235a8370d2f7870Gabor Juhos	case REV_ID_MAJOR_AR9344:
77908987797076b848f01b32c21d61d0e152efc236Gabor Juhos	case REV_ID_MAJOR_QCA9556:
78908987797076b848f01b32c21d61d0e152efc236Gabor Juhos	case REV_ID_MAJOR_QCA9558:
790bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos		_prom_putchar = prom_putchar_ar71xx;
800bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos		break;
810bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos
820bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	case REV_ID_MAJOR_AR9330:
830bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	case REV_ID_MAJOR_AR9331:
840bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos		_prom_putchar = prom_putchar_ar933x;
850bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos		break;
860bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos
870bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	default:
880bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos		_prom_putchar = prom_putchar_dummy;
890bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos		break;
900bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	}
910bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos}
920bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos
930bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhosvoid prom_putchar(unsigned char ch)
940bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos{
950bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	if (!_prom_putchar)
960bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos		prom_putchar_init();
970bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos
980bd3acdf7d559c8289de73c4c711fd2381e6c7adGabor Juhos	_prom_putchar(ch);
99d4a67d9dc8a5a80c4ec1814791af8c0252c158b8Gabor Juhos}
100