aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/imx
diff options
context:
space:
mode:
authorPhilipp Zabel <p.zabel@pengutronix.de>2017-05-19 10:05:51 -0400
committerPhilipp Zabel <p.zabel@pengutronix.de>2017-07-17 06:58:11 -0400
commit790cb4c7c9545953d22d3d425e49b36a711bae5b (patch)
tree33913a427dd96b884fa6786cebb74426fd6a5b8a /drivers/gpu/drm/imx
parent58dff39904c02199b80395dac2fa3dec0d8f3861 (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.c38
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
499static 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
499static void ipu_plane_atomic_update(struct drm_plane *plane, 520static 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