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