1 /* $NetBSD: j720ssp.c,v 1.5 2002/03/17 19:40:39 atatat 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 #include <machine/bootinfo.h> 87 88 #include <hpcarm/dev/sed1356var.h> 89 #include <hpcarm/sa11x0/sa11x0_var.h> 90 #include <hpcarm/sa11x0/sa11x0_gpioreg.h> 91 #include <hpcarm/sa11x0/sa11x0_ppcreg.h> 92 #include <hpcarm/sa11x0/sa11x0_sspreg.h> 93 94 #include <dev/wscons/wsconsio.h> 95 #include <dev/wscons/wskbdvar.h> 96 #include <dev/wscons/wsksymdef.h> 97 #include <dev/wscons/wsksymvar.h> 98 99 extern const struct wscons_keydesc j720kbd_keydesctab[]; 100 101 struct j720ssp_softc { 102 struct device sc_dev; 103 104 bus_space_tag_t sc_iot; 105 bus_space_handle_t sc_gpioh; 106 bus_space_handle_t sc_ssph; 107 108 struct device *sc_wskbddev; 109 110 void *sc_si; 111 int sc_enabled; 112 }; 113 114 int j720kbd_intr(void *); 115 void j720kbdsoft(void *); 116 int j720lcdparam(void *, int, long, void *); 117 static void j720kbd_read(struct j720ssp_softc *, char *); 118 static int j720ssp_readwrite(struct j720ssp_softc *, int, int, int *); 119 120 int j720sspprobe(struct device *, struct cfdata *, void *); 121 void j720sspattach(struct device *, struct device *, void *); 122 123 int j720kbd_enable(void *, int); 124 void j720kbd_set_leds(void *, int); 125 int j720kbd_ioctl(void *, u_long, caddr_t, int, struct proc *); 126 127 struct cfattach j720ssp_ca = { 128 sizeof(struct j720ssp_softc), j720sspprobe, j720sspattach, 129 }; 130 131 const struct wskbd_accessops j720kbd_accessops = { 132 j720kbd_enable, 133 j720kbd_set_leds, 134 j720kbd_ioctl, 135 }; 136 137 void j720kbd_cngetc(void *, u_int *, int *); 138 void j720kbd_cnpollc(void *, int); 139 void j720kbd_cnbell(void *, u_int, u_int, u_int); 140 141 const struct wskbd_consops j720kbd_consops = { 142 j720kbd_cngetc, 143 j720kbd_cnpollc, 144 j720kbd_cnbell, 145 }; 146 147 const struct wskbd_mapdata j720kbd_keymapdata = { 148 j720kbd_keydesctab, 149 #ifdef J720KBD_LAYOUT 150 J720KBD_LAYOUT, 151 #else 152 KB_US, 153 #endif 154 }; 155 156 static int j720ssp_powerstate = 1; 157 158 static struct j720ssp_softc j720kbdcons_sc; 159 static int j720kbdcons_initstate = 0; 160 161 #define DEBUG 162 #ifdef DEBUG 163 int j720sspwaitcnt; 164 int j720sspwaittime; 165 extern int gettick(); 166 #endif 167 168 #define BIT_INVERT(x) do { \ 169 (x) = ((((x) & 0xf0) >> 4) | (((x) & 0x0f) << 4)); \ 170 (x) = ((((x) & 0xcc) >> 2) | (((x) & 0x33) << 2)); \ 171 (x) = ((((x) & 0xaa) >> 1) | (((x) & 0x55) << 1)); \ 172 } while(0) 173 174 int 175 j720sspprobe(struct device *parent, struct cfdata *cf, void *aux) 176 { 177 return (1); 178 } 179 180 void 181 j720sspattach(struct device *parent, struct device *self, void *aux) 182 { 183 struct j720ssp_softc *sc = (void *)self; 184 struct sa11x0_softc *psc = (void *)parent; 185 struct sa11x0_attach_args *sa = aux; 186 struct wskbddev_attach_args a; 187 188 printf("\n"); 189 190 sc->sc_iot = psc->sc_iot; 191 sc->sc_gpioh = psc->sc_gpioh; 192 if (bus_space_map(sc->sc_iot, sa->sa_addr, sa->sa_size, 0, 193 &sc->sc_ssph)) { 194 printf("%s: unable to map SSP registers\n", 195 sc->sc_dev.dv_xname); 196 return; 197 } 198 199 sc->sc_si = softintr_establish(IPL_SOFTCLOCK, j720kbdsoft, sc); 200 201 sc->sc_enabled = 0; 202 203 a.console = 0; 204 205 a.keymap = &j720kbd_keymapdata; 206 207 a.accessops = &j720kbd_accessops; 208 a.accesscookie = sc; 209 210 /* Do console initialization */ 211 if (! (bootinfo->bi_cnuse & BI_CNUSE_SERIAL)) { 212 j720kbdcons_sc = *sc; 213 a.console = 1; 214 215 wskbd_cnattach(&j720kbd_consops, NULL, &j720kbd_keymapdata); 216 j720kbdcons_initstate = 1; 217 } 218 219 /* 220 * Attach the wskbd, saving a handle to it. 221 * XXX XXX XXX 222 */ 223 sc->sc_wskbddev = config_found(self, &a, wskbddevprint); 224 225 #ifdef DEBUG 226 /* Zero the stat counters */ 227 j720sspwaitcnt = 0; 228 j720sspwaittime = 0; 229 #endif 230 231 if (j720kbdcons_initstate == 1) 232 j720kbd_enable(sc, 1); 233 234 /* LCD control is on the same bus */ 235 config_hook(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, 236 CONFIG_HOOK_SHARE, j720lcdparam, sc); 237 config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_BRIGHTNESS, 238 CONFIG_HOOK_SHARE, j720lcdparam, sc); 239 config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_BRIGHTNESS_MAX, 240 CONFIG_HOOK_SHARE, j720lcdparam, sc); 241 242 config_hook(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, 243 CONFIG_HOOK_SHARE, j720lcdparam, sc); 244 config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_CONTRAST, 245 CONFIG_HOOK_SHARE, j720lcdparam, sc); 246 config_hook(CONFIG_HOOK_GET, CONFIG_HOOK_CONTRAST_MAX, 247 CONFIG_HOOK_SHARE, j720lcdparam, sc); 248 } 249 250 int 251 j720kbd_enable(void *v, int on) 252 { 253 struct j720ssp_softc *sc = v; 254 255 if (! sc->sc_enabled) { 256 sc->sc_enabled = 1; 257 258 sa11x0_intr_establish(0, 0, 1, IPL_BIO, j720kbd_intr, sc); 259 } 260 /* XXX */ 261 return (0); 262 } 263 264 void 265 j720kbd_set_leds(void *v, int on) 266 { 267 /* XXX */ 268 return; 269 } 270 271 int 272 j720kbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 273 { 274 return (EPASSTHROUGH); 275 } 276 277 int 278 j720kbd_intr(void *arg) 279 { 280 struct j720ssp_softc *sc = arg; 281 282 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_EDR, 1); 283 284 /* 285 * Schedule a soft interrupt to process at lower priority, 286 * as reading keycodes takes time. 287 * 288 * Interrupts are generated every 25-33ms as long as there 289 * are unprocessed key events. So it is not a good idea to 290 * use callout to call j720kbdsoft after some delay in hope 291 * of reducing interrupts. 292 */ 293 softintr_schedule(sc->sc_si); 294 295 return (1); 296 } 297 298 void 299 j720kbdsoft(void *arg) 300 { 301 struct j720ssp_softc *sc = arg; 302 int s, type, value; 303 char buf[9], *p; 304 305 j720kbd_read(sc, buf); 306 307 for(p = buf; *p; p++) { 308 type = *p & 0x80 ? WSCONS_EVENT_KEY_UP : 309 WSCONS_EVENT_KEY_DOWN; 310 value = *p & 0x7f; 311 s = spltty(); 312 wskbd_input(sc->sc_wskbddev, type, value); 313 splx(s); 314 if (type == WSCONS_EVENT_KEY_DOWN && 315 value == 0x7f) { 316 j720ssp_powerstate = ! j720ssp_powerstate; 317 config_hook_call(CONFIG_HOOK_POWERCONTROL, 318 CONFIG_HOOK_POWERCONTROL_LCDLIGHT, 319 (void *)j720ssp_powerstate); 320 } 321 } 322 323 return; 324 } 325 326 void 327 j720kbd_read(struct j720ssp_softc *sc, char *buf) 328 { 329 int data, count; 330 #ifdef DEBUG 331 u_int32_t oscr; 332 333 oscr = gettick(); 334 #endif 335 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PCR, 0x2000000); 336 337 /* send scan keycode command */ 338 if (j720ssp_readwrite(sc, 1, 0x900, &data) < 0 || 339 data != 0x88) 340 goto out; 341 342 /* read numbers of scancode available */ 343 if (j720ssp_readwrite(sc, 0, 0x8800, &data) < 0) 344 goto out; 345 BIT_INVERT(data); 346 count = data; 347 348 for(; count; count--) { 349 if (j720ssp_readwrite(sc, 0, 0x8800, &data) < 0) 350 goto out; 351 BIT_INVERT(data); 352 *buf++ = data; 353 } 354 *buf = 0; 355 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PSR, 0x2000000); 356 357 #ifdef DEBUG 358 oscr = (u_int32_t)gettick() - oscr; 359 j720sspwaitcnt++; 360 j720sspwaittime += oscr; 361 #endif 362 363 return; 364 365 out: 366 *buf = 0; 367 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PSR, 0x2000000); 368 369 /* reset SSP */ 370 bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_CR0, 0x307); 371 delay(100); 372 bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_CR0, 0x387); 373 printf("j720kbd_read: error %x\n", data); 374 } 375 376 int 377 j720lcdparam(void *ctx, int type, long id, void *msg) 378 { 379 struct j720ssp_softc *sc = ctx; 380 int i, s; 381 u_int32_t data[2], len; 382 383 switch (type) { 384 case CONFIG_HOOK_GET: 385 switch (id) { 386 case CONFIG_HOOK_BRIGHTNESS_MAX: 387 case CONFIG_HOOK_CONTRAST_MAX: 388 *(int *)msg = 255; 389 return 1; 390 case CONFIG_HOOK_BRIGHTNESS: 391 data[0] = 0x6b00; 392 data[1] = 0x8800; 393 len = 2; 394 break; 395 case CONFIG_HOOK_CONTRAST: 396 data[0] = 0x2b00; 397 data[1] = 0x8800; 398 len = 2; 399 break; 400 default: 401 return 0; 402 } 403 break; 404 405 case CONFIG_HOOK_SET: 406 switch (id) { 407 case CONFIG_HOOK_BRIGHTNESS: 408 if (*(int *)msg >= 0) { 409 data[0] = 0xcb00; 410 data[1] = *(int *)msg; 411 BIT_INVERT(data[1]); 412 data[1] <<= 8; 413 len = 2; 414 } else { 415 /* XXX hack */ 416 data[0] = 0xfb00; 417 len = 1; 418 } 419 break; 420 case CONFIG_HOOK_CONTRAST: 421 data[0] = 0x8b00; 422 data[1] = *(int *)msg; 423 BIT_INVERT(data[1]); 424 data[1] <<= 8; 425 len = 2; 426 break; 427 default: 428 return 0; 429 } 430 } 431 432 s = splbio(); 433 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PCR, 0x2000000); 434 435 for (i = 0; i < len; i++) { 436 if (j720ssp_readwrite(sc, 1, data[i], &data[i]) < 0) 437 goto out; 438 } 439 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PSR, 0x2000000); 440 splx(s); 441 442 if (type == CONFIG_HOOK_SET) 443 return 1; 444 445 BIT_INVERT(data[1]); 446 *(int *)msg = data[1]; 447 448 return 1; 449 450 out: 451 bus_space_write_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PSR, 0x2000000); 452 453 /* reset SSP */ 454 bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_CR0, 0x307); 455 delay(100); 456 bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_CR0, 0x387); 457 splx(s); 458 return 0; 459 } 460 461 static int 462 j720ssp_readwrite(struct j720ssp_softc *sc, int drainfifo, int in, int *out) 463 { 464 int timo; 465 466 timo = 100000; 467 while(bus_space_read_4(sc->sc_iot, sc->sc_gpioh, SAGPIO_PLR) & 0x400) 468 if (--timo == 0) { 469 printf("timo0\n"); 470 return -1; 471 } 472 if (drainfifo) { 473 while(bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_SR) & 474 SR_RNE) 475 bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_DR); 476 #if 1 477 delay(5000); 478 #endif 479 } 480 481 bus_space_write_4(sc->sc_iot, sc->sc_ssph, SASSP_DR, in); 482 483 delay(5000); 484 timo = 100000; 485 while(! (bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_SR) & SR_RNE)) 486 if (--timo == 0) { 487 printf("timo1\n"); 488 return -1; 489 } 490 491 *out = bus_space_read_4(sc->sc_iot, sc->sc_ssph, SASSP_DR); 492 493 return 0; 494 } 495 496 #if 0 497 int 498 j720kbd_cnattach() 499 { 500 /* XXX defer initialization till j720sspattach */ 501 502 return (0); 503 } 504 #endif 505 506 /* ARGSUSED */ 507 void 508 j720kbd_cngetc(void *v, u_int *type, int *data) 509 { 510 char buf[9]; 511 512 if (j720kbdcons_initstate < 1) 513 return; 514 515 for (;;) { 516 j720kbd_read(&j720kbdcons_sc, buf); 517 518 if (buf[0] != 0) { 519 /* XXX we are discarding buffer contents */ 520 *type = buf[0] & 0x80 ? WSCONS_EVENT_KEY_UP : 521 WSCONS_EVENT_KEY_DOWN; 522 *data = buf[0] & 0x7f; 523 return; 524 } 525 } 526 } 527 528 void 529 j720kbd_cnpollc(void *v, int on) 530 { 531 #if 0 532 /* XXX */ 533 struct j720kbd_internal *t = v; 534 535 pckbc_set_poll(t->t_kbctag, t->t_kbcslot, on); 536 #endif 537 } 538 539 void 540 j720kbd_cnbell(void *v, u_int pitch, u_int period, u_int volume) 541 { 542 } 543 544 int 545 j720lcdpower(void *ctx, int type, long id, void *msg) 546 { 547 struct sed1356_softc *sc = ctx; 548 struct sa11x0_softc *psc = sc->sc_parent; 549 int val; 550 u_int32_t reg; 551 552 if (type != CONFIG_HOOK_POWERCONTROL || 553 id != CONFIG_HOOK_POWERCONTROL_LCDLIGHT) 554 return 0; 555 556 sed1356_init_brightness(sc, 0); 557 sed1356_init_contrast(sc, 0); 558 559 if (msg) { 560 bus_space_write_1(sc->sc_iot, sc->sc_regh, 0x1f0, 0); 561 562 reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR); 563 reg |= 0x1; 564 bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg); 565 delay(50000); 566 567 val = sc->sc_contrast; 568 config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, &val); 569 delay(100000); 570 571 reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR); 572 reg |= 0x4; 573 bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg); 574 575 val = sc->sc_brightness; 576 config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val); 577 578 reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR); 579 reg |= 0x2; 580 bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg); 581 } else { 582 reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR); 583 reg &= ~0x2; 584 bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg); 585 reg &= ~0x4; 586 bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg); 587 delay(100000); 588 589 val = -2; 590 config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val); 591 592 bus_space_write_1(sc->sc_iot, sc->sc_regh, 0x1f0, 1); 593 594 delay(100000); 595 reg = bus_space_read_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR); 596 reg &= ~0x1; 597 bus_space_write_4(psc->sc_iot, psc->sc_ppch, SAPPC_PSR, reg); 598 } 599 return 1; 600 } 601