Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:59

0001 /*
0002  *  This file contains the console driver for the xilinx uart lite.
0003  *
0004  *  Author: Keith Robertson <kjrobert@alumni.uwaterloo.ca>
0005  *  COPYRIGHT (c) 2005 by Linn Products Ltd, Scotland.
0006  *
0007  *  Derived from libbsp/no_cpu/no_bsp/console.c and therefore also:
0008  *
0009  *  COPYRIGHT (c) 1989-1999.
0010  *  On-Line Applications Research Corporation (OAR).
0011  *
0012  *  The license and distribution terms for this file may be
0013  *  found in the file LICENSE in this distribution or at
0014  *  http://www.rtems.org/license/LICENSE.
0015  *
0016  */
0017 
0018 #include <assert.h>
0019 
0020 #include <rtems.h>
0021 #include <rtems/libio.h>
0022 #include <bsp/irq.h>
0023 
0024 #include <bsp.h>
0025 #include <libchip/serial.h>
0026 #include <libchip/sersupp.h>
0027 
0028 #include RTEMS_XPARAMETERS_H
0029 
0030 /* Status Register Masks */
0031 #define PARITY_ERROR       0x80 /* Parity Error */
0032 #define FRAME_ERROR        0x40 /* Frame Error */
0033 #define OVERRUN_ERROR      0x20 /* Overrun Error */
0034 #define STATUS_REG_ERROR_MASK ( PARITY_ERROR | FRAME_ERROR | OVERRUN_ERROR )
0035 
0036 #define INTR_ENABLED       0x10 /* Interrupts are enabled */
0037 #define TX_FIFO_FULL       0x08 /* Transmit FIFO is full */
0038 #define TX_FIFO_EMPTY      0x04 /* Transmit FIFO is empty */
0039 #define RX_FIFO_FULL       0x02 /* Receive FIFO is full */
0040 #define RX_FIFO_VALID_DATA 0x01 /* Receive FIFO has valid data */
0041 /* Control Register Masks*/
0042 #define ENABLE_INTR        0x10 /* Enable interrupts */
0043 #define RST_RX_FIFO        0x02 /* Reset and clear RX FIFO */
0044 #define RST_TX_FIFO        0x01 /* Reset and clear TX FIFO */
0045 
0046 /* General Defines */
0047 #define TX_FIFO_SIZE       16
0048 #define RX_FIFO_SIZE       16
0049 
0050 
0051 
0052 
0053 #define RECV_REG 0
0054 #define TRAN_REG 4
0055 #define STAT_REG 8
0056 #define CTRL_REG 12
0057 
0058 
0059 
0060 static inline uint32_t xlite_uart_control(uint32_t base)
0061 {
0062   uint32_t c = *((volatile uint32_t*)(base+CTRL_REG));
0063   return c;
0064 }
0065 
0066 
0067 static inline uint32_t xlite_uart_status(uint32_t base)
0068 {
0069   uint32_t c = *((volatile uint32_t*)(base+STAT_REG));
0070   return c;
0071 }
0072 
0073 
0074 static inline uint32_t xlite_uart_read(uint32_t base)
0075 {
0076   uint32_t c = *((volatile uint32_t*)(base+RECV_REG));
0077   return c;
0078 }
0079 
0080 
0081 static inline void xlite_uart_write(uint32_t base, char ch)
0082 {
0083   *(volatile uint32_t*)(base+TRAN_REG) = (uint32_t)ch;
0084   return;
0085 }
0086 
0087 
0088 
0089 static int xlite_write_char(uint32_t base, char ch)
0090 {
0091    uint32_t  retrycount= 0, idler, status;
0092 
0093    while( ((status = xlite_uart_status(base)) & TX_FIFO_FULL) != 0 )
0094    {
0095       ++retrycount;
0096 
0097       /* uart tx is busy */
0098       if( retrycount == 0x4000 )
0099       {
0100      /* retrycount is arbitrary- just make it big enough so the uart is sure to be timed out before it trips */
0101      return -1;
0102       }
0103 
0104       /* spin for a bit so we can sample the register rather than
0105        * continually reading it */
0106       for( idler= 0; idler < 0x2000; idler++);
0107    }
0108 
0109    xlite_uart_write(base, ch);
0110 
0111    return 1;
0112 }
0113 
0114 static void xlite_init(int minor )
0115 {
0116    /* Nothing to do */
0117 }
0118 
0119 #if VIRTEX_CONSOLE_USE_INTERRUPTS
0120 static void xlite_interrupt_handler(void *arg)
0121 {
0122    int minor = (int) arg;
0123    const console_tbl *ct = Console_Port_Tbl[minor];
0124    console_data *cd = &Console_Port_Data[minor];
0125    uint32_t base = ct->ulCtrlPort1;
0126    uint32_t status = xlite_uart_status(base);
0127 
0128    while ((status & RX_FIFO_VALID_DATA) != 0) {
0129       char c = (char) xlite_uart_read(base);
0130 
0131       rtems_termios_enqueue_raw_characters(cd->termios_data, &c, 1);
0132 
0133       status = xlite_uart_status(base);
0134    }
0135 
0136    if (cd->bActive) {
0137       rtems_termios_dequeue_characters(cd->termios_data, 1);
0138    }
0139 }
0140 #endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
0141 
0142 static int xlite_open(
0143   int      major,
0144   int      minor,
0145   void    *arg
0146 )
0147 {
0148    const console_tbl *ct = Console_Port_Tbl[minor];
0149    uint32_t base = ct->ulCtrlPort1;
0150 #if VIRTEX_CONSOLE_USE_INTERRUPTS
0151    rtems_status_code sc;
0152 #endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
0153 
0154    /* clear status register */
0155    *((volatile uint32_t*)(base+STAT_REG)) = 0;
0156 
0157    /* clear control register; reset fifos */
0158    *((volatile uint32_t*)(base+CTRL_REG)) = RST_RX_FIFO | RST_TX_FIFO;
0159 
0160 #if VIRTEX_CONSOLE_USE_INTERRUPTS
0161    *((volatile uint32_t*)(base+CTRL_REG)) = ENABLE_INTR;
0162 
0163    sc = rtems_interrupt_handler_install(
0164       ct->ulIntVector,
0165       "xlite",
0166       RTEMS_INTERRUPT_UNIQUE,
0167       xlite_interrupt_handler,
0168       (void *) minor
0169    );
0170    assert(sc == RTEMS_SUCCESSFUL);
0171 #endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
0172 
0173    return 0;
0174 }
0175 
0176 static int xlite_close(
0177   int      major,
0178   int      minor,
0179   void    *arg
0180 )
0181 {
0182    const console_tbl *ct = Console_Port_Tbl[minor];
0183    uint32_t base = ct->ulCtrlPort1;
0184 #if VIRTEX_CONSOLE_USE_INTERRUPTS
0185    rtems_status_code sc;
0186 #endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
0187 
0188    *((volatile uint32_t*)(base+CTRL_REG)) = 0;
0189 
0190 #if VIRTEX_CONSOLE_USE_INTERRUPTS
0191    sc = rtems_interrupt_handler_remove(
0192       ct->ulIntVector,
0193       xlite_interrupt_handler,
0194       (void *) minor
0195    );
0196    assert(sc == RTEMS_SUCCESSFUL);
0197 #endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
0198 
0199    return 0;
0200 }
0201 
0202 
0203 
0204 static int xlite_read_polled (int minor )
0205 {
0206    uint32_t base = Console_Port_Tbl[minor]->ulCtrlPort1;
0207 
0208    unsigned int status = xlite_uart_status(base);
0209 
0210    if(status & RX_FIFO_VALID_DATA)
0211       return (int)xlite_uart_read(base);
0212    else
0213       return -1;
0214 }
0215 
0216 #if VIRTEX_CONSOLE_USE_INTERRUPTS
0217 
0218 static ssize_t xlite_write_interrupt_driven(
0219   int minor,
0220   const char *buf,
0221   size_t len
0222 )
0223 {
0224   console_data *cd = &Console_Port_Data[minor];
0225 
0226   if (len > 0) {
0227     const console_tbl *ct = Console_Port_Tbl[minor];
0228     uint32_t base = ct->ulCtrlPort1;
0229 
0230     xlite_uart_write(base, buf[0]);
0231 
0232     cd->bActive = true;
0233   } else {
0234     cd->bActive = false;
0235   }
0236 
0237   return 0;
0238 }
0239 
0240 #else /* VIRTEX_CONSOLE_USE_INTERRUPTS */
0241 
0242 static ssize_t xlite_write_buffer_polled(
0243   int         minor,
0244   const char *buf,
0245   size_t      len
0246 )
0247 {
0248    uint32_t base = Console_Port_Tbl[minor]->ulCtrlPort1;
0249    int nwrite = 0;
0250 
0251    /*
0252     * poll each byte in the string out of the port.
0253     */
0254    while (nwrite < len)
0255    {
0256       if( xlite_write_char(base, *buf++) < 0 ) break;
0257       nwrite++;
0258    }
0259 
0260    /*
0261     * return the number of bytes written.
0262     */
0263    return nwrite;
0264 }
0265 
0266 #endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
0267 
0268 static void xlite_write_char_polled(
0269   int   minor,
0270   char  c
0271 )
0272 {
0273    uint32_t base = Console_Port_Tbl[minor]->ulCtrlPort1;
0274    xlite_write_char(base, c);
0275    return;
0276 }
0277 
0278 static int xlite_set_attributes(int minor, const struct termios *t)
0279 {
0280    return RTEMS_SUCCESSFUL;
0281 }
0282 
0283 
0284 
0285 
0286 
0287 
0288 
0289 static const console_fns xlite_fns_polled =
0290 {
0291   .deviceProbe = libchip_serial_default_probe,
0292   .deviceFirstOpen = xlite_open,
0293   .deviceLastClose = xlite_close,
0294   .deviceRead = xlite_read_polled,
0295   .deviceInitialize = xlite_init,
0296   .deviceWritePolled = xlite_write_char_polled,
0297   .deviceSetAttributes = xlite_set_attributes,
0298 #if VIRTEX_CONSOLE_USE_INTERRUPTS
0299   .deviceWrite = xlite_write_interrupt_driven,
0300   .deviceOutputUsesInterrupts = true
0301 #else /* VIRTEX_CONSOLE_USE_INTERRUPTS */
0302   .deviceWrite = xlite_write_buffer_polled,
0303   .deviceOutputUsesInterrupts = false
0304 #endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
0305 };
0306 
0307 
0308 
0309 
0310 
0311 
0312 /*
0313 ** Set ulCtrlPort1 to the base address of each UART Lite instance.  Set in vhdl model.
0314 */
0315 
0316 
0317 console_tbl     Console_Configuration_Ports[] = {
0318 {
0319   "/dev/ttyS0",                             /* sDeviceName */
0320    SERIAL_CUSTOM,                           /* deviceType */
0321    &xlite_fns_polled,                      /* pDeviceFns */
0322    NULL,                                   /* deviceProbe, assume it is there */
0323    NULL,                                   /* pDeviceFlow */
0324    16,                                     /* ulMargin */
0325    8,                                      /* ulHysteresis */
0326    (void *) NULL,               /* NULL */ /* pDeviceParams */
0327    STDIN_BASEADDRESS,                      /* ulCtrlPort1 */
0328    0,                                      /* ulCtrlPort2 */
0329    0,                                      /* ulDataPort */
0330    NULL,                                   /* getRegister */
0331    NULL,                                   /* setRegister */
0332    NULL, /* unused */                      /* getData */
0333    NULL, /* unused */                      /* setData */
0334    0,                                      /* ulClock */
0335    #ifdef XPAR_XPS_INTC_0_RS232_UART_INTERRUPT_INTR
0336      .ulIntVector = XPAR_XPS_INTC_0_RS232_UART_INTERRUPT_INTR
0337    #else
0338      .ulIntVector = 0
0339    #endif
0340 },
0341 #ifdef XPAR_UARTLITE_1_BASEADDR
0342 {
0343   "/dev/ttyS1",                             /* sDeviceName */
0344    SERIAL_CUSTOM,                           /* deviceType */
0345    &xlite_fns_polled,                       /* pDeviceFns */
0346    NULL,                                   /* deviceProbe, assume it is there */
0347    NULL,                                   /* pDeviceFlow */
0348    16,                                     /* ulMargin */
0349    8,                                      /* ulHysteresis */
0350    (void *) NULL,               /* NULL */ /* pDeviceParams */
0351    XPAR_UARTLITE_1_BASEADDR,               /* ulCtrlPort1 */
0352    0,                                      /* ulCtrlPort2 */
0353    0,                                      /* ulDataPort */
0354    NULL,                                   /* getRegister */
0355    NULL,                                   /* setRegister */
0356    NULL, /* unused */                      /* getData */
0357    NULL, /* unused */                      /* setData */
0358    0,                                      /* ulClock */
0359    0                                       /* ulIntVector -- base for port */
0360 },
0361 #endif
0362 #ifdef XPAR_UARTLITE_2_BASEADDR
0363 {
0364   "/dev/ttyS2",                             /* sDeviceName */
0365    SERIAL_CUSTOM,                           /* deviceType */
0366    &xlite_fns_polled,                       /* pDeviceFns */
0367    NULL,                                   /* deviceProbe, assume it is there */
0368    NULL,                                   /* pDeviceFlow */
0369    16,                                     /* ulMargin */
0370    8,                                      /* ulHysteresis */
0371    (void *) NULL,               /* NULL */ /* pDeviceParams */
0372    XPAR_UARTLITE_2_BASEADDR,               /* ulCtrlPort1 */
0373    0,                                      /* ulCtrlPort2 */
0374    0,                                      /* ulDataPort */
0375    NULL,                                   /* getRegister */
0376    NULL,                                   /* setRegister */
0377    NULL, /* unused */                      /* getData */
0378    NULL, /* unused */                      /* setData */
0379    0,                                      /* ulClock */
0380    0                                       /* ulIntVector -- base for port */
0381 },
0382 #endif
0383 #ifdef XPAR_UARTLITE_2_BASEADDR
0384 {
0385   "/dev/ttyS3",                             /* sDeviceName */
0386    SERIAL_CUSTOM,                           /* deviceType */
0387    &xlite_fns_polled,                       /* pDeviceFns */
0388    NULL,                                   /* deviceProbe, assume it is there */
0389    NULL,                                   /* pDeviceFlow */
0390    16,                                     /* ulMargin */
0391    8,                                      /* ulHysteresis */
0392    (void *) NULL,               /* NULL */ /* pDeviceParams */
0393    XPAR_UARTLITE_3_BASEADDR,               /* ulCtrlPort1 */
0394    0,                                      /* ulCtrlPort2 */
0395    0,                                      /* ulDataPort */
0396    NULL,                                   /* getRegister */
0397    NULL,                                   /* setRegister */
0398    NULL, /* unused */                      /* getData */
0399    NULL, /* unused */                      /* setData */
0400    0,                                      /* ulClock */
0401    0                                       /* ulIntVector -- base for port */
0402 }
0403 #endif
0404 };
0405 
0406 unsigned long Console_Configuration_Count =
0407   RTEMS_ARRAY_SIZE(Console_Configuration_Ports);
0408 
0409 
0410 #include <rtems/bspIo.h>
0411 
0412 static void outputChar(char ch)
0413 {
0414    xlite_write_char_polled( 0, ch );
0415 }
0416 
0417 static int inputChar(void)
0418 {
0419    return xlite_read_polled(0);
0420 }
0421 
0422 BSP_output_char_function_type BSP_output_char = outputChar;
0423 BSP_polling_getchar_function_type BSP_poll_char = inputChar;
0424 
0425