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