2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2011-01-04 21:28:14 +01:00
/*
2011-06-20 21:26:03 +02:00
* Atheros AR7XXX / AR9XXX SoC early printk support
2011-01-04 21:28:14 +01:00
*
2011-06-20 21:26:03 +02:00
* Copyright ( C ) 2008 - 2011 Gabor Juhos < juhosg @ openwrt . org >
2011-01-04 21:28:14 +01:00
* Copyright ( C ) 2008 Imre Kaloz < kaloz @ openwrt . org >
*/
# include <linux/io.h>
2011-06-20 21:26:03 +02:00
# include <linux/errno.h>
2011-01-04 21:28:14 +01:00
# include <linux/serial_reg.h>
# include <asm/addrspace.h>
2018-07-13 17:51:56 +02:00
# include <asm/setup.h>
2011-01-04 21:28:14 +01:00
2011-06-20 21:26:03 +02:00
# include <asm/mach-ath79/ath79.h>
2011-01-04 21:28:14 +01:00
# include <asm/mach-ath79/ar71xx_regs.h>
2011-06-20 21:26:03 +02:00
# include <asm/mach-ath79/ar933x_uart.h>
2011-01-04 21:28:14 +01:00
2018-07-13 17:51:56 +02:00
static void ( * _prom_putchar ) ( char ) ;
2011-06-20 21:26:03 +02:00
static inline void prom_putchar_wait ( void __iomem * reg , u32 mask , u32 val )
2011-01-04 21:28:14 +01:00
{
2011-06-20 21:26:03 +02:00
u32 t ;
2011-01-04 21:28:14 +01:00
do {
2011-06-20 21:26:03 +02:00
t = __raw_readl ( reg ) ;
if ( ( t & mask ) = = val )
2011-01-04 21:28:14 +01:00
break ;
} while ( 1 ) ;
}
2016-03-24 16:02:52 +01:00
# define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
2018-07-13 17:51:56 +02:00
static void prom_putchar_ar71xx ( char ch )
2011-01-04 21:28:14 +01:00
{
void __iomem * base = ( void __iomem * ) ( KSEG1ADDR ( AR71XX_UART_BASE ) ) ;
2016-03-24 16:02:52 +01:00
prom_putchar_wait ( base + UART_LSR * 4 , BOTH_EMPTY , BOTH_EMPTY ) ;
2018-07-13 17:51:56 +02:00
__raw_writel ( ( unsigned char ) ch , base + UART_TX * 4 ) ;
2016-03-24 16:02:52 +01:00
prom_putchar_wait ( base + UART_LSR * 4 , BOTH_EMPTY , BOTH_EMPTY ) ;
2011-06-20 21:26:03 +02:00
}
2018-07-13 17:51:56 +02:00
static void prom_putchar_ar933x ( char ch )
2011-06-20 21:26:03 +02:00
{
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 ) ;
2018-07-13 17:51:56 +02:00
__raw_writel ( AR933X_UART_DATA_TX_CSR | ( unsigned char ) ch ,
base + AR933X_UART_DATA_REG ) ;
2011-06-20 21:26:03 +02:00
prom_putchar_wait ( base + AR933X_UART_DATA_REG , AR933X_UART_DATA_TX_CSR ,
AR933X_UART_DATA_TX_CSR ) ;
}
2018-07-13 17:51:56 +02:00
static void prom_putchar_dummy ( char ch )
2011-06-20 21:26:03 +02:00
{
/* nothing to do */
}
2018-07-20 13:58:24 +02:00
static void prom_enable_uart ( u32 id )
{
void __iomem * gpio_base ;
u32 uart_en ;
u32 t ;
switch ( id ) {
case REV_ID_MAJOR_AR71XX :
uart_en = AR71XX_GPIO_FUNC_UART_EN ;
break ;
case REV_ID_MAJOR_AR7240 :
case REV_ID_MAJOR_AR7241 :
case REV_ID_MAJOR_AR7242 :
uart_en = AR724X_GPIO_FUNC_UART_EN ;
break ;
case REV_ID_MAJOR_AR913X :
uart_en = AR913X_GPIO_FUNC_UART_EN ;
break ;
case REV_ID_MAJOR_AR9330 :
case REV_ID_MAJOR_AR9331 :
uart_en = AR933X_GPIO_FUNC_UART_EN ;
break ;
case REV_ID_MAJOR_AR9341 :
case REV_ID_MAJOR_AR9342 :
case REV_ID_MAJOR_AR9344 :
/* TODO */
default :
return ;
}
gpio_base = ( void __iomem * ) KSEG1ADDR ( AR71XX_GPIO_BASE ) ;
t = __raw_readl ( gpio_base + AR71XX_GPIO_REG_FUNC ) ;
t | = uart_en ;
__raw_writel ( t , gpio_base + AR71XX_GPIO_REG_FUNC ) ;
}
2011-06-20 21:26:03 +02:00
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 10:45:19 +01:00
case REV_ID_MAJOR_AR9341 :
case REV_ID_MAJOR_AR9342 :
case REV_ID_MAJOR_AR9344 :
2018-07-20 13:58:19 +02:00
case REV_ID_MAJOR_QCA9533 :
case REV_ID_MAJOR_QCA9533_V2 :
2013-02-15 13:38:15 +00:00
case REV_ID_MAJOR_QCA9556 :
case REV_ID_MAJOR_QCA9558 :
2018-07-20 13:58:19 +02:00
case REV_ID_MAJOR_TP9343 :
case REV_ID_MAJOR_QCA956X :
2011-06-20 21:26:03 +02: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 ;
2018-07-20 13:58:24 +02:00
return ;
2011-06-20 21:26:03 +02:00
}
2018-07-20 13:58:24 +02:00
prom_enable_uart ( id ) ;
2011-06-20 21:26:03 +02:00
}
2018-07-13 17:51:56 +02:00
void prom_putchar ( char ch )
2011-06-20 21:26:03 +02:00
{
if ( ! _prom_putchar )
prom_putchar_init ( ) ;
_prom_putchar ( ch ) ;
2011-01-04 21:28:14 +01:00
}