blob: 3e546b766b6a1842b3c972257b27ffa2fc1eca7c [file] [log] [blame]
/*
* Copyright (c) 2016 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <asm/addrspace.h>
#include <asm/types.h>
#include <config.h>
#include <atheros.h>
#include <serial.h>
int qca_serial_init(void)
{
//#if !defined(CONFIG_ATH_EMULATION)
uint32_t div, val;
div = ath_uart_freq() / (16 * CONFIG_BAUDRATE);
#if defined(CONFIG_SCO_SLAVE_CONNECTED)
val = ath_reg_rd(GPIO_OE_ADDRESS) & (~0xcbf410u);
#elif defined(CONFIG_MACH_QCA956x)
val = ath_reg_rd(GPIO_OE_ADDRESS) & 0xbbfdf6;
#else
val = ath_reg_rd(GPIO_OE_ADDRESS) & (~0xcffc10u);
#endif
#if defined(CONFIG_ATH_SPI_NAND_CS_GPIO)
val |= 1 << CONFIG_ATH_SPI_NAND_CS_GPIO;
#endif
#if defined(CONFIG_ATH_SPI_CS1_GPIO)
val |= 1 << CONFIG_ATH_SPI_CS1_GPIO;
#endif
ath_reg_wr(GPIO_OE_ADDRESS, val);
#ifdef CONFIG_MACH_QCA956x
#if defined(UART_RX20_TX22)
val = (ath_reg_rd(GPIO_OE_ADDRESS) & (~0x400000));
ath_reg_wr(GPIO_OE_ADDRESS, val);
ath_reg_rmw_clear(GPIO_OUT_FUNCTION5_ADDRESS,
GPIO_OUT_FUNCTION5_ENABLE_GPIO_22_MASK);
ath_reg_rmw_set(GPIO_OUT_FUNCTION5_ADDRESS,
GPIO_OUT_FUNCTION5_ENABLE_GPIO_22_SET(0x16));
ath_reg_rmw_clear(GPIO_IN_ENABLE0_ADDRESS,
GPIO_IN_ENABLE0_UART_SIN_MASK);
ath_reg_rmw_set(GPIO_IN_ENABLE0_ADDRESS,
GPIO_IN_ENABLE0_UART_SIN_SET(0x14));
#elif defined(UART_RX18_TX22)
val = (ath_reg_rd(GPIO_OE_ADDRESS) & (~0x400000)) | 0x40000;
ath_reg_wr(GPIO_OE_ADDRESS, val);
ath_reg_rmw_clear(GPIO_OUT_FUNCTION5_ADDRESS,
GPIO_OUT_FUNCTION5_ENABLE_GPIO_22_MASK);
ath_reg_rmw_set(GPIO_OUT_FUNCTION5_ADDRESS,
GPIO_OUT_FUNCTION5_ENABLE_GPIO_22_SET(0x16));
ath_reg_rmw_clear(GPIO_IN_ENABLE0_ADDRESS,
GPIO_IN_ENABLE0_UART_SIN_MASK);
ath_reg_rmw_set(GPIO_IN_ENABLE0_ADDRESS,
GPIO_IN_ENABLE0_UART_SIN_SET(0x12));
#elif defined(UART_RX18_TX20)
val = (ath_reg_rd(GPIO_OE_ADDRESS) & (~0x100000)) | 0x40000;
ath_reg_wr(GPIO_OE_ADDRESS, val);
val = ath_reg_rd(GPIO_OUT_ADDRESS) | 0xeffff6;
ath_reg_wr(GPIO_OUT_ADDRESS, val);
ath_reg_rmw_clear(GPIO_OUT_FUNCTION5_ADDRESS,
GPIO_OUT_FUNCTION5_ENABLE_GPIO_20_MASK);
ath_reg_rmw_set(GPIO_OUT_FUNCTION5_ADDRESS,
GPIO_OUT_FUNCTION5_ENABLE_GPIO_20_SET(0x16));
ath_reg_rmw_clear(GPIO_IN_ENABLE0_ADDRESS,
GPIO_IN_ENABLE0_UART_SIN_MASK);
ath_reg_rmw_set(GPIO_IN_ENABLE0_ADDRESS,
GPIO_IN_ENABLE0_UART_SIN_SET(0x12));
#elif defined(UART_RX24_TX20)
// Turn off LED before XLNA swap to GPO
val = ath_reg_rd(GPIO_OUT_ADDRESS) | 0xaffff6;
ath_reg_wr(GPIO_OUT_ADDRESS, val);
//Switch GPI and GPO and XPA, XLNA
ath_reg_wr(GPIO_FUNCTION_ADDRESS, 0x8000);
val = (ath_reg_rd(GPIO_OE_ADDRESS) & (~0x100000)) | 0x1000000;
ath_reg_wr(GPIO_OE_ADDRESS, val);
ath_reg_rmw_set(GPIO_OUT_FUNCTION5_ADDRESS,
GPIO_OUT_FUNCTION5_ENABLE_GPIO_20_SET(0x16));
ath_reg_rmw_clear(GPIO_IN_ENABLE0_ADDRESS,
GPIO_IN_ENABLE0_UART_SIN_SET(0xff));
ath_reg_rmw_set(GPIO_IN_ENABLE0_ADDRESS,
GPIO_IN_ENABLE0_UART_SIN_SET(0x18));
#elif defined(TEST_BOARD_UART)
//Switch GPI and GPO and XPA1, ANTC
ath_reg_wr(GPIO_FUNCTION_ADDRESS, 0xc000);
val = ath_reg_rd(GPIO_OE_ADDRESS) & (~0x2000);
ath_reg_wr(GPIO_OE_ADDRESS, val);
ath_reg_rmw_clear(GPIO_OUT_FUNCTION3_ADDRESS,
GPIO_OUT_FUNCTION3_ENABLE_GPIO_13_MASK);
ath_reg_rmw_set(GPIO_OUT_FUNCTION3_ADDRESS,
GPIO_OUT_FUNCTION3_ENABLE_GPIO_13_SET(0x16));
ath_reg_rmw_clear(GPIO_IN_ENABLE0_ADDRESS,
GPIO_IN_ENABLE0_UART_SIN_SET(0xff));
ath_reg_rmw_set(GPIO_IN_ENABLE0_ADDRESS,
GPIO_IN_ENABLE0_UART_SIN_SET(0x17));
#else
val = (ath_reg_rd(GPIO_OE_ADDRESS) & (~0x100000)) | 0x80000;
ath_reg_wr(GPIO_OE_ADDRESS, val);
ath_reg_rmw_set(GPIO_OUT_FUNCTION5_ADDRESS,
GPIO_OUT_FUNCTION5_ENABLE_GPIO_20_SET(0x16));
ath_reg_rmw_clear(GPIO_IN_ENABLE0_ADDRESS,
GPIO_IN_ENABLE0_UART_SIN_SET(0xff));
ath_reg_rmw_set(GPIO_IN_ENABLE0_ADDRESS,
GPIO_IN_ENABLE0_UART_SIN_SET(0x13));
#endif
val = ath_reg_rd(GPIO_OUT_ADDRESS) | 0xaffff6;
ath_reg_wr(GPIO_OUT_ADDRESS, val);
val = ath_reg_rd(GPIO_SPARE_ADDRESS);
ath_reg_wr(GPIO_SPARE_ADDRESS, (val | 0x8402));
#else
ath_reg_rmw_set(GPIO_OUT_FUNCTION2_ADDRESS,
GPIO_OUT_FUNCTION2_ENABLE_GPIO_10_SET(0x16));
ath_reg_rmw_clear(GPIO_IN_ENABLE0_ADDRESS,
GPIO_IN_ENABLE0_UART_SIN_SET(0xff));
ath_reg_rmw_set(GPIO_IN_ENABLE0_ADDRESS,
GPIO_IN_ENABLE0_UART_SIN_SET(0x9));
val = ath_reg_rd(GPIO_OUT_ADDRESS) | 0xcffc10u;
ath_reg_wr(GPIO_OUT_ADDRESS, val);
val = ath_reg_rd(GPIO_SPARE_ADDRESS);
ath_reg_wr(GPIO_SPARE_ADDRESS, (val | 0x8402));
ath_reg_wr(GPIO_OUT_ADDRESS, 0x2f);
#endif
/*
* set DIAB bit
*/
ath_uart_wr(OFS_LINE_CONTROL, 0x80);
/* set divisor */
ath_uart_wr(OFS_DIVISOR_LSB, (div & 0xff));
ath_uart_wr(OFS_DIVISOR_MSB, ((div >> 8) & 0xff));
/* clear DIAB bit*/
ath_uart_wr(OFS_LINE_CONTROL, 0x00);
/* set data format */
ath_uart_wr(OFS_DATA_FORMAT, 0x3);
ath_uart_wr(OFS_INTR_ENABLE, 0);
//#endif
return 0;
}
int qca_serial_tstc (void)
{
return(ath_uart_rd(OFS_LINE_STATUS) & 0x1);
}
u8 qca_serial_getc(void)
{
while(!serial_tstc());
return ath_uart_rd(OFS_RCV_BUFFER);
}
void qca_serial_putc(u8 byte)
{
if (byte == '\n') serial_putc ('\r');
while (((ath_uart_rd(OFS_LINE_STATUS)) & 0x20) == 0x0);
ath_uart_wr(OFS_SEND_BUFFER, byte);
}
void qca_serial_setbrg (void)
{
}
void qca_serial_puts (const char *s)
{
while (*s)
{
serial_putc (*s++);
}
}
static struct serial_device qca956x_serial_drv = {
.name = "qca956x_serial",
.start = qca_serial_init,
.stop = NULL,
.setbrg = NULL,
.putc = qca_serial_putc,
.puts = qca_serial_puts,
.getc = qca_serial_getc,
.tstc = qca_serial_tstc,
};
void qca_serial_initialize(void)
{
serial_register(&qca956x_serial_drv);
}
__weak struct serial_device *default_serial_console(void)
{
return &qca956x_serial_drv;
}