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