diff options
author | Philipp Zabel <p.zabel@pengutronix.de> | 2017-05-19 10:05:51 -0400 |
---|---|---|
committer | Philipp Zabel <p.zabel@pengutronix.de> | 2017-07-17 06:58:11 -0400 |
commit | 790cb4c7c9545953d22d3d425e49b36a711bae5b (patch) | |
tree | 33913a427dd96b884fa6786cebb74426fd6a5b8a /drivers/gpu/drm/imx | |
parent | 58dff39904c02199b80395dac2fa3dec0d8f3861 (diff) |
drm/imx: lock scanout transfers for consecutive bursts
Because of its shallow queues and limited reordering ability, the i.MX6Q
memory controller likes AXI bursts of consecutive addresses a lot.
To optimize memory access performance, lock the IPU scanout channels for
a number of burst accesses each, before switching to the next channel.
The burst size and length of a locked burst chain are chosen not to
overshoot the stride.
Enabling the 8-burst channel lock on a single 1920x1080@60Hz RGBx
scanout (474 MiB/s of 64-byte IPU memory read accesses) reduces the
reported memory controller busy cycles from 46% to below 28% on an
otherwise idle i.MX6Q.
Tested-by: Lucas Stach <l.stach@pengutronix.de>
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Diffstat (limited to 'drivers/gpu/drm/imx')
-rw-r--r-- | drivers/gpu/drm/imx/ipuv3-plane.c | 38 |
1 files changed, 35 insertions, 3 deletions
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index 553dc9926e49..0be08c654a7a 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c | |||
@@ -496,6 +496,27 @@ static int ipu_chan_assign_axi_id(int ipu_chan) | |||
496 | } | 496 | } |
497 | } | 497 | } |
498 | 498 | ||
499 | static void ipu_calculate_bursts(u32 width, u32 cpp, u32 stride, | ||
500 | u8 *burstsize, u8 *num_bursts) | ||
501 | { | ||
502 | const unsigned int width_bytes = width * cpp; | ||
503 | unsigned int npb, bursts; | ||
504 | |||
505 | /* Maximum number of pixels per burst without overshooting stride */ | ||
506 | for (npb = 64 / cpp; npb > 0; --npb) { | ||
507 | if (round_up(width_bytes, npb * cpp) <= stride) | ||
508 | break; | ||
509 | } | ||
510 | *burstsize = npb; | ||
511 | |||
512 | /* Maximum number of consecutive bursts without overshooting stride */ | ||
513 | for (bursts = 8; bursts > 1; bursts /= 2) { | ||
514 | if (round_up(width_bytes, npb * cpp * bursts) <= stride) | ||
515 | break; | ||
516 | } | ||
517 | *num_bursts = bursts; | ||
518 | } | ||
519 | |||
499 | static void ipu_plane_atomic_update(struct drm_plane *plane, | 520 | static void ipu_plane_atomic_update(struct drm_plane *plane, |
500 | struct drm_plane_state *old_state) | 521 | struct drm_plane_state *old_state) |
501 | { | 522 | { |
@@ -509,6 +530,9 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, | |||
509 | unsigned long alpha_eba = 0; | 530 | unsigned long alpha_eba = 0; |
510 | enum ipu_color_space ics; | 531 | enum ipu_color_space ics; |
511 | unsigned int axi_id = 0; | 532 | unsigned int axi_id = 0; |
533 | const struct drm_format_info *info; | ||
534 | u8 burstsize, num_bursts; | ||
535 | u32 width, height; | ||
512 | int active; | 536 | int active; |
513 | 537 | ||
514 | if (ipu_plane->dp_flow == IPU_DP_FLOW_SYNC_FG) | 538 | if (ipu_plane->dp_flow == IPU_DP_FLOW_SYNC_FG) |
@@ -583,15 +607,21 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, | |||
583 | 607 | ||
584 | ipu_dmfc_config_wait4eot(ipu_plane->dmfc, drm_rect_width(dst)); | 608 | ipu_dmfc_config_wait4eot(ipu_plane->dmfc, drm_rect_width(dst)); |
585 | 609 | ||
610 | width = drm_rect_width(&state->src) >> 16; | ||
611 | height = drm_rect_height(&state->src) >> 16; | ||
612 | info = drm_format_info(fb->format->format); | ||
613 | ipu_calculate_bursts(width, info->cpp[0], fb->pitches[0], | ||
614 | &burstsize, &num_bursts); | ||
615 | |||
586 | ipu_cpmem_zero(ipu_plane->ipu_ch); | 616 | ipu_cpmem_zero(ipu_plane->ipu_ch); |
587 | ipu_cpmem_set_resolution(ipu_plane->ipu_ch, | 617 | ipu_cpmem_set_resolution(ipu_plane->ipu_ch, width, height); |
588 | drm_rect_width(&state->src) >> 16, | ||
589 | drm_rect_height(&state->src) >> 16); | ||
590 | ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->format->format); | 618 | ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->format->format); |
619 | ipu_cpmem_set_burstsize(ipu_plane->ipu_ch, burstsize); | ||
591 | ipu_cpmem_set_high_priority(ipu_plane->ipu_ch); | 620 | ipu_cpmem_set_high_priority(ipu_plane->ipu_ch); |
592 | ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1); | 621 | ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1); |
593 | ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]); | 622 | ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]); |
594 | ipu_cpmem_set_axi_id(ipu_plane->ipu_ch, axi_id); | 623 | ipu_cpmem_set_axi_id(ipu_plane->ipu_ch, axi_id); |
624 | |||
595 | switch (fb->format->format) { | 625 | switch (fb->format->format) { |
596 | case DRM_FORMAT_YUV420: | 626 | case DRM_FORMAT_YUV420: |
597 | case DRM_FORMAT_YVU420: | 627 | case DRM_FORMAT_YVU420: |
@@ -631,6 +661,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, | |||
631 | case DRM_FORMAT_RGBX8888_A8: | 661 | case DRM_FORMAT_RGBX8888_A8: |
632 | case DRM_FORMAT_BGRX8888_A8: | 662 | case DRM_FORMAT_BGRX8888_A8: |
633 | alpha_eba = drm_plane_state_to_eba(state, 1); | 663 | alpha_eba = drm_plane_state_to_eba(state, 1); |
664 | num_bursts = 0; | ||
634 | 665 | ||
635 | dev_dbg(ipu_plane->base.dev->dev, "phys = %lu %lu, x = %d, y = %d", | 666 | dev_dbg(ipu_plane->base.dev->dev, "phys = %lu %lu, x = %d, y = %d", |
636 | eba, alpha_eba, state->src.x1 >> 16, state->src.y1 >> 16); | 667 | eba, alpha_eba, state->src.x1 >> 16, state->src.y1 >> 16); |
@@ -656,6 +687,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, | |||
656 | } | 687 | } |
657 | ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba); | 688 | ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba); |
658 | ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba); | 689 | ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba); |
690 | ipu_idmac_lock_enable(ipu_plane->ipu_ch, num_bursts); | ||
659 | ipu_plane_enable(ipu_plane); | 691 | ipu_plane_enable(ipu_plane); |
660 | } | 692 | } |
661 | 693 | ||