1 /* $NetBSD: tx39io.c,v 1.22 2010/06/06 06:12:49 dholland Exp $ */ 2 3 /*- 4 * Copyright (c) 1999-2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: tx39io.c,v 1.22 2010/06/06 06:12:49 dholland Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/device.h> 38 39 #include <machine/bus.h> 40 41 #include <hpcmips/tx/tx39var.h> 42 #include <hpcmips/tx/tx39icureg.h> 43 #define __TX39IO_PRIVATE 44 #include <hpcmips/tx/tx39iovar.h> 45 #include <hpcmips/tx/tx39ioreg.h> 46 47 #ifdef TX39IO_DEBUG 48 #define DPRINTF_ENABLE 49 #define DPRINTF_DEBUG tx39io_debug 50 #endif 51 #include <machine/debug.h> 52 53 #define ISBITSET(x, s) ((x) & (1 << (s))) 54 55 int tx39io_match(struct device *, struct cfdata *, void *); 56 void tx39io_attach(struct device *, struct device *, void *); 57 58 CFATTACH_DECL(tx39io, sizeof(struct tx39io_softc), 59 tx39io_match, tx39io_attach, NULL, NULL); 60 61 /* IO/MFIO common */ 62 static void port_intr_disestablish(hpcio_chip_t, hpcio_intr_handle_t); 63 static void port_intr_clear(hpcio_chip_t, hpcio_intr_handle_t); 64 /* MFIO */ 65 static void *mfio_intr_establish(hpcio_chip_t, int, int, int (*)(void *), 66 void *); 67 static int mfio_in(hpcio_chip_t, int); 68 static void mfio_out(hpcio_chip_t, int, int); 69 static int mfio_intr_map(int *, int, int); 70 static void mfio_dump(hpcio_chip_t); 71 static void mfio_update(hpcio_chip_t); 72 /* IO */ 73 static void *io_intr_establish(hpcio_chip_t, int, int, int (*)(void *), 74 void *); 75 #ifdef TX391X 76 static int tx391x_io_in(hpcio_chip_t, int); 77 static void tx391x_io_out(hpcio_chip_t, int, int); 78 static void tx391x_io_update(hpcio_chip_t); 79 static int tx391x_io_intr_map(int *, int, int); 80 #endif 81 #ifdef TX392X 82 static int tx392x_io_in(hpcio_chip_t, int); 83 static void tx392x_io_out(hpcio_chip_t, int, int); 84 static void tx392x_io_update(hpcio_chip_t); 85 static int tx392x_io_intr_map(int *, int, int); 86 #endif 87 #if defined TX391X && defined TX392X 88 #define tx39_io_intr_map(t, s, p, m) \ 89 (IS_TX391X(t) \ 90 ? tx391x_io_intr_map(s, p, m) : tx392x_io_intr_map(s, p, m)) 91 #elif defined TX391X 92 #define tx39io_intr_map(t, s, p, m) tx391x_io_intr_map(s, p, m) 93 #elif defined TX392X 94 #define tx39io_intr_map(t, s, p, m) tx392x_io_intr_map(s, p, m) 95 #endif 96 static void io_dump(hpcio_chip_t); 97 98 static void __print_port_status(struct tx39io_port_status *, int); 99 100 int 101 tx39io_match(struct device *parent, struct cfdata *cf, void *aux) 102 { 103 return (ATTACH_FIRST); /* 1st attach group of txsim */ 104 } 105 106 void 107 tx39io_attach(struct device *parent, struct device *self, void *aux) 108 { 109 struct txsim_attach_args *ta = aux; 110 struct tx39io_softc *sc = (void *)self; 111 tx_chipset_tag_t tc; 112 struct hpcio_chip *io_hc = &sc->sc_io_ops; 113 struct hpcio_chip *mfio_hc = &sc->sc_mfio_ops; 114 115 tc = sc->sc_tc = ta->ta_tc; 116 117 printf("\n"); 118 sc->sc_stat_io_mask = ~(1 << 5); /* exclude Plum2 INT */ 119 sc->sc_stat_mfio_mask = ~(0x3|(0x3 << 23)); 120 121 /* IO */ 122 io_hc->hc_chipid = IO; 123 io_hc->hc_name = "IO"; 124 io_hc->hc_sc = sc; 125 io_hc->hc_intr_establish = io_intr_establish; 126 io_hc->hc_intr_disestablish = port_intr_disestablish; 127 io_hc->hc_intr_clear = port_intr_clear; 128 io_hc->hc_dump = io_dump; 129 if (IS_TX391X(tc)) { 130 #ifdef TX391X 131 io_hc->hc_portread = tx391x_io_in; 132 io_hc->hc_portwrite = tx391x_io_out; 133 io_hc->hc_update = tx391x_io_update; 134 #endif 135 } else if (IS_TX392X(tc)) { 136 #ifdef TX392X 137 io_hc->hc_portread = tx392x_io_in; 138 io_hc->hc_portwrite = tx392x_io_out; 139 io_hc->hc_update = tx392x_io_update; 140 #endif 141 } 142 tx_conf_register_ioman(tc, io_hc); 143 144 /* MFIO */ 145 mfio_hc->hc_chipid = MFIO; 146 mfio_hc->hc_name = "MFIO"; 147 mfio_hc->hc_sc = sc; 148 mfio_hc->hc_portread = mfio_in; 149 mfio_hc->hc_portwrite = mfio_out; 150 mfio_hc->hc_intr_establish = mfio_intr_establish; 151 mfio_hc->hc_intr_disestablish = port_intr_disestablish; 152 mfio_hc->hc_update = mfio_update; 153 mfio_hc->hc_dump = mfio_dump; 154 155 tx_conf_register_ioman(tc, mfio_hc); 156 157 hpcio_update(io_hc); 158 hpcio_update(mfio_hc); 159 160 #ifdef TX39IO_DEBUG 161 hpcio_dump(io_hc); 162 hpcio_dump(mfio_hc); 163 printf("IO i0x%08x o0x%08x MFIO i0x%08x o0x%08x\n", 164 sc->sc_stat_io.in, sc->sc_stat_io.out, 165 sc->sc_stat_mfio.in, sc->sc_stat_mfio.out); 166 #endif /* TX39IO_DEBUG */ 167 } 168 169 /* 170 * TX391X, TX392X common 171 */ 172 static void * 173 io_intr_establish(hpcio_chip_t arg, int port, int mode, int (*func)(void *), 174 void *func_arg) 175 { 176 struct tx39io_softc *sc = arg->hc_sc; 177 int src; 178 179 if (tx39io_intr_map(sc->sc_tc, &src, port, mode) != 0) 180 return (0); 181 182 return (tx_intr_establish(sc->sc_tc, src, IST_EDGE, IPL_CLOCK, func, 183 func_arg)); 184 } 185 186 static void * 187 mfio_intr_establish(hpcio_chip_t arg, int port, int mode, int (*func)(void *), 188 void *func_arg) 189 { 190 struct tx39io_softc *sc = arg->hc_sc; 191 int src; 192 193 if (mfio_intr_map(&src, port, mode) != 0) 194 return (0); 195 196 return (tx_intr_establish(sc->sc_tc, src, IST_EDGE, IPL_CLOCK, func, 197 func_arg)); 198 } 199 200 static void 201 port_intr_disestablish(hpcio_chip_t arg, void *ih) 202 { 203 struct tx39io_softc *sc = arg->hc_sc; 204 tx_intr_disestablish(sc->sc_tc, ih); 205 } 206 207 static void 208 port_intr_clear(hpcio_chip_t arg, void *ih) 209 { 210 } 211 212 static void 213 mfio_out(hpcio_chip_t arg, int port, int onoff) 214 { 215 struct tx39io_softc *sc = arg->hc_sc; 216 tx_chipset_tag_t tc; 217 txreg_t reg, pos; 218 219 DPRINTF("port #%d\n", port); 220 tc = sc->sc_tc; 221 /* MFIO */ 222 pos = 1 << port; 223 #ifdef DIAGNOSTIC 224 if (!(sc->sc_stat_mfio.dir & pos)) { 225 panic("%s: MFIO%d is not output port.", 226 sc->sc_dev.dv_xname, port); 227 } 228 #endif 229 reg = tx_conf_read(tc, TX39_IOMFIODATAOUT_REG); 230 if (onoff) 231 reg |= pos; 232 else 233 reg &= ~pos; 234 tx_conf_write(tc, TX39_IOMFIODATAOUT_REG, reg); 235 } 236 237 static int 238 mfio_in(hpcio_chip_t arg, int port) 239 { 240 struct tx39io_softc *sc __attribute__((__unused__)) = arg->hc_sc ; 241 242 DPRINTF("port #%d\n", port); 243 return (tx_conf_read(sc->sc_tc, TX39_IOMFIODATAIN_REG) & (1 << port)); 244 } 245 246 static int 247 mfio_intr_map(int *src, int port, int mode) 248 { 249 250 if (mode & HPCIO_INTR_POSEDGE) { 251 *src = MAKEINTR(3, (1 << port)); 252 return (0); 253 } else if (mode & HPCIO_INTR_NEGEDGE) { 254 *src = MAKEINTR(4, (1 << port)); 255 return (0); 256 } 257 258 DPRINTF("invalid interrupt mode.\n"); 259 260 return (1); 261 } 262 263 static void 264 mfio_update(hpcio_chip_t arg) 265 { 266 struct tx39io_softc *sc = arg->hc_sc; 267 tx_chipset_tag_t tc = sc->sc_tc; 268 struct tx39io_port_status *stat_mfio = &sc->sc_stat_mfio; 269 270 sc->sc_ostat_mfio = *stat_mfio; /* save old status */ 271 stat_mfio->dir = tx_conf_read(tc, TX39_IOMFIODATADIR_REG); 272 stat_mfio->in = tx_conf_read(tc, TX39_IOMFIODATAIN_REG); 273 stat_mfio->out = tx_conf_read(tc, TX39_IOMFIODATAOUT_REG); 274 stat_mfio->power = tx_conf_read(tc, TX39_IOMFIOPOWERDWN_REG); 275 stat_mfio->u.select = tx_conf_read(tc, TX39_IOMFIODATASEL_REG); 276 } 277 278 #ifdef TX391X 279 /* 280 * TMPR3912 specific 281 */ 282 int 283 tx391x_io_in(hpcio_chip_t arg, int port) 284 { 285 struct tx39io_softc *sc __attribute__((__unused__)) = arg->hc_sc; 286 txreg_t reg = tx_conf_read(sc->sc_tc, TX39_IOCTRL_REG); 287 288 DPRINTF("port #%d\n", port); 289 return (TX391X_IOCTRL_IODIN(reg) & (1 << port)); 290 } 291 292 void 293 tx391x_io_out(hpcio_chip_t arg, int port, int onoff) 294 { 295 struct tx39io_softc *sc = arg->hc_sc; 296 tx_chipset_tag_t tc; 297 txreg_t reg, pos, iostat; 298 299 KASSERT(sc); 300 DPRINTF("port #%d\n", port); 301 302 tc = sc->sc_tc; 303 304 /* IO [0:6] */ 305 pos = 1 << port; 306 #ifdef DIAGNOSTIC 307 if (!(sc->sc_stat_io.dir & pos)) 308 panic("%s: IO%d is not output port.", sc->sc_dev.dv_xname, 309 port); 310 #endif 311 reg = tx_conf_read(tc, TX39_IOCTRL_REG); 312 iostat = TX391X_IOCTRL_IODOUT(reg); 313 if (onoff) 314 iostat |= pos; 315 else 316 iostat &= ~pos; 317 TX391X_IOCTRL_IODOUT_CLR(reg); 318 reg = TX391X_IOCTRL_IODOUT_SET(reg, iostat); 319 tx_conf_write(tc, TX39_IOCTRL_REG, reg); 320 } 321 322 void 323 tx391x_io_update(hpcio_chip_t arg) 324 { 325 struct tx39io_softc *sc = arg->hc_sc; 326 struct tx39io_port_status *stat_io = &sc->sc_stat_io; 327 tx_chipset_tag_t tc = sc->sc_tc; 328 txreg_t reg; 329 330 /* IO [0:6] */ 331 sc->sc_ostat_io = *stat_io; /* save old status */ 332 reg = tx_conf_read(tc, TX39_IOCTRL_REG); 333 stat_io->dir = TX391X_IOCTRL_IODIREC(reg); 334 stat_io->in = TX391X_IOCTRL_IODIN(reg); 335 stat_io->out = TX391X_IOCTRL_IODOUT(reg); 336 stat_io->u.debounce = TX391X_IOCTRL_IODEBSEL(reg); 337 reg = tx_conf_read(tc, TX39_IOIOPOWERDWN_REG); 338 stat_io->power = TX391X_IOIOPOWERDWN_IOPD(reg); 339 } 340 341 int 342 tx391x_io_intr_map(int *src, int port, int mode) 343 { 344 345 if (mode & HPCIO_INTR_POSEDGE) { 346 *src = MAKEINTR(5, (1 << (port + 7))); 347 return (0); 348 } else if (mode & HPCIO_INTR_NEGEDGE) { 349 *src = MAKEINTR(5, (1 << port)); 350 return (0); 351 } 352 353 DPRINTF("invalid interrupt mode.\n"); 354 355 return (1); 356 } 357 #endif /* TX391X */ 358 359 #ifdef TX392X 360 /* 361 * TMPR3922 specific 362 */ 363 int 364 tx392x_io_in(hpcio_chip_t arg, int port) 365 { 366 struct tx39io_softc *sc __attribute__((__unused__)) = arg->hc_sc; 367 txreg_t reg = tx_conf_read(sc->sc_tc, TX392X_IODATAINOUT_REG); 368 369 DPRINTF("port #%d\n", port); 370 371 return (TX392X_IODATAINOUT_DIN(reg) & (1 << port)); 372 } 373 374 void 375 tx392x_io_out(hpcio_chip_t arg, int port, int onoff) 376 { 377 struct tx39io_softc *sc = arg->hc_sc; 378 #ifdef DIAGNOSTIC 379 const char *devname = sc->sc_dev.dv_xname; 380 #endif 381 tx_chipset_tag_t tc = sc->sc_tc; 382 txreg_t reg, pos, iostat; 383 384 DPRINTF("port #%d\n", port); 385 /* IO [0:15] */ 386 pos = 1 << port; 387 #ifdef DIAGNOSTIC 388 if (!(sc->sc_stat_io.dir & pos)) 389 panic("%s: IO%d is not output port.", devname, port); 390 #endif 391 reg = tx_conf_read(tc, TX392X_IODATAINOUT_REG); 392 iostat = TX392X_IODATAINOUT_DOUT(reg); 393 if (onoff) 394 iostat |= pos; 395 else 396 iostat &= ~pos; 397 TX392X_IODATAINOUT_DOUT_CLR(reg); 398 reg = TX392X_IODATAINOUT_DOUT_SET(reg, iostat); 399 tx_conf_write(tc, TX392X_IODATAINOUT_REG, reg); 400 } 401 402 int 403 tx392x_io_intr_map(int *src, int port, int mode) 404 { 405 406 if (mode & HPCIO_INTR_POSEDGE) { 407 *src = MAKEINTR(8, (1 << (port + 16))); 408 return (0); 409 } else if (mode & HPCIO_INTR_NEGEDGE) { 410 *src = MAKEINTR(8, (1 << port)); 411 return (0); 412 } 413 414 DPRINTF("invalid interrupt mode.\n"); 415 416 return (1); 417 } 418 419 void 420 tx392x_io_update(hpcio_chip_t arg) 421 { 422 struct tx39io_softc *sc = arg->hc_sc; 423 struct tx39io_port_status *stat_io = &sc->sc_stat_io; 424 tx_chipset_tag_t tc = sc->sc_tc; 425 txreg_t reg; 426 427 sc->sc_ostat_io = *stat_io; /* save old status */ 428 /* IO [0:15] */ 429 reg = tx_conf_read(tc, TX39_IOCTRL_REG); 430 stat_io->dir = TX392X_IOCTRL_IODIREC(reg); 431 stat_io->u.debounce = TX392X_IOCTRL_IODEBSEL(reg); 432 reg = tx_conf_read(tc, TX392X_IODATAINOUT_REG); 433 stat_io->in = TX392X_IODATAINOUT_DIN(reg); 434 stat_io->out = TX392X_IODATAINOUT_DOUT(reg); 435 reg = tx_conf_read(tc, TX39_IOIOPOWERDWN_REG); 436 stat_io->power = TX392X_IOIOPOWERDWN_IOPD(reg); 437 } 438 439 #endif /* TX392X */ 440 441 static const char *line = "--------------------------------------------------" 442 "------------\n"; 443 static void 444 mfio_dump(hpcio_chip_t arg) 445 { 446 struct tx39io_softc *sc = arg->hc_sc; 447 const struct tx39io_mfio_map *map = tx39io_get_mfio_map(tc); 448 struct tx39io_port_status *stat; 449 int i; 450 451 printf("%s", line); 452 stat = &sc->sc_stat_mfio; 453 for (i = TX39_IO_MFIO_MAX - 1; i >= 0 ; i--) { 454 /* MFIO port has power down state */ 455 printf("MFIO %2d: - ", i); 456 __print_port_status(stat, i); 457 printf(ISBITSET(stat->u.select, i) ? " MFIO(%s)\n" : " %s\n", 458 map[i].std_pin_name); 459 } 460 printf("%s", line); 461 } 462 463 static void 464 io_dump(hpcio_chip_t arg) 465 { 466 struct tx39io_softc *sc = arg->hc_sc; 467 struct tx39io_port_status *stat; 468 int i; 469 470 printf("%s Debounce Direction DataOut DataIn PowerDown Select" 471 "\n%s", line, line); 472 stat = &sc->sc_stat_io; 473 for (i = tx39io_get_io_max(tc) - 1; i >= 0 ; i--) { 474 /* IO port has debouncer */ 475 printf("IO %2d: %s ", i, 476 ISBITSET(stat->u.debounce, i) ? "On " : "Off"); 477 __print_port_status(stat, i); 478 printf(" -\n"); 479 } 480 } 481 482 static void 483 __print_port_status(struct tx39io_port_status *stat, int i) 484 { 485 printf("%s %d %d %s", 486 ISBITSET(stat->dir, i) ? "Out" : "In ", 487 ISBITSET(stat->out, i) ? 1 : 0, 488 ISBITSET(stat->in, i) ? 1 : 0, 489 ISBITSET(stat->power, i) ? "Down ": "Active"); 490 } 491