Prex Home / Browse Source - Prex Version: 0.9.0

root/bsp/drv/dev/serial/pl011.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pl011_xmt_char
  2. pl011_rcv_char
  3. pl011_set_poll
  4. pl011_isr
  5. pl011_start
  6. pl011_stop
  7. pl011_init

   1 /*-
   2  * Copyright (c) 2008-2009, Kohsuke Ohtani
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. Neither the name of the author nor the names of any co-contributors
  14  *    may be used to endorse or promote products derived from this software
  15  *    without specific prior written permission.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  */
  29 
  30 /*
  31  * pl011.c - ARM PrimeCell PL011 UART
  32  */
  33 
  34 #include <driver.h>
  35 #include <tty.h>
  36 #include <serial.h>
  37 
  38 /* #define DEBUG_PL011 1 */
  39 
  40 #ifdef DEBUG_PL011
  41 #define DPRINTF(a) printf a
  42 #else
  43 #define DPRINTF(a)
  44 #endif
  45 
  46 #define UART_BASE       CONFIG_PL011_BASE
  47 #define UART_IRQ        CONFIG_PL011_IRQ
  48 #define UART_CLK        14745600
  49 #define BAUD_RATE       115200
  50 
  51 /* UART Registers */
  52 #define UART_DR         (UART_BASE + 0x00)
  53 #define UART_RSR        (UART_BASE + 0x04)
  54 #define UART_ECR        (UART_BASE + 0x04)
  55 #define UART_FR         (UART_BASE + 0x18)
  56 #define UART_IBRD       (UART_BASE + 0x24)
  57 #define UART_FBRD       (UART_BASE + 0x28)
  58 #define UART_LCRH       (UART_BASE + 0x2c)
  59 #define UART_CR         (UART_BASE + 0x30)
  60 #define UART_IMSC       (UART_BASE + 0x38)
  61 #define UART_MIS        (UART_BASE + 0x40)
  62 #define UART_ICR        (UART_BASE + 0x44)
  63 
  64 /* Flag register */
  65 #define FR_RXFE         0x10    /* Receive FIFO empty */
  66 #define FR_TXFF         0x20    /* Transmit FIFO full */
  67 
  68 /* Masked interrupt status register */
  69 #define MIS_RX          0x10    /* Receive interrupt */
  70 #define MIS_TX          0x20    /* Transmit interrupt */
  71 
  72 /* Interrupt clear register */
  73 #define ICR_RX          0x10    /* Clear receive interrupt */
  74 #define ICR_TX          0x20    /* Clear transmit interrupt */
  75 
  76 /* Line control register (High) */
  77 #define LCRH_WLEN8      0x60    /* 8 bits */
  78 #define LCRH_FEN        0x10    /* Enable FIFO */
  79 
  80 /* Control register */
  81 #define CR_UARTEN       0x0001  /* UART enable */
  82 #define CR_TXE          0x0100  /* Transmit enable */
  83 #define CR_RXE          0x0200  /* Receive enable */
  84 
  85 /* Interrupt mask set/clear register */
  86 #define IMSC_RX         0x10    /* Receive interrupt mask */
  87 #define IMSC_TX         0x20    /* Transmit interrupt mask */
  88 
  89 /* Forward functions */
  90 static int      pl011_init(struct driver *);
  91 static void     pl011_xmt_char(struct serial_port *, char);
  92 static char     pl011_rcv_char(struct serial_port *);
  93 static void     pl011_set_poll(struct serial_port *, int);
  94 static void     pl011_start(struct serial_port *);
  95 static void     pl011_stop(struct serial_port *);
  96 
  97 
  98 struct driver pl011_driver = {
  99         /* name */      "pl011",
 100         /* devops */    NULL,
 101         /* devsz */     0,
 102         /* flags */     0,
 103         /* probe */     NULL,
 104         /* init */      pl011_init,
 105         /* detach */    NULL,
 106 };
 107 
 108 static struct serial_ops pl011_ops = {
 109         /* xmt_char */  pl011_xmt_char,
 110         /* rcv_char */  pl011_rcv_char,
 111         /* set_poll */  pl011_set_poll,
 112         /* start */     pl011_start,
 113         /* stop */      pl011_stop,
 114 };
 115 
 116 static struct serial_port pl011_port;
 117 
 118 
 119 static void
 120 pl011_xmt_char(struct serial_port *sp, char c)
 121 {
 122 
 123         while (bus_read_32(UART_FR) & FR_TXFF)
 124                 ;
 125         bus_write_32(UART_DR, (uint32_t)c);
 126 }
 127 
 128 static char
 129 pl011_rcv_char(struct serial_port *sp)
 130 {
 131         char c;
 132 
 133         while (bus_read_32(UART_FR) & FR_RXFE)
 134                 ;
 135         c = bus_read_32(UART_DR) & 0xff;
 136         return c;
 137 }
 138 
 139 static void
 140 pl011_set_poll(struct serial_port *sp, int on)
 141 {
 142 
 143         if (on) {
 144                 /*
 145                  * Disable interrupt for polling mode.
 146                  */
 147                 bus_write_32(UART_IMSC, 0);
 148         } else
 149                 bus_write_32(UART_IMSC, (IMSC_RX | IMSC_TX));
 150 }
 151 
 152 static int
 153 pl011_isr(void *arg)
 154 {
 155         struct serial_port *sp = arg;
 156         int c;
 157         uint32_t mis;
 158 
 159         mis = bus_read_32(UART_MIS);
 160 
 161         if (mis & MIS_RX) {
 162                 /*
 163                  * Receive interrupt
 164                  */
 165                 while (bus_read_32(UART_FR) & FR_RXFE)
 166                         ;
 167                 do {
 168                         c = bus_read_32(UART_DR);
 169                         serial_rcv_char(sp, c);
 170                 } while ((bus_read_32(UART_FR) & FR_RXFE) == 0);
 171 
 172                 /* Clear interrupt status */
 173                 bus_write_32(UART_ICR, ICR_RX);
 174         }
 175         if (mis & MIS_TX) {
 176                 /*
 177                  * Transmit interrupt
 178                  */
 179                 serial_xmt_done(sp);
 180 
 181                 /* Clear interrupt status */
 182                 bus_write_32(UART_ICR, ICR_TX);
 183         }
 184         return 0;
 185 }
 186 
 187 static void
 188 pl011_start(struct serial_port *sp)
 189 {
 190         uint32_t divider, remainder, fraction;
 191 
 192         bus_write_32(UART_CR, 0);       /* Disable everything */
 193         bus_write_32(UART_ICR, 0x07ff); /* Clear all interrupt status */
 194 
 195         /*
 196          * Set baud rate:
 197          * IBRD = UART_CLK / (16 * BAUD_RATE)
 198          * FBRD = ROUND((64 * MOD(UART_CLK,(16 * BAUD_RATE))) / (16 * BAUD_RATE))
 199          */
 200         divider = UART_CLK / (16 * BAUD_RATE);
 201         remainder = UART_CLK % (16 * BAUD_RATE);
 202         fraction = (8 * remainder / BAUD_RATE) >> 1;
 203         fraction += (8 * remainder / BAUD_RATE) & 1;
 204         bus_write_32(UART_IBRD, divider);
 205         bus_write_32(UART_FBRD, fraction);
 206 
 207         /* Set N, 8, 1, FIFO enable */
 208         bus_write_32(UART_LCRH, (LCRH_WLEN8 | LCRH_FEN));
 209 
 210         /* Enable UART */
 211         bus_write_32(UART_CR, (CR_RXE | CR_TXE | CR_UARTEN));
 212 
 213         /* Install interrupt handler */
 214         sp->irq = irq_attach(UART_IRQ, IPL_COMM, 0, pl011_isr, IST_NONE, sp);
 215 
 216         /* Enable TX/RX interrupt */
 217         bus_write_32(UART_IMSC, (IMSC_RX | IMSC_TX));
 218 }
 219 
 220 static void
 221 pl011_stop(struct serial_port *sp)
 222 {
 223 
 224         bus_write_32(UART_IMSC, 0);     /* Disable all interrupts */
 225         bus_write_32(UART_CR, 0);       /* Disable everything */
 226 }
 227 
 228 static int
 229 pl011_init(struct driver *self)
 230 {
 231 
 232         serial_attach(&pl011_ops, &pl011_port);
 233         return 0;
 234 }

/* [<][>][^][v][top][bottom][index][help] */