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