summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVencislav Atanasov <user890104@freemyipod.org>2024-11-20 23:55:47 +0200
committerSolomon Peachy <pizza@shaftnet.org>2024-11-21 20:05:18 -0500
commit39f8101d603a76448a4f3d1786f7cf2d6d683606 (patch)
tree62ce2c49a536eb2683eca619d8af54299c72a9fd
parent1c7fddad5b7525b1d5edbd6d775ef529ef2a2c7c (diff)
downloadrockbox-39f8101d60.tar.gz
rockbox-39f8101d60.zip
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
-rw-r--r--firmware/export/uc870x.h61
-rw-r--r--firmware/target/arm/uc870x.c81
2 files changed, 79 insertions, 63 deletions
diff --git a/firmware/export/uc870x.h b/firmware/export/uc870x.h
index ad7168fe64..7f0ac8169a 100644
--- a/firmware/export/uc870x.h
+++ b/firmware/export/uc870x.h
@@ -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__ */
diff --git a/firmware/target/arm/uc870x.c b/firmware/target/arm/uc870x.c
index 9537c15e1a..61a1cc41e0 100644
--- a/firmware/target/arm/uc870x.c
+++ b/firmware/target/arm/uc870x.c
@@ -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 */