aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/imx
diff options
context:
space:
mode:
authorPhilipp Zabel <p.zabel@pengutronix.de>2016-07-22 06:02:45 -0400
committerPhilipp Zabel <p.zabel@pengutronix.de>2017-03-15 10:42:33 -0400
commitf6b50ef14ea84725c1b41c9ffea611cdfb71c7dd (patch)
treeaa54a5dfdd0eff33e576ae70325405bdc0c435a8 /drivers/gpu/drm/imx
parent0bfd56f05552b7d0d08a8c39b6198018b52de7f5 (diff)
drm/imx: ipuv3-plane: add support for separate alpha planes
The IPUv3 can read 8-bit alpha values from a separate plane buffer using a companion IDMAC channel driven by the Alpha Transparency Controller (ATC) for the graphics channels. The conditional read mechanism allows to reduce memory bandwidth by skipping reads of color data for completely transparent bursts. 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.c97
-rw-r--r--drivers/gpu/drm/imx/ipuv3-plane.h1
2 files changed, 97 insertions, 1 deletions
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c
index 53eceff09d17..cecb8eba5c32 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.c
+++ b/drivers/gpu/drm/imx/ipuv3-plane.c
@@ -57,6 +57,12 @@ static const uint32_t ipu_plane_formats[] = {
57 DRM_FORMAT_NV12, 57 DRM_FORMAT_NV12,
58 DRM_FORMAT_NV16, 58 DRM_FORMAT_NV16,
59 DRM_FORMAT_RGB565, 59 DRM_FORMAT_RGB565,
60 DRM_FORMAT_RGB565_A8,
61 DRM_FORMAT_BGR565_A8,
62 DRM_FORMAT_RGB888_A8,
63 DRM_FORMAT_BGR888_A8,
64 DRM_FORMAT_RGBX8888_A8,
65 DRM_FORMAT_BGRX8888_A8,
60}; 66};
61 67
62int ipu_plane_irq(struct ipu_plane *ipu_plane) 68int ipu_plane_irq(struct ipu_plane *ipu_plane)
@@ -126,11 +132,14 @@ void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
126 ipu_dmfc_put(ipu_plane->dmfc); 132 ipu_dmfc_put(ipu_plane->dmfc);
127 if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch)) 133 if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch))
128 ipu_idmac_put(ipu_plane->ipu_ch); 134 ipu_idmac_put(ipu_plane->ipu_ch);
135 if (!IS_ERR_OR_NULL(ipu_plane->alpha_ch))
136 ipu_idmac_put(ipu_plane->alpha_ch);
129} 137}
130 138
131int ipu_plane_get_resources(struct ipu_plane *ipu_plane) 139int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
132{ 140{
133 int ret; 141 int ret;
142 int alpha_ch;
134 143
135 ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma); 144 ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma);
136 if (IS_ERR(ipu_plane->ipu_ch)) { 145 if (IS_ERR(ipu_plane->ipu_ch)) {
@@ -139,6 +148,17 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
139 return ret; 148 return ret;
140 } 149 }
141 150
151 alpha_ch = ipu_channel_alpha_channel(ipu_plane->dma);
152 if (alpha_ch >= 0) {
153 ipu_plane->alpha_ch = ipu_idmac_get(ipu_plane->ipu, alpha_ch);
154 if (IS_ERR(ipu_plane->alpha_ch)) {
155 ret = PTR_ERR(ipu_plane->alpha_ch);
156 DRM_ERROR("failed to get alpha idmac channel %d: %d\n",
157 alpha_ch, ret);
158 return ret;
159 }
160 }
161
142 ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma); 162 ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma);
143 if (IS_ERR(ipu_plane->dmfc)) { 163 if (IS_ERR(ipu_plane->dmfc)) {
144 ret = PTR_ERR(ipu_plane->dmfc); 164 ret = PTR_ERR(ipu_plane->dmfc);
@@ -162,12 +182,29 @@ err_out:
162 return ret; 182 return ret;
163} 183}
164 184
185static bool ipu_plane_separate_alpha(struct ipu_plane *ipu_plane)
186{
187 switch (ipu_plane->base.state->fb->format->format) {
188 case DRM_FORMAT_RGB565_A8:
189 case DRM_FORMAT_BGR565_A8:
190 case DRM_FORMAT_RGB888_A8:
191 case DRM_FORMAT_BGR888_A8:
192 case DRM_FORMAT_RGBX8888_A8:
193 case DRM_FORMAT_BGRX8888_A8:
194 return true;
195 default:
196 return false;
197 }
198}
199
165static void ipu_plane_enable(struct ipu_plane *ipu_plane) 200static void ipu_plane_enable(struct ipu_plane *ipu_plane)
166{ 201{
167 if (ipu_plane->dp) 202 if (ipu_plane->dp)
168 ipu_dp_enable(ipu_plane->ipu); 203 ipu_dp_enable(ipu_plane->ipu);
169 ipu_dmfc_enable_channel(ipu_plane->dmfc); 204 ipu_dmfc_enable_channel(ipu_plane->dmfc);
170 ipu_idmac_enable_channel(ipu_plane->ipu_ch); 205 ipu_idmac_enable_channel(ipu_plane->ipu_ch);
206 if (ipu_plane_separate_alpha(ipu_plane))
207 ipu_idmac_enable_channel(ipu_plane->alpha_ch);
171 if (ipu_plane->dp) 208 if (ipu_plane->dp)
172 ipu_dp_enable_channel(ipu_plane->dp); 209 ipu_dp_enable_channel(ipu_plane->dp);
173} 210}
@@ -181,6 +218,8 @@ void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel)
181 if (ipu_plane->dp && disable_dp_channel) 218 if (ipu_plane->dp && disable_dp_channel)
182 ipu_dp_disable_channel(ipu_plane->dp, false); 219 ipu_dp_disable_channel(ipu_plane->dp, false);
183 ipu_idmac_disable_channel(ipu_plane->ipu_ch); 220 ipu_idmac_disable_channel(ipu_plane->ipu_ch);
221 if (ipu_plane->alpha_ch)
222 ipu_idmac_disable_channel(ipu_plane->alpha_ch);
184 ipu_dmfc_disable_channel(ipu_plane->dmfc); 223 ipu_dmfc_disable_channel(ipu_plane->dmfc);
185 if (ipu_plane->dp) 224 if (ipu_plane->dp)
186 ipu_dp_disable(ipu_plane->ipu); 225 ipu_dp_disable(ipu_plane->ipu);
@@ -224,7 +263,7 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
224 struct device *dev = plane->dev->dev; 263 struct device *dev = plane->dev->dev;
225 struct drm_framebuffer *fb = state->fb; 264 struct drm_framebuffer *fb = state->fb;
226 struct drm_framebuffer *old_fb = old_state->fb; 265 struct drm_framebuffer *old_fb = old_state->fb;
227 unsigned long eba, ubo, vbo, old_ubo, old_vbo; 266 unsigned long eba, ubo, vbo, old_ubo, old_vbo, alpha_eba;
228 bool can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY); 267 bool can_position = (plane->type == DRM_PLANE_TYPE_OVERLAY);
229 struct drm_rect clip; 268 struct drm_rect clip;
230 int hsub, vsub; 269 int hsub, vsub;
@@ -355,6 +394,23 @@ static int ipu_plane_atomic_check(struct drm_plane *plane,
355 if (((state->src.x1 >> 16) & (hsub - 1)) || 394 if (((state->src.x1 >> 16) & (hsub - 1)) ||
356 ((state->src.y1 >> 16) & (vsub - 1))) 395 ((state->src.y1 >> 16) & (vsub - 1)))
357 return -EINVAL; 396 return -EINVAL;
397 break;
398 case DRM_FORMAT_RGB565_A8:
399 case DRM_FORMAT_BGR565_A8:
400 case DRM_FORMAT_RGB888_A8:
401 case DRM_FORMAT_BGR888_A8:
402 case DRM_FORMAT_RGBX8888_A8:
403 case DRM_FORMAT_BGRX8888_A8:
404 alpha_eba = drm_plane_state_to_eba(state, 1);
405 if (alpha_eba & 0x7)
406 return -EINVAL;
407
408 if (fb->pitches[1] < 1 || fb->pitches[1] > 16384)
409 return -EINVAL;
410
411 if (old_fb && old_fb->pitches[1] != fb->pitches[1])
412 crtc_state->mode_changed = true;
413 break;
358 } 414 }
359 415
360 return 0; 416 return 0;
@@ -379,6 +435,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
379 struct drm_framebuffer *fb = state->fb; 435 struct drm_framebuffer *fb = state->fb;
380 struct drm_rect *dst = &state->dst; 436 struct drm_rect *dst = &state->dst;
381 unsigned long eba, ubo, vbo; 437 unsigned long eba, ubo, vbo;
438 unsigned long alpha_eba = 0;
382 enum ipu_color_space ics; 439 enum ipu_color_space ics;
383 int active; 440 int active;
384 441
@@ -391,6 +448,12 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
391 active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch); 448 active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
392 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba); 449 ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
393 ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active); 450 ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
451 if (ipu_plane_separate_alpha(ipu_plane)) {
452 active = ipu_idmac_get_current_buffer(ipu_plane->alpha_ch);
453 ipu_cpmem_set_buffer(ipu_plane->alpha_ch, !active,
454 alpha_eba);
455 ipu_idmac_select_buffer(ipu_plane->alpha_ch, !active);
456 }
394 return; 457 return;
395 } 458 }
396 459
@@ -416,6 +479,12 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
416 case DRM_FORMAT_ABGR8888: 479 case DRM_FORMAT_ABGR8888:
417 case DRM_FORMAT_RGBA8888: 480 case DRM_FORMAT_RGBA8888:
418 case DRM_FORMAT_BGRA8888: 481 case DRM_FORMAT_BGRA8888:
482 case DRM_FORMAT_RGB565_A8:
483 case DRM_FORMAT_BGR565_A8:
484 case DRM_FORMAT_RGB888_A8:
485 case DRM_FORMAT_BGR888_A8:
486 case DRM_FORMAT_RGBX8888_A8:
487 case DRM_FORMAT_BGRX8888_A8:
419 ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false); 488 ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false);
420 break; 489 break;
421 default: 490 default:
@@ -466,6 +535,32 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
466 "phy = %lu %lu, x = %d, y = %d", eba, ubo, 535 "phy = %lu %lu, x = %d, y = %d", eba, ubo,
467 state->src.x1 >> 16, state->src.y1 >> 16); 536 state->src.x1 >> 16, state->src.y1 >> 16);
468 break; 537 break;
538 case DRM_FORMAT_RGB565_A8:
539 case DRM_FORMAT_BGR565_A8:
540 case DRM_FORMAT_RGB888_A8:
541 case DRM_FORMAT_BGR888_A8:
542 case DRM_FORMAT_RGBX8888_A8:
543 case DRM_FORMAT_BGRX8888_A8:
544 alpha_eba = drm_plane_state_to_eba(state, 1);
545
546 dev_dbg(ipu_plane->base.dev->dev, "phys = %lu %lu, x = %d, y = %d",
547 eba, alpha_eba, state->src.x1 >> 16, state->src.y1 >> 16);
548
549 ipu_cpmem_set_burstsize(ipu_plane->ipu_ch, 16);
550
551 ipu_cpmem_zero(ipu_plane->alpha_ch);
552 ipu_cpmem_set_resolution(ipu_plane->alpha_ch,
553 drm_rect_width(&state->src) >> 16,
554 drm_rect_height(&state->src) >> 16);
555 ipu_cpmem_set_format_passthrough(ipu_plane->alpha_ch, 8);
556 ipu_cpmem_set_high_priority(ipu_plane->alpha_ch);
557 ipu_idmac_set_double_buffer(ipu_plane->alpha_ch, 1);
558 ipu_cpmem_set_stride(ipu_plane->alpha_ch,
559 state->fb->pitches[1]);
560 ipu_cpmem_set_burstsize(ipu_plane->alpha_ch, 16);
561 ipu_cpmem_set_buffer(ipu_plane->alpha_ch, 0, alpha_eba);
562 ipu_cpmem_set_buffer(ipu_plane->alpha_ch, 1, alpha_eba);
563 break;
469 default: 564 default:
470 dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d", 565 dev_dbg(ipu_plane->base.dev->dev, "phys = %lu, x = %d, y = %d",
471 eba, state->src.x1 >> 16, state->src.y1 >> 16); 566 eba, state->src.x1 >> 16, state->src.y1 >> 16);
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.h b/drivers/gpu/drm/imx/ipuv3-plane.h
index 0e2a723ff981..596b24ddbf65 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.h
+++ b/drivers/gpu/drm/imx/ipuv3-plane.h
@@ -18,6 +18,7 @@ struct ipu_plane {
18 18
19 struct ipu_soc *ipu; 19 struct ipu_soc *ipu;
20 struct ipuv3_channel *ipu_ch; 20 struct ipuv3_channel *ipu_ch;
21 struct ipuv3_channel *alpha_ch;
21 struct dmfc_channel *dmfc; 22 struct dmfc_channel *dmfc;
22 struct ipu_dp *dp; 23 struct ipu_dp *dp;
23 24