1#include <barrelfish/barrelfish.h> 2#include "serial.h" 3#include <barrelfish/inthandler.h> 4#include <driverkit/driverkit.h> 5 6#include <dev/omap/omap44xx_uart3_dev.h> 7#include <arch/arm/omap44xx/device_registers.h> 8#include <maps/omap44xx_map.h> 9 10/* XXX */ 11#define UART_IRQ (32+74) 12 13#define DEFAULT_MEMBASE OMAP44XX_MAP_L4_PER_UART3 14 15static omap44xx_uart3_t port; 16 17static void serial_poll(omap44xx_uart3_t *uart) 18{ 19 // Read while we can 20 while(omap44xx_uart3_lsr_rx_fifo_e_rdf(uart)) { 21 char c = omap44xx_uart3_rhr_rhr_rdf(uart); 22 serial_input(&c, 1); 23 } 24} 25 26static void serial_interrupt(void *arg) 27{ 28 // get type 29 omap44xx_uart3_iir_t iir= omap44xx_uart3_iir_rd(&port); 30 31 if (omap44xx_uart3_iir_it_pending_extract(iir) == 0) { 32 omap44xx_uart3_it_type_status_t it_type= 33 omap44xx_uart3_iir_it_type_extract(iir); 34 switch(it_type) { 35 case omap44xx_uart3_it_modem: 36 omap44xx_uart3_msr_rd(&port); 37 break; 38 case omap44xx_uart3_it_rxtimeout: 39 case omap44xx_uart3_it_rhr: 40 serial_poll(&port); 41 break; 42 default: 43 debug_printf("serial_interrupt: unhandled irq: %d\n", it_type); 44 break; 45 } 46 } 47} 48 49static bool convert_rx_simple(uint8_t *trig) 50{ 51 switch(*trig) { 52 case 8: 53 *trig = 0; 54 return true; 55 case 16: 56 *trig = 1; 57 return true; 58 case 56: 59 *trig = 2; 60 return true; 61 case 60: 62 *trig = 3; 63 return true; 64 default: 65 return false; 66 } 67} 68 69static bool convert_tx_simple(uint8_t *trig) 70{ 71 switch(*trig) { 72 case 8: 73 *trig = 0; 74 return true; 75 case 16: 76 *trig = 1; 77 return true; 78 case 32: 79 *trig = 2; 80 return true; 81 case 56: 82 *trig = 3; 83 return true; 84 default: 85 return false; 86 } 87} 88 89/* 90 * Initialzie OMAP UART with interrupt 91 * UART TRM 23.3 92 */ 93static void omap44xx_uart3_init(omap44xx_uart3_t *uart, lvaddr_t base) 94{ 95 // XXX: test this with other values 96 // rx and tx FIFO threshold values (1 -- 63) 97 uint8_t rx_trig = 1; // amount of characters in fifo 98 uint8_t tx_trig = 63; // amount of free spaces in fifo 99 bool need_rx_1b = convert_rx_simple(&rx_trig); 100 bool need_tx_1b = convert_tx_simple(&tx_trig); 101 102 omap44xx_uart3_initialize(uart, (mackerel_addr_t) base); 103 // do soft reset -- not the best idea if we rely on the same UART for 104 // debug output 105 //omap44xx_uart3_sysc_softreset_wrf(uart, 0x1); 106 //while (!omap44xx_uart3_syss_resetdone_rdf(uart)); // poll for reset completion 107 108 // configure FIFOs according to TRM (section 25.3.5.1.1.2) 109 //1 switch to config mode B (access to efr register): set lcr to 0xbf 110 omap44xx_uart3_lcr_t old_lcr = omap44xx_uart3_lcr_rd(uart); 111 omap44xx_uart3_lcr_wr(uart, 0xbf); 112 // 1.1 disable baud clock so we can write to FCR[0] and FCR[3] 113 omap44xx_uart3_dll_clock_lsb_wrf(uart, 0x0); 114 omap44xx_uart3_dlh_clock_msb_wrf(uart, 0x0); 115 //2 enable register submode tlr to access tlr register 116 omap44xx_uart3_enhanced_en_status_t old_enhanced_en = 117 omap44xx_uart3_efr_enhanced_en_rdf(uart); 118 omap44xx_uart3_efr_enhanced_en_wrf(uart, 1); 119 //3 switch to config mode A (access to mcr register): set lcr to: 0x80 120 omap44xx_uart3_lcr_wr(uart, 0x80); 121 //4 enable register submode tlr to access tlr register 122 omap44xx_uart3_tcr_tlr_status_t old_tcr_tlr = 123 omap44xx_uart3_mcr_tcr_tlr_rdf(uart); 124 omap44xx_uart3_mcr_tcr_tlr_wrf(uart, 1); 125 //5 enable FIFO, load FIFO triggers, load DMA mode (part1) 126 omap44xx_uart3_fcr_t fcr = omap44xx_uart3_fcr_default; 127 // set trigger lvls of rx and tx FIFOs (defined above) 128 fcr = omap44xx_uart3_fcr_rx_fifo_trig_insert(fcr, rx_trig&0x3); 129 fcr = omap44xx_uart3_fcr_tx_fifo_trig_insert(fcr, tx_trig&0x3); 130 fcr = omap44xx_uart3_fcr_dma_mode_insert(fcr, 0); // no DMA 131 fcr = omap44xx_uart3_fcr_fifo_en_insert(fcr, 0); // enable FIFOs 132 omap44xx_uart3_fcr_wr(uart, fcr); 133 //6 switch to config mode B 134 omap44xx_uart3_lcr_wr(uart, 0xbf); 135 //7 load FIFO triggers (DMA only?, part2) 136 omap44xx_uart3_tlr_t tlr = omap44xx_uart3_tlr_default; 137 omap44xx_uart3_tlr_rx_fifo_trig_dma_insert(tlr, rx_trig>>2); 138 omap44xx_uart3_tlr_tx_fifo_trig_dma_insert(tlr, tx_trig>>2); 139 omap44xx_uart3_tlr_wr(uart, tlr); 140 //8 load new FIFO triggers & new DMA mode (part3) 141 omap44xx_uart3_scr_t scr = omap44xx_uart3_scr_default; 142 // make FIFO trigger levels byte granularity 143 // --> lvl = { *_fifo_trig_dma : *_fifo_trig } 144 scr = omap44xx_uart3_scr_rx_trig_granu1_insert(scr, need_rx_1b); 145 scr = omap44xx_uart3_scr_tx_trig_granu1_insert(scr, need_tx_1b); 146 scr = omap44xx_uart3_scr_dma_mode_2_insert(scr, 0); // no DMA 147 scr = omap44xx_uart3_scr_dma_mode_ctl_insert(scr, 0); // shouldn't matter w/ DMA off 148 omap44xx_uart3_scr_wr(uart, scr); 149 //8b clear fifo queues 150 omap44xx_uart3_fcr_rx_fifo_clear_wrf(uart, 1); 151 omap44xx_uart3_fcr_tx_fifo_clear_wrf(uart, 1); 152 //9 restore enhanced_en 153 omap44xx_uart3_efr_enhanced_en_wrf(uart, old_enhanced_en); 154 //10 switch to config mode A 155 omap44xx_uart3_lcr_wr(uart, 0x80); 156 //11 restore TCR_TLR 157 omap44xx_uart3_mcr_tcr_tlr_wrf(uart, old_tcr_tlr); 158 //12 restore LCR 159 omap44xx_uart3_lcr_wr(uart, old_lcr); 160 161 // configure protocol, baud rate and irq according to trm (section 162 // 23.3.5.1.1.3) 163 //1 disable UART access to DLL and DLH regs 164 omap44xx_uart3_mdr1_mode_select_wrf(uart, 0x7); 165 //2 switch to register config mode B 166 omap44xx_uart3_lcr_wr(uart, 0xbf); 167 //3 enable access to IER bit field 168 old_enhanced_en = omap44xx_uart3_efr_enhanced_en_rdf(uart); 169 omap44xx_uart3_efr_enhanced_en_wrf(uart, 1); 170 //4 switch to reg operational mode to access IER register 171 omap44xx_uart3_lcr_wr(uart, 0); 172 //5 clear IER register 173 omap44xx_uart3_ier_wr(uart, 0); 174 //6 config mode B 175 omap44xx_uart3_lcr_wr(uart, 0xbf); 176 //7 new divisor value --> 115200 baud == 0x00, 0x1A (dlh, dll) 177 omap44xx_uart3_dll_clock_lsb_wrf(uart, 0x1a); 178 omap44xx_uart3_dlh_clock_msb_wrf(uart, 0x0); 179 //8 register operational mode 180 omap44xx_uart3_lcr_wr(uart, 0); 181 //9 load irq config --> only rhr irq for now 182 omap44xx_uart3_ier_rhr_it_wrf(uart, 1); 183 //10 register config mode B 184 omap44xx_uart3_lcr_wr(uart, 0xbf); 185 //11 restore efr.enhanced_en 186 omap44xx_uart3_efr_enhanced_en_wrf(uart, old_enhanced_en); 187 //12 load protocol formatting --> 8N1 188 omap44xx_uart3_lcr_t lcr = omap44xx_uart3_lcr_default; 189 lcr = omap44xx_uart3_lcr_parity_en_insert(lcr, 0); // No parity 190 lcr = omap44xx_uart3_lcr_nb_stop_insert(lcr, 0); // 1 stop bit 191 lcr = omap44xx_uart3_lcr_char_length_insert(lcr, omap44xx_uart3_cl8); // 8 data bits 192 omap44xx_uart3_lcr_wr(uart, lcr); 193 //13 load UART mode 194 omap44xx_uart3_mdr1_mode_select_wrf(uart, 0x0); 195 // DONE 196} 197 198 199static 200errval_t real_init(uint32_t membase) { 201 // XXX: TODO: figure this out --> kaluga magic? 202 errval_t err; 203 lvaddr_t vbase; 204 err = map_device_register(membase, BASE_PAGE_SIZE, &vbase); 205 if (err_is_fail(err)) { 206 USER_PANIC_ERR(err, "map_device_register failed\n"); 207 return err; 208 } 209 assert(vbase); 210 211 // paging_map_device returns an address pointing to the beginning of 212 // a section, need to add the offset for within the section again 213 debug_printf("omap serial_init base = 0x%"PRIxLVADDR"\n", vbase); 214 omap44xx_uart3_init(&port, vbase); 215 debug_printf("omap serial_init[%d]: done.\n", port); 216 return SYS_ERR_OK; 217} 218 219errval_t serial_init(struct serial_params *params) 220{ 221 uint32_t membase= DEFAULT_MEMBASE; 222 if(params->membase != SERIAL_MEMBASE_INVALID) 223 membase= (uint32_t)params->membase; 224 225 uint8_t irq= UART_IRQ; 226 if(params->irq != SERIAL_IRQ_INVALID) 227 irq= params->irq; 228 229 // initialize hardware 230 errval_t err = real_init(membase); 231 if (err_is_fail(err)) { 232 USER_PANIC_ERR(err, "serial_init failed\n"); 233 return -1; 234 } 235 236 // register interrupt 237 err = inthandler_setup_arm(serial_interrupt, NULL, irq); 238 if (err_is_fail(err)) { 239 USER_PANIC_ERR(err, "interrupt setup failed."); 240 } 241 242 // offer service now we're up 243 start_service(); 244 return SYS_ERR_OK; 245} 246 247/** output a single character */ 248static void serial_putchar(char c) 249{ 250 // Wait until FIFO can hold more characters 251 while (!omap44xx_uart3_lsr_tx_fifo_e_rdf(&port)); 252 // Write character 253 omap44xx_uart3_thr_thr_wrf(&port, c); 254} 255 256/** write string to serial port */ 257void serial_write(const char *c, size_t len) 258{ 259 for (int i = 0; i < len; i++) { 260 serial_putchar(c[i]); 261 } 262} 263