serial.c (2394B)
1 /* serial.c 2 * 3 * Copyright 2011 Brian Swetland <swetland@frotz.net> 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #include <fw/types.h> 19 #include <fw/io.h> 20 #include <fw/lib.h> 21 22 #include <arch/hardware.h> 23 24 static void (*serial_async_cb)(char c); 25 26 /* only works for multiples of 12MHz and 115.2kbaud right now */ 27 void serial_init(unsigned sysclk_mhz, unsigned baud) { 28 29 if (sysclk_mhz % 12000000) 30 return; 31 if (baud != 115200) 32 return; 33 34 /* XXX: this is board specific */ 35 writel(IOCON_FUNC_1 | IOCON_DIGITAL, IOCON_PIO1_6); /* RXD */ 36 writel(IOCON_FUNC_1 | IOCON_DIGITAL, IOCON_PIO1_7); /* TXD */ 37 38 writel(sysclk_mhz / 12000000, SYS_DIV_UART); /* SYS / n -> 12MHz */ 39 writel(readl(SYS_CLK_CTRL) | SYS_CLK_UART, SYS_CLK_CTRL); 40 41 writel(0x80, 0x4000800C); /* DLAB=1 */ 42 writel(0x04, 0x40008000); /* DLL=4 */ 43 writel(0x00, 0x40008004); /* DLM=0 */ 44 writel(0x85, 0x40008028); /* DIVADDVAL=5, MULVAL=8 */ 45 writel(0x03, 0x4000800C); /* DLAB=0, 8N1 */ 46 writel(0x00, 0x40008010); /* no flow control */ 47 writel(1, 0x40008008); /* enable FIFO */ 48 writel(1, 0x40008008); /* enable FIFO */ 49 } 50 51 void serial_putc(unsigned c) { 52 /* wait until xmit holding register is empty */ 53 while (!(readl(0x40008014) & (1 << 5))) ; 54 writel(c, 0x40008000); 55 } 56 57 void serial_start_async_rx(void (*async_cb)(char c)) 58 { 59 serial_async_cb = async_cb; 60 61 writel((1<<2) | (1<<0), 0x40008004); /* IER=1, receive data avail */ 62 } 63 64 void handle_irq_uart(void) 65 { 66 do { 67 u32 lsr = readl(0x40008014); 68 if (lsr & (1<<1)) { 69 serial_async_cb('O'); 70 } 71 if (lsr & (1<<2)) { 72 serial_async_cb('P'); 73 } 74 if (lsr & (1<<3)) { 75 serial_async_cb('F'); 76 } 77 if (lsr & (1<<4)) { 78 serial_async_cb('B'); 79 } 80 if (lsr & (1<<7)) { 81 serial_async_cb('E'); 82 } 83 if (lsr & (1<<0)) { 84 char c = readl(0x40008000); 85 if (serial_async_cb) 86 serial_async_cb(c); 87 continue; /* we got a char, try again */ 88 } 89 } while (0); 90 } 91