ser_dsp56k.c

Go to the documentation of this file.
00001 
00042 #include <drv/ser.h>
00043 #include <drv/ser_p.h>
00044 #include <drv/irq.h>
00045 #include <cfg/debug.h>
00046 #include <hw.h>
00047 #include <DSP56F807.h>
00048 
00049 // GPIO E is shared with SPI (in DSP56807). Pins 0&1 are TXD0 and RXD0. To use
00050 //  the serial, we need to disable the GPIO functions on them.
00051 #define REG_GPIO_SERIAL_0       REG_GPIO_E
00052 #define REG_GPIO_SERIAL_MASK_0  0x03
00053 
00054 #define REG_GPIO_SERIAL_1       REG_GPIO_D
00055 #define REG_GPIO_SERIAL_MASK_1  0xC0
00056 
00057 
00058 // Check flag consistency
00059 #if (SERRF_PARITYERROR != REG_SCI_SR_PF) || \
00060     (SERRF_RXSROVERRUN != REG_SCI_SR_OR) || \
00061     (SERRF_FRAMEERROR  != REG_SCI_SR_FE) || \
00062     (SERRF_NOISEERROR  != REG_SCI_SR_NF)
00063     #error error flags do not match with register bits
00064 #endif
00065 
00066 static unsigned char ser0_fifo_rx[CONFIG_SER0_FIFOSIZE_RX];
00067 static unsigned char ser0_fifo_tx[CONFIG_SER0_FIFOSIZE_TX];
00068 static unsigned char ser1_fifo_rx[CONFIG_SER1_FIFOSIZE_RX];
00069 static unsigned char ser1_fifo_tx[CONFIG_SER1_FIFOSIZE_TX];
00070 
00071 #if CONFIG_SER_MULTI
00072     #include <kern/sem.h>
00073 
00074     #define MAX_MULTI_GROUPS     1
00075 
00076     struct Semaphore multi_sems[MAX_MULTI_GROUPS];
00077 #endif
00078 
00079 
00080 struct SCI
00081 {
00082     struct SerialHardware hw;
00083     struct Serial* serial;
00084     volatile struct REG_SCI_STRUCT* regs;
00085     IRQ_VECTOR irq_tx;
00086     IRQ_VECTOR irq_rx;
00087     int num_group;
00088     int id;
00089 };
00090 
00091 static inline void enable_tx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
00092 {
00093     regs->CR |= REG_SCI_CR_TEIE | REG_SCI_CR_TIIE;
00094 }
00095 
00096 static inline void enable_rx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
00097 {
00098     regs->CR |= REG_SCI_CR_RIE;
00099 }
00100 
00101 static inline void disable_tx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
00102 {
00103     regs->CR &= ~(REG_SCI_CR_TEIE | REG_SCI_CR_TIIE);
00104 }
00105 
00106 static inline void disable_rx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
00107 {
00108     regs->CR &= ~(REG_SCI_CR_RIE | REG_SCI_CR_REIE);
00109 }
00110 
00111 static inline void disable_tx_irq(struct SerialHardware* _hw)
00112 {
00113     struct SCI* hw = (struct SCI*)_hw;
00114 
00115     disable_tx_irq_bare(hw->regs);
00116 }
00117 
00118 static inline void disable_rx_irq(struct SerialHardware* _hw)
00119 {
00120     struct SCI* hw = (struct SCI*)_hw;
00121 
00122     disable_rx_irq_bare(hw->regs);
00123 }
00124 
00125 static inline void enable_tx_irq(struct SerialHardware* _hw)
00126 {
00127     struct SCI* hw = (struct SCI*)_hw;
00128 
00129     enable_tx_irq_bare(hw->regs);
00130 }
00131 
00132 static inline void enable_rx_irq(struct SerialHardware* _hw)
00133 {
00134     struct SCI* hw = (struct SCI*)_hw;
00135 
00136     enable_rx_irq_bare(hw->regs);
00137 }
00138 
00139 static inline bool tx_irq_enabled(struct SerialHardware* _hw)
00140 {
00141     struct SCI* hw = (struct SCI*)_hw;
00142 
00143     return (hw->regs->CR & REG_SCI_CR_TEIE);
00144 }
00145 
00146 static void tx_isr(const struct SCI *hw)
00147 {
00148 #pragma interrupt warn
00149     volatile struct REG_SCI_STRUCT* regs = hw->regs;
00150 
00151     if (fifo_isempty(&hw->serial->txfifo))
00152         disable_tx_irq_bare(regs);
00153     else
00154     {
00155         // Clear transmitter flags before sending data
00156         (void)regs->SR;
00157         regs->DR = fifo_pop(&hw->serial->txfifo);
00158     }
00159 }
00160 
00161 static void rx_isr(const struct SCI *hw)
00162 {
00163 #pragma interrupt warn
00164     volatile struct REG_SCI_STRUCT* regs = hw->regs;
00165 
00166     // Propagate errors
00167     hw->serial->status |= regs->SR & (SERRF_PARITYERROR |
00168                                       SERRF_RXSROVERRUN |
00169                                       SERRF_FRAMEERROR |
00170                                       SERRF_NOISEERROR);
00171 
00172     /*
00173      * Serial IRQ can happen for two reason: data ready (RDRF) or overrun (OR)
00174      * If the data is ready, we need to fetch it from the data register or
00175      * the interrupt will retrigger immediatly. In case of overrun, instead,
00176      * the value of the data register is meaningless.
00177      */
00178     if (regs->SR & REG_SCI_SR_RDRF)
00179     {
00180         unsigned char data = regs->DR;
00181 
00182         if (fifo_isfull(&hw->serial->rxfifo))
00183             hw->serial->status |= SERRF_RXFIFOOVERRUN;
00184         else
00185             fifo_push(&hw->serial->rxfifo, data);
00186     }
00187 
00188     // Writing anything to the status register clear the error bits.
00189     regs->SR = 0;
00190 }
00191 
00192 static void init(struct SerialHardware* _hw, struct Serial* ser)
00193 {
00194     struct SCI* hw = (struct SCI*)_hw;
00195     volatile struct REG_SCI_STRUCT* regs = hw->regs;
00196 
00197     // Clear status register (IRQ/status flags)
00198     (void)regs->SR;
00199     regs->SR = 0;
00200 
00201     // Clear data register
00202     (void)regs->DR;
00203 
00204     // Install the handlers and set priorities for both IRQs
00205     irq_install(hw->irq_tx, (isr_t)tx_isr, hw);
00206     irq_install(hw->irq_rx, (isr_t)rx_isr, hw);
00207     irq_setpriority(hw->irq_tx, IRQ_PRIORITY_SCI_TX);
00208     irq_setpriority(hw->irq_rx, IRQ_PRIORITY_SCI_RX);
00209 
00210     // Activate the RX error interrupts, and RX/TX transmissions
00211     regs->CR = REG_SCI_CR_TE | REG_SCI_CR_RE;
00212     enable_rx_irq_bare(regs);
00213 
00214     // Disable GPIO pins for TX and RX lines
00215     // \todo this should be divided into serial 0 and 1
00216     REG_GPIO_SERIAL_0->PER |= REG_GPIO_SERIAL_MASK_0;
00217     REG_GPIO_SERIAL_1->PER |= REG_GPIO_SERIAL_MASK_1;
00218 
00219     hw->serial = ser;
00220 }
00221 
00222 static void cleanup(struct SerialHardware* _hw)
00223 {
00224     struct SCI* hw = (struct SCI*)_hw;
00225 
00226     // Uninstall the ISRs
00227     disable_rx_irq(_hw);
00228     disable_tx_irq(_hw);
00229     irq_uninstall(hw->irq_tx);
00230     irq_uninstall(hw->irq_rx);
00231 }
00232 
00233 static void setbaudrate(struct SerialHardware* _hw, unsigned long rate)
00234 {
00235     struct SCI* hw = (struct SCI*)_hw;
00236 
00237     // SCI has an internal 16x divider on the input clock, which comes
00238     //  from the IPbus (see the scheme in user manual, 12.7.3). We apply
00239     //  it to calculate the period to store in the register.
00240     hw->regs->BR = (IPBUS_FREQ + rate * 8ul) / (rate * 16ul);
00241 }
00242 
00243 static void setparity(struct SerialHardware* _hw, int parity)
00244 {
00245     // ???
00246     ASSERT(0);
00247 }
00248 
00249 
00250 #if CONFIG_SER_MULTI
00251 
00252 static void multi_init(void)
00253 {
00254     static bool flag = false;
00255     int i;
00256 
00257     if (flag)
00258         return;
00259 
00260     for (i = 0; i < MAX_MULTI_GROUPS; ++i)
00261         sem_init(&multi_sems[i]);
00262     flag = true;
00263 }
00264 
00265 static void init_lock(struct SerialHardware* _hw, struct Serial *ser)
00266 {
00267     struct SCI* hw = (struct SCI*)_hw;
00268 
00269     // Initialize the multi engine (if needed)
00270     multi_init();
00271 
00272     // Acquire the lock of the semaphore for this group
00273     ASSERT(hw->num_group >= 0);
00274     ASSERT(hw->num_group < MAX_MULTI_GROUPS);
00275     sem_obtain(&multi_sems[hw->num_group]);
00276 
00277     // Do a hardware switch to the given serial
00278     ser_hw_switch(hw->num_group, hw->id);
00279 
00280     init(_hw, ser);
00281 }
00282 
00283 static void cleanup_unlock(struct SerialHardware* _hw)
00284 {
00285     struct SCI* hw = (struct SCI*)_hw;
00286 
00287     cleanup(_hw);
00288 
00289     sem_release(&multi_sems[hw->num_group]);
00290 }
00291 
00292 #endif /* CONFIG_SER_MULTI */
00293 
00294 
00295 static const struct SerialHardwareVT SCI_VT =
00296 {
00297     .init = init,
00298     .cleanup = cleanup,
00299     .setBaudrate = setbaudrate,
00300     .setParity = setparity,
00301     .txStart = enable_tx_irq,
00302     .txSending = tx_irq_enabled,
00303 };
00304 
00305 #if CONFIG_SER_MULTI
00306 static const struct SerialHardwareVT SCI_MULTI_VT =
00307 {
00308     .init = init_lock,
00309     .cleanup = cleanup_unlock,
00310     .setBaudrate = setbaudrate,
00311     .setParity = setparity,
00312     .txStart = enable_tx_irq,
00313     .txSending = tx_irq_enabled,
00314 };
00315 #endif /* CONFIG_SER_MULTI */
00316 
00317 #define SCI_DESC_NORMAL(hwch) \
00318     { \
00319         .hw = \
00320         { \
00321             .table = &SCI_VT, \
00322             .rxbuffer = ser ## hwch ## _fifo_rx, \
00323             .txbuffer = ser ## hwch ## _fifo_tx, \
00324             .rxbuffer_size = countof(ser ## hwch ## _fifo_rx), \
00325             .txbuffer_size = countof(ser ## hwch ## _fifo_tx), \
00326         }, \
00327         .regs = &REG_SCI[hwch], \
00328         .irq_rx = IRQ_SCI ## hwch ## _RECEIVER_FULL, \
00329         .irq_tx = IRQ_SCI ## hwch ## _TRANSMITTER_READY, \
00330         .num_group = -1, \
00331         .id = -1, \
00332     } \
00333     
00334 
00335 #if CONFIG_SER_MULTI
00336 #define SCI_DESC_MULTI(hwch, group_, id_) \
00337     { \
00338         .hw = \
00339         { \
00340             .table = &SCI_MULTI_VT, \
00341             .rxbuffer = ser ## hwch ## _fifo_rx, \
00342             .txbuffer = ser ## hwch ## _fifo_tx, \
00343             .rxbuffer_size = countof(ser ## hwch ## _fifo_rx), \
00344             .txbuffer_size = countof(ser ## hwch ## _fifo_tx), \
00345         }, \
00346         .regs = &REG_SCI[hwch], \
00347         .irq_rx = IRQ_SCI ## hwch ## _RECEIVER_FULL, \
00348         .irq_tx = IRQ_SCI ## hwch ## _TRANSMITTER_READY, \
00349         .num_group = group_, \
00350         .id = id_, \
00351     } \
00352     
00353 #endif /* CONFIG_SER_MULTI */
00354 
00355 // \todo Move this into hw.h, with a little preprocessor magic
00356 static struct SCI SCIDescs[] =
00357 {
00358     SCI_DESC_NORMAL(0),
00359     SCI_DESC_MULTI(1, 0, 0),
00360     SCI_DESC_MULTI(1, 0, 1),
00361 };
00362 
00363 struct SerialHardware* ser_hw_getdesc(int unit)
00364 {
00365     ASSERT(unit < countof(SCIDescs));
00366     return &SCIDescs[unit].hw;
00367 }