1 /* $NetBSD: tx39io.c,v 1.15 2002/10/02 05:26:50 thorpej 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 CFATTACH_DECL(tx39io, sizeof(struct tx39io_softc), 63 tx39io_match, tx39io_attach, NULL, NULL); 64 65 /* IO/MFIO common */ 66 static void port_intr_disestablish(hpcio_chip_t, hpcio_intr_handle_t); 67 static void port_intr_clear(hpcio_chip_t, hpcio_intr_handle_t); 68 /* MFIO */ 69 static void *mfio_intr_establish(hpcio_chip_t, int, int, int (*)(void *), 70 void *); 71 static int mfio_in(hpcio_chip_t, int); 72 static void mfio_out(hpcio_chip_t, int, int); 73 static int mfio_intr_map(int *, int, int); 74 static void mfio_dump(hpcio_chip_t); 75 static void mfio_update(hpcio_chip_t); 76 /* IO */ 77 static void *io_intr_establish(hpcio_chip_t, int, int, int (*)(void *), 78 void *); 79 #ifdef TX391X 80 static int tx391x_io_in(hpcio_chip_t, int); 81 static void tx391x_io_out(hpcio_chip_t, int, int); 82 static void tx391x_io_update(hpcio_chip_t); 83 static int tx391x_io_intr_map(int *, int, int); 84 #endif 85 #ifdef TX392X 86 static int tx392x_io_in(hpcio_chip_t, int); 87 static void tx392x_io_out(hpcio_chip_t, int, int); 88 static void tx392x_io_update(hpcio_chip_t); 89 static int tx392x_io_intr_map(int *, int, int); 90 #endif 91 #if defined TX391X && defined TX392X 92 #define tx39_io_intr_map(t, s, p, m) \ 93 (IS_TX391X(t) 94 ? tx391x_io_intr_map(s, p, m) : tx392x_io_intr_map(s, p, m)) 95 #elif defined TX391X 96 #define tx39io_intr_map(t, s, p, m) tx391x_io_intr_map(s, p, m) 97 #elif defined TX392X 98 #define tx39io_intr_map(t, s, p, m) tx392x_io_intr_map(s, p, m) 99 #endif 100 static void io_dump(hpcio_chip_t); 101 102 static void __print_port_status(struct tx39io_port_status *, int); 103 104 int 105 tx39io_match(struct device *parent, struct cfdata *cf, void *aux) 106 { 107 return (ATTACH_FIRST); /* 1st attach group of txsim */ 108 } 109 110 void 111 tx39io_attach(struct device *parent, struct device *self, void *aux) 112 { 113 struct txsim_attach_args *ta = aux; 114 struct tx39io_softc *sc = (void *)self; 115 tx_chipset_tag_t tc; 116 struct hpcio_chip *io_hc = &sc->sc_io_ops; 117 struct hpcio_chip *mfio_hc = &sc->sc_mfio_ops; 118 119 tc = sc->sc_tc = ta->ta_tc; 120 121 printf("\n"); 122 sc->sc_stat_io_mask = ~(1 << 5); /* exclude Plum2 INT */ 123 sc->sc_stat_mfio_mask = ~(0x3|(0x3 << 23)); 124 125 /* IO */ 126 io_hc->hc_chipid = IO; 127 io_hc->hc_name = "IO"; 128 io_hc->hc_sc = sc; 129 io_hc->hc_intr_establish = io_intr_establish; 130 io_hc->hc_intr_disestablish = port_intr_disestablish; 131 io_hc->hc_intr_clear = port_intr_clear; 132 io_hc->hc_dump = io_dump; 133 if (IS_TX391X(tc)) { 134 #ifdef TX391X 135 io_hc->hc_portread = tx391x_io_in; 136 io_hc->hc_portwrite = tx391x_io_out; 137 io_hc->hc_update = tx391x_io_update; 138 #endif 139 } else if (IS_TX392X(tc)) { 140 #ifdef TX392X 141 io_hc->hc_portread = tx392x_io_in; 142 io_hc->hc_portwrite = tx392x_io_out; 143 io_hc->hc_update = tx392x_io_update; 144 #endif 145 } 146 tx_conf_register_ioman(tc, io_hc); 147 148 /* MFIO */ 149 mfio_hc->hc_chipid = MFIO; 150 mfio_hc->hc_name = "MFIO"; 151 mfio_hc->hc_sc = sc; 152 mfio_hc->hc_portread = mfio_in; 153 mfio_hc->hc_portwrite = mfio_out; 154 mfio_hc->hc_intr_establish = mfio_intr_establish; 155 mfio_hc->hc_intr_disestablish = port_intr_disestablish; 156 mfio_hc->hc_update = mfio_update; 157 mfio_hc->hc_dump = mfio_dump; 158 159 tx_conf_register_ioman(tc, mfio_hc); 160 161 hpcio_update(io_hc); 162 hpcio_update(mfio_hc); 163 164 #ifdef TX39IO_DEBUG 165 hpcio_dump(io_hc); 166 hpcio_dump(mfio_hc); 167 printf("IO i0x%08x o0x%08x MFIO i0x%08x o0x%08x\n", 168 sc->sc_stat_io.in, sc->sc_stat_io.out, 169 sc->sc_stat_mfio.in, sc->sc_stat_mfio.out); 170 #endif /* TX39IO_DEBUG */ 171 } 172 173 /* 174 * TX391X, TX392X common 175 */ 176 static void * 177 io_intr_establish(hpcio_chip_t arg, int port, int mode, int (*func)(void *), 178 void *func_arg) 179 { 180 struct tx39io_softc *sc = arg->hc_sc; 181 int src; 182 183 if (tx39io_intr_map(sc->sc_tc, &src, port, mode) != 0) 184 return (0); 185 186 return (tx_intr_establish(sc->sc_tc, src, IST_EDGE, IPL_CLOCK, func, 187 func_arg)); 188 } 189 190 static void * 191 mfio_intr_establish(hpcio_chip_t arg, int port, int mode, int (*func)(void *), 192 void *func_arg) 193 { 194 struct tx39io_softc *sc = arg->hc_sc; 195 int src; 196 197 if (mfio_intr_map(&src, port, mode) != 0) 198 return (0); 199 200 return (tx_intr_establish(sc->sc_tc, src, IST_EDGE, IPL_CLOCK, func, 201 func_arg)); 202 } 203 204 static void 205 port_intr_disestablish(hpcio_chip_t arg, void *ih) 206 { 207 struct tx39io_softc *sc = arg->hc_sc; 208 tx_intr_disestablish(sc->sc_tc, ih); 209 } 210 211 static void 212 port_intr_clear(hpcio_chip_t arg, void *ih) 213 { 214 } 215 216 static void 217 mfio_out(hpcio_chip_t arg, int port, int onoff) 218 { 219 struct tx39io_softc *sc = arg->hc_sc; 220 tx_chipset_tag_t tc; 221 txreg_t reg, pos; 222 223 DPRINTF("port #%d\n", port); 224 tc = sc->sc_tc; 225 /* MFIO */ 226 pos = 1 << port; 227 #ifdef DIAGNOSTIC 228 if (!(sc->sc_stat_mfio.dir & pos)) { 229 panic("%s: MFIO%d is not output port.", 230 sc->sc_dev.dv_xname, port); 231 } 232 #endif 233 reg = tx_conf_read(tc, TX39_IOMFIODATAOUT_REG); 234 if (onoff) 235 reg |= pos; 236 else 237 reg &= ~pos; 238 tx_conf_write(tc, TX39_IOMFIODATAOUT_REG, reg); 239 } 240 241 static int 242 mfio_in(hpcio_chip_t arg, int port) 243 { 244 struct tx39io_softc *sc __attribute__((__unused__)) = arg->hc_sc ; 245 246 DPRINTF("port #%d\n", port); 247 return (tx_conf_read(sc->sc_tc, TX39_IOMFIODATAIN_REG) & (1 << port)); 248 } 249 250 static int 251 mfio_intr_map(int *src, int port, int mode) 252 { 253 254 if (mode & HPCIO_INTR_POSEDGE) { 255 *src = MAKEINTR(3, (1 << port)); 256 return (0); 257 } else if (mode & HPCIO_INTR_NEGEDGE) { 258 *src = MAKEINTR(4, (1 << port)); 259 return (0); 260 } 261 262 DPRINTF("invalid interrupt mode.\n"); 263 264 return (1); 265 } 266 267 static void 268 mfio_update(hpcio_chip_t arg) 269 { 270 struct tx39io_softc *sc = arg->hc_sc; 271 tx_chipset_tag_t tc = sc->sc_tc; 272 struct tx39io_port_status *stat_mfio = &sc->sc_stat_mfio; 273 274 sc->sc_ostat_mfio = *stat_mfio; /* save old status */ 275 stat_mfio->dir = tx_conf_read(tc, TX39_IOMFIODATADIR_REG); 276 stat_mfio->in = tx_conf_read(tc, TX39_IOMFIODATAIN_REG); 277 stat_mfio->out = tx_conf_read(tc, TX39_IOMFIODATAOUT_REG); 278 stat_mfio->power = tx_conf_read(tc, TX39_IOMFIOPOWERDWN_REG); 279 stat_mfio->u.select = tx_conf_read(tc, TX39_IOMFIODATASEL_REG); 280 } 281 282 #ifdef TX391X 283 /* 284 * TMPR3912 specific 285 */ 286 int 287 tx391x_io_in(hpcio_chip_t arg, int port) 288 { 289 struct tx39io_softc *sc __attribute__((__unused__)) = arg->hc_sc; 290 txreg_t reg = tx_conf_read(sc->sc_tc, TX39_IOCTRL_REG); 291 292 DPRINTF("port #%d\n", port); 293 return (TX391X_IOCTRL_IODIN(reg) & (1 << port)); 294 } 295 296 void 297 tx391x_io_out(hpcio_chip_t arg, int port, int onoff) 298 { 299 struct tx39io_softc *sc = arg->hc_sc; 300 tx_chipset_tag_t tc; 301 txreg_t reg, pos, iostat; 302 303 KASSERT(sc); 304 DPRINTF("port #%d\n", port); 305 306 tc = sc->sc_tc; 307 308 /* IO [0:6] */ 309 pos = 1 << port; 310 #ifdef DIAGNOSTIC 311 if (!(sc->sc_stat_io.dir & pos)) 312 panic("%s: IO%d is not output port.", sc->sc_dev.dv_xname, 313 port); 314 #endif 315 reg = tx_conf_read(tc, TX39_IOCTRL_REG); 316 iostat = TX391X_IOCTRL_IODOUT(reg); 317 if (onoff) 318 iostat |= pos; 319 else 320 iostat &= ~pos; 321 TX391X_IOCTRL_IODOUT_CLR(reg); 322 reg = TX391X_IOCTRL_IODOUT_SET(reg, iostat); 323 tx_conf_write(tc, TX39_IOCTRL_REG, reg); 324 } 325 326 void 327 tx391x_io_update(hpcio_chip_t arg) 328 { 329 struct tx39io_softc *sc = arg->hc_sc; 330 struct tx39io_port_status *stat_io = &sc->sc_stat_io; 331 tx_chipset_tag_t tc = sc->sc_tc; 332 txreg_t reg; 333 334 /* IO [0:6] */ 335 sc->sc_ostat_io = *stat_io; /* save old status */ 336 reg = tx_conf_read(tc, TX39_IOCTRL_REG); 337 stat_io->dir = TX391X_IOCTRL_IODIREC(reg); 338 stat_io->in = TX391X_IOCTRL_IODIN(reg); 339 stat_io->out = TX391X_IOCTRL_IODOUT(reg); 340 stat_io->u.debounce = TX391X_IOCTRL_IODEBSEL(reg); 341 reg = tx_conf_read(tc, TX39_IOIOPOWERDWN_REG); 342 stat_io->power = TX391X_IOIOPOWERDWN_IOPD(reg); 343 } 344 345 int 346 tx391x_io_intr_map(int *src, int port, int mode) 347 { 348 349 if (mode & HPCIO_INTR_POSEDGE) { 350 *src = MAKEINTR(5, (1 << (port + 7))); 351 return (0); 352 } else if (mode & HPCIO_INTR_NEGEDGE) { 353 *src = MAKEINTR(5, (1 << port)); 354 return (0); 355 } 356 357 DPRINTF("invalid interrupt mode.\n"); 358 359 return (1); 360 } 361 #endif /* TX391X */ 362 363 #ifdef TX392X 364 /* 365 * TMPR3922 specific 366 */ 367 int 368 tx392x_io_in(hpcio_chip_t arg, int port) 369 { 370 struct tx39io_softc *sc __attribute__((__unused__)) = arg->hc_sc; 371 txreg_t reg = tx_conf_read(sc->sc_tc, TX392X_IODATAINOUT_REG); 372 373 DPRINTF("port #%d\n", port); 374 375 return (TX392X_IODATAINOUT_DIN(reg) & (1 << port)); 376 } 377 378 void 379 tx392x_io_out(hpcio_chip_t arg, int port, int onoff) 380 { 381 struct tx39io_softc *sc = arg->hc_sc; 382 #ifdef DIAGNOSTIC 383 const char *devname = sc->sc_dev.dv_xname; 384 #endif 385 tx_chipset_tag_t tc = sc->sc_tc; 386 txreg_t reg, pos, iostat; 387 388 DPRINTF("port #%d\n", port); 389 /* IO [0:15] */ 390 pos = 1 << port; 391 #ifdef DIAGNOSTIC 392 if (!(sc->sc_stat_io.dir & pos)) 393 panic("%s: IO%d is not output port.", devname, port); 394 #endif 395 reg = tx_conf_read(tc, TX392X_IODATAINOUT_REG); 396 iostat = TX392X_IODATAINOUT_DOUT(reg); 397 if (onoff) 398 iostat |= pos; 399 else 400 iostat &= ~pos; 401 TX392X_IODATAINOUT_DOUT_CLR(reg); 402 reg = TX392X_IODATAINOUT_DOUT_SET(reg, iostat); 403 tx_conf_write(tc, TX392X_IODATAINOUT_REG, reg); 404 } 405 406 int 407 tx392x_io_intr_map(int *src, int port, int mode) 408 { 409 410 if (mode & HPCIO_INTR_POSEDGE) { 411 *src = MAKEINTR(8, (1 << (port + 16))); 412 return (0); 413 } else if (mode & HPCIO_INTR_NEGEDGE) { 414 *src = MAKEINTR(8, (1 << port)); 415 return (0); 416 } 417 418 DPRINTF("invalid interrupt mode.\n"); 419 420 return (1); 421 } 422 423 void 424 tx392x_io_update(hpcio_chip_t arg) 425 { 426 struct tx39io_softc *sc = arg->hc_sc; 427 struct tx39io_port_status *stat_io = &sc->sc_stat_io; 428 tx_chipset_tag_t tc = sc->sc_tc; 429 txreg_t reg; 430 431 sc->sc_ostat_io = *stat_io; /* save old status */ 432 /* IO [0:15] */ 433 reg = tx_conf_read(tc, TX39_IOCTRL_REG); 434 stat_io->dir = TX392X_IOCTRL_IODIREC(reg); 435 stat_io->u.debounce = TX392X_IOCTRL_IODEBSEL(reg); 436 reg = tx_conf_read(tc, TX392X_IODATAINOUT_REG); 437 stat_io->in = TX392X_IODATAINOUT_DIN(reg); 438 stat_io->out = TX392X_IODATAINOUT_DOUT(reg); 439 reg = tx_conf_read(tc, TX39_IOIOPOWERDWN_REG); 440 stat_io->power = TX392X_IOIOPOWERDWN_IOPD(reg); 441 } 442 443 #endif /* TX392X */ 444 445 static const char *line = "--------------------------------------------------" 446 "------------\n"; 447 static void 448 mfio_dump(hpcio_chip_t arg) 449 { 450 struct tx39io_softc *sc = arg->hc_sc; 451 const struct tx39io_mfio_map *map = tx39io_get_mfio_map(tc); 452 struct tx39io_port_status *stat; 453 int i; 454 455 printf("%s", line); 456 stat = &sc->sc_stat_mfio; 457 for (i = TX39_IO_MFIO_MAX - 1; i >= 0 ; i--) { 458 /* MFIO port has power down state */ 459 printf("MFIO %2d: - ", i); 460 __print_port_status(stat, i); 461 printf(ISSET(stat->u.select, i) ? " MFIO(%s)\n" : " %s\n", 462 map[i].std_pin_name); 463 } 464 printf("%s", line); 465 } 466 467 static void 468 io_dump(hpcio_chip_t arg) 469 { 470 struct tx39io_softc *sc = arg->hc_sc; 471 struct tx39io_port_status *stat; 472 int i; 473 474 printf("%s Debounce Direction DataOut DataIn PowerDown Select" 475 "\n%s", line, line); 476 stat = &sc->sc_stat_io; 477 for (i = tx39io_get_io_max(tc) - 1; i >= 0 ; i--) { 478 /* IO port has debouncer */ 479 printf("IO %2d: %s ", i, 480 ISSET(stat->u.debounce, i) ? "On " : "Off"); 481 __print_port_status(stat, i); 482 printf(" -\n"); 483 } 484 } 485 486 static void 487 __print_port_status(struct tx39io_port_status *stat, int i) 488 { 489 printf("%s %d %d %s", 490 ISSET(stat->dir, i) ? "Out" : "In ", 491 ISSET(stat->out, i) ? 1 : 0, 492 ISSET(stat->in, i) ? 1 : 0, 493 ISSET(stat->power, i) ? "Down ": "Active"); 494 } 495