1 /* $NetBSD: tctrl.c,v 1.2 1999/08/11 00:46:06 matt Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matt Thomas. 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/ioctl.h> 42 #include <sys/select.h> 43 #include <sys/tty.h> 44 #include <sys/proc.h> 45 #include <sys/user.h> 46 #include <sys/conf.h> 47 #include <sys/file.h> 48 #include <sys/uio.h> 49 #include <sys/kernel.h> 50 #include <sys/syslog.h> 51 #include <sys/types.h> 52 #include <sys/device.h> 53 54 #include <machine/autoconf.h> 55 #include <machine/cpu.h> 56 #include <machine/bus.h> 57 58 #include <sparc/dev/ts102reg.h> 59 #include <sparc/dev/tctrlvar.h> 60 61 static const char *tctrl_ext_statuses[16] = { 62 "main power available", 63 "internal battery attached", 64 "external battery attached", 65 "external VGA attached", 66 "external keyboard attached", 67 "external mouse attached", 68 "lid down", 69 "internal battery charging", 70 "external battery charging", 71 "internal battery discharging", 72 "external battery discharging", 73 }; 74 75 struct tctrl_softc { 76 struct device sc_dev; 77 bus_space_tag_t sc_memt; 78 bus_space_handle_t sc_memh; 79 unsigned int sc_junk; 80 unsigned int sc_ext_status; 81 unsigned int sc_pending; 82 #define TCTRL_SEND_BITPORT 0x0001 83 #define TCTRL_SEND_POWEROFF 0x0002 84 #define TCTRL_SEND_RD_EXT_STATUS 0x0004 85 #define TCTRL_SEND_RD_EVENT_STATUS 0x0008 86 #define TCTRL_SEND_BITPORT_NOP 0x0010 87 enum { TCTRL_IDLE, TCTRL_ARGS, 88 TCTRL_ACK, TCTRL_DATA } sc_state; 89 u_int8_t sc_cmdbuf[16]; 90 u_int8_t sc_rspbuf[16]; 91 u_int8_t sc_bitport; 92 u_int8_t sc_tft_on; 93 u_int8_t sc_op; 94 u_int8_t sc_cmdoff; 95 u_int8_t sc_cmdlen; 96 u_int8_t sc_rspoff; 97 u_int8_t sc_rsplen; 98 99 struct evcnt sc_intrcnt; /* interrupt counting */ 100 }; 101 102 static int tctrl_match(struct device *parent, struct cfdata *cf, void *aux); 103 static void tctrl_attach(struct device *parent, struct device *self, void *aux); 104 105 static void tctrl_write(struct tctrl_softc *sc, bus_size_t off, u_int8_t v); 106 static u_int8_t tctrl_read(struct tctrl_softc *sc, bus_size_t off); 107 static void tctrl_write_data(struct tctrl_softc *sc, u_int8_t v); 108 static u_int8_t tctrl_read_data(struct tctrl_softc *sc); 109 static int tctrl_intr(void *arg); 110 static void tctrl_setup_bitport(struct tctrl_softc *sc, int nop); 111 static void tctrl_process_response(struct tctrl_softc *sc); 112 113 struct cfattach tctrl_ca = { 114 sizeof(struct tctrl_softc), tctrl_match, tctrl_attach 115 }; 116 117 extern struct cfdriver tctrl_cd; 118 119 static int 120 tctrl_match(struct device *parent, struct cfdata *cf, void *aux) 121 { 122 union obio_attach_args *uoba = aux; 123 struct sbus_attach_args *sa = &uoba->uoba_sbus; 124 125 if (uoba->uoba_isobio4 != 0) { 126 return (0); 127 } 128 129 /* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller 130 * (who's interface is off the TS102 PCMCIA controller but there 131 * exists a OpenProm for microcontroller interface). 132 */ 133 return strcmp("uctrl", sa->sa_name) == 0; 134 } 135 136 static void 137 tctrl_attach(struct device *parent, struct device *self, void *aux) 138 { 139 struct tctrl_softc *sc = (void *)self; 140 union obio_attach_args *uoba = aux; 141 struct sbus_attach_args *sa = &uoba->uoba_sbus; 142 unsigned int i, v; 143 #if 0 144 unsigned int ack, msb, lsb; 145 #endif 146 147 /* We're living on a sbus slot that looks like an obio that 148 * looks like an sbus slot. 149 */ 150 sc->sc_memt = sa->sa_bustag; 151 if (sbus_bus_map(sc->sc_memt, sa->sa_slot, 152 sa->sa_offset - TS102_REG_UCTRL_INT, sa->sa_size, 153 BUS_SPACE_MAP_LINEAR, 0, 154 &sc->sc_memh) != 0) { 155 printf(": can't map registers\n"); 156 return; 157 } 158 159 printf("\n"); 160 161 sc->sc_tft_on = 1; 162 163 /* clear any pending data. 164 */ 165 for (i = 0; i < 10000; i++) { 166 if ((TS102_UCTRL_STS_RXNE_STA & tctrl_read(sc, TS102_REG_UCTRL_STS)) == 0) { 167 break; 168 } 169 v = tctrl_read(sc, TS102_REG_UCTRL_DATA); 170 tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA); 171 } 172 173 (void)bus_intr_establish(sc->sc_memt, sa->sa_pri, 0, tctrl_intr, sc); 174 evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt); 175 176 /* See what the external status is 177 */ 178 sc->sc_pending |= TCTRL_SEND_RD_EXT_STATUS; 179 do { 180 tctrl_intr(sc); 181 } while (sc->sc_state != TCTRL_IDLE); 182 183 if (sc->sc_ext_status != 0) { 184 const char *sep; 185 186 printf("%s: ", sc->sc_dev.dv_xname); 187 v = sc->sc_ext_status; 188 for (i = 0, sep = ""; v != 0; i++, v >>= 1) { 189 if (v & 1) { 190 printf("%s%s", sep, tctrl_ext_statuses[i]); 191 sep = ", "; 192 } 193 } 194 printf("\n"); 195 } 196 197 /* Get a current of the control bitport; 198 */ 199 sc->sc_pending |= TCTRL_SEND_BITPORT_NOP; 200 do { 201 tctrl_intr(sc); 202 } while (sc->sc_state != TCTRL_IDLE); 203 204 tctrl_write(sc, TS102_REG_UCTRL_INT, 205 TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK); 206 207 } 208 209 static int 210 tctrl_intr(void *arg) 211 { 212 struct tctrl_softc *sc = arg; 213 unsigned int v, d; 214 int progress = 0; 215 216 again: 217 /* find out the cause(s) of the interrupt */ 218 v = tctrl_read(sc, TS102_REG_UCTRL_STS); 219 220 /* clear the cause(s) of the interrupt */ 221 tctrl_write(sc, TS102_REG_UCTRL_STS, v); 222 223 v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA); 224 if (sc->sc_cmdoff >= sc->sc_cmdlen) { 225 v &= ~TS102_UCTRL_STS_TXNF_STA; 226 } 227 if ((v == 0) && (sc->sc_pending == 0 || sc->sc_state != TCTRL_IDLE)) { 228 return progress; 229 } 230 231 progress = 1; 232 if (v & TS102_UCTRL_STS_RXNE_STA) { 233 d = tctrl_read_data(sc); 234 switch (sc->sc_state) { 235 case TCTRL_IDLE: 236 if (d == 0xfa) { 237 sc->sc_pending |= TCTRL_SEND_RD_EVENT_STATUS; 238 } else { 239 printf("%s: (op=0x%02x): unexpected data (0x%02x)\n", 240 sc->sc_dev.dv_xname, sc->sc_op, d); 241 } 242 goto again; 243 case TCTRL_ACK: 244 if (d != 0xfe) { 245 printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n", 246 sc->sc_dev.dv_xname, sc->sc_op, d); 247 } 248 #if 0 249 printf(" ack=0x%02x", d); 250 #endif 251 sc->sc_rsplen--; 252 sc->sc_rspoff = 0; 253 sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE; 254 #if 0 255 if (sc->sc_rsplen > 0) { 256 printf(" [data(%u)]", sc->sc_rsplen); 257 } else { 258 printf(" [idle]\n"); 259 } 260 #endif 261 goto again; 262 case TCTRL_DATA: 263 sc->sc_rspbuf[sc->sc_rspoff++] = d; 264 #if 0 265 printf(" [%d]=0x%02x", sc->sc_rspoff-1, d); 266 #endif 267 if (sc->sc_rspoff == sc->sc_rsplen) { 268 #if 0 269 printf(" [idle]\n"); 270 #endif 271 sc->sc_state = TCTRL_IDLE; 272 tctrl_process_response(sc); 273 } 274 goto again; 275 default: 276 printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n", 277 sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state); 278 goto again; 279 } 280 } 281 if (sc->sc_state == TCTRL_IDLE) { 282 sc->sc_cmdoff = 0; 283 sc->sc_cmdlen = 0; 284 if (sc->sc_pending & TCTRL_SEND_POWEROFF) { 285 sc->sc_pending &= ~TCTRL_SEND_POWEROFF; 286 sc->sc_cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF; 287 sc->sc_cmdlen = 1; 288 sc->sc_rsplen = 0; 289 } else if (sc->sc_pending & TCTRL_SEND_RD_EVENT_STATUS) { 290 sc->sc_pending &= ~TCTRL_SEND_RD_EVENT_STATUS; 291 sc->sc_cmdbuf[0] = TS102_OP_RD_EVENT_STATUS; 292 sc->sc_cmdlen = 1; 293 sc->sc_rsplen = 3; 294 } else if (sc->sc_pending & TCTRL_SEND_RD_EXT_STATUS) { 295 sc->sc_pending &= ~TCTRL_SEND_RD_EXT_STATUS; 296 sc->sc_cmdbuf[0] = TS102_OP_RD_EXT_STATUS; 297 sc->sc_cmdlen = 1; 298 sc->sc_rsplen = 3; 299 } else if (sc->sc_pending & TCTRL_SEND_BITPORT_NOP) { 300 sc->sc_pending &= ~TCTRL_SEND_BITPORT_NOP; 301 tctrl_setup_bitport(sc, 1); 302 } else if (sc->sc_pending & TCTRL_SEND_BITPORT) { 303 sc->sc_pending &= ~TCTRL_SEND_BITPORT; 304 tctrl_setup_bitport(sc, 0); 305 } 306 if (sc->sc_cmdlen > 0) { 307 tctrl_write(sc, TS102_REG_UCTRL_INT, 308 tctrl_read(sc, TS102_REG_UCTRL_INT) 309 |TS102_UCTRL_INT_TXNF_MSK 310 |TS102_UCTRL_INT_TXNF_REQ); 311 v = tctrl_read(sc, TS102_REG_UCTRL_STS); 312 } 313 } 314 if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) { 315 tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]); 316 #if 0 317 if (sc->sc_cmdoff == 1) { 318 printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname, 319 sc->sc_cmdbuf[0], sc->sc_rsplen); 320 } else { 321 printf(" [%d]=0x%02x", sc->sc_cmdoff-1, 322 sc->sc_cmdbuf[sc->sc_cmdoff-1]); 323 } 324 #endif 325 if (sc->sc_cmdoff == sc->sc_cmdlen) { 326 sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE; 327 #if 0 328 printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n"); 329 #endif 330 if (sc->sc_cmdoff == 1) { 331 sc->sc_op = sc->sc_cmdbuf[0]; 332 } 333 tctrl_write(sc, TS102_REG_UCTRL_INT, 334 tctrl_read(sc, TS102_REG_UCTRL_INT) 335 & (~TS102_UCTRL_INT_TXNF_MSK 336 |TS102_UCTRL_INT_TXNF_REQ)); 337 } else if (sc->sc_state == TCTRL_IDLE) { 338 sc->sc_op = sc->sc_cmdbuf[0]; 339 sc->sc_state = TCTRL_ARGS; 340 #if 0 341 printf(" [args]"); 342 #endif 343 } 344 } 345 goto again; 346 } 347 348 static void 349 tctrl_setup_bitport(struct tctrl_softc *sc, int nop) 350 { 351 if (nop) { 352 sc->sc_cmdbuf[0] = TS102_OP_CTL_BITPORT; 353 sc->sc_cmdbuf[1] = 0xff; 354 sc->sc_cmdbuf[2] = 0; 355 sc->sc_cmdlen = 3; 356 sc->sc_rsplen = 2; 357 } else { 358 if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) 359 || (!sc->sc_tft_on)) { 360 sc->sc_cmdbuf[2] = TS102_BITPORT_TFTPWR; 361 } else { 362 sc->sc_cmdbuf[2] = 0; 363 } 364 sc->sc_cmdbuf[0] = TS102_OP_CTL_BITPORT; 365 sc->sc_cmdbuf[1] = ~TS102_BITPORT_TFTPWR; 366 sc->sc_cmdlen = 3; 367 sc->sc_rsplen = 2; 368 } 369 } 370 371 static void 372 tctrl_process_response(struct tctrl_softc *sc) 373 { 374 switch (sc->sc_op) { 375 case TS102_OP_RD_EXT_STATUS: { 376 sc->sc_ext_status = sc->sc_rspbuf[0] * 256 + sc->sc_rspbuf[1]; 377 break; 378 } 379 case TS102_OP_RD_EVENT_STATUS: { 380 unsigned int v = sc->sc_rspbuf[0] * 256 + sc->sc_rspbuf[1]; 381 if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) { 382 printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname); 383 } 384 if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) { 385 printf("%s: VERY LOW POWER WARNING!\n", sc->sc_dev.dv_xname); 386 } 387 if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) { 388 printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname); 389 } 390 if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) { 391 sc->sc_pending |= TCTRL_SEND_RD_EXT_STATUS; 392 printf("%s: main power %s\n", sc->sc_dev.dv_xname, 393 (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ? "removed" : "restored"); 394 } 395 if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) { 396 sc->sc_pending |= TCTRL_SEND_RD_EXT_STATUS; 397 sc->sc_pending |= TCTRL_SEND_BITPORT; 398 #if 0 399 printf("%s: lid %s\n", sc->sc_dev.dv_xname, 400 (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) ? "opened" : "closed"); 401 #endif 402 } 403 break; 404 } 405 case TS102_OP_CTL_BITPORT: 406 sc->sc_bitport = (sc->sc_rspbuf[0] & sc->sc_cmdbuf[1]) ^ sc->sc_cmdbuf[2]; 407 break; 408 default: 409 break; 410 } 411 } 412 413 void 414 tadpole_powerdown(void) 415 { 416 struct tctrl_softc *sc; 417 int i, s; 418 419 if (tctrl_cd.cd_devs == NULL 420 || tctrl_cd.cd_ndevs == 0 421 || tctrl_cd.cd_devs[0] == NULL) { 422 return; 423 } 424 425 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[0]; 426 s = splhigh(); 427 sc->sc_pending |= TCTRL_SEND_POWEROFF; 428 for (i = 0; i < 10000; i++) { 429 tctrl_intr(sc); 430 DELAY(1); 431 } 432 splx(s); 433 } 434 435 void 436 tadpole_set_video(int enabled) 437 { 438 struct tctrl_softc *sc; 439 int s; 440 441 if (tctrl_cd.cd_devs == NULL 442 || tctrl_cd.cd_ndevs == 0 443 || tctrl_cd.cd_devs[0] == NULL) { 444 return; 445 } 446 447 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[0]; 448 s = splhigh(); 449 if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) { 450 sc->sc_tft_on = enabled; 451 if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) { 452 splx(s); 453 return; 454 } 455 sc->sc_pending |= TCTRL_SEND_BITPORT; 456 tctrl_intr(sc); 457 } 458 splx(s); 459 } 460 461 static void 462 tctrl_write_data(struct tctrl_softc *sc, u_int8_t v) 463 { 464 unsigned int i; 465 for (i = 0; i < 100; i++) { 466 if (TS102_UCTRL_STS_TXNF_STA & tctrl_read(sc, TS102_REG_UCTRL_STS)) 467 break; 468 } 469 tctrl_write(sc, TS102_REG_UCTRL_DATA, v); 470 } 471 472 static u_int8_t 473 tctrl_read_data(struct tctrl_softc *sc) 474 { 475 unsigned int i, v; 476 477 for (i = 0; i < 100000; i++) { 478 if (TS102_UCTRL_STS_RXNE_STA & tctrl_read(sc, TS102_REG_UCTRL_STS)) 479 break; 480 DELAY(1); 481 } 482 483 v = tctrl_read(sc, TS102_REG_UCTRL_DATA); 484 tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA); 485 return v; 486 } 487 488 static u_int8_t 489 tctrl_read(struct tctrl_softc *sc, bus_size_t off) 490 { 491 sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off); 492 return sc->sc_junk; 493 } 494 495 static void 496 tctrl_write(struct tctrl_softc *sc, bus_size_t off, u_int8_t v) 497 { 498 sc->sc_junk = v; 499 bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v); 500 } 501