4 * Copyright 2003, 2004 Develer S.r.l. (http://www.develer.com/)
5 * This file is part of DevLib - See README.devlib for information.
10 * \author Stefano Fedrigo <aleph@develer.com>
11 * \author Giovanni Bajo <rasky@develer.com>
13 * \brief DSP5680x CPU specific serial I/O driver
18 *#* Revision 1.13 2005/11/04 16:20:02 bernie
19 *#* Fix reference to README.devlib in header.
21 *#* Revision 1.12 2005/04/11 19:10:27 bernie
22 *#* Include top-level headers from cfg/ subdir.
24 *#* Revision 1.11 2005/01/25 07:42:04 bernie
27 *#* Revision 1.10 2005/01/14 00:48:33 aleph
28 *#* Rename callbacks; SerialHardwareVT.txSending: New callback.
30 *#* Revision 1.9 2004/12/08 09:42:55 bernie
31 *#* Add support for multiplexed serial ports.
33 *#* Revision 1.8 2004/10/26 09:00:49 bernie
34 *#* Don't access serial data register twice.
36 *#* Revision 1.7 2004/10/19 08:57:15 bernie
37 *#* Bugfixes for DSP56K serial driver from scfirm.
39 *#* Revision 1.5 2004/08/25 14:12:08 rasky
40 *#* Aggiornato il comment block dei log RCS
42 *#* Revision 1.4 2004/07/30 14:27:49 rasky
43 *#* Aggiornati alcuni file DSP56k per la nuova libreria di IRQ management
45 *#* Revision 1.3 2004/06/03 11:27:09 bernie
46 *#* Add dual-license information.
48 *#* Revision 1.2 2004/05/23 18:21:53 bernie
49 *#* Trim CVS logs and cleanup header info.
55 #include <cfg/debug.h>
57 #include <DSP56F807.h>
59 // GPIO E is shared with SPI (in DSP56807). Pins 0&1 are TXD0 and RXD0. To use
60 // the serial, we need to disable the GPIO functions on them.
61 #define REG_GPIO_SERIAL_0 REG_GPIO_E
62 #define REG_GPIO_SERIAL_MASK_0 0x03
64 #define REG_GPIO_SERIAL_1 REG_GPIO_D
65 #define REG_GPIO_SERIAL_MASK_1 0xC0
68 // Check flag consistency
69 #if (SERRF_PARITYERROR != REG_SCI_SR_PF) || \
70 (SERRF_RXSROVERRUN != REG_SCI_SR_OR) || \
71 (SERRF_FRAMEERROR != REG_SCI_SR_FE) || \
72 (SERRF_NOISEERROR != REG_SCI_SR_NF)
73 #error error flags do not match with register bits
76 static unsigned char ser0_fifo_rx[CONFIG_SER0_FIFOSIZE_RX];
77 static unsigned char ser0_fifo_tx[CONFIG_SER0_FIFOSIZE_TX];
78 static unsigned char ser1_fifo_rx[CONFIG_SER1_FIFOSIZE_RX];
79 static unsigned char ser1_fifo_tx[CONFIG_SER1_FIFOSIZE_TX];
84 #define MAX_MULTI_GROUPS 1
86 struct Semaphore multi_sems[MAX_MULTI_GROUPS];
92 struct SerialHardware hw;
93 struct Serial* serial;
94 volatile struct REG_SCI_STRUCT* regs;
101 static inline void enable_tx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
103 regs->CR |= REG_SCI_CR_TEIE | REG_SCI_CR_TIIE;
106 static inline void enable_rx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
108 regs->CR |= REG_SCI_CR_RIE;
111 static inline void disable_tx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
113 regs->CR &= ~(REG_SCI_CR_TEIE | REG_SCI_CR_TIIE);
116 static inline void disable_rx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
118 regs->CR &= ~(REG_SCI_CR_RIE | REG_SCI_CR_REIE);
121 static inline void disable_tx_irq(struct SerialHardware* _hw)
123 struct SCI* hw = (struct SCI*)_hw;
125 disable_tx_irq_bare(hw->regs);
128 static inline void disable_rx_irq(struct SerialHardware* _hw)
130 struct SCI* hw = (struct SCI*)_hw;
132 disable_rx_irq_bare(hw->regs);
135 static inline void enable_tx_irq(struct SerialHardware* _hw)
137 struct SCI* hw = (struct SCI*)_hw;
139 enable_tx_irq_bare(hw->regs);
142 static inline void enable_rx_irq(struct SerialHardware* _hw)
144 struct SCI* hw = (struct SCI*)_hw;
146 enable_rx_irq_bare(hw->regs);
149 static inline bool tx_irq_enabled(struct SerialHardware* _hw)
151 struct SCI* hw = (struct SCI*)_hw;
153 return (hw->regs->CR & REG_SCI_CR_TEIE);
156 static void tx_isr(const struct SCI *hw)
158 #pragma interrupt warn
159 volatile struct REG_SCI_STRUCT* regs = hw->regs;
161 if (fifo_isempty(&hw->serial->txfifo))
162 disable_tx_irq_bare(regs);
165 // Clear transmitter flags before sending data
167 regs->DR = fifo_pop(&hw->serial->txfifo);
171 static void rx_isr(const struct SCI *hw)
173 #pragma interrupt warn
174 volatile struct REG_SCI_STRUCT* regs = hw->regs;
177 hw->serial->status |= regs->SR & (SERRF_PARITYERROR |
183 * Serial IRQ can happen for two reason: data ready (RDRF) or overrun (OR)
184 * If the data is ready, we need to fetch it from the data register or
185 * the interrupt will retrigger immediatly. In case of overrun, instead,
186 * the value of the data register is meaningless.
188 if (regs->SR & REG_SCI_SR_RDRF)
190 unsigned char data = regs->DR;
192 if (fifo_isfull(&hw->serial->rxfifo))
193 hw->serial->status |= SERRF_RXFIFOOVERRUN;
195 fifo_push(&hw->serial->rxfifo, data);
198 // Writing anything to the status register clear the error bits.
202 static void init(struct SerialHardware* _hw, struct Serial* ser)
204 struct SCI* hw = (struct SCI*)_hw;
205 volatile struct REG_SCI_STRUCT* regs = hw->regs;
207 // Clear status register (IRQ/status flags)
211 // Clear data register
214 // Install the handlers and set priorities for both IRQs
215 irq_install(hw->irq_tx, (isr_t)tx_isr, hw);
216 irq_install(hw->irq_rx, (isr_t)rx_isr, hw);
217 irq_setpriority(hw->irq_tx, IRQ_PRIORITY_SCI_TX);
218 irq_setpriority(hw->irq_rx, IRQ_PRIORITY_SCI_RX);
220 // Activate the RX error interrupts, and RX/TX transmissions
221 regs->CR = REG_SCI_CR_TE | REG_SCI_CR_RE;
222 enable_rx_irq_bare(regs);
224 // Disable GPIO pins for TX and RX lines
225 // \todo this should be divided into serial 0 and 1
226 REG_GPIO_SERIAL_0->PER |= REG_GPIO_SERIAL_MASK_0;
227 REG_GPIO_SERIAL_1->PER |= REG_GPIO_SERIAL_MASK_1;
232 static void cleanup(struct SerialHardware* _hw)
234 struct SCI* hw = (struct SCI*)_hw;
236 // Uninstall the ISRs
239 irq_uninstall(hw->irq_tx);
240 irq_uninstall(hw->irq_rx);
243 static void setbaudrate(struct SerialHardware* _hw, unsigned long rate)
245 struct SCI* hw = (struct SCI*)_hw;
247 // SCI has an internal 16x divider on the input clock, which comes
248 // from the IPbus (see the scheme in user manual, 12.7.3). We apply
249 // it to calculate the period to store in the register.
250 hw->regs->BR = (IPBUS_FREQ + rate * 8ul) / (rate * 16ul);
253 static void setparity(struct SerialHardware* _hw, int parity)
262 static void multi_init(void)
264 static bool flag = false;
270 for (i = 0; i < MAX_MULTI_GROUPS; ++i)
271 sem_init(&multi_sems[i]);
275 static void init_lock(struct SerialHardware* _hw, struct Serial *ser)
277 struct SCI* hw = (struct SCI*)_hw;
279 // Initialize the multi engine (if needed)
282 // Acquire the lock of the semaphore for this group
283 ASSERT(hw->num_group >= 0);
284 ASSERT(hw->num_group < MAX_MULTI_GROUPS);
285 sem_obtain(&multi_sems[hw->num_group]);
287 // Do a hardware switch to the given serial
288 ser_hw_switch(hw->num_group, hw->id);
293 static void cleanup_unlock(struct SerialHardware* _hw)
295 struct SCI* hw = (struct SCI*)_hw;
299 sem_release(&multi_sems[hw->num_group]);
302 #endif /* CONFIG_SER_MULTI */
305 static const struct SerialHardwareVT SCI_VT =
309 .setBaudrate = setbaudrate,
310 .setParity = setparity,
311 .txStart = enable_tx_irq,
312 .txSending = tx_irq_enabled,
316 static const struct SerialHardwareVT SCI_MULTI_VT =
319 .cleanup = cleanup_unlock,
320 .setBaudrate = setbaudrate,
321 .setParity = setparity,
322 .txStart = enable_tx_irq,
323 .txSending = tx_irq_enabled,
325 #endif /* CONFIG_SER_MULTI */
327 #define SCI_DESC_NORMAL(hwch) \
332 .rxbuffer = ser ## hwch ## _fifo_rx, \
333 .txbuffer = ser ## hwch ## _fifo_tx, \
334 .rxbuffer_size = countof(ser ## hwch ## _fifo_rx), \
335 .txbuffer_size = countof(ser ## hwch ## _fifo_tx), \
337 .regs = ®_SCI[hwch], \
338 .irq_rx = IRQ_SCI ## hwch ## _RECEIVER_FULL, \
339 .irq_tx = IRQ_SCI ## hwch ## _TRANSMITTER_READY, \
346 #define SCI_DESC_MULTI(hwch, group_, id_) \
350 .table = &SCI_MULTI_VT, \
351 .rxbuffer = ser ## hwch ## _fifo_rx, \
352 .txbuffer = ser ## hwch ## _fifo_tx, \
353 .rxbuffer_size = countof(ser ## hwch ## _fifo_rx), \
354 .txbuffer_size = countof(ser ## hwch ## _fifo_tx), \
356 .regs = ®_SCI[hwch], \
357 .irq_rx = IRQ_SCI ## hwch ## _RECEIVER_FULL, \
358 .irq_tx = IRQ_SCI ## hwch ## _TRANSMITTER_READY, \
359 .num_group = group_, \
363 #endif /* CONFIG_SER_MULTI */
365 // \todo Move this into hw.h, with a little preprocessor magic
366 static struct SCI SCIDescs[] =
369 SCI_DESC_MULTI(1, 0, 0),
370 SCI_DESC_MULTI(1, 0, 1),
373 struct SerialHardware* ser_hw_getdesc(int unit)
375 ASSERT(unit < countof(SCIDescs));
376 return &SCIDescs[unit].hw;