j720ssp.c revision 1.3 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