Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm: sti: convert driver to atomic modeset

v1: This patch does the minimum to make sti driver use atomic helpers.
No big bang, only adapt some functions to new call order.

v2: Use dpms and page flip atomic helpers

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>

+207 -148
+41 -138
drivers/gpu/drm/sti/sti_drm_crtc.c
··· 9 9 #include <linux/clk.h> 10 10 11 11 #include <drm/drmP.h> 12 + #include <drm/drm_atomic.h> 13 + #include <drm/drm_atomic_helper.h> 12 14 #include <drm/drm_crtc_helper.h> 13 15 #include <drm/drm_plane_helper.h> 14 16 ··· 79 77 } 80 78 81 79 static int 82 - sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, 83 - struct drm_display_mode *adjusted_mode, int x, int y, 84 - struct drm_framebuffer *old_fb) 80 + sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode) 85 81 { 86 82 struct sti_mixer *mixer = to_sti_mixer(crtc); 87 83 struct device *dev = mixer->dev; 88 84 struct sti_compositor *compo = dev_get_drvdata(dev); 89 - struct sti_layer *layer; 90 85 struct clk *clk; 91 86 int rate = mode->clock * 1000; 92 87 int res; 93 - unsigned int w, h; 94 88 95 - DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d mode:%d (%s)\n", 89 + DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n", 96 90 crtc->base.id, sti_mixer_to_str(mixer), 97 - crtc->primary->fb->base.id, mode->base.id, mode->name); 91 + mode->base.id, mode->name); 98 92 99 93 DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", 100 94 mode->vrefresh, mode->clock, ··· 120 122 sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ? 121 123 compo->vtg_main : compo->vtg_aux, &crtc->mode); 122 124 123 - /* a GDP is reserved to the CRTC FB */ 124 - layer = to_sti_layer(crtc->primary); 125 - if (!layer) { 126 - DRM_ERROR("Can not find GDP0)\n"); 127 - return -EINVAL; 128 - } 129 - 130 - /* copy the mode data adjusted by mode_fixup() into crtc->mode 131 - * so that hardware can be set to proper mode 132 - */ 133 - memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode)); 134 - 135 - res = sti_mixer_set_layer_depth(mixer, layer); 136 - if (res) { 137 - DRM_ERROR("Can not set layer depth\n"); 138 - return -EINVAL; 139 - } 140 125 res = sti_mixer_active_video_area(mixer, &crtc->mode); 141 126 if (res) { 142 127 DRM_ERROR("Can not set active video area\n"); 143 128 return -EINVAL; 144 129 } 145 130 146 - w = crtc->primary->fb->width - x; 147 - h = crtc->primary->fb->height - y; 148 - 149 - return sti_layer_prepare(layer, crtc, 150 - crtc->primary->fb, &crtc->mode, 151 - mixer->id, 0, 0, w, h, x, y, w, h); 152 - } 153 - 154 - static int sti_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 155 - struct drm_framebuffer *old_fb) 156 - { 157 - struct sti_mixer *mixer = to_sti_mixer(crtc); 158 - struct sti_layer *layer; 159 - unsigned int w, h; 160 - int ret; 161 - 162 - DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d (%d,%d)\n", 163 - crtc->base.id, sti_mixer_to_str(mixer), 164 - crtc->primary->fb->base.id, x, y); 165 - 166 - /* GDP is reserved to the CRTC FB */ 167 - layer = to_sti_layer(crtc->primary); 168 - if (!layer) { 169 - DRM_ERROR("Can not find GDP0)\n"); 170 - ret = -EINVAL; 171 - goto out; 172 - } 173 - 174 - w = crtc->primary->fb->width - crtc->x; 175 - h = crtc->primary->fb->height - crtc->y; 176 - 177 - ret = sti_layer_prepare(layer, crtc, 178 - crtc->primary->fb, &crtc->mode, 179 - mixer->id, 0, 0, w, h, 180 - crtc->x, crtc->y, w, h); 181 - if (ret) { 182 - DRM_ERROR("Can not prepare layer\n"); 183 - goto out; 184 - } 185 - 186 - sti_drm_crtc_commit(crtc); 187 - out: 188 - return ret; 131 + return res; 189 132 } 190 133 191 134 static void sti_drm_crtc_disable(struct drm_crtc *crtc) ··· 134 195 struct sti_mixer *mixer = to_sti_mixer(crtc); 135 196 struct device *dev = mixer->dev; 136 197 struct sti_compositor *compo = dev_get_drvdata(dev); 137 - struct sti_layer *layer; 138 198 139 199 if (!mixer->enabled) 140 200 return; ··· 142 204 143 205 /* Disable Background */ 144 206 sti_mixer_set_background_status(mixer, false); 145 - 146 - /* Disable GDP */ 147 - layer = to_sti_layer(crtc->primary); 148 - if (!layer) { 149 - DRM_ERROR("Cannot find GDP0\n"); 150 - return; 151 - } 152 - 153 - /* Disable layer at mixer level */ 154 - if (sti_mixer_set_layer_status(mixer, layer, false)) 155 - DRM_ERROR("Can not disable %s layer at mixer\n", 156 - sti_layer_to_str(layer)); 157 - 158 - /* Wait a while to be sure that a Vsync event is received */ 159 - msleep(WAIT_NEXT_VSYNC_MS); 160 - 161 - /* Then disable layer itself */ 162 - sti_layer_disable(layer); 163 207 164 208 drm_crtc_vblank_off(crtc); 165 209 ··· 157 237 mixer->enabled = false; 158 238 } 159 239 240 + static void 241 + sti_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) 242 + { 243 + sti_drm_crtc_prepare(crtc); 244 + sti_drm_crtc_mode_set(crtc, &crtc->state->adjusted_mode); 245 + } 246 + 247 + static void sti_drm_atomic_begin(struct drm_crtc *crtc) 248 + { 249 + struct sti_mixer *mixer = to_sti_mixer(crtc); 250 + 251 + if (crtc->state->event) { 252 + crtc->state->event->pipe = drm_crtc_index(crtc); 253 + 254 + WARN_ON(drm_crtc_vblank_get(crtc) != 0); 255 + 256 + mixer->pending_event = crtc->state->event; 257 + crtc->state->event = NULL; 258 + } 259 + } 260 + 261 + static void sti_drm_atomic_flush(struct drm_crtc *crtc) 262 + { 263 + } 264 + 160 265 static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { 161 266 .dpms = sti_drm_crtc_dpms, 162 267 .prepare = sti_drm_crtc_prepare, 163 268 .commit = sti_drm_crtc_commit, 164 269 .mode_fixup = sti_drm_crtc_mode_fixup, 165 - .mode_set = sti_drm_crtc_mode_set, 166 - .mode_set_base = sti_drm_crtc_mode_set_base, 270 + .mode_set = drm_helper_crtc_mode_set, 271 + .mode_set_nofb = sti_drm_crtc_mode_set_nofb, 272 + .mode_set_base = drm_helper_crtc_mode_set_base, 167 273 .disable = sti_drm_crtc_disable, 274 + .atomic_begin = sti_drm_atomic_begin, 275 + .atomic_flush = sti_drm_atomic_flush, 168 276 }; 169 - 170 - static int sti_drm_crtc_page_flip(struct drm_crtc *crtc, 171 - struct drm_framebuffer *fb, 172 - struct drm_pending_vblank_event *event, 173 - uint32_t page_flip_flags) 174 - { 175 - struct drm_device *drm_dev = crtc->dev; 176 - struct drm_framebuffer *old_fb; 177 - struct sti_mixer *mixer = to_sti_mixer(crtc); 178 - unsigned long flags; 179 - int ret; 180 - 181 - DRM_DEBUG_KMS("fb %d --> fb %d\n", 182 - crtc->primary->fb->base.id, fb->base.id); 183 - 184 - mutex_lock(&drm_dev->struct_mutex); 185 - 186 - old_fb = crtc->primary->fb; 187 - crtc->primary->fb = fb; 188 - ret = sti_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb); 189 - if (ret) { 190 - DRM_ERROR("failed\n"); 191 - crtc->primary->fb = old_fb; 192 - goto out; 193 - } 194 - 195 - if (event) { 196 - event->pipe = mixer->id; 197 - 198 - ret = drm_vblank_get(drm_dev, event->pipe); 199 - if (ret) { 200 - DRM_ERROR("Cannot get vblank\n"); 201 - goto out; 202 - } 203 - 204 - spin_lock_irqsave(&drm_dev->event_lock, flags); 205 - if (mixer->pending_event) { 206 - drm_vblank_put(drm_dev, event->pipe); 207 - ret = -EBUSY; 208 - } else { 209 - mixer->pending_event = event; 210 - } 211 - spin_unlock_irqrestore(&drm_dev->event_lock, flags); 212 - } 213 - out: 214 - mutex_unlock(&drm_dev->struct_mutex); 215 - return ret; 216 - } 217 277 218 278 static void sti_drm_crtc_destroy(struct drm_crtc *crtc) 219 279 { ··· 280 380 EXPORT_SYMBOL(sti_drm_crtc_disable_vblank); 281 381 282 382 static struct drm_crtc_funcs sti_crtc_funcs = { 283 - .set_config = drm_crtc_helper_set_config, 284 - .page_flip = sti_drm_crtc_page_flip, 383 + .set_config = drm_atomic_helper_set_config, 384 + .page_flip = drm_atomic_helper_page_flip, 285 385 .destroy = sti_drm_crtc_destroy, 286 386 .set_property = sti_drm_crtc_set_property, 387 + .reset = drm_atomic_helper_crtc_reset, 388 + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 389 + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 287 390 }; 288 391 289 392 bool sti_drm_crtc_is_main(struct drm_crtc *crtc)
+85 -1
drivers/gpu/drm/sti/sti_drm_drv.c
··· 12 12 #include <linux/module.h> 13 13 #include <linux/of_platform.h> 14 14 15 + #include <drm/drm_atomic.h> 16 + #include <drm/drm_atomic_helper.h> 15 17 #include <drm/drm_crtc_helper.h> 16 18 #include <drm/drm_gem_cma_helper.h> 17 19 #include <drm/drm_fb_cma_helper.h> ··· 30 28 #define STI_MAX_FB_HEIGHT 4096 31 29 #define STI_MAX_FB_WIDTH 4096 32 30 31 + static void sti_drm_atomic_schedule(struct sti_drm_private *private, 32 + struct drm_atomic_state *state) 33 + { 34 + private->commit.state = state; 35 + schedule_work(&private->commit.work); 36 + } 37 + 38 + static void sti_drm_atomic_complete(struct sti_drm_private *private, 39 + struct drm_atomic_state *state) 40 + { 41 + struct drm_device *drm = private->drm_dev; 42 + 43 + /* 44 + * Everything below can be run asynchronously without the need to grab 45 + * any modeset locks at all under one condition: It must be guaranteed 46 + * that the asynchronous work has either been cancelled (if the driver 47 + * supports it, which at least requires that the framebuffers get 48 + * cleaned up with drm_atomic_helper_cleanup_planes()) or completed 49 + * before the new state gets committed on the software side with 50 + * drm_atomic_helper_swap_state(). 51 + * 52 + * This scheme allows new atomic state updates to be prepared and 53 + * checked in parallel to the asynchronous completion of the previous 54 + * update. Which is important since compositors need to figure out the 55 + * composition of the next frame right after having submitted the 56 + * current layout. 57 + */ 58 + 59 + drm_atomic_helper_commit_modeset_disables(drm, state); 60 + drm_atomic_helper_commit_planes(drm, state); 61 + drm_atomic_helper_commit_modeset_enables(drm, state); 62 + 63 + drm_atomic_helper_wait_for_vblanks(drm, state); 64 + 65 + drm_atomic_helper_cleanup_planes(drm, state); 66 + drm_atomic_state_free(state); 67 + } 68 + 69 + static void sti_drm_atomic_work(struct work_struct *work) 70 + { 71 + struct sti_drm_private *private = container_of(work, 72 + struct sti_drm_private, commit.work); 73 + 74 + sti_drm_atomic_complete(private, private->commit.state); 75 + } 76 + 77 + static int sti_drm_atomic_commit(struct drm_device *drm, 78 + struct drm_atomic_state *state, bool async) 79 + { 80 + struct sti_drm_private *private = drm->dev_private; 81 + int err; 82 + 83 + err = drm_atomic_helper_prepare_planes(drm, state); 84 + if (err) 85 + return err; 86 + 87 + /* serialize outstanding asynchronous commits */ 88 + mutex_lock(&private->commit.lock); 89 + flush_work(&private->commit.work); 90 + 91 + /* 92 + * This is the point of no return - everything below never fails except 93 + * when the hw goes bonghits. Which means we can commit the new state on 94 + * the software side now. 95 + */ 96 + 97 + drm_atomic_helper_swap_state(drm, state); 98 + 99 + if (async) 100 + sti_drm_atomic_schedule(private, state); 101 + else 102 + sti_drm_atomic_complete(private, state); 103 + 104 + mutex_unlock(&private->commit.lock); 105 + return 0; 106 + } 107 + 33 108 static struct drm_mode_config_funcs sti_drm_mode_config_funcs = { 34 109 .fb_create = drm_fb_cma_create, 110 + .atomic_check = drm_atomic_helper_check, 111 + .atomic_commit = sti_drm_atomic_commit, 35 112 }; 36 113 37 114 static void sti_drm_mode_config_init(struct drm_device *dev) ··· 142 61 dev->dev_private = (void *)private; 143 62 private->drm_dev = dev; 144 63 64 + mutex_init(&private->commit.lock); 65 + INIT_WORK(&private->commit.work, sti_drm_atomic_work); 66 + 145 67 drm_mode_config_init(dev); 146 68 drm_kms_helper_poll_init(dev); 147 69 ··· 158 74 return ret; 159 75 } 160 76 161 - drm_helper_disable_unused_functions(dev); 77 + drm_mode_config_reset(dev); 162 78 163 79 #ifdef CONFIG_DRM_STI_FBDEV 164 80 drm_fbdev_cma_init(dev, 32,
+6
drivers/gpu/drm/sti/sti_drm_drv.h
··· 24 24 struct sti_compositor *compo; 25 25 struct drm_property *plane_zorder_property; 26 26 struct drm_device *drm_dev; 27 + 28 + struct { 29 + struct drm_atomic_state *state; 30 + struct work_struct work; 31 + struct mutex lock; 32 + } commit; 27 33 }; 28 34 29 35 #endif
+60 -6
drivers/gpu/drm/sti/sti_drm_plane.c
··· 6 6 * License terms: GNU General Public License (GPL), version 2 7 7 */ 8 8 9 + #include <drm/drmP.h> 10 + #include <drm/drm_atomic_helper.h> 11 + #include <drm/drm_plane_helper.h> 12 + 9 13 #include "sti_compositor.h" 10 14 #include "sti_drm_drv.h" 11 15 #include "sti_drm_plane.h" ··· 37 33 struct sti_mixer *mixer = to_sti_mixer(crtc); 38 34 int res; 39 35 40 - DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s) drm fb:%d\n", 36 + DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", 41 37 crtc->base.id, sti_mixer_to_str(mixer), 42 - plane->base.id, sti_layer_to_str(layer), fb->base.id); 38 + plane->base.id, sti_layer_to_str(layer)); 43 39 DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", crtc_w, crtc_h, crtc_x, crtc_y); 44 40 45 41 res = sti_mixer_set_layer_depth(mixer, layer); ··· 114 110 { 115 111 DRM_DEBUG_DRIVER("\n"); 116 112 117 - sti_drm_disable_plane(plane); 113 + drm_plane_helper_disable(plane); 118 114 drm_plane_cleanup(plane); 119 115 } 120 116 ··· 137 133 } 138 134 139 135 static struct drm_plane_funcs sti_drm_plane_funcs = { 140 - .update_plane = sti_drm_update_plane, 141 - .disable_plane = sti_drm_disable_plane, 136 + .update_plane = drm_atomic_helper_update_plane, 137 + .disable_plane = drm_atomic_helper_disable_plane, 142 138 .destroy = sti_drm_plane_destroy, 143 139 .set_property = sti_drm_plane_set_property, 140 + .reset = drm_atomic_helper_plane_reset, 141 + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 142 + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 143 + }; 144 + 145 + static int sti_drm_plane_prepare_fb(struct drm_plane *plane, 146 + struct drm_framebuffer *fb, 147 + const struct drm_plane_state *new_state) 148 + { 149 + return 0; 150 + } 151 + 152 + static void sti_drm_plane_cleanup_fb(struct drm_plane *plane, 153 + struct drm_framebuffer *fb, 154 + const struct drm_plane_state *old_fb) 155 + { 156 + } 157 + 158 + static int sti_drm_plane_atomic_check(struct drm_plane *plane, 159 + struct drm_plane_state *state) 160 + { 161 + return 0; 162 + } 163 + 164 + static void sti_drm_plane_atomic_update(struct drm_plane *plane, 165 + struct drm_plane_state *oldstate) 166 + { 167 + struct drm_plane_state *state = plane->state; 168 + 169 + sti_drm_update_plane(plane, state->crtc, state->fb, 170 + state->crtc_x, state->crtc_y, 171 + state->crtc_w, state->crtc_h, 172 + state->src_x, state->src_y, 173 + state->src_w, state->src_h); 174 + } 175 + 176 + static void sti_drm_plane_atomic_disable(struct drm_plane *plane, 177 + struct drm_plane_state *oldstate) 178 + { 179 + sti_drm_disable_plane(plane); 180 + } 181 + 182 + static const struct drm_plane_helper_funcs sti_drm_plane_helpers_funcs = { 183 + .prepare_fb = sti_drm_plane_prepare_fb, 184 + .cleanup_fb = sti_drm_plane_cleanup_fb, 185 + .atomic_check = sti_drm_plane_atomic_check, 186 + .atomic_update = sti_drm_plane_atomic_update, 187 + .atomic_disable = sti_drm_plane_atomic_disable, 144 188 }; 145 189 146 190 static void sti_drm_plane_attach_zorder_property(struct drm_plane *plane, ··· 230 178 return NULL; 231 179 } 232 180 181 + drm_plane_helper_add(&layer->plane, &sti_drm_plane_helpers_funcs); 182 + 233 183 for (i = 0; i < ARRAY_SIZE(sti_layer_default_zorder); i++) 234 184 if (sti_layer_default_zorder[i] == layer->desc) 235 185 break; 236 186 237 - default_zorder = i; 187 + default_zorder = i + 1; 238 188 239 189 if (type == DRM_PLANE_TYPE_OVERLAY) 240 190 sti_drm_plane_attach_zorder_property(&layer->plane,
+5 -1
drivers/gpu/drm/sti/sti_dvo.c
··· 11 11 #include <linux/platform_device.h> 12 12 13 13 #include <drm/drmP.h> 14 + #include <drm/drm_atomic_helper.h> 14 15 #include <drm/drm_crtc_helper.h> 15 16 #include <drm/drm_panel.h> 16 17 ··· 365 364 } 366 365 367 366 static struct drm_connector_funcs sti_dvo_connector_funcs = { 368 - .dpms = drm_helper_connector_dpms, 367 + .dpms = drm_atomic_helper_connector_dpms, 369 368 .fill_modes = drm_helper_probe_single_connector_modes, 370 369 .detect = sti_dvo_connector_detect, 371 370 .destroy = sti_dvo_connector_destroy, 371 + .reset = drm_atomic_helper_connector_reset, 372 + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 373 + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 372 374 }; 373 375 374 376 static struct drm_encoder *sti_dvo_find_encoder(struct drm_device *dev)
+5 -1
drivers/gpu/drm/sti/sti_hda.c
··· 10 10 #include <linux/platform_device.h> 11 11 12 12 #include <drm/drmP.h> 13 + #include <drm/drm_atomic_helper.h> 13 14 #include <drm/drm_crtc_helper.h> 14 15 15 16 /* HDformatter registers */ ··· 612 611 } 613 612 614 613 static struct drm_connector_funcs sti_hda_connector_funcs = { 615 - .dpms = drm_helper_connector_dpms, 614 + .dpms = drm_atomic_helper_connector_dpms, 616 615 .fill_modes = drm_helper_probe_single_connector_modes, 617 616 .detect = sti_hda_connector_detect, 618 617 .destroy = sti_hda_connector_destroy, 618 + .reset = drm_atomic_helper_connector_reset, 619 + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 620 + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 619 621 }; 620 622 621 623 static struct drm_encoder *sti_hda_find_encoder(struct drm_device *dev)
+5 -1
drivers/gpu/drm/sti/sti_hdmi.c
··· 13 13 #include <linux/reset.h> 14 14 15 15 #include <drm/drmP.h> 16 + #include <drm/drm_atomic_helper.h> 16 17 #include <drm/drm_crtc_helper.h> 17 18 #include <drm/drm_edid.h> 18 19 ··· 664 663 } 665 664 666 665 static struct drm_connector_funcs sti_hdmi_connector_funcs = { 667 - .dpms = drm_helper_connector_dpms, 666 + .dpms = drm_atomic_helper_connector_dpms, 668 667 .fill_modes = drm_helper_probe_single_connector_modes, 669 668 .detect = sti_hdmi_connector_detect, 670 669 .destroy = sti_hdmi_connector_destroy, 670 + .reset = drm_atomic_helper_connector_reset, 671 + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 672 + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 671 673 }; 672 674 673 675 static struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev)