aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLucas Stach <l.stach@pengutronix.de>2017-03-08 06:13:21 -0500
committerPhilipp Zabel <p.zabel@pengutronix.de>2017-03-16 05:14:51 -0400
commit00514e8593350498790d19c7e21b720fee899cf7 (patch)
treebc725d9c69a4158c7f0b4fca54b0d878b411d4d6
parente0fb7dd2f00440b5449f625dee7b442219d8a56e (diff)
drm/imx: use PRG/PRE when possible
Allow the planes to use the PRG/PRE units as linear prefetchers when possible. This improves DRAM efficiency a bit and reduces the chance for display underflow when the memory subsystem is under load. This does not yet support scanning out tiled buffers directly, as this needs more work, but it already wires up the basic interaction between imx-drm, the IPUv3 driver and the PRG and PRE drivers. Signed-off-by: Lucas Stach <l.stach@pengutronix.de> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
-rw-r--r--drivers/gpu/drm/imx/imx-drm-core.c5
-rw-r--r--drivers/gpu/drm/imx/imx-drm.h3
-rw-r--r--drivers/gpu/drm/imx/ipuv3-plane.c124
3 files changed, 129 insertions, 3 deletions
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
index cd3c2013ea70..f42cf9ea911b 100644
--- a/drivers/gpu/drm/imx/imx-drm-core.c
+++ b/drivers/gpu/drm/imx/imx-drm-core.c
@@ -110,6 +110,11 @@ static int imx_drm_atomic_check(struct drm_device *dev,
110 if (ret) 110 if (ret)
111 return ret; 111 return ret;
112 112
113 /* Assign PRG/PRE channels and check if all constrains are satisfied. */
114 ret = ipu_planes_assign_pre(dev, state);
115 if (ret)
116 return ret;
117
113 return ret; 118 return ret;
114} 119}
115 120
diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/imx-drm.h
index cc003334505d..295434b199db 100644
--- a/drivers/gpu/drm/imx/imx-drm.h
+++ b/drivers/gpu/drm/imx/imx-drm.h
@@ -39,4 +39,7 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
39void imx_drm_connector_destroy(struct drm_connector *connector); 39void imx_drm_connector_destroy(struct drm_connector *connector);
40void imx_drm_encoder_destroy(struct drm_encoder *encoder); 40void imx_drm_encoder_destroy(struct drm_encoder *encoder);
41 41
42int ipu_planes_assign_pre(struct drm_device *dev,
43 struct drm_atomic_state *state);
44
42#endif /* _IMX_DRM_H_ */ 45#endif /* _IMX_DRM_H_ */
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c
index cecb8eba5c32..d63e853a0300 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.c
+++ b/drivers/gpu/drm/imx/ipuv3-plane.c
@@ -23,6 +23,17 @@
23#include "video/imx-ipu-v3.h" 23#include "video/imx-ipu-v3.h"
24#include "ipuv3-plane.h" 24#include "ipuv3-plane.h"
25 25
26struct ipu_plane_state {
27 struct drm_plane_state base;
28 bool use_pre;
29};
30
31static inline struct ipu_plane_state *
32to_ipu_plane_state(struct drm_plane_state *p)
33{
34 return container_of(p, struct ipu_plane_state, base);
35}
36
26static inline struct ipu_plane *to_ipu_plane(struct drm_plane *p) 37static inline struct ipu_plane *to_ipu_plane(struct drm_plane *p)
27{ 38{
28 return container_of(p, struct ipu_plane, base); 39 return container_of(p, struct ipu_plane, base);
@@ -223,6 +234,8 @@ void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel)
223 ipu_dmfc_disable_channel(ipu_plane->dmfc); 234 ipu_dmfc_disable_channel(ipu_plane->dmfc);
224 if (ipu_plane->dp) 235 if (ipu_plane->dp)
225 ipu_dp_disable(ipu_plane->ipu); 236 ipu_dp_disable(ipu_plane->ipu);
237 if (ipu_prg_present(ipu_plane->ipu))
238 ipu_prg_channel_disable(ipu_plane->ipu_ch);
226} 239}
227 240
228void ipu_plane_disable_deferred(struct drm_plane *plane) 241void ipu_plane_disable_deferred(struct drm_plane *plane)
@@ -246,13 +259,56 @@ static void ipu_plane_destroy(struct drm_plane *plane)
246 kfree(ipu_plane); 259 kfree(ipu_plane);
247} 260}
248 261
262void ipu_plane_state_reset(struct drm_plane *plane)
263{
264 struct ipu_plane_state *ipu_state;
265
266 if (plane->state) {
267 ipu_state = to_ipu_plane_state(plane->state);
268 __drm_atomic_helper_plane_destroy_state(plane->state);
269 kfree(ipu_state);
270 }
271
272 ipu_state = kzalloc(sizeof(*ipu_state), GFP_KERNEL);
273
274 if (ipu_state) {
275 ipu_state->base.plane = plane;
276 ipu_state->base.rotation = DRM_ROTATE_0;
277 }
278
279 plane->state = &ipu_state->base;
280}
281
282struct drm_plane_state *ipu_plane_duplicate_state(struct drm_plane *plane)
283{
284 struct ipu_plane_state *state;
285
286 if (WARN_ON(!plane->state))
287 return NULL;
288
289 state = kmalloc(sizeof(*state), GFP_KERNEL);
290 if (state)
291 __drm_atomic_helper_plane_duplicate_state(plane, &state->base);
292
293 return &state->base;
294}
295
296void ipu_plane_destroy_state(struct drm_plane *plane,
297 struct drm_plane_state *state)
298{
299 struct ipu_plane_state *ipu_state = to_ipu_plane_state(state);
300
301 __drm_atomic_helper_plane_destroy_state(state);
302 kfree(ipu_state);
303}
304
249static const struct drm_plane_funcs ipu_plane_funcs = { 305static const struct drm_plane_funcs ipu_plane_funcs = {
250 .update_plane = drm_atomic_helper_update_plane, 306 .update_plane = drm_atomic_helper_update_plane,
251 .disable_plane = drm_atomic_helper_disable_plane, 307 .disable_plane = drm_atomic_helper_disable_plane,
252 .destroy = ipu_plane_destroy, 308 .destroy = ipu_plane_destroy,
253 .reset = drm_atomic_helper_plane_reset, 309 .reset = ipu_plane_state_reset,
254 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 310 .atomic_duplicate_state = ipu_plane_duplicate_state,
255 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 311 .atomic_destroy_state = ipu_plane_destroy_state,
256}; 312};
257 313
258static int ipu_plane_atomic_check(struct drm_plane *plane, 314static int ipu_plane_atomic_check(struct drm_plane *plane,
@@ -426,17 +482,33 @@ static void ipu_plane_atomic_disable(struct drm_plane *plane,
426 ipu_plane->disabling = true; 482 ipu_plane->disabling = true;
427} 483}
428 484
485static int ipu_chan_assign_axi_id(int ipu_chan)
486{
487 switch (ipu_chan) {
488 case IPUV3_CHANNEL_MEM_BG_SYNC:
489 return 1;
490 case IPUV3_CHANNEL_MEM_FG_SYNC:
491 return 2;
492 case IPUV3_CHANNEL_MEM_DC_SYNC:
493 return 3;
494 default:
495 return 0;
496 }
497}
498
429static void ipu_plane_atomic_update(struct drm_plane *plane, 499static void ipu_plane_atomic_update(struct drm_plane *plane,
430 struct drm_plane_state *old_state) 500 struct drm_plane_state *old_state)
431{ 501{
432 struct ipu_plane *ipu_plane = to_ipu_plane(plane); 502 struct ipu_plane *ipu_plane = to_ipu_plane(plane);
433 struct drm_plane_state *state = plane->state; 503 struct drm_plane_state *state = plane->state;
504 struct ipu_plane_state *ipu_state = to_ipu_plane_state(state);
434 struct drm_crtc_state *crtc_state = state->crtc->state; 505 struct drm_crtc_state *crtc_state = state->crtc->state;
435 struct drm_framebuffer *fb = state->fb; 506 struct drm_framebuffer *fb = state->fb;
436 struct drm_rect *dst = &state->dst; 507 struct drm_rect *dst = &state->dst;
437 unsigned long eba, ubo, vbo; 508 unsigned long eba, ubo, vbo;
438 unsigned long alpha_eba = 0; 509 unsigned long alpha_eba = 0;
439 enum ipu_color_space ics; 510 enum ipu_color_space ics;
511 unsigned int axi_id = 0;
440 int active; 512 int active;
441 513
442 if (ipu_plane->dp_flow == IPU_DP_FLOW_SYNC_FG) 514 if (ipu_plane->dp_flow == IPU_DP_FLOW_SYNC_FG)
@@ -444,7 +516,23 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
444 516
445 eba = drm_plane_state_to_eba(state, 0); 517 eba = drm_plane_state_to_eba(state, 0);
446 518
519 /*
520 * Configure PRG channel and attached PRE, this changes the EBA to an
521 * internal SRAM location.
522 */
523 if (ipu_state->use_pre) {
524 axi_id = ipu_chan_assign_axi_id(ipu_plane->dma);
525 ipu_prg_channel_configure(ipu_plane->ipu_ch, axi_id,
526 drm_rect_width(&state->src) >> 16,
527 drm_rect_height(&state->src) >> 16,
528 state->fb->pitches[0],
529 state->fb->format->format, &eba);
530 }
531
447 if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state)) { 532 if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state)) {
533 /* nothing to do if PRE is used */
534 if (ipu_state->use_pre)
535 return;
448 active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch); 536 active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
449 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba); 537 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
450 ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active); 538 ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
@@ -503,6 +591,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
503 ipu_cpmem_set_high_priority(ipu_plane->ipu_ch); 591 ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
504 ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1); 592 ipu_idmac_set_double_buffer(ipu_plane->ipu_ch, 1);
505 ipu_cpmem_set_stride(ipu_plane->ipu_ch, state->fb->pitches[0]); 593 ipu_cpmem_set_stride(ipu_plane->ipu_ch, state->fb->pitches[0]);
594 ipu_cpmem_set_axi_id(ipu_plane->ipu_ch, axi_id);
506 switch (fb->format->format) { 595 switch (fb->format->format) {
507 case DRM_FORMAT_YUV420: 596 case DRM_FORMAT_YUV420:
508 case DRM_FORMAT_YVU420: 597 case DRM_FORMAT_YVU420:
@@ -578,6 +667,35 @@ static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = {
578 .atomic_update = ipu_plane_atomic_update, 667 .atomic_update = ipu_plane_atomic_update,
579}; 668};
580 669
670int ipu_planes_assign_pre(struct drm_device *dev,
671 struct drm_atomic_state *state)
672{
673 struct drm_plane_state *plane_state;
674 struct drm_plane *plane;
675 int available_pres = ipu_prg_max_active_channels();
676 int i;
677
678 for_each_plane_in_state(state, plane, plane_state, i) {
679 struct ipu_plane_state *ipu_state =
680 to_ipu_plane_state(plane_state);
681 struct ipu_plane *ipu_plane = to_ipu_plane(plane);
682
683 if (ipu_prg_present(ipu_plane->ipu) && available_pres &&
684 plane_state->fb &&
685 ipu_prg_format_supported(ipu_plane->ipu,
686 plane_state->fb->format->format,
687 plane_state->fb->modifier)) {
688 ipu_state->use_pre = true;
689 available_pres--;
690 } else {
691 ipu_state->use_pre = false;
692 }
693 }
694
695 return 0;
696}
697EXPORT_SYMBOL_GPL(ipu_planes_assign_pre);
698
581struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, 699struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
582 int dma, int dp, unsigned int possible_crtcs, 700 int dma, int dp, unsigned int possible_crtcs,
583 enum drm_plane_type type) 701 enum drm_plane_type type)