summaryrefslogtreecommitdiff
path: root/firmware/target/arm
diff options
context:
space:
mode:
authorCástor Muñoz <cmvidal@gmail.com>2016-05-12 06:47:38 +0200
committerCástor Muñoz <cmvidal@gmail.com>2016-05-13 23:21:42 +0200
commit8fb67f48ab57770c3233352de17846a8a773192a (patch)
treefcf00f022dcd297c10ab92df8b85021f55e96f6f /firmware/target/arm
parent2a1e9eb8a8f50f636f86988de1f0cd1b3acf55bb (diff)
downloadrockbox-8fb67f48ab57770c3233352de17846a8a773192a.tar.gz
rockbox-8fb67f48ab57770c3233352de17846a8a773192a.zip
iPod Classic: updates for uc8702 driver
- Small rework on the UC8702 UART controller to make it compatible with other s5l870x SOCs. Files moved and renamed, many conditional code added to deal with capabilities and 'features' of the different CPUs. - A couple of optimizacions that should not affect the functionality. Change-Id: I705169f7e8b18d5d1da642f81ffc31c4089780a6
Diffstat (limited to 'firmware/target/arm')
-rw-r--r--firmware/target/arm/s5l8702/debug-s5l8702.c23
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/serial-ipod6g.c71
-rw-r--r--firmware/target/arm/s5l8702/system-s5l8702.c2
-rw-r--r--firmware/target/arm/s5l8702/uart-s5l8702.c155
-rw-r--r--firmware/target/arm/s5l8702/uart-target.h (renamed from firmware/target/arm/s5l8702/uart-s5l8702.h)24
-rw-r--r--firmware/target/arm/s5l8702/uc8702.h321
-rw-r--r--firmware/target/arm/uc870x.c (renamed from firmware/target/arm/s5l8702/uc8702.c)226
7 files changed, 300 insertions, 522 deletions
diff --git a/firmware/target/arm/s5l8702/debug-s5l8702.c b/firmware/target/arm/s5l8702/debug-s5l8702.c
index 291c809bce..614019bac1 100644
--- a/firmware/target/arm/s5l8702/debug-s5l8702.c
+++ b/firmware/target/arm/s5l8702/debug-s5l8702.c
@@ -31,7 +31,8 @@
31#include "pmu-target.h" 31#include "pmu-target.h"
32#include "pcm-target.h" 32#include "pcm-target.h"
33#ifdef HAVE_SERIAL 33#ifdef HAVE_SERIAL
34#include "uc8702.h" 34#include "uart-target.h"
35#include "uc870x.h"
35#endif 36#endif
36#include "clocking-s5l8702.h" 37#include "clocking-s5l8702.h"
37 38
@@ -50,7 +51,7 @@ bool dbg_hw_info(void)
50 int line; 51 int line;
51 int i; 52 int i;
52 unsigned int state = 0; 53 unsigned int state = 0;
53#ifdef UC8702_DEBUG 54#ifdef UC870X_DEBUG
54 const unsigned int max_states=3; 55 const unsigned int max_states=3;
55#else 56#else
56 const unsigned int max_states=2; 57 const unsigned int max_states=2;
@@ -120,20 +121,18 @@ bool dbg_hw_info(void)
120 _DEBUG_PRINTF("backlight: %s", pmu_read(0x29) ? "on" : "off"); 121 _DEBUG_PRINTF("backlight: %s", pmu_read(0x29) ? "on" : "off");
121 _DEBUG_PRINTF("brightness value: %d", pmu_read(0x28)); 122 _DEBUG_PRINTF("brightness value: %d", pmu_read(0x28));
122 } 123 }
123#ifdef UC8702_DEBUG 124#ifdef UC870X_DEBUG
124 else if(state==2) 125 else if(state==2)
125 { 126 {
126 extern struct uartc_port ser_port; 127 extern struct uartc_port ser_port;
127 int tx_stat, rx_stat, tx_speed, rx_speed; 128 int tx_stat, rx_stat, tx_speed, rx_speed;
128 char line_cfg[4]; 129 char line_cfg[4];
129 int abr_stat; 130 int abr_stat;
130 unsigned int abr_cnt; 131 uint32_t abr_cnt;
131
132 char *abrstatus[] = {"Idle", "Launched", "Counting", "Abnormal"}; 132 char *abrstatus[] = {"Idle", "Launched", "Counting", "Abnormal"};
133 133
134 uartc_port_get_line_info(&ser_port, &tx_stat, &rx_stat, 134 uartc_port_get_line_info(&ser_port,
135 &tx_speed, &rx_speed, line_cfg); 135 &tx_stat, &rx_stat, &tx_speed, &rx_speed, line_cfg);
136
137 abr_stat = uartc_port_get_abr_info(&ser_port, &abr_cnt); 136 abr_stat = uartc_port_get_abr_info(&ser_port, &abr_cnt);
138 137
139 _DEBUG_PRINTF("UART %d:", ser_port.id); 138 _DEBUG_PRINTF("UART %d:", ser_port.id);
@@ -141,7 +140,7 @@ bool dbg_hw_info(void)
141 _DEBUG_PRINTF("line: %s", line_cfg); 140 _DEBUG_PRINTF("line: %s", line_cfg);
142 _DEBUG_PRINTF("Tx: %s, speed: %d", tx_stat ? "On":"Off", tx_speed); 141 _DEBUG_PRINTF("Tx: %s, speed: %d", tx_stat ? "On":"Off", tx_speed);
143 _DEBUG_PRINTF("Rx: %s, speed: %d", rx_stat ? "On":"Off", rx_speed); 142 _DEBUG_PRINTF("Rx: %s, speed: %d", rx_stat ? "On":"Off", rx_speed);
144 _DEBUG_PRINTF("ABR: %s, cnt: %d", abrstatus[abr_stat], abr_cnt); 143 _DEBUG_PRINTF("ABR: %s, cnt: %u", abrstatus[abr_stat], abr_cnt);
145 line++; 144 line++;
146 _DEBUG_PRINTF("n_tx_bytes: %u", ser_port.n_tx_bytes); 145 _DEBUG_PRINTF("n_tx_bytes: %u", ser_port.n_tx_bytes);
147 _DEBUG_PRINTF("n_rx_bytes: %u", ser_port.n_rx_bytes); 146 _DEBUG_PRINTF("n_rx_bytes: %u", ser_port.n_rx_bytes);
@@ -149,10 +148,8 @@ bool dbg_hw_info(void)
149 _DEBUG_PRINTF("n_parity_err: %u", ser_port.n_parity_err); 148 _DEBUG_PRINTF("n_parity_err: %u", ser_port.n_parity_err);
150 _DEBUG_PRINTF("n_frame_err: %u", ser_port.n_frame_err); 149 _DEBUG_PRINTF("n_frame_err: %u", ser_port.n_frame_err);
151 _DEBUG_PRINTF("n_break_detect: %u", ser_port.n_break_detect); 150 _DEBUG_PRINTF("n_break_detect: %u", ser_port.n_break_detect);
152 _DEBUG_PRINTF("n_abnormal0: %u", ser_port.n_abnormal0); 151 _DEBUG_PRINTF("ABR n_abnormal: %u %u",
153 _DEBUG_PRINTF("n_abnormal1: %u", ser_port.n_abnormal1); 152 ser_port.n_abnormal0, ser_port.n_abnormal1);
154
155 sleep(HZ/20);
156 } 153 }
157#endif 154#endif
158 else 155 else
diff --git a/firmware/target/arm/s5l8702/ipod6g/serial-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/serial-ipod6g.c
index b022fef675..c77b5d0c95 100644
--- a/firmware/target/arm/s5l8702/ipod6g/serial-ipod6g.c
+++ b/firmware/target/arm/s5l8702/ipod6g/serial-ipod6g.c
@@ -18,19 +18,16 @@
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#include <stdio.h> 21#include <stdint.h>
22#include <stdlib.h> 22#include <stdbool.h>
23#include <stdarg.h>
24 23
25#include "config.h" 24#include "config.h"
26#include "cpu.h" 25#include "cpu.h"
27#include "system.h" 26#include "system.h"
28#include "kernel.h"
29
30#include "serial.h" 27#include "serial.h"
28
31#include "s5l8702.h" 29#include "s5l8702.h"
32#include "uc8702.h" 30#include "uc870x.h"
33#include "uart-s5l8702.h"
34 31
35/* Define LOGF_ENABLE to enable logf output in this file */ 32/* Define LOGF_ENABLE to enable logf output in this file */
36#define LOGF_ENABLE 33#define LOGF_ENABLE
@@ -38,16 +35,26 @@
38 35
39 36
40/* shall include serial HW configuracion for specific target */ 37/* shall include serial HW configuracion for specific target */
41#define IPOD6G_UART_CLK_HZ 12000000 /* external OSC0 ??? */ 38#define IPOD6G_UART_CLK_HZ 12000000 /* external OSC0 ??? */
39
40/* This values below are valid with a UCLK of 12MHz */
41#define BRDATA_9600 (77) /* 9615 */
42#define BRDATA_19200 (38) /* 19231 */
43#define BRDATA_28800 (25) /* 28846 */
44#define BRDATA_38400 (19 | (0xc330c << 8)) /* 38305 */
45#define BRDATA_57600 (12) /* 57692 */
46#define BRDATA_115200 (6 | (0xffffff << 8)) /* 114286 */
42 47
43extern struct uartc s5l8702_uart; 48
49extern const struct uartc s5l8702_uartc;
44#ifdef IPOD_ACCESSORY_PROTOCOL 50#ifdef IPOD_ACCESSORY_PROTOCOL
45void iap_rx_isr(int, char*, char*, uint32_t); 51void iap_rx_isr(int, char*, char*, uint32_t);
46#endif 52#endif
47 53
48struct uartc_port ser_port IDATA_ATTR = { 54struct uartc_port ser_port IDATA_ATTR =
55{
49 /* location */ 56 /* location */
50 .uartc = &s5l8702_uart, 57 .uartc = &s5l8702_uartc,
51 .id = 0, 58 .id = 0,
52 59
53 /* configuration */ 60 /* configuration */
@@ -70,17 +77,18 @@ struct uartc_port ser_port IDATA_ATTR = {
70 */ 77 */
71void serial_setup(void) 78void serial_setup(void)
72{ 79{
73 uart_port_init(&ser_port); 80 uartc_port_open(&ser_port);
74 81
75 /* set a default configuration, Tx and Rx modes are 82 /* set a default configuration, Tx and Rx modes are
76 disabled when the port is initialized */ 83 disabled when the port is initialized */
77 uartc_port_config(&ser_port, 115200, ULCON_DATA_BITS_8, 84 uartc_port_config(&ser_port, ULCON_DATA_BITS_8,
78 ULCON_PARITY_NONE, ULCON_STOP_BITS_1); 85 ULCON_PARITY_NONE, ULCON_STOP_BITS_1);
86 uartc_port_set_bitrate_raw(&ser_port, BRDATA_115200);
79 87
80 /* enable Tx interrupt request or POLLING mode */ 88 /* enable Tx interrupt request or POLLING mode */
81 uartc_port_set_tx_mode(&ser_port, UCON_MODE_INTREQ); 89 uartc_port_set_tx_mode(&ser_port, UCON_MODE_INTREQ);
82 90
83 logf("[%lu] serial_setup(): port %d ready!", USEC_TIMER, ser_port.id); 91 logf("[%lu] "MODEL_NAME" port %d ready!", USEC_TIMER, ser_port.id);
84} 92}
85 93
86int tx_rdy(void) 94int tx_rdy(void)
@@ -93,16 +101,15 @@ void tx_writec(unsigned char c)
93 uartc_port_tx_byte(&ser_port, c); 101 uartc_port_tx_byte(&ser_port, c);
94} 102}
95 103
104
96#ifdef IPOD_ACCESSORY_PROTOCOL 105#ifdef IPOD_ACCESSORY_PROTOCOL
97#include "iap.h" 106#include "iap.h"
98 107
99enum { 108static enum {
100 ABR_STATUS_LAUNCHED, /* ST_SYNC */ 109 ABR_STATUS_LAUNCHED, /* ST_SYNC */
101 ABR_STATUS_SYNCING, /* ST_SOF */ 110 ABR_STATUS_SYNCING, /* ST_SOF */
102 ABR_STATUS_DONE 111 ABR_STATUS_DONE
103}; 112} abr_status;
104
105int abr_status;
106 113
107void serial_bitrate(int rate) 114void serial_bitrate(int rate)
108{ 115{
@@ -131,8 +138,13 @@ void serial_bitrate(int rate)
131 abr_status = ABR_STATUS_LAUNCHED; 138 abr_status = ABR_STATUS_LAUNCHED;
132 } 139 }
133 else { 140 else {
141 uint32_t brdata;
142 if (rate == 57600) brdata = BRDATA_57600;
143 else if (rate == 38400) brdata = BRDATA_38400;
144 else if (rate == 19200) brdata = BRDATA_19200;
145 else brdata = BRDATA_9600;
134 uartc_port_abr_stop(&ser_port); /* abort ABR if already launched */ 146 uartc_port_abr_stop(&ser_port); /* abort ABR if already launched */
135 uartc_port_set_bitrate(&ser_port, rate); 147 uartc_port_set_bitrate_raw(&ser_port, brdata);
136 uartc_port_set_rx_mode(&ser_port, UCON_MODE_INTREQ); 148 uartc_port_set_rx_mode(&ser_port, UCON_MODE_INTREQ);
137 abr_status = ABR_STATUS_DONE; 149 abr_status = ABR_STATUS_DONE;
138 } 150 }
@@ -149,22 +161,21 @@ void iap_rx_isr(int len, char *data, char *err, uint32_t abr_cnt)
149 /* autobauding */ 161 /* autobauding */
150 if (abr_cnt) { 162 if (abr_cnt) {
151 #define BR2CNT(s) (IPOD6G_UART_CLK_HZ / (unsigned)(s)) 163 #define BR2CNT(s) (IPOD6G_UART_CLK_HZ / (unsigned)(s))
152 unsigned speed;
153
154 if (abr_cnt < BR2CNT(57600*1.1) || abr_cnt > BR2CNT(9600*0.9)) { 164 if (abr_cnt < BR2CNT(57600*1.1) || abr_cnt > BR2CNT(9600*0.9)) {
155 /* detected speed out of range, relaunch ABR */ 165 /* detected speed out of range, relaunch ABR */
156 uartc_port_abr_start(&ser_port); 166 uartc_port_abr_start(&ser_port);
157 return; 167 return;
158 } 168 }
159 /* valid speed detected, select it */ 169 /* valid speed detected, select it */
160 else if (abr_cnt < BR2CNT(48000)) speed = 57600; 170 uint32_t brdata;
161 else if (abr_cnt < BR2CNT(33600)) speed = 38400; 171 if (abr_cnt < BR2CNT(48000)) brdata = BRDATA_57600;
162 else if (abr_cnt < BR2CNT(24000)) speed = 28800; 172 else if (abr_cnt < BR2CNT(33600)) brdata = BRDATA_38400;
163 else if (abr_cnt < BR2CNT(14400)) speed = 19200; 173 else if (abr_cnt < BR2CNT(24000)) brdata = BRDATA_28800;
164 else speed = 9600; 174 else if (abr_cnt < BR2CNT(14400)) brdata = BRDATA_19200;
175 else brdata = BRDATA_9600;
165 176
166 /* set detected speed */ 177 /* set detected speed */
167 uartc_port_set_bitrate(&ser_port, speed); 178 uartc_port_set_bitrate_raw(&ser_port, brdata);
168 uartc_port_set_rx_mode(&ser_port, UCON_MODE_INTREQ); 179 uartc_port_set_rx_mode(&ser_port, UCON_MODE_INTREQ);
169 180
170 /* enter SOF state */ 181 /* enter SOF state */
@@ -176,10 +187,12 @@ void iap_rx_isr(int len, char *data, char *err, uint32_t abr_cnt)
176 } 187 }
177 188
178 /* process received data */ 189 /* process received data */
179 while (len--) { 190 while (len--)
191 {
180 bool sync_done = !iap_getc(*data++); 192 bool sync_done = !iap_getc(*data++);
181 193
182 if (abr_status == ABR_STATUS_SYNCING) { 194 if (abr_status == ABR_STATUS_SYNCING)
195 {
183 if (sync_done) { 196 if (sync_done) {
184 abr_status = ABR_STATUS_DONE; 197 abr_status = ABR_STATUS_DONE;
185 } 198 }
diff --git a/firmware/target/arm/s5l8702/system-s5l8702.c b/firmware/target/arm/s5l8702/system-s5l8702.c
index 6b20f44acb..fd3a464e2f 100644
--- a/firmware/target/arm/s5l8702/system-s5l8702.c
+++ b/firmware/target/arm/s5l8702/system-s5l8702.c
@@ -24,9 +24,9 @@
24#include "panic.h" 24#include "panic.h"
25#include "system-target.h" 25#include "system-target.h"
26#include "pmu-target.h" 26#include "pmu-target.h"
27#include "uart-target.h"
27#include "gpio-s5l8702.h" 28#include "gpio-s5l8702.h"
28#include "dma-s5l8702.h" 29#include "dma-s5l8702.h"
29#include "uart-s5l8702.h"
30#include "clocking-s5l8702.h" 30#include "clocking-s5l8702.h"
31 31
32#define default_interrupt(name) \ 32#define default_interrupt(name) \
diff --git a/firmware/target/arm/s5l8702/uart-s5l8702.c b/firmware/target/arm/s5l8702/uart-s5l8702.c
index 45d61ba627..9d8faaa173 100644
--- a/firmware/target/arm/s5l8702/uart-s5l8702.c
+++ b/firmware/target/arm/s5l8702/uart-s5l8702.c
@@ -18,110 +18,133 @@
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21 21#include <stdint.h>
22/* Include Standard files */ 22#include <stdbool.h>
23#include <stdlib.h>
24#include <stdio.h>
25#include <stdarg.h>
26 23
27#include "config.h" 24#include "config.h"
28#include "cpu.h" 25#include "cpu.h"
29#include "system.h" 26#include "system.h"
30#include "kernel.h"
31 27
32#include "s5l8702.h" 28#include "s5l8702.h"
33#include "uc8702.h" 29#include "uc870x.h"
34#include "uart-s5l8702.h"
35 30
36 31
37/* s5l8702 UART configuration */ 32/*
38struct uartc s5l8702_uart = { 33 * s5l8702 UC870X HW: 1 UARTC, 4 ports
39 .baddr = S5L8702_UART_BASE 34 */
35static struct uartc_port *uartc_port_l[UARTC_N_PORTS];
36const struct uartc s5l8702_uartc =
37{
38 .id = 0,
39 .baddr = UARTC_BASE_ADDR,
40 .port_off = UARTC_PORT_OFFSET,
41 .n_ports = UARTC_N_PORTS,
42 .port_l = uartc_port_l,
40}; 43};
41 44
42/* 45/*
43 * Device level functions specific to S5L8702 46 * Device level functions specific to S5L8702
44 */ 47 */
45void uart_gpio_control(int port_id, bool onoff) 48void uart_target_enable_gpio(int uart_id, int port_id)
46{ 49{
47 if (onoff) { 50 (void) uart_id;
48 switch (port_id) { 51 switch (port_id) {
49 case 0: 52 case 0:
50 /* configure UART0 Tx/Rx GPIO ports */ 53 /* configure UART0 Tx/Rx GPIO ports */
51 PCON0 = (PCON0 & 0xff00ffff) | 0x00220000; 54 PCON0 = (PCON0 & 0xff00ffff) | 0x00220000;
52 break; 55 break;
53 case 1: 56 case 1:
54 /* configure UART1 GPIO ports, including RTS/CTS signals */ 57 /* configure UART1 GPIO ports, including RTS/CTS signals */
55 PCOND = (PCOND & 0xff0000ff) | 0x00222200; 58 PCOND = (PCOND & 0xff0000ff) | 0x00222200;
56 break; 59 break;
57 case 2: 60 case 2:
58 case 3: 61 case 3:
59 /* unknown, probably UART3/4 not routed on s5l8702 */ 62 /* unknown */
60 default: 63 default:
61 break; 64 break;
62 }
63 } 65 }
64 else { 66}
67
68void uart_target_disable_gpio(int uart_id, int port_id)
69{
70 (void) uart_id;
71 switch (port_id) {
65 /* configure minimal power consumption */ 72 /* configure minimal power consumption */
66 switch (port_id) { 73 case 0:
67 case 0: 74 PCON0 = (PCON0 & 0xff00ffff) | 0x00ee0000;
68 PCON0 = (PCON0 & 0xff00ffff) | 0x00ee0000; 75 break;
69 break; 76 case 1:
70 case 1: 77 PCOND = (PCOND & 0xff0000ff) | 0x00eeee00;
71 PCOND = (PCOND & 0xff0000ff) | 0x00eeee00; 78 break;
72 break; 79 case 2:
73 case 2: 80 case 3:
74 case 3: 81 default:
75 default: 82 break;
76 break;
77 }
78 } 83 }
79} 84}
80 85
81/* reset s5l8702 uart related hardware */ 86void uart_target_enable_irq(int uart_id, int port_id)
82static void s5l8702_uart_hw_init(void)
83{ 87{
84 for (int id = 0; id < S5L8702_UART_PORT_MAX; id++) { 88 (void) uart_id;
85 VIC0INTENCLEAR = 1 << IRQ_UART(id); /* mask INT */ 89 VIC0INTENABLE = 1 << IRQ_UART(port_id);
86 uart_gpio_control(id, 0);
87 }
88} 90}
89 91
90void uart_init(void) 92void uart_target_disable_irq(int uart_id, int port_id)
91{ 93{
92 s5l8702_uart_hw_init(); 94 (void) uart_id;
93 PWRCON(1) &= ~(1 << (CLOCKGATE_UART - 32)); /* on */ 95 VIC0INTENCLEAR = 1 << IRQ_UART(port_id);
94 uartc_open(&s5l8702_uart);
95} 96}
96 97
97void uart_close(void) 98void uart_target_clear_irq(int uart_id, int port_id)
98{ 99{
99 uartc_close(&s5l8702_uart); 100 (void) uart_id;
100 PWRCON(1) |= (1 << (CLOCKGATE_UART - 32)); /* off */ 101 (void) port_id;
101 s5l8702_uart_hw_init();
102} 102}
103 103
104void uart_port_init(struct uartc_port *port) 104void uart_target_enable_clocks(int uart_id)
105{ 105{
106 uart_gpio_control(port->id, 1); 106 (void) uart_id;
107 uartc_port_open(port); 107 PWRCON(1) &= ~(1 << (CLOCKGATE_UARTC - 32));
108 VIC0INTENABLE = 1 << IRQ_UART(port->id); /* unmask INT */
109} 108}
110 109
111void uart_port_close(struct uartc_port *port) 110void uart_target_disable_clocks(int uart_id)
112{ 111{
113 VIC0INTENCLEAR = 1 << IRQ_UART(port->id); /* mask INT */ 112 (void) uart_id;
114 uartc_port_close(port); 113 PWRCON(1) |= (1 << (CLOCKGATE_UARTC - 32));
115 uart_gpio_control(port->id, 0);
116} 114}
117 115
118/* ISRs */ 116/*
117 * ISRs
118 */
119
120/* On Classic, PORT0 interrupts are not used when iAP is disabled */
121#if !defined(IPOD_6G) || defined(IPOD_ACCESSORY_PROTOCOL)
119void ICODE_ATTR INT_UART0(void) 122void ICODE_ATTR INT_UART0(void)
120{ 123{
121 uartc_callback(&s5l8702_uart, 0); 124 uartc_callback(&s5l8702_uartc, 0);
122} 125}
126#endif
123 127
128/* PORT1,2,3 not used on Classic */
129#ifndef IPOD_6G
124void ICODE_ATTR INT_UART1(void) 130void ICODE_ATTR INT_UART1(void)
125{ 131{
126 uartc_callback(&s5l8702_uart, 1); 132 uartc_callback(&s5l8702_uartc, 1);
133}
134
135void ICODE_ATTR INT_UART2(void)
136{
137 uartc_callback(&s5l8702_uartc, 2);
138}
139
140void ICODE_ATTR INT_UART3(void)
141{
142 uartc_callback(&s5l8702_uartc, 3);
143}
144#endif
145
146/* Main init */
147void uart_init(void)
148{
149 uartc_open(&s5l8702_uartc);
127} 150}
diff --git a/firmware/target/arm/s5l8702/uart-s5l8702.h b/firmware/target/arm/s5l8702/uart-target.h
index c7ec684284..d6d45b9073 100644
--- a/firmware/target/arm/s5l8702/uart-s5l8702.h
+++ b/firmware/target/arm/s5l8702/uart-target.h
@@ -18,15 +18,21 @@
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#ifndef __UART_S5L8702_H__ 21#ifndef __UART_TARGET_H__
22#define __UART_S5L8702_H__ 22#define __UART_TARGET_H__
23 23
24#include "uc8702.h" 24/* Define this to show debug data on "View HW Info" */
25/* #define UC870X_DEBUG */
25 26
26/* s5l8702 low level routines */ 27void uart_init(void);
27void uart_init (void);
28void uart_close(void);
29void uart_port_init (struct uartc_port *port);
30void uart_port_close (struct uartc_port *port);
31 28
32#endif /* __UART_S5L8702_H__ */ 29/* s5l870x low level routines */
30void uart_target_enable_clocks(int uart_id);
31void uart_target_disable_clocks(int uart_id);
32void uart_target_enable_irq(int uart_id, int port_id);
33void uart_target_disable_irq(int uart_id, int port_id);
34void uart_target_clear_irq(int uart_id, int port_id);
35void uart_target_enable_gpio(int uart_id, int port_id);
36void uart_target_disable_gpio(int uart_id, int port_id);
37
38#endif /* __UART_TARGET_H__ */
diff --git a/firmware/target/arm/s5l8702/uc8702.h b/firmware/target/arm/s5l8702/uc8702.h
deleted file mode 100644
index 36e4f8faa4..0000000000
--- a/firmware/target/arm/s5l8702/uc8702.h
+++ /dev/null
@@ -1,321 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2014 by Cástor Muñoz
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#ifndef __UC8702_H__
22#define __UC8702_H__
23
24#include <stdint.h>
25#include <stdbool.h>
26
27
28/* s5l8702 UART controller (UC8702):
29 *
30 * This UART is similar to the UART included in s5l8700 (see also
31 * s3c2416 and s3c6400 datasheets), UC8702 adds fine tunning for
32 * Tx/Rx bitrate and autobauding.
33 */
34
35/*#define UC8702_DEBUG*/
36
37/*
38 * uc8702 HW definitions
39 */
40#define UART_PORT_MAX 4
41#define UART_FIFO_SIZE 16
42
43#define UART_PORT_BASE(b,i) ((b) + 0x4000 * (i))
44
45/*
46 * controller registers
47 */
48#define REG32_PTR_T volatile uint32_t *
49
50#define ULCON(ba) (*((REG32_PTR_T)((ba) + 0x00))) /* line control */
51#define UCON(ba) (*((REG32_PTR_T)((ba) + 0x04))) /* control */
52#define UFCON(ba) (*((REG32_PTR_T)((ba) + 0x08))) /* FIFO control */
53#define UMCON(ba) (*((REG32_PTR_T)((ba) + 0x0C))) /* modem control */
54#define UTRSTAT(ba) (*((REG32_PTR_T)((ba) + 0x10))) /* Tx/Rx status */
55#define UERSTAT(ba) (*((REG32_PTR_T)((ba) + 0x14))) /* Rx error status */
56#define UFSTAT(ba) (*((REG32_PTR_T)((ba) + 0x18))) /* FIFO status */
57#define UMSTAT(ba) (*((REG32_PTR_T)((ba) + 0x1C))) /* modem status */
58#define UTXH(ba) (*((REG32_PTR_T)((ba) + 0x20))) /* transmission hold */
59#define URXH(ba) (*((REG32_PTR_T)((ba) + 0x24))) /* receive buffer */
60#define UBRDIV(ba) (*((REG32_PTR_T)((ba) + 0x28))) /* baud rate divisor */
61#define UABRCNT(ba) (*((REG32_PTR_T)((ba) + 0x2c))) /* autobaud counter */
62#define UABRSTAT(ba) (*((REG32_PTR_T)((ba) + 0x30))) /* autobaud status */
63#define UBRCONTX(ba) (*((REG32_PTR_T)((ba) + 0x34))) /* Tx frame config */
64#define UBRCONRX(ba) (*((REG32_PTR_T)((ba) + 0x38))) /* Rx frame config */
65
66/* ULCON register */
67#define ULCON_DATA_BITS_MASK 0x3
68#define ULCON_DATA_BITS_POS 0
69#define ULCON_DATA_BITS_5 0
70#define ULCON_DATA_BITS_6 1
71#define ULCON_DATA_BITS_7 2
72#define ULCON_DATA_BITS_8 3
73
74#define ULCON_STOP_BITS_MASK 0x1
75#define ULCON_STOP_BITS_POS 2
76#define ULCON_STOP_BITS_1 0
77#define ULCON_STOP_BITS_2 1
78
79#define ULCON_PARITY_MASK 0x7
80#define ULCON_PARITY_POS 3
81#define ULCON_PARITY_NONE 0
82#define ULCON_PARITY_ODD 4
83#define ULCON_PARITY_EVEN 5
84#define ULCON_PARITY_FORCE_1 6
85#define ULCON_PARITY_FORCE_0 7
86
87#define ULCON_INFRARED_EN_BIT (1 << 6)
88
89/* UCON register */
90#define UCON_RX_MODE_MASK 0x3
91#define UCON_RX_MODE_POS 0
92
93#define UCON_TX_MODE_MASK 0x3
94#define UCON_TX_MODE_POS 2
95
96#define UCON_MODE_DISABLED 0
97#define UCON_MODE_INTREQ 1 /* INT request or polling mode */
98#define UCON_MODE_UNDEFINED 2 /* Not defined, DMAREQ signal 1 ??? */
99#define UCON_MODE_DMAREQ 3 /* DMA request (signal 0) */
100
101#define UCON_SEND_BREAK_BIT (1 << 4)
102#define UCON_LOOPBACK_BIT (1 << 5)
103#define UCON_RX_TOUT_EN_BIT (1 << 7) /* Rx timeout enable */
104
105#define UCON_CLKSEL_MASK 0x1
106#define UCON_CLKSEL_POS 10
107#define UCON_CLKSEL_PCLK 0 /* internal */
108#define UCON_CLKSEL_ECLK 1 /* external */
109
110#define UCON_RX_TOUT_INT_BIT (1 << 11) /* Rx timeout INT enable */
111#define UCON_RX_INT_BIT (1 << 12) /* Rx INT enable */
112#define UCON_TX_INT_BIT (1 << 13) /* Tx INT enable */
113#define UCON_ERR_INT_BIT (1 << 14) /* Rx error INT enable */
114#define UCON_MODEM_INT_BIT (1 << 15) /* modem INT enable (TBC) */
115#define UCON_AUTOBR_INT_BIT (1 << 16) /* autobauding INT enable */
116#define UCON_AUTOBR_START_BIT (1 << 17) /* autobauding start/stop */
117
118/* UFCON register */
119#define UFCON_FIFO_ENABLE_BIT (1 << 0)
120#define UFCON_RX_FIFO_RST_BIT (1 << 1)
121#define UFCON_TX_FIFO_RST_BIT (1 << 2)
122
123#define UFCON_RX_FIFO_TRG_MASK 0x3
124#define UFCON_RX_FIFO_TRG_POS 4
125#define UFCON_RX_FIFO_TRG_4 0
126#define UFCON_RX_FIFO_TRG_8 1
127#define UFCON_RX_FIFO_TRG_12 2
128#define UFCON_RX_FIFO_TRG_16 3
129
130#define UFCON_TX_FIFO_TRG_MASK 0x3
131#define UFCON_TX_FIFO_TRG_POS 6
132#define UFCON_TX_FIFO_TRG_EMPTY 0
133#define UFCON_TX_FIFO_TRG_4 1
134#define UFCON_TX_FIFO_TRG_8 2
135#define UFCON_TX_FIFO_TRG_12 3
136
137/* UMCON register */
138#define UMCON_RTS_BIT (1 << 0)
139#define UMCON_AUTO_FLOW_CTRL_BIT (1 << 4)
140
141/* UTRSTAT register */
142#define UTRSTAT_RXBUF_RDY_BIT (1 << 0)
143#define UTRSTAT_TXBUF_EMPTY_BIT (1 << 1)
144#define UTRSTAT_TX_EMPTY_BIT (1 << 2)
145#define UTRSTAT_RX_TOUT_INT_BIT (1 << 3) /* Rx timeout INT status */
146#define UTRSTAT_RX_INT_BIT (1 << 4)
147#define UTRSTAT_TX_INT_BIT (1 << 5)
148#define UTRSTAT_ERR_INT_BIT (1 << 6)
149#define UTRSTAT_MODEM_INT_BIT (1 << 7) /* modem INT status (TBC) */
150#define UTRSTAT_AUTOBR_INT_BIT (1 << 8) /* autobauding INT status */
151
152/* UERSTAT register */
153#define UERSTAT_OVERRUN_BIT (1 << 0)
154#define UERSTAT_PARITY_ERR_BIT (1 << 1)
155#define UERSTAT_FRAME_ERR_BIT (1 << 2)
156#define UERSTAT_BREAK_DETECT_BIT (1 << 3)
157
158/* UFSTAT register */
159#define UFSTAT_RX_FIFO_CNT_MASK 0xf
160#define UFSTAT_RX_FIFO_CNT_POS 0
161
162#define UFSTAT_TX_FIFO_CNT_MASK 0xf
163#define UFSTAT_TX_FIFO_CNT_POS 4
164
165#define UFSTAT_RX_FIFO_FULL_BIT (1 << 8)
166#define UFSTAT_TX_FIFO_FULL_BIT (1 << 9)
167#define UFSTAT_RX_FIFO_ERR_BIT (1 << 10) /* clears when reading UERSTAT
168 for the last pending error */
169/* UMSTAT register */
170#define UMSTAT_CTS_ACTIVE_BIT (1 << 0)
171#define UMSTAT_CTS_DELTA_BIT (1 << 4)
172
173/* Bitrate:
174 *
175 * Master UCLK clock is divided by 16 to serialize data, UBRDIV is
176 * used to configure nominal bit width, NBW = (UBRDIV+1)*16 in UCLK
177 * clock ticks.
178 *
179 * Fine tuning works shrining/expanding each individual bit of each
180 * frame. Each bit width can be incremented/decremented by 1/16 of
181 * nominal bit width, it seems UCLK is divided by 17 for expanded
182 * bits and divided by 15 for compressed bits. A whole frame of N
183 * bits can be shrined or expanded up to (NBW * N / 16) UCLK clock
184 * ticks (in 1/16 steps).
185 */
186/* UBRCONx register */
187#define UC_FRAME_MAX_LEN 12 /* 1 start + 8 data + 1 par + 2 stop */
188#define UBRCON_JITTER_MASK 0x3
189#define UBRCON_JITTER_POS(bit) ((bit) << 1) /* 0..UC_FRAME_MAX_LEN-1 */
190
191#define UBRCON_JITTER_NONE 0 /* no jitter for this bit */
192#define UBRCON_JITTER_INC 1 /* increment 1/16 bit width */
193#define UBRCON_JITTER_UNUSED 2 /* does nothing */
194#define UBRCON_JITTER_DEC 3 /* decremet 1/16 bit width */
195
196/* Autobauding:
197 *
198 * Initial UABRSTAT is NOT_INIT, it goes to READY when either of
199 * UCON_AUTOBR bits are enabled for the first time.
200 *
201 * Interrupts are enabled/disabled using UCON_AUTOBR_INT_BIT and
202 * checked using UTRSTAT_AUTOBR_INT_BIT, writing this bit cleans the
203 * interrupt.
204 *
205 * When UCON_AUTOBR_START_BIT is enabled, autobauding starts and the
206 * hardware waits for a low pulse on RX line.
207 *
208 * Once autobauding is started, when a falling edge is detected on
209 * the RX line, UABRSTAT changes to COUNTING status, an internal
210 * counter starts incrementing at UCLK clock frequency. During
211 * COUNTING state, UABRCNT reads as the value of the previous ABR
212 * count, not the value of the current internal count.
213 *
214 * Count finish when a rising edge is detected on the line, at this
215 * moment internal counter stops and it can be read using UABRCNT
216 * register, UABRSTAT goes to READY, AUTOBR_START_BIT is disabled,
217 * and an interrupt is raised if UCON_AUTOBR_INT_BIT is enabled.
218 */
219/* UABRSTAT register */
220#define UABRSTAT_STATUS_MASK 0x3
221#define UABRSTAT_STATUS_POS 0
222
223#define UABRSTAT_STATUS_NOT_INIT 0 /* initial status */
224#define UABRSTAT_STATUS_READY 1 /* machine is ready */
225#define UABRSTAT_STATUS_COUNTING 2 /* count in progress */
226
227
228/*
229 * structs
230 */
231struct uartc
232{
233 /* static configuration */
234 const uint32_t baddr;
235 /* private */
236 struct uartc_port *port_l[UART_PORT_MAX];
237};
238
239struct uartc_port
240{
241 /* static configuration */
242 struct uartc * const uartc;
243 const uint8_t id; /* port number */
244 const uint8_t rx_trg; /* UFCON_RX_FIFO_TRG_xxx */
245 const uint8_t tx_trg; /* UFCON_TX_FIFO_TRG_xxx */
246 const uint8_t clksel; /* UFCON_CLKSEL_xxx */
247 const uint32_t clkhz; /* UCLK (PCLK or ECLK) frequency */
248 void (* const tx_cb) (int len); /* ISRs */
249 void (* const rx_cb) (int len, char *data, char *err, uint32_t abr_cnt);
250
251 /* private */
252 uint32_t baddr;
253 uint32_t utrstat_int_mask;
254 bool abr_aborted;
255 uint8_t rx_data[UART_FIFO_SIZE]; /* data buffer for rx_cb */
256 uint8_t rx_err[UART_FIFO_SIZE]; /* error buffer for rx_cb */
257
258#ifdef UC8702_DEBUG
259 uint32_t n_tx_bytes;
260 uint32_t n_rx_bytes;
261 uint32_t n_ovr_err;
262 uint32_t n_parity_err;
263 uint32_t n_frame_err;
264 uint32_t n_break_detect;
265 uint32_t n_abnormal0;
266 uint32_t n_abnormal1;
267#endif
268};
269
270
271/*
272 * uc8702 low level API
273 */
274
275/* Initialization */
276void uartc_open(struct uartc* uartc);
277void uartc_close(struct uartc* uartc);
278void uartc_port_open(struct uartc_port *port);
279void uartc_port_close(struct uartc_port *port);
280void uartc_port_rx_onoff(struct uartc_port *port, bool onoff);
281void uartc_port_tx_onoff(struct uartc_port *port, bool onoff);
282
283/* Configuration */
284void uartc_port_config(struct uartc_port *port, unsigned int speed,
285 uint8_t data_bits, uint8_t parity, uint8_t stop_bits);
286void uartc_port_set_bitrate(struct uartc_port *port, unsigned int speed);
287void uartc_port_set_rx_mode(struct uartc_port *port, uint32_t mode);
288void uartc_port_set_tx_mode(struct uartc_port *port, uint32_t mode);
289
290/* Transmit */
291bool uartc_port_tx_ready(struct uartc_port *port);
292void uartc_port_tx_byte(struct uartc_port *port, uint8_t ch);
293void uartc_port_send_byte(struct uartc_port *port, uint8_t ch);
294
295/* Receive */
296bool uartc_port_rx_ready(struct uartc_port *port);
297uint8_t uartc_port_rx_byte(struct uartc_port *port);
298uint8_t uartc_port_read_byte(struct uartc_port *port);
299
300/* Autobauding */
301void uartc_port_abr_start(struct uartc_port *port);
302void uartc_port_abr_stop(struct uartc_port *port);
303
304/* ISR */
305void uartc_callback(struct uartc *uartc, int dev);
306
307#ifdef UC8702_DEBUG
308enum {
309 ABR_INFO_ST_IDLE,
310 ABR_INFO_ST_LAUNCHED,
311 ABR_INFO_ST_COUNTING,
312 ABR_INFO_ST_ABNORMAL
313};
314
315void uartc_port_get_line_info(struct uartc_port *port,
316 int *tx_status, int *rx_status,
317 int *tx_speed, int *rx_speed, char *line_cfg);
318
319int uartc_port_get_abr_info(struct uartc_port *port, unsigned int *abr_cnt);
320#endif
321#endif /* __UC8702_H__ */
diff --git a/firmware/target/arm/s5l8702/uc8702.c b/firmware/target/arm/uc870x.c
index 91c4a3c9e6..9537c15e1a 100644
--- a/firmware/target/arm/s5l8702/uc8702.c
+++ b/firmware/target/arm/uc870x.c
@@ -19,79 +19,100 @@
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#include <stdint.h> 21#include <stdint.h>
22#include "kernel.h" 22#include <stdbool.h>
23#include "uc8702.h" 23
24#include "config.h"
25#include "system.h"
26
27#include "uart-target.h"
28#include "uc870x.h"
24 29
25 30
26/* 31/*
27 * s5l8702 UART controller (UC8702) 32 * UC870x: UART controller for s5l870x
28 */ 33 */
29 34
30/* Rx related masks */ 35/* Rx related masks */
36#if CONFIG_CPU == S5L8700
37#define UTRSTAT_RX_RELATED_INTS (UTRSTAT_RX_INT_BIT | UTRSTAT_ERR_INT_BIT)
38#define UCON_RX_RELATED_INTS (UCON_RX_INT_BIT | UCON_ERR_INT_BIT)
39
40#elif CONFIG_CPU == S5L8701
31#define UTRSTAT_RX_RELATED_INTS \ 41#define UTRSTAT_RX_RELATED_INTS \
32 (UTRSTAT_RX_INT_BIT | UTRSTAT_RX_TOUT_INT_BIT | \ 42 (UTRSTAT_RX_INT_BIT | UTRSTAT_ERR_INT_BIT | UTRSTAT_AUTOBR_INT_BIT)
33 UTRSTAT_ERR_INT_BIT | UTRSTAT_AUTOBR_INT_BIT)
34#define UCON_RX_RELATED_INTS \ 43#define UCON_RX_RELATED_INTS \
35 (UCON_RX_INT_BIT | UCON_RX_TOUT_INT_BIT | \ 44 (UCON_RX_INT_BIT | UCON_ERR_INT_BIT | UCON_AUTOBR_INT_BIT)
36 UCON_ERR_INT_BIT | UCON_AUTOBR_INT_BIT) 45
46#else /* CONFIG_CPU == S5L8702 */
47#define UTRSTAT_RX_RELATED_INTS \
48 (UTRSTAT_RX_INT_BIT | UTRSTAT_ERR_INT_BIT | \
49 UTRSTAT_AUTOBR_INT_BIT | UTRSTAT_RX_TOUT_INT_BIT)
50#define UCON_RX_RELATED_INTS \
51 (UCON_RX_INT_BIT | UCON_ERR_INT_BIT | \
52 UCON_AUTOBR_INT_BIT | UCON_RX_TOUT_INT_BIT)
53#endif
54
55#define UART_PORT_BASE(u,i) (((u)->baddr) + (u)->port_off * (i))
37 56
38/* Initialization */ 57/* Initialization */
39static void uartc_port_id_reset(struct uartc* uartc, int id) 58static void uartc_reset_port_id(const struct uartc* uartc, int port_id)
40{ 59{
41 uint32_t baddr = UART_PORT_BASE(uartc->baddr, id); 60 uart_target_disable_irq(uartc->id, port_id);
61 uart_target_disable_gpio(uartc->id, port_id);
42 62
43 /* set port registers to default reset values */ 63 /* set port registers to default reset values */
64 uint32_t baddr = UART_PORT_BASE(uartc, port_id);
44 UCON(baddr) = 0; 65 UCON(baddr) = 0;
45 ULCON(baddr) = 0; 66 ULCON(baddr) = 0;
46 UMCON(baddr) = 0; 67 UMCON(baddr) = 0;
47 UFCON(baddr) = UFCON_RX_FIFO_RST_BIT | UFCON_TX_FIFO_RST_BIT; 68 UFCON(baddr) = UFCON_RX_FIFO_RST_BIT | UFCON_TX_FIFO_RST_BIT;
48 /* clear all interrupts */ 69 UTRSTAT(baddr) = ~0; /* clear all interrupts */
49 UTRSTAT(baddr) = UTRSTAT_RX_RELATED_INTS
50 | UTRSTAT_TX_INT_BIT
51 | UTRSTAT_MODEM_INT_BIT;
52 UBRDIV(baddr) = 0; 70 UBRDIV(baddr) = 0;
71#if CONFIG_CPU == S5L8702
53 UBRCONTX(baddr) = 0; 72 UBRCONTX(baddr) = 0;
54 UBRCONRX(baddr) = 0; 73 UBRCONRX(baddr) = 0;
74#endif
55 75
56 uartc->port_l[id] = (void*)0; 76 uartc->port_l[port_id] = (void*)0;
57} 77}
58 78
59static void uartc_reset(struct uartc* uartc) 79static void uartc_reset(const struct uartc* uartc)
60{ 80{
61 for (int id = 0; id < UART_PORT_MAX; id++) 81 for (int port_id = 0; port_id < uartc->n_ports; port_id++)
62 uartc_port_id_reset(uartc, id); 82 uartc_reset_port_id(uartc, port_id);
63} 83}
64 84
65void uartc_open(struct uartc* uartc) 85void uartc_open(const struct uartc *uartc)
66 __attribute__((alias("uartc_reset"))); 86{
87 uart_target_enable_clocks(uartc->id);
88 uartc_reset(uartc);
89}
67 90
68void uartc_close(struct uartc* uartc) 91void uartc_close(const struct uartc *uartc)
69 __attribute__((alias("uartc_reset"))); 92{
93 uartc_reset(uartc);
94 uart_target_disable_clocks(uartc->id);
95}
70 96
71void uartc_port_open(struct uartc_port *port) 97void uartc_port_open(struct uartc_port *port)
72{ 98{
73 struct uartc *uartc = port->uartc; 99 const struct uartc *uartc = port->uartc;
74 uint32_t baddr = UART_PORT_BASE(uartc->baddr, port->id); 100 uint32_t baddr = UART_PORT_BASE(uartc, port->id);
75 101
76 port->baddr = baddr; 102 uart_target_enable_gpio(uartc->id, port->id);
77 port->utrstat_int_mask = (port->rx_cb ? UTRSTAT_RX_RELATED_INTS : 0)
78 | (port->tx_cb ? UTRSTAT_TX_INT_BIT : 0);
79 port->abr_aborted = 0;
80 103
81 /* disable Tx/Rx and mask all interrupts */ 104 /* disable Tx/Rx and mask all interrupts */
82 UCON(baddr) = 0; 105 UCON(baddr) = 0;
83 106
84 /* clear all interrupts */ 107 /* clear all interrupts */
85 UTRSTAT(baddr) = UTRSTAT_RX_RELATED_INTS 108 UTRSTAT(baddr) = ~0;
86 | UTRSTAT_TX_INT_BIT
87 | UTRSTAT_MODEM_INT_BIT;
88 109
89 /* configure registers */ 110 /* configure registers */
90 UFCON(baddr) = UFCON_FIFO_ENABLE_BIT 111 UFCON(baddr) = UFCON_FIFO_ENABLE_BIT
91 | UFCON_RX_FIFO_RST_BIT 112 | UFCON_RX_FIFO_RST_BIT
92 | UFCON_TX_FIFO_RST_BIT 113 | UFCON_TX_FIFO_RST_BIT
93 | ((port->rx_trg & UFCON_RX_FIFO_TRG_MASK) << UFCON_RX_FIFO_TRG_POS) 114 | ((port->rx_trg & UFCON_RX_FIFO_TRG_MASK) << UFCON_RX_FIFO_TRG_POS)
94 | ((port->tx_trg & UFCON_TX_FIFO_TRG_MASK) << UFCON_TX_FIFO_TRG_POS); 115 | ((port->tx_trg & UFCON_TX_FIFO_TRG_MASK) << UFCON_TX_FIFO_TRG_POS);
95 116
96 UMCON(baddr) = UMCON_RTS_BIT; /* activate nRTS (low level) */ 117 UMCON(baddr) = UMCON_RTS_BIT; /* activate nRTS (low level) */
97 118
@@ -101,38 +122,59 @@ void uartc_port_open(struct uartc_port *port)
101 | (port->rx_cb ? UCON_RX_RELATED_INTS|UCON_RX_TOUT_EN_BIT : 0) 122 | (port->rx_cb ? UCON_RX_RELATED_INTS|UCON_RX_TOUT_EN_BIT : 0)
102 | (port->tx_cb ? UCON_TX_INT_BIT : 0); 123 | (port->tx_cb ? UCON_TX_INT_BIT : 0);
103 124
104 /* register port on parent controller */ 125 /* init and register port struct */
126 port->baddr = baddr;
127 port->utrstat_int_mask = (port->rx_cb ? UTRSTAT_RX_RELATED_INTS : 0)
128 | (port->tx_cb ? UTRSTAT_TX_INT_BIT : 0);
129#if CONFIG_CPU != S5L8700
130 port->abr_aborted = 0;
131#endif
105 uartc->port_l[port->id] = port; 132 uartc->port_l[port->id] = port;
133
134 /* enable interrupts */
135 uart_target_clear_irq(uartc->id, port->id);
136 /*if (port->utrstat_int_mask)*/
137 uart_target_enable_irq(uartc->id, port->id);
106} 138}
107 139
108void uartc_port_close(struct uartc_port *port) 140void uartc_port_close(struct uartc_port *port)
109{ 141{
110 uartc_port_id_reset(port->uartc, port->id); 142 uartc_reset_port_id(port->uartc, port->id);
111} 143}
112 144
113/* Configuration */ 145/* Configuration */
114void uartc_port_config(struct uartc_port *port, unsigned int speed, 146void uartc_port_config(struct uartc_port *port,
115 uint8_t data_bits, uint8_t parity, uint8_t stop_bits) 147 uint8_t data_bits, uint8_t parity, uint8_t stop_bits)
116{ 148{
117 uint32_t baddr = port->baddr; 149 ULCON(port->baddr) = ((parity & ULCON_PARITY_MASK) << ULCON_PARITY_POS)
118 150 | ((stop_bits & ULCON_STOP_BITS_MASK) << ULCON_STOP_BITS_POS)
119 ULCON(baddr) = ((parity & ULCON_PARITY_MASK) << ULCON_PARITY_POS) 151 | ((data_bits & ULCON_DATA_BITS_MASK) << ULCON_DATA_BITS_POS);
120 | ((stop_bits & ULCON_STOP_BITS_MASK) << ULCON_STOP_BITS_POS) 152}
121 | ((data_bits & ULCON_DATA_BITS_MASK) << ULCON_DATA_BITS_POS);
122 153
123 uartc_port_set_bitrate(port, speed); 154/* set bitrate using precalculated values */
155void uartc_port_set_bitrate_raw(struct uartc_port *port, uint32_t brdata)
156{
157 uint32_t baddr = port->baddr;
158 UBRDIV(baddr) = brdata & 0xff;
159#if CONFIG_CPU == S5L8702
160 UBRCONRX(baddr) = brdata >> 8;
161 UBRCONTX(baddr) = brdata >> 8;
162#endif
124} 163}
125 164
165#if 0
166/* calculate values to set real bitrate as close as possible to the
167 requested speed */
126void uartc_port_set_bitrate(struct uartc_port *port, unsigned int speed) 168void uartc_port_set_bitrate(struct uartc_port *port, unsigned int speed)
127{ 169{
128 uint32_t baddr = port->baddr;
129 int uclk = port->clkhz; 170 int uclk = port->clkhz;
130 171
131 /* Real baud width in UCLK/16 ticks: trunc(UCLK/(16*speed) + 0.5) */ 172 /* Real baud width in UCLK/16 ticks: trunc(UCLK/(16*speed) + 0.5) */
132 int brdiv = (uclk + (speed << 3)) / (speed << 4); 173 int brdiv = (uclk + (speed << 3)) / (speed << 4);
133 174
134 UBRDIV(baddr) = brdiv - 1; 175 uint32_t brdata = brdiv - 1;
135 176
177#if CONFIG_CPU == S5L8702
136 /* Fine adjust: 178 /* Fine adjust:
137 * 179 *
138 * Along the whole frame, insert/remove "jittered" bauds when needed 180 * Along the whole frame, insert/remove "jittered" bauds when needed
@@ -158,7 +200,6 @@ void uartc_port_set_bitrate(struct uartc_port *port, unsigned int speed)
158 200
159 int err_width = 0; 201 int err_width = 0;
160 uint32_t brcon = 0; 202 uint32_t brcon = 0;
161 /* TODO: for (bit < configured frame length) */
162 for (int bit = 0; bit < UC_FRAME_MAX_LEN; bit++) { 203 for (int bit = 0; bit < UC_FRAME_MAX_LEN; bit++) {
163 err_width += baud_err_width; 204 err_width += baud_err_width;
164 /* adjust to the nearest width */ 205 /* adjust to the nearest width */
@@ -168,24 +209,25 @@ void uartc_port_set_bitrate(struct uartc_port *port, unsigned int speed)
168 } 209 }
169 } 210 }
170 211
171 UBRCONRX(baddr) = brcon; 212 brdata |= (brcon << 8);
172 UBRCONTX(baddr) = brcon; 213#endif /* CONFIG_CPU == S5L8702 */
173}
174 214
175/* TODO: uarc_port_set_bitrate_raw() using precalculated values */ 215 uartc_port_set_rawbr(port, brdata);
216}
217#endif
176 218
177/* Select Tx/Rx modes: disabling Tx/Rx resets HW, including 219/* Select Tx/Rx modes: disabling Tx/Rx resets HW, including
178 FIFOs and shift registers */ 220 FIFOs and shift registers */
179void uartc_port_set_rx_mode(struct uartc_port *port, uint32_t mode) 221void uartc_port_set_rx_mode(struct uartc_port *port, uint32_t mode)
180{ 222{
181 UCON(port->baddr) = (mode << UCON_RX_MODE_POS) | 223 UCON(port->baddr) = (mode << UCON_RX_MODE_POS) |
182 (UCON(port->baddr) & ~(UCON_RX_MODE_MASK << UCON_RX_MODE_POS)); 224 (_UCON_RD(port->baddr) & ~(UCON_RX_MODE_MASK << UCON_RX_MODE_POS));
183} 225}
184 226
185void uartc_port_set_tx_mode(struct uartc_port *port, uint32_t mode) 227void uartc_port_set_tx_mode(struct uartc_port *port, uint32_t mode)
186{ 228{
187 UCON(port->baddr) = (mode << UCON_TX_MODE_POS) | 229 UCON(port->baddr) = (mode << UCON_TX_MODE_POS) |
188 (UCON(port->baddr) & ~(UCON_TX_MODE_MASK << UCON_TX_MODE_POS)); 230 (_UCON_RD(port->baddr) & ~(UCON_TX_MODE_MASK << UCON_TX_MODE_POS));
189} 231}
190 232
191/* Transmit */ 233/* Transmit */
@@ -197,7 +239,7 @@ bool uartc_port_tx_ready(struct uartc_port *port)
197void uartc_port_tx_byte(struct uartc_port *port, uint8_t ch) 239void uartc_port_tx_byte(struct uartc_port *port, uint8_t ch)
198{ 240{
199 UTXH(port->baddr) = ch; 241 UTXH(port->baddr) = ch;
200#ifdef UC8702_DEBUG 242#ifdef UC870X_DEBUG
201 port->n_tx_bytes++; 243 port->n_tx_bytes++;
202#endif 244#endif
203} 245}
@@ -227,6 +269,7 @@ uint8_t uartc_port_read_byte(struct uartc_port *port)
227 return uartc_port_rx_byte(port); 269 return uartc_port_rx_byte(port);
228} 270}
229 271
272#if CONFIG_CPU != S5L8700
230/* Autobauding */ 273/* Autobauding */
231static inline int uartc_port_abr_status(struct uartc_port *port) 274static inline int uartc_port_abr_status(struct uartc_port *port)
232{ 275{
@@ -236,7 +279,7 @@ static inline int uartc_port_abr_status(struct uartc_port *port)
236void uartc_port_abr_start(struct uartc_port *port) 279void uartc_port_abr_start(struct uartc_port *port)
237{ 280{
238 port->abr_aborted = 0; 281 port->abr_aborted = 0;
239 UCON(port->baddr) |= UCON_AUTOBR_START_BIT; 282 UCON(port->baddr) = _UCON_RD(port->baddr) | UCON_AUTOBR_START_BIT;
240} 283}
241 284
242void uartc_port_abr_stop(struct uartc_port *port) 285void uartc_port_abr_stop(struct uartc_port *port)
@@ -255,13 +298,14 @@ void uartc_port_abr_stop(struct uartc_port *port)
255 */ 298 */
256 port->abr_aborted = 1; 299 port->abr_aborted = 1;
257 else 300 else
258 UCON(port->baddr) &= ~UCON_AUTOBR_START_BIT; 301 UCON(port->baddr) = _UCON_RD(port->baddr) & ~UCON_AUTOBR_START_BIT;
259} 302}
303#endif /* CONFIG_CPU != S5L8700 */
260 304
261/* ISR */ 305/* ISR */
262void ICODE_ATTR uartc_callback(struct uartc *uartc, int id) 306void ICODE_ATTR uartc_callback(const struct uartc* uartc, int port_id)
263{ 307{
264 struct uartc_port *port = uartc->port_l[id]; 308 struct uartc_port *port = uartc->port_l[port_id];
265 uint32_t baddr = port->baddr; 309 uint32_t baddr = port->baddr;
266 310
267 /* filter registered interrupts */ 311 /* filter registered interrupts */
@@ -274,23 +318,25 @@ void ICODE_ATTR uartc_callback(struct uartc *uartc, int id)
274 if (ints & UTRSTAT_RX_RELATED_INTS) 318 if (ints & UTRSTAT_RX_RELATED_INTS)
275 { 319 {
276 int len = 0; 320 int len = 0;
321#if CONFIG_CPU != S5L8700
277 uint32_t abr_cnt = 0; 322 uint32_t abr_cnt = 0;
278 323
279 if (ints & UTRSTAT_AUTOBR_INT_BIT) 324 if (ints & UTRSTAT_AUTOBR_INT_BIT)
280 { 325 {
281 if (uartc_port_abr_status(port) == UABRSTAT_STATUS_COUNTING) { 326 if (uartc_port_abr_status(port) == UABRSTAT_STATUS_COUNTING) {
282 #ifdef UC8702_DEBUG 327 #ifdef UC870X_DEBUG
283 if (UCON(baddr) & UCON_AUTOBR_START_BIT) port->n_abnormal0++; 328 if (_UCON_RD(baddr) & UCON_AUTOBR_START_BIT) port->n_abnormal0++;
284 else port->n_abnormal1++; 329 else port->n_abnormal1++;
285 #endif 330 #endif
286 /* try to fix abnormal situations */ 331 /* try to fix abnormal situations */
287 UCON(baddr) |= UCON_AUTOBR_START_BIT; 332 UCON(baddr) = _UCON_RD(baddr) | UCON_AUTOBR_START_BIT;
288 } 333 }
289 else if (!port->abr_aborted) 334 else if (!port->abr_aborted)
290 abr_cnt = UABRCNT(baddr); 335 abr_cnt = UABRCNT(baddr);
291 } 336 }
292 337
293 if (ints & (UTRSTAT_RX_RELATED_INTS ^ UTRSTAT_AUTOBR_INT_BIT)) 338 if (ints & (UTRSTAT_RX_RELATED_INTS ^ UTRSTAT_AUTOBR_INT_BIT))
339#endif /* CONFIG_CPU != S5L8700 */
294 { 340 {
295 /* get FIFO count */ 341 /* get FIFO count */
296 uint32_t ufstat = UFSTAT(baddr); 342 uint32_t ufstat = UFSTAT(baddr);
@@ -304,15 +350,19 @@ void ICODE_ATTR uartc_callback(struct uartc *uartc, int id)
304 } 350 }
305 } 351 }
306 352
307 /* 'abr_cnt' is zero when no ABR interrupt exists, 'len' 353 /* 'len' might be zero due to RX_TOUT interrupts are
308 * might be zero due to RX_TOUT interrupts are raised by 354 * raised by the hardware even when RX FIFO is empty.
309 * the hardware even when RX FIFO is empty. 355 * When overrun, it is marked on the first error:
310 * When overrun, it is marked on the first readed error:
311 * overrun = len ? (rx_err[0] & UERSTAT_OVERRUN_BIT) : 0 356 * overrun = len ? (rx_err[0] & UERSTAT_OVERRUN_BIT) : 0
312 */ 357 */
358#if CONFIG_CPU == S5L8700
359 port->rx_cb(len, port->rx_data, port->rx_err);
360#else
361 /* 'abr_cnt' is zero when no ABR interrupt exists */
313 port->rx_cb(len, port->rx_data, port->rx_err, abr_cnt); 362 port->rx_cb(len, port->rx_data, port->rx_err, abr_cnt);
363#endif
314 364
315 #ifdef UC8702_DEBUG 365#ifdef UC870X_DEBUG
316 if (len) { 366 if (len) {
317 port->n_rx_bytes += len; 367 port->n_rx_bytes += len;
318 if (port->rx_err[0] & UERSTAT_OVERRUN_BIT) 368 if (port->rx_err[0] & UERSTAT_OVERRUN_BIT)
@@ -326,24 +376,25 @@ void ICODE_ATTR uartc_callback(struct uartc *uartc, int id)
326 port->n_break_detect++; 376 port->n_break_detect++;
327 } 377 }
328 } 378 }
329 #endif 379#endif
330 } 380 }
331 381
332 #if 0 382#if 0
333 /* not used and not tested */ 383 /* not used and not tested */
334 if (ints & UTRSTAT_TX_INT_BIT) 384 if (ints & UTRSTAT_TX_INT_BIT)
335 { 385 {
336 port->tx_cb(UART_FIFO_SIZE - ((UFSTAT(baddr) & \ 386 port->tx_cb(UART_FIFO_SIZE - ((UFSTAT(baddr) & \
337 UFSTAT_TX_FIFO_CNT_MASK) >> UFSTAT_TX_FIFO_CNT_POS)); 387 UFSTAT_TX_FIFO_CNT_MASK) >> UFSTAT_TX_FIFO_CNT_POS));
338 } 388 }
339 #endif 389#endif
340} 390}
341 391
342 392
343#ifdef UC8702_DEBUG 393#ifdef UC870X_DEBUG
344/*#define LOGF_ENABLE*/ 394/*#define LOGF_ENABLE*/
345#include "logf.h" 395#include "logf.h"
346 396
397#if CONFIG_CPU == S5L8702
347static int get_bitrate(int uclk, int brdiv, int brcon, int frame_len) 398static int get_bitrate(int uclk, int brdiv, int brcon, int frame_len)
348{ 399{
349 logf("get_bitrate(%d, %d, 0x%08x, %d)", uclk, brdiv, brcon, frame_len); 400 logf("get_bitrate(%d, %d, 0x%08x, %d)", uclk, brdiv, brcon, frame_len);
@@ -375,6 +426,7 @@ static int get_bitrate(int uclk, int brdiv, int brcon, int frame_len)
375 426
376 return avg_speed; 427 return avg_speed;
377} 428}
429#endif /* CONFIG_CPU == S5L8702 */
378 430
379void uartc_port_get_line_info(struct uartc_port *port, 431void uartc_port_get_line_info(struct uartc_port *port,
380 int *tx_status, int *rx_status, 432 int *tx_status, int *rx_status,
@@ -382,25 +434,32 @@ void uartc_port_get_line_info(struct uartc_port *port,
382{ 434{
383 uint32_t baddr = port->baddr; 435 uint32_t baddr = port->baddr;
384 436
385 uint32_t ucon = UCON(baddr); 437 uint32_t ucon = _UCON_RD(baddr);
386 if (*tx_status) 438 if (tx_status)
387 *tx_status = ((ucon >> UCON_TX_MODE_POS) & UCON_TX_MODE_MASK) ? 1 : 0; 439 *tx_status = ((ucon >> UCON_TX_MODE_POS) & UCON_TX_MODE_MASK) ? 1 : 0;
388 if (*rx_status) 440 if (rx_status)
389 *rx_status = ((ucon >> UCON_RX_MODE_POS) & UCON_RX_MODE_MASK) ? 1 : 0; 441 *rx_status = ((ucon >> UCON_RX_MODE_POS) & UCON_RX_MODE_MASK) ? 1 : 0;
390 442
391 uint32_t ulcon = ULCON(baddr); 443 uint32_t ulcon = ULCON(baddr);
392 int n_data = ((ulcon >> ULCON_DATA_BITS_POS) & ULCON_DATA_BITS_MASK) + 5; 444 int n_data = ((ulcon >> ULCON_DATA_BITS_POS) & ULCON_DATA_BITS_MASK) + 5;
393 int n_stop = ((ulcon >> ULCON_STOP_BITS_POS) & ULCON_STOP_BITS_MASK) + 1; 445 int n_stop = ((ulcon >> ULCON_STOP_BITS_POS) & ULCON_STOP_BITS_MASK) + 1;
394 int parity = (ulcon >> ULCON_PARITY_POS) & ULCON_PARITY_MASK; 446 int parity = (ulcon >> ULCON_PARITY_POS) & ULCON_PARITY_MASK;
395 int frame_len = 1 + n_data + (parity ? 1 : 0) + n_stop;
396 447
397 uint32_t brdiv = UBRDIV(baddr) + 1; 448 uint32_t brdiv = UBRDIV(baddr) + 1;
398 if (*tx_speed) 449#if CONFIG_CPU == S5L8702
450 int frame_len = 1 + n_data + (parity ? 1 : 0) + n_stop;
451 if (tx_speed)
399 *tx_speed = get_bitrate(port->clkhz, brdiv, UBRCONTX(baddr), frame_len); 452 *tx_speed = get_bitrate(port->clkhz, brdiv, UBRCONTX(baddr), frame_len);
400 if (*rx_speed) 453 if (rx_speed)
401 *rx_speed = get_bitrate(port->clkhz, brdiv, UBRCONRX(baddr), frame_len); 454 *rx_speed = get_bitrate(port->clkhz, brdiv, UBRCONRX(baddr), frame_len);
455#else
456 /* speed = truncate(UCLK/(16*brdiv) + 0.5) */
457 int speed = (port->clkhz + (brdiv << 3)) / (brdiv << 4);
458 if (tx_speed) *tx_speed = speed;
459 if (rx_speed) *rx_speed = speed;
460#endif
402 461
403 if (*line_cfg) { 462 if (line_cfg) {
404 line_cfg[0] = '0' + n_data; 463 line_cfg[0] = '0' + n_data;
405 line_cfg[1] = ((parity == ULCON_PARITY_NONE) ? 'N' : 464 line_cfg[1] = ((parity == ULCON_PARITY_NONE) ? 'N' :
406 ((parity == ULCON_PARITY_EVEN) ? 'E' : 465 ((parity == ULCON_PARITY_EVEN) ? 'E' :
@@ -412,18 +471,18 @@ void uartc_port_get_line_info(struct uartc_port *port,
412 } 471 }
413} 472}
414 473
474#if CONFIG_CPU != S5L8700
415/* Autobauding */ 475/* Autobauding */
416int uartc_port_get_abr_info(struct uartc_port *port, unsigned int *abr_cnt) 476int uartc_port_get_abr_info(struct uartc_port *port, uint32_t *abr_cnt)
417{ 477{
418 int status; 478 int status;
419 uint32_t abr_status; 479 uint32_t abr_status;
420 uint32_t baddr = port->baddr;
421 480
422 int flags = disable_irq_save(); 481 int flags = disable_irq_save();
423 482
424 abr_status = uartc_port_abr_status(port); 483 abr_status = uartc_port_abr_status(port);
425 484
426 if (UCON(port->baddr) & UCON_AUTOBR_START_BIT) { 485 if (_UCON_RD(port->baddr) & UCON_AUTOBR_START_BIT) {
427 if (abr_status == UABRSTAT_STATUS_COUNTING) 486 if (abr_status == UABRSTAT_STATUS_COUNTING)
428 status = ABR_INFO_ST_COUNTING; /* waiting for rising edge */ 487 status = ABR_INFO_ST_COUNTING; /* waiting for rising edge */
429 else 488 else
@@ -436,11 +495,12 @@ int uartc_port_get_abr_info(struct uartc_port *port, unsigned int *abr_cnt)
436 status = ABR_INFO_ST_IDLE; 495 status = ABR_INFO_ST_IDLE;
437 } 496 }
438 497
439 if (*abr_cnt) 498 if (abr_cnt)
440 *abr_cnt = UABRCNT(baddr); 499 *abr_cnt = UABRCNT(port->baddr);
441 500
442 restore_irq(flags); 501 restore_irq(flags);
443 502
444 return status; 503 return status;
445} 504}
446#endif /* UC8702_DEBUG */ 505#endif /* CONFIG_CPU != S5L8700 */
506#endif /* UC870X_DEBUG */