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