- Timestamp:
- 04/20/11 20:20:47 (13 years ago)
- Branches:
- 4.11, 5, master
- Children:
- ad65fc7f
- Parents:
- 5eb50f3
- Location:
- c/src/lib/libcpu/bfin
- Files:
-
- 3 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
c/src/lib/libcpu/bfin/ChangeLog
r5eb50f3 rcb4c90b2 1 2011-04-20 Rohan Kangralkar <rkangral@ece.neu.edu> 2 3 PR 1781/bsps 4 * bf52x/include: Added additional MMR. 5 * bf52x/interrupt: The BF52X processors have a different 6 System interrupt controller than present in the 53X range of 7 processors. The 52X have 8 interrupt assignment registers. The 8 implementation uses tables to increase predictability. 9 * serial/uart.?: Added DMA based and interrupt based transfer 10 support. The uart code used a single ISR for TX and RX and tried 11 to identify and multiplex inside the ISR. In the new code the 12 type of interrupt is identified by the central ISR dispatcher 13 bf52x/interrupt or interrupt/. This simplifies the UART ISR. 14 1 15 2011-02-11 Ralf Corsépius <ralf.corsepius@rtems.org> 2 16 -
c/src/lib/libcpu/bfin/Makefile.am
r5eb50f3 rcb4c90b2 11 11 noinst_PROGRAMS = 12 12 13 include_bspdir = $(includedir)/bsp 13 14 include_libcpudir = $(includedir)/libcpu 15 16 include_bsp_HEADERS = 14 17 include_libcpu_HEADERS = 18 19 20 ############ 21 # Start of bf52x files 22 if bf52x 23 24 include_HEADERS = bf52x/include/bf52x.h 25 26 ## INTERRUPT 27 include_bsp_HEADERS += bf52x/interrupt/interrupt.h 28 noinst_PROGRAMS += bf52x/interrupt.rel 29 bf52x_interrupt_rel_SOURCES = bf52x/interrupt/interrupt.c \ 30 bf52x/interrupt/interrupt.h 31 bf52x_interrupt_rel_CPPFLAGS = $(AM_CPPFLAGS) 32 bf52x_interrupt_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) 33 34 endif 35 # endof bf52x 36 ############ 15 37 16 38 include_libcpu_HEADERS += include/bf533.h … … 48 70 mmu_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) 49 71 72 if bf52x 73 74 else 50 75 include_libcpu_HEADERS += interrupt/interrupt.h 51 76 noinst_PROGRAMS += interrupt.rel … … 53 78 interrupt_rel_CPPFLAGS = $(AM_CPPFLAGS) 54 79 interrupt_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) 80 81 endif 55 82 56 83 noinst_PROGRAMS += clock.rel -
c/src/lib/libcpu/bfin/configure.ac
r5eb50f3 rcb4c90b2 25 25 AM_CONDITIONAL(HAS_NETWORKING,test "$HAS_NETWORKING" = "yes") 26 26 27 # AM_CONDITIONAL(shared, test "$RTEMS_CPU_MODEL" = "bf52x") 28 AM_CONDITIONAL(bf52x, test "$RTEMS_CPU_MODEL" = "bf52x") 29 30 27 31 RTEMS_AMPOLISH3 28 32 -
c/src/lib/libcpu/bfin/include/sicRegs.h
r5eb50f3 rcb4c90b2 17 17 18 18 #define SIC_IMASK (SIC_BASE_ADDRESS + 0x000c) 19 #define SIC_IMASK_PITCH (0x40) 20 21 #define SIC_ISR (SIC_BASE_ADDRESS + 0x0020) 22 #define SIC_ISR_PITCH (0x40) 23 19 24 #define SIC_IAR_BASE_ADDRESS (SIC_BASE_ADDRESS + 0x0010) 20 25 #define SIC_IAR_PITCH 0x04 26 21 27 #define SIC_IAR0 (SIC_BASE_ADDRESS + 0x0010) 22 28 #if SIC_IAR_COUNT > 1 … … 29 35 #define SIC_IAR3 (SIC_BASE_ADDRESS + 0x001c) 30 36 #endif 31 #define SIC_ISR (SIC_BASE_ADDRESS + 0x0020) 37 32 38 #define SIC_IWR (SIC_BASE_ADDRESS + 0x0024) 33 39 -
c/src/lib/libcpu/bfin/preinstall.am
r5eb50f3 rcb4c90b2 14 14 CLEANFILES = $(PREINSTALL_FILES) 15 15 16 $(PROJECT_INCLUDE)/$(dirstamp): 17 @$(MKDIR_P) $(PROJECT_INCLUDE) 18 @: > $(PROJECT_INCLUDE)/$(dirstamp) 19 PREINSTALL_DIRS += $(PROJECT_INCLUDE)/$(dirstamp) 20 21 $(PROJECT_INCLUDE)/bsp/$(dirstamp): 22 @$(MKDIR_P) $(PROJECT_INCLUDE)/bsp 23 @: > $(PROJECT_INCLUDE)/bsp/$(dirstamp) 24 PREINSTALL_DIRS += $(PROJECT_INCLUDE)/bsp/$(dirstamp) 25 16 26 $(PROJECT_INCLUDE)/libcpu/$(dirstamp): 17 27 @$(MKDIR_P) $(PROJECT_INCLUDE)/libcpu … … 19 29 PREINSTALL_DIRS += $(PROJECT_INCLUDE)/libcpu/$(dirstamp) 20 30 31 if bf52x 32 $(PROJECT_INCLUDE)/bf52x.h: bf52x/include/bf52x.h $(PROJECT_INCLUDE)/$(dirstamp) 33 $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bf52x.h 34 PREINSTALL_FILES += $(PROJECT_INCLUDE)/bf52x.h 35 36 $(PROJECT_INCLUDE)/bsp/interrupt.h: bf52x/interrupt/interrupt.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) 37 $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/interrupt.h 38 PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/interrupt.h 39 endif 21 40 $(PROJECT_INCLUDE)/libcpu/bf533.h: include/bf533.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp) 22 41 $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/bf533.h … … 103 122 PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/mmu.h 104 123 124 if bf52x 125 else 105 126 $(PROJECT_INCLUDE)/libcpu/interrupt.h: interrupt/interrupt.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp) 106 127 $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/interrupt.h 107 128 PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/interrupt.h 108 129 endif 109 130 $(PROJECT_INCLUDE)/libcpu/uart.h: serial/uart.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp) 110 131 $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/uart.h -
c/src/lib/libcpu/bfin/serial/uart.c
r5eb50f3 rcb4c90b2 7 7 * found in the file LICENSE in this distribution or at 8 8 * http://www.rtems.com/license/LICENSE. 9 * 10 * Modified: 11 * $ $Author$ Added interrupt support and DMA support 9 12 * 10 13 * $Id$ … … 19 22 20 23 #include <libcpu/uartRegs.h> 24 #include <libcpu/dmaRegs.h> 21 25 #include "uart.h" 22 23 26 24 27 /* flags */ … … 29 32 30 33 31 static void initializeHardware(int minor) {32 uint16_t divisor;33 char *base;34 uint16_t r;35 36 base = uartsConfig->channels[minor].base_address;37 38 *(uint16_t volatile *) (base + UART_IER_OFFSET) = 0;39 40 if (uartsConfig->channels[minor].force_baud)41 divisor = (uint16_t) (uartsConfig->freq /42 (uartsConfig->channels[minor].force_baud * 16));43 else44 divisor = (uint16_t) (uartsConfig->freq / (9600 * 16));45 *(uint16_t volatile *) (base + UART_LCR_OFFSET) = UART_LCR_DLAB;46 *(uint16_t volatile *) (base + UART_DLL_OFFSET) = (divisor & 0xff);47 *(uint16_t volatile *) (base + UART_DLH_OFFSET) = ((divisor >> 8) & 0xff);48 49 *(uint16_t volatile *) (base + UART_LCR_OFFSET) = UART_LCR_WLS_8;50 51 *(uint16_t volatile *) (base + UART_GCTL_OFFSET) = UART_GCTL_UCEN;52 53 r = *(uint16_t volatile *) (base + UART_LSR_OFFSET);54 r = *(uint16_t volatile *) (base + UART_RBR_OFFSET);55 r = *(uint16_t volatile *) (base + UART_IIR_OFFSET);56 57 return;58 }59 60 34 static int pollRead(int minor) { 61 35 int c; 62 char *base;63 64 base = uartsConfig->channels[minor]. base_address;36 uint32_t base; 37 38 base = uartsConfig->channels[minor].uart_baseAddress; 65 39 66 40 /* check to see if driver is using interrupts so this call will be 67 41 harmless (though non-functional) in case some debug code tries to 68 42 use it */ 69 if (!uartsConfig->channels[minor].u se_interrupts &&43 if (!uartsConfig->channels[minor].uart_useInterrupts && 70 44 *((uint16_t volatile *) (base + UART_LSR_OFFSET)) & UART_LSR_DR) 71 45 c = *((uint16_t volatile *) (base + UART_RBR_OFFSET)); … … 76 50 } 77 51 78 char bfin_uart_poll_read( intminor) {52 char bfin_uart_poll_read(rtems_device_minor_number minor) { 79 53 int c; 80 54 … … 87 61 88 62 void bfin_uart_poll_write(int minor, char c) { 89 char *base;90 91 base = uartsConfig->channels[minor]. base_address;63 uint32_t base; 64 65 base = uartsConfig->channels[minor].uart_baseAddress; 92 66 93 67 while (!(*((uint16_t volatile *) (base + UART_LSR_OFFSET)) & UART_LSR_THRE)) … … 158 132 } 159 133 160 static void enableInterrupts(int minor) { 161 char *base; 162 163 base = uartsConfig->channels[minor].base_address; 164 165 *(uint16_t volatile *) (base + UART_IER_OFFSET) = UART_IER_ETBEI | 166 UART_IER_ERBFI; 167 } 168 169 static void disableAllInterrupts(void) { 170 int i; 171 char *base; 172 173 for (i = 0; i < uartsConfig->num_channels; i++) { 174 base = uartsConfig->channels[i].base_address; 175 *(uint16_t volatile *) (base + UART_IER_OFFSET) = 0; 176 } 177 } 178 179 static ssize_t interruptWrite(int minor, const char *buf, size_t len) { 180 char *base; 181 182 base = uartsConfig->channels[minor].base_address; 183 184 uartsConfig->channels[minor].flags |= BFIN_UART_XMIT_BUSY; 185 *(uint16_t volatile *) (base + UART_THR_OFFSET) = *buf; 186 187 /* one byte written */ 188 return 1; 189 } 190 134 135 /** 136 * Routine to initialize the hardware. It initialize the DMA, 137 * interrupt if required. 138 * @param channel channel information 139 */ 140 static void initializeHardware(bfin_uart_channel_t *channel) { 141 uint16_t divisor = 0; 142 uint32_t base = 0; 143 uint32_t tx_dma_base = 0; 144 145 if ( NULL == channel ) { 146 return; 147 } 148 149 base = channel->uart_baseAddress; 150 tx_dma_base = channel->uart_txDmaBaseAddress; 151 /** 152 * RX based DMA and interrupt is not supported yet 153 * uint32_t tx_dma_base = 0; 154 * 155 * rx_dma_base = channel->uart_rxDmaBaseAddress; 156 */ 157 158 159 *(uint16_t volatile *) (base + UART_IER_OFFSET) = 0; 160 161 if ( 0 != channel->uart_baud) { 162 divisor = (uint16_t) (uartsConfig->freq / 163 (channel->uart_baud * 16)); 164 } else { 165 divisor = (uint16_t) (uartsConfig->freq / (9600 * 16)); 166 } 167 168 *(uint16_t volatile *) (base + UART_LCR_OFFSET) = UART_LCR_DLAB; 169 *(uint16_t volatile *) (base + UART_DLL_OFFSET) = (divisor & 0xff); 170 *(uint16_t volatile *) (base + UART_DLH_OFFSET) = ((divisor >> 8) & 0xff); 171 172 *(uint16_t volatile *) (base + UART_LCR_OFFSET) = UART_LCR_WLS_8; 173 174 *(uint16_t volatile *) (base + UART_GCTL_OFFSET) = UART_GCTL_UCEN; 175 176 /** 177 * To clear previous status 178 * divisor is a temp variable here 179 */ 180 divisor = *(uint16_t volatile *) (base + UART_LSR_OFFSET); 181 divisor = *(uint16_t volatile *) (base + UART_RBR_OFFSET); 182 divisor = *(uint16_t volatile *) (base + UART_IIR_OFFSET); 183 184 if ( channel->uart_useDma ) { 185 *(uint16_t volatile *)(tx_dma_base + DMA_CONFIG_OFFSET) = 0; 186 *(uint16_t volatile *)(tx_dma_base + DMA_CONFIG_OFFSET) = DMA_CONFIG_DI_EN 187 | DMA_CONFIG_SYNC ; 188 *(uint16_t volatile *)(tx_dma_base + DMA_IRQ_STATUS_OFFSET) |= 189 DMA_IRQ_STATUS_DMA_DONE | DMA_IRQ_STATUS_DMA_ERR; 190 191 } else { 192 /** 193 * We use polling or interrupts only sending one char at a time :( 194 */ 195 } 196 197 return; 198 } 199 200 201 /** 202 * Set the UART attributes. 203 * @param minor 204 * @param termios 205 * @return 206 */ 191 207 static int setAttributes(int minor, const struct termios *termios) { 192 char *base;208 uint32_t base; 193 209 int baud; 194 210 uint16_t divisor; 195 211 uint16_t lcr; 196 212 197 base = uartsConfig->channels[minor]. base_address;213 base = uartsConfig->channels[minor].uart_baseAddress; 198 214 switch (termios->c_cflag & CBAUD) { 199 215 case B0: … … 261 277 break; 262 278 } 263 if (baud > 0 && uartsConfig->channels[minor]. force_baud)264 baud = uartsConfig->channels[minor]. force_baud;279 if (baud > 0 && uartsConfig->channels[minor].uart_baud) 280 baud = uartsConfig->channels[minor].uart_baud; 265 281 switch (termios->c_cflag & CSIZE) { 266 282 case CS5: … … 283 299 break; 284 300 case PARENB | PARODD: 285 286 301 lcr |= UART_LCR_PEN; 302 break; 287 303 default: 288 304 break; … … 302 318 } 303 319 304 void bfin_uart_isr(int source) { 305 int i; 306 char *base; 307 uint16_t uartStat; 308 char c; 309 uint8_t uartLSR; 310 311 /* Just use one ISR and check for all UART interrupt sources in it. 312 This is less efficient than making use of the vector to narrow down 313 the things we need to check, but not all Blackfins separate the 314 UART interrupt sources in the same ways. This way we don't have 315 to make this code dependent on the type of Blackfin. */ 316 for (i = 0; i < uartsConfig->num_channels; i++) { 317 if (uartsConfig->channels[i].use_interrupts) { 318 base = uartsConfig->channels[i].base_address; 319 uartStat = *(uint16_t volatile *) (base + UART_IIR_OFFSET); 320 if ((uartStat & UART_IIR_NINT) == 0) { 321 switch (uartStat & UART_IIR_STATUS_MASK) { 322 case UART_IIR_STATUS_THRE: 323 if (uartsConfig->channels[i].termios && 324 (uartsConfig->channels[i].flags & BFIN_UART_XMIT_BUSY)) { 325 uartsConfig->channels[i].flags &= ~BFIN_UART_XMIT_BUSY; 326 rtems_termios_dequeue_characters(uartsConfig->channels[i].termios, 327 1); 328 } 329 break; 330 case UART_IIR_STATUS_RDR: 331 c = *(uint16_t volatile *) (base + UART_RBR_OFFSET); 332 if (uartsConfig->channels[i].termios) 333 rtems_termios_enqueue_raw_characters( 334 uartsConfig->channels[i].termios, &c, 1); 335 break; 336 case UART_IIR_STATUS_LS: 337 uartLSR = *(uint16_t volatile *) (base + UART_LSR_OFFSET); 338 /* break, framing error, parity error, or overrun error 339 has been detected */ 340 break; 341 default: 342 break; 343 } 344 } 345 } 346 } 347 } 348 320 /** 321 * Interrupt based uart tx routine. The routine writes one character at a time. 322 * 323 * @param minor Minor number to indicate uart number 324 * @param buf Character buffer which stores characters to be transmitted. 325 * @param len Length of buffer to be transmitted. 326 * @return 327 */ 328 static ssize_t uart_interruptWrite(int minor, const char *buf, size_t len) { 329 uint32_t base = 0; 330 bfin_uart_channel_t* channel = NULL; 331 rtems_interrupt_level isrLevel; 332 333 /** 334 * Sanity Check 335 */ 336 if (NULL == buf || NULL == channel || NULL == uartsConfig || minor < 0) { 337 return 0; 338 } 339 340 channel = &(uartsConfig->channels[minor]); 341 342 if ( NULL == channel || channel->flags & BFIN_UART_XMIT_BUSY ) { 343 return 0; 344 } 345 346 rtems_interrupt_disable(isrLevel); 347 348 base = channel->uart_baseAddress; 349 350 channel->flags |= BFIN_UART_XMIT_BUSY; 351 channel->length = 1; 352 *(uint16_t volatile *) (base + UART_THR_OFFSET) = *buf; 353 *(uint16_t volatile *) (base + UART_IER_OFFSET) = UART_IER_ETBEI; 354 355 rtems_interrupt_enable(isrLevel); 356 357 return 0; 358 } 359 360 /** 361 * This function implements RX ISR 362 */ 363 void bfinUart_rxIsr(void *_arg) 364 { 365 /** 366 * TODO: UART RX ISR implementation. 367 */ 368 369 } 370 371 372 /** 373 * This function implements TX ISR. The function gets called when the TX FIFO is 374 * empty. It clears the interrupt and dequeues the character. It only tx one 375 * character at a time. 376 * 377 * TODO: error handling. 378 * @param _arg gets the channel information. 379 */ 380 void bfinUart_txIsr(void *_arg) { 381 bfin_uart_channel_t* channel = NULL; 382 uint32_t base = 0; 383 384 /** 385 * Sanity check 386 */ 387 if (NULL == _arg) { 388 /** It should never be NULL */ 389 return; 390 } 391 392 channel = (bfin_uart_channel_t *) _arg; 393 394 base = channel->uart_baseAddress; 395 396 *(uint16_t volatile *) (base + UART_IER_OFFSET) &= ~UART_IER_ETBEI; 397 channel->flags &= ~BFIN_UART_XMIT_BUSY; 398 399 rtems_termios_dequeue_characters(channel->termios, channel->length); 400 401 return; 402 } 403 404 405 406 407 /** 408 * interrupt based DMA write Routine. It configure the DMA to write len bytes. 409 * The DMA supports 64K data only. 410 * 411 * @param minor Identification number of the UART. 412 * @param buf Character buffer pointer 413 * @param len length of data items to be written 414 * @return data already written 415 */ 416 static ssize_t uart_DmaWrite(int minor, const char *buf, size_t len) { 417 uint32_t base = 0; 418 bfin_uart_channel_t* channel = NULL; 419 uint32_t tx_dma_base = 0; 420 rtems_interrupt_level isrLevel; 421 422 /** 423 * Sanity Check 424 */ 425 if ( NULL == buf || 0 > minor || NULL == uartsConfig ) { 426 return 0; 427 } 428 429 channel = &(uartsConfig->channels[minor]); 430 431 /** 432 * Sanity Check and check for transmit busy. 433 */ 434 if ( NULL == channel || BFIN_UART_XMIT_BUSY & channel->flags ) { 435 return 0; 436 } 437 438 rtems_interrupt_disable(isrLevel); 439 440 base = channel->uart_baseAddress; 441 tx_dma_base = channel->uart_txDmaBaseAddress; 442 443 channel->flags |= BFIN_UART_XMIT_BUSY; 444 channel->length = len; 445 446 *(uint16_t volatile *) (tx_dma_base + DMA_CONFIG_OFFSET) &= ~DMA_CONFIG_DMAEN; 447 *(uint32_t volatile *) (tx_dma_base + DMA_START_ADDR_OFFSET) = (uint32_t)buf; 448 *(uint16_t volatile *) (tx_dma_base + DMA_X_COUNT_OFFSET) = channel->length; 449 *(uint16_t volatile *) (tx_dma_base + DMA_X_MODIFY_OFFSET) = 1; 450 *(uint16_t volatile *) (tx_dma_base + DMA_CONFIG_OFFSET) |= DMA_CONFIG_DMAEN; 451 *(uint16_t volatile *) (base + UART_IER_OFFSET) = UART_IER_ETBEI; 452 453 rtems_interrupt_enable(isrLevel); 454 455 return 0; 456 } 457 458 459 /** 460 * RX DMA ISR. 461 * The polling route is used for receiving the characters. This is a place 462 * holder for future implementation. 463 * @param _arg 464 */ 465 void bfinUart_rxDmaIsr(void *_arg) { 466 /** 467 * TODO: Implementation of RX DMA 468 */ 469 } 470 471 /** 472 * This function implements TX dma ISR. It clears the IRQ and dequeues a char 473 * The channel argument will have the base address. Since there are two uart 474 * and both the uarts can use the same tx dma isr. 475 * 476 * TODO: 1. Error checking 2. sending correct length ie after looking at the 477 * number of elements the uart transmitted. 478 * 479 * @param _arg argument passed to the interrupt handler. It contains the 480 * channel argument. 481 */ 482 void bfinUart_txDmaIsr(void *_arg) { 483 bfin_uart_channel_t* channel = NULL; 484 uint32_t tx_dma_base = 0; 485 486 /** 487 * Sanity check 488 */ 489 if (NULL == _arg) { 490 /** It should never be NULL */ 491 return; 492 } 493 494 channel = (bfin_uart_channel_t *) _arg; 495 496 tx_dma_base = channel->uart_txDmaBaseAddress; 497 498 if ((*(uint16_t volatile *) (tx_dma_base + DMA_IRQ_STATUS_OFFSET) 499 & DMA_IRQ_STATUS_DMA_DONE)) { 500 501 *(uint16_t volatile *) (tx_dma_base + DMA_IRQ_STATUS_OFFSET) 502 |= DMA_IRQ_STATUS_DMA_DONE | DMA_IRQ_STATUS_DMA_ERR; 503 channel->flags &= ~BFIN_UART_XMIT_BUSY; 504 rtems_termios_dequeue_characters(channel->termios, channel->length); 505 } else { 506 /* UART DMA did not generate interrupt. 507 * This routine must not be called. 508 */ 509 } 510 511 return; 512 } 513 514 /** 515 * Function called during exit 516 */ 517 void uart_exit(void) 518 { 519 /** 520 * TODO: Flushing of quques 521 */ 522 523 } 524 525 /** 526 * Opens the device in different modes. The supported modes are 527 * 1. Polling 528 * 2. Interrupt 529 * 3. DMA 530 * At exit the uart_Exit function will be called to flush the device. 531 * 532 * @param major Major number of the device 533 * @param minor Minor number of the device 534 * @param arg 535 * @return 536 */ 537 rtems_device_driver bfin_uart_open(rtems_device_major_number major, 538 rtems_device_minor_number minor, void *arg) { 539 rtems_status_code sc = RTEMS_NOT_DEFINED;; 540 rtems_libio_open_close_args_t *args = NULL; 541 542 /** 543 * Callback function for polling 544 */ 545 static const rtems_termios_callbacks pollCallbacks = { 546 NULL, /* firstOpen */ 547 NULL, /* lastClose */ 548 pollRead, /* pollRead */ 549 pollWrite, /* write */ 550 setAttributes, /* setAttributes */ 551 NULL, /* stopRemoteTx */ 552 NULL, /* startRemoteTx */ 553 TERMIOS_POLLED /* outputUsesInterrupts */ 554 }; 555 556 /** 557 * Callback function for interrupt based transfers without DMA. 558 * We use interrupts for writing only. For reading we use polling. 559 */ 560 static const rtems_termios_callbacks interruptCallbacks = { 561 NULL, /* firstOpen */ 562 NULL, /* lastClose */ 563 pollRead, /* pollRead */ 564 uart_interruptWrite, /* write */ 565 setAttributes, /* setAttributes */ 566 NULL, /* stopRemoteTx */ 567 NULL, /* startRemoteTx */ 568 TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */ 569 }; 570 571 /** 572 * Callback function for interrupt based DMA transfers. 573 * We use interrupts for writing only. For reading we use polling. 574 */ 575 static const rtems_termios_callbacks interruptDmaCallbacks = { 576 NULL, /* firstOpen */ 577 NULL, /* lastClose */ 578 NULL, /* pollRead */ 579 uart_DmaWrite, /* write */ 580 setAttributes, /* setAttributes */ 581 NULL, /* stopRemoteTx */ 582 NULL, /* startRemoteTx */ 583 TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */ 584 }; 585 586 587 if ( NULL == uartsConfig || 0 > minor || minor >= uartsConfig->num_channels) { 588 return RTEMS_INVALID_NUMBER; 589 } 590 591 /** 592 * Opens device for handling uart send request either by 593 * 1. interrupt with DMA 594 * 2. interrupt based 595 * 3. Polling 596 */ 597 if ( uartsConfig->channels[minor].uart_useDma ) { 598 sc = rtems_termios_open(major, minor, arg, &interruptDmaCallbacks); 599 } else { 600 sc = rtems_termios_open(major, minor, arg, 601 uartsConfig->channels[minor].uart_useInterrupts ? 602 &interruptCallbacks : &pollCallbacks); 603 } 604 605 args = arg; 606 uartsConfig->channels[minor].termios = args->iop->data1; 607 608 atexit(uart_exit); 609 610 return sc; 611 } 612 613 614 /** 615 * Uart initialization function. 616 * @param major major number of the device 617 * @param config configuration parameters 618 * @return rtems status code 619 */ 349 620 rtems_status_code bfin_uart_initialize(rtems_device_major_number major, 350 bfin_uart_config_t *config) { 351 rtems_status_code status; 352 int i; 353 354 status = RTEMS_SUCCESSFUL; 621 bfin_uart_config_t *config) { 622 rtems_status_code sc = RTEMS_NOT_DEFINED; 623 int i = 0; 355 624 356 625 rtems_termios_initialize(); … … 359 628 * Register Device Names 360 629 */ 361 362 630 uartsConfig = config; 363 631 for (i = 0; i < config->num_channels; i++) { 364 632 config->channels[i].termios = NULL; 365 633 config->channels[i].flags = 0; 366 initializeHardware(i); 367 status = rtems_io_register_name(config->channels[i].name, major, i); 368 } 369 370 return RTEMS_SUCCESSFUL; 371 } 372 373 rtems_device_driver bfin_uart_open(rtems_device_major_number major, 374 rtems_device_minor_number minor, 375 void *arg) { 376 rtems_status_code sc; 377 rtems_libio_open_close_args_t *args; 378 static const rtems_termios_callbacks pollCallbacks = { 379 NULL, /* firstOpen */ 380 NULL, /* lastClose */ 381 pollRead, /* pollRead */ 382 pollWrite, /* write */ 383 setAttributes, /* setAttributes */ 384 NULL, /* stopRemoteTx */ 385 NULL, /* startRemoteTx */ 386 TERMIOS_POLLED /* outputUsesInterrupts */ 387 }; 388 static const rtems_termios_callbacks interruptCallbacks = { 389 NULL, /* firstOpen */ 390 NULL, /* lastClose */ 391 NULL, /* pollRead */ 392 interruptWrite, /* write */ 393 setAttributes, /* setAttributes */ 394 NULL, /* stopRemoteTx */ 395 NULL, /* startRemoteTx */ 396 TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */ 397 }; 398 399 if (uartsConfig == NULL || minor < 0 || minor >= uartsConfig->num_channels) 400 return RTEMS_INVALID_NUMBER; 401 402 sc = rtems_termios_open(major, minor, arg, 403 uartsConfig->channels[minor].use_interrupts ? 404 &interruptCallbacks : &pollCallbacks); 405 args = arg; 406 uartsConfig->channels[minor].termios = args->iop->data1; 407 408 if (uartsConfig->channels[minor].use_interrupts) 409 enableInterrupts(minor); 410 atexit(disableAllInterrupts); 634 initializeHardware(&(config->channels[i])); 635 sc = rtems_io_register_name(config->channels[i].name, major, i); 636 if (RTEMS_SUCCESSFUL != sc) { 637 return sc; 638 } 639 } 411 640 412 641 return sc; 413 642 } 414 -
c/src/lib/libcpu/bfin/serial/uart.h
r5eb50f3 rcb4c90b2 9 9 * http://www.rtems.com/license/LICENSE. 10 10 * 11 * Modified: 12 * $Author$ Added interrupt support and DMA support 13 * 11 14 * $Id$ 12 15 */ 13 16 14 #ifndef _uart_h_ 15 #define _uart_h_ 17 18 #ifndef _UART_H_ 19 #define _UART_H_ 16 20 17 21 … … 20 24 #endif 21 25 26 /** bfin_uart_channel object 27 */ 28 typedef struct { 29 const char *name; /** Holds name of the device */ 30 uint32_t uart_baseAddress; /** UART base address */ 31 uint32_t uart_rxDmaBaseAddress; /** RX DMA base address */ 32 uint32_t uart_txDmaBaseAddress; /** TX DMA base address */ 33 bool uart_useInterrupts; /** are interrupts used */ 34 bool uart_useDma; /** is dma used */ 35 int uart_baud; /** baud rate, 0 for default */ 22 36 23 typedef struct { 24 const char *name; 25 void *base_address; 26 bool use_interrupts; 27 int force_baud; 28 /* the following are for internal use */ 29 void *termios; 30 uint8_t volatile flags; 37 void *termios; /** termios associated */ 38 uint8_t volatile flags; /** flags for internal use */ 39 uint16_t length; /** length for internal use */ 31 40 } bfin_uart_channel_t; 41 32 42 33 43 typedef struct { … … 37 47 } bfin_uart_config_t; 38 48 49 /** 50 * @param base_address defines the UART base address 51 * @param source defines the source that caused the interrupt. This argument 52 * will help us in identifying if Rx or TX caused the interrupt. 53 */ 54 typedef struct { 55 uint32_t base_address; 56 int source; 57 } bfin_uart_arg_t; 39 58 40 char bfin_uart_poll_read(int minor); 59 60 61 char bfin_uart_poll_read(rtems_device_minor_number minor); 41 62 42 63 void bfin_uart_poll_write(int minor, char c); 43 64 65 66 /** 67 * Uart initialization function. 68 * @param major major number of the device 69 * @param config configuration parameters 70 * @return rtems status code 71 */ 44 72 rtems_status_code bfin_uart_initialize(rtems_device_major_number major, 45 73 bfin_uart_config_t *config); 46 74 75 76 77 /** 78 * Opens the device in different modes. The supported modes are 79 * 1. Polling 80 * 2. Interrupt 81 * 3. DMA 82 * At exit the uart_Exit function will be called to flush the device. 83 * 84 * @param major Major number of the device 85 * @param minor Minor number of the device 86 * @param arg 87 * @return 88 */ 47 89 rtems_device_driver bfin_uart_open(rtems_device_major_number major, 48 rtems_device_minor_number minor, 49 void *arg); 90 rtems_device_minor_number minor, void *arg); 50 91 51 void bfin_uart_isr(int source); 92 93 94 /** 95 * This function implements TX dma ISR. It clears the IRQ and dequeues a char 96 * The channel argument will have the base address. Since there are two uart 97 * and both the uarts can use the same tx dma isr. 98 * 99 * TODO: 1. Error checking 2. sending correct length ie after looking at the 100 * number of elements the uart transmitted. 101 * 102 * @param _arg argument passed to the interrupt handler. It contains the 103 * channel argument. 104 */ 105 void bfinUart_txDmaIsr(void *_arg); 106 107 108 109 /** 110 * RX DMA ISR. 111 * The polling route is used for receiving the characters. This is a place 112 * holder for future implementation. 113 * @param _arg 114 */ 115 void bfinUart_rxDmaIsr(void *_arg); 116 117 118 /** 119 * This function implements TX ISR. The function gets called when the TX FIFO is 120 * empty. It clears the interrupt and dequeues the character. It only tx one 121 * character at a time. 122 * 123 * TODO: error handling. 124 * @param _arg gets the channel information. 125 */ 126 void bfinUart_txIsr(void *_arg); 127 128 129 /** 130 * This function implements RX ISR 131 */ 132 void bfinUart_rxIsr(void *_arg); 52 133 53 134 … … 56 137 #endif 57 138 58 #endif /* _ uart_h_ */139 #endif /* _UART_H_ */ 59 140
Note: See TracChangeset
for help on using the changeset viewer.