The driver for on-chip UART used on Panasonic UniPhier platform. Signed-off-by: Masahiro Yamada <yamada.m@jp.panasonic.com>master
parent
845034e6b2
commit
7f368553fc
@ -0,0 +1,204 @@ |
||||
/*
|
||||
* Copyright (C) 2012-2014 Panasonic Corporation |
||||
* Author: Masahiro Yamada <yamada.m@jp.panasonic.com> |
||||
* |
||||
* Based on serial_ns16550.c |
||||
* (C) Copyright 2000 |
||||
* Rob Taylor, Flying Pig Systems. robt@flyingpig.com. |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <serial.h> |
||||
|
||||
#define UART_REG(x) \ |
||||
u8 x; \
|
||||
u8 postpad_##x[3]; |
||||
|
||||
/*
|
||||
* Note: Register map is slightly different from that of 16550. |
||||
*/ |
||||
struct uniphier_serial { |
||||
UART_REG(rbr); /* 0x00 */ |
||||
UART_REG(ier); /* 0x04 */ |
||||
UART_REG(iir); /* 0x08 */ |
||||
UART_REG(fcr); /* 0x0c */ |
||||
u8 mcr; /* 0x10 */ |
||||
u8 lcr; |
||||
u16 __postpad; |
||||
UART_REG(lsr); /* 0x14 */ |
||||
UART_REG(msr); /* 0x18 */ |
||||
u32 __none1; |
||||
u32 __none2; |
||||
u16 dlr; |
||||
u16 __postpad2; |
||||
}; |
||||
|
||||
#define thr rbr |
||||
|
||||
/*
|
||||
* These are the definitions for the Line Control Register |
||||
*/ |
||||
#define UART_LCR_WLS_8 0x03 /* 8 bit character length */ |
||||
|
||||
/*
|
||||
* These are the definitions for the Line Status Register |
||||
*/ |
||||
#define UART_LSR_DR 0x01 /* Data ready */ |
||||
#define UART_LSR_THRE 0x20 /* Xmit holding register empty */ |
||||
|
||||
DECLARE_GLOBAL_DATA_PTR; |
||||
|
||||
static void uniphier_serial_init(struct uniphier_serial *port) |
||||
{ |
||||
const unsigned int mode_x_div = 16; |
||||
unsigned int divisor; |
||||
|
||||
writeb(UART_LCR_WLS_8, &port->lcr); |
||||
|
||||
divisor = DIV_ROUND_CLOSEST(CONFIG_SYS_UNIPHIER_UART_CLK, |
||||
mode_x_div * gd->baudrate); |
||||
|
||||
writew(divisor, &port->dlr); |
||||
} |
||||
|
||||
static void uniphier_serial_setbrg(struct uniphier_serial *port) |
||||
{ |
||||
uniphier_serial_init(port); |
||||
} |
||||
|
||||
static int uniphier_serial_tstc(struct uniphier_serial *port) |
||||
{ |
||||
return (readb(&port->lsr) & UART_LSR_DR) != 0; |
||||
} |
||||
|
||||
static int uniphier_serial_getc(struct uniphier_serial *port) |
||||
{ |
||||
while (!uniphier_serial_tstc(port)) |
||||
; |
||||
|
||||
return readb(&port->rbr); |
||||
} |
||||
|
||||
static void uniphier_serial_putc(struct uniphier_serial *port, const char c) |
||||
{ |
||||
if (c == '\n') |
||||
uniphier_serial_putc(port, '\r'); |
||||
|
||||
while (!(readb(&port->lsr) & UART_LSR_THRE)) |
||||
; |
||||
|
||||
writeb(c, &port->thr); |
||||
} |
||||
|
||||
static struct uniphier_serial *serial_ports[4] = { |
||||
#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE0 |
||||
(struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE0, |
||||
#else |
||||
NULL, |
||||
#endif |
||||
#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE1 |
||||
(struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE1, |
||||
#else |
||||
NULL, |
||||
#endif |
||||
#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE2 |
||||
(struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE2, |
||||
#else |
||||
NULL, |
||||
#endif |
||||
#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE3 |
||||
(struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE3, |
||||
#else |
||||
NULL, |
||||
#endif |
||||
}; |
||||
|
||||
/* Multi serial device functions */ |
||||
#define DECLARE_ESERIAL_FUNCTIONS(port) \ |
||||
static int eserial##port##_init(void) \
|
||||
{ \
|
||||
uniphier_serial_init(serial_ports[port]); \
|
||||
return 0 ; \
|
||||
} \
|
||||
static void eserial##port##_setbrg(void) \
|
||||
{ \
|
||||
uniphier_serial_setbrg(serial_ports[port]); \
|
||||
} \
|
||||
static int eserial##port##_getc(void) \
|
||||
{ \
|
||||
return uniphier_serial_getc(serial_ports[port]); \
|
||||
} \
|
||||
static int eserial##port##_tstc(void) \
|
||||
{ \
|
||||
return uniphier_serial_tstc(serial_ports[port]); \
|
||||
} \
|
||||
static void eserial##port##_putc(const char c) \
|
||||
{ \
|
||||
uniphier_serial_putc(serial_ports[port], c); \
|
||||
} |
||||
|
||||
/* Serial device descriptor */ |
||||
#define INIT_ESERIAL_STRUCTURE(port, __name) { \ |
||||
.name = __name, \
|
||||
.start = eserial##port##_init, \
|
||||
.stop = NULL, \
|
||||
.setbrg = eserial##port##_setbrg, \
|
||||
.getc = eserial##port##_getc, \
|
||||
.tstc = eserial##port##_tstc, \
|
||||
.putc = eserial##port##_putc, \
|
||||
.puts = default_serial_puts, \
|
||||
} |
||||
|
||||
#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0) |
||||
DECLARE_ESERIAL_FUNCTIONS(0); |
||||
struct serial_device uniphier_serial0_device = |
||||
INIT_ESERIAL_STRUCTURE(0, "ttyS0"); |
||||
#endif |
||||
#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1) |
||||
DECLARE_ESERIAL_FUNCTIONS(1); |
||||
struct serial_device uniphier_serial1_device = |
||||
INIT_ESERIAL_STRUCTURE(1, "ttyS1"); |
||||
#endif |
||||
#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2) |
||||
DECLARE_ESERIAL_FUNCTIONS(2); |
||||
struct serial_device uniphier_serial2_device = |
||||
INIT_ESERIAL_STRUCTURE(2, "ttyS2"); |
||||
#endif |
||||
#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3) |
||||
DECLARE_ESERIAL_FUNCTIONS(3); |
||||
struct serial_device uniphier_serial3_device = |
||||
INIT_ESERIAL_STRUCTURE(3, "ttyS3"); |
||||
#endif |
||||
|
||||
__weak struct serial_device *default_serial_console(void) |
||||
{ |
||||
#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0) |
||||
return &uniphier_serial0_device; |
||||
#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1) |
||||
return &uniphier_serial1_device; |
||||
#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2) |
||||
return &uniphier_serial2_device; |
||||
#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3) |
||||
return &uniphier_serial3_device; |
||||
#else |
||||
#error "No uniphier serial ports configured." |
||||
#endif |
||||
} |
||||
|
||||
void uniphier_serial_initialize(void) |
||||
{ |
||||
#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0) |
||||
serial_register(&uniphier_serial0_device); |
||||
#endif |
||||
#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1) |
||||
serial_register(&uniphier_serial1_device); |
||||
#endif |
||||
#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2) |
||||
serial_register(&uniphier_serial2_device); |
||||
#endif |
||||
#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3) |
||||
serial_register(&uniphier_serial3_device); |
||||
#endif |
||||
} |
Loading…
Reference in new issue