|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/bsp/drv/dev/serial/pl011.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.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] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |