mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-11-09 21:22:39 -05:00
Enable UC870x "auto baud" and "fine tune" features based on the SoC capabilities
This makes it easier to add support for the remaining SoCs of the S5L87xx series. Change-Id: I563aa55eed385b5f8e1c52edb866b08176ea116e
This commit is contained in:
parent
1c7fddad5b
commit
39f8101d60
2 changed files with 79 additions and 63 deletions
|
|
@ -33,9 +33,16 @@
|
|||
* UC870x: UART controller for s5l870x
|
||||
*
|
||||
* This UART is similar to the UART described in s5l8700 datasheet,
|
||||
* (see also s3c2416 and s3c6400 datasheets). On s5l8701/2 the UC870x
|
||||
* includes autobauding, and fine tunning for Tx/Rx on s5l8702.
|
||||
* (see also s3c2416 and s3c6400 datasheets). On s5l8701+ the UC870x
|
||||
* includes autobauding, and fine tuning for Tx/Rx speed on s5l8702+.
|
||||
*/
|
||||
#if (CONFIG_CPU == S5L8701)
|
||||
#define UART_CAP_AUTOBAUD
|
||||
#elif (CONFIG_CPU == S5L8702) || (CONFIG_CPU == S5L8720)
|
||||
#define UART_CAP_AUTOBAUD
|
||||
#define UART_CAP_FINETUNE
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Controller registers
|
||||
|
|
@ -53,11 +60,13 @@
|
|||
#define UTXH(ba) (*((REG32_PTR_T)((ba) + 0x20))) /* transmission hold */
|
||||
#define URXH(ba) (*((REG32_PTR_T)((ba) + 0x24))) /* receive buffer */
|
||||
#define UBRDIV(ba) (*((REG32_PTR_T)((ba) + 0x28))) /* baud rate divisor */
|
||||
#if CONFIG_CPU != S5L8700
|
||||
|
||||
#ifdef UART_CAP_AUTOBAUD
|
||||
#define UABRCNT(ba) (*((REG32_PTR_T)((ba) + 0x2c))) /* autobaud counter */
|
||||
#define UABRSTAT(ba) (*((REG32_PTR_T)((ba) + 0x30))) /* autobaud status */
|
||||
#endif
|
||||
#if CONFIG_CPU == S5L8702
|
||||
|
||||
#ifdef UART_CAP_FINETUNE
|
||||
#define UBRCONTX(ba) (*((REG32_PTR_T)((ba) + 0x34))) /* Tx frame config */
|
||||
#define UBRCONRX(ba) (*((REG32_PTR_T)((ba) + 0x38))) /* Rx frame config */
|
||||
#endif
|
||||
|
|
@ -106,19 +115,20 @@
|
|||
#define UCON_CLKSEL_PCLK 0 /* internal */
|
||||
#define UCON_CLKSEL_ECLK 1 /* external */
|
||||
|
||||
#if CONFIG_CPU == S5L8702
|
||||
#ifdef UART_CAP_FINETUNE
|
||||
#define UCON_RX_TOUT_INT_BIT (1 << 11) /* Rx timeout INT enable */
|
||||
#endif
|
||||
|
||||
#define UCON_RX_INT_BIT (1 << 12) /* Rx INT enable */
|
||||
#define UCON_TX_INT_BIT (1 << 13) /* Tx INT enable */
|
||||
#define UCON_ERR_INT_BIT (1 << 14) /* Rx error INT enable */
|
||||
#define UCON_MODEM_INT_BIT (1 << 15) /* modem INT enable (TBC) */
|
||||
#if CONFIG_CPU != S5L8700
|
||||
|
||||
#ifdef UART_CAP_AUTOBAUD
|
||||
#define UCON_AUTOBR_INT_BIT (1 << 16) /* autobauding INT enable */
|
||||
#define UCON_AUTOBR_START_BIT (1 << 17) /* autobauding start/stop */
|
||||
#endif
|
||||
|
||||
#if CONFIG_CPU == S5L8701
|
||||
#if (CONFIG_CPU == S5L8701)
|
||||
/* WTF! ABR bits are swapped on reads, so don't forget to
|
||||
always use this workaround to read the UCON register. */
|
||||
static inline uint32_t _UCON_RD(uint32_t ba)
|
||||
|
|
@ -130,7 +140,8 @@ static inline uint32_t _UCON_RD(uint32_t ba)
|
|||
}
|
||||
#else
|
||||
#define _UCON_RD(ba) UCON(ba)
|
||||
#endif
|
||||
#endif /* (CONFIG_CPU == S5L8701) */
|
||||
#endif /* UART_CAP_AUTOBAUD */
|
||||
|
||||
/* UFCON register */
|
||||
#define UFCON_FIFO_ENABLE_BIT (1 << 0)
|
||||
|
|
@ -159,14 +170,17 @@ static inline uint32_t _UCON_RD(uint32_t ba)
|
|||
#define UTRSTAT_RXBUF_RDY_BIT (1 << 0)
|
||||
#define UTRSTAT_TXBUF_EMPTY_BIT (1 << 1)
|
||||
#define UTRSTAT_TX_EMPTY_BIT (1 << 2)
|
||||
#if CONFIG_CPU == S5L8702
|
||||
|
||||
#ifdef UART_CAP_FINETUNE
|
||||
#define UTRSTAT_RX_TOUT_INT_BIT (1 << 3) /* Rx timeout INT status */
|
||||
#endif
|
||||
|
||||
#define UTRSTAT_RX_INT_BIT (1 << 4)
|
||||
#define UTRSTAT_TX_INT_BIT (1 << 5)
|
||||
#define UTRSTAT_ERR_INT_BIT (1 << 6)
|
||||
#define UTRSTAT_MODEM_INT_BIT (1 << 7) /* modem INT status */
|
||||
#if CONFIG_CPU != S5L8700
|
||||
|
||||
#ifdef UART_CAP_AUTOBAUD
|
||||
#define UTRSTAT_AUTOBR_INT_BIT (1 << 8) /* autobauding INT status */
|
||||
#endif
|
||||
|
||||
|
|
@ -192,7 +206,7 @@ static inline uint32_t _UCON_RD(uint32_t ba)
|
|||
#define UMSTAT_CTS_DELTA_BIT (1 << 4)
|
||||
|
||||
|
||||
#if CONFIG_CPU == S5L8702
|
||||
#ifdef UART_CAP_FINETUNE
|
||||
/* Bitrate:
|
||||
*
|
||||
* Master UCLK clock is divided by 16 to serialize data, UBRDIV is
|
||||
|
|
@ -215,10 +229,10 @@ static inline uint32_t _UCON_RD(uint32_t ba)
|
|||
#define UBRCON_JITTER_INC 1 /* increment 1/16 bit width */
|
||||
#define UBRCON_JITTER_UNUSED 2 /* does nothing */
|
||||
#define UBRCON_JITTER_DEC 3 /* decremet 1/16 bit width */
|
||||
#endif /* CONFIG_CPU == S5L8702 */
|
||||
#endif /* UART_CAP_FINETUNE */
|
||||
|
||||
|
||||
#if CONFIG_CPU != S5L8700
|
||||
#ifdef UART_CAP_AUTOBAUD
|
||||
/* Autobauding:
|
||||
*
|
||||
* Initial UABRSTAT is NOT_INIT, it goes to READY when either of
|
||||
|
|
@ -249,7 +263,7 @@ static inline uint32_t _UCON_RD(uint32_t ba)
|
|||
#define UABRSTAT_STATUS_NOT_INIT 0 /* initial status */
|
||||
#define UABRSTAT_STATUS_READY 1 /* machine is ready */
|
||||
#define UABRSTAT_STATUS_COUNTING 2 /* count in progress */
|
||||
#endif /* CONFIG_CPU != S5L8700 */
|
||||
#endif /* UART_CAP_AUTOBAUD */
|
||||
|
||||
|
||||
/*
|
||||
|
|
@ -281,7 +295,7 @@ struct uartc_port
|
|||
const uint8_t clksel; /* UFCON_CLKSEL_xxx */
|
||||
const uint32_t clkhz; /* UCLK (PCLK or ECLK) frequency */
|
||||
void (* const tx_cb) (int len); /* ISRs */
|
||||
#if CONFIG_CPU != S5L8700
|
||||
#ifdef UART_CAP_AUTOBAUD
|
||||
void (* const rx_cb) (int len, char *data, char *err, uint32_t abr_cnt);
|
||||
#else
|
||||
void (* const rx_cb) (int len, char *data, char *err);
|
||||
|
|
@ -292,7 +306,7 @@ struct uartc_port
|
|||
uint32_t utrstat_int_mask;
|
||||
uint8_t rx_data[UART_FIFO_SIZE]; /* data buffer for rx_cb */
|
||||
uint8_t rx_err[UART_FIFO_SIZE]; /* error buffer for rx_cb */
|
||||
#if CONFIG_CPU != S5L8700
|
||||
#ifdef UART_CAP_AUTOBAUD
|
||||
bool abr_aborted;
|
||||
#endif
|
||||
|
||||
|
|
@ -303,12 +317,11 @@ struct uartc_port
|
|||
uint32_t n_parity_err;
|
||||
uint32_t n_frame_err;
|
||||
uint32_t n_break_detect;
|
||||
#if CONFIG_CPU != S5L8700
|
||||
/* autobauding */
|
||||
#ifdef UART_CAP_AUTOBAUD
|
||||
uint32_t n_abnormal0;
|
||||
uint32_t n_abnormal1;
|
||||
#endif
|
||||
#endif
|
||||
#endif /* UART_CAP_AUTOBAUD */
|
||||
#endif /* UC870X_DEBUG */
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -342,7 +355,7 @@ bool uartc_port_rx_ready(struct uartc_port *port);
|
|||
uint8_t uartc_port_rx_byte(struct uartc_port *port);
|
||||
uint8_t uartc_port_read_byte(struct uartc_port *port);
|
||||
|
||||
#if CONFIG_CPU != S5L8700
|
||||
#ifdef UART_CAP_AUTOBAUD
|
||||
/* Autobauding */
|
||||
void uartc_port_abr_start(struct uartc_port *port);
|
||||
void uartc_port_abr_stop(struct uartc_port *port);
|
||||
|
|
@ -357,7 +370,7 @@ void uartc_port_get_line_info(struct uartc_port *port,
|
|||
int *tx_status, int *rx_status,
|
||||
int *tx_speed, int *rx_speed, char *line_cfg);
|
||||
|
||||
#if CONFIG_CPU != S5L8700
|
||||
#ifdef UART_CAP_AUTOBAUD
|
||||
enum {
|
||||
ABR_INFO_ST_IDLE,
|
||||
ABR_INFO_ST_LAUNCHED,
|
||||
|
|
@ -366,7 +379,7 @@ enum {
|
|||
};
|
||||
|
||||
int uartc_port_get_abr_info(struct uartc_port *port, uint32_t *abr_cnt);
|
||||
#endif
|
||||
#endif /* UART_CAP_AUTOBAUD */
|
||||
#endif /* UC870X_DEBUG */
|
||||
|
||||
#endif /* __UC870X_H__ */
|
||||
|
|
|
|||
|
|
@ -32,26 +32,29 @@
|
|||
* UC870x: UART controller for s5l870x
|
||||
*/
|
||||
|
||||
/* Rx related masks */
|
||||
#if CONFIG_CPU == S5L8700
|
||||
#define UTRSTAT_RX_RELATED_INTS (UTRSTAT_RX_INT_BIT | UTRSTAT_ERR_INT_BIT)
|
||||
#define UCON_RX_RELATED_INTS (UCON_RX_INT_BIT | UCON_ERR_INT_BIT)
|
||||
|
||||
#elif CONFIG_CPU == S5L8701
|
||||
#define UTRSTAT_RX_RELATED_INTS \
|
||||
(UTRSTAT_RX_INT_BIT | UTRSTAT_ERR_INT_BIT | UTRSTAT_AUTOBR_INT_BIT)
|
||||
#define UCON_RX_RELATED_INTS \
|
||||
(UCON_RX_INT_BIT | UCON_ERR_INT_BIT | UCON_AUTOBR_INT_BIT)
|
||||
|
||||
#else /* CONFIG_CPU == S5L8702 */
|
||||
#define UTRSTAT_RX_RELATED_INTS \
|
||||
(UTRSTAT_RX_INT_BIT | UTRSTAT_ERR_INT_BIT | \
|
||||
UTRSTAT_AUTOBR_INT_BIT | UTRSTAT_RX_TOUT_INT_BIT)
|
||||
#define UCON_RX_RELATED_INTS \
|
||||
(UCON_RX_INT_BIT | UCON_ERR_INT_BIT | \
|
||||
UCON_AUTOBR_INT_BIT | UCON_RX_TOUT_INT_BIT)
|
||||
/* Rx related INTs */
|
||||
#ifdef UART_CAP_AUTOBAUD
|
||||
#define AUTOBAUD_UTRSTAT_INT UTRSTAT_AUTOBR_INT_BIT
|
||||
#define AUTOBAUD_UCON_INT UCON_AUTOBR_INT_BIT
|
||||
#else
|
||||
#define AUTOBAUD_UTRSTAT_INT 0
|
||||
#define AUTOBAUD_UCON_INT 0
|
||||
#endif
|
||||
|
||||
#ifdef UART_CAP_FINETUNE
|
||||
#define FINETUNE_UTRSTAT_INT UTRSTAT_RX_TOUT_INT_BIT
|
||||
#define FINETUNE_UCON_INT UCON_RX_TOUT_INT_BIT
|
||||
#else
|
||||
#define FINETUNE_UTRSTAT_INT 0
|
||||
#define FINETUNE_UCON_INT 0
|
||||
#endif
|
||||
|
||||
#define UTRSTAT_RX_INTS (UTRSTAT_RX_INT_BIT | UTRSTAT_ERR_INT_BIT | \
|
||||
AUTOBAUD_UTRSTAT_INT | FINETUNE_UTRSTAT_INT)
|
||||
|
||||
#define UCON_RX_INTS (UCON_RX_INT_BIT | UCON_ERR_INT_BIT | \
|
||||
AUTOBAUD_UCON_INT | FINETUNE_UCON_INT)
|
||||
|
||||
#define UART_PORT_BASE(u,i) (((u)->baddr) + (u)->port_off * (i))
|
||||
|
||||
/* Initialization */
|
||||
|
|
@ -68,7 +71,7 @@ static void uartc_reset_port_id(const struct uartc* uartc, int port_id)
|
|||
UFCON(baddr) = UFCON_RX_FIFO_RST_BIT | UFCON_TX_FIFO_RST_BIT;
|
||||
UTRSTAT(baddr) = ~0; /* clear all interrupts */
|
||||
UBRDIV(baddr) = 0;
|
||||
#if CONFIG_CPU == S5L8702
|
||||
#ifdef UART_CAP_FINETUNE
|
||||
UBRCONTX(baddr) = 0;
|
||||
UBRCONRX(baddr) = 0;
|
||||
#endif
|
||||
|
|
@ -119,14 +122,14 @@ void uartc_port_open(struct uartc_port *port)
|
|||
UCON(baddr) = (UCON_MODE_DISABLED << UCON_RX_MODE_POS)
|
||||
| (UCON_MODE_DISABLED << UCON_TX_MODE_POS)
|
||||
| ((port->clksel & UCON_CLKSEL_MASK) << UCON_CLKSEL_POS)
|
||||
| (port->rx_cb ? UCON_RX_RELATED_INTS|UCON_RX_TOUT_EN_BIT : 0)
|
||||
| (port->rx_cb ? UCON_RX_INTS|UCON_RX_TOUT_EN_BIT : 0)
|
||||
| (port->tx_cb ? UCON_TX_INT_BIT : 0);
|
||||
|
||||
/* init and register port struct */
|
||||
port->baddr = baddr;
|
||||
port->utrstat_int_mask = (port->rx_cb ? UTRSTAT_RX_RELATED_INTS : 0)
|
||||
port->utrstat_int_mask = (port->rx_cb ? UTRSTAT_RX_INTS : 0)
|
||||
| (port->tx_cb ? UTRSTAT_TX_INT_BIT : 0);
|
||||
#if CONFIG_CPU != S5L8700
|
||||
#ifdef UART_CAP_AUTOBAUD
|
||||
port->abr_aborted = 0;
|
||||
#endif
|
||||
uartc->port_l[port->id] = port;
|
||||
|
|
@ -156,7 +159,7 @@ void uartc_port_set_bitrate_raw(struct uartc_port *port, uint32_t brdata)
|
|||
{
|
||||
uint32_t baddr = port->baddr;
|
||||
UBRDIV(baddr) = brdata & 0xff;
|
||||
#if CONFIG_CPU == S5L8702
|
||||
#ifdef UART_CAP_FINETUNE
|
||||
UBRCONRX(baddr) = brdata >> 8;
|
||||
UBRCONTX(baddr) = brdata >> 8;
|
||||
#endif
|
||||
|
|
@ -174,7 +177,7 @@ void uartc_port_set_bitrate(struct uartc_port *port, unsigned int speed)
|
|||
|
||||
uint32_t brdata = brdiv - 1;
|
||||
|
||||
#if CONFIG_CPU == S5L8702
|
||||
#ifdef UART_CAP_FINETUNE
|
||||
/* Fine adjust:
|
||||
*
|
||||
* Along the whole frame, insert/remove "jittered" bauds when needed
|
||||
|
|
@ -210,7 +213,7 @@ void uartc_port_set_bitrate(struct uartc_port *port, unsigned int speed)
|
|||
}
|
||||
|
||||
brdata |= (brcon << 8);
|
||||
#endif /* CONFIG_CPU == S5L8702 */
|
||||
#endif /* UART_CAP_FINETUNE */
|
||||
|
||||
uartc_port_set_rawbr(port, brdata);
|
||||
}
|
||||
|
|
@ -269,7 +272,7 @@ uint8_t uartc_port_read_byte(struct uartc_port *port)
|
|||
return uartc_port_rx_byte(port);
|
||||
}
|
||||
|
||||
#if CONFIG_CPU != S5L8700
|
||||
#ifdef UART_CAP_AUTOBAUD
|
||||
/* Autobauding */
|
||||
static inline int uartc_port_abr_status(struct uartc_port *port)
|
||||
{
|
||||
|
|
@ -300,7 +303,7 @@ void uartc_port_abr_stop(struct uartc_port *port)
|
|||
else
|
||||
UCON(port->baddr) = _UCON_RD(port->baddr) & ~UCON_AUTOBR_START_BIT;
|
||||
}
|
||||
#endif /* CONFIG_CPU != S5L8700 */
|
||||
#endif /* UART_CAP_AUTOBAUD */
|
||||
|
||||
/* ISR */
|
||||
void ICODE_ATTR uartc_callback(const struct uartc* uartc, int port_id)
|
||||
|
|
@ -315,10 +318,10 @@ void ICODE_ATTR uartc_callback(const struct uartc* uartc, int port_id)
|
|||
this ISR will be processed in the next call */
|
||||
UTRSTAT(baddr) = ints;
|
||||
|
||||
if (ints & UTRSTAT_RX_RELATED_INTS)
|
||||
if (ints & UTRSTAT_RX_INTS)
|
||||
{
|
||||
int len = 0;
|
||||
#if CONFIG_CPU != S5L8700
|
||||
#ifdef UART_CAP_AUTOBAUD
|
||||
uint32_t abr_cnt = 0;
|
||||
|
||||
if (ints & UTRSTAT_AUTOBR_INT_BIT)
|
||||
|
|
@ -335,8 +338,8 @@ void ICODE_ATTR uartc_callback(const struct uartc* uartc, int port_id)
|
|||
abr_cnt = UABRCNT(baddr);
|
||||
}
|
||||
|
||||
if (ints & (UTRSTAT_RX_RELATED_INTS ^ UTRSTAT_AUTOBR_INT_BIT))
|
||||
#endif /* CONFIG_CPU != S5L8700 */
|
||||
if (ints & (UTRSTAT_RX_INTS ^ UTRSTAT_AUTOBR_INT_BIT))
|
||||
#endif /* UART_CAP_AUTOBAUD */
|
||||
{
|
||||
/* get FIFO count */
|
||||
uint32_t ufstat = UFSTAT(baddr);
|
||||
|
|
@ -355,11 +358,11 @@ void ICODE_ATTR uartc_callback(const struct uartc* uartc, int port_id)
|
|||
* When overrun, it is marked on the first error:
|
||||
* overrun = len ? (rx_err[0] & UERSTAT_OVERRUN_BIT) : 0
|
||||
*/
|
||||
#if CONFIG_CPU == S5L8700
|
||||
port->rx_cb(len, port->rx_data, port->rx_err);
|
||||
#else
|
||||
#ifdef UART_CAP_AUTOBAUD
|
||||
/* 'abr_cnt' is zero when no ABR interrupt exists */
|
||||
port->rx_cb(len, port->rx_data, port->rx_err, abr_cnt);
|
||||
#else
|
||||
port->rx_cb(len, port->rx_data, port->rx_err);
|
||||
#endif
|
||||
|
||||
#ifdef UC870X_DEBUG
|
||||
|
|
@ -394,7 +397,7 @@ void ICODE_ATTR uartc_callback(const struct uartc* uartc, int port_id)
|
|||
/*#define LOGF_ENABLE*/
|
||||
#include "logf.h"
|
||||
|
||||
#if CONFIG_CPU == S5L8702
|
||||
#ifdef UART_CAP_FINETUNE
|
||||
static int get_bitrate(int uclk, int brdiv, int brcon, int frame_len)
|
||||
{
|
||||
logf("get_bitrate(%d, %d, 0x%08x, %d)", uclk, brdiv, brcon, frame_len);
|
||||
|
|
@ -426,7 +429,7 @@ static int get_bitrate(int uclk, int brdiv, int brcon, int frame_len)
|
|||
|
||||
return avg_speed;
|
||||
}
|
||||
#endif /* CONFIG_CPU == S5L8702 */
|
||||
#endif /* UART_CAP_FINETUNE */
|
||||
|
||||
void uartc_port_get_line_info(struct uartc_port *port,
|
||||
int *tx_status, int *rx_status,
|
||||
|
|
@ -446,7 +449,7 @@ void uartc_port_get_line_info(struct uartc_port *port,
|
|||
int parity = (ulcon >> ULCON_PARITY_POS) & ULCON_PARITY_MASK;
|
||||
|
||||
uint32_t brdiv = UBRDIV(baddr) + 1;
|
||||
#if CONFIG_CPU == S5L8702
|
||||
#ifdef UART_CAP_FINETUNE
|
||||
int frame_len = 1 + n_data + (parity ? 1 : 0) + n_stop;
|
||||
if (tx_speed)
|
||||
*tx_speed = get_bitrate(port->clkhz, brdiv, UBRCONTX(baddr), frame_len);
|
||||
|
|
@ -471,7 +474,7 @@ void uartc_port_get_line_info(struct uartc_port *port,
|
|||
}
|
||||
}
|
||||
|
||||
#if CONFIG_CPU != S5L8700
|
||||
#ifdef UART_CAP_AUTOBAUD
|
||||
/* Autobauding */
|
||||
int uartc_port_get_abr_info(struct uartc_port *port, uint32_t *abr_cnt)
|
||||
{
|
||||
|
|
@ -502,5 +505,5 @@ int uartc_port_get_abr_info(struct uartc_port *port, uint32_t *abr_cnt)
|
|||
|
||||
return status;
|
||||
}
|
||||
#endif /* CONFIG_CPU != S5L8700 */
|
||||
#endif /* UART_CAP_AUTOBAUD */
|
||||
#endif /* UC870X_DEBUG */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue