summaryrefslogtreecommitdiff
path: root/firmware/export/uc870x.h
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/export/uc870x.h
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/export/uc870x.h')
-rw-r--r--firmware/export/uc870x.h372
1 files changed, 372 insertions, 0 deletions
diff --git a/firmware/export/uc870x.h b/firmware/export/uc870x.h
new file mode 100644
index 0000000000..ad7168fe64
--- /dev/null
+++ b/firmware/export/uc870x.h
@@ -0,0 +1,372 @@
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 __UC870X_H__
22#define __UC870X_H__
23
24#include <stdint.h>
25#include <stdbool.h>
26
27#include "config.h"
28#include "system.h"
29#include "uart-target.h"
30
31
32/*
33 * UC870x: UART controller for s5l870x
34 *
35 * This UART is similar to the UART described in s5l8700 datasheet,
36 * (see also s3c2416 and s3c6400 datasheets). On s5l8701/2 the UC870x
37 * includes autobauding, and fine tunning for Tx/Rx on s5l8702.
38 */
39
40/*
41 * Controller registers
42 */
43#define REG32_PTR_T volatile uint32_t *
44
45#define ULCON(ba) (*((REG32_PTR_T)((ba) + 0x00))) /* line control */
46#define UCON(ba) (*((REG32_PTR_T)((ba) + 0x04))) /* control */
47#define UFCON(ba) (*((REG32_PTR_T)((ba) + 0x08))) /* FIFO control */
48#define UMCON(ba) (*((REG32_PTR_T)((ba) + 0x0C))) /* modem control */
49#define UTRSTAT(ba) (*((REG32_PTR_T)((ba) + 0x10))) /* Tx/Rx status */
50#define UERSTAT(ba) (*((REG32_PTR_T)((ba) + 0x14))) /* Rx error status */
51#define UFSTAT(ba) (*((REG32_PTR_T)((ba) + 0x18))) /* FIFO status */
52#define UMSTAT(ba) (*((REG32_PTR_T)((ba) + 0x1C))) /* modem status */
53#define UTXH(ba) (*((REG32_PTR_T)((ba) + 0x20))) /* transmission hold */
54#define URXH(ba) (*((REG32_PTR_T)((ba) + 0x24))) /* receive buffer */
55#define UBRDIV(ba) (*((REG32_PTR_T)((ba) + 0x28))) /* baud rate divisor */
56#if CONFIG_CPU != S5L8700
57#define UABRCNT(ba) (*((REG32_PTR_T)((ba) + 0x2c))) /* autobaud counter */
58#define UABRSTAT(ba) (*((REG32_PTR_T)((ba) + 0x30))) /* autobaud status */
59#endif
60#if CONFIG_CPU == S5L8702
61#define UBRCONTX(ba) (*((REG32_PTR_T)((ba) + 0x34))) /* Tx frame config */
62#define UBRCONRX(ba) (*((REG32_PTR_T)((ba) + 0x38))) /* Rx frame config */
63#endif
64
65/* ULCON register */
66#define ULCON_DATA_BITS_MASK 0x3
67#define ULCON_DATA_BITS_POS 0
68#define ULCON_DATA_BITS_5 0
69#define ULCON_DATA_BITS_6 1
70#define ULCON_DATA_BITS_7 2
71#define ULCON_DATA_BITS_8 3
72
73#define ULCON_STOP_BITS_MASK 0x1
74#define ULCON_STOP_BITS_POS 2
75#define ULCON_STOP_BITS_1 0
76#define ULCON_STOP_BITS_2 1
77
78#define ULCON_PARITY_MASK 0x7
79#define ULCON_PARITY_POS 3
80#define ULCON_PARITY_NONE 0
81#define ULCON_PARITY_ODD 4
82#define ULCON_PARITY_EVEN 5
83#define ULCON_PARITY_FORCE_1 6
84#define ULCON_PARITY_FORCE_0 7
85
86#define ULCON_INFRARED_EN_BIT (1 << 6)
87
88/* UCON register */
89#define UCON_RX_MODE_MASK 0x3
90#define UCON_RX_MODE_POS 0
91
92#define UCON_TX_MODE_MASK 0x3
93#define UCON_TX_MODE_POS 2
94
95#define UCON_MODE_DISABLED 0
96#define UCON_MODE_INTREQ 1 /* INT request or polling mode */
97#define UCON_MODE_UNDEFINED 2 /* Not defined, DMAREQ signal 1 ??? */
98#define UCON_MODE_DMAREQ 3 /* DMA request (signal 0) */
99
100#define UCON_SEND_BREAK_BIT (1 << 4)
101#define UCON_LOOPBACK_BIT (1 << 5)
102#define UCON_RX_TOUT_EN_BIT (1 << 7) /* Rx timeout enable */
103
104#define UCON_CLKSEL_MASK 0x1
105#define UCON_CLKSEL_POS 10
106#define UCON_CLKSEL_PCLK 0 /* internal */
107#define UCON_CLKSEL_ECLK 1 /* external */
108
109#if CONFIG_CPU == S5L8702
110#define UCON_RX_TOUT_INT_BIT (1 << 11) /* Rx timeout INT enable */
111#endif
112#define UCON_RX_INT_BIT (1 << 12) /* Rx INT enable */
113#define UCON_TX_INT_BIT (1 << 13) /* Tx INT enable */
114#define UCON_ERR_INT_BIT (1 << 14) /* Rx error INT enable */
115#define UCON_MODEM_INT_BIT (1 << 15) /* modem INT enable (TBC) */
116#if CONFIG_CPU != S5L8700
117#define UCON_AUTOBR_INT_BIT (1 << 16) /* autobauding INT enable */
118#define UCON_AUTOBR_START_BIT (1 << 17) /* autobauding start/stop */
119#endif
120
121#if CONFIG_CPU == S5L8701
122/* WTF! ABR bits are swapped on reads, so don't forget to
123 always use this workaround to read the UCON register. */
124static inline uint32_t _UCON_RD(uint32_t ba)
125{
126 uint32_t ucon = UCON(ba);
127 return ((ucon & 0xffff) |
128 ((ucon & UCON_AUTOBR_INT_BIT) << 1) |
129 ((ucon & UCON_AUTOBR_START_BIT) >> 1));
130}
131#else
132#define _UCON_RD(ba) UCON(ba)
133#endif
134
135/* UFCON register */
136#define UFCON_FIFO_ENABLE_BIT (1 << 0)
137#define UFCON_RX_FIFO_RST_BIT (1 << 1)
138#define UFCON_TX_FIFO_RST_BIT (1 << 2)
139
140#define UFCON_RX_FIFO_TRG_MASK 0x3
141#define UFCON_RX_FIFO_TRG_POS 4
142#define UFCON_RX_FIFO_TRG_4 0
143#define UFCON_RX_FIFO_TRG_8 1
144#define UFCON_RX_FIFO_TRG_12 2
145#define UFCON_RX_FIFO_TRG_16 3
146
147#define UFCON_TX_FIFO_TRG_MASK 0x3
148#define UFCON_TX_FIFO_TRG_POS 6
149#define UFCON_TX_FIFO_TRG_EMPTY 0
150#define UFCON_TX_FIFO_TRG_4 1
151#define UFCON_TX_FIFO_TRG_8 2
152#define UFCON_TX_FIFO_TRG_12 3
153
154/* UMCON register */
155#define UMCON_RTS_BIT (1 << 0)
156#define UMCON_AUTO_FLOW_CTRL_BIT (1 << 4)
157
158/* UTRSTAT register */
159#define UTRSTAT_RXBUF_RDY_BIT (1 << 0)
160#define UTRSTAT_TXBUF_EMPTY_BIT (1 << 1)
161#define UTRSTAT_TX_EMPTY_BIT (1 << 2)
162#if CONFIG_CPU == S5L8702
163#define UTRSTAT_RX_TOUT_INT_BIT (1 << 3) /* Rx timeout INT status */
164#endif
165#define UTRSTAT_RX_INT_BIT (1 << 4)
166#define UTRSTAT_TX_INT_BIT (1 << 5)
167#define UTRSTAT_ERR_INT_BIT (1 << 6)
168#define UTRSTAT_MODEM_INT_BIT (1 << 7) /* modem INT status */
169#if CONFIG_CPU != S5L8700
170#define UTRSTAT_AUTOBR_INT_BIT (1 << 8) /* autobauding INT status */
171#endif
172
173/* UERSTAT register */
174#define UERSTAT_OVERRUN_BIT (1 << 0)
175#define UERSTAT_PARITY_ERR_BIT (1 << 1)
176#define UERSTAT_FRAME_ERR_BIT (1 << 2)
177#define UERSTAT_BREAK_DETECT_BIT (1 << 3)
178
179/* UFSTAT register */
180#define UFSTAT_RX_FIFO_CNT_MASK 0xf
181#define UFSTAT_RX_FIFO_CNT_POS 0
182
183#define UFSTAT_TX_FIFO_CNT_MASK 0xf
184#define UFSTAT_TX_FIFO_CNT_POS 4
185
186#define UFSTAT_RX_FIFO_FULL_BIT (1 << 8)
187#define UFSTAT_TX_FIFO_FULL_BIT (1 << 9)
188#define UFSTAT_RX_FIFO_ERR_BIT (1 << 10) /* clears when reading UERSTAT
189 for the last pending error */
190/* UMSTAT register */
191#define UMSTAT_CTS_ACTIVE_BIT (1 << 0)
192#define UMSTAT_CTS_DELTA_BIT (1 << 4)
193
194
195#if CONFIG_CPU == S5L8702
196/* Bitrate:
197 *
198 * Master UCLK clock is divided by 16 to serialize data, UBRDIV is
199 * used to configure nominal bit width, NBW = (UBRDIV+1)*16 in UCLK
200 * clock ticks.
201 *
202 * Fine tuning works shrining/expanding each individual bit of each
203 * frame. Each bit width can be incremented/decremented by 1/16 of
204 * nominal bit width, it seems UCLK is divided by 17 for expanded
205 * bits and divided by 15 for compressed bits. A whole frame of N
206 * bits can be shrined or expanded up to (NBW * N / 16) UCLK clock
207 * ticks (in 1/16 steps).
208 */
209/* UBRCONx register */
210#define UC_FRAME_MAX_LEN 12 /* 1 start + 8 data + 1 par + 2 stop */
211#define UBRCON_JITTER_MASK 0x3
212#define UBRCON_JITTER_POS(bit) ((bit) << 1) /* 0..UC_FRAME_MAX_LEN-1 */
213
214#define UBRCON_JITTER_NONE 0 /* no jitter for this bit */
215#define UBRCON_JITTER_INC 1 /* increment 1/16 bit width */
216#define UBRCON_JITTER_UNUSED 2 /* does nothing */
217#define UBRCON_JITTER_DEC 3 /* decremet 1/16 bit width */
218#endif /* CONFIG_CPU == S5L8702 */
219
220
221#if CONFIG_CPU != S5L8700
222/* Autobauding:
223 *
224 * Initial UABRSTAT is NOT_INIT, it goes to READY when either of
225 * UCON_AUTOBR bits are enabled for the first time.
226 *
227 * Interrupts are enabled/disabled using UCON_AUTOBR_INT_BIT and
228 * checked using UTRSTAT_AUTOBR_INT_BIT, writing this bit cleans the
229 * interrupt.
230 *
231 * When UCON_AUTOBR_START_BIT is enabled, autobauding starts and the
232 * hardware waits for a low pulse on RX line.
233 *
234 * Once autobauding is started, when a falling edge is detected on
235 * the RX line, UABRSTAT changes to COUNTING status, an internal
236 * counter starts incrementing at UCLK clock frequency. During
237 * COUNTING state, UABRCNT reads as the value of the previous ABR
238 * count, not the value of the current internal count.
239 *
240 * Count finish when a rising edge is detected on the line, at this
241 * moment internal counter stops and it can be read using UABRCNT
242 * register, UABRSTAT goes to READY, AUTOBR_START_BIT is disabled,
243 * and an interrupt is raised if UCON_AUTOBR_INT_BIT is enabled.
244 */
245/* UABRSTAT register */
246#define UABRSTAT_STATUS_MASK 0x3
247#define UABRSTAT_STATUS_POS 0
248
249#define UABRSTAT_STATUS_NOT_INIT 0 /* initial status */
250#define UABRSTAT_STATUS_READY 1 /* machine is ready */
251#define UABRSTAT_STATUS_COUNTING 2 /* count in progress */
252#endif /* CONFIG_CPU != S5L8700 */
253
254
255/*
256 * other HW definitions
257 */
258#define UART_FIFO_SIZE 16
259
260
261/*
262 * structs
263 */
264struct uartc
265{
266 /* static configuration */
267 uint8_t id;
268 uint8_t n_ports;
269 uint16_t port_off;
270 uint32_t baddr;
271 struct uartc_port **port_l;
272};
273
274struct uartc_port
275{
276 /* static configuration */
277 const struct uartc * const uartc;
278 const uint8_t id; /* port number */
279 const uint8_t rx_trg; /* UFCON_RX_FIFO_TRG_xxx */
280 const uint8_t tx_trg; /* UFCON_TX_FIFO_TRG_xxx */
281 const uint8_t clksel; /* UFCON_CLKSEL_xxx */
282 const uint32_t clkhz; /* UCLK (PCLK or ECLK) frequency */
283 void (* const tx_cb) (int len); /* ISRs */
284#if CONFIG_CPU != S5L8700
285 void (* const rx_cb) (int len, char *data, char *err, uint32_t abr_cnt);
286#else
287 void (* const rx_cb) (int len, char *data, char *err);
288#endif
289
290 /* private */
291 uint32_t baddr;
292 uint32_t utrstat_int_mask;
293 uint8_t rx_data[UART_FIFO_SIZE]; /* data buffer for rx_cb */
294 uint8_t rx_err[UART_FIFO_SIZE]; /* error buffer for rx_cb */
295#if CONFIG_CPU != S5L8700
296 bool abr_aborted;
297#endif
298
299#ifdef UC870X_DEBUG
300 uint32_t n_tx_bytes;
301 uint32_t n_rx_bytes;
302 uint32_t n_ovr_err;
303 uint32_t n_parity_err;
304 uint32_t n_frame_err;
305 uint32_t n_break_detect;
306#if CONFIG_CPU != S5L8700
307 /* autobauding */
308 uint32_t n_abnormal0;
309 uint32_t n_abnormal1;
310#endif
311#endif
312};
313
314
315/*
316 * uc870x low level API
317 */
318
319/* Initialization */
320void uartc_open(const struct uartc* uartc);
321void uartc_close(const struct uartc* uartc);
322void uartc_port_open(struct uartc_port *port);
323void uartc_port_close(struct uartc_port *port);
324void uartc_port_rx_onoff(struct uartc_port *port, bool onoff);
325void uartc_port_tx_onoff(struct uartc_port *port, bool onoff);
326
327/* Configuration */
328void uartc_port_config(struct uartc_port *port,
329 uint8_t data_bits, uint8_t parity, uint8_t stop_bits);
330void uartc_port_set_bitrate_raw(struct uartc_port *port, uint32_t brdata);
331void uartc_port_set_bitrate(struct uartc_port *port, unsigned int speed);
332void uartc_port_set_rx_mode(struct uartc_port *port, uint32_t mode);
333void uartc_port_set_tx_mode(struct uartc_port *port, uint32_t mode);
334
335/* Transmit */
336bool uartc_port_tx_ready(struct uartc_port *port);
337void uartc_port_tx_byte(struct uartc_port *port, uint8_t ch);
338void uartc_port_send_byte(struct uartc_port *port, uint8_t ch);
339
340/* Receive */
341bool uartc_port_rx_ready(struct uartc_port *port);
342uint8_t uartc_port_rx_byte(struct uartc_port *port);
343uint8_t uartc_port_read_byte(struct uartc_port *port);
344
345#if CONFIG_CPU != S5L8700
346/* Autobauding */
347void uartc_port_abr_start(struct uartc_port *port);
348void uartc_port_abr_stop(struct uartc_port *port);
349#endif
350
351/* ISR */
352void uartc_callback(const struct uartc *uartc, int port_id);
353
354/* Debug */
355#ifdef UC870X_DEBUG
356void uartc_port_get_line_info(struct uartc_port *port,
357 int *tx_status, int *rx_status,
358 int *tx_speed, int *rx_speed, char *line_cfg);
359
360#if CONFIG_CPU != S5L8700
361enum {
362 ABR_INFO_ST_IDLE,
363 ABR_INFO_ST_LAUNCHED,
364 ABR_INFO_ST_COUNTING,
365 ABR_INFO_ST_ABNORMAL
366};
367
368int uartc_port_get_abr_info(struct uartc_port *port, uint32_t *abr_cnt);
369#endif
370#endif /* UC870X_DEBUG */
371
372#endif /* __UC870X_H__ */