aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2017-07-08 05:22:27 -0400
committerRussell King <rmk+kernel@armlinux.org.uk>2017-12-08 07:20:52 -0500
commit890ca8df5a75b3bfdab86bec03aa60cff90a573e (patch)
treeafd596d9c68b845ba5ddc8e7523dbf32542fdc53
parentd924155dae5c59fc69be98392306970510768d0b (diff)
drm/armada: disable planes at next blanking period
Disable planes at the next blanking period rather than immediately. In order to achieve this, we need to delay the clearing of dcrtc->plane until after the next blanking period, so move that into a separate work function. To avoid races, we also need to move its assignment in the overlay code. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.c59
-rw-r--r--drivers/gpu/drm/armada/armada_overlay.c23
2 files changed, 50 insertions, 32 deletions
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index 98fb955f6889..c38a1409a14e 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -293,6 +293,19 @@ static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc,
293 spin_unlock_irqrestore(&dcrtc->irq_lock, flags); 293 spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
294} 294}
295 295
296static void armada_drm_crtc_complete_disable_work(struct armada_crtc *dcrtc,
297 struct armada_plane_work *work)
298{
299 unsigned long flags;
300
301 if (dcrtc->plane == work->plane)
302 dcrtc->plane = NULL;
303
304 spin_lock_irqsave(&dcrtc->irq_lock, flags);
305 armada_drm_crtc_update_regs(dcrtc, work->regs);
306 spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
307}
308
296static struct armada_plane_work * 309static struct armada_plane_work *
297armada_drm_crtc_alloc_plane_work(struct drm_plane *plane) 310armada_drm_crtc_alloc_plane_work(struct drm_plane *plane)
298{ 311{
@@ -392,8 +405,11 @@ static void armada_drm_crtc_prepare(struct drm_crtc *crtc)
392 * the new mode parameters. 405 * the new mode parameters.
393 */ 406 */
394 plane = dcrtc->plane; 407 plane = dcrtc->plane;
395 if (plane) 408 if (plane) {
396 drm_plane_force_disable(plane); 409 drm_plane_force_disable(plane);
410 WARN_ON(!armada_drm_plane_work_wait(drm_to_armada_plane(plane),
411 HZ));
412 }
397} 413}
398 414
399/* The mode_config.mutex will be held for this call */ 415/* The mode_config.mutex will be held for this call */
@@ -1120,28 +1136,22 @@ int armada_drm_plane_disable(struct drm_plane *plane,
1120{ 1136{
1121 struct armada_plane *dplane = drm_to_armada_plane(plane); 1137 struct armada_plane *dplane = drm_to_armada_plane(plane);
1122 struct armada_crtc *dcrtc; 1138 struct armada_crtc *dcrtc;
1139 struct armada_plane_work *work;
1140 unsigned int idx = 0;
1123 u32 sram_para1, enable_mask; 1141 u32 sram_para1, enable_mask;
1124 1142
1125 if (!plane->crtc) 1143 if (!plane->crtc)
1126 return 0; 1144 return 0;
1127 1145
1128 /* 1146 /*
1129 * Drop our reference on any framebuffer attached to this plane. 1147 * Arrange to power down most RAMs and FIFOs if this is the primary
1130 * We don't need to NULL this out as drm_plane_force_disable(), 1148 * plane, otherwise just the YUV FIFOs for the overlay plane.
1131 * and __setplane_internal() will do so for an overlay plane, and
1132 * __drm_helper_disable_unused_functions() will do so for the
1133 * primary plane.
1134 */ 1149 */
1135 if (plane->fb)
1136 drm_framebuffer_put(plane->fb);
1137
1138 /* Power down most RAMs and FIFOs if this is the primary plane */
1139 if (plane->type == DRM_PLANE_TYPE_PRIMARY) { 1150 if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
1140 sram_para1 = CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 | 1151 sram_para1 = CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 |
1141 CFG_PDWN32x32 | CFG_PDWN64x66; 1152 CFG_PDWN32x32 | CFG_PDWN64x66;
1142 enable_mask = CFG_GRA_ENA; 1153 enable_mask = CFG_GRA_ENA;
1143 } else { 1154 } else {
1144 /* Power down the Y/U/V FIFOs */
1145 sram_para1 = CFG_PDWN16x66 | CFG_PDWN32x66; 1155 sram_para1 = CFG_PDWN16x66 | CFG_PDWN32x66;
1146 enable_mask = CFG_DMA_ENA; 1156 enable_mask = CFG_DMA_ENA;
1147 } 1157 }
@@ -1150,14 +1160,33 @@ int armada_drm_plane_disable(struct drm_plane *plane,
1150 1160
1151 dcrtc = drm_to_armada_crtc(plane->crtc); 1161 dcrtc = drm_to_armada_crtc(plane->crtc);
1152 1162
1163 /*
1164 * Try to disable the plane and drop our ref on the framebuffer
1165 * at the next frame update. If we fail for any reason, disable
1166 * the plane immediately.
1167 */
1168 work = &dplane->works[dplane->next_work];
1169 work->fn = armada_drm_crtc_complete_disable_work;
1170 work->cancel = armada_drm_crtc_complete_disable_work;
1171 work->old_fb = plane->fb;
1172
1173 armada_reg_queue_mod(work->regs, idx,
1174 0, enable_mask, LCD_SPU_DMA_CTRL0);
1175 armada_reg_queue_mod(work->regs, idx,
1176 sram_para1, 0, LCD_SPU_SRAM_PARA1);
1177 armada_reg_queue_end(work->regs, idx);
1178
1153 /* Wait for any preceding work to complete, but don't wedge */ 1179 /* Wait for any preceding work to complete, but don't wedge */
1154 if (WARN_ON(!armada_drm_plane_work_wait(dplane, HZ))) 1180 if (WARN_ON(!armada_drm_plane_work_wait(dplane, HZ)))
1155 armada_drm_plane_work_cancel(dcrtc, dplane); 1181 armada_drm_plane_work_cancel(dcrtc, dplane);
1156 1182
1157 spin_lock_irq(&dcrtc->irq_lock); 1183 if (armada_drm_plane_work_queue(dcrtc, work)) {
1158 armada_updatel(0, enable_mask, dcrtc->base + LCD_SPU_DMA_CTRL0); 1184 work->fn(dcrtc, work);
1159 armada_updatel(sram_para1, 0, dcrtc->base + LCD_SPU_SRAM_PARA1); 1185 if (work->old_fb)
1160 spin_unlock_irq(&dcrtc->irq_lock); 1186 drm_framebuffer_unreference(work->old_fb);
1187 }
1188
1189 dplane->next_work = !dplane->next_work;
1161 1190
1162 return 0; 1191 return 0;
1163} 1192}
diff --git a/drivers/gpu/drm/armada/armada_overlay.c b/drivers/gpu/drm/armada/armada_overlay.c
index bad966ae6758..0fe3f2db8ff5 100644
--- a/drivers/gpu/drm/armada/armada_overlay.c
+++ b/drivers/gpu/drm/armada/armada_overlay.c
@@ -140,11 +140,6 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
140 dplane->base.state.src_x != state.src.x1 >> 16 || 140 dplane->base.state.src_x != state.src.x1 >> 16 ||
141 dplane->base.state.src_y != state.src.y1 >> 16; 141 dplane->base.state.src_y != state.src.y1 >> 16;
142 142
143 if (!dcrtc->plane) {
144 dcrtc->plane = plane;
145 armada_ovl_update_attr(&dplane->prop, dcrtc);
146 }
147
148 /* FIXME: overlay on an interlaced display */ 143 /* FIXME: overlay on an interlaced display */
149 /* Just updating the position/size? */ 144 /* Just updating the position/size? */
150 if (!fb_changed && dplane->base.state.ctrl0 == ctrl0) { 145 if (!fb_changed && dplane->base.state.ctrl0 == ctrl0) {
@@ -173,6 +168,11 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
173 if (armada_drm_plane_work_wait(&dplane->base, HZ / 25) == 0) 168 if (armada_drm_plane_work_wait(&dplane->base, HZ / 25) == 0)
174 armada_drm_plane_work_cancel(dcrtc, &dplane->base); 169 armada_drm_plane_work_cancel(dcrtc, &dplane->base);
175 170
171 if (!dcrtc->plane) {
172 dcrtc->plane = plane;
173 armada_ovl_update_attr(&dplane->prop, dcrtc);
174 }
175
176 if (fb_changed) { 176 if (fb_changed) {
177 u32 addrs[3]; 177 u32 addrs[3];
178 178
@@ -255,17 +255,6 @@ armada_ovl_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
255 return 0; 255 return 0;
256} 256}
257 257
258static int armada_ovl_plane_disable(struct drm_plane *plane,
259 struct drm_modeset_acquire_ctx *ctx)
260{
261 armada_drm_plane_disable(plane, ctx);
262
263 if (plane->crtc)
264 drm_to_armada_crtc(plane->crtc)->plane = NULL;
265
266 return 0;
267}
268
269static void armada_ovl_plane_destroy(struct drm_plane *plane) 258static void armada_ovl_plane_destroy(struct drm_plane *plane)
270{ 259{
271 struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane); 260 struct armada_ovl_plane *dplane = drm_to_armada_ovl_plane(plane);
@@ -345,7 +334,7 @@ static int armada_ovl_plane_set_property(struct drm_plane *plane,
345 334
346static const struct drm_plane_funcs armada_ovl_plane_funcs = { 335static const struct drm_plane_funcs armada_ovl_plane_funcs = {
347 .update_plane = armada_ovl_plane_update, 336 .update_plane = armada_ovl_plane_update,
348 .disable_plane = armada_ovl_plane_disable, 337 .disable_plane = armada_drm_plane_disable,
349 .destroy = armada_ovl_plane_destroy, 338 .destroy = armada_ovl_plane_destroy,
350 .set_property = armada_ovl_plane_set_property, 339 .set_property = armada_ovl_plane_set_property,
351}; 340};