1 /* $Id: imxuart.c,v 1.3 2008/06/30 00:46:41 perry Exp $ */ 2 #include <sys/types.h> 3 #include <sys/systm.h> 4 #include <sys/device.h> 5 #include <sys/conf.h> 6 7 #include <arm/armreg.h> 8 9 #include <sys/tty.h> 10 #include <sys/termios.h> 11 #include <dev/cons.h> 12 13 #include <machine/bus.h> 14 #include <arm/imx/imx31var.h> 15 #include <arm/imx/imxuartreg.h> 16 #include <arm/imx/imxuartvar.h> 17 #include <evbarm/imx31/imx31lk_reg.h> 18 19 #define IMXUART_UNIT_MASK 0x7ffff 20 #define IMXUART_DIALOUT_MASK 0x80000 21 22 #define IMXUART_UNIT(dev) (minor(dev) & IMXUART_UNIT_MASK) 23 #define IMXUART_DIALOUT(dev) (minor(dev) & IMXUART_DIALOUT_MASK) 24 25 26 27 #define __TRACE imxuart_puts(&imxuart_softc, __func__ ) 28 29 extern struct bus_space imx31_bs_tag; 30 31 imxuart_softc_t imxuart_softc = { { 0, }, }; 32 33 uint32_t imxuart_snapshot_data[32]; 34 const char *imxuart_test_string = 35 "0123456789012345678901234567890123456789\r\n"; 36 37 38 cons_decl(imxuart); 39 static struct consdev imxuartcntab = cons_init(imxuart); 40 41 #ifdef NOTYET 42 dev_type_open(imxuartopen); 43 dev_type_close(imxuartclose); 44 dev_type_read(imxuartread); 45 dev_type_write(imxuartwrite); 46 dev_type_ioctl(imxuartioctl); 47 dev_type_stop(imxuartstop); 48 dev_type_tty(imxuarttty); 49 dev_type_poll(imxuartpoll); 50 const struct cdevsw imxuart_cdevsw = { 51 imxuartopen, imxuartclose, imxuartread, imxuartwrite, 52 imxuartioctl, imxuartstop, imxuarttty, imxuartpoll, 53 nommap, ttykqfilter, D_TTY 54 }; 55 #else 56 const struct cdevsw imxuart_cdevsw = { 57 nullopen, nullclose, nullread, nullwrite, 58 nullioctl, nullstop, notty, nullpoll, 59 nommap, nullkqfilter, D_TTY 60 }; 61 #endif 62 63 64 int imxuart_cnattach(bus_space_tag_t, bus_addr_t, int, int, int, tcflag_t); 65 int imxuart_puts(imxuart_softc_t *, const char *); 66 int imxuart_putchar(imxuart_softc_t *, int); 67 int imxuart_getchar(imxuart_softc_t *); 68 69 static int imxuart_urxd_brk(void); 70 static void imxuart_urxd_err(imxuart_softc_t *, uint32_t); 71 72 static int imxuart_match(struct device *, struct cfdata *, void *); 73 static void imxuart_attach(struct device *, struct device *, void *); 74 75 static void imxuart_start(struct tty *); 76 static int imxuart_param(struct tty *, struct termios *); 77 static void imxuart_shutdownhook(void *arg); 78 79 CFATTACH_DECL(imxuart, sizeof(struct imxuart_softc), 80 imxuart_match, imxuart_attach, NULL, NULL); 81 82 83 /* 84 * disable the specified IMX UART interrupt in softc 85 * return -1 on error 86 * else return previous enabled state 87 */ 88 static __inline int 89 imxuart_intrspec_dis(imxuart_softc_t *sc, imxuart_intrix_t ix) 90 { 91 const imxuart_intrspec_t *spec = &imxuart_intrspec_tab[ix]; 92 uint32_t v; 93 uint32_t b; 94 const uint32_t syncbit = 1 << 31; 95 uint n; 96 97 if (ix >= IMXUART_INTRSPEC_TAB_SZ) 98 return -1; 99 100 v = (1 << ix); 101 if ((sc->sc_intrspec_enb & v) == 0) 102 return 0; 103 sc->sc_intrspec_enb &= ~v; 104 105 n = spec->enb_reg; 106 b = spec->enb_bit; 107 v = sc->sc_ucr[n]; 108 v &= ~b; 109 v |= syncbit; 110 sc->sc_ucr[n] = v; 111 112 n = spec->flg_reg; 113 b = spec->flg_bit; 114 v = sc->sc_usr[n]; 115 v &= ~b; 116 v |= syncbit; 117 sc->sc_usr[n] = v; 118 119 return 1; 120 } 121 122 /* 123 * enable the specified IMX UART interrupt in softc 124 * return -1 on error 125 * else return previous enabled state 126 */ 127 static __inline int 128 imxuart_intrspec_enb(imxuart_softc_t *sc, imxuart_intrix_t ix) 129 { 130 const imxuart_intrspec_t *spec = &imxuart_intrspec_tab[ix]; 131 uint32_t v; 132 uint n; 133 const uint32_t syncbit = 1 << 31; 134 135 if (ix >= IMXUART_INTRSPEC_TAB_SZ) 136 return -1; 137 138 v = (1 << ix); 139 if ((sc->sc_intrspec_enb & v) != 0) 140 return 1; 141 sc->sc_intrspec_enb |= v; 142 143 144 n = spec->enb_reg; 145 v = spec->enb_bit; 146 v |= syncbit; 147 sc->sc_ucr[n] |= v; 148 149 n = spec->flg_reg; 150 v = spec->flg_bit; 151 v |= syncbit; 152 sc->sc_usr[n] |= v; 153 154 return 0; 155 } 156 157 /* 158 * sync softc interrupt spec to UART Control regs 159 */ 160 static __inline void 161 imxuart_intrspec_sync(imxuart_softc_t *sc) 162 { 163 int i; 164 uint32_t r; 165 uint32_t v; 166 const uint32_t syncbit = 1 << 31; 167 const uint32_t mask[4] = { 168 IMXUART_INTRS_UCR1, 169 IMXUART_INTRS_UCR2, 170 IMXUART_INTRS_UCR3, 171 IMXUART_INTRS_UCR4 172 }; 173 174 for (i=0; i < 4; i++) { 175 v = sc->sc_ucr[i]; 176 if (v & syncbit) { 177 v &= ~syncbit; 178 sc->sc_ucr[i] = v; 179 r = bus_space_read_4(sc->sc_bt, sc->sc_bh, IMX_UCRn(i)); 180 r &= ~mask[i]; 181 r |= v; 182 bus_space_write_4(sc->sc_bt, sc->sc_bh, IMX_UCRn(i), r); 183 } 184 } 185 } 186 187 188 int 189 imxuart_init(imxuart_softc_t *sc, uint bh) 190 { 191 if (sc == 0) 192 sc = &imxuart_softc; 193 sc->sc_init_cnt++; 194 cn_tab = &imxuartcntab; 195 sc->sc_bt = &imx31_bs_tag; 196 sc->sc_bh = bh; 197 198 memset(&sc->sc_errors, 0, sizeof(sc->sc_errors)); 199 200 return 0; 201 } 202 203 int 204 imxuart_puts(imxuart_softc_t *sc, const char *s) 205 { 206 char c; 207 int err = -2; 208 209 for(;;) { 210 c = *s++; 211 if (c == '\0') 212 break; 213 err = imxuart_putchar(sc, c); 214 } 215 return err; 216 } 217 218 int 219 imxuart_putchar(imxuart_softc_t *sc, int c) 220 { 221 uint32_t r; 222 223 for (;;) { 224 r = bus_space_read_4(sc->sc_bt, sc->sc_bh, IMX_UTS); 225 if ((r & IMX_UTS_TXFUL) == 0) 226 break; 227 } 228 229 r = (uint32_t)c & IMX_UTXD_TX_DATA; 230 bus_space_write_4(sc->sc_bt, sc->sc_bh, IMX_UTXD, r); 231 232 return 0; 233 } 234 235 int 236 imxuart_getchar(imxuart_softc_t *sc) 237 { 238 uint32_t r; 239 int c; 240 241 for(;;) { 242 r = bus_space_read_4(sc->sc_bt, sc->sc_bh, IMX_URXD); 243 if (r & IMX_URXD_ERR) { 244 imxuart_urxd_err(sc, r); 245 continue; 246 } 247 if (r & IMX_URXD_CHARDY) { 248 c = (int)(r & IMX_URXD_RX_DATA); 249 break; 250 } 251 } 252 253 return c; 254 } 255 256 static int 257 imxuart_urxd_brk(void) 258 { 259 #ifdef DDB 260 if (cn_tab == &imxuartcntab) { 261 Debugger(); 262 return 0; 263 } 264 #endif 265 return 1; 266 } 267 268 static void 269 imxuart_urxd_err(imxuart_softc_t *sc, uint32_t r) 270 { 271 if (r & IMX_URXD_BRK) 272 if (imxuart_urxd_brk() == 0) 273 return; 274 275 sc->sc_errors.err++; 276 if (r & IMX_URXD_BRK) 277 sc->sc_errors.brk++; 278 if (r & IMX_URXD_PRERR) 279 sc->sc_errors.prerr++; 280 if (r & IMX_URXD_FRMERR) 281 sc->sc_errors.frmerr++; 282 if (r & IMX_URXD_OVRRUN) 283 sc->sc_errors.ovrrun++; 284 } 285 286 static int 287 imxuart_snapshot(imxuart_softc_t *sc, uint32_t *p) 288 { 289 int i; 290 const uint r[] = { IMX_URXD, IMX_UTXD, IMX_UCR1, IMX_UCR2, 291 IMX_UCR3, IMX_UCR4, IMX_UFCR, IMX_USR1, 292 IMX_USR2, IMX_UESC, IMX_UTIM, IMX_UBIR, 293 IMX_UBMR, IMX_UBRC, IMX_ONEMS, IMX_UTS }; 294 295 for (i=0; i < ((sizeof(r)/sizeof(r[0]))); i++) { 296 *p++ = sc->sc_bh + r[i]; 297 *p++ = bus_space_read_4(sc->sc_bt, sc->sc_bh, r[i]); 298 } 299 return 0; 300 } 301 302 int 303 imxuart_test(void) 304 { 305 imxuart_softc_t *sc = &imxuart_softc; 306 int n; 307 int err; 308 309 err = imxuart_init(sc, 1); 310 if (err != 0) 311 return err; 312 313 if (0) { 314 extern u_int cpufunc_id(void); 315 err = cpufunc_id(); 316 return err; 317 } 318 319 #if 0 320 err = imxuart_snapshot(sc, imxuart_snapshot_data); 321 if (err != 0) 322 return err; 323 #endif 324 325 326 err = imxuart_putchar(sc, 'x'); 327 if (err != 0) 328 return err; 329 330 for (n=100; n--; ) { 331 err = imxuart_puts(sc, imxuart_test_string); 332 if (err != 0) 333 break; 334 } 335 336 err = imxuart_snapshot(sc, imxuart_snapshot_data); 337 if (err != 0) 338 return err; 339 340 return err; 341 } 342 343 static int 344 imxuart_match(struct device *parent, struct cfdata *cf, void *aux) 345 { 346 struct aips_attach_args * const aipsa = aux; 347 348 switch (aipsa->aipsa_addr) { 349 case IMX_UART1_BASE: 350 case IMX_UART2_BASE: 351 case IMX_UART3_BASE: 352 case IMX_UART4_BASE: 353 case IMX_UART5_BASE: 354 return 1; 355 default: 356 return 0; 357 } 358 } 359 360 static void 361 imxuart_attach(struct device *parent, struct device *self, void *aux) 362 { 363 imxuart_softc_t *sc = (void *)self; 364 struct aips_attach_args * const aipsa = aux; 365 struct tty *tp; 366 367 sc->sc_bt = aipsa->aipsa_memt; 368 sc->sc_addr = aipsa->aipsa_addr; 369 sc->sc_size = aipsa->aipsa_size; 370 sc->sc_intr = aipsa->aipsa_intr; 371 372 sc->sc_tty = tp = ttymalloc(); 373 tp->t_oproc = imxuart_start; 374 tp->t_param = imxuart_param; 375 tty_attach(tp); 376 377 shutdownhook_establish(imxuart_shutdownhook, sc); 378 379 printf("\n"); 380 } 381 382 void 383 imxuartcnprobe(struct consdev *cp) 384 { 385 int major; 386 387 __TRACE; 388 major = cdevsw_lookup_major(&imxuart_cdevsw); 389 cp->cn_dev = makedev(major, 0); /* XXX unit 0 */ 390 cp->cn_pri = CN_REMOTE; 391 } 392 393 static void 394 imxuart_start(struct tty *tp) 395 { 396 __TRACE; 397 } 398 399 static int 400 imxuart_param(struct tty *tp, struct termios *termios) 401 { 402 __TRACE; 403 return 0; 404 } 405 406 static void 407 imxuart_shutdownhook(void *arg) 408 { 409 __TRACE; 410 } 411 412 void 413 imxuartcninit(struct consdev *cp) 414 { 415 __TRACE; 416 } 417 418 int 419 imxuartcngetc(dev_t dev) 420 { 421 struct imxuart_softc *sc; 422 uint unit; 423 int c; 424 425 unit = IMXUART_UNIT(dev); 426 if (unit != 0) 427 return 0; 428 sc = &imxuart_softc; 429 c = imxuart_getchar(sc); 430 return c; 431 } 432 433 void 434 imxuartcnputc(dev_t dev, int c) 435 { 436 (void)imxuart_putchar(&imxuart_softc, c); 437 } 438 439 void 440 imxuartcnpollc(dev_t dev, int mode) 441 { 442 /* always polled for now */ 443 } 444 int 445 imxuart_cnattach(bus_space_tag_t iot, bus_addr_t iobase, 446 int rate, int frequency, int type, tcflag_t cflag) 447 { 448 cn_tab = &imxuartcntab; 449 return 0; 450 } 451 452