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 if (panel->funcs && panel->funcs->init) { 203 ret = panel->funcs->init(state); 204 if (ret) { 205 printf("failed to init panel driver\n"); 206 return ret; 207 } 208 } 209 210 dsp_lut_node = dev_read_subnode(dev, "dsp-lut"); 211 if (!ofnode_valid(dsp_lut_node)) { 212 debug("%s can not find dsp-lut node\n", __func__); 213 return 0; 214 } 215 216 ofnode_get_property(dsp_lut_node, "gamma-lut", &len); 217 if (len > 0) { 218 conn_state->gamma.size = len / sizeof(u32); 219 conn_state->gamma.lut = malloc(len); 220 if (!conn_state->gamma.lut) { 221 printf("malloc gamma lut failed\n"); 222 return -ENOMEM; 223 } 224 ret = ofnode_read_u32_array(dsp_lut_node, "gamma-lut", 225 conn_state->gamma.lut, 226 conn_state->gamma.size); 227 if (ret) { 228 printf("Cannot decode gamma_lut\n"); 229 conn_state->gamma.lut = NULL; 230 return -EINVAL; 231 } 232 panel_state->dsp_lut_node = dsp_lut_node; 233 } 234 235 return 0; 236 } 237 238 int drm_mode_vrefresh(const struct drm_display_mode *mode) 239 { 240 int refresh = 0; 241 unsigned int calc_val; 242 243 if (mode->vrefresh > 0) { 244 refresh = mode->vrefresh; 245 } else if (mode->htotal > 0 && mode->vtotal > 0) { 246 int vtotal; 247 248 vtotal = mode->vtotal; 249 /* work out vrefresh the value will be x1000 */ 250 calc_val = (mode->clock * 1000); 251 calc_val /= mode->htotal; 252 refresh = (calc_val + vtotal / 2) / vtotal; 253 254 if (mode->flags & DRM_MODE_FLAG_INTERLACE) 255 refresh *= 2; 256 if (mode->flags & DRM_MODE_FLAG_DBLSCAN) 257 refresh /= 2; 258 if (mode->vscan > 1) 259 refresh /= mode->vscan; 260 } 261 return refresh; 262 } 263 264 static int display_get_timing_from_dts(struct panel_state *panel_state, 265 struct drm_display_mode *mode) 266 { 267 int phandle; 268 int hactive, vactive, pixelclock; 269 int hfront_porch, hback_porch, hsync_len; 270 int vfront_porch, vback_porch, vsync_len; 271 int val, flags = 0; 272 ofnode timing, native_mode; 273 274 timing = dev_read_subnode(panel_state->dev, "display-timings"); 275 if (!ofnode_valid(timing)) 276 return -ENODEV; 277 278 native_mode = ofnode_find_subnode(timing, "timing"); 279 if (!ofnode_valid(native_mode)) { 280 phandle = ofnode_read_u32_default(timing, "native-mode", -1); 281 native_mode = np_to_ofnode(of_find_node_by_phandle(phandle)); 282 if (!ofnode_valid(native_mode)) { 283 printf("failed to get display timings from DT\n"); 284 return -ENXIO; 285 } 286 } 287 288 #define FDT_GET_INT(val, name) \ 289 val = ofnode_read_s32_default(native_mode, name, -1); \ 290 if (val < 0) { \ 291 printf("Can't get %s\n", name); \ 292 return -ENXIO; \ 293 } 294 295 FDT_GET_INT(hactive, "hactive"); 296 FDT_GET_INT(vactive, "vactive"); 297 FDT_GET_INT(pixelclock, "clock-frequency"); 298 FDT_GET_INT(hsync_len, "hsync-len"); 299 FDT_GET_INT(hfront_porch, "hfront-porch"); 300 FDT_GET_INT(hback_porch, "hback-porch"); 301 FDT_GET_INT(vsync_len, "vsync-len"); 302 FDT_GET_INT(vfront_porch, "vfront-porch"); 303 FDT_GET_INT(vback_porch, "vback-porch"); 304 FDT_GET_INT(val, "hsync-active"); 305 flags |= val ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; 306 FDT_GET_INT(val, "vsync-active"); 307 flags |= val ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; 308 FDT_GET_INT(val, "pixelclk-active"); 309 flags |= val ? DRM_MODE_FLAG_PPIXDATA : 0; 310 311 mode->hdisplay = hactive; 312 mode->hsync_start = mode->hdisplay + hfront_porch; 313 mode->hsync_end = mode->hsync_start + hsync_len; 314 mode->htotal = mode->hsync_end + hback_porch; 315 316 mode->vdisplay = vactive; 317 mode->vsync_start = mode->vdisplay + vfront_porch; 318 mode->vsync_end = mode->vsync_start + vsync_len; 319 mode->vtotal = mode->vsync_end + vback_porch; 320 321 mode->clock = pixelclock / 1000; 322 mode->flags = flags; 323 324 return 0; 325 } 326 327 /** 328 * drm_mode_set_crtcinfo - set CRTC modesetting timing parameters 329 * @p: mode 330 * @adjust_flags: a combination of adjustment flags 331 * 332 * Setup the CRTC modesetting timing parameters for @p, adjusting if necessary. 333 * 334 * - The CRTC_INTERLACE_HALVE_V flag can be used to halve vertical timings of 335 * interlaced modes. 336 * - The CRTC_STEREO_DOUBLE flag can be used to compute the timings for 337 * buffers containing two eyes (only adjust the timings when needed, eg. for 338 * "frame packing" or "side by side full"). 339 * - The CRTC_NO_DBLSCAN and CRTC_NO_VSCAN flags request that adjustment *not* 340 * be performed for doublescan and vscan > 1 modes respectively. 341 */ 342 void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) 343 { 344 if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN)) 345 return; 346 347 if (p->flags & DRM_MODE_FLAG_DBLCLK) 348 p->crtc_clock = 2 * p->clock; 349 else 350 p->crtc_clock = p->clock; 351 p->crtc_hdisplay = p->hdisplay; 352 p->crtc_hsync_start = p->hsync_start; 353 p->crtc_hsync_end = p->hsync_end; 354 p->crtc_htotal = p->htotal; 355 p->crtc_hskew = p->hskew; 356 p->crtc_vdisplay = p->vdisplay; 357 p->crtc_vsync_start = p->vsync_start; 358 p->crtc_vsync_end = p->vsync_end; 359 p->crtc_vtotal = p->vtotal; 360 361 if (p->flags & DRM_MODE_FLAG_INTERLACE) { 362 if (adjust_flags & CRTC_INTERLACE_HALVE_V) { 363 p->crtc_vdisplay /= 2; 364 p->crtc_vsync_start /= 2; 365 p->crtc_vsync_end /= 2; 366 p->crtc_vtotal /= 2; 367 } 368 } 369 370 if (!(adjust_flags & CRTC_NO_DBLSCAN)) { 371 if (p->flags & DRM_MODE_FLAG_DBLSCAN) { 372 p->crtc_vdisplay *= 2; 373 p->crtc_vsync_start *= 2; 374 p->crtc_vsync_end *= 2; 375 p->crtc_vtotal *= 2; 376 } 377 } 378 379 if (!(adjust_flags & CRTC_NO_VSCAN)) { 380 if (p->vscan > 1) { 381 p->crtc_vdisplay *= p->vscan; 382 p->crtc_vsync_start *= p->vscan; 383 p->crtc_vsync_end *= p->vscan; 384 p->crtc_vtotal *= p->vscan; 385 } 386 } 387 388 if (adjust_flags & CRTC_STEREO_DOUBLE) { 389 unsigned int layout = p->flags & DRM_MODE_FLAG_3D_MASK; 390 391 switch (layout) { 392 case DRM_MODE_FLAG_3D_FRAME_PACKING: 393 p->crtc_clock *= 2; 394 p->crtc_vdisplay += p->crtc_vtotal; 395 p->crtc_vsync_start += p->crtc_vtotal; 396 p->crtc_vsync_end += p->crtc_vtotal; 397 p->crtc_vtotal += p->crtc_vtotal; 398 break; 399 } 400 } 401 402 p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay); 403 p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal); 404 p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay); 405 p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal); 406 } 407 408 static int display_get_timing(struct display_state *state) 409 { 410 struct connector_state *conn_state = &state->conn_state; 411 const struct rockchip_connector *conn = conn_state->connector; 412 const struct rockchip_connector_funcs *conn_funcs = conn->funcs; 413 struct drm_display_mode *mode = &conn_state->mode; 414 const struct drm_display_mode *m; 415 struct panel_state *panel_state = &state->panel_state; 416 const struct rockchip_panel *panel = panel_state->panel; 417 const struct rockchip_panel_funcs *panel_funcs = panel->funcs; 418 ofnode panel_node = panel_state->node; 419 int ret; 420 421 if (ofnode_valid(panel_node) && !display_get_timing_from_dts(panel_state, mode)) { 422 printf("Using display timing dts\n"); 423 goto done; 424 } 425 426 if (panel->data) { 427 m = (const struct drm_display_mode *)panel->data; 428 memcpy(mode, m, sizeof(*m)); 429 printf("Using display timing from compatible panel driver\n"); 430 goto done; 431 } 432 433 if (conn_funcs->get_edid && !conn_funcs->get_edid(state)) { 434 int panel_bits_per_colourp; 435 436 /* In order to read EDID, the panel needs to be powered on */ 437 if (panel_funcs->prepare) { 438 ret = panel_funcs->prepare(state); 439 if (ret) { 440 printf("failed to prepare panel\n"); 441 return ret; 442 } 443 } 444 445 if (!edid_get_drm_mode((void *)&conn_state->edid, 446 sizeof(conn_state->edid), mode, 447 &panel_bits_per_colourp)) { 448 printf("Using display timing from edid\n"); 449 edid_print_info((void *)&conn_state->edid); 450 goto done; 451 } else { 452 if (panel_funcs->unprepare) 453 panel_funcs->unprepare(state); 454 } 455 } 456 457 printf("failed to find display timing\n"); 458 return -ENODEV; 459 done: 460 printf("Detailed mode clock %u kHz, flags[%x]\n" 461 " H: %04d %04d %04d %04d\n" 462 " V: %04d %04d %04d %04d\n" 463 "bus_format: %x\n", 464 mode->clock, mode->flags, 465 mode->hdisplay, mode->hsync_start, 466 mode->hsync_end, mode->htotal, 467 mode->vdisplay, mode->vsync_start, 468 mode->vsync_end, mode->vtotal, 469 conn_state->bus_format); 470 471 return 0; 472 } 473 474 static int display_init(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 struct drm_display_mode *mode = &conn_state->mode; 483 int ret = 0; 484 static bool __print_once = false; 485 486 if (!__print_once) { 487 __print_once = true; 488 printf("Rockchip UBOOT DRM driver version: %s\n", DRIVER_VERSION); 489 } 490 491 if (state->is_init) 492 return 0; 493 494 if (!conn_funcs || !crtc_funcs) { 495 printf("failed to find connector or crtc functions\n"); 496 return -ENXIO; 497 } 498 499 if (conn_funcs->init) { 500 ret = conn_funcs->init(state); 501 if (ret) 502 goto deinit; 503 } 504 /* 505 * support hotplug, but not connect; 506 */ 507 if (conn_funcs->detect) { 508 ret = conn_funcs->detect(state); 509 if (!ret) 510 goto deinit; 511 } 512 513 if (conn_funcs->get_timing) { 514 ret = conn_funcs->get_timing(state); 515 if (ret) 516 goto deinit; 517 } else { 518 ret = display_get_timing(state); 519 if (ret) 520 goto deinit; 521 } 522 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); 523 524 if (crtc_funcs->init) { 525 ret = crtc_funcs->init(state); 526 if (ret) 527 goto deinit; 528 } 529 530 state->is_init = 1; 531 532 return 0; 533 534 deinit: 535 if (conn_funcs->deinit) 536 conn_funcs->deinit(state); 537 return ret; 538 } 539 540 int display_send_mcu_cmd(struct display_state *state, u32 type, u32 val) 541 { 542 struct crtc_state *crtc_state = &state->crtc_state; 543 const struct rockchip_crtc *crtc = crtc_state->crtc; 544 const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs; 545 int ret; 546 547 if (!state->is_init) 548 return -EINVAL; 549 550 if (crtc_funcs->send_mcu_cmd) { 551 ret = crtc_funcs->send_mcu_cmd(state, type, val); 552 if (ret) 553 return ret; 554 } 555 556 return 0; 557 } 558 559 static int display_set_plane(struct display_state *state) 560 { 561 struct crtc_state *crtc_state = &state->crtc_state; 562 const struct rockchip_crtc *crtc = crtc_state->crtc; 563 const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs; 564 int ret; 565 566 if (!state->is_init) 567 return -EINVAL; 568 569 if (crtc_funcs->set_plane) { 570 ret = crtc_funcs->set_plane(state); 571 if (ret) 572 return ret; 573 } 574 575 return 0; 576 } 577 578 static int display_panel_prepare(struct display_state *state) 579 { 580 struct panel_state *panel_state = &state->panel_state; 581 const struct rockchip_panel *panel = panel_state->panel; 582 583 if (!panel || !panel->funcs || !panel->funcs->prepare) { 584 printf("%s: failed to find panel prepare funcs\n", __func__); 585 return -ENODEV; 586 } 587 588 return panel->funcs->prepare(state); 589 } 590 591 static int display_panel_enable(struct display_state *state) 592 { 593 struct panel_state *panel_state = &state->panel_state; 594 const struct rockchip_panel *panel = panel_state->panel; 595 596 if (!panel || !panel->funcs || !panel->funcs->enable) { 597 printf("%s: failed to find panel enable funcs\n", __func__); 598 return -ENODEV; 599 } 600 601 return panel->funcs->enable(state); 602 } 603 604 static void display_panel_unprepare(struct display_state *state) 605 { 606 struct panel_state *panel_state = &state->panel_state; 607 const struct rockchip_panel *panel = panel_state->panel; 608 609 if (!panel || !panel->funcs || !panel->funcs->unprepare) { 610 printf("%s: failed to find panel unprepare funcs\n", __func__); 611 return; 612 } 613 614 panel->funcs->unprepare(state); 615 } 616 617 static void display_panel_disable(struct display_state *state) 618 { 619 struct panel_state *panel_state = &state->panel_state; 620 const struct rockchip_panel *panel = panel_state->panel; 621 622 if (!panel || !panel->funcs || !panel->funcs->disable) { 623 printf("%s: failed to find panel disable funcs\n", __func__); 624 return; 625 } 626 627 panel->funcs->disable(state); 628 } 629 630 static int display_enable(struct display_state *state) 631 { 632 struct connector_state *conn_state = &state->conn_state; 633 const struct rockchip_connector *conn = conn_state->connector; 634 const struct rockchip_connector_funcs *conn_funcs = conn->funcs; 635 struct crtc_state *crtc_state = &state->crtc_state; 636 const struct rockchip_crtc *crtc = crtc_state->crtc; 637 const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs; 638 int ret = 0; 639 640 display_init(state); 641 642 if (!state->is_init) 643 return -EINVAL; 644 645 if (state->is_enable) 646 return 0; 647 648 if (crtc_funcs->prepare) { 649 ret = crtc_funcs->prepare(state); 650 if (ret) 651 return ret; 652 } 653 654 if (conn_funcs->prepare) { 655 ret = conn_funcs->prepare(state); 656 if (ret) 657 goto unprepare_crtc; 658 } 659 660 display_panel_prepare(state); 661 662 if (crtc_funcs->enable) { 663 ret = crtc_funcs->enable(state); 664 if (ret) 665 goto unprepare_conn; 666 } 667 668 if (conn_funcs->enable) { 669 ret = conn_funcs->enable(state); 670 if (ret) 671 goto disable_crtc; 672 } 673 674 display_panel_enable(state); 675 676 state->is_enable = true; 677 return 0; 678 679 disable_crtc: 680 if (crtc_funcs->disable) 681 crtc_funcs->disable(state); 682 unprepare_conn: 683 if (conn_funcs->unprepare) 684 conn_funcs->unprepare(state); 685 unprepare_crtc: 686 if (crtc_funcs->unprepare) 687 crtc_funcs->unprepare(state); 688 return ret; 689 } 690 691 static int display_disable(struct display_state *state) 692 { 693 struct connector_state *conn_state = &state->conn_state; 694 const struct rockchip_connector *conn = conn_state->connector; 695 const struct rockchip_connector_funcs *conn_funcs = conn->funcs; 696 struct crtc_state *crtc_state = &state->crtc_state; 697 const struct rockchip_crtc *crtc = crtc_state->crtc; 698 const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs; 699 700 if (!state->is_init) 701 return 0; 702 703 if (!state->is_enable) 704 return 0; 705 706 display_panel_disable(state); 707 708 if (crtc_funcs->disable) 709 crtc_funcs->disable(state); 710 711 if (conn_funcs->disable) 712 conn_funcs->disable(state); 713 714 display_panel_unprepare(state); 715 716 if (conn_funcs->unprepare) 717 conn_funcs->unprepare(state); 718 719 state->is_enable = 0; 720 state->is_init = 0; 721 722 return 0; 723 } 724 725 static int display_logo(struct display_state *state) 726 { 727 struct crtc_state *crtc_state = &state->crtc_state; 728 struct connector_state *conn_state = &state->conn_state; 729 struct logo_info *logo = &state->logo; 730 int hdisplay, vdisplay; 731 732 display_init(state); 733 if (!state->is_init) 734 return -ENODEV; 735 736 switch (logo->bpp) { 737 case 16: 738 crtc_state->format = ROCKCHIP_FMT_RGB565; 739 break; 740 case 24: 741 crtc_state->format = ROCKCHIP_FMT_RGB888; 742 break; 743 case 32: 744 crtc_state->format = ROCKCHIP_FMT_ARGB8888; 745 break; 746 default: 747 printf("can't support bmp bits[%d]\n", logo->bpp); 748 return -EINVAL; 749 } 750 crtc_state->rb_swap = logo->bpp != 32; 751 hdisplay = conn_state->mode.hdisplay; 752 vdisplay = conn_state->mode.vdisplay; 753 crtc_state->src_w = logo->width; 754 crtc_state->src_h = logo->height; 755 crtc_state->src_x = 0; 756 crtc_state->src_y = 0; 757 crtc_state->ymirror = logo->ymirror; 758 759 crtc_state->dma_addr = (u32)(unsigned long)logo->mem + logo->offset; 760 crtc_state->xvir = ALIGN(crtc_state->src_w * logo->bpp, 32) >> 5; 761 762 if (logo->mode == ROCKCHIP_DISPLAY_FULLSCREEN) { 763 crtc_state->crtc_x = 0; 764 crtc_state->crtc_y = 0; 765 crtc_state->crtc_w = hdisplay; 766 crtc_state->crtc_h = vdisplay; 767 } else { 768 if (crtc_state->src_w >= hdisplay) { 769 crtc_state->crtc_x = 0; 770 crtc_state->crtc_w = hdisplay; 771 } else { 772 crtc_state->crtc_x = (hdisplay - crtc_state->src_w) / 2; 773 crtc_state->crtc_w = crtc_state->src_w; 774 } 775 776 if (crtc_state->src_h >= vdisplay) { 777 crtc_state->crtc_y = 0; 778 crtc_state->crtc_h = vdisplay; 779 } else { 780 crtc_state->crtc_y = (vdisplay - crtc_state->src_h) / 2; 781 crtc_state->crtc_h = crtc_state->src_h; 782 } 783 } 784 785 display_set_plane(state); 786 display_enable(state); 787 788 return 0; 789 } 790 791 static int get_crtc_id(ofnode connect) 792 { 793 int phandle; 794 struct device_node *remote; 795 int val; 796 797 phandle = ofnode_read_u32_default(connect, "remote-endpoint", -1); 798 if (phandle < 0) 799 goto err; 800 remote = of_find_node_by_phandle(phandle); 801 val = ofnode_read_u32_default(np_to_ofnode(remote), "reg", -1); 802 if (val < 0) 803 goto err; 804 805 return val; 806 err: 807 printf("Can't get crtc id, default set to id = 0\n"); 808 return 0; 809 } 810 811 static int get_crtc_mcu_mode(struct crtc_state *crtc_state) 812 { 813 ofnode mcu_node; 814 int total_pixel, cs_pst, cs_pend, rw_pst, rw_pend; 815 816 mcu_node = dev_read_subnode(crtc_state->dev, "mcu-timing"); 817 818 #define FDT_GET_MCU_INT(val, name) \ 819 do { \ 820 val = ofnode_read_s32_default(mcu_node, name, -1); \ 821 if (val < 0) { \ 822 printf("Can't get %s\n", name); \ 823 return -ENXIO; \ 824 } \ 825 } while (0) 826 827 FDT_GET_MCU_INT(total_pixel, "mcu-pix-total"); 828 FDT_GET_MCU_INT(cs_pst, "mcu-cs-pst"); 829 FDT_GET_MCU_INT(cs_pend, "mcu-cs-pend"); 830 FDT_GET_MCU_INT(rw_pst, "mcu-rw-pst"); 831 FDT_GET_MCU_INT(rw_pend, "mcu-rw-pend"); 832 833 crtc_state->mcu_timing.mcu_pix_total = total_pixel; 834 crtc_state->mcu_timing.mcu_cs_pst = cs_pst; 835 crtc_state->mcu_timing.mcu_cs_pend = cs_pend; 836 crtc_state->mcu_timing.mcu_rw_pst = rw_pst; 837 crtc_state->mcu_timing.mcu_rw_pend = rw_pend; 838 839 return 0; 840 } 841 842 struct rockchip_logo_cache *find_or_alloc_logo_cache(const char *bmp) 843 { 844 struct rockchip_logo_cache *tmp, *logo_cache = NULL; 845 846 list_for_each_entry(tmp, &logo_cache_list, head) { 847 if (!strcmp(tmp->name, bmp)) { 848 logo_cache = tmp; 849 break; 850 } 851 } 852 853 if (!logo_cache) { 854 logo_cache = malloc(sizeof(*logo_cache)); 855 if (!logo_cache) { 856 printf("failed to alloc memory for logo cache\n"); 857 return NULL; 858 } 859 memset(logo_cache, 0, sizeof(*logo_cache)); 860 strcpy(logo_cache->name, bmp); 861 INIT_LIST_HEAD(&logo_cache->head); 862 list_add_tail(&logo_cache->head, &logo_cache_list); 863 } 864 865 return logo_cache; 866 } 867 868 /* Note: used only for rkfb kernel driver */ 869 static int load_kernel_bmp_logo(struct logo_info *logo, const char *bmp_name) 870 { 871 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE 872 void *dst = NULL; 873 int len, size; 874 struct bmp_header *header; 875 876 if (!logo || !bmp_name) 877 return -EINVAL; 878 879 header = malloc(RK_BLK_SIZE); 880 if (!header) 881 return -ENOMEM; 882 883 len = rockchip_read_resource_file(header, bmp_name, 0, RK_BLK_SIZE); 884 if (len != RK_BLK_SIZE) { 885 free(header); 886 return -EINVAL; 887 } 888 size = get_unaligned_le32(&header->file_size); 889 dst = (void *)(memory_start + MEMORY_POOL_SIZE / 2); 890 len = rockchip_read_resource_file(dst, bmp_name, 0, size); 891 if (len != size) { 892 printf("failed to load bmp %s\n", bmp_name); 893 free(header); 894 return -ENOENT; 895 } 896 897 logo->mem = dst; 898 899 return 0; 900 #endif 901 } 902 903 static int load_bmp_logo(struct logo_info *logo, const char *bmp_name) 904 { 905 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE 906 struct rockchip_logo_cache *logo_cache; 907 struct bmp_header *header; 908 void *dst = NULL, *pdst; 909 int size, len; 910 int ret = 0; 911 912 if (!logo || !bmp_name) 913 return -EINVAL; 914 logo_cache = find_or_alloc_logo_cache(bmp_name); 915 if (!logo_cache) 916 return -ENOMEM; 917 918 if (logo_cache->logo.mem) { 919 memcpy(logo, &logo_cache->logo, sizeof(*logo)); 920 return 0; 921 } 922 923 header = malloc(RK_BLK_SIZE); 924 if (!header) 925 return -ENOMEM; 926 927 len = rockchip_read_resource_file(header, bmp_name, 0, RK_BLK_SIZE); 928 if (len != RK_BLK_SIZE) { 929 ret = -EINVAL; 930 goto free_header; 931 } 932 933 logo->bpp = get_unaligned_le16(&header->bit_count); 934 logo->width = get_unaligned_le32(&header->width); 935 logo->height = get_unaligned_le32(&header->height); 936 size = get_unaligned_le32(&header->file_size); 937 if (!can_direct_logo(logo->bpp)) { 938 if (size > MEMORY_POOL_SIZE) { 939 printf("failed to use boot buf as temp bmp buffer\n"); 940 ret = -ENOMEM; 941 goto free_header; 942 } 943 pdst = get_display_buffer(size); 944 945 } else { 946 pdst = get_display_buffer(size); 947 dst = pdst; 948 } 949 950 len = rockchip_read_resource_file(pdst, bmp_name, 0, size); 951 if (len != size) { 952 printf("failed to load bmp %s\n", bmp_name); 953 ret = -ENOENT; 954 goto free_header; 955 } 956 957 if (!can_direct_logo(logo->bpp)) { 958 int dst_size; 959 /* 960 * TODO: force use 16bpp if bpp less than 16; 961 */ 962 logo->bpp = (logo->bpp <= 16) ? 16 : logo->bpp; 963 dst_size = logo->width * logo->height * logo->bpp >> 3; 964 965 dst = get_display_buffer(dst_size); 966 if (!dst) { 967 ret = -ENOMEM; 968 goto free_header; 969 } 970 if (bmpdecoder(pdst, dst, logo->bpp)) { 971 printf("failed to decode bmp %s\n", bmp_name); 972 ret = -EINVAL; 973 goto free_header; 974 } 975 flush_dcache_range((ulong)dst, 976 ALIGN((ulong)dst + dst_size, 977 CONFIG_SYS_CACHELINE_SIZE)); 978 979 logo->offset = 0; 980 logo->ymirror = 0; 981 } else { 982 logo->offset = get_unaligned_le32(&header->data_offset); 983 logo->ymirror = 1; 984 } 985 logo->mem = dst; 986 987 memcpy(&logo_cache->logo, logo, sizeof(*logo)); 988 989 free_header: 990 991 free(header); 992 993 return ret; 994 #else 995 return -EINVAL; 996 #endif 997 } 998 999 void rockchip_show_fbbase(ulong fbbase) 1000 { 1001 struct display_state *s; 1002 1003 list_for_each_entry(s, &rockchip_display_list, head) { 1004 s->logo.mode = ROCKCHIP_DISPLAY_FULLSCREEN; 1005 s->logo.mem = (char *)fbbase; 1006 s->logo.width = DRM_ROCKCHIP_FB_WIDTH; 1007 s->logo.height = DRM_ROCKCHIP_FB_HEIGHT; 1008 s->logo.bpp = 32; 1009 s->logo.ymirror = 0; 1010 1011 display_logo(s); 1012 } 1013 } 1014 1015 void rockchip_show_bmp(const char *bmp) 1016 { 1017 struct display_state *s; 1018 1019 if (!bmp) { 1020 list_for_each_entry(s, &rockchip_display_list, head) 1021 display_disable(s); 1022 return; 1023 } 1024 1025 list_for_each_entry(s, &rockchip_display_list, head) { 1026 s->logo.mode = s->charge_logo_mode; 1027 if (load_bmp_logo(&s->logo, bmp)) 1028 continue; 1029 display_logo(s); 1030 } 1031 } 1032 1033 void rockchip_show_logo(void) 1034 { 1035 struct display_state *s; 1036 1037 list_for_each_entry(s, &rockchip_display_list, head) { 1038 s->logo.mode = s->logo_mode; 1039 if (load_bmp_logo(&s->logo, s->ulogo_name)) 1040 printf("failed to display uboot logo\n"); 1041 else 1042 display_logo(s); 1043 1044 /* Load kernel bmp in rockchip_display_fixup() later */ 1045 } 1046 } 1047 1048 static int rockchip_display_probe(struct udevice *dev) 1049 { 1050 struct video_priv *uc_priv = dev_get_uclass_priv(dev); 1051 struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); 1052 const void *blob = gd->fdt_blob; 1053 int phandle; 1054 struct udevice *crtc_dev, *conn_dev; 1055 const struct rockchip_crtc *crtc; 1056 const struct rockchip_connector *conn; 1057 struct display_state *s; 1058 const char *name; 1059 int ret; 1060 ofnode node, route_node; 1061 struct device_node *port_node, *vop_node, *ep_node; 1062 struct device_node *cnt_node, *p; 1063 1064 /* Before relocation we don't need to do anything */ 1065 if (!(gd->flags & GD_FLG_RELOC)) 1066 return 0; 1067 init_display_buffer(plat->base); 1068 1069 route_node = dev_read_subnode(dev, "route"); 1070 if (!ofnode_valid(route_node)) 1071 return -ENODEV; 1072 1073 ofnode_for_each_subnode(node, route_node) { 1074 if (!ofnode_is_available(node)) 1075 continue; 1076 phandle = ofnode_read_u32_default(node, "connect", -1); 1077 if (phandle < 0) { 1078 printf("Warn: can't find connect node's handle\n"); 1079 continue; 1080 } 1081 ep_node = of_find_node_by_phandle(phandle); 1082 if (!ofnode_valid(np_to_ofnode(ep_node))) { 1083 printf("Warn: can't find endpoint node from phandle\n"); 1084 continue; 1085 } 1086 port_node = of_get_parent(ep_node); 1087 if (!ofnode_valid(np_to_ofnode(port_node))) { 1088 printf("Warn: can't find port node from phandle\n"); 1089 continue; 1090 } 1091 vop_node = of_get_parent(port_node); 1092 if (!ofnode_valid(np_to_ofnode(vop_node))) { 1093 printf("Warn: can't find crtc node from phandle\n"); 1094 continue; 1095 } 1096 ret = uclass_get_device_by_ofnode(UCLASS_VIDEO_CRTC, 1097 np_to_ofnode(vop_node), 1098 &crtc_dev); 1099 if (ret) { 1100 printf("Warn: can't find crtc driver %d\n", ret); 1101 continue; 1102 } 1103 crtc = (const struct rockchip_crtc *)dev_get_driver_data(crtc_dev); 1104 1105 phandle = ofnode_read_u32_default(np_to_ofnode(ep_node), 1106 "remote-endpoint", -1); 1107 cnt_node = of_find_node_by_phandle(phandle); 1108 if (phandle < 0) { 1109 printf("Warn: can't find remote-endpoint's handle\n"); 1110 continue; 1111 } 1112 while (cnt_node->parent){ 1113 p = of_get_parent(cnt_node); 1114 if (!strcmp(p->full_name, "/")) 1115 break; 1116 cnt_node = p; 1117 } 1118 if (!of_device_is_available(cnt_node)) 1119 continue; 1120 ret = uclass_get_device_by_ofnode(UCLASS_DISPLAY, 1121 np_to_ofnode(cnt_node), 1122 &conn_dev); 1123 if (ret) { 1124 printf("Warn: can't find connect driver\n"); 1125 continue; 1126 } 1127 conn = (const struct rockchip_connector *)dev_get_driver_data(conn_dev); 1128 1129 s = malloc(sizeof(*s)); 1130 if (!s) 1131 continue; 1132 1133 memset(s, 0, sizeof(*s)); 1134 1135 INIT_LIST_HEAD(&s->head); 1136 ret = ofnode_read_string_index(node, "logo,uboot", 0, &s->ulogo_name); 1137 ret = ofnode_read_string_index(node, "logo,kernel", 0, &s->klogo_name); 1138 ret = ofnode_read_string_index(node, "logo,mode", 0, &name); 1139 if (!strcmp(name, "fullscreen")) 1140 s->logo_mode = ROCKCHIP_DISPLAY_FULLSCREEN; 1141 else 1142 s->logo_mode = ROCKCHIP_DISPLAY_CENTER; 1143 ret = ofnode_read_string_index(node, "charge_logo,mode", 0, &name); 1144 if (!strcmp(name, "fullscreen")) 1145 s->charge_logo_mode = ROCKCHIP_DISPLAY_FULLSCREEN; 1146 else 1147 s->charge_logo_mode = ROCKCHIP_DISPLAY_CENTER; 1148 1149 s->blob = blob; 1150 s->conn_state.node = np_to_ofnode(cnt_node); 1151 s->conn_state.dev = conn_dev; 1152 s->conn_state.connector = conn; 1153 s->conn_state.overscan.left_margin = 100; 1154 s->conn_state.overscan.right_margin = 100; 1155 s->conn_state.overscan.top_margin = 100; 1156 s->conn_state.overscan.bottom_margin = 100; 1157 s->crtc_state.node = np_to_ofnode(vop_node); 1158 s->crtc_state.dev = crtc_dev; 1159 s->crtc_state.crtc = crtc; 1160 s->crtc_state.crtc_id = get_crtc_id(np_to_ofnode(ep_node)); 1161 s->node = node; 1162 get_crtc_mcu_mode(&s->crtc_state); 1163 1164 if (connector_panel_init(s)) { 1165 printf("Warn: Failed to init panel drivers\n"); 1166 free(s); 1167 continue; 1168 } 1169 1170 if (connector_phy_init(s)) { 1171 printf("Warn: Failed to init phy drivers\n"); 1172 free(s); 1173 continue; 1174 } 1175 list_add_tail(&s->head, &rockchip_display_list); 1176 1177 } 1178 1179 if (list_empty(&rockchip_display_list)) { 1180 printf("Failed to found available display route\n"); 1181 return -ENODEV; 1182 } 1183 1184 uc_priv->xsize = DRM_ROCKCHIP_FB_WIDTH; 1185 uc_priv->ysize = DRM_ROCKCHIP_FB_HEIGHT; 1186 uc_priv->bpix = VIDEO_BPP32; 1187 1188 #ifdef CONFIG_DRM_ROCKCHIP_VIDEO_FRAMEBUFFER 1189 rockchip_show_fbbase(plat->base); 1190 video_set_flush_dcache(dev, true); 1191 #endif 1192 1193 return 0; 1194 } 1195 1196 void rockchip_display_fixup(void *blob) 1197 { 1198 const struct rockchip_connector_funcs *conn_funcs; 1199 const struct rockchip_crtc_funcs *crtc_funcs; 1200 const struct rockchip_connector *conn; 1201 const struct rockchip_crtc *crtc; 1202 struct display_state *s; 1203 int offset; 1204 const struct device_node *np; 1205 const char *path; 1206 1207 if (!get_display_size()) 1208 return; 1209 1210 if (fdt_node_offset_by_compatible(blob, 0, "rockchip,drm-logo") >= 0) { 1211 list_for_each_entry(s, &rockchip_display_list, head) 1212 load_bmp_logo(&s->logo, s->klogo_name); 1213 offset = fdt_update_reserved_memory(blob, "rockchip,drm-logo", 1214 (u64)memory_start, 1215 (u64)get_display_size()); 1216 if (offset < 0) 1217 printf("failed to reserve drm-loader-logo memory\n"); 1218 } else { 1219 printf("can't found rockchip,drm-logo, use rockchip,fb-logo\n"); 1220 /* Compatible with rkfb display, only need reserve memory */ 1221 offset = fdt_update_reserved_memory(blob, "rockchip,fb-logo", 1222 (u64)memory_start, 1223 MEMORY_POOL_SIZE); 1224 if (offset < 0) 1225 printf("failed to reserve fb-loader-logo memory\n"); 1226 else 1227 list_for_each_entry(s, &rockchip_display_list, head) 1228 load_kernel_bmp_logo(&s->logo, s->klogo_name); 1229 return; 1230 } 1231 1232 list_for_each_entry(s, &rockchip_display_list, head) { 1233 conn = s->conn_state.connector; 1234 if (!conn) 1235 continue; 1236 conn_funcs = conn->funcs; 1237 if (!conn_funcs) { 1238 printf("failed to get exist connector\n"); 1239 continue; 1240 } 1241 1242 crtc = s->crtc_state.crtc; 1243 if (!crtc) 1244 continue; 1245 1246 crtc_funcs = crtc->funcs; 1247 if (!crtc_funcs) { 1248 printf("failed to get exist crtc\n"); 1249 continue; 1250 } 1251 1252 if (crtc_funcs->fixup_dts) 1253 crtc_funcs->fixup_dts(s, blob); 1254 1255 if (conn_funcs->fixup_dts) 1256 conn_funcs->fixup_dts(s, blob); 1257 1258 np = ofnode_to_np(s->node); 1259 path = np->full_name; 1260 fdt_increase_size(blob, 0x400); 1261 #define FDT_SET_U32(name, val) \ 1262 do_fixup_by_path_u32(blob, path, name, val, 1); 1263 1264 offset = s->logo.offset + (u32)(unsigned long)s->logo.mem 1265 - memory_start; 1266 FDT_SET_U32("logo,offset", offset); 1267 FDT_SET_U32("logo,width", s->logo.width); 1268 FDT_SET_U32("logo,height", s->logo.height); 1269 FDT_SET_U32("logo,bpp", s->logo.bpp); 1270 FDT_SET_U32("logo,ymirror", s->logo.ymirror); 1271 FDT_SET_U32("video,hdisplay", s->conn_state.mode.hdisplay); 1272 FDT_SET_U32("video,vdisplay", s->conn_state.mode.vdisplay); 1273 FDT_SET_U32("video,crtc_hsync_end", s->conn_state.mode.crtc_hsync_end); 1274 FDT_SET_U32("video,crtc_vsync_end", s->conn_state.mode.crtc_vsync_end); 1275 FDT_SET_U32("video,vrefresh", 1276 drm_mode_vrefresh(&s->conn_state.mode)); 1277 FDT_SET_U32("video,flags", s->conn_state.mode.flags); 1278 FDT_SET_U32("overscan,left_margin", s->conn_state.overscan.left_margin); 1279 FDT_SET_U32("overscan,right_margin", s->conn_state.overscan.right_margin); 1280 FDT_SET_U32("overscan,top_margin", s->conn_state.overscan.top_margin); 1281 FDT_SET_U32("overscan,bottom_margin", s->conn_state.overscan.bottom_margin); 1282 #undef FDT_SET_U32 1283 } 1284 } 1285 1286 int rockchip_display_bind(struct udevice *dev) 1287 { 1288 struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); 1289 1290 plat->size = DRM_ROCKCHIP_FB_SIZE + MEMORY_POOL_SIZE; 1291 1292 return 0; 1293 } 1294 1295 static const struct udevice_id rockchip_display_ids[] = { 1296 { .compatible = "rockchip,display-subsystem" }, 1297 { } 1298 }; 1299 1300 U_BOOT_DRIVER(rockchip_display) = { 1301 .name = "rockchip_display", 1302 .id = UCLASS_VIDEO, 1303 .of_match = rockchip_display_ids, 1304 .bind = rockchip_display_bind, 1305 .probe = rockchip_display_probe, 1306 }; 1307 1308 static int do_rockchip_logo_show(cmd_tbl_t *cmdtp, int flag, int argc, 1309 char *const argv[]) 1310 { 1311 if (argc != 1) 1312 return CMD_RET_USAGE; 1313 1314 rockchip_show_logo(); 1315 1316 return 0; 1317 } 1318 1319 static int do_rockchip_show_bmp(cmd_tbl_t *cmdtp, int flag, int argc, 1320 char *const argv[]) 1321 { 1322 if (argc != 2) 1323 return CMD_RET_USAGE; 1324 1325 rockchip_show_bmp(argv[1]); 1326 1327 return 0; 1328 } 1329 1330 U_BOOT_CMD( 1331 rockchip_show_logo, 1, 1, do_rockchip_logo_show, 1332 "load and display log from resource partition", 1333 NULL 1334 ); 1335 1336 U_BOOT_CMD( 1337 rockchip_show_bmp, 2, 1, do_rockchip_show_bmp, 1338 "load and display bmp from resource partition", 1339 " <bmp_name>" 1340 ); 1341