2011-01-04 23:28:14 +03:00
/*
2011-06-20 23:26:03 +04:00
* Atheros AR7XXX / AR9XXX SoC early printk support
2011-01-04 23:28:14 +03:00
*
2011-06-20 23:26:03 +04:00
* Copyright ( C ) 2008 - 2011 Gabor Juhos < juhosg @ openwrt . org >
2011-01-04 23:28:14 +03:00
* Copyright ( C ) 2008 Imre Kaloz < kaloz @ openwrt . org >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation .
*/
# include <linux/io.h>
2011-06-20 23:26:03 +04:00
# include <linux/errno.h>
2011-01-04 23:28:14 +03:00
# include <linux/serial_reg.h>
# include <asm/addrspace.h>
2011-06-20 23:26:03 +04:00
# include <asm/mach-ath79/ath79.h>
2011-01-04 23:28:14 +03:00
# include <asm/mach-ath79/ar71xx_regs.h>
2011-06-20 23:26:03 +04:00
# include <asm/mach-ath79/ar933x_uart.h>
2011-01-04 23:28:14 +03:00
2011-06-20 23:26:03 +04:00
static void ( * _prom_putchar ) ( unsigned char ) ;
static inline void prom_putchar_wait ( void __iomem * reg , u32 mask , u32 val )
2011-01-04 23:28:14 +03:00
{
2011-06-20 23:26:03 +04:00
u32 t ;
2011-01-04 23:28:14 +03:00
do {
2011-06-20 23:26:03 +04:00
t = __raw_readl ( reg ) ;
if ( ( t & mask ) = = val )
2011-01-04 23:28:14 +03:00
break ;
} while ( 1 ) ;
}
2016-03-24 18:02:52 +03:00
# define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
2011-06-20 23:26:03 +04:00
static void prom_putchar_ar71xx ( unsigned char ch )
2011-01-04 23:28:14 +03:00
{
void __iomem * base = ( void __iomem * ) ( KSEG1ADDR ( AR71XX_UART_BASE ) ) ;
2016-03-24 18:02:52 +03:00
prom_putchar_wait ( base + UART_LSR * 4 , BOTH_EMPTY , BOTH_EMPTY ) ;
2011-01-04 23:28:14 +03:00
__raw_writel ( ch , base + UART_TX * 4 ) ;
2016-03-24 18:02:52 +03:00
prom_putchar_wait ( base + UART_LSR * 4 , BOTH_EMPTY , BOTH_EMPTY ) ;
2011-06-20 23:26:03 +04:00
}
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 )
{
/* 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 :
2012-03-14 13:45:19 +04:00
case REV_ID_MAJOR_AR9341 :
case REV_ID_MAJOR_AR9342 :
case REV_ID_MAJOR_AR9344 :
2013-02-15 17:38:15 +04:00
case REV_ID_MAJOR_QCA9556 :
case REV_ID_MAJOR_QCA9558 :
2011-06-20 23:26:03 +04:00
_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 ) ;
2011-01-04 23:28:14 +03:00
}