diff options
author | Russell King <rmk+kernel@armlinux.org.uk> | 2017-07-08 05:22:27 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@armlinux.org.uk> | 2017-12-08 07:20:52 -0500 |
commit | 890ca8df5a75b3bfdab86bec03aa60cff90a573e (patch) | |
tree | afd596d9c68b845ba5ddc8e7523dbf32542fdc53 | |
parent | d924155dae5c59fc69be98392306970510768d0b (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.c | 59 | ||||
-rw-r--r-- | drivers/gpu/drm/armada/armada_overlay.c | 23 |
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 | ||
296 | static 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 | |||
296 | static struct armada_plane_work * | 309 | static struct armada_plane_work * |
297 | armada_drm_crtc_alloc_plane_work(struct drm_plane *plane) | 310 | armada_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 | ||
258 | static 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 | |||
269 | static void armada_ovl_plane_destroy(struct drm_plane *plane) | 258 | static 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 | ||
346 | static const struct drm_plane_funcs armada_ovl_plane_funcs = { | 335 | static 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 | }; |