hd64461video.c revision 1.32 1 /* $NetBSD: hd64461video.c,v 1.32 2005/12/11 12:17:36 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2001, 2002, 2004 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/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: hd64461video.c,v 1.32 2005/12/11 12:17:36 christos Exp $");
41
42 #include "debug_hpcsh.h"
43 // #define HD64461VIDEO_HWACCEL
44
45 #include <sys/param.h>
46 #include <sys/kernel.h>
47 #include <sys/systm.h>
48 #include <sys/device.h>
49 #include <sys/malloc.h>
50
51 #include <sys/conf.h> /* cdev_decl */
52 #include <dev/cons.h> /* consdev */
53
54 /* ioctl */
55 #include <sys/ioctl.h>
56 #include <sys/buf.h>
57 #include <uvm/uvm_extern.h>
58
59 #include <machine/bus.h>
60 #include <machine/intr.h>
61
62 #include <hpcsh/dev/hd64461/hd64461var.h>
63 #include <hpcsh/dev/hd64461/hd64461reg.h>
64 #include <hpcsh/dev/hd64461/hd64461videoreg.h>
65
66 #include <dev/wscons/wsdisplayvar.h>
67 #include <dev/rasops/rasops.h>
68
69 #include <dev/wscons/wsconsio.h>
70 #include <dev/hpc/hpcfbvar.h>
71 #include <dev/hpc/hpcfbio.h>
72 #include <dev/hpc/video_subr.h>
73
74 #include <machine/config_hook.h>
75 #include <machine/bootinfo.h>
76
77 #ifdef HD64461VIDEO_DEBUG
78 #define DPRINTF_ENABLE
79 #define DPRINTF_DEBUG hd64461video_debug
80 #endif
81 #include <machine/debug.h>
82
83 struct hd64461video_chip;
84 struct hd64461video_font {
85 struct wsdisplay_font wsfont;
86 int c, cw, cstep;
87 int loaded;
88 };
89
90 struct hd64461video_softc {
91 struct device sc_dev;
92 enum hd64461_module_id sc_module_id;
93 struct hd64461video_chip *sc_vc;
94
95 struct hd64461video_font sc_font;
96 };
97
98 enum hd64461video_display_mode {
99 LCD256_C,
100 LCD64K_C,
101 LCD64_MONO,
102 LCD16_MONO,
103 LCD4_MONO,
104 LCD2_MONO,
105 CRT256_C,
106 LCDCRT
107 };
108
109 STATIC struct hd64461video_chip {
110 struct video_chip vc;
111 enum hd64461video_display_mode mode;
112 struct hpcfb_dspconf hd;
113 struct hpcfb_fbconf hf;
114 u_int8_t *off_screen_addr;
115 size_t off_screen_size;
116
117 struct callout unblank_ch;
118 int blanked;
119
120 int console;
121 } hd64461video_chip;
122
123 void hd64461video_cnprobe(struct consdev *);
124 void hd64461video_cninit(struct consdev *);
125
126 STATIC int hd64461video_match(struct device *, struct cfdata *, void *);
127 STATIC void hd64461video_attach(struct device *, struct device *, void *);
128
129 STATIC void hd64461video_setup_hpcfbif(struct hd64461video_chip *);
130 STATIC void hd64461video_update_videochip_status(struct hd64461video_chip *);
131 STATIC size_t hd64461video_frame_buffer_size(struct hd64461video_chip *);
132 STATIC void hd64461video_hwaccel_init(struct hd64461video_chip *);
133
134 STATIC void hd64461video_set_clut(struct hd64461video_chip *, int, int,
135 u_int8_t *, u_int8_t *, u_int8_t *);
136 STATIC void hd64461video_get_clut(struct hd64461video_chip *, int, int,
137 u_int8_t *, u_int8_t *, u_int8_t *);
138 STATIC int hd64461video_power(void *, int, long, void *);
139 STATIC void hd64461video_off(struct hd64461video_chip *);
140 STATIC void hd64461video_on(struct hd64461video_chip *);
141 STATIC void hd64461video_display_onoff(void *, boolean_t);
142 STATIC void hd64461video_display_on(void *);
143
144 #if notyet
145 STATIC void hd64461video_set_display_mode(struct hd64461video_chip *);
146 STATIC void hd64461video_set_display_mode_lcdc(struct hd64461video_chip *);
147 STATIC void hd64461video_set_display_mode_crtc(struct hd64461video_chip *);
148 #endif
149
150 #ifdef HD64461VIDEO_DEBUG
151 STATIC void hd64461video_info(struct hd64461video_softc *);
152 STATIC void hd64461video_dump(void) __attribute__((__unused__));
153 #endif
154
155 CFATTACH_DECL(hd64461video, sizeof(struct hd64461video_softc),
156 hd64461video_match, hd64461video_attach, NULL, NULL);
157
158 int hd64461video_ioctl(void *, u_long, caddr_t, int, struct lwp *);
159 paddr_t hd64461video_mmap(void *, off_t, int);
160 void hd64461video_cursor(void *, int, int, int, int, int);
161 void hd64461video_bitblit(void *, int, int, int, int, int, int);
162 void hd64461video_erase(void *, int, int, int, int, int);
163 void hd64461video_putchar(void *, int, int, struct wsdisplay_font *, int, int,
164 u_int, int);
165 void hd64461video_setclut(void *, struct rasops_info *);
166 void hd64461video_font(void *, struct wsdisplay_font *);
167 void hd64461video_iodone(void *);
168
169 struct hpcfb_accessops hd64461video_ha = {
170 .ioctl = hd64461video_ioctl,
171 .mmap = hd64461video_mmap,
172 #ifdef HD64461VIDEO_HWACCEL
173 .cursor = hd64461video_cursor,
174 .bitblit= hd64461video_bitblit,
175 .erase = hd64461video_erase,
176 .putchar= hd64461video_putchar,
177 .setclut= hd64461video_setclut,
178 .font = hd64461video_font,
179 .iodone = hd64461video_iodone
180 #endif /* HD64461VIDEO_HWACCEL */
181 };
182
183 /* font */
184 STATIC void hd64461video_font_load_16bpp(u_int16_t *, u_int8_t *, int, int, int);
185 STATIC void hd64461video_font_load_8bpp(u_int8_t *, u_int8_t *, int, int, int);
186 STATIC void hd64461video_font_set_attr(struct hd64461video_softc *,
187 struct wsdisplay_font *);
188 STATIC void hd64461video_font_load(struct hd64461video_softc *);
189 STATIC vaddr_t hd64461video_font_start_addr(struct hd64461video_softc *, int);
190
191 int
192 hd64461video_match(struct device *parent, struct cfdata *cf, void *aux)
193 {
194 struct hd64461_attach_args *ha = aux;
195
196 return (ha->ha_module_id == HD64461_MODULE_VIDEO);
197 }
198
199 void
200 hd64461video_attach(struct device *parent, struct device *self, void *aux)
201 {
202 struct hd64461_attach_args *ha = aux;
203 struct hd64461video_softc *sc = (struct hd64461video_softc *)self;
204 struct hpcfb_attach_args hfa;
205 struct video_chip *vc = &hd64461video_chip.vc;
206 char pbuf[9];
207 size_t fbsize, on_screen_size;
208
209 sc->sc_module_id = ha->ha_module_id;
210 sc->sc_vc = &hd64461video_chip;
211 printf(": ");
212
213 /* detect frame buffer size */
214 fbsize = hd64461video_frame_buffer_size(&hd64461video_chip);
215 format_bytes(pbuf, sizeof(pbuf), fbsize);
216 printf("frame buffer = %s ", pbuf);
217
218 /* update chip status */
219 hd64461video_update_videochip_status(&hd64461video_chip);
220 // hd64461video_set_display_mode(&hd64461video_chip);
221
222 if (hd64461video_chip.console)
223 printf(", console");
224
225 printf("\n");
226 #ifdef HD64461VIDEO_DEBUG
227 hd64461video_info(sc);
228 hd64461video_dump();
229 #endif
230 /* Add a hard power hook to power saving */
231 config_hook(CONFIG_HOOK_PMEVENT, CONFIG_HOOK_PMEVENT_HARDPOWER,
232 CONFIG_HOOK_SHARE, hd64461video_power, sc);
233
234 /* setup hpcfb interface */
235 hd64461video_setup_hpcfbif(&hd64461video_chip);
236
237 /* setup off-screen buffer */
238 on_screen_size = (vc->vc_fbwidth * vc->vc_fbheight * vc->vc_fbdepth) /
239 NBBY;
240 hd64461video_chip.off_screen_addr = (u_int8_t *)vc->vc_fbvaddr +
241 on_screen_size;
242 hd64461video_chip.off_screen_size = fbsize - on_screen_size;
243 /* clean up off-screen area */
244 {
245 u_int8_t *p = hd64461video_chip.off_screen_addr;
246 u_int8_t *end = p + hd64461video_chip.off_screen_size;
247 while (p < end)
248 *p++ = 0xff;
249 }
250
251 /* initialize hardware acceralation */
252 hd64461video_hwaccel_init(&hd64461video_chip);
253
254 /* register interface to hpcfb */
255 hfa.ha_console = hd64461video_chip.console;
256 hfa.ha_accessops = &hd64461video_ha;
257 hfa.ha_accessctx = sc;
258 hfa.ha_curfbconf = 0;
259 hfa.ha_nfbconf = 1;
260 hfa.ha_fbconflist = &hd64461video_chip.hf;
261 hfa.ha_curdspconf = 0;
262 hfa.ha_ndspconf = 1;
263 hfa.ha_dspconflist = &hd64461video_chip.hd;
264
265 config_found(self, &hfa, hpcfbprint);
266 }
267
268 /* console support */
269 void
270 hd64461video_cninit(struct consdev *cndev)
271 {
272 hd64461video_chip.console = 1;
273 hd64461video_chip.vc.vc_reverse = video_reverse_color();
274
275 hd64461video_update_videochip_status(&hd64461video_chip);
276 hd64461video_setup_hpcfbif(&hd64461video_chip);
277 hpcfb_cnattach(&hd64461video_chip.hf);
278
279 cn_tab->cn_pri = CN_INTERNAL;
280 }
281
282 void
283 hd64461video_cnprobe(struct consdev *cndev)
284 {
285 #if NWSDISPLAY > 0
286 extern const struct cdevsw wsdisplay_cdevsw;
287 int maj, unit;
288 #endif
289 cndev->cn_dev = NODEV;
290 cndev->cn_pri = CN_NORMAL;
291
292 #if NWSDISPLAY > 0
293 unit = 0;
294 maj = cdevsw_lookup_major(&wsdisplay_cdevsw);
295
296 if (maj != -1) {
297 cndev->cn_pri = CN_INTERNAL;
298 cndev->cn_dev = makedev(maj, unit);
299 }
300 #endif /* NWSDISPLAY > 0 */
301 }
302
303 /* hpcfb support */
304 void
305 hd64461video_setup_hpcfbif(struct hd64461video_chip *hvc)
306 {
307 struct video_chip *vc = &hvc->vc;
308 struct hpcfb_fbconf *fb = &hvc->hf;
309 vaddr_t fbvaddr = vc->vc_fbvaddr;
310 int height = vc->vc_fbheight;
311 int width = vc->vc_fbwidth;
312 int depth = vc->vc_fbdepth;
313
314 memset(fb, 0, sizeof(struct hpcfb_fbconf));
315
316 fb->hf_conf_index = 0; /* configuration index */
317 fb->hf_nconfs = 1; /* how many configurations */
318 strncpy(fb->hf_name, "HD64461 video module", HPCFB_MAXNAMELEN);
319
320 /* frame buffer name */
321 strncpy(fb->hf_conf_name, "LCD", HPCFB_MAXNAMELEN);
322
323 /* configuration name */
324 fb->hf_height = height;
325 fb->hf_width = width;
326 fb->hf_baseaddr = (u_long)fbvaddr;
327 fb->hf_offset = (u_long)fbvaddr -
328 sh3_ptob(sh3_btop(fbvaddr));
329
330 /* frame buffer start offset */
331 fb->hf_bytes_per_line = (width * depth) / NBBY;
332 fb->hf_nplanes = 1;
333 fb->hf_bytes_per_plane = height * fb->hf_bytes_per_line;
334
335 fb->hf_access_flags |= HPCFB_ACCESS_BYTE;
336 fb->hf_access_flags |= HPCFB_ACCESS_WORD;
337 fb->hf_access_flags |= HPCFB_ACCESS_DWORD;
338 if (vc->vc_reverse)
339 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
340
341 switch (depth) {
342 default:
343 panic("%s: not supported color depth", __FUNCTION__);
344 /* NOTREACHED */
345 case 16:
346 fb->hf_class = HPCFB_CLASS_RGBCOLOR;
347 fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
348 fb->hf_pack_width = 16;
349 fb->hf_pixels_per_pack = 1;
350 fb->hf_pixel_width = 16;
351 /*
352 * XXX: uwe: if I RTFS correctly, this really means
353 * that uint16_t pixel is fetched as little endian.
354 */
355 fb->hf_order_flags = HPCFB_REVORDER_BYTE;
356
357 fb->hf_class_data_length = sizeof(struct hf_rgb_tag);
358 /* reserved for future use */
359 fb->hf_u.hf_rgb.hf_flags = 0;
360
361 fb->hf_u.hf_rgb.hf_red_width = 5;
362 fb->hf_u.hf_rgb.hf_red_shift = 11;
363 fb->hf_u.hf_rgb.hf_green_width = 6;
364 fb->hf_u.hf_rgb.hf_green_shift = 5;
365 fb->hf_u.hf_rgb.hf_blue_width = 5;
366 fb->hf_u.hf_rgb.hf_blue_shift = 0;
367 fb->hf_u.hf_rgb.hf_alpha_width = 0;
368 fb->hf_u.hf_rgb.hf_alpha_shift = 0;
369 break;
370
371 case 8:
372 fb->hf_class = HPCFB_CLASS_INDEXCOLOR;
373 fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
374 fb->hf_pack_width = 8;
375 fb->hf_pixels_per_pack = 1;
376 fb->hf_pixel_width = 8;
377 fb->hf_class_data_length = sizeof(struct hf_indexed_tag);
378 /* reserved for future use */
379 fb->hf_u.hf_indexed.hf_flags = 0;
380 break;
381 }
382 }
383
384 void
385 hd64461video_hwaccel_init(struct hd64461video_chip *hvc)
386 {
387 u_int16_t r;
388
389 r = HD64461_LCDGRCFGR_ACCRESET;
390 switch (hvc->vc.vc_fbdepth) {
391 default:
392 panic("no bitblit acceralation.");
393 case 16:
394 break;
395 case 8:
396 r |= HD64461_LCDGRCFGR_COLORDEPTH_8BPP;
397 break;
398 }
399 hd64461_reg_write_2(HD64461_LCDGRCFGR_REG16, r);
400
401 while ((hd64461_reg_read_2(HD64461_LCDGRCFGR_REG16) &
402 HD64461_LCDGRCFGR_ACCSTATUS) != 0)
403 /* busy loop */;
404 r &= ~HD64461_LCDGRCFGR_ACCRESET;
405 hd64461_reg_write_2(HD64461_LCDGRCFGR_REG16, r);
406
407 while ((hd64461_reg_read_2(HD64461_LCDGRCFGR_REG16) &
408 HD64461_LCDGRCFGR_ACCSTATUS) != 0)
409 /* busy loop */;
410
411 hd64461_reg_write_2(HD64461_LCDGRDOR_REG16,
412 (hvc->vc.vc_fbwidth - 1) & HD64461_LCDGRDOR_MASK);
413 }
414
415 /* hpcfb ops */
416 int
417 hd64461video_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct lwp *l)
418 {
419 struct hd64461video_softc *sc = (struct hd64461video_softc *)v;
420 struct hpcfb_fbconf *hf = &sc->sc_vc->hf;
421 struct hpcfb_fbconf *fbconf;
422 struct hpcfb_dspconf *dspconf;
423 struct wsdisplay_cmap *cmap;
424 struct wsdisplay_param *dispparam;
425 long id, idmax;
426 int turnoff;
427 u_int8_t *r, *g, *b;
428 int error;
429 size_t idx, cnt;
430
431 switch (cmd) {
432 case WSDISPLAYIO_GVIDEO:
433 *(u_int *)data = sc->sc_vc->blanked ?
434 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
435 return (0);
436
437 case WSDISPLAYIO_SVIDEO:
438 turnoff = (*(u_int *)data == WSDISPLAYIO_VIDEO_OFF);
439 if (sc->sc_vc->blanked != turnoff) {
440 sc->sc_vc->blanked = turnoff;
441 if (turnoff)
442 hd64461video_off(sc->sc_vc);
443 else
444 hd64461video_on(sc->sc_vc);
445 }
446
447 return (0);
448
449 case WSDISPLAYIO_GETPARAM:
450 dispparam = (struct wsdisplay_param *)data;
451 dispparam->min = 0;
452 switch (dispparam->param) {
453 case WSDISPLAYIO_PARAM_BACKLIGHT:
454 id = CONFIG_HOOK_POWER_LCDLIGHT;
455 idmax = -1;
456 dispparam->max = ~0;
457 break;
458 case WSDISPLAYIO_PARAM_BRIGHTNESS:
459 id = CONFIG_HOOK_BRIGHTNESS;
460 idmax = CONFIG_HOOK_BRIGHTNESS_MAX;
461 break;
462 case WSDISPLAYIO_PARAM_CONTRAST:
463 id = CONFIG_HOOK_CONTRAST;
464 idmax = CONFIG_HOOK_CONTRAST_MAX;
465 break;
466 default:
467 return (EINVAL);
468 }
469
470 if (idmax >= 0) {
471 error = config_hook_call(CONFIG_HOOK_GET, idmax,
472 &dispparam->max);
473 if (error)
474 return (error);
475 }
476 return config_hook_call(CONFIG_HOOK_GET, id,
477 &dispparam->curval);
478
479 case WSDISPLAYIO_SETPARAM:
480 dispparam = (struct wsdisplay_param *)data;
481 switch (dispparam->param) {
482 case WSDISPLAYIO_PARAM_BACKLIGHT:
483 id = CONFIG_HOOK_POWER_LCDLIGHT;
484 break;
485 case WSDISPLAYIO_PARAM_BRIGHTNESS:
486 id = CONFIG_HOOK_BRIGHTNESS;
487 break;
488 case WSDISPLAYIO_PARAM_CONTRAST:
489 id = CONFIG_HOOK_CONTRAST;
490 break;
491 default:
492 return (EINVAL);
493 }
494 return config_hook_call(CONFIG_HOOK_SET, id,
495 &dispparam->curval);
496
497 case WSDISPLAYIO_GETCMAP:
498 cmap = (struct wsdisplay_cmap *)data;
499 cnt = cmap->count;
500 idx = cmap->index;
501
502 if (hf->hf_class != HPCFB_CLASS_INDEXCOLOR ||
503 hf->hf_pack_width != 8 ||
504 !LEGAL_CLUT_INDEX(idx) ||
505 !LEGAL_CLUT_INDEX(idx + cnt -1)) {
506 return (EINVAL);
507 }
508
509 error = cmap_work_alloc(&r, &g, &b, 0, cnt);
510 if (error)
511 goto out;
512 hd64461video_get_clut(sc->sc_vc, idx, cnt, r, g, b);
513 error = copyout(r, cmap->red, cnt);
514 if (error)
515 goto out;
516 error = copyout(g, cmap->green,cnt);
517 if (error)
518 goto out;
519 error = copyout(b, cmap->blue, cnt);
520
521 out:
522 cmap_work_free(r, g, b, 0);
523 return error;
524
525 case WSDISPLAYIO_PUTCMAP:
526 cmap = (struct wsdisplay_cmap *)data;
527 cnt = cmap->count;
528 idx = cmap->index;
529
530 if (hf->hf_class != HPCFB_CLASS_INDEXCOLOR ||
531 hf->hf_pack_width != 8 ||
532 !LEGAL_CLUT_INDEX(idx) ||
533 !LEGAL_CLUT_INDEX(idx + cnt -1)) {
534 return (EINVAL);
535 }
536
537 error = cmap_work_alloc(&r, &g, &b, 0, cnt);
538 if (error)
539 goto out;
540
541 error = copyin(cmap->red, r, cnt);
542 if (error)
543 goto out;
544 error = copyin(cmap->green,g, cnt);
545 if (error)
546 goto out;
547 error = copyin(cmap->blue, b, cnt);
548 if (error)
549 goto out;
550 hd64461video_set_clut(sc->sc_vc, idx, cnt, r, g, b);
551 goto out;
552
553 case HPCFBIO_GCONF:
554 fbconf = (struct hpcfb_fbconf *)data;
555 if (fbconf->hf_conf_index != 0 &&
556 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
557 return (EINVAL);
558 }
559 *fbconf = *hf; /* structure assignment */
560 return (0);
561
562 case HPCFBIO_SCONF:
563 fbconf = (struct hpcfb_fbconf *)data;
564 if (fbconf->hf_conf_index != 0 &&
565 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
566 return (EINVAL);
567 }
568 /*
569 * nothing to do because we have only one configuration
570 */
571 return (0);
572
573 case HPCFBIO_GDSPCONF:
574 dspconf = (struct hpcfb_dspconf *)data;
575 if ((dspconf->hd_unit_index != 0 &&
576 dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
577 (dspconf->hd_conf_index != 0 &&
578 dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
579 return (EINVAL);
580 }
581 *dspconf = sc->sc_vc->hd; /* structure assignment */
582 return (0);
583
584 case HPCFBIO_SDSPCONF:
585 dspconf = (struct hpcfb_dspconf *)data;
586 if ((dspconf->hd_unit_index != 0 &&
587 dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
588 (dspconf->hd_conf_index != 0 &&
589 dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
590 return (EINVAL);
591 }
592 /*
593 * nothing to do
594 * because we have only one unit and one configuration
595 */
596 return (0);
597
598 case HPCFBIO_GOP:
599 case HPCFBIO_SOP:
600 /* XXX not implemented yet */
601 return (EINVAL);
602 }
603
604 return (EPASSTHROUGH);
605 }
606
607 paddr_t
608 hd64461video_mmap(void *ctx, off_t offset, int prot)
609 {
610 struct hd64461video_softc *sc = (struct hd64461video_softc *)ctx;
611 struct hpcfb_fbconf *hf = &sc->sc_vc->hf;
612
613 if (offset < 0 || (hf->hf_bytes_per_plane + hf->hf_offset) < offset)
614 return (-1);
615
616 return (sh3_btop(HD64461_FBBASE + offset));
617 }
618
619 void
620 hd64461video_cursor(void *ctx, int on, int xd, int yd, int w, int h)
621 {
622 struct hd64461video_softc *sc = (struct hd64461video_softc *)ctx;
623 int xw, yh, width, bpp, adr;
624 u_int16_t r;
625
626 width = sc->sc_vc->vc.vc_fbwidth;
627 bpp = sc->sc_vc->vc.vc_fbdepth;
628 xw = w - 1;
629 yh = h - 1;
630
631 /* Wait until previous command done. */
632 hd64461video_iodone(ctx);
633
634 /* Destination addr */
635 adr = width * yd + xd;
636 if (bpp == 16)
637 adr *= 2;
638 hd64461_reg_write_2(HD64461_LCDBBTDSARH_REG16,
639 HD64461_LCDBBTDSARH(adr));
640 hd64461_reg_write_2(HD64461_LCDBBTDSARL_REG16,
641 HD64461_LCDBBTDSARL(adr));
642
643 // Width
644 hd64461_reg_write_2(HD64461_LCDBBTDWR_REG16,
645 xw & HD64461_LCDBBTDWR_MASK);
646
647 // Height
648 hd64461_reg_write_2(HD64461_LCDBBTDHR_REG16,
649 yh & HD64461_LCDBBTDHR_MASK);
650
651 // Operation (Destination Invert)
652 hd64461_reg_write_2(HD64461_LCDBBTROPR_REG16,
653 HD64461_LCDC_BITBLT_DSTINVERT);
654
655 // BitBLT mode (Destination Invert)
656 hd64461_reg_write_2(HD64461_LCDBBTMDR_REG16, 0);
657
658 // Kick.
659 r = hd64461_reg_read_2(HD64461_LCDGRCFGR_REG16);
660 r &= ~HD64461_LCDGRCFGR_ACCSTART_MASK;
661 r |= HD64461_LCDGRCFGR_ACCSTART_BITBLT;
662 hd64461_reg_write_2(HD64461_LCDGRCFGR_REG16, r);
663 }
664
665 void
666 hd64461video_bitblit(void *ctx, int xs, int ys, int xd, int yd, int h, int w)
667 {
668 struct hd64461video_softc *sc = (struct hd64461video_softc *)ctx;
669 int xw, yh, width, bpp, condition_a, adr;
670 u_int16_t r;
671
672 xw = w - 1;
673 yh = h - 1;
674 width = sc->sc_vc->vc.vc_fbwidth;
675 bpp = sc->sc_vc->vc.vc_fbdepth;
676 condition_a = ((ys == yd) && (xs <= xd)) || (ys < yd);
677
678 hd64461video_iodone(ctx);
679
680 // Source addr
681 if (condition_a)
682 adr = (width * (ys + yh)) + (xs + xw);
683 else
684 adr = width * ys + xs;
685 if (bpp == 16)
686 adr *= 2;
687
688 hd64461_reg_write_2(HD64461_LCDBBTSSARH_REG16,
689 HD64461_LCDBBTSSARH(adr));
690 hd64461_reg_write_2(HD64461_LCDBBTSSARL_REG16,
691 HD64461_LCDBBTSSARL(adr));
692
693 // Destination addr
694 if (condition_a)
695 adr = (width * (yd + yh)) + (xd + xw);
696 else
697 adr = width * yd + xd;
698 if (bpp == 16)
699 adr *= 2;
700
701 hd64461_reg_write_2(HD64461_LCDBBTDSARH_REG16,
702 HD64461_LCDBBTDSARH(adr));
703 hd64461_reg_write_2(HD64461_LCDBBTDSARL_REG16,
704 HD64461_LCDBBTDSARL(adr));
705
706 // Width
707 hd64461_reg_write_2(HD64461_LCDBBTDWR_REG16,
708 xw & HD64461_LCDBBTDWR_MASK);
709
710 // Height
711 hd64461_reg_write_2(HD64461_LCDBBTDHR_REG16,
712 yh & HD64461_LCDBBTDHR_MASK);
713
714 // Operation (source copy)
715 hd64461_reg_write_2(HD64461_LCDBBTROPR_REG16,
716 HD64461_LCDC_BITBLT_SRCCOPY);
717
718 // BitBLT mode (on screen to on screen)
719 r = HD64461_LCDBBTMDR_SET(0,
720 HD64461_LCDBBTMDR_ON_SCREEN_TO_ON_SCREEN);
721 if (condition_a) /* reverse direction */
722 r |= HD64461_LCDBBTMDR_SCANDRCT_RL_BT;
723 hd64461_reg_write_2(HD64461_LCDBBTMDR_REG16, r);
724
725 // Kick.
726 r = hd64461_reg_read_2(HD64461_LCDGRCFGR_REG16);
727 r &= ~HD64461_LCDGRCFGR_ACCSTART_MASK;
728 r |= HD64461_LCDGRCFGR_ACCSTART_BITBLT;
729 hd64461_reg_write_2(HD64461_LCDGRCFGR_REG16, r);
730 }
731
732 void
733 hd64461video_erase(void *ctx, int xd, int yd, int h, int w, int attr)
734 {
735 struct hd64461video_softc *sc = (struct hd64461video_softc *)ctx;
736 int xw, yh, width, bpp, adr;
737 u_int16_t r;
738
739 width = sc->sc_vc->vc.vc_fbwidth;
740 bpp = sc->sc_vc->vc.vc_fbdepth;
741 xw = w - 1;
742 yh = h - 1;
743
744 /* Wait until previous command done. */
745 hd64461video_iodone(ctx);
746
747 /* Destination addr */
748 adr = width * yd + xd;
749 if (bpp == 16)
750 adr *= 2;
751 hd64461_reg_write_2(HD64461_LCDBBTDSARH_REG16,
752 HD64461_LCDBBTDSARH(adr));
753 hd64461_reg_write_2(HD64461_LCDBBTDSARL_REG16,
754 HD64461_LCDBBTDSARL(adr));
755
756 // Width
757 hd64461_reg_write_2(HD64461_LCDBBTDWR_REG16,
758 xw & HD64461_LCDBBTDWR_MASK);
759
760 // Height
761 hd64461_reg_write_2(HD64461_LCDBBTDHR_REG16,
762 yh & HD64461_LCDBBTDHR_MASK);
763
764 // Color
765 hd64461_reg_write_2(HD64461_LCDGRSCR_REG16, 0); //XXX black only
766
767 // Operation (Solid Color Fill)
768 hd64461_reg_write_2(HD64461_LCDBBTROPR_REG16,
769 HD64461_LCDC_BITBLT_PATCOPY);
770
771 // BitBLT mode (Solid Color)
772 hd64461_reg_write_2(HD64461_LCDBBTMDR_REG16,
773 HD64461_LCDBBTMDR_PATSELECT_SOLIDCOLOR);
774
775 // Kick.
776 r = hd64461_reg_read_2(HD64461_LCDGRCFGR_REG16);
777 r &= ~HD64461_LCDGRCFGR_ACCSTART_MASK;
778 r |= HD64461_LCDGRCFGR_ACCSTART_BITBLT;
779 hd64461_reg_write_2(HD64461_LCDGRCFGR_REG16, r);
780 }
781
782 void
783 hd64461video_putchar(void *ctx, int row, int col, struct wsdisplay_font *font,
784 int fclr, int uclr, u_int uc, int attr)
785 {
786 struct hd64461video_softc *sc = (struct hd64461video_softc *)ctx;
787 int w, h, cw;
788
789 w = font->fontwidth;
790 h = font->fontheight;
791 cw = sc->sc_font.cw;
792 hd64461video_bitblit(ctx, (uc % cw) * w,
793 sc->sc_vc->vc.vc_fbheight + (uc / cw) * h, row, col, h, w);
794 }
795
796 void
797 hd64461video_setclut(void *ctx, struct rasops_info *info)
798 {
799 struct hd64461video_softc *sc = (struct hd64461video_softc *)ctx;
800
801 if (sc->sc_vc->vc.vc_fbdepth != 8)
802 return;
803 }
804
805 void
806 hd64461video_font(void *ctx, struct wsdisplay_font *font)
807 {
808 struct hd64461video_softc *sc = (struct hd64461video_softc *)ctx;
809
810 hd64461video_font_set_attr(sc, font);
811 hd64461video_font_load(sc);
812 }
813
814 void
815 hd64461video_iodone(void *ctx)
816 {
817 while ((hd64461_reg_read_2(HD64461_LCDGRCFGR_REG16) &
818 HD64461_LCDGRCFGR_ACCSTATUS) != 0)
819 /* busy loop */;
820 }
821
822 /* internal */
823 void
824 hd64461video_font_load_16bpp(u_int16_t *d, u_int8_t *s, int w, int h, int step)
825 {
826 int i, j, n;
827 n = step / sizeof(u_int16_t);
828
829 for (i = 0; i < h; i++, d += n) {
830 for (j = 0; j < w; j++) {
831 d[j] = *s & (1 << (w - j - 1)) ? 0xffff : 0x0000;
832 }
833 s++;
834 }
835 }
836
837 void
838 hd64461video_font_load_8bpp(u_int8_t *d, u_int8_t *s, int w, int h, int step)
839 {
840 int i, j, n;
841 n = step / sizeof(u_int8_t);
842
843 for (i = 0; i < h; i++, d += n) {
844 for (j = 0; j < w; j++) {
845 d[j] = *s & (1 << (w - j - 1)) ? 0xff : 0x00;
846 }
847 s++;
848 }
849 }
850
851 void
852 hd64461video_font_set_attr(struct hd64461video_softc *sc,
853 struct wsdisplay_font *f)
854 {
855 struct hd64461video_chip *hvc = sc->sc_vc;
856 struct wsdisplay_font *font = (struct wsdisplay_font *)&sc->sc_font;
857 int w, h, bpp;
858
859 w = f->fontwidth;
860 h = f->fontheight;
861 bpp = hvc->vc.vc_fbdepth;
862
863 *font = *f;
864 sc->sc_font.c = (w * bpp) / NBBY;
865 sc->sc_font.cw = hvc->hf.hf_width / w;
866 sc->sc_font.cstep = ((w * h * bpp) / NBBY) * sc->sc_font.cw;
867
868 DPRINTF("c = %d cw = %d cstep = %d\n", sc->sc_font.c,
869 sc->sc_font.cw, sc->sc_font.cstep);
870
871 }
872
873 /* return frame buffer virtual address of charcter #n */
874 vaddr_t
875 hd64461video_font_start_addr(struct hd64461video_softc *sc, int n)
876 {
877 struct hd64461video_chip *hvc = sc->sc_vc;
878 struct hd64461video_font *font = &sc->sc_font;
879 vaddr_t base;
880
881 base = (vaddr_t)hvc->off_screen_addr;
882 base += (n / font->cw) * font->cstep + font->c * (n % font->cw);
883
884 return base;
885 }
886
887 void
888 hd64461video_font_load(struct hd64461video_softc *sc)
889 {
890 struct hd64461video_chip *hvc = sc->sc_vc;
891 struct wsdisplay_font *font = (struct wsdisplay_font *)&sc->sc_font;
892 u_int8_t *q;
893 int w, h, step, i, n;
894
895 if (sc->sc_font.loaded) {
896 printf("reload font\n");
897 }
898
899 w = font->fontwidth;
900 h = font->fontheight;
901 step = sc->sc_font.cw * sc->sc_font.c;
902 n = (w * h) / NBBY;
903 q = font->data;
904
905 DPRINTF("%s (%dx%d) %d+%d\n", font->name, w, h, font->firstchar,
906 font->numchars);
907 DPRINTF("bitorder %d byteorder %d stride %d\n", font->bitorder,
908 font->byteorder, font->stride);
909
910 switch (hvc->vc.vc_fbdepth) {
911 case 8:
912 for (i = font->firstchar; i < font->numchars; i++) {
913 hd64461video_font_load_8bpp
914 ((u_int8_t *)hd64461video_font_start_addr(sc, i),
915 q, w, h, step);
916 q += n;
917 }
918 break;
919 case 16:
920 for (i = font->firstchar; i < font->numchars; i++) {
921 hd64461video_font_load_16bpp
922 ((u_int16_t *)hd64461video_font_start_addr(sc, i),
923 q, w, h, step);
924 q += n;
925 }
926 break;
927 }
928
929 sc->sc_font.loaded = TRUE;
930 }
931
932 void
933 hd64461video_update_videochip_status(struct hd64461video_chip *hvc)
934 {
935 struct video_chip *vc = &hvc->vc;
936 u_int16_t r;
937 int i;
938 int depth, width, height;
939
940 depth = 0; /* XXX: -Wuninitialized */
941
942 /* display mode */
943 r = hd64461_reg_read_2(HD64461_LCDLDR3_REG16);
944 i = HD64461_LCDLDR3_CG(r);
945 switch (i) {
946 case HD64461_LCDLDR3_CG_COLOR16:
947 depth = 16;
948 hvc->mode = LCD64K_C;
949 break;
950 case HD64461_LCDLDR3_CG_COLOR8:
951 depth = 8;
952 hvc->mode = LCD256_C;
953 break;
954 case HD64461_LCDLDR3_CG_GRAY6:
955 depth = 6;
956 hvc->mode = LCD64_MONO;
957 break;
958 case HD64461_LCDLDR3_CG_GRAY4:
959 depth = 4;
960 hvc->mode = LCD16_MONO;
961 break;
962 case HD64461_LCDLDR3_CG_GRAY2:
963 depth = 2;
964 hvc->mode = LCD4_MONO;
965 break;
966 case HD64461_LCDLDR3_CG_GRAY1:
967 depth = 1;
968 hvc->mode = LCD2_MONO;
969 break;
970 }
971
972 r = hd64461_reg_read_2(HD64461_LCDCCR_REG16);
973 i = HD64461_LCDCCR_DSPSEL(i);
974 switch (i) {
975 case HD64461_LCDCCR_DSPSEL_LCD_CRT:
976 depth = 8;
977 hvc->mode = LCDCRT;
978 break;
979 case HD64461_LCDCCR_DSPSEL_CRT:
980 depth = 8;
981 hvc->mode = CRT256_C;
982 break;
983 case HD64461_LCDCCR_DSPSEL_LCD:
984 /* nothing to do */
985 break;
986 }
987
988 callout_init(&hvc->unblank_ch);
989 hvc->blanked = 0;
990
991 width = bootinfo->fb_width;
992 height = bootinfo->fb_height;
993
994 vc->vc_fbvaddr = HD64461_FBBASE;
995 vc->vc_fbpaddr = HD64461_FBBASE;
996 vc->vc_fbdepth = depth;
997 vc->vc_fbsize = (width * height * depth) / NBBY;
998 vc->vc_fbwidth = width;
999 vc->vc_fbheight = height;
1000 }
1001
1002 #if notyet
1003 void
1004 hd64461video_set_display_mode(struct hd64461video_chip *hvc)
1005 {
1006
1007 if (hvc->mode == LCDCRT || hvc->mode == CRT256_C)
1008 hd64461video_set_display_mode_crtc(hvc);
1009
1010 hd64461video_set_display_mode_lcdc(hvc);
1011 }
1012
1013 void
1014 hd64461video_set_display_mode_lcdc(struct hd64461video_chip *hvc)
1015 {
1016 struct {
1017 u_int16_t clor; /* display size 640 x 240 */
1018 u_int16_t ldr3;
1019 const char *name;
1020 } disp_conf[] = {
1021 [LCD256_C] = { 0x280 , HD64461_LCDLDR3_CG_COLOR8 ,
1022 "8bit color" },
1023 [LCD64K_C] = { 0x500 , HD64461_LCDLDR3_CG_COLOR16 ,
1024 "16bit color" },
1025 [LCD64_MONO] = { 0x280 , HD64461_LCDLDR3_CG_GRAY6 ,
1026 "6bit gray scale" },
1027 [LCD16_MONO] = { 0x140 , HD64461_LCDLDR3_CG_GRAY4 ,
1028 "4bit gray scale" },
1029 [LCD4_MONO] = { 0x0a0 , HD64461_LCDLDR3_CG_GRAY2 ,
1030 "2bit gray scale" },
1031 [LCD2_MONO] = { 0x050 , HD64461_LCDLDR3_CG_GRAY1 ,
1032 "mono chrome" },
1033 }, *conf;
1034 u_int16_t r;
1035 int omode;
1036
1037 conf = &disp_conf[hvc->mode];
1038
1039 hd64461_reg_write_2(HD64461_LCDCLOR_REG16, conf->clor);
1040 r = hd64461_reg_read_2(HD64461_LCDLDR3_REG16);
1041 omode = HD64461_LCDLDR3_CG(r);
1042 r = HD64461_LCDLDR3_CG_CLR(r);
1043 r = HD64461_LCDLDR3_CG_SET(r, conf->ldr3);
1044 hd64461_reg_write_2(HD64461_LCDLDR3_REG16, r);
1045
1046 printf("%s ", conf->name);
1047 }
1048
1049 void
1050 hd64461video_set_display_mode_crtc(struct hd64461video_chip *hvc)
1051 {
1052 /* not yet */
1053 }
1054 #endif /* notyet */
1055
1056 size_t
1057 hd64461video_frame_buffer_size(struct hd64461video_chip *hvc)
1058 {
1059 vaddr_t page, startaddr, endaddr;
1060 int x;
1061
1062 startaddr = HD64461_FBBASE;
1063 endaddr = startaddr + HD64461_FBSIZE - 1;
1064
1065 page = startaddr;
1066
1067 x = random();
1068 *(volatile int *)(page + 0) = x;
1069 *(volatile int *)(page + 4) = ~x;
1070
1071 if (*(volatile int *)(page + 0) != x ||
1072 *(volatile int *)(page + 4) != ~x)
1073 return (0);
1074
1075 for (page += HD64461_FBPAGESIZE; page < endaddr;
1076 page += HD64461_FBPAGESIZE) {
1077 if (*(volatile int *)(page + 0) == x &&
1078 *(volatile int *)(page + 4) == ~x)
1079 goto fbend_found;
1080 }
1081
1082 page -= HD64461_FBPAGESIZE;
1083 *(volatile int *)(page + 0) = x;
1084 *(volatile int *)(page + 4) = ~x;
1085
1086 if (*(volatile int *)(page + 0) != x ||
1087 *(volatile int *)(page + 4) != ~x)
1088 return (0);
1089
1090 fbend_found:
1091 return (page - startaddr);
1092 }
1093
1094 void
1095 hd64461video_set_clut(struct hd64461video_chip *vc, int idx, int cnt,
1096 u_int8_t *r, u_int8_t *g, u_int8_t *b)
1097 {
1098 KASSERT(r && g && b);
1099
1100 /* index pallete */
1101 hd64461_reg_write_2(HD64461_LCDCPTWAR_REG16,
1102 HD64461_LCDCPTWAR_SET(0, idx));
1103 /* set data */
1104 while (cnt && LEGAL_CLUT_INDEX(idx)) {
1105 u_int16_t v;
1106 #define HD64461VIDEO_SET_CLUT(x) \
1107 v = (x >> 2) & 0x3f; \
1108 hd64461_reg_write_2(HD64461_LCDCPTWDR_REG16, v)
1109 HD64461VIDEO_SET_CLUT(*r);
1110 HD64461VIDEO_SET_CLUT(*g);
1111 HD64461VIDEO_SET_CLUT(*b);
1112 #undef HD64461VIDEO_SET_CLUT
1113 r++, g++, b++;
1114 idx++, cnt--;
1115 }
1116 }
1117
1118 void
1119 hd64461video_get_clut(struct hd64461video_chip *vc, int idx, int cnt,
1120 u_int8_t *r, u_int8_t *g, u_int8_t *b)
1121 {
1122 KASSERT(r && g && b);
1123
1124 /* index pallete */
1125 hd64461_reg_write_2(HD64461_LCDCPTRAR_REG16,
1126 HD64461_LCDCPTRAR_SET(0, idx));
1127
1128 /* get data */
1129 while (cnt && LEGAL_CLUT_INDEX(idx)) {
1130 u_int16_t v;
1131 #define HD64461VIDEO_GET_CLUT(x) \
1132 v = hd64461_reg_read_2(HD64461_LCDCPTRDR_REG16); \
1133 x = HD64461_LCDCPTRDR(v); \
1134 x <<= 2
1135 HD64461VIDEO_GET_CLUT(*r);
1136 HD64461VIDEO_GET_CLUT(*g);
1137 HD64461VIDEO_GET_CLUT(*b);
1138 #undef HD64461VIDEO_GET_CLUT
1139 r++, g++, b++;
1140 idx++, cnt--;
1141 }
1142 }
1143
1144 int
1145 hd64461video_power(void *ctx, int type, long id, void *msg)
1146 {
1147 struct hd64461video_softc *sc = ctx;
1148 struct hd64461video_chip *hvc = sc->sc_vc;
1149
1150 switch ((int)msg) {
1151 case PWR_RESUME:
1152 if (!hvc->console)
1153 break; /* serial console */
1154 DPRINTF("%s: ON\n", sc->sc_dev.dv_xname);
1155 hd64461video_on(hvc);
1156 break;
1157 case PWR_SUSPEND:
1158 /* FALLTHROUGH */
1159 case PWR_STANDBY:
1160 DPRINTF("%s: OFF\n", sc->sc_dev.dv_xname);
1161 hd64461video_off(hvc);
1162 break;
1163 }
1164
1165 return 0;
1166 }
1167
1168 void
1169 hd64461video_off(struct hd64461video_chip *vc)
1170 {
1171
1172 callout_stop(&vc->unblank_ch);
1173
1174 /* turn off display in LCDC */
1175 hd64461video_display_onoff(vc, FALSE);
1176
1177 /* turn off the LCD */
1178 config_hook_call(CONFIG_HOOK_POWERCONTROL,
1179 CONFIG_HOOK_POWERCONTROL_LCD,
1180 (void *)0);
1181 }
1182
1183 void
1184 hd64461video_on(struct hd64461video_chip *vc)
1185 {
1186 int err;
1187
1188 /* turn on the LCD */
1189 err = config_hook_call(CONFIG_HOOK_POWERCONTROL,
1190 CONFIG_HOOK_POWERCONTROL_LCD,
1191 (void *)1);
1192
1193 if (err == 0)
1194 /* let the LCD warm up before turning on the display */
1195 callout_reset(&vc->unblank_ch, hz/2,
1196 hd64461video_display_on, vc);
1197 else
1198 hd64461video_display_onoff(vc, TRUE);
1199 }
1200
1201 void
1202 hd64461video_display_on(void *arg)
1203 {
1204
1205 hd64461video_display_onoff(arg, TRUE);
1206 }
1207
1208 void
1209 hd64461video_display_onoff(void *arg, boolean_t on)
1210 {
1211 /* struct hd64461video_chip *vc = arg; */
1212 u_int16_t r;
1213
1214 /* turn on/off display in LCDC */
1215 r = hd64461_reg_read_2(HD64461_LCDLDR1_REG16);
1216 if (on)
1217 r |= HD64461_LCDLDR1_DON;
1218 else
1219 r &= ~HD64461_LCDLDR1_DON;
1220 hd64461_reg_write_2(HD64461_LCDLDR1_REG16, r);
1221 }
1222
1223 #ifdef HD64461VIDEO_DEBUG
1224 void
1225 hd64461video_info(struct hd64461video_softc *sc)
1226 {
1227 u_int16_t r;
1228 int color;
1229 int i;
1230
1231 dbg_banner_function();
1232 printf("---[LCD]---\n");
1233 /* Base Address Register */
1234 r = hd64461_reg_read_2(HD64461_LCDCBAR_REG16);
1235 printf("LCDCBAR Frame buffer base address (4KB align): 0x%08x\n",
1236 HD64461_LCDCBAR_BASEADDR(r));
1237
1238 /* Line Address Offset Register */
1239 r = hd64461_reg_read_2(HD64461_LCDCLOR_REG16);
1240 printf("LCDCLOR Line address offset: %d\n", HD64461_LCDCLOR(r));
1241
1242 /* LCDC Control Register */
1243 r = hd64461_reg_read_2(HD64461_LCDCCR_REG16);
1244 i = HD64461_LCDCCR_DSPSEL(r);
1245 #define DBG_BITMASK_PRINT(r, m) dbg_bitmask_print(r, HD64461_LCDCCR_##m, #m)
1246 printf("LCDCCR (LCD Control Register)\n");
1247 DBG_BITMASK_PRINT(r, STBAK);
1248 DBG_BITMASK_PRINT(r, STREQ);
1249 DBG_BITMASK_PRINT(r, MOFF);
1250 DBG_BITMASK_PRINT(r, REFSEL);
1251 DBG_BITMASK_PRINT(r, EPON);
1252 DBG_BITMASK_PRINT(r, SPON);
1253 printf("\n");
1254 #undef DBG_BITMASK_PRINT
1255 printf("LCDCCR Display select LCD[%c] CRT[%c]\n",
1256 i == HD64461_LCDCCR_DSPSEL_LCD_CRT ||
1257 i == HD64461_LCDCCR_DSPSEL_LCD ? 'x' : '_',
1258 i == HD64461_LCDCCR_DSPSEL_LCD_CRT ||
1259 i == HD64461_LCDCCR_DSPSEL_CRT ? 'x' : '_');
1260
1261 /* LCD Display Register */
1262 /* 1 */
1263 r = hd64461_reg_read_2(HD64461_LCDLDR1_REG16);
1264 printf("(LCD Display Register)\n");
1265 #define DBG_BITMASK_PRINT(r, m) dbg_bitmask_print(r, HD64461_LCDLDR1_##m, #m)
1266 printf("LCDLDR1: ");
1267 DBG_BITMASK_PRINT(r, DINV);
1268 DBG_BITMASK_PRINT(r, DON);
1269 printf("\n");
1270 #undef DBG_BITMASK_PRINT
1271 /* 2 */
1272 r = hd64461_reg_read_2(HD64461_LCDLDR2_REG16);
1273 i = HD64461_LCDLDR2_LM(r);
1274 #define DBG_BITMASK_PRINT(r, m) dbg_bitmask_print(r, HD64461_LCDLDR2_##m, #m)
1275 printf("LCDLDR2: ");
1276 DBG_BITMASK_PRINT(r, CC1);
1277 DBG_BITMASK_PRINT(r, CC2);
1278 #undef DBG_BITMASK_PRINT
1279 color = 0;
1280 switch (i) {
1281 default:
1282 panic("unknown unknown LCD interface.");
1283 break;
1284 case HD64461_LCDLDR2_LM_COLOR:
1285 color = 1;
1286 printf("Color");
1287 break;
1288 case HD64461_LCDLDR2_LM_GRAY8:
1289 printf("8-bit grayscale");
1290 break;
1291 case HD64461_LCDLDR2_LM_GRAY4:
1292 printf("8-bit grayscale");
1293 break;
1294 }
1295 printf(" LCD interface\n");
1296 /* 3 */
1297 printf("LCDLDR3: ");
1298 r = hd64461_reg_read_2(HD64461_LCDLDR3_REG16);
1299 i = HD64461_LCDLDR3_CS(r);
1300 printf("CS ");
1301 switch (i) {
1302 case 0:
1303 printf("15");
1304 break;
1305 case 1:
1306 printf("2.5");
1307 break;
1308 case 2:
1309 printf("3.75");
1310 break;
1311 case 4:
1312 printf("5");
1313 break;
1314 case 8:
1315 printf("7.5");
1316 break;
1317 case 16:
1318 printf("10");
1319 break;
1320 }
1321 printf("%s MHz ", color ? "" : "/2");
1322 i = HD64461_LCDLDR3_CG(r);
1323 switch (i) {
1324 case HD64461_LCDLDR3_CG_COLOR16:
1325 printf("Color 64K colors\n");
1326 break;
1327 case HD64461_LCDLDR3_CG_COLOR8:
1328 printf("Color 256 colors\n");
1329 break;
1330 case HD64461_LCDLDR3_CG_GRAY6:
1331 printf("6-bit Grayscale\n");
1332 break;
1333 case HD64461_LCDLDR3_CG_GRAY4:
1334 printf("4-bit Grayscale\n");
1335 break;
1336 case HD64461_LCDLDR3_CG_GRAY2:
1337 printf("2-bit Grayscale\n");
1338 break;
1339 case HD64461_LCDLDR3_CG_GRAY1:
1340 printf("1-bit Grayscale\n");
1341 break;
1342 }
1343
1344 /* LCD Number of Characters in Horizontal Register */
1345 r = hd64461_reg_read_2(HD64461_LCDLDHNCR_REG16);
1346 printf("LDHNCR: NHD %d NHT %d (# of horizontal characters)\n",
1347 HD64461_LCDLDHNCR_NHD(r), HD64461_LCDLDHNCR_NHT(r));
1348
1349 /* Start Position of Horizontal Register */
1350 r = hd64461_reg_read_2(HD64461_LCDLDHNSR_REG16);
1351 printf("LDHNSR: HSW %d HSP %d (start position of horizontal)\n",
1352 HD64461_LCDLDHNSR_HSW(r), HD64461_LCDLDHNSR_HSP(r));
1353
1354 /* Total Vertical Lines Register */
1355 r = hd64461_reg_read_2(HD64461_LCDLDVNTR_REG16);
1356 printf("LDVNTR: %d (total vertical lines)\n",
1357 HD64461_LCDLDVNTR_VTL(r));
1358
1359 /* Display Vertical Lines Register */
1360 r = hd64461_reg_read_2(HD64461_LCDLDVNDR_REG16);
1361 printf("LDVNDR: %d (display vertical lines)\n",
1362 HD64461_LCDLDVSPR_VSP(r));
1363
1364 /* Vertical Synchronization Position Register */
1365 r = hd64461_reg_read_2(HD64461_LCDLDVSPR_REG16);
1366 printf("LDVSPR: %d (vertical synchronization position)\n",
1367 HD64461_LCDLDVSPR_VSP(r));
1368
1369 /*
1370 * CRT Control Register
1371 */
1372 printf("---[CRT]---\n");
1373 r = hd64461_reg_read_2(HD64461_LCDCRTVTR_REG16);
1374 printf("CRTVTR: %d (CRTC total vertical lines)\n",
1375 HD64461_LCDCRTVTR(r));
1376 r = hd64461_reg_read_2(HD64461_LCDCRTVRSR_REG16);
1377 printf("CRTVRSR: %d (CRTC vertical retrace start line)\n",
1378 HD64461_LCDCRTVRSR(r));
1379 r = hd64461_reg_read_2(HD64461_LCDCRTVRER_REG16);
1380 printf("CRTVRER: %d (CRTC vertical retrace end line)\n",
1381 HD64461_LCDCRTVRER(r));
1382
1383 }
1384
1385 void
1386 hd64461video_dump()
1387 {
1388 u_int16_t r;
1389 printf("---[Display Mode Setting]---\n");
1390 #define DUMPREG(x) \
1391 r = hd64461_reg_read_2(HD64461_LCD ## x ## _REG16); \
1392 __dbg_bit_print(r, sizeof(u_int16_t), 0, 0, #x, DBG_BIT_PRINT_COUNT)
1393 DUMPREG(CBAR);
1394 DUMPREG(CLOR);
1395 DUMPREG(CCR);
1396 DUMPREG(LDR1);
1397 DUMPREG(LDR2);
1398 DUMPREG(LDHNCR);
1399 DUMPREG(LDHNSR);
1400 DUMPREG(LDVNTR);
1401 DUMPREG(LDVNDR);
1402 DUMPREG(LDVSPR);
1403 DUMPREG(LDR3);
1404 DUMPREG(CRTVTR);
1405 DUMPREG(CRTVRSR);
1406 DUMPREG(CRTVRER);
1407 #undef DUMPREG
1408 dbg_banner_line();
1409 }
1410
1411 #endif /* HD64461VIDEO_DEBUG */
1412