4 * Copyright 2003, 2004 Develer S.r.l. (http://www.develer.com/)
5 * This file is part of DevLib - See devlib/README 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.10 2005/01/14 00:48:33 aleph
19 *#* Rename callbacks; SerialHardwareVT.txSending: New callback.
21 *#* Revision 1.9 2004/12/08 09:42:55 bernie
22 *#* Add support for multiplexed serial ports.
24 *#* Revision 1.8 2004/10/26 09:00:49 bernie
25 *#* Don't access serial data register twice.
27 *#* Revision 1.7 2004/10/19 08:57:15 bernie
28 *#* Bugfixes for DSP56K serial driver from scfirm.
30 *#* Revision 1.5 2004/08/25 14:12:08 rasky
31 *#* Aggiornato il comment block dei log RCS
33 *#* Revision 1.4 2004/07/30 14:27:49 rasky
34 *#* Aggiornati alcuni file DSP56k per la nuova libreria di IRQ management
36 *#* Revision 1.3 2004/06/03 11:27:09 bernie
37 *#* Add dual-license information.
39 *#* Revision 1.2 2004/05/23 18:21:53 bernie
40 *#* Trim CVS logs and cleanup header info.
48 #include <DSP56F807.h>
50 // GPIO E is shared with SPI (in DSP56807). Pins 0&1 are TXD0 and RXD0. To use
51 // the serial, we need to disable the GPIO functions on them.
52 #define REG_GPIO_SERIAL_0 REG_GPIO_E
53 #define REG_GPIO_SERIAL_MASK_0 0x03
55 #define REG_GPIO_SERIAL_1 REG_GPIO_D
56 #define REG_GPIO_SERIAL_MASK_1 0xC0
59 // Check flag consistency
60 #if (SERRF_PARITYERROR != REG_SCI_SR_PF) || \
61 (SERRF_RXSROVERRUN != REG_SCI_SR_OR) || \
62 (SERRF_FRAMEERROR != REG_SCI_SR_FE) || \
63 (SERRF_NOISEERROR != REG_SCI_SR_NF)
64 #error error flags do not match with register bits
67 static unsigned char ser0_fifo_rx[CONFIG_SER0_FIFOSIZE_RX];
68 static unsigned char ser0_fifo_tx[CONFIG_SER0_FIFOSIZE_TX];
69 static unsigned char ser1_fifo_rx[CONFIG_SER1_FIFOSIZE_RX];
70 static unsigned char ser1_fifo_tx[CONFIG_SER1_FIFOSIZE_TX];
75 #define MAX_MULTI_GROUPS 1
77 struct Semaphore multi_sems[MAX_MULTI_GROUPS];
83 struct SerialHardware hw;
84 struct Serial* serial;
85 volatile struct REG_SCI_STRUCT* regs;
92 static inline void enable_tx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
94 regs->CR |= REG_SCI_CR_TEIE | REG_SCI_CR_TIIE;
97 static inline void enable_rx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
99 regs->CR |= REG_SCI_CR_RIE;
102 static inline void disable_tx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
104 regs->CR &= ~(REG_SCI_CR_TEIE | REG_SCI_CR_TIIE);
107 static inline void disable_rx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
109 regs->CR &= ~(REG_SCI_CR_RIE | REG_SCI_CR_REIE);
112 static inline void disable_tx_irq(struct SerialHardware* _hw)
114 struct SCI* hw = (struct SCI*)_hw;
115 volatile struct REG_SCI_STRUCT* regs = hw->regs;
117 disable_tx_irq_bare(regs);
120 static inline void disable_rx_irq(struct SerialHardware* _hw)
122 struct SCI* hw = (struct SCI*)_hw;
123 volatile struct REG_SCI_STRUCT* regs = hw->regs;
125 disable_rx_irq_bare(regs);
128 static inline void enable_tx_irq(struct SerialHardware* _hw)
130 struct SCI* hw = (struct SCI*)_hw;
131 volatile struct REG_SCI_STRUCT* regs = hw->regs;
133 enable_tx_irq_bare(regs);
136 static inline void enable_rx_irq(struct SerialHardware* _hw)
138 struct SCI* hw = (struct SCI*)_hw;
139 volatile struct REG_SCI_STRUCT* regs = hw->regs;
141 enable_rx_irq_bare(regs);
144 static inline bool tx_irq_enabled(struct SerialHardware* _hw)
146 struct SCI* hw = (struct SCI*)_hw;
147 volatile struct REG_SCI_STRUCT* regs = hw->regs;
149 return (regs->CR & REG_SCI_CR_TEIE);
152 static void tx_isr(const struct SCI *hw)
154 #pragma interrupt warn
155 volatile struct REG_SCI_STRUCT* regs = hw->regs;
157 if (fifo_isempty(&hw->serial->txfifo))
158 disable_tx_irq_bare(regs);
161 // Clear transmitter flags before sending data
163 regs->DR = fifo_pop(&hw->serial->txfifo);
167 static void rx_isr(const struct SCI *hw)
169 #pragma interrupt warn
170 volatile struct REG_SCI_STRUCT* regs = hw->regs;
173 hw->serial->status |= regs->SR & (SERRF_PARITYERROR |
179 * Serial IRQ can happen for two reason: data ready (RDRF) or overrun (OR)
180 * If the data is ready, we need to fetch it from the data register or
181 * the interrupt will retrigger immediatly. In case of overrun, instead,
182 * the value of the data register is meaningless.
184 if (regs->SR & REG_SCI_SR_RDRF)
186 unsigned char data = regs->DR;
188 if (fifo_isfull(&hw->serial->rxfifo))
189 hw->serial->status |= SERRF_RXFIFOOVERRUN;
191 fifo_push(&hw->serial->rxfifo, data);
194 // Writing anything to the status register clear the error bits.
198 static void init(struct SerialHardware* _hw, struct Serial* ser)
200 struct SCI* hw = (struct SCI*)_hw;
201 volatile struct REG_SCI_STRUCT* regs = hw->regs;
203 // Clear status register (IRQ/status flags)
207 // Clear data register
210 // Install the handlers and set priorities for both IRQs
211 irq_install(hw->irq_tx, (isr_t)tx_isr, hw);
212 irq_install(hw->irq_rx, (isr_t)rx_isr, hw);
213 irq_setpriority(hw->irq_tx, IRQ_PRIORITY_SCI_TX);
214 irq_setpriority(hw->irq_rx, IRQ_PRIORITY_SCI_RX);
216 // Activate the RX error interrupts, and RX/TX transmissions
217 regs->CR = REG_SCI_CR_TE | REG_SCI_CR_RE;
218 enable_rx_irq_bare(regs);
220 // Disable GPIO pins for TX and RX lines
221 // \todo this should be divided into serial 0 and 1
222 REG_GPIO_SERIAL_0->PER |= REG_GPIO_SERIAL_MASK_0;
223 REG_GPIO_SERIAL_1->PER |= REG_GPIO_SERIAL_MASK_1;
228 static void cleanup(struct SerialHardware* _hw)
230 struct SCI* hw = (struct SCI*)_hw;
232 // Uninstall the ISRs
235 irq_uninstall(hw->irq_tx);
236 irq_uninstall(hw->irq_rx);
239 static void setbaudrate(struct SerialHardware* _hw, unsigned long rate)
241 struct SCI* hw = (struct SCI*)_hw;
243 // SCI has an internal 16x divider on the input clock, which comes
244 // from the IPbus (see the scheme in user manual, 12.7.3). We apply
245 // it to calculate the period to store in the register.
246 hw->regs->BR = (IPBUS_FREQ + rate * 8ul) / (rate * 16ul);
249 static void setparity(struct SerialHardware* _hw, int parity)
258 static void multi_init(void)
260 static bool flag = false;
266 for (i = 0; i < MAX_MULTI_GROUPS; ++i)
267 sem_init(&multi_sems[i]);
271 static void init_lock(struct SerialHardware* _hw, struct Serial *ser)
273 struct SCI* hw = (struct SCI*)_hw;
275 // Initialize the multi engine (if needed)
278 // Acquire the lock of the semaphore for this group
279 ASSERT(hw->num_group >= 0);
280 ASSERT(hw->num_group < MAX_MULTI_GROUPS);
281 sem_obtain(&multi_sems[hw->num_group]);
283 // Do a hardware switch to the given serial
284 ser_hw_switch(hw->num_group, hw->id);
289 static void cleanup_unlock(struct SerialHardware* _hw)
291 struct SCI* hw = (struct SCI*)_hw;
295 sem_release(&multi_sems[hw->num_group]);
298 #endif /* CONFIG_SER_MULTI */
301 static const struct SerialHardwareVT SCI_VT =
305 .setBaudrate = setbaudrate,
306 .setParity = setparity,
307 .txStart = enable_tx_irq,
308 .txSending = tx_irq_enabled,
312 static const struct SerialHardwareVT SCI_MULTI_VT =
315 .cleanup = cleanup_unlock,
316 .setBaudrate = setbaudrate,
317 .setParity = setparity,
318 .txStart = enable_tx_irq,
319 .txSending = tx_irq_enabled,
321 #endif /* CONFIG_SER_MULTI */
323 #define SCI_DESC_NORMAL(hwch) \
328 .rxbuffer = ser ## hwch ## _fifo_rx, \
329 .txbuffer = ser ## hwch ## _fifo_tx, \
330 .rxbuffer_size = countof(ser ## hwch ## _fifo_rx), \
331 .txbuffer_size = countof(ser ## hwch ## _fifo_tx), \
333 .regs = ®_SCI[hwch], \
334 .irq_rx = IRQ_SCI ## hwch ## _RECEIVER_FULL, \
335 .irq_tx = IRQ_SCI ## hwch ## _TRANSMITTER_READY, \
342 #define SCI_DESC_MULTI(hwch, group_, id_) \
346 .table = &SCI_MULTI_VT, \
347 .rxbuffer = ser ## hwch ## _fifo_rx, \
348 .txbuffer = ser ## hwch ## _fifo_tx, \
349 .rxbuffer_size = countof(ser ## hwch ## _fifo_rx), \
350 .txbuffer_size = countof(ser ## hwch ## _fifo_tx), \
352 .regs = ®_SCI[hwch], \
353 .irq_rx = IRQ_SCI ## hwch ## _RECEIVER_FULL, \
354 .irq_tx = IRQ_SCI ## hwch ## _TRANSMITTER_READY, \
355 .num_group = group_, \
359 #endif /* CONFIG_SER_MULTI */
361 // \todo Move this into hw.h, with a little preprocessor magic
362 static struct SCI SCIDescs[] =
365 SCI_DESC_MULTI(1, 0, 0),
366 SCI_DESC_MULTI(1, 0, 1),
369 struct SerialHardware* ser_hw_getdesc(int unit)
371 ASSERT(unit < countof(SCIDescs));
372 return &SCIDescs[unit].hw;