ar71xx: use the tp-link parser on the tp-link boards
[openwrt.git] / target / linux / ar71xx / files / arch / mips / ar71xx / early_printk.c
index 76f69c562b8c4d563e95938376854cc6e82427a2..c85a04d2c1b162cf347afd7fad608f8ad7187914 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  Atheros AR71xx SoC early printk support
+ *  Atheros AR7xxx/AR9xxx SoC early printk support
  *
- *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
+ *  Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
  *  Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
  *
  *  This program is free software; you can redistribute it and/or modify it
@@ -9,24 +9,88 @@
  *  by the Free Software Foundation.
  */
 
+#include <linux/errno.h>
 #include <linux/io.h>
 #include <linux/serial_reg.h>
 #include <asm/addrspace.h>
 
 #include <asm/mach-ar71xx/ar71xx.h>
+#include <asm/mach-ar71xx/ar933x_uart.h>
 
-#define UART_READ(r) \
-       __raw_readl((void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE) + 4 * (r)))
+static void (*_prom_putchar) (unsigned char);
 
-#define UART_WRITE(r, v) \
-       __raw_writel((v), (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE) + 4*(r)))
+static inline void prom_putchar_wait(void __iomem *reg, u32 mask, u32 val)
+{
+       u32 t;
 
-void prom_putchar(unsigned char ch)
+       do {
+               t = __raw_readl(reg);
+               if ((t & mask) == val)
+                       break;
+       } while (1);
+}
+
+static void prom_putchar_ar71xx(unsigned char ch)
+{
+       void __iomem *base = (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE));
+
+       prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE);
+       __raw_writel(ch, base + UART_TX * 4);
+       prom_putchar_wait(base + UART_LSR * 4, UART_LSR_THRE, UART_LSR_THRE);
+}
+
+static void prom_putchar_ar933x(unsigned char ch)
+{
+       void __iomem *base = (void __iomem *)(KSEG1ADDR(AR933X_UART_BASE));
+
+       prom_putchar_wait(base + AR933X_UART_DATA_REG, AR933X_UART_DATA_TX_CSR,
+                         AR933X_UART_DATA_TX_CSR);
+       __raw_writel(AR933X_UART_DATA_TX_CSR | ch, base + AR933X_UART_DATA_REG);
+       prom_putchar_wait(base + AR933X_UART_DATA_REG, AR933X_UART_DATA_TX_CSR,
+                         AR933X_UART_DATA_TX_CSR);
+}
+
+static void prom_putchar_dummy(unsigned char ch)
 {
-       while (((UART_READ(UART_LSR)) & UART_LSR_THRE) == 0)
-               ;
-       UART_WRITE(UART_TX, ch);
-       while (((UART_READ(UART_LSR)) & UART_LSR_THRE) == 0)
-               ;
+       /* nothing to do */
 }
 
+static void prom_putchar_init(void)
+{
+       void __iomem *base;
+       u32 id;
+
+       base = (void __iomem *)(KSEG1ADDR(AR71XX_RESET_BASE));
+       id = __raw_readl(base + AR71XX_RESET_REG_REV_ID);
+       id &= REV_ID_MAJOR_MASK;
+
+       switch (id) {
+       case REV_ID_MAJOR_AR71XX:
+       case REV_ID_MAJOR_AR7240:
+       case REV_ID_MAJOR_AR7241:
+       case REV_ID_MAJOR_AR7242:
+       case REV_ID_MAJOR_AR913X:
+       case REV_ID_MAJOR_AR9341:
+       case REV_ID_MAJOR_AR9342:
+       case REV_ID_MAJOR_AR9344:
+               _prom_putchar = prom_putchar_ar71xx;
+               break;
+
+       case REV_ID_MAJOR_AR9330:
+       case REV_ID_MAJOR_AR9331:
+               _prom_putchar = prom_putchar_ar933x;
+               break;
+
+       default:
+               _prom_putchar = prom_putchar_dummy;
+               break;
+       }
+}
+
+void prom_putchar(unsigned char ch)
+{
+       if (!_prom_putchar)
+               prom_putchar_init();
+
+       _prom_putchar(ch);
+}