|
30 | 30 | #include "lcdif_drv.h" |
31 | 31 | #include "lcdif_regs.h" |
32 | 32 |
|
| 33 | +struct lcdif_crtc_state { |
| 34 | + struct drm_crtc_state base; /* always be the first member */ |
| 35 | + u32 bus_format; |
| 36 | + u32 bus_flags; |
| 37 | +}; |
| 38 | + |
| 39 | +static inline struct lcdif_crtc_state * |
| 40 | +to_lcdif_crtc_state(struct drm_crtc_state *s) |
| 41 | +{ |
| 42 | + return container_of(s, struct lcdif_crtc_state, base); |
| 43 | +} |
| 44 | + |
33 | 45 | /* ----------------------------------------------------------------------------- |
34 | 46 | * CRTC |
35 | 47 | */ |
@@ -385,48 +397,75 @@ static void lcdif_reset_block(struct lcdif_drm_private *lcdif) |
385 | 397 | readl(lcdif->base + LCDC_V8_CTRL); |
386 | 398 | } |
387 | 399 |
|
388 | | -static void lcdif_crtc_mode_set_nofb(struct lcdif_drm_private *lcdif, |
389 | | - struct drm_plane_state *plane_state, |
390 | | - struct drm_bridge_state *bridge_state, |
391 | | - const u32 bus_format) |
| 400 | +static void lcdif_crtc_mode_set_nofb(struct drm_crtc_state *crtc_state, |
| 401 | + struct drm_plane_state *plane_state) |
392 | 402 | { |
393 | | - struct drm_device *drm = lcdif->crtc.dev; |
394 | | - struct drm_display_mode *m = &lcdif->crtc.state->adjusted_mode; |
395 | | - u32 bus_flags = 0; |
396 | | - |
397 | | - if (lcdif->bridge->timings) |
398 | | - bus_flags = lcdif->bridge->timings->input_bus_flags; |
399 | | - else if (bridge_state) |
400 | | - bus_flags = bridge_state->input_bus_cfg.flags; |
| 403 | + struct lcdif_crtc_state *lcdif_crtc_state = to_lcdif_crtc_state(crtc_state); |
| 404 | + struct drm_device *drm = crtc_state->crtc->dev; |
| 405 | + struct lcdif_drm_private *lcdif = to_lcdif_drm_private(drm); |
| 406 | + struct drm_display_mode *m = &crtc_state->adjusted_mode; |
401 | 407 |
|
402 | 408 | DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n", |
403 | 409 | m->crtc_clock, |
404 | 410 | (int)(clk_get_rate(lcdif->clk) / 1000)); |
405 | 411 | DRM_DEV_DEBUG_DRIVER(drm->dev, "Bridge bus_flags: 0x%08X\n", |
406 | | - bus_flags); |
| 412 | + lcdif_crtc_state->bus_flags); |
407 | 413 | DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags); |
408 | 414 |
|
409 | 415 | /* Mandatory eLCDIF reset as per the Reference Manual */ |
410 | 416 | lcdif_reset_block(lcdif); |
411 | 417 |
|
412 | | - lcdif_set_formats(lcdif, plane_state, bus_format); |
| 418 | + lcdif_set_formats(lcdif, plane_state, lcdif_crtc_state->bus_format); |
413 | 419 |
|
414 | | - lcdif_set_mode(lcdif, bus_flags); |
| 420 | + lcdif_set_mode(lcdif, lcdif_crtc_state->bus_flags); |
415 | 421 | } |
416 | 422 |
|
417 | 423 | static int lcdif_crtc_atomic_check(struct drm_crtc *crtc, |
418 | 424 | struct drm_atomic_state *state) |
419 | 425 | { |
| 426 | + struct drm_device *drm = crtc->dev; |
| 427 | + struct lcdif_drm_private *lcdif = to_lcdif_drm_private(drm); |
420 | 428 | struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, |
421 | 429 | crtc); |
| 430 | + struct lcdif_crtc_state *lcdif_crtc_state = to_lcdif_crtc_state(crtc_state); |
422 | 431 | bool has_primary = crtc_state->plane_mask & |
423 | 432 | drm_plane_mask(crtc->primary); |
| 433 | + struct drm_bridge_state *bridge_state; |
| 434 | + struct drm_bridge *bridge = lcdif->bridge; |
| 435 | + int ret; |
424 | 436 |
|
425 | 437 | /* The primary plane has to be enabled when the CRTC is active. */ |
426 | 438 | if (crtc_state->active && !has_primary) |
427 | 439 | return -EINVAL; |
428 | 440 |
|
429 | | - return drm_atomic_add_affected_planes(state, crtc); |
| 441 | + ret = drm_atomic_add_affected_planes(state, crtc); |
| 442 | + if (ret) |
| 443 | + return ret; |
| 444 | + |
| 445 | + bridge_state = drm_atomic_get_new_bridge_state(state, bridge); |
| 446 | + if (!bridge_state) |
| 447 | + lcdif_crtc_state->bus_format = MEDIA_BUS_FMT_FIXED; |
| 448 | + else |
| 449 | + lcdif_crtc_state->bus_format = bridge_state->input_bus_cfg.format; |
| 450 | + |
| 451 | + if (lcdif_crtc_state->bus_format == MEDIA_BUS_FMT_FIXED) { |
| 452 | + dev_warn_once(drm->dev, |
| 453 | + "Bridge does not provide bus format, assuming MEDIA_BUS_FMT_RGB888_1X24.\n" |
| 454 | + "Please fix bridge driver by handling atomic_get_input_bus_fmts.\n"); |
| 455 | + lcdif_crtc_state->bus_format = MEDIA_BUS_FMT_RGB888_1X24; |
| 456 | + } else if (!lcdif_crtc_state->bus_format) { |
| 457 | + /* If all else fails, default to RGB888_1X24 */ |
| 458 | + lcdif_crtc_state->bus_format = MEDIA_BUS_FMT_RGB888_1X24; |
| 459 | + } |
| 460 | + |
| 461 | + if (bridge->timings) |
| 462 | + lcdif_crtc_state->bus_flags = bridge->timings->input_bus_flags; |
| 463 | + else if (bridge_state) |
| 464 | + lcdif_crtc_state->bus_flags = bridge_state->input_bus_cfg.flags; |
| 465 | + else |
| 466 | + lcdif_crtc_state->bus_flags = 0; |
| 467 | + |
| 468 | + return 0; |
430 | 469 | } |
431 | 470 |
|
432 | 471 | static void lcdif_crtc_atomic_flush(struct drm_crtc *crtc, |
@@ -458,35 +497,18 @@ static void lcdif_crtc_atomic_enable(struct drm_crtc *crtc, |
458 | 497 | struct drm_atomic_state *state) |
459 | 498 | { |
460 | 499 | struct lcdif_drm_private *lcdif = to_lcdif_drm_private(crtc->dev); |
| 500 | + struct drm_crtc_state *new_cstate = drm_atomic_get_new_crtc_state(state, crtc); |
461 | 501 | struct drm_plane_state *new_pstate = drm_atomic_get_new_plane_state(state, |
462 | 502 | crtc->primary); |
463 | 503 | struct drm_display_mode *m = &lcdif->crtc.state->adjusted_mode; |
464 | | - struct drm_bridge_state *bridge_state = NULL; |
465 | 504 | struct drm_device *drm = lcdif->drm; |
466 | | - u32 bus_format; |
467 | 505 | dma_addr_t paddr; |
468 | 506 |
|
469 | | - bridge_state = drm_atomic_get_new_bridge_state(state, lcdif->bridge); |
470 | | - if (!bridge_state) |
471 | | - bus_format = MEDIA_BUS_FMT_FIXED; |
472 | | - else |
473 | | - bus_format = bridge_state->input_bus_cfg.format; |
474 | | - |
475 | | - if (bus_format == MEDIA_BUS_FMT_FIXED) { |
476 | | - dev_warn_once(drm->dev, |
477 | | - "Bridge does not provide bus format, assuming MEDIA_BUS_FMT_RGB888_1X24.\n" |
478 | | - "Please fix bridge driver by handling atomic_get_input_bus_fmts.\n"); |
479 | | - bus_format = MEDIA_BUS_FMT_RGB888_1X24; |
480 | | - } else if (!bus_format) { |
481 | | - /* If all else fails, default to RGB888_1X24 */ |
482 | | - bus_format = MEDIA_BUS_FMT_RGB888_1X24; |
483 | | - } |
484 | | - |
485 | 507 | clk_set_rate(lcdif->clk, m->crtc_clock * 1000); |
486 | 508 |
|
487 | 509 | pm_runtime_get_sync(drm->dev); |
488 | 510 |
|
489 | | - lcdif_crtc_mode_set_nofb(lcdif, new_pstate, bridge_state, bus_format); |
| 511 | + lcdif_crtc_mode_set_nofb(new_cstate, new_pstate); |
490 | 512 |
|
491 | 513 | /* Write cur_buf as well to avoid an initial corrupt frame */ |
492 | 514 | paddr = drm_fb_dma_get_gem_addr(new_pstate->fb, new_pstate, 0); |
@@ -523,6 +545,48 @@ static void lcdif_crtc_atomic_disable(struct drm_crtc *crtc, |
523 | 545 | pm_runtime_put_sync(drm->dev); |
524 | 546 | } |
525 | 547 |
|
| 548 | +static void lcdif_crtc_atomic_destroy_state(struct drm_crtc *crtc, |
| 549 | + struct drm_crtc_state *state) |
| 550 | +{ |
| 551 | + __drm_atomic_helper_crtc_destroy_state(state); |
| 552 | + kfree(to_lcdif_crtc_state(state)); |
| 553 | +} |
| 554 | + |
| 555 | +static void lcdif_crtc_reset(struct drm_crtc *crtc) |
| 556 | +{ |
| 557 | + struct lcdif_crtc_state *state; |
| 558 | + |
| 559 | + if (crtc->state) |
| 560 | + lcdif_crtc_atomic_destroy_state(crtc, crtc->state); |
| 561 | + |
| 562 | + crtc->state = NULL; |
| 563 | + |
| 564 | + state = kzalloc(sizeof(*state), GFP_KERNEL); |
| 565 | + if (state) |
| 566 | + __drm_atomic_helper_crtc_reset(crtc, &state->base); |
| 567 | +} |
| 568 | + |
| 569 | +static struct drm_crtc_state * |
| 570 | +lcdif_crtc_atomic_duplicate_state(struct drm_crtc *crtc) |
| 571 | +{ |
| 572 | + struct lcdif_crtc_state *old = to_lcdif_crtc_state(crtc->state); |
| 573 | + struct lcdif_crtc_state *new; |
| 574 | + |
| 575 | + if (WARN_ON(!crtc->state)) |
| 576 | + return NULL; |
| 577 | + |
| 578 | + new = kzalloc(sizeof(*new), GFP_KERNEL); |
| 579 | + if (!new) |
| 580 | + return NULL; |
| 581 | + |
| 582 | + __drm_atomic_helper_crtc_duplicate_state(crtc, &new->base); |
| 583 | + |
| 584 | + new->bus_format = old->bus_format; |
| 585 | + new->bus_flags = old->bus_flags; |
| 586 | + |
| 587 | + return &new->base; |
| 588 | +} |
| 589 | + |
526 | 590 | static int lcdif_crtc_enable_vblank(struct drm_crtc *crtc) |
527 | 591 | { |
528 | 592 | struct lcdif_drm_private *lcdif = to_lcdif_drm_private(crtc->dev); |
@@ -551,12 +615,12 @@ static const struct drm_crtc_helper_funcs lcdif_crtc_helper_funcs = { |
551 | 615 | }; |
552 | 616 |
|
553 | 617 | static const struct drm_crtc_funcs lcdif_crtc_funcs = { |
554 | | - .reset = drm_atomic_helper_crtc_reset, |
| 618 | + .reset = lcdif_crtc_reset, |
555 | 619 | .destroy = drm_crtc_cleanup, |
556 | 620 | .set_config = drm_atomic_helper_set_config, |
557 | 621 | .page_flip = drm_atomic_helper_page_flip, |
558 | | - .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, |
559 | | - .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, |
| 622 | + .atomic_duplicate_state = lcdif_crtc_atomic_duplicate_state, |
| 623 | + .atomic_destroy_state = lcdif_crtc_atomic_destroy_state, |
560 | 624 | .enable_vblank = lcdif_crtc_enable_vblank, |
561 | 625 | .disable_vblank = lcdif_crtc_disable_vblank, |
562 | 626 | }; |
|
0 commit comments