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