1 /* 2 * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <asm/unaligned.h> 8 #include <config.h> 9 #include <common.h> 10 #include <errno.h> 11 #include <libfdt.h> 12 #include <fdtdec.h> 13 #include <fdt_support.h> 14 #include <linux/list.h> 15 #include <linux/compat.h> 16 #include <linux/media-bus-format.h> 17 #include <malloc.h> 18 #include <video.h> 19 #include <video_rockchip.h> 20 #include <dm/device.h> 21 #include <dm/uclass-internal.h> 22 #include <asm/arch-rockchip/resource_img.h> 23 24 #include "bmp_helper.h" 25 #include "rockchip_display.h" 26 #include "rockchip_crtc.h" 27 #include "rockchip_connector.h" 28 #include "rockchip_phy.h" 29 #include "rockchip_panel.h" 30 #include <dm.h> 31 #include <dm/of_access.h> 32 #include <dm/ofnode.h> 33 34 #define DRIVER_VERSION "v1.0.0" 35 36 /*********************************************************************** 37 * Rockchip UBOOT DRM driver version 38 * 39 * v1.0.0 : add basic version for rockchip drm driver(hjc) 40 * 41 **********************************************************************/ 42 43 #define RK_BLK_SIZE 512 44 45 DECLARE_GLOBAL_DATA_PTR; 46 static LIST_HEAD(rockchip_display_list); 47 static LIST_HEAD(logo_cache_list); 48 49 static unsigned long memory_start; 50 static unsigned long memory_end; 51 52 static void init_display_buffer(ulong base) 53 { 54 memory_start = base + DRM_ROCKCHIP_FB_SIZE; 55 memory_end = memory_start; 56 } 57 58 static void *get_display_buffer(int size) 59 { 60 unsigned long roundup_memory = roundup(memory_end, PAGE_SIZE); 61 void *buf; 62 63 if (roundup_memory + size > memory_start + MEMORY_POOL_SIZE) { 64 printf("failed to alloc %dbyte memory to display\n", size); 65 return NULL; 66 } 67 buf = (void *)roundup_memory; 68 69 memory_end = roundup_memory + size; 70 71 return buf; 72 } 73 74 static unsigned long get_display_size(void) 75 { 76 return memory_end - memory_start; 77 } 78 79 static bool can_direct_logo(int bpp) 80 { 81 return bpp == 24 || bpp == 32; 82 } 83 84 85 static struct udevice *get_panel_device(struct display_state *state, ofnode conn_node) 86 { 87 struct panel_state *panel_state = &state->panel_state; 88 struct udevice *dev; 89 struct connector_state *conn_state = &state->conn_state; 90 ofnode node, ports_node, port_node; 91 struct device_node *port, *panel, *ep; 92 int ph; 93 int ret; 94 95 node = dev_read_subnode(conn_state->dev, "panel"); 96 if (ofnode_valid(node) && 97 of_device_is_available(ofnode_to_np(node))) { 98 ret = uclass_get_device_by_ofnode(UCLASS_PANEL, node, &dev); 99 if (!ret) { 100 panel_state->node = node; 101 return dev; 102 } 103 } 104 105 /* TODO: this path not tested */ 106 ports_node = dev_read_subnode(conn_state->dev, "ports"); 107 if (!ofnode_valid(ports_node)) 108 return NULL; 109 110 ofnode_for_each_subnode(port_node, ports_node) { 111 ofnode_for_each_subnode(node, port_node) { 112 ph = ofnode_read_u32_default(node, "remote-endpoint", -1); 113 if (!ph) 114 continue; 115 ep = of_find_node_by_phandle(ph); 116 if (!ofnode_valid(np_to_ofnode(ep))) { 117 printf("Warn: can't find endpoint from phdl\n"); 118 continue; 119 } 120 port = of_get_parent(ep); 121 if (!ofnode_valid(np_to_ofnode(port))) { 122 printf("Warn: can't find port node\n"); 123 continue; 124 } 125 panel = of_get_parent(port); 126 if (!ofnode_valid(np_to_ofnode(panel))) { 127 printf("Warn: can't find panel node\n"); 128 continue; 129 } 130 ret = uclass_get_device_by_ofnode(UCLASS_PANEL, 131 np_to_ofnode(panel), 132 &dev); 133 if (!ret) { 134 panel_state->node = np_to_ofnode(panel); 135 return dev; 136 } 137 } 138 } 139 140 return NULL; 141 } 142 143 static int connector_phy_init(struct display_state *state) 144 { 145 struct connector_state *conn_state = &state->conn_state; 146 const struct rockchip_phy *phy; 147 struct udevice *dev; 148 int ret; 149 150 ret = uclass_get_device_by_phandle(UCLASS_PHY, conn_state->dev, "phys", 151 &dev); 152 if (ret) { 153 debug("Warn: can't find phy driver\n"); 154 return 0; 155 } 156 157 phy = (const struct rockchip_phy *)dev_get_driver_data(dev); 158 if (!phy) { 159 printf("failed to find phy driver\n"); 160 return 0; 161 } 162 163 conn_state->phy_dev = dev; 164 conn_state->phy_node = dev->node; 165 166 if (!phy->funcs || !phy->funcs->init || 167 phy->funcs->init(state)) { 168 printf("failed to init phy driver\n"); 169 return -EINVAL; 170 } 171 172 conn_state->phy = phy; 173 return 0; 174 } 175 176 static int connector_panel_init(struct display_state *state) 177 { 178 struct connector_state *conn_state = &state->conn_state; 179 struct panel_state *panel_state = &state->panel_state; 180 struct udevice *dev; 181 ofnode conn_node = conn_state->node; 182 const struct rockchip_panel *panel; 183 ofnode dsp_lut_node; 184 int ret, len; 185 186 dm_scan_fdt_dev(conn_state->dev); 187 188 dev = get_panel_device(state, conn_node); 189 if (!dev) { 190 return 0; 191 } 192 193 panel = (const struct rockchip_panel *)dev_get_driver_data(dev); 194 if (!panel) { 195 printf("failed to find panel driver\n"); 196 return 0; 197 } 198 199 panel_state->dev = dev; 200 panel_state->panel = panel; 201 202 ret = rockchip_panel_init(state); 203 if (ret) { 204 printf("failed to init panel driver\n"); 205 return ret; 206 } 207 208 dsp_lut_node = dev_read_subnode(dev, "dsp-lut"); 209 if (!ofnode_valid(dsp_lut_node)) { 210 debug("%s can not find dsp-lut node\n", __func__); 211 return 0; 212 } 213 214 ofnode_get_property(dsp_lut_node, "gamma-lut", &len); 215 if (len > 0) { 216 conn_state->gamma.size = len / sizeof(u32); 217 conn_state->gamma.lut = malloc(len); 218 if (!conn_state->gamma.lut) { 219 printf("malloc gamma lut failed\n"); 220 return -ENOMEM; 221 } 222 ret = ofnode_read_u32_array(dsp_lut_node, "gamma-lut", 223 conn_state->gamma.lut, 224 conn_state->gamma.size); 225 if (ret) { 226 printf("Cannot decode gamma_lut\n"); 227 conn_state->gamma.lut = NULL; 228 return -EINVAL; 229 } 230 panel_state->dsp_lut_node = dsp_lut_node; 231 } 232 233 return 0; 234 } 235 236 int drm_mode_vrefresh(const struct drm_display_mode *mode) 237 { 238 int refresh = 0; 239 unsigned int calc_val; 240 241 if (mode->vrefresh > 0) { 242 refresh = mode->vrefresh; 243 } else if (mode->htotal > 0 && mode->vtotal > 0) { 244 int vtotal; 245 246 vtotal = mode->vtotal; 247 /* work out vrefresh the value will be x1000 */ 248 calc_val = (mode->clock * 1000); 249 calc_val /= mode->htotal; 250 refresh = (calc_val + vtotal / 2) / vtotal; 251 252 if (mode->flags & DRM_MODE_FLAG_INTERLACE) 253 refresh *= 2; 254 if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 255 refresh /= 2; 256 if (mode->vscan > 1) 257 refresh /= mode->vscan; 258 } 259 return refresh; 260 } 261 262 static int display_get_timing_from_dts(struct panel_state *panel_state, 263 struct drm_display_mode *mode) 264 { 265 int phandle; 266 int hactive, vactive, pixelclock; 267 int hfront_porch, hback_porch, hsync_len; 268 int vfront_porch, vback_porch, vsync_len; 269 int val, flags = 0; 270 ofnode timing, native_mode; 271 272 timing = dev_read_subnode(panel_state->dev, "display-timings"); 273 if (!ofnode_valid(timing)) 274 return -ENODEV; 275 276 native_mode = ofnode_find_subnode(timing, "timing"); 277 if (!ofnode_valid(native_mode)) { 278 phandle = ofnode_read_u32_default(timing, "native-mode", -1); 279 native_mode = np_to_ofnode(of_find_node_by_phandle(phandle)); 280 if (!ofnode_valid(native_mode)) { 281 printf("failed to get display timings from DT\n"); 282 return -ENXIO; 283 } 284 } 285 286 #define FDT_GET_INT(val, name) \ 287 val = ofnode_read_s32_default(native_mode, name, -1); \ 288 if (val < 0) { \ 289 printf("Can't get %s\n", name); \ 290 return -ENXIO; \ 291 } 292 293 FDT_GET_INT(hactive, "hactive"); 294 FDT_GET_INT(vactive, "vactive"); 295 FDT_GET_INT(pixelclock, "clock-frequency"); 296 FDT_GET_INT(hsync_len, "hsync-len"); 297 FDT_GET_INT(hfront_porch, "hfront-porch"); 298 FDT_GET_INT(hback_porch, "hback-porch"); 299 FDT_GET_INT(vsync_len, "vsync-len"); 300 FDT_GET_INT(vfront_porch, "vfront-porch"); 301 FDT_GET_INT(vback_porch, "vback-porch"); 302 FDT_GET_INT(val, "hsync-active"); 303 flags |= val ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; 304 FDT_GET_INT(val, "vsync-active"); 305 flags |= val ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; 306 307 mode->hdisplay = hactive; 308 mode->hsync_start = mode->hdisplay + hfront_porch; 309 mode->hsync_end = mode->hsync_start + hsync_len; 310 mode->htotal = mode->hsync_end + hback_porch; 311 312 mode->vdisplay = vactive; 313 mode->vsync_start = mode->vdisplay + vfront_porch; 314 mode->vsync_end = mode->vsync_start + vsync_len; 315 mode->vtotal = mode->vsync_end + vback_porch; 316 317 mode->clock = pixelclock / 1000; 318 mode->flags = flags; 319 320 return 0; 321 } 322 323 /** 324 * drm_mode_set_crtcinfo - set CRTC modesetting timing parameters 325 * @p: mode 326 * @adjust_flags: a combination of adjustment flags 327 * 328 * Setup the CRTC modesetting timing parameters for @p, adjusting if necessary. 329 * 330 * - The CRTC_INTERLACE_HALVE_V flag can be used to halve vertical timings of 331 * interlaced modes. 332 * - The CRTC_STEREO_DOUBLE flag can be used to compute the timings for 333 * buffers containing two eyes (only adjust the timings when needed, eg. for 334 * "frame packing" or "side by side full"). 335 * - The CRTC_NO_DBLSCAN and CRTC_NO_VSCAN flags request that adjustment *not* 336 * be performed for doublescan and vscan > 1 modes respectively. 337 */ 338 void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) 339 { 340 if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN)) 341 return; 342 343 if (p->flags & DRM_MODE_FLAG_DBLCLK) 344 p->crtc_clock = 2 * p->clock; 345 else 346 p->crtc_clock = p->clock; 347 p->crtc_hdisplay = p->hdisplay; 348 p->crtc_hsync_start = p->hsync_start; 349 p->crtc_hsync_end = p->hsync_end; 350 p->crtc_htotal = p->htotal; 351 p->crtc_hskew = p->hskew; 352 p->crtc_vdisplay = p->vdisplay; 353 p->crtc_vsync_start = p->vsync_start; 354 p->crtc_vsync_end = p->vsync_end; 355 p->crtc_vtotal = p->vtotal; 356 357 if (p->flags & DRM_MODE_FLAG_INTERLACE) { 358 if (adjust_flags & CRTC_INTERLACE_HALVE_V) { 359 p->crtc_vdisplay /= 2; 360 p->crtc_vsync_start /= 2; 361 p->crtc_vsync_end /= 2; 362 p->crtc_vtotal /= 2; 363 } 364 } 365 366 if (!(adjust_flags & CRTC_NO_DBLSCAN)) { 367 if (p->flags & DRM_MODE_FLAG_DBLSCAN) { 368 p->crtc_vdisplay *= 2; 369 p->crtc_vsync_start *= 2; 370 p->crtc_vsync_end *= 2; 371 p->crtc_vtotal *= 2; 372 } 373 } 374 375 if (!(adjust_flags & CRTC_NO_VSCAN)) { 376 if (p->vscan > 1) { 377 p->crtc_vdisplay *= p->vscan; 378 p->crtc_vsync_start *= p->vscan; 379 p->crtc_vsync_end *= p->vscan; 380 p->crtc_vtotal *= p->vscan; 381 } 382 } 383 384 if (adjust_flags & CRTC_STEREO_DOUBLE) { 385 unsigned int layout = p->flags & DRM_MODE_FLAG_3D_MASK; 386 387 switch (layout) { 388 case DRM_MODE_FLAG_3D_FRAME_PACKING: 389 p->crtc_clock *= 2; 390 p->crtc_vdisplay += p->crtc_vtotal; 391 p->crtc_vsync_start += p->crtc_vtotal; 392 p->crtc_vsync_end += p->crtc_vtotal; 393 p->crtc_vtotal += p->crtc_vtotal; 394 break; 395 } 396 } 397 398 p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay); 399 p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal); 400 p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay); 401 p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal); 402 } 403 404 static int display_get_timing(struct display_state *state) 405 { 406 struct connector_state *conn_state = &state->conn_state; 407 const struct rockchip_connector *conn = conn_state->connector; 408 const struct rockchip_connector_funcs *conn_funcs = conn->funcs; 409 struct drm_display_mode *mode = &conn_state->mode; 410 const struct drm_display_mode *m; 411 struct panel_state *panel_state = &state->panel_state; 412 ofnode panel = panel_state->node; 413 414 if (ofnode_valid(panel) && !display_get_timing_from_dts(panel_state, mode)) { 415 printf("Using display timing dts\n"); 416 goto done; 417 } 418 419 m = rockchip_get_display_mode_from_panel(state); 420 if (m) { 421 printf("Using display timing from compatible panel driver\n"); 422 memcpy(mode, m, sizeof(*m)); 423 goto done; 424 } 425 426 rockchip_panel_prepare(state); 427 428 if (conn_funcs->get_edid && !conn_funcs->get_edid(state)) { 429 int panel_bits_per_colourp; 430 431 if (!edid_get_drm_mode((void *)&conn_state->edid, 432 sizeof(conn_state->edid), mode, 433 &panel_bits_per_colourp)) { 434 printf("Using display timing from edid\n"); 435 edid_print_info((void *)&conn_state->edid); 436 goto done; 437 } 438 } 439 440 printf("failed to find display timing\n"); 441 return -ENODEV; 442 done: 443 printf("Detailed mode clock %u kHz, flags[%x]\n" 444 " H: %04d %04d %04d %04d\n" 445 " V: %04d %04d %04d %04d\n" 446 "bus_format: %x\n", 447 mode->clock, mode->flags, 448 mode->hdisplay, mode->hsync_start, 449 mode->hsync_end, mode->htotal, 450 mode->vdisplay, mode->vsync_start, 451 mode->vsync_end, mode->vtotal, 452 conn_state->bus_format); 453 454 return 0; 455 } 456 457 static int display_init(struct display_state *state) 458 { 459 struct connector_state *conn_state = &state->conn_state; 460 const struct rockchip_connector *conn = conn_state->connector; 461 const struct rockchip_connector_funcs *conn_funcs = conn->funcs; 462 struct crtc_state *crtc_state = &state->crtc_state; 463 const struct rockchip_crtc *crtc = crtc_state->crtc; 464 const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs; 465 struct drm_display_mode *mode = &conn_state->mode; 466 int ret = 0; 467 static bool __print_once = false; 468 469 if (!__print_once) { 470 __print_once = true; 471 printf("Rockchip UBOOT DRM driver version: %s\n", DRIVER_VERSION); 472 } 473 474 if (state->is_init) 475 return 0; 476 477 if (!conn_funcs || !crtc_funcs) { 478 printf("failed to find connector or crtc functions\n"); 479 return -ENXIO; 480 } 481 482 if (conn_funcs->init) { 483 ret = conn_funcs->init(state); 484 if (ret) 485 goto deinit; 486 } 487 /* 488 * support hotplug, but not connect; 489 */ 490 if (conn_funcs->detect) { 491 ret = conn_funcs->detect(state); 492 if (!ret) 493 goto deinit; 494 } 495 496 if (conn_funcs->get_timing) { 497 ret = conn_funcs->get_timing(state); 498 if (ret) 499 goto deinit; 500 } else { 501 ret = display_get_timing(state); 502 if (ret) 503 goto deinit; 504 } 505 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); 506 507 if (crtc_funcs->init) { 508 ret = crtc_funcs->init(state); 509 if (ret) 510 goto deinit; 511 } 512 513 state->is_init = 1; 514 515 return 0; 516 517 deinit: 518 if (conn_funcs->deinit) 519 conn_funcs->deinit(state); 520 return ret; 521 } 522 523 static int display_set_plane(struct display_state *state) 524 { 525 struct crtc_state *crtc_state = &state->crtc_state; 526 const struct rockchip_crtc *crtc = crtc_state->crtc; 527 const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs; 528 int ret; 529 530 if (!state->is_init) 531 return -EINVAL; 532 533 if (crtc_funcs->set_plane) { 534 ret = crtc_funcs->set_plane(state); 535 if (ret) 536 return ret; 537 } 538 539 return 0; 540 } 541 542 static int display_enable(struct display_state *state) 543 { 544 struct connector_state *conn_state = &state->conn_state; 545 const struct rockchip_connector *conn = conn_state->connector; 546 const struct rockchip_connector_funcs *conn_funcs = conn->funcs; 547 struct crtc_state *crtc_state = &state->crtc_state; 548 const struct rockchip_crtc *crtc = crtc_state->crtc; 549 const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs; 550 int ret = 0; 551 552 display_init(state); 553 554 if (!state->is_init) 555 return -EINVAL; 556 557 if (state->is_enable) 558 return 0; 559 560 if (crtc_funcs->prepare) { 561 ret = crtc_funcs->prepare(state); 562 if (ret) 563 return ret; 564 } 565 566 if (conn_funcs->prepare) { 567 ret = conn_funcs->prepare(state); 568 if (ret) 569 goto unprepare_crtc; 570 } 571 572 rockchip_panel_prepare(state); 573 574 if (crtc_funcs->enable) { 575 ret = crtc_funcs->enable(state); 576 if (ret) 577 goto unprepare_conn; 578 } 579 580 if (conn_funcs->enable) { 581 ret = conn_funcs->enable(state); 582 if (ret) 583 goto disable_crtc; 584 } 585 586 rockchip_panel_enable(state); 587 588 state->is_enable = true; 589 590 return 0; 591 unprepare_crtc: 592 if (crtc_funcs->unprepare) 593 crtc_funcs->unprepare(state); 594 unprepare_conn: 595 if (conn_funcs->unprepare) 596 conn_funcs->unprepare(state); 597 disable_crtc: 598 if (crtc_funcs->disable) 599 crtc_funcs->disable(state); 600 return ret; 601 } 602 603 static int display_disable(struct display_state *state) 604 { 605 struct connector_state *conn_state = &state->conn_state; 606 const struct rockchip_connector *conn = conn_state->connector; 607 const struct rockchip_connector_funcs *conn_funcs = conn->funcs; 608 struct crtc_state *crtc_state = &state->crtc_state; 609 const struct rockchip_crtc *crtc = crtc_state->crtc; 610 const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs; 611 612 if (!state->is_init) 613 return 0; 614 615 if (!state->is_enable) 616 return 0; 617 618 rockchip_panel_disable(state); 619 620 if (crtc_funcs->disable) 621 crtc_funcs->disable(state); 622 623 if (conn_funcs->disable) 624 conn_funcs->disable(state); 625 626 rockchip_panel_unprepare(state); 627 628 if (conn_funcs->unprepare) 629 conn_funcs->unprepare(state); 630 631 state->is_enable = 0; 632 state->is_init = 0; 633 634 return 0; 635 } 636 637 static int display_logo(struct display_state *state) 638 { 639 struct crtc_state *crtc_state = &state->crtc_state; 640 struct connector_state *conn_state = &state->conn_state; 641 struct logo_info *logo = &state->logo; 642 int hdisplay, vdisplay; 643 644 display_init(state); 645 if (!state->is_init) 646 return -ENODEV; 647 648 switch (logo->bpp) { 649 case 16: 650 crtc_state->format = ROCKCHIP_FMT_RGB565; 651 break; 652 case 24: 653 crtc_state->format = ROCKCHIP_FMT_RGB888; 654 break; 655 case 32: 656 crtc_state->format = ROCKCHIP_FMT_ARGB8888; 657 break; 658 default: 659 printf("can't support bmp bits[%d]\n", logo->bpp); 660 return -EINVAL; 661 } 662 crtc_state->rb_swap = logo->bpp != 32; 663 hdisplay = conn_state->mode.hdisplay; 664 vdisplay = conn_state->mode.vdisplay; 665 crtc_state->src_w = logo->width; 666 crtc_state->src_h = logo->height; 667 crtc_state->src_x = 0; 668 crtc_state->src_y = 0; 669 crtc_state->ymirror = logo->ymirror; 670 671 crtc_state->dma_addr = (u32)(unsigned long)logo->mem + logo->offset; 672 crtc_state->xvir = ALIGN(crtc_state->src_w * logo->bpp, 32) >> 5; 673 674 if (logo->mode == ROCKCHIP_DISPLAY_FULLSCREEN) { 675 crtc_state->crtc_x = 0; 676 crtc_state->crtc_y = 0; 677 crtc_state->crtc_w = hdisplay; 678 crtc_state->crtc_h = vdisplay; 679 } else { 680 if (crtc_state->src_w >= hdisplay) { 681 crtc_state->crtc_x = 0; 682 crtc_state->crtc_w = hdisplay; 683 } else { 684 crtc_state->crtc_x = (hdisplay - crtc_state->src_w) / 2; 685 crtc_state->crtc_w = crtc_state->src_w; 686 } 687 688 if (crtc_state->src_h >= vdisplay) { 689 crtc_state->crtc_y = 0; 690 crtc_state->crtc_h = vdisplay; 691 } else { 692 crtc_state->crtc_y = (vdisplay - crtc_state->src_h) / 2; 693 crtc_state->crtc_h = crtc_state->src_h; 694 } 695 } 696 697 display_set_plane(state); 698 display_enable(state); 699 700 return 0; 701 } 702 703 static int get_crtc_id(ofnode connect) 704 { 705 int phandle; 706 struct device_node *remote; 707 int val; 708 709 phandle = ofnode_read_u32_default(connect, "remote-endpoint", -1); 710 if (phandle < 0) 711 goto err; 712 remote = of_find_node_by_phandle(phandle); 713 val = ofnode_read_u32_default(np_to_ofnode(remote), "reg", -1); 714 if (val < 0) 715 goto err; 716 717 return val; 718 err: 719 printf("Can't get crtc id, default set to id = 0\n"); 720 return 0; 721 } 722 723 struct rockchip_logo_cache *find_or_alloc_logo_cache(const char *bmp) 724 { 725 struct rockchip_logo_cache *tmp, *logo_cache = NULL; 726 727 list_for_each_entry(tmp, &logo_cache_list, head) { 728 if (!strcmp(tmp->name, bmp)) { 729 logo_cache = tmp; 730 break; 731 } 732 } 733 734 if (!logo_cache) { 735 logo_cache = malloc(sizeof(*logo_cache)); 736 if (!logo_cache) { 737 printf("failed to alloc memory for logo cache\n"); 738 return NULL; 739 } 740 memset(logo_cache, 0, sizeof(*logo_cache)); 741 strcpy(logo_cache->name, bmp); 742 INIT_LIST_HEAD(&logo_cache->head); 743 list_add_tail(&logo_cache->head, &logo_cache_list); 744 } 745 746 return logo_cache; 747 } 748 749 static int load_bmp_logo(struct logo_info *logo, const char *bmp_name) 750 { 751 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE 752 struct rockchip_logo_cache *logo_cache; 753 struct bmp_header *header; 754 void *dst = NULL, *pdst; 755 int size, len; 756 int ret = 0; 757 758 if (!logo || !bmp_name) 759 return -EINVAL; 760 logo_cache = find_or_alloc_logo_cache(bmp_name); 761 if (!logo_cache) 762 return -ENOMEM; 763 764 if (logo_cache->logo.mem) { 765 memcpy(logo, &logo_cache->logo, sizeof(*logo)); 766 return 0; 767 } 768 769 header = malloc(RK_BLK_SIZE); 770 if (!header) 771 return -ENOMEM; 772 773 len = rockchip_read_resource_file(header, bmp_name, 0, RK_BLK_SIZE); 774 if (len != RK_BLK_SIZE) { 775 ret = -EINVAL; 776 goto free_header; 777 } 778 779 logo->bpp = get_unaligned_le16(&header->bit_count); 780 logo->width = get_unaligned_le32(&header->width); 781 logo->height = get_unaligned_le32(&header->height); 782 size = get_unaligned_le32(&header->file_size); 783 if (!can_direct_logo(logo->bpp)) { 784 if (size > MEMORY_POOL_SIZE) { 785 printf("failed to use boot buf as temp bmp buffer\n"); 786 ret = -ENOMEM; 787 goto free_header; 788 } 789 pdst = get_display_buffer(size); 790 791 } else { 792 pdst = get_display_buffer(size); 793 dst = pdst; 794 } 795 796 len = rockchip_read_resource_file(pdst, bmp_name, 0, size); 797 if (len != size) { 798 printf("failed to load bmp %s\n", bmp_name); 799 ret = -ENOENT; 800 goto free_header; 801 } 802 803 if (!can_direct_logo(logo->bpp)) { 804 int dst_size; 805 /* 806 * TODO: force use 16bpp if bpp less than 16; 807 */ 808 logo->bpp = (logo->bpp <= 16) ? 16 : logo->bpp; 809 dst_size = logo->width * logo->height * logo->bpp >> 3; 810 811 dst = get_display_buffer(dst_size); 812 if (!dst) { 813 ret = -ENOMEM; 814 goto free_header; 815 } 816 if (bmpdecoder(pdst, dst, logo->bpp)) { 817 printf("failed to decode bmp %s\n", bmp_name); 818 ret = -EINVAL; 819 goto free_header; 820 } 821 flush_dcache_range((ulong)dst, 822 ALIGN((ulong)dst + dst_size, 823 CONFIG_SYS_CACHELINE_SIZE)); 824 825 logo->offset = 0; 826 logo->ymirror = 0; 827 } else { 828 logo->offset = get_unaligned_le32(&header->data_offset); 829 logo->ymirror = 1; 830 } 831 logo->mem = dst; 832 833 memcpy(&logo_cache->logo, logo, sizeof(*logo)); 834 835 free_header: 836 837 free(header); 838 839 return ret; 840 #else 841 return -EINVAL; 842 #endif 843 } 844 845 void rockchip_show_fbbase(ulong fbbase) 846 { 847 struct display_state *s; 848 849 list_for_each_entry(s, &rockchip_display_list, head) { 850 s->logo.mode = ROCKCHIP_DISPLAY_FULLSCREEN; 851 s->logo.mem = (char *)fbbase; 852 s->logo.width = DRM_ROCKCHIP_FB_WIDTH; 853 s->logo.height = DRM_ROCKCHIP_FB_HEIGHT; 854 s->logo.bpp = 32; 855 s->logo.ymirror = 0; 856 857 display_logo(s); 858 } 859 } 860 861 void rockchip_show_bmp(const char *bmp) 862 { 863 struct display_state *s; 864 865 if (!bmp) { 866 list_for_each_entry(s, &rockchip_display_list, head) 867 display_disable(s); 868 return; 869 } 870 871 list_for_each_entry(s, &rockchip_display_list, head) { 872 s->logo.mode = s->charge_logo_mode; 873 if (load_bmp_logo(&s->logo, bmp)) 874 continue; 875 display_logo(s); 876 } 877 } 878 879 void rockchip_show_logo(void) 880 { 881 struct display_state *s; 882 883 list_for_each_entry(s, &rockchip_display_list, head) { 884 s->logo.mode = s->logo_mode; 885 if (load_bmp_logo(&s->logo, s->ulogo_name)) 886 printf("failed to display uboot logo\n"); 887 else 888 display_logo(s); 889 if (load_bmp_logo(&s->logo, s->klogo_name)) 890 printf("failed to display kernel logo\n"); 891 } 892 } 893 894 static int rockchip_display_probe(struct udevice *dev) 895 { 896 struct video_priv *uc_priv = dev_get_uclass_priv(dev); 897 struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); 898 const void *blob = gd->fdt_blob; 899 int phandle; 900 struct udevice *crtc_dev, *conn_dev; 901 const struct rockchip_crtc *crtc; 902 const struct rockchip_connector *conn; 903 struct display_state *s; 904 const char *name; 905 int ret; 906 ofnode node, route_node; 907 struct device_node *port_node, *vop_node, *ep_node; 908 struct device_node *cnt_node, *p; 909 910 /* Before relocation we don't need to do anything */ 911 if (!(gd->flags & GD_FLG_RELOC)) 912 return 0; 913 init_display_buffer(plat->base); 914 915 route_node = dev_read_subnode(dev, "route"); 916 if (!ofnode_valid(route_node)) 917 return -ENODEV; 918 919 ofnode_for_each_subnode(node, route_node) { 920 if (!ofnode_is_available(node)) 921 continue; 922 phandle = ofnode_read_u32_default(node, "connect", -1); 923 if (phandle < 0) { 924 printf("Warn: can't find connect node's handle\n"); 925 continue; 926 } 927 ep_node = of_find_node_by_phandle(phandle); 928 if (!ofnode_valid(np_to_ofnode(ep_node))) { 929 printf("Warn: can't find endpoint node from phandle\n"); 930 continue; 931 } 932 port_node = of_get_parent(ep_node); 933 if (!ofnode_valid(np_to_ofnode(port_node))) { 934 printf("Warn: can't find port node from phandle\n"); 935 continue; 936 } 937 vop_node = of_get_parent(port_node); 938 if (!ofnode_valid(np_to_ofnode(vop_node))) { 939 printf("Warn: can't find crtc node from phandle\n"); 940 continue; 941 } 942 ret = uclass_get_device_by_ofnode(UCLASS_VIDEO_CRTC, 943 np_to_ofnode(vop_node), 944 &crtc_dev); 945 if (ret) { 946 printf("Warn: can't find crtc driver %d\n", ret); 947 continue; 948 } 949 crtc = (const struct rockchip_crtc *)dev_get_driver_data(crtc_dev); 950 951 phandle = ofnode_read_u32_default(np_to_ofnode(ep_node), 952 "remote-endpoint", -1); 953 cnt_node = of_find_node_by_phandle(phandle); 954 if (phandle < 0) { 955 printf("Warn: can't find remote-endpoint's handle\n"); 956 continue; 957 } 958 while (cnt_node->parent){ 959 p = of_get_parent(cnt_node); 960 if (!strcmp(p->full_name, "/")) 961 break; 962 cnt_node = p; 963 } 964 if (!of_device_is_available(cnt_node)) 965 continue; 966 ret = uclass_get_device_by_ofnode(UCLASS_DISPLAY, 967 np_to_ofnode(cnt_node), 968 &conn_dev); 969 if (ret) { 970 printf("Warn: can't find connect driver\n"); 971 continue; 972 } 973 conn = (const struct rockchip_connector *)dev_get_driver_data(conn_dev); 974 975 s = malloc(sizeof(*s)); 976 if (!s) 977 continue; 978 979 memset(s, 0, sizeof(*s)); 980 981 INIT_LIST_HEAD(&s->head); 982 ret = ofnode_read_string_index(node, "logo,uboot", 0, &s->ulogo_name); 983 ret = ofnode_read_string_index(node, "logo,kernel", 0, &s->klogo_name); 984 ret = ofnode_read_string_index(node, "logo,mode", 0, &name); 985 if (!strcmp(name, "fullscreen")) 986 s->logo_mode = ROCKCHIP_DISPLAY_FULLSCREEN; 987 else 988 s->logo_mode = ROCKCHIP_DISPLAY_CENTER; 989 ret = ofnode_read_string_index(node, "charge_logo,mode", 0, &name); 990 if (!strcmp(name, "fullscreen")) 991 s->charge_logo_mode = ROCKCHIP_DISPLAY_FULLSCREEN; 992 else 993 s->charge_logo_mode = ROCKCHIP_DISPLAY_CENTER; 994 995 s->blob = blob; 996 s->conn_state.node = np_to_ofnode(cnt_node); 997 s->conn_state.dev = conn_dev; 998 s->conn_state.connector = conn; 999 s->conn_state.overscan.left_margin = 100; 1000 s->conn_state.overscan.right_margin = 100; 1001 s->conn_state.overscan.top_margin = 100; 1002 s->conn_state.overscan.bottom_margin = 100; 1003 s->crtc_state.node = np_to_ofnode(vop_node); 1004 s->crtc_state.dev = crtc_dev; 1005 s->crtc_state.crtc = crtc; 1006 s->crtc_state.crtc_id = get_crtc_id(np_to_ofnode(ep_node)); 1007 s->node = node; 1008 1009 if (connector_panel_init(s)) { 1010 printf("Warn: Failed to init panel drivers\n"); 1011 free(s); 1012 continue; 1013 } 1014 1015 if (connector_phy_init(s)) { 1016 printf("Warn: Failed to init phy drivers\n"); 1017 free(s); 1018 continue; 1019 } 1020 list_add_tail(&s->head, &rockchip_display_list); 1021 1022 } 1023 1024 if (list_empty(&rockchip_display_list)) { 1025 printf("Failed to found available display route\n"); 1026 return -ENODEV; 1027 } 1028 1029 uc_priv->xsize = DRM_ROCKCHIP_FB_WIDTH; 1030 uc_priv->ysize = DRM_ROCKCHIP_FB_HEIGHT; 1031 uc_priv->bpix = VIDEO_BPP32; 1032 1033 #ifdef CONFIG_DRM_ROCKCHIP_VIDEO_FRAMEBUFFER 1034 rockchip_show_fbbase(plat->base); 1035 video_set_flush_dcache(dev, true); 1036 #endif 1037 1038 return 0; 1039 } 1040 1041 void rockchip_display_fixup(void *blob) 1042 { 1043 const struct rockchip_connector_funcs *conn_funcs; 1044 const struct rockchip_crtc_funcs *crtc_funcs; 1045 const struct rockchip_connector *conn; 1046 const struct rockchip_crtc *crtc; 1047 struct display_state *s; 1048 u32 offset; 1049 const struct device_node *np; 1050 const char *path; 1051 1052 if (!get_display_size()) 1053 return; 1054 1055 offset = fdt_update_reserved_memory(blob, "rockchip,drm-logo", 1056 (u64)memory_start, 1057 (u64)get_display_size()); 1058 if (offset < 0) { 1059 printf("failed to add drm-loader-logo memory\n"); 1060 return; 1061 } 1062 1063 list_for_each_entry(s, &rockchip_display_list, head) { 1064 conn = s->conn_state.connector; 1065 if (!conn) 1066 continue; 1067 conn_funcs = conn->funcs; 1068 if (!conn_funcs) { 1069 printf("failed to get exist connector\n"); 1070 continue; 1071 } 1072 1073 crtc = s->crtc_state.crtc; 1074 if (!crtc) 1075 continue; 1076 1077 crtc_funcs = crtc->funcs; 1078 if (!crtc_funcs) { 1079 printf("failed to get exist crtc\n"); 1080 continue; 1081 } 1082 1083 if (crtc_funcs->fixup_dts) 1084 crtc_funcs->fixup_dts(s, blob); 1085 1086 if (conn_funcs->fixup_dts) 1087 conn_funcs->fixup_dts(s, blob); 1088 1089 np = ofnode_to_np(s->node); 1090 path = np->full_name; 1091 fdt_increase_size(blob, 0x400); 1092 #define FDT_SET_U32(name, val) \ 1093 do_fixup_by_path_u32(blob, path, name, val, 1); 1094 1095 offset = s->logo.offset + (u32)(unsigned long)s->logo.mem 1096 - memory_start; 1097 FDT_SET_U32("logo,offset", offset); 1098 FDT_SET_U32("logo,width", s->logo.width); 1099 FDT_SET_U32("logo,height", s->logo.height); 1100 FDT_SET_U32("logo,bpp", s->logo.bpp); 1101 FDT_SET_U32("logo,ymirror", s->logo.ymirror); 1102 FDT_SET_U32("video,hdisplay", s->conn_state.mode.hdisplay); 1103 FDT_SET_U32("video,vdisplay", s->conn_state.mode.vdisplay); 1104 FDT_SET_U32("video,crtc_hsync_end", s->conn_state.mode.crtc_hsync_end); 1105 FDT_SET_U32("video,crtc_vsync_end", s->conn_state.mode.crtc_vsync_end); 1106 FDT_SET_U32("video,vrefresh", 1107 drm_mode_vrefresh(&s->conn_state.mode)); 1108 FDT_SET_U32("video,flags", s->conn_state.mode.flags); 1109 FDT_SET_U32("overscan,left_margin", s->conn_state.overscan.left_margin); 1110 FDT_SET_U32("overscan,right_margin", s->conn_state.overscan.right_margin); 1111 FDT_SET_U32("overscan,top_margin", s->conn_state.overscan.top_margin); 1112 FDT_SET_U32("overscan,bottom_margin", s->conn_state.overscan.bottom_margin); 1113 #undef FDT_SET_U32 1114 } 1115 } 1116 1117 int rockchip_display_bind(struct udevice *dev) 1118 { 1119 struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); 1120 1121 plat->size = DRM_ROCKCHIP_FB_SIZE + MEMORY_POOL_SIZE; 1122 1123 return 0; 1124 } 1125 1126 static const struct udevice_id rockchip_display_ids[] = { 1127 { .compatible = "rockchip,display-subsystem" }, 1128 { } 1129 }; 1130 1131 U_BOOT_DRIVER(rockchip_display) = { 1132 .name = "rockchip_display", 1133 .id = UCLASS_VIDEO, 1134 .of_match = rockchip_display_ids, 1135 .bind = rockchip_display_bind, 1136 .probe = rockchip_display_probe, 1137 }; 1138 1139 static int do_rockchip_logo_show(cmd_tbl_t *cmdtp, int flag, int argc, 1140 char *const argv[]) 1141 { 1142 if (argc != 1) 1143 return CMD_RET_USAGE; 1144 1145 rockchip_show_logo(); 1146 1147 return 0; 1148 } 1149 1150 static int do_rockchip_show_bmp(cmd_tbl_t *cmdtp, int flag, int argc, 1151 char *const argv[]) 1152 { 1153 if (argc != 2) 1154 return CMD_RET_USAGE; 1155 1156 rockchip_show_bmp(argv[1]); 1157 1158 return 0; 1159 } 1160 1161 U_BOOT_CMD( 1162 rockchip_show_logo, 1, 1, do_rockchip_logo_show, 1163 "load and display log from resource partition", 1164 NULL 1165 ); 1166 1167 U_BOOT_CMD( 1168 rockchip_show_bmp, 2, 1, do_rockchip_show_bmp, 1169 "load and display bmp from resource partition", 1170 " <bmp_name>" 1171 ); 1172