u-boot/u-boot/cpu/mips/ar7240/ar933x_serial.c

194 lines
4.0 KiB
C

/*
* Atheros AR933x UART driver
*
* Copyright (C) 2014 Mantas Pucka <mantas@8devices.com>
* Copyright (C) 2014 Piotr Dymacz <piotr@dymacz.pl>
* Copyright (C) 2008-2010 Atheros Communications Inc.
*
* Based on Linux/drivers/tty/serial/ar933x_uart.c
*
* SPDX-License-Identifier:GPL-2.0
*/
#include <config.h>
#include <common.h>
#include <asm/addrspace.h>
#include <asm/ar933x.h>
DECLARE_GLOBAL_DATA_PTR;
#define AR933X_UART_MAX_SCALE 0xff
#define AR933X_UART_MAX_STEP 0x3333
#define abs(x) ({ \
long ret; \
if (sizeof(x) == sizeof(long)) { \
long __x = (x); \
ret = (__x < 0) ? -__x : __x; \
} else { \
int __x = (x); \
ret = (__x < 0) ? -__x : __x; \
} \
ret; \
})
/*
* baudrate = (clk / (scale + 1)) * (step * (1 / 2^17))
*/
static unsigned long ar933x_uart_get_baud(unsigned int clk,
unsigned int scale,
unsigned int step)
{
u64 t;
u32 div;
div = (2 << 16) * (scale + 1);
t = clk;
t *= step;
t += (div / 2);
t = t / div;
return t;
}
static void ar933x_serial_get_scale_step(unsigned int clk,
unsigned int baud,
unsigned int *scale,
unsigned int *step)
{
unsigned int tscale;
long min_diff;
*scale = 0;
*step = 0;
min_diff = baud;
for (tscale = 0; tscale < AR933X_UART_MAX_SCALE; tscale++) {
u64 tstep;
int diff;
tstep = baud * (tscale + 1);
tstep *= (2 << 16);
tstep = tstep / clk;
if (tstep > AR933X_UART_MAX_STEP)
break;
diff = abs(ar933x_uart_get_baud(clk, tscale, tstep) - baud);
if (diff < min_diff) {
min_diff = diff;
*scale = tscale;
*step = tstep;
}
}
return;
}
void serial_setbrg(void)
{
u32 uart_clock;
u32 uart_scale;
u32 uart_step;
if (ar933x_40MHz_xtal() == 1)
uart_clock = 40 * 1000000;
else
uart_clock = 25 * 1000000;
ar933x_serial_get_scale_step(uart_clock, gd->baudrate, &uart_scale, &uart_step);
uart_clock = (uart_scale << UART_CLOCK_SCALE_SHIFT);
uart_clock |= (uart_step << UART_CLOCK_STEP_SHIFT);
ar933x_reg_write(UART_CLOCK_REG, uart_clock);
}
int serial_init(void)
{
u32 uart_cs;
/*
* Set GPIO10 (UART_SO) as output and enable UART and RTS/CTS,
* BIT(15) in GPIO_FUNCTION_1 register must be written with 1
*/
ar933x_reg_read_set(GPIO_OE_REG, GPIO10);
ar933x_reg_read_set(GPIO_FUNCTION_1_REG,
(1 << GPIO_FUNCTION_1_UART_EN_SHIFT) |
(1 << GPIO_FUNCTION_1_UART_RTS_CTS_EN_SHIFT) |
(1 << 15));
/*
* UART controller configuration:
* - no DMA
* - no interrupt
* - DCE mode
* - no flow control
* - set RX ready oride
* - set TX ready oride
*/
uart_cs = (0 << UART_CS_DMA_EN_SHIFT) |
(0 << UART_CS_HOST_INT_EN_SHIFT) |
(1 << UART_CS_RX_READY_ORIDE_SHIFT) |
(1 << UART_CS_TX_READY_ORIDE_SHIFT) |
(UART_CS_IFACE_MODE_DCE_VAL << UART_CS_IFACE_MODE_SHIFT) |
(UART_CS_FLOW_MODE_NO_VAL << UART_CS_FLOW_MODE_SHIFT);
ar933x_reg_write(UART_CS_REG, uart_cs);
serial_setbrg();
return 0;
}
void serial_putc(const char c)
{
u32 uart_data;
if(c == '\n')
serial_putc('\r');
/* Wait for FIFO */
do{
uart_data = ar933x_reg_read(UART_DATA_REG);
} while(((uart_data & UART_TX_CSR_MASK) >> UART_TX_CSR_SHIFT) == 0);
/* Put data in buffer and set CSR bit */
uart_data = (u32)c | (1 << UART_TX_CSR_SHIFT);
ar933x_reg_write(UART_DATA_REG, uart_data);
}
int serial_getc(void)
{
u32 uart_data;
while(!serial_tstc())
;
uart_data = ar933x_reg_read(UART_DATA_REG);
ar933x_reg_write(UART_DATA_REG, (1 << UART_RX_CSR_SHIFT));
return (uart_data & UART_TX_RX_DATA_MASK);
}
int serial_tstc(void)
{
u32 uart_data = ar933x_reg_read(UART_DATA_REG);
if((uart_data & UART_RX_CSR_MASK) >> UART_RX_CSR_SHIFT){
return 1;
}
return 0;
}
void serial_puts(const char *s)
{
while(*s){
serial_putc(*s++);
}
}