970a5c3db523097a1efe3c70dd1fb018526d9707
[bertos.git] / drv / ser_dsp56k.c
1 /*!
2  * \file
3  * <!--
4  * Copyright (C) 2003,2004 Develer S.r.l. (http://www.develer.com/)
5  * All Rights Reserved.
6  * -->
7  *
8  * \version $Id$
9  *
10  * \author Stefano Fedrigo <aleph@develer.com>
11  * \author Giovanni Bajo <rasky@develer.com>
12  *
13  * \brief DSP5680x CPU specific serial I/O driver
14  */
15
16 /*
17  * $Log$
18  * Revision 1.2  2004/05/23 18:21:53  bernie
19  * Trim CVS logs and cleanup header info.
20  *
21  */
22
23 #include "ser.h"
24 #include "ser_p.h"
25 #include <drv/kdebug.h>
26 #include <hw.h>
27 #include <DSP56F807.H>
28
29 // GPIO E is shared with SPI (in DSP56807). Pins 0&1 are TXD0 and RXD0. To use
30 //  the serial, we need to disable the GPIO functions on them.
31 #define REG_GPIO_SERIAL         REG_GPIO_E
32 #define REG_GPIO_SERIAL_MASK    0x3
33
34 // Check flag consistency
35 #if (SERRF_PARITYERROR != REG_SCI_SR_PF) || \
36         (SERRF_RXSROVERRUN != REG_SCI_SR_OR) || \
37         (SERRF_FRAMEERROR  != REG_SCI_SR_FE) || \
38         (SERRF_NOISEERROR  != REG_SCI_SR_NF)
39         #error error flags do not match with register bits
40 #endif
41
42 struct SCI
43 {
44         struct SerialHardware hw;
45         struct Serial* serial;
46         volatile struct REG_SCI_STRUCT* regs;
47         uint16_t irq_tx;
48         uint16_t irq_rx;
49 };
50
51
52 static inline void enable_tx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
53 {
54         regs->CR |= REG_SCI_CR_TEIE | REG_SCI_CR_TIIE;
55 }
56
57 static inline void enable_rx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
58 {
59         regs->CR |= REG_SCI_CR_RIE | REG_SCI_CR_REIE;
60 }
61
62 static inline void disable_tx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
63 {
64         regs->CR &= ~(REG_SCI_CR_TEIE | REG_SCI_CR_TIIE);
65 }
66
67 static inline void disable_rx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
68 {
69         regs->CR &= ~(REG_SCI_CR_RIE | REG_SCI_CR_REIE);
70 }
71
72 static inline void disable_tx_irq(struct SerialHardware* _hw)
73 {
74         struct SCI* hw = (struct SCI*)_hw;
75         volatile struct REG_SCI_STRUCT* regs = hw->regs;
76
77         disable_tx_irq_bare(regs);
78 }
79
80 static inline void enable_tx_irq(struct SerialHardware* _hw)
81 {
82         struct SCI* hw = (struct SCI*)_hw;
83         volatile struct REG_SCI_STRUCT* regs = hw->regs;
84
85         enable_tx_irq_bare(regs);
86 }
87
88 static inline void enable_rx_irq(struct SerialHardware* _hw)
89 {
90         struct SCI* hw = (struct SCI*)_hw;
91         volatile struct REG_SCI_STRUCT* regs = hw->regs;
92
93         enable_rx_irq_bare(regs);
94 }
95
96 INLINE void tx_isr(struct SCI *hw)
97 {
98         volatile struct REG_SCI_STRUCT* regs = hw->regs;
99
100         if (fifo_isempty(&hw->serial->txfifo))
101                 disable_tx_irq_bare(regs);
102         else
103         {
104                 // Clear transmitter flags before sending data
105                 (void)regs->SR;
106                 regs->DR = fifo_pop(&hw->serial->txfifo);
107         }
108 }
109
110 INLINE void rx_isr(struct SCI *hw)
111 {
112         volatile struct REG_SCI_STRUCT* regs = hw->regs;
113
114         hw->serial->status |= regs->SR & (SERRF_PARITYERROR |
115                                           SERRF_RXSROVERRUN |
116                                           SERRF_FRAMEERROR |
117                                           SERRF_NOISEERROR);
118
119         if (fifo_isfull(&hw->serial->rxfifo))
120                 hw->serial->status |= SERRF_RXFIFOOVERRUN;
121         else
122                 fifo_push(&hw->serial->rxfifo, regs->DR);
123
124         // Writing anything to the status register clear the
125         //  error bits.
126         regs->SR = 0;
127 }
128
129 static void init(struct SerialHardware* _hw, struct Serial* ser)
130 {
131         struct SCI* hw = (struct SCI*)_hw;
132         volatile struct REG_SCI_STRUCT* regs = hw->regs;
133
134         // Clear status register (IRQ/status flags)
135         (void)regs->SR;
136         regs->SR = 0;
137
138         // Clear data register
139         (void)regs->DR;
140
141         // Set priorities for both IRQs
142         irq_setpriority(hw->irq_tx, IRQ_PRIORITY_SCI_TX);
143         irq_setpriority(hw->irq_rx, IRQ_PRIORITY_SCI_RX);
144
145         // Activate the RX error interrupts, and RX/TX transmissions
146         regs->CR = REG_SCI_CR_TE | REG_SCI_CR_RE;
147         enable_rx_irq_bare(regs);
148
149         // Disable GPIO pins for TX and RX lines
150         REG_GPIO_SERIAL->PER |= REG_GPIO_SERIAL_MASK;
151
152         hw->serial = ser;
153 }
154
155 static void cleanup(struct SerialHardware* _hw)
156 {
157         // TODO!
158         ASSERT(0);
159 }
160
161 static void setbaudrate(struct SerialHardware* _hw, unsigned long rate)
162 {
163         struct SCI* hw = (struct SCI*)_hw;
164
165         // SCI has an internal 16x divider on the input clock, which comes
166         //  from the IPbus (see the scheme in user manual, 12.7.3). We apply
167         //  it to calculate the period to store in the register.
168         hw->regs->BR = (IPBUS_FREQ + rate * 8ul) / (rate * 16ul);
169 }
170
171 static void setparity(struct SerialHardware* _hw, int parity)
172 {
173         // ???
174         ASSERT(0);
175 }
176
177
178 static const struct SerialHardwareVT SCI_VT = 
179 {
180         .init = init,
181         .cleanup = cleanup,
182         .setbaudrate = setbaudrate,
183         .setparity = setparity,
184         .enabletxirq = enable_tx_irq,
185 };
186
187 static struct SCI SCIDescs[2] =
188 {
189         {
190                 .hw = { .table = &SCI_VT },
191                 .regs = &REG_SCI[0],
192                 .irq_rx = IRQ_SCI0_RECEIVER_FULL,
193                 .irq_tx = IRQ_SCI0_TRANSMITTER_READY,
194         },
195
196         {
197                 .hw = { .table = &SCI_VT },
198                 .regs = &REG_SCI[1],
199                 .irq_rx = IRQ_SCI1_RECEIVER_FULL,
200                 .irq_tx = IRQ_SCI1_TRANSMITTER_READY,
201         },
202 };
203
204
205
206 void ser_hw_tx_isr_0(void);
207 void ser_hw_tx_isr_0(void)
208 {
209 #pragma interrupt warn
210         tx_isr(&SCIDescs[0]);
211 }
212
213 void ser_hw_rx_isr_0(void);
214 void ser_hw_rx_isr_0(void)
215 {
216 #pragma interrupt warn
217         rx_isr(&SCIDescs[0]);
218 }
219
220 void ser_hw_tx_isr_1(void);
221 void ser_hw_tx_isr_1(void)
222 {
223 #pragma interrupt warn
224         tx_isr(&SCIDescs[1]);
225 }
226
227 void ser_hw_rx_isr_1(void);
228 void ser_hw_rx_isr_1(void)
229 {
230 #pragma interrupt warn
231         rx_isr(&SCIDescs[1]);
232 }
233
234 struct SerialHardware* ser_hw_getdesc(int unit)
235 {
236         ASSERT(unit < 2);
237         return &SCIDescs[unit].hw;
238 }