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