diff options
Diffstat (limited to 'drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c')
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c | 348 |
1 files changed, 104 insertions, 244 deletions
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index 7d00f7fb5773..a7672e100d8b 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c | |||
@@ -25,8 +25,6 @@ | |||
25 | struct mdp4_crtc { | 25 | struct mdp4_crtc { |
26 | struct drm_crtc base; | 26 | struct drm_crtc base; |
27 | char name[8]; | 27 | char name[8]; |
28 | struct drm_plane *plane; | ||
29 | struct drm_plane *planes[8]; | ||
30 | int id; | 28 | int id; |
31 | int ovlp; | 29 | int ovlp; |
32 | enum mdp4_dma dma; | 30 | enum mdp4_dma dma; |
@@ -52,25 +50,11 @@ struct mdp4_crtc { | |||
52 | 50 | ||
53 | /* if there is a pending flip, these will be non-null: */ | 51 | /* if there is a pending flip, these will be non-null: */ |
54 | struct drm_pending_vblank_event *event; | 52 | struct drm_pending_vblank_event *event; |
55 | struct msm_fence_cb pageflip_cb; | ||
56 | 53 | ||
57 | #define PENDING_CURSOR 0x1 | 54 | #define PENDING_CURSOR 0x1 |
58 | #define PENDING_FLIP 0x2 | 55 | #define PENDING_FLIP 0x2 |
59 | atomic_t pending; | 56 | atomic_t pending; |
60 | 57 | ||
61 | /* the fb that we logically (from PoV of KMS API) hold a ref | ||
62 | * to. Which we may not yet be scanning out (we may still | ||
63 | * be scanning out previous in case of page_flip while waiting | ||
64 | * for gpu rendering to complete: | ||
65 | */ | ||
66 | struct drm_framebuffer *fb; | ||
67 | |||
68 | /* the fb that we currently hold a scanout ref to: */ | ||
69 | struct drm_framebuffer *scanout_fb; | ||
70 | |||
71 | /* for unref'ing framebuffers after scanout completes: */ | ||
72 | struct drm_flip_work unref_fb_work; | ||
73 | |||
74 | /* for unref'ing cursor bo's after scanout completes: */ | 58 | /* for unref'ing cursor bo's after scanout completes: */ |
75 | struct drm_flip_work unref_cursor_work; | 59 | struct drm_flip_work unref_cursor_work; |
76 | 60 | ||
@@ -97,15 +81,14 @@ static void crtc_flush(struct drm_crtc *crtc) | |||
97 | { | 81 | { |
98 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); | 82 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); |
99 | struct mdp4_kms *mdp4_kms = get_kms(crtc); | 83 | struct mdp4_kms *mdp4_kms = get_kms(crtc); |
100 | uint32_t i, flush = 0; | 84 | struct drm_plane *plane; |
85 | uint32_t flush = 0; | ||
101 | 86 | ||
102 | for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) { | 87 | drm_atomic_crtc_for_each_plane(plane, crtc) { |
103 | struct drm_plane *plane = mdp4_crtc->planes[i]; | 88 | enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane); |
104 | if (plane) { | 89 | flush |= pipe2flush(pipe_id); |
105 | enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane); | ||
106 | flush |= pipe2flush(pipe_id); | ||
107 | } | ||
108 | } | 90 | } |
91 | |||
109 | flush |= ovlp2flush(mdp4_crtc->ovlp); | 92 | flush |= ovlp2flush(mdp4_crtc->ovlp); |
110 | 93 | ||
111 | DBG("%s: flush=%08x", mdp4_crtc->name, flush); | 94 | DBG("%s: flush=%08x", mdp4_crtc->name, flush); |
@@ -113,47 +96,6 @@ static void crtc_flush(struct drm_crtc *crtc) | |||
113 | mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush); | 96 | mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush); |
114 | } | 97 | } |
115 | 98 | ||
116 | static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb) | ||
117 | { | ||
118 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); | ||
119 | struct drm_framebuffer *old_fb = mdp4_crtc->fb; | ||
120 | |||
121 | /* grab reference to incoming scanout fb: */ | ||
122 | drm_framebuffer_reference(new_fb); | ||
123 | mdp4_crtc->base.primary->fb = new_fb; | ||
124 | mdp4_crtc->fb = new_fb; | ||
125 | |||
126 | if (old_fb) | ||
127 | drm_flip_work_queue(&mdp4_crtc->unref_fb_work, old_fb); | ||
128 | } | ||
129 | |||
130 | /* unlike update_fb(), take a ref to the new scanout fb *before* updating | ||
131 | * plane, then call this. Needed to ensure we don't unref the buffer that | ||
132 | * is actually still being scanned out. | ||
133 | * | ||
134 | * Note that this whole thing goes away with atomic.. since we can defer | ||
135 | * calling into driver until rendering is done. | ||
136 | */ | ||
137 | static void update_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb) | ||
138 | { | ||
139 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); | ||
140 | |||
141 | /* flush updates, to make sure hw is updated to new scanout fb, | ||
142 | * so that we can safely queue unref to current fb (ie. next | ||
143 | * vblank we know hw is done w/ previous scanout_fb). | ||
144 | */ | ||
145 | crtc_flush(crtc); | ||
146 | |||
147 | if (mdp4_crtc->scanout_fb) | ||
148 | drm_flip_work_queue(&mdp4_crtc->unref_fb_work, | ||
149 | mdp4_crtc->scanout_fb); | ||
150 | |||
151 | mdp4_crtc->scanout_fb = fb; | ||
152 | |||
153 | /* enable vblank to complete flip: */ | ||
154 | request_pending(crtc, PENDING_FLIP); | ||
155 | } | ||
156 | |||
157 | /* if file!=NULL, this is preclose potential cancel-flip path */ | 99 | /* if file!=NULL, this is preclose potential cancel-flip path */ |
158 | static void complete_flip(struct drm_crtc *crtc, struct drm_file *file) | 100 | static void complete_flip(struct drm_crtc *crtc, struct drm_file *file) |
159 | { | 101 | { |
@@ -171,38 +113,13 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file) | |||
171 | */ | 113 | */ |
172 | if (!file || (event->base.file_priv == file)) { | 114 | if (!file || (event->base.file_priv == file)) { |
173 | mdp4_crtc->event = NULL; | 115 | mdp4_crtc->event = NULL; |
116 | DBG("%s: send event: %p", mdp4_crtc->name, event); | ||
174 | drm_send_vblank_event(dev, mdp4_crtc->id, event); | 117 | drm_send_vblank_event(dev, mdp4_crtc->id, event); |
175 | } | 118 | } |
176 | } | 119 | } |
177 | spin_unlock_irqrestore(&dev->event_lock, flags); | 120 | spin_unlock_irqrestore(&dev->event_lock, flags); |
178 | } | 121 | } |
179 | 122 | ||
180 | static void pageflip_cb(struct msm_fence_cb *cb) | ||
181 | { | ||
182 | struct mdp4_crtc *mdp4_crtc = | ||
183 | container_of(cb, struct mdp4_crtc, pageflip_cb); | ||
184 | struct drm_crtc *crtc = &mdp4_crtc->base; | ||
185 | struct drm_framebuffer *fb = crtc->primary->fb; | ||
186 | |||
187 | if (!fb) | ||
188 | return; | ||
189 | |||
190 | drm_framebuffer_reference(fb); | ||
191 | mdp4_plane_set_scanout(mdp4_crtc->plane, fb); | ||
192 | update_scanout(crtc, fb); | ||
193 | } | ||
194 | |||
195 | static void unref_fb_worker(struct drm_flip_work *work, void *val) | ||
196 | { | ||
197 | struct mdp4_crtc *mdp4_crtc = | ||
198 | container_of(work, struct mdp4_crtc, unref_fb_work); | ||
199 | struct drm_device *dev = mdp4_crtc->base.dev; | ||
200 | |||
201 | mutex_lock(&dev->mode_config.mutex); | ||
202 | drm_framebuffer_unreference(val); | ||
203 | mutex_unlock(&dev->mode_config.mutex); | ||
204 | } | ||
205 | |||
206 | static void unref_cursor_worker(struct drm_flip_work *work, void *val) | 123 | static void unref_cursor_worker(struct drm_flip_work *work, void *val) |
207 | { | 124 | { |
208 | struct mdp4_crtc *mdp4_crtc = | 125 | struct mdp4_crtc *mdp4_crtc = |
@@ -218,7 +135,6 @@ static void mdp4_crtc_destroy(struct drm_crtc *crtc) | |||
218 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); | 135 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); |
219 | 136 | ||
220 | drm_crtc_cleanup(crtc); | 137 | drm_crtc_cleanup(crtc); |
221 | drm_flip_work_cleanup(&mdp4_crtc->unref_fb_work); | ||
222 | drm_flip_work_cleanup(&mdp4_crtc->unref_cursor_work); | 138 | drm_flip_work_cleanup(&mdp4_crtc->unref_cursor_work); |
223 | 139 | ||
224 | kfree(mdp4_crtc); | 140 | kfree(mdp4_crtc); |
@@ -251,57 +167,70 @@ static bool mdp4_crtc_mode_fixup(struct drm_crtc *crtc, | |||
251 | return true; | 167 | return true; |
252 | } | 168 | } |
253 | 169 | ||
254 | static void blend_setup(struct drm_crtc *crtc) | 170 | /* statically (for now) map planes to mixer stage (z-order): */ |
171 | static const int idxs[] = { | ||
172 | [VG1] = 1, | ||
173 | [VG2] = 2, | ||
174 | [RGB1] = 0, | ||
175 | [RGB2] = 0, | ||
176 | [RGB3] = 0, | ||
177 | [VG3] = 3, | ||
178 | [VG4] = 4, | ||
179 | |||
180 | }; | ||
181 | |||
182 | /* setup mixer config, for which we need to consider all crtc's and | ||
183 | * the planes attached to them | ||
184 | * | ||
185 | * TODO may possibly need some extra locking here | ||
186 | */ | ||
187 | static void setup_mixer(struct mdp4_kms *mdp4_kms) | ||
255 | { | 188 | { |
256 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); | 189 | struct drm_mode_config *config = &mdp4_kms->dev->mode_config; |
257 | struct mdp4_kms *mdp4_kms = get_kms(crtc); | 190 | struct drm_crtc *crtc; |
258 | int i, ovlp = mdp4_crtc->ovlp; | ||
259 | uint32_t mixer_cfg = 0; | 191 | uint32_t mixer_cfg = 0; |
260 | static const enum mdp_mixer_stage_id stages[] = { | 192 | static const enum mdp_mixer_stage_id stages[] = { |
261 | STAGE_BASE, STAGE0, STAGE1, STAGE2, STAGE3, | 193 | STAGE_BASE, STAGE0, STAGE1, STAGE2, STAGE3, |
262 | }; | 194 | }; |
263 | /* statically (for now) map planes to mixer stage (z-order): */ | ||
264 | static const int idxs[] = { | ||
265 | [VG1] = 1, | ||
266 | [VG2] = 2, | ||
267 | [RGB1] = 0, | ||
268 | [RGB2] = 0, | ||
269 | [RGB3] = 0, | ||
270 | [VG3] = 3, | ||
271 | [VG4] = 4, | ||
272 | 195 | ||
273 | }; | 196 | list_for_each_entry(crtc, &config->crtc_list, head) { |
274 | bool alpha[4]= { false, false, false, false }; | 197 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); |
198 | struct drm_plane *plane; | ||
275 | 199 | ||
276 | /* Don't rely on value read back from hw, but instead use our | 200 | drm_atomic_crtc_for_each_plane(plane, crtc) { |
277 | * own shadowed value. Possibly disable/reenable looses the | 201 | enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane); |
278 | * previous value and goes back to power-on default? | 202 | int idx = idxs[pipe_id]; |
279 | */ | 203 | mixer_cfg = mixercfg(mixer_cfg, mdp4_crtc->mixer, |
280 | mixer_cfg = mdp4_kms->mixer_cfg; | 204 | pipe_id, stages[idx]); |
205 | } | ||
206 | } | ||
207 | |||
208 | mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, mixer_cfg); | ||
209 | } | ||
210 | |||
211 | static void blend_setup(struct drm_crtc *crtc) | ||
212 | { | ||
213 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); | ||
214 | struct mdp4_kms *mdp4_kms = get_kms(crtc); | ||
215 | struct drm_plane *plane; | ||
216 | int i, ovlp = mdp4_crtc->ovlp; | ||
217 | bool alpha[4]= { false, false, false, false }; | ||
281 | 218 | ||
282 | mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW0(ovlp), 0); | 219 | mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW0(ovlp), 0); |
283 | mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW1(ovlp), 0); | 220 | mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW1(ovlp), 0); |
284 | mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH0(ovlp), 0); | 221 | mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH0(ovlp), 0); |
285 | mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH1(ovlp), 0); | 222 | mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH1(ovlp), 0); |
286 | 223 | ||
287 | for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) { | 224 | drm_atomic_crtc_for_each_plane(plane, crtc) { |
288 | struct drm_plane *plane = mdp4_crtc->planes[i]; | 225 | enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane); |
289 | if (plane) { | 226 | int idx = idxs[pipe_id]; |
290 | enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane); | 227 | if (idx > 0) { |
291 | int idx = idxs[pipe_id]; | 228 | const struct mdp_format *format = |
292 | if (idx > 0) { | ||
293 | const struct mdp_format *format = | ||
294 | to_mdp_format(msm_framebuffer_format(plane->fb)); | 229 | to_mdp_format(msm_framebuffer_format(plane->fb)); |
295 | alpha[idx-1] = format->alpha_enable; | 230 | alpha[idx-1] = format->alpha_enable; |
296 | } | ||
297 | mixer_cfg = mixercfg(mixer_cfg, mdp4_crtc->mixer, | ||
298 | pipe_id, stages[idx]); | ||
299 | } | 231 | } |
300 | } | 232 | } |
301 | 233 | ||
302 | /* this shouldn't happen.. and seems to cause underflow: */ | ||
303 | WARN_ON(!mixer_cfg); | ||
304 | |||
305 | for (i = 0; i < 4; i++) { | 234 | for (i = 0; i < 4; i++) { |
306 | uint32_t op; | 235 | uint32_t op; |
307 | 236 | ||
@@ -324,22 +253,21 @@ static void blend_setup(struct drm_crtc *crtc) | |||
324 | mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH1(ovlp, i), 0); | 253 | mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH1(ovlp, i), 0); |
325 | } | 254 | } |
326 | 255 | ||
327 | mdp4_kms->mixer_cfg = mixer_cfg; | 256 | setup_mixer(mdp4_kms); |
328 | mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, mixer_cfg); | ||
329 | } | 257 | } |
330 | 258 | ||
331 | static int mdp4_crtc_mode_set(struct drm_crtc *crtc, | 259 | static void mdp4_crtc_mode_set_nofb(struct drm_crtc *crtc) |
332 | struct drm_display_mode *mode, | ||
333 | struct drm_display_mode *adjusted_mode, | ||
334 | int x, int y, | ||
335 | struct drm_framebuffer *old_fb) | ||
336 | { | 260 | { |
337 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); | 261 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); |
338 | struct mdp4_kms *mdp4_kms = get_kms(crtc); | 262 | struct mdp4_kms *mdp4_kms = get_kms(crtc); |
339 | enum mdp4_dma dma = mdp4_crtc->dma; | 263 | enum mdp4_dma dma = mdp4_crtc->dma; |
340 | int ret, ovlp = mdp4_crtc->ovlp; | 264 | int ovlp = mdp4_crtc->ovlp; |
265 | struct drm_display_mode *mode; | ||
266 | |||
267 | if (WARN_ON(!crtc->state)) | ||
268 | return; | ||
341 | 269 | ||
342 | mode = adjusted_mode; | 270 | mode = &crtc->state->adjusted_mode; |
343 | 271 | ||
344 | DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", | 272 | DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", |
345 | mdp4_crtc->name, mode->base.id, mode->name, | 273 | mdp4_crtc->name, mode->base.id, mode->name, |
@@ -350,28 +278,13 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc, | |||
350 | mode->vsync_end, mode->vtotal, | 278 | mode->vsync_end, mode->vtotal, |
351 | mode->type, mode->flags); | 279 | mode->type, mode->flags); |
352 | 280 | ||
353 | /* grab extra ref for update_scanout() */ | ||
354 | drm_framebuffer_reference(crtc->primary->fb); | ||
355 | |||
356 | ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->primary->fb, | ||
357 | 0, 0, mode->hdisplay, mode->vdisplay, | ||
358 | x << 16, y << 16, | ||
359 | mode->hdisplay << 16, mode->vdisplay << 16); | ||
360 | if (ret) { | ||
361 | drm_framebuffer_unreference(crtc->primary->fb); | ||
362 | dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n", | ||
363 | mdp4_crtc->name, ret); | ||
364 | return ret; | ||
365 | } | ||
366 | |||
367 | mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_SIZE(dma), | 281 | mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_SIZE(dma), |
368 | MDP4_DMA_SRC_SIZE_WIDTH(mode->hdisplay) | | 282 | MDP4_DMA_SRC_SIZE_WIDTH(mode->hdisplay) | |
369 | MDP4_DMA_SRC_SIZE_HEIGHT(mode->vdisplay)); | 283 | MDP4_DMA_SRC_SIZE_HEIGHT(mode->vdisplay)); |
370 | 284 | ||
371 | /* take data from pipe: */ | 285 | /* take data from pipe: */ |
372 | mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_BASE(dma), 0); | 286 | mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_BASE(dma), 0); |
373 | mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_STRIDE(dma), | 287 | mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_STRIDE(dma), 0); |
374 | crtc->primary->fb->pitches[0]); | ||
375 | mdp4_write(mdp4_kms, REG_MDP4_DMA_DST_SIZE(dma), | 288 | mdp4_write(mdp4_kms, REG_MDP4_DMA_DST_SIZE(dma), |
376 | MDP4_DMA_DST_SIZE_WIDTH(0) | | 289 | MDP4_DMA_DST_SIZE_WIDTH(0) | |
377 | MDP4_DMA_DST_SIZE_HEIGHT(0)); | 290 | MDP4_DMA_DST_SIZE_HEIGHT(0)); |
@@ -380,8 +293,7 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc, | |||
380 | mdp4_write(mdp4_kms, REG_MDP4_OVLP_SIZE(ovlp), | 293 | mdp4_write(mdp4_kms, REG_MDP4_OVLP_SIZE(ovlp), |
381 | MDP4_OVLP_SIZE_WIDTH(mode->hdisplay) | | 294 | MDP4_OVLP_SIZE_WIDTH(mode->hdisplay) | |
382 | MDP4_OVLP_SIZE_HEIGHT(mode->vdisplay)); | 295 | MDP4_OVLP_SIZE_HEIGHT(mode->vdisplay)); |
383 | mdp4_write(mdp4_kms, REG_MDP4_OVLP_STRIDE(ovlp), | 296 | mdp4_write(mdp4_kms, REG_MDP4_OVLP_STRIDE(ovlp), 0); |
384 | crtc->primary->fb->pitches[0]); | ||
385 | 297 | ||
386 | mdp4_write(mdp4_kms, REG_MDP4_OVLP_CFG(ovlp), 1); | 298 | mdp4_write(mdp4_kms, REG_MDP4_OVLP_CFG(ovlp), 1); |
387 | 299 | ||
@@ -390,11 +302,6 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc, | |||
390 | mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(1), 0x00ff0000); | 302 | mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(1), 0x00ff0000); |
391 | mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(2), 0x00ff0000); | 303 | mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(2), 0x00ff0000); |
392 | } | 304 | } |
393 | |||
394 | update_fb(crtc, crtc->primary->fb); | ||
395 | update_scanout(crtc, crtc->primary->fb); | ||
396 | |||
397 | return 0; | ||
398 | } | 305 | } |
399 | 306 | ||
400 | static void mdp4_crtc_prepare(struct drm_crtc *crtc) | 307 | static void mdp4_crtc_prepare(struct drm_crtc *crtc) |
@@ -416,60 +323,51 @@ static void mdp4_crtc_commit(struct drm_crtc *crtc) | |||
416 | drm_crtc_vblank_put(crtc); | 323 | drm_crtc_vblank_put(crtc); |
417 | } | 324 | } |
418 | 325 | ||
419 | static int mdp4_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | 326 | static void mdp4_crtc_load_lut(struct drm_crtc *crtc) |
420 | struct drm_framebuffer *old_fb) | 327 | { |
328 | } | ||
329 | |||
330 | static int mdp4_crtc_atomic_check(struct drm_crtc *crtc, | ||
331 | struct drm_crtc_state *state) | ||
421 | { | 332 | { |
422 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); | 333 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); |
423 | struct drm_plane *plane = mdp4_crtc->plane; | 334 | struct drm_device *dev = crtc->dev; |
424 | struct drm_display_mode *mode = &crtc->mode; | ||
425 | int ret; | ||
426 | 335 | ||
427 | /* grab extra ref for update_scanout() */ | 336 | DBG("%s: check", mdp4_crtc->name); |
428 | drm_framebuffer_reference(crtc->primary->fb); | ||
429 | 337 | ||
430 | ret = mdp4_plane_mode_set(plane, crtc, crtc->primary->fb, | 338 | if (mdp4_crtc->event) { |
431 | 0, 0, mode->hdisplay, mode->vdisplay, | 339 | dev_err(dev->dev, "already pending flip!\n"); |
432 | x << 16, y << 16, | 340 | return -EBUSY; |
433 | mode->hdisplay << 16, mode->vdisplay << 16); | ||
434 | if (ret) { | ||
435 | drm_framebuffer_unreference(crtc->primary->fb); | ||
436 | return ret; | ||
437 | } | 341 | } |
438 | 342 | ||
439 | update_fb(crtc, crtc->primary->fb); | 343 | // TODO anything else to check? |
440 | update_scanout(crtc, crtc->primary->fb); | ||
441 | 344 | ||
442 | return 0; | 345 | return 0; |
443 | } | 346 | } |
444 | 347 | ||
445 | static void mdp4_crtc_load_lut(struct drm_crtc *crtc) | 348 | static void mdp4_crtc_atomic_begin(struct drm_crtc *crtc) |
446 | { | 349 | { |
350 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); | ||
351 | DBG("%s: begin", mdp4_crtc->name); | ||
447 | } | 352 | } |
448 | 353 | ||
449 | static int mdp4_crtc_page_flip(struct drm_crtc *crtc, | 354 | static void mdp4_crtc_atomic_flush(struct drm_crtc *crtc) |
450 | struct drm_framebuffer *new_fb, | ||
451 | struct drm_pending_vblank_event *event, | ||
452 | uint32_t page_flip_flags) | ||
453 | { | 355 | { |
454 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); | 356 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); |
455 | struct drm_device *dev = crtc->dev; | 357 | struct drm_device *dev = crtc->dev; |
456 | struct drm_gem_object *obj; | ||
457 | unsigned long flags; | 358 | unsigned long flags; |
458 | 359 | ||
459 | if (mdp4_crtc->event) { | 360 | DBG("%s: flush", mdp4_crtc->name); |
460 | dev_err(dev->dev, "already pending flip!\n"); | ||
461 | return -EBUSY; | ||
462 | } | ||
463 | 361 | ||
464 | obj = msm_framebuffer_bo(new_fb, 0); | 362 | WARN_ON(mdp4_crtc->event); |
465 | 363 | ||
466 | spin_lock_irqsave(&dev->event_lock, flags); | 364 | spin_lock_irqsave(&dev->event_lock, flags); |
467 | mdp4_crtc->event = event; | 365 | mdp4_crtc->event = crtc->state->event; |
468 | spin_unlock_irqrestore(&dev->event_lock, flags); | 366 | spin_unlock_irqrestore(&dev->event_lock, flags); |
469 | 367 | ||
470 | update_fb(crtc, new_fb); | 368 | blend_setup(crtc); |
471 | 369 | crtc_flush(crtc); | |
472 | return msm_gem_queue_inactive_cb(obj, &mdp4_crtc->pageflip_cb); | 370 | request_pending(crtc, PENDING_FLIP); |
473 | } | 371 | } |
474 | 372 | ||
475 | static int mdp4_crtc_set_property(struct drm_crtc *crtc, | 373 | static int mdp4_crtc_set_property(struct drm_crtc *crtc, |
@@ -607,22 +505,29 @@ static int mdp4_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) | |||
607 | } | 505 | } |
608 | 506 | ||
609 | static const struct drm_crtc_funcs mdp4_crtc_funcs = { | 507 | static const struct drm_crtc_funcs mdp4_crtc_funcs = { |
610 | .set_config = drm_crtc_helper_set_config, | 508 | .set_config = drm_atomic_helper_set_config, |
611 | .destroy = mdp4_crtc_destroy, | 509 | .destroy = mdp4_crtc_destroy, |
612 | .page_flip = mdp4_crtc_page_flip, | 510 | .page_flip = drm_atomic_helper_page_flip, |
613 | .set_property = mdp4_crtc_set_property, | 511 | .set_property = mdp4_crtc_set_property, |
614 | .cursor_set = mdp4_crtc_cursor_set, | 512 | .cursor_set = mdp4_crtc_cursor_set, |
615 | .cursor_move = mdp4_crtc_cursor_move, | 513 | .cursor_move = mdp4_crtc_cursor_move, |
514 | .reset = drm_atomic_helper_crtc_reset, | ||
515 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, | ||
516 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, | ||
616 | }; | 517 | }; |
617 | 518 | ||
618 | static const struct drm_crtc_helper_funcs mdp4_crtc_helper_funcs = { | 519 | static const struct drm_crtc_helper_funcs mdp4_crtc_helper_funcs = { |
619 | .dpms = mdp4_crtc_dpms, | 520 | .dpms = mdp4_crtc_dpms, |
620 | .mode_fixup = mdp4_crtc_mode_fixup, | 521 | .mode_fixup = mdp4_crtc_mode_fixup, |
621 | .mode_set = mdp4_crtc_mode_set, | 522 | .mode_set_nofb = mdp4_crtc_mode_set_nofb, |
523 | .mode_set = drm_helper_crtc_mode_set, | ||
524 | .mode_set_base = drm_helper_crtc_mode_set_base, | ||
622 | .prepare = mdp4_crtc_prepare, | 525 | .prepare = mdp4_crtc_prepare, |
623 | .commit = mdp4_crtc_commit, | 526 | .commit = mdp4_crtc_commit, |
624 | .mode_set_base = mdp4_crtc_mode_set_base, | ||
625 | .load_lut = mdp4_crtc_load_lut, | 527 | .load_lut = mdp4_crtc_load_lut, |
528 | .atomic_check = mdp4_crtc_atomic_check, | ||
529 | .atomic_begin = mdp4_crtc_atomic_begin, | ||
530 | .atomic_flush = mdp4_crtc_atomic_flush, | ||
626 | }; | 531 | }; |
627 | 532 | ||
628 | static void mdp4_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus) | 533 | static void mdp4_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus) |
@@ -638,7 +543,6 @@ static void mdp4_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus) | |||
638 | 543 | ||
639 | if (pending & PENDING_FLIP) { | 544 | if (pending & PENDING_FLIP) { |
640 | complete_flip(crtc, NULL); | 545 | complete_flip(crtc, NULL); |
641 | drm_flip_work_commit(&mdp4_crtc->unref_fb_work, priv->wq); | ||
642 | } | 546 | } |
643 | 547 | ||
644 | if (pending & PENDING_CURSOR) { | 548 | if (pending & PENDING_CURSOR) { |
@@ -663,7 +567,8 @@ uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc) | |||
663 | 567 | ||
664 | void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file) | 568 | void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file) |
665 | { | 569 | { |
666 | DBG("cancel: %p", file); | 570 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); |
571 | DBG("%s: cancel: %p", mdp4_crtc->name, file); | ||
667 | complete_flip(crtc, file); | 572 | complete_flip(crtc, file); |
668 | } | 573 | } |
669 | 574 | ||
@@ -717,35 +622,6 @@ void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer) | |||
717 | mdp4_write(mdp4_kms, REG_MDP4_DISP_INTF_SEL, intf_sel); | 622 | mdp4_write(mdp4_kms, REG_MDP4_DISP_INTF_SEL, intf_sel); |
718 | } | 623 | } |
719 | 624 | ||
720 | static void set_attach(struct drm_crtc *crtc, enum mdp4_pipe pipe_id, | ||
721 | struct drm_plane *plane) | ||
722 | { | ||
723 | struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); | ||
724 | |||
725 | BUG_ON(pipe_id >= ARRAY_SIZE(mdp4_crtc->planes)); | ||
726 | |||
727 | if (mdp4_crtc->planes[pipe_id] == plane) | ||
728 | return; | ||
729 | |||
730 | mdp4_crtc->planes[pipe_id] = plane; | ||
731 | blend_setup(crtc); | ||
732 | if (mdp4_crtc->enabled && (plane != mdp4_crtc->plane)) | ||
733 | crtc_flush(crtc); | ||
734 | } | ||
735 | |||
736 | void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane) | ||
737 | { | ||
738 | set_attach(crtc, mdp4_plane_pipe(plane), plane); | ||
739 | } | ||
740 | |||
741 | void mdp4_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane) | ||
742 | { | ||
743 | /* don't actually detatch our primary plane: */ | ||
744 | if (to_mdp4_crtc(crtc)->plane == plane) | ||
745 | return; | ||
746 | set_attach(crtc, mdp4_plane_pipe(plane), NULL); | ||
747 | } | ||
748 | |||
749 | static const char *dma_names[] = { | 625 | static const char *dma_names[] = { |
750 | "DMA_P", "DMA_S", "DMA_E", | 626 | "DMA_P", "DMA_S", "DMA_E", |
751 | }; | 627 | }; |
@@ -757,17 +633,13 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev, | |||
757 | { | 633 | { |
758 | struct drm_crtc *crtc = NULL; | 634 | struct drm_crtc *crtc = NULL; |
759 | struct mdp4_crtc *mdp4_crtc; | 635 | struct mdp4_crtc *mdp4_crtc; |
760 | int ret; | ||
761 | 636 | ||
762 | mdp4_crtc = kzalloc(sizeof(*mdp4_crtc), GFP_KERNEL); | 637 | mdp4_crtc = kzalloc(sizeof(*mdp4_crtc), GFP_KERNEL); |
763 | if (!mdp4_crtc) { | 638 | if (!mdp4_crtc) |
764 | ret = -ENOMEM; | 639 | return ERR_PTR(-ENOMEM); |
765 | goto fail; | ||
766 | } | ||
767 | 640 | ||
768 | crtc = &mdp4_crtc->base; | 641 | crtc = &mdp4_crtc->base; |
769 | 642 | ||
770 | mdp4_crtc->plane = plane; | ||
771 | mdp4_crtc->id = id; | 643 | mdp4_crtc->id = id; |
772 | 644 | ||
773 | mdp4_crtc->ovlp = ovlp_id; | 645 | mdp4_crtc->ovlp = ovlp_id; |
@@ -784,26 +656,14 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev, | |||
784 | 656 | ||
785 | spin_lock_init(&mdp4_crtc->cursor.lock); | 657 | spin_lock_init(&mdp4_crtc->cursor.lock); |
786 | 658 | ||
787 | ret = drm_flip_work_init(&mdp4_crtc->unref_fb_work, 16, | 659 | drm_flip_work_init(&mdp4_crtc->unref_cursor_work, |
788 | "unref fb", unref_fb_worker); | ||
789 | if (ret) | ||
790 | goto fail; | ||
791 | |||
792 | ret = drm_flip_work_init(&mdp4_crtc->unref_cursor_work, 64, | ||
793 | "unref cursor", unref_cursor_worker); | 660 | "unref cursor", unref_cursor_worker); |
794 | 661 | ||
795 | INIT_FENCE_CB(&mdp4_crtc->pageflip_cb, pageflip_cb); | ||
796 | |||
797 | drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp4_crtc_funcs); | 662 | drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp4_crtc_funcs); |
798 | drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs); | 663 | drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs); |
664 | plane->crtc = crtc; | ||
799 | 665 | ||
800 | mdp4_plane_install_properties(mdp4_crtc->plane, &crtc->base); | 666 | mdp4_plane_install_properties(plane, &crtc->base); |
801 | 667 | ||
802 | return crtc; | 668 | return crtc; |
803 | |||
804 | fail: | ||
805 | if (crtc) | ||
806 | mdp4_crtc_destroy(crtc); | ||
807 | |||
808 | return ERR_PTR(ret); | ||
809 | } | 669 | } |