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