blob: 61b549b705c5ea90293f5952bd6208fc0d4ae7e3 [file] [log] [blame]
/*
* Copyright (c) 2014 Qualcomm Atheros, Inc.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <asm/addrspace.h>
#include <asm/types.h>
#include <config.h>
#include <hornet_soc.h>
#define uart_reg_read(x) ar7240_reg_rd( (AR7240_UART_BASE+x) )
#define uart_reg_write(x, y) ar7240_reg_wr( (AR7240_UART_BASE+x), y)
static int
AthrUartGet(char *__ch_data)
{
u32 rdata;
rdata = uart_reg_read(UARTDATA_ADDRESS);
if (UARTDATA_UARTRXCSR_GET(rdata)) {
*__ch_data = (char)UARTDATA_UARTTXRXDATA_GET(rdata);
rdata = UARTDATA_UARTRXCSR_SET(1);
uart_reg_write(UARTDATA_ADDRESS, rdata);
return 1;
}
else {
return 0;
}
}
static void
AthrUartPut(char __ch_data)
{
u32 rdata;
do {
rdata = uart_reg_read(UARTDATA_ADDRESS);
} while (UARTDATA_UARTTXCSR_GET(rdata) == 0);
rdata = UARTDATA_UARTTXRXDATA_SET((u32)__ch_data);
rdata |= UARTDATA_UARTTXCSR_SET(1);
uart_reg_write(UARTDATA_ADDRESS, rdata);
}
void
ar7240_sys_frequency(u32 *cpu_freq, u32 *ddr_freq, u32 *ahb_freq)
{
#ifdef CONFIG_HORNET_EMU
#ifdef CONFIG_HORNET_EMU_HARDI_WLAN
*cpu_freq = 48 * 1000000;
*ddr_freq = 48 * 1000000;
*ahb_freq = 24 * 1000000;
#else
*cpu_freq = 80 * 1000000;
*ddr_freq = 80 * 1000000;
*ahb_freq = 40 * 1000000;
#endif
#else
u32 ref_clock_rate, pll_freq;
u32 pllreg, clockreg;
u32 nint, refdiv, outdiv;
u32 cpu_div, ahb_div, ddr_div;
if ( ar7240_reg_rd(HORNET_BOOTSTRAP_STATUS) & HORNET_BOOTSTRAP_SEL_25M_40M_MASK )
ref_clock_rate = 40 * 1000000;
else
ref_clock_rate = 25 * 1000000;
pllreg = ar7240_reg_rd(AR7240_CPU_PLL_CONFIG);
clockreg = ar7240_reg_rd(AR7240_CPU_CLOCK_CONTROL);
if (clockreg & HORNET_CLOCK_CONTROL_BYPASS_MASK) {
/* Bypass PLL */
pll_freq = ref_clock_rate;
cpu_div = ahb_div = ddr_div = 1;
}
else {
nint = (pllreg & HORNET_PLL_CONFIG_NINT_MASK) >> HORNET_PLL_CONFIG_NINT_SHIFT;
refdiv = (pllreg & HORNET_PLL_CONFIG_REFDIV_MASK) >> HORNET_PLL_CONFIG_REFDIV_SHIFT;
outdiv = (pllreg & HORNET_PLL_CONFIG_OUTDIV_MASK) >> HORNET_PLL_CONFIG_OUTDIV_SHIFT;
pll_freq = (ref_clock_rate / refdiv) * nint;
if (outdiv == 1)
pll_freq /= 2;
else if (outdiv == 2)
pll_freq /= 4;
else if (outdiv == 3)
pll_freq /= 8;
else if (outdiv == 4)
pll_freq /= 16;
else if (outdiv == 5)
pll_freq /= 32;
else if (outdiv == 6)
pll_freq /= 64;
else if (outdiv == 7)
pll_freq /= 128;
else /* outdiv == 0 --> illegal value */
pll_freq /= 2;
cpu_div = (clockreg & HORNET_CLOCK_CONTROL_CPU_POST_DIV_MASK) >> HORNET_CLOCK_CONTROL_CPU_POST_DIV_SHIFT;
ddr_div = (clockreg & HORNET_CLOCK_CONTROL_DDR_POST_DIV_MASK) >> HORNET_CLOCK_CONTROL_DDR_POST_DIV_SFIFT;
ahb_div = (clockreg & HORNET_CLOCK_CONTROL_AHB_POST_DIV_MASK) >> HORNET_CLOCK_CONTROL_AHB_POST_DIV_SFIFT;
/*
* b00 : div by 1, b01 : div by 2, b10 : div by 3, b11 : div by 4
*/
cpu_div++;
ddr_div++;
ahb_div++;
}
*cpu_freq = pll_freq / cpu_div;
*ddr_freq = pll_freq / ddr_div;
*ahb_freq = pll_freq / ahb_div;
#endif
}
int serial_init(void)
{
u32 rdata;
u32 baudRateDivisor, clock_step;
u32 fcEnable = 0;
u32 ahb_freq, ddr_freq, cpu_freq;
ar7240_sys_frequency(&cpu_freq, &ddr_freq, &ahb_freq);
/* GPIO Configuration */
ar7240_reg_wr(AR7240_GPIO_OE, 0xcff);
rdata = ar7240_reg_rd(AR7240_GPIO_OUT);
rdata |= 0x400; // GPIO 10 (UART_SOUT) must output 1
ar7240_reg_wr(AR7240_GPIO_OUT, rdata);
rdata = ar7240_reg_rd(AR7240_GPIO_FUNC);
/* GPIO_FUN, bit1/UART_EN, bit2/UART_RTS_CTS_EN, bit15(disable_s26_uart) */
rdata |= (0x3<<1)|(0x1<<15);
ar7240_reg_wr(AR7240_GPIO_FUNC, rdata);
/* Get reference clock rate, then set baud rate to 115200 */
#ifndef CONFIG_HORNET_EMU
rdata = ar7240_reg_rd(HORNET_BOOTSTRAP_STATUS);
rdata &= HORNET_BOOTSTRAP_SEL_25M_40M_MASK;
if (rdata)
baudRateDivisor = ( 40000000 / (16*115200) ) - 1; // 40 MHz clock is taken as UART clock
else
baudRateDivisor = ( 25000000 / (16*115200) ) - 1; // 25 MHz clock is taken as UART clock
#else
baudRateDivisor = ( ahb_freq / (16*115200) ) - 1; // 40 MHz clock is taken as UART clock
#endif
clock_step = 8192;
rdata = UARTCLOCK_UARTCLOCKSCALE_SET(baudRateDivisor) | UARTCLOCK_UARTCLOCKSTEP_SET(clock_step);
uart_reg_write(UARTCLOCK_ADDRESS, rdata);
/* Config Uart Controller */
#if 1 /* No interrupt */
rdata = UARTCS_UARTDMAEN_SET(0) | UARTCS_UARTHOSTINTEN_SET(0) | UARTCS_UARTHOSTINT_SET(0)
| UARTCS_UARTSERIATXREADY_SET(0) | UARTCS_UARTTXREADYORIDE_SET(~fcEnable)
| UARTCS_UARTRXREADYORIDE_SET(~fcEnable) | UARTCS_UARTHOSTINTEN_SET(0);
#else
rdata = UARTCS_UARTDMAEN_SET(0) | UARTCS_UARTHOSTINTEN_SET(0) | UARTCS_UARTHOSTINT_SET(0)
| UARTCS_UARTSERIATXREADY_SET(0) | UARTCS_UARTTXREADYORIDE_SET(~fcEnable)
| UARTCS_UARTRXREADYORIDE_SET(~fcEnable) | UARTCS_UARTHOSTINTEN_SET(1);
#endif
/* is_dte == 1 */
rdata = rdata | UARTCS_UARTINTERFACEMODE_SET(2);
if (fcEnable) {
rdata = rdata | UARTCS_UARTFLOWCONTROLMODE_SET(2);
}
/* invert_fc ==0 (Inverted Flow Control) */
//rdata = rdata | UARTCS_UARTFLOWCONTROLMODE_SET(3);
/* parityEnable == 0 */
//rdata = rdata | UARTCS_UARTPARITYMODE_SET(2); -->Parity Odd
//rdata = rdata | UARTCS_UARTPARITYMODE_SET(3); -->Parity Even
uart_reg_write(UARTCS_ADDRESS, rdata);
return 0;
}
int serial_tstc (void)
{
return (UARTDATA_UARTRXCSR_GET(uart_reg_read(UARTDATA_ADDRESS)));
}
u8 serial_getc(void)
{
char ch_data;
while (!AthrUartGet(&ch_data)) ;
return (u8)ch_data;
}
void serial_putc(u8 byte)
{
if (byte == '\n') AthrUartPut('\r');
AthrUartPut((char)byte);
}
void serial_setbrg (void)
{
}
void serial_puts (const char *s)
{
while (*s)
{
serial_putc (*s++);
}
}