1 /* $NetBSD: j720ssp.c,v 1.3 2001/12/28 01:41:53 toshii Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum. 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 /*- 40 * Copyright (c) 1990 The Regents of the University of California. 41 * All rights reserved. 42 * 43 * This code is derived from software contributed to Berkeley by 44 * William Jolitz and Don Ahn. 45 * 46 * Redistribution and use in source and binary forms, with or without 47 * modification, are permitted provided that the following conditions 48 * are met: 49 * 1. Redistributions of source code must retain the above copyright 50 * notice, this list of conditions and the following disclaimer. 51 * 2. Redistributions in binary form must reproduce the above copyright 52 * notice, this list of conditions and the following disclaimer in the 53 * documentation and/or other materials provided with the distribution. 54 * 3. All advertising materials mentioning features or use of this software 55 * must display the following acknowledgement: 56 * This product includes software developed by the University of 57 * California, Berkeley and its contributors. 58 * 4. Neither the name of the University nor the names of its contributors 59 * may be used to endorse or promote products derived from this software 60 * without specific prior written permission. 61 * 62 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 63 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 64 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 65 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 66 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 67 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 68 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 69 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 70 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 71 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 72 * SUCH DAMAGE. 73 * 74 * @(#)pccons.c 5.11 (Berkeley) 5/21/91 75 */ 76 77 #include <sys/param.h> 78 #include <sys/systm.h> 79 #include <sys/device.h> 80 #include <sys/kernel.h> 81 #include <sys/malloc.h> 82 #include <sys/ioctl.h> 83 84 #include <machine/bus.h> 85 #include <machine/config_hook.h> 86 87 #include <hpc/hpc/bootinfo.h> 88 #include <hpc/hpc/config_hook.h> 89 #include <hpcarm/dev/sed1356var.h> 90 #include <hpcarm/sa11x0/sa11x0_var.h> 91 #include <hpcarm/sa11x0/sa11x0_gpioreg.h> 92 #include <hpcarm/sa11x0/sa11x0_ppcreg.h> 93 #include <hpcarm/sa11x0/sa11x0_sspreg.h> 94 95 #include <dev/wscons/wsconsio.h> 96 #include <dev/wscons/wskbdvar.h> 97 #include <dev/wscons/wsksymdef.h> 98 #include <dev/wscons/wsksymvar.h> 99 100 extern const struct wscons_keydesc j720kbd_keydesctab[]; 101 102 struct j720ssp_softc { 103 struct device sc_dev; 104 105 bus_space_tag_t sc_iot; 106 bus_space_handle_t sc_gpioh; 107 bus_space_handle_t sc_ssph; 108 109 struct device *sc_wskbddev; 110 111 void *sc_si; 112 int sc_enabled; 113 }; 114 115 int j720kbd_intr(void *); 116 void j720kbdsoft(void *); 117 int j720lcdparam(void *, int, long, void *); 118 static void j720kbd_read(struct j720ssp_softc *, char *); 119 static int j720ssp_readwrite(struct j720ssp_softc *, int, int, int *); 120 121 int j720sspprobe(struct device *, struct cfdata *, void *); 122 void j720sspattach(struct device *, struct device *, void *); 123 124 int j720kbd_enable(void *, int); 125 void j720kbd_set_leds(void *, int); 126 int j720kbd_ioctl(void *, u_long, caddr_t, int, struct proc *); 127 128 struct cfattach j720ssp_ca = { 129 sizeof(struct j720ssp_softc), j720sspprobe, j720sspattach, 130 }; 131 132 const struct wskbd_accessops j720kbd_accessops = { 133 j720kbd_enable, 134 j720kbd_set_leds, 135 j720kbd_ioctl, 136 }; 137 138 void j720kbd_cngetc(void *, u_int *, int *); 139 void j720kbd_cnpollc(void *, int); 140 void j720kbd_cnbell(void *, u_int, u_int, u_int); 141 142 const struct wskbd_consops j720kbd_consops = { 143 j720kbd_cngetc, 144 j720kbd_cnpollc, 145 j720kbd_cnbell, 146 }; 147 148 const struct wskbd_mapdata j720kbd_keymapdata = { 149 j720kbd_keydesctab, 150 #ifdef J720KBD_LAYOUT 151 J720KBD_LAYOUT, 152 #else 153 KB_US, 154 #endif 155 }; 156 157 static int j720ssp_powerstate = 1; 158 159 static struct j720ssp_softc j720kbdcons_sc; 160 static int j720kbdcons_initstate = 0; 161 162 #define DEBUG 163 #ifdef DEBUG 164 int j720sspwaitcnt; 165 int j720sspwaittime; 166 extern int gettick(); 167 #endif 168 169 #define BIT_INVERT(x) do { \ 170 (x) = ((((x) & 0xf0) >> 4) | (((x) & 0x0f) << 4)); \ 171 (x) = ((((x) & 0xcc) >> 2) | (((x) & 0x33) << 2)); \ 172 (x) = ((((x) & 0xaa) >> 1) | (((x) & 0x55) << 1)); \ 173 } while(0) 174 175 int 176 j720sspprobe(struct device *parent, struct cfdata *cf, void *aux) 177 { 178 return (1); 179 } 180 181 void 182 j720sspattach(struct device *parent, struct device *self, void *aux) 183 { 184 struct j720ssp_softc *sc = (void *)self; 185 struct sa11x0_softc *psc = (void *)parent; 186 struct sa11x0_attach_args *sa = aux; 187 struct wskbddev_attach_args a; 188 189 printf("\n"); 190 191 sc->sc_iot = psc->sc_iot; 192 sc->sc_gpioh = psc->sc_gpioh; 193 if (bus_space_map(sc->sc_iot, sa->sa_addr, sa->sa_size, 0, 194 &sc->sc_ssph)) { 195 printf("%s: unable to map SSP registers\n", 196 sc->sc_dev.dv_xname); 197 return; 198 } 199 200 sc->sc_si = softintr_establish(IPL_SOFTCLOCK, j720kbdsoft, sc); 201 202 sc->sc_enabled = 0; 203 204 a.console = 0; 205 206 a.keymap = &j720kbd_keymapdata; 207 208 a.accessops = &j720kbd_accessops; 209 a.accesscookie = sc; 210 211 /* Do console initialization */ 212 if (! (bootinfo->bi_cnuse & BI_CNUSE_SERIAL)) { 213 j720kbdcons_sc = *sc; 214 a.console = 1; 215 216 wskbd_cnattach(&j720kbd_consops, NULL, &j720kbd_keymapdata); 217 j720kbdcons_initstate = 1; 218 } 219 220 /* 221 * Attach the wskbd, saving a handle to it. 222 * XXX XXX XXX 223 */ 224 sc->sc_wskbddev = config_found(self, &a, wskbddevprint); 225 226 #ifdef DEBUG 227 /* Zero the stat counters */ 228 j720sspwaitcnt = 0; 229 j720sspwaittime = 0; 230 #endif 231 232 if (j720kbdcons_initstate == 1) 233 j720kbd_enable(sc, 1); 234 235 /* LCD control is on the same bus */ 236 config_hook(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, 237 CONFIG_HOOK_SHARE, j720lcdparam, sc); 238 config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_BRIGHTNESS, 239 CONFIG_HOOK_SHARE, j720lcdparam, sc); 240 config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_BRIGHTNESS_MAX, 241 CONFIG_HOOK_SHARE, j720lcdparam, sc); 242 243 config_hook(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, 244 CONFIG_HOOK_SHARE, j720lcdparam, sc); 245 config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_CONTRAST, 246 CONFIG_HOOK_SHARE, j720lcdparam, sc); 247 config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_CONTRAST_MAX, 248 CONFIG_HOOK_SHARE, j720lcdparam, sc); 249 } 250 251 int 252 j720kbd_enable(void *v, int on) 253 { 254 struct j720ssp_softc *sc = v; 255 256 if (! sc->sc_enabled) { 257 sc->sc_enabled = 1; 258 259 sa11x0_intr_establish(0, 0, 1, IPL_BIO, j720kbd_intr, sc); 260 } 261 /* XXX */ 262 return (0); 263 } 264 265 void 266 j720kbd_set_leds(void *v, int on) 267 { 268 /* XXX */ 269 return; 270 } 271 272 int 273 j720kbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 274 { 275 return (-1); 276 } 277 278 int 279 j720kbd_intr(void *arg) 280 { 281 struct j720ssp_softc *sc = arg; 282 283 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_EDR, 1); 284 285 /* 286 * Schedule a soft interrupt to process at lower priority, 287 * as reading keycodes takes time. 288 * 289 * Interrupts are generated every 25-33ms as long as there 290 * are unprocessed key events. So it is not a good idea to 291 * use callout to call j720kbdsoft after some delay in hope 292 * of reducing interrupts. 293 */ 294 softintr_schedule(sc->sc_si); 295 296 return (1); 297 } 298 299 void 300 j720kbdsoft(void *arg) 301 { 302 struct j720ssp_softc *sc = arg; 303 int s, type, value; 304 char buf[9], *p; 305 306 j720kbd_read(sc, buf); 307 308 for(p = buf; *p; p++) { 309 type = *p & 0x80 ? WSCONS_EVENT_KEY_UP : 310 WSCONS_EVENT_KEY_DOWN; 311 value = *p & 0x7f; 312 s = spltty(); 313 wskbd_input(sc->sc_wskbddev, type, value); 314 splx(s); 315 if (type == WSCONS_EVENT_KEY_DOWN && 316 value == 0x7f) { 317 j720ssp_powerstate = ! j720ssp_powerstate; 318 config_hook_call(CONFIG_HOOK_POWERCONTROL, 319 CONFIG_HOOK_POWERCONTROL_LCDLIGHT, 320 (void *)j720ssp_powerstate); 321 } 322 } 323 324 return; 325 } 326 327 void 328 j720kbd_read(struct j720ssp_softc *sc, char *buf) 329 { 330 int data, count; 331 #ifdef DEBUG 332 u_int32_t oscr; 333 334 oscr = gettick(); 335 #endif 336 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PCR, 0x2000000); 337 338 /* send scan keycode command */ 339 if (j720ssp_readwrite(sc, 1, 0x900, &data) < 0 || 340 data != 0x88) 341 goto out; 342 343 /* read numbers of scancode available */ 344 if (j720ssp_readwrite(sc, 0, 0x8800, &data) < 0) 345 goto out; 346 BIT_INVERT(data); 347 count = data; 348 349 for(; count; count--) { 350 if (j720ssp_readwrite(sc, 0, 0x8800, &data) < 0) 351 goto out; 352 BIT_INVERT(data); 353 *buf++ = data; 354 } 355 *buf = 0; 356 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PSR, 0x2000000); 357 358 #ifdef DEBUG 359 oscr = (u_int32_t)gettick() - oscr; 360 j720sspwaitcnt++; 361 j720sspwaittime += oscr; 362 #endif 363 364 return; 365 366 out: 367 *buf = 0; 368 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PSR, 0x2000000); 369 370 /* reset SSP */ 371 bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_CR0, 0x307); 372 delay(100); 373 bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_CR0, 0x387); 374 printf("j720kbd_read: error %x\n", data); 375 } 376 377 int 378 j720lcdparam(void *ctx, int type, long id, void *msg) 379 { 380 struct j720ssp_softc *sc = ctx; 381 int i, s; 382 u_int32_t data[2], len; 383 384 switch (type) { 385 case CONFIG_HOOK_GET: 386 switch (id) { 387 case CONFIG_HOOK_BRIGHTNESS_MAX: 388 case CONFIG_HOOK_CONTRAST_MAX: 389 *(int *)msg = 255; 390 return 1; 391 case CONFIG_HOOK_BRIGHTNESS: 392 data[0] = 0x6b00; 393 data[1] = 0x8800; 394 len = 2; 395 break; 396 case CONFIG_HOOK_CONTRAST: 397 data[0] = 0x2b00; 398 data[1] = 0x8800; 399 len = 2; 400 break; 401 default: 402 return 0; 403 } 404 break; 405 406 case CONFIG_HOOK_SET: 407 switch (id) { 408 case CONFIG_HOOK_BRIGHTNESS: 409 if (*(int *)msg >= 0) { 410 data[0] = 0xcb00; 411 data[1] = *(int *)msg; 412 BIT_INVERT(data[1]); 413 data[1] <<= 8; 414 len = 2; 415 } else { 416 /* XXX hack */ 417 data[0] = 0xfb00; 418 len = 1; 419 } 420 break; 421 case CONFIG_HOOK_CONTRAST: 422 data[0] = 0x8b00; 423 data[1] = *(int *)msg; 424 BIT_INVERT(data[1]); 425 data[1] <<= 8; 426 len = 2; 427 break; 428 default: 429 return 0; 430 } 431 } 432 433 s = splbio(); 434 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PCR, 0x2000000); 435 436 for (i = 0; i < len; i++) { 437 if (j720ssp_readwrite(sc, 1, data[i], &data[i]) < 0) 438 goto out; 439 } 440 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PSR, 0x2000000); 441 splx(s); 442 443 if (type == CONFIG_HOOK_SET) 444 return 1; 445 446 BIT_INVERT(data[1]); 447 *(int *)msg = data[1]; 448 449 return 1; 450 451 out: 452 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PSR, 0x2000000); 453 454 /* reset SSP */ 455 bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_CR0, 0x307); 456 delay(100); 457 bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_CR0, 0x387); 458 splx(s); 459 return 0; 460 } 461 462 static int 463 j720ssp_readwrite(struct j720ssp_softc *sc, int drainfifo, int in, int *out) 464 { 465 int timo; 466 467 timo = 100000; 468 while(bus_space_read_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PLR) & 0x400) 469 if (--timo == 0) { 470 printf("timo0\n"); 471 return -1; 472 } 473 if (drainfifo) { 474 while(bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_SR) & 475 SR_RNE) 476 bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_DR); 477 #if 1 478 delay(5000); 479 #endif 480 } 481 482 bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_DR, in); 483 484 delay(5000); 485 timo = 100000; 486 while(! (bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_SR) & SR_RNE)) 487 if (--timo == 0) { 488 printf("timo1\n"); 489 return -1; 490 } 491 492 *out = bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_DR); 493 494 return 0; 495 } 496 497 #if 0 498 int 499 j720kbd_cnattach() 500 { 501 /* XXX defer initialization till j720sspattach */ 502 503 return (0); 504 } 505 #endif 506 507 /* ARGSUSED */ 508 void 509 j720kbd_cngetc(void *v, u_int *type, int *data) 510 { 511 char buf[9]; 512 513 if (j720kbdcons_initstate < 1) 514 return; 515 516 for (;;) { 517 j720kbd_read(&j720kbdcons_sc, buf); 518 519 if (buf[0] != 0) { 520 /* XXX we are discarding buffer contents */ 521 *type = buf[0] & 0x80 ? WSCONS_EVENT_KEY_UP : 522 WSCONS_EVENT_KEY_DOWN; 523 *data = buf[0] & 0x7f; 524 return; 525 } 526 } 527 } 528 529 void 530 j720kbd_cnpollc(void *v, int on) 531 { 532 #if 0 533 /* XXX */ 534 struct j720kbd_internal *t = v; 535 536 pckbc_set_poll(t->t_kbctag, t->t_kbcslot, on); 537 #endif 538 } 539 540 void 541 j720kbd_cnbell(void *v, u_int pitch, u_int period, u_int volume) 542 { 543 } 544 545 int 546 j720lcdpower(void *ctx, int type, long id, void *msg) 547 { 548 struct sed1356_softc *sc = ctx; 549 struct sa11x0_softc *psc = sc->sc_parent; 550 int val; 551 u_int32_t reg; 552 553 if (type != CONFIG_HOOK_POWERCONTROL || 554 id != CONFIG_HOOK_POWERCONTROL_LCDLIGHT) 555 return 0; 556 557 sed1356_init_brightness(sc, 0); 558 sed1356_init_contrast(sc, 0); 559 560 if (msg) { 561 bus_space_write_1(sc->sc_iot, sc->sc_regh, 0x1f0, 0); 562 563 reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR); 564 reg |= 0x1; 565 bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg); 566 delay(50000); 567 568 val = sc->sc_contrast; 569 config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, &val); 570 delay(100000); 571 572 reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR); 573 reg |= 0x4; 574 bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg); 575 576 val = sc->sc_brightness; 577 config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val); 578 579 reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR); 580 reg |= 0x2; 581 bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg); 582 } else { 583 reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR); 584 reg &= ~0x2; 585 bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg); 586 reg &= ~0x4; 587 bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg); 588 delay(100000); 589 590 val = -2; 591 config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val); 592 593 bus_space_write_1(sc->sc_iot, sc->sc_regh, 0x1f0, 1); 594 595 delay(100000); 596 reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR); 597 reg &= ~0x1; 598 bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg); 599 } 600 return 1; 601 } 602