1 /* 2 * marvell kirkwood uart (supposed to be a 16550) 3 */ 4 #include "u.h" 5 #include "../port/lib.h" 6 #include "mem.h" 7 #include "dat.h" 8 #include "fns.h" 9 #include "io.h" 10 #include "../port/error.h" 11 // #include "../port/uart.h" 12 13 enum { 14 UartFREQ = 0, // xxx 15 16 IERrx = 1<<0, 17 IERtx = 1<<1, 18 19 IRRintrmask = (1<<4)-1, 20 IRRnointr = 1, 21 IRRthrempty = 2, 22 IRRrxdata = 4, 23 IRRrxstatus = 6, 24 IRRtimeout = 12, 25 26 IRRfifomask = 3<<6, 27 IRRfifoenable = 3<<6, 28 29 FCRenable = 1<<0, 30 FCRrxreset = 1<<1, 31 FCRtxreset = 1<<2, 32 /* reserved */ 33 FCRrxtriggermask = 3<<6, 34 FCRrxtrigger1 = 0<<6, 35 FCRrxtrigger4 = 1<<6, 36 FCRrxtrigger8 = 2<<6, 37 FCRrxtrigger14 = 3<<6, 38 39 LCRbpcmask = 3<<0, 40 LCRbpc5 = 0<<0, 41 LCRbpc6 = 1<<0, 42 LCRbpc7 = 2<<0, 43 LCRbpc8 = 3<<0, 44 LCRstop2b = 1<<2, 45 LCRparity = 1<<3, 46 LCRparityeven = 1<<4, 47 LCRbreak = 1<<6, 48 LCRdivlatch = 1<<7, 49 50 LSRrx = 1<<0, 51 LSRrunerr = 1<<1, 52 LSRparerr = 1<<2, 53 LSRframeerr = 1<<3, 54 LSRbi = 1<<4, 55 LSRthre = 1<<5, 56 LSRtxempty = 1<<6, 57 LSRfifoerr = 1<<7, 58 }; 59 60 extern PhysUart kwphysuart; 61 62 #define UART0REG ((UartReg*)AddrUart0) 63 64 typedef struct UartReg UartReg; 65 struct UartReg 66 { 67 union { 68 ulong thr; 69 ulong dll; 70 ulong rbr; 71 }; 72 union { 73 ulong ier; 74 ulong dlh; 75 }; 76 union { 77 ulong iir; 78 ulong fcr; 79 }; 80 ulong lcr; 81 ulong mcr; 82 ulong lsr; 83 ulong scr; 84 }; 85 86 typedef struct Ctlr Ctlr; 87 struct Ctlr { 88 UartReg*regs; 89 int irq; 90 Lock; 91 }; 92 93 static Ctlr kirkwoodctlr[] = { 94 { 95 .regs = UART0REG, 96 .irq = IRQ1uart0, }, 97 }; 98 99 static Uart kirkwooduart[] = { 100 { 101 .regs = &kirkwoodctlr[0], 102 .name = "eia0", 103 .freq = UartFREQ, 104 .phys = &kwphysuart, 105 .special= 0, 106 .console= 1, 107 .next = nil, }, 108 }; 109 110 static void 111 kw_read(Uart *uart) 112 { 113 Ctlr *ctlr = uart->regs; 114 UartReg *regs = ctlr->regs; 115 ulong lsr; 116 char c; 117 118 while ((lsr = regs->lsr) & LSRrx) { 119 if(lsr&LSRrunerr) 120 uart->oerr++; 121 if(lsr&LSRparerr) 122 uart->perr++; 123 if(lsr&LSRframeerr) 124 uart->ferr++; 125 c = regs->rbr; 126 if((lsr & (LSRbi|LSRframeerr|LSRparerr)) == 0) 127 uartrecv(uart, c); 128 } 129 } 130 131 static void 132 kw_intr(Ureg*, void *arg) 133 { 134 Uart *uart = arg; 135 Ctlr *ctlr = uart->regs; 136 UartReg *regs = ctlr->regs; 137 ulong v; 138 139 v = regs->iir; 140 if(v & IRRthrempty) 141 uartkick(uart); 142 if(v & IRRrxdata) 143 kw_read(uart); 144 145 intrclear(Irqhi, ctlr->irq); 146 } 147 148 static Uart* 149 kw_pnp(void) 150 { 151 return kirkwooduart; 152 } 153 154 static void 155 kw_enable(Uart* uart, int ie) 156 { 157 Ctlr *ctlr = uart->regs; 158 UartReg *regs = ctlr->regs; 159 160 USED(ie); 161 regs->fcr = FCRenable|FCRrxtrigger4; 162 regs->ier = IERrx|IERtx; 163 intrenable(Irqhi, ctlr->irq, kw_intr, uart, uart->name); 164 165 (*uart->phys->dtr)(uart, 1); 166 (*uart->phys->rts)(uart, 1); 167 } 168 169 static void 170 kw_disable(Uart* uart) 171 { 172 Ctlr *ctlr = uart->regs; 173 174 (*uart->phys->dtr)(uart, 0); 175 (*uart->phys->rts)(uart, 0); 176 (*uart->phys->fifo)(uart, 0); 177 178 intrdisable(Irqhi, ctlr->irq, kw_intr, uart, uart->name); 179 } 180 181 static void 182 kw_kick(Uart* uart) 183 { 184 Ctlr *ctlr = uart->regs; 185 UartReg *regs = ctlr->regs; 186 int i; 187 188 if(uart->cts == 0 || uart->blocked) 189 return; 190 191 for(i = 0; i < 16; i++) { 192 if((regs->lsr & LSRthre) == 0 || 193 uart->op >= uart->oe && uartstageoutput(uart) == 0) 194 break; 195 regs->thr = *uart->op++; 196 } 197 } 198 199 static void 200 kw_break(Uart* uart, int ms) 201 { 202 USED(uart, ms); 203 } 204 205 static int 206 kw_baud(Uart* uart, int baud) 207 { 208 USED(uart, baud); 209 return 0; 210 } 211 212 static int 213 kw_bits(Uart* uart, int bits) 214 { 215 USED(uart, bits); 216 return 0; 217 } 218 219 static int 220 kw_stop(Uart* uart, int stop) 221 { 222 USED(uart, stop); 223 return 0; 224 } 225 226 static int 227 kw_parity(Uart* uart, int parity) 228 { 229 USED(uart, parity); 230 return 0; 231 } 232 233 static void 234 kw_modemctl(Uart* uart, int on) 235 { 236 USED(uart, on); 237 } 238 239 static void 240 kw_rts(Uart* uart, int on) 241 { 242 USED(uart, on); 243 } 244 245 static void 246 kw_dtr(Uart* uart, int on) 247 { 248 USED(uart, on); 249 } 250 251 static long 252 kw_status(Uart* uart, void* buf, long n, long offset) 253 { 254 USED(uart, buf, n, offset); 255 return 0; 256 } 257 258 static void 259 kw_fifo(Uart* uart, int level) 260 { 261 USED(uart, level); 262 } 263 264 static int 265 kw_getc(Uart *uart) 266 { 267 Ctlr *ctlr = uart->regs; 268 UartReg *regs = ctlr->regs; 269 270 while((regs->lsr&LSRrx) == 0) 271 ; 272 return regs->rbr; 273 } 274 275 static void 276 kw_putc(Uart *uart, int c) 277 { 278 Ctlr *ctlr = uart->regs; 279 UartReg *regs = ctlr->regs; 280 281 while((regs->lsr&LSRthre) == 0) 282 ; 283 regs->thr = c; 284 } 285 286 PhysUart kwphysuart = { 287 .name = "kirkwood", 288 .pnp = kw_pnp, 289 .enable = kw_enable, 290 .disable = kw_disable, 291 .kick = kw_kick, 292 .dobreak = kw_break, 293 .baud = kw_baud, 294 .bits = kw_bits, 295 .stop = kw_stop, 296 .parity = kw_parity, 297 .modemctl = kw_modemctl, 298 .rts = kw_rts, 299 .dtr = kw_dtr, 300 .status = kw_status, 301 .fifo = kw_fifo, 302 .getc = kw_getc, 303 .putc = kw_putc, 304 }; 305 306 void 307 uartkirkwoodconsole(void) 308 { 309 Uart *uart; 310 311 uart = &kirkwooduart[0]; 312 (*uart->phys->enable)(uart, 0); 313 uartctl(uart, "b115200 l8 pn s1 i1"); 314 uart->console = 1; 315 consuart = uart; 316 //serialputs("uart0 kirkwood\n", strlen("uart0 kirkwood\n")); 317 } 318 319 void 320 serialputc(int c) 321 { 322 int cnt, s; 323 324 s = splhi(); 325 cnt = m->cpuhz; 326 if (cnt <= 0) /* cpuhz not set yet? */ 327 cnt = 1000000; 328 while((UART0REG->lsr & LSRthre) == 0 && --cnt > 0) 329 ; 330 UART0REG->thr = c; 331 delay(1); 332 splx(s); 333 } 334 335 void 336 serialputs(char *p, int len) 337 { 338 while(--len >= 0) { 339 if(*p == '\n') 340 serialputc('\r'); 341 serialputc(*p++); 342 } 343 } 344