aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-01-31 17:43:42 -0500
committerDave Airlie <airlied@redhat.com>2017-01-31 17:43:42 -0500
commit18566acac18f5784347bc5fe636a26897d1c963b (patch)
tree14eb4a9c01d55040ce3564b014d792c14c0f09ac /drivers/gpu/drm
parent02a84c135ee94924c094fdbb70030a49cddbe85b (diff)
parente41456bfc811f12b5dcda6f2d6849bdff68f6c0a (diff)
Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
adding runtime PM support to MIC driver, and including some cleanups - especially using atomic helper functions instead of specific ones - and fixups. * 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: drm/exynos: g2d: prevent integer overflow in drm/exynos: fix a timeout loop drm/exynos: use atomic helper commit drm/exynos: remove unnecessary codes drm/exynos: mic: Add runtime PM support drm/exynos: Stop using drm_framebuffer_unregister_private drm/exynos: mic: Fix parse_dt function drm/exynos: mic: Add mode_set callback function
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c28
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.h4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c114
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.c32
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_g2d.c17
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_mic.c126
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c2
8 files changed, 131 insertions, 196 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 309c8ee52524..5367b6664fe3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -39,6 +39,14 @@ static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
39 39
40 if (exynos_crtc->ops->disable) 40 if (exynos_crtc->ops->disable)
41 exynos_crtc->ops->disable(exynos_crtc); 41 exynos_crtc->ops->disable(exynos_crtc);
42
43 if (crtc->state->event && !crtc->state->active) {
44 spin_lock_irq(&crtc->dev->event_lock);
45 drm_crtc_send_vblank_event(crtc, crtc->state->event);
46 spin_unlock_irq(&crtc->dev->event_lock);
47
48 crtc->state->event = NULL;
49 }
42} 50}
43 51
44static void 52static void
@@ -203,23 +211,3 @@ void exynos_drm_crtc_te_handler(struct drm_crtc *crtc)
203 if (exynos_crtc->ops->te_handler) 211 if (exynos_crtc->ops->te_handler)
204 exynos_crtc->ops->te_handler(exynos_crtc); 212 exynos_crtc->ops->te_handler(exynos_crtc);
205} 213}
206
207void exynos_drm_crtc_cancel_page_flip(struct drm_crtc *crtc,
208 struct drm_file *file)
209{
210 struct drm_pending_vblank_event *e;
211 unsigned long flags;
212
213 spin_lock_irqsave(&crtc->dev->event_lock, flags);
214
215 e = crtc->state->event;
216 if (e && e->base.file_priv == file)
217 crtc->state->event = NULL;
218 else
219 e = NULL;
220
221 spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
222
223 if (e)
224 drm_event_cancel_free(crtc->dev, &e->base);
225}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
index cfdcf3e4eb1b..6a581a8af465 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
@@ -40,8 +40,4 @@ int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
40 */ 40 */
41void exynos_drm_crtc_te_handler(struct drm_crtc *crtc); 41void exynos_drm_crtc_te_handler(struct drm_crtc *crtc);
42 42
43/* This function cancels a page flip request. */
44void exynos_drm_crtc_cancel_page_flip(struct drm_crtc *crtc,
45 struct drm_file *file);
46
47#endif 43#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 3ec053542e93..035d02ecffcd 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -38,56 +38,6 @@
38#define DRIVER_MAJOR 1 38#define DRIVER_MAJOR 1
39#define DRIVER_MINOR 0 39#define DRIVER_MINOR 0
40 40
41struct exynos_atomic_commit {
42 struct work_struct work;
43 struct drm_device *dev;
44 struct drm_atomic_state *state;
45 u32 crtcs;
46};
47
48static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit)
49{
50 struct drm_device *dev = commit->dev;
51 struct exynos_drm_private *priv = dev->dev_private;
52 struct drm_atomic_state *state = commit->state;
53
54 drm_atomic_helper_commit_modeset_disables(dev, state);
55
56 drm_atomic_helper_commit_modeset_enables(dev, state);
57
58 /*
59 * Exynos can't update planes with CRTCs and encoders disabled,
60 * its updates routines, specially for FIMD, requires the clocks
61 * to be enabled. So it is necessary to handle the modeset operations
62 * *before* the commit_planes() step, this way it will always
63 * have the relevant clocks enabled to perform the update.
64 */
65
66 drm_atomic_helper_commit_planes(dev, state, 0);
67
68 drm_atomic_helper_wait_for_vblanks(dev, state);
69
70 drm_atomic_helper_cleanup_planes(dev, state);
71
72 drm_atomic_state_put(state);
73
74 spin_lock(&priv->lock);
75 priv->pending &= ~commit->crtcs;
76 spin_unlock(&priv->lock);
77
78 wake_up_all(&priv->wait);
79
80 kfree(commit);
81}
82
83static void exynos_drm_atomic_work(struct work_struct *work)
84{
85 struct exynos_atomic_commit *commit = container_of(work,
86 struct exynos_atomic_commit, work);
87
88 exynos_atomic_commit_complete(commit);
89}
90
91static struct device *exynos_drm_get_dma_device(void); 41static struct device *exynos_drm_get_dma_device(void);
92 42
93static int exynos_drm_load(struct drm_device *dev, unsigned long flags) 43static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
@@ -202,65 +152,6 @@ static void exynos_drm_unload(struct drm_device *dev)
202 dev->dev_private = NULL; 152 dev->dev_private = NULL;
203} 153}
204 154
205static int commit_is_pending(struct exynos_drm_private *priv, u32 crtcs)
206{
207 bool pending;
208
209 spin_lock(&priv->lock);
210 pending = priv->pending & crtcs;
211 spin_unlock(&priv->lock);
212
213 return pending;
214}
215
216int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state,
217 bool nonblock)
218{
219 struct exynos_drm_private *priv = dev->dev_private;
220 struct exynos_atomic_commit *commit;
221 struct drm_crtc *crtc;
222 struct drm_crtc_state *crtc_state;
223 int i, ret;
224
225 commit = kzalloc(sizeof(*commit), GFP_KERNEL);
226 if (!commit)
227 return -ENOMEM;
228
229 ret = drm_atomic_helper_prepare_planes(dev, state);
230 if (ret) {
231 kfree(commit);
232 return ret;
233 }
234
235 /* This is the point of no return */
236
237 INIT_WORK(&commit->work, exynos_drm_atomic_work);
238 commit->dev = dev;
239 commit->state = state;
240
241 /* Wait until all affected CRTCs have completed previous commits and
242 * mark them as pending.
243 */
244 for_each_crtc_in_state(state, crtc, crtc_state, i)
245 commit->crtcs |= drm_crtc_mask(crtc);
246
247 wait_event(priv->wait, !commit_is_pending(priv, commit->crtcs));
248
249 spin_lock(&priv->lock);
250 priv->pending |= commit->crtcs;
251 spin_unlock(&priv->lock);
252
253 drm_atomic_helper_swap_state(state, true);
254
255 drm_atomic_state_get(state);
256 if (nonblock)
257 schedule_work(&commit->work);
258 else
259 exynos_atomic_commit_complete(commit);
260
261 return 0;
262}
263
264int exynos_atomic_check(struct drm_device *dev, 155int exynos_atomic_check(struct drm_device *dev,
265 struct drm_atomic_state *state) 156 struct drm_atomic_state *state)
266{ 157{
@@ -307,12 +198,7 @@ err_file_priv_free:
307static void exynos_drm_preclose(struct drm_device *dev, 198static void exynos_drm_preclose(struct drm_device *dev,
308 struct drm_file *file) 199 struct drm_file *file)
309{ 200{
310 struct drm_crtc *crtc;
311
312 exynos_drm_subdrv_close(dev, file); 201 exynos_drm_subdrv_close(dev, file);
313
314 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
315 exynos_drm_crtc_cancel_page_flip(crtc, file);
316} 202}
317 203
318static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) 204static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index 68d414227533..c77a5aced81a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -187,11 +187,40 @@ dma_addr_t exynos_drm_fb_dma_addr(struct drm_framebuffer *fb, int index)
187 return exynos_fb->dma_addr[index]; 187 return exynos_fb->dma_addr[index];
188} 188}
189 189
190static void exynos_drm_atomic_commit_tail(struct drm_atomic_state *state)
191{
192 struct drm_device *dev = state->dev;
193
194 drm_atomic_helper_commit_modeset_disables(dev, state);
195
196 drm_atomic_helper_commit_modeset_enables(dev, state);
197
198 /*
199 * Exynos can't update planes with CRTCs and encoders disabled,
200 * its updates routines, specially for FIMD, requires the clocks
201 * to be enabled. So it is necessary to handle the modeset operations
202 * *before* the commit_planes() step, this way it will always
203 * have the relevant clocks enabled to perform the update.
204 */
205 drm_atomic_helper_commit_planes(dev, state,
206 DRM_PLANE_COMMIT_ACTIVE_ONLY);
207
208 drm_atomic_helper_commit_hw_done(state);
209
210 drm_atomic_helper_wait_for_vblanks(dev, state);
211
212 drm_atomic_helper_cleanup_planes(dev, state);
213}
214
215static struct drm_mode_config_helper_funcs exynos_drm_mode_config_helpers = {
216 .atomic_commit_tail = exynos_drm_atomic_commit_tail,
217};
218
190static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = { 219static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
191 .fb_create = exynos_user_fb_create, 220 .fb_create = exynos_user_fb_create,
192 .output_poll_changed = exynos_drm_output_poll_changed, 221 .output_poll_changed = exynos_drm_output_poll_changed,
193 .atomic_check = exynos_atomic_check, 222 .atomic_check = exynos_atomic_check,
194 .atomic_commit = exynos_atomic_commit, 223 .atomic_commit = drm_atomic_helper_commit,
195}; 224};
196 225
197void exynos_drm_mode_config_init(struct drm_device *dev) 226void exynos_drm_mode_config_init(struct drm_device *dev)
@@ -208,4 +237,5 @@ void exynos_drm_mode_config_init(struct drm_device *dev)
208 dev->mode_config.max_height = 4096; 237 dev->mode_config.max_height = 4096;
209 238
210 dev->mode_config.funcs = &exynos_drm_mode_config_funcs; 239 dev->mode_config.funcs = &exynos_drm_mode_config_funcs;
240 dev->mode_config.helper_private = &exynos_drm_mode_config_helpers;
211} 241}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index d8808158d418..a7884bea42eb 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -270,10 +270,8 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev,
270 /* release drm framebuffer and real buffer */ 270 /* release drm framebuffer and real buffer */
271 if (fb_helper->fb && fb_helper->fb->funcs) { 271 if (fb_helper->fb && fb_helper->fb->funcs) {
272 fb = fb_helper->fb; 272 fb = fb_helper->fb;
273 if (fb) { 273 if (fb)
274 drm_framebuffer_unregister_private(fb);
275 drm_framebuffer_remove(fb); 274 drm_framebuffer_remove(fb);
276 }
277 } 275 }
278 276
279 drm_fb_helper_unregister_fbi(fb_helper); 277 drm_fb_helper_unregister_fbi(fb_helper);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index fbd13fabdf2d..603d8425cca6 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -1193,6 +1193,17 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
1193 if (!node) 1193 if (!node)
1194 return -ENOMEM; 1194 return -ENOMEM;
1195 1195
1196 /*
1197 * To avoid an integer overflow for the later size computations, we
1198 * enforce a maximum number of submitted commands here. This limit is
1199 * sufficient for all conceivable usage cases of the G2D.
1200 */
1201 if (req->cmd_nr > G2D_CMDLIST_DATA_NUM ||
1202 req->cmd_buf_nr > G2D_CMDLIST_DATA_NUM) {
1203 dev_err(dev, "number of submitted G2D commands exceeds limit\n");
1204 return -EINVAL;
1205 }
1206
1196 node->event = NULL; 1207 node->event = NULL;
1197 1208
1198 if (req->event_type != G2D_EVENT_NOT) { 1209 if (req->event_type != G2D_EVENT_NOT) {
@@ -1250,7 +1261,11 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
1250 cmdlist->data[cmdlist->last++] = G2D_INTEN_ACF; 1261 cmdlist->data[cmdlist->last++] = G2D_INTEN_ACF;
1251 } 1262 }
1252 1263
1253 /* Check size of cmdlist: last 2 is about G2D_BITBLT_START */ 1264 /*
1265 * Check the size of cmdlist. The 2 that is added last comes from
1266 * the implicit G2D_BITBLT_START that is appended once we have
1267 * checked all the submitted commands.
1268 */
1254 size = cmdlist->last + req->cmd_nr * 2 + req->cmd_buf_nr * 2 + 2; 1269 size = cmdlist->last + req->cmd_nr * 2 + req->cmd_buf_nr * 2 + 2;
1255 if (size > G2D_CMDLIST_DATA_NUM) { 1270 if (size > G2D_CMDLIST_DATA_NUM) {
1256 dev_err(dev, "cmdlist size is too big\n"); 1271 dev_err(dev, "cmdlist size is too big\n");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c
index a0def0be6d65..2ef43d403eaa 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_mic.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c
@@ -19,6 +19,7 @@
19#include <linux/of_graph.h> 19#include <linux/of_graph.h>
20#include <linux/clk.h> 20#include <linux/clk.h>
21#include <linux/component.h> 21#include <linux/component.h>
22#include <linux/pm_runtime.h>
22#include <drm/drmP.h> 23#include <drm/drmP.h>
23#include <linux/mfd/syscon.h> 24#include <linux/mfd/syscon.h>
24#include <linux/regmap.h> 25#include <linux/regmap.h>
@@ -269,35 +270,9 @@ static int parse_dt(struct exynos_mic *mic)
269 } 270 }
270 nodes[j++] = remote_node; 271 nodes[j++] = remote_node;
271 272
272 switch (i) { 273 if (i == ENDPOINT_DECON_NODE &&
273 case ENDPOINT_DECON_NODE: 274 of_get_child_by_name(remote_node, "i80-if-timings"))
274 /* decon node */ 275 mic->i80_mode = 1;
275 if (of_get_child_by_name(remote_node,
276 "i80-if-timings"))
277 mic->i80_mode = 1;
278
279 break;
280 case ENDPOINT_DSI_NODE:
281 /* panel node */
282 remote_node = get_remote_node(remote_node, 1);
283 if (!remote_node) {
284 ret = -EPIPE;
285 goto exit;
286 }
287 nodes[j++] = remote_node;
288
289 ret = of_get_videomode(remote_node,
290 &mic->vm, 0);
291 if (ret) {
292 DRM_ERROR("mic: failed to get videomode");
293 goto exit;
294 }
295
296 break;
297 default:
298 DRM_ERROR("mic: Unknown endpoint from MIC");
299 break;
300 }
301 } 276 }
302 277
303exit: 278exit:
@@ -312,7 +287,6 @@ static void mic_disable(struct drm_bridge *bridge) { }
312static void mic_post_disable(struct drm_bridge *bridge) 287static void mic_post_disable(struct drm_bridge *bridge)
313{ 288{
314 struct exynos_mic *mic = bridge->driver_private; 289 struct exynos_mic *mic = bridge->driver_private;
315 int i;
316 290
317 mutex_lock(&mic_mutex); 291 mutex_lock(&mic_mutex);
318 if (!mic->enabled) 292 if (!mic->enabled)
@@ -320,39 +294,43 @@ static void mic_post_disable(struct drm_bridge *bridge)
320 294
321 mic_set_path(mic, 0); 295 mic_set_path(mic, 0);
322 296
323 for (i = NUM_CLKS - 1; i > -1; i--) 297 pm_runtime_put(mic->dev);
324 clk_disable_unprepare(mic->clks[i]);
325
326 mic->enabled = 0; 298 mic->enabled = 0;
327 299
328already_disabled: 300already_disabled:
329 mutex_unlock(&mic_mutex); 301 mutex_unlock(&mic_mutex);
330} 302}
331 303
304static void mic_mode_set(struct drm_bridge *bridge,
305 struct drm_display_mode *mode,
306 struct drm_display_mode *adjusted_mode)
307{
308 struct exynos_mic *mic = bridge->driver_private;
309
310 mutex_lock(&mic_mutex);
311 drm_display_mode_to_videomode(mode, &mic->vm);
312 mutex_unlock(&mic_mutex);
313}
314
332static void mic_pre_enable(struct drm_bridge *bridge) 315static void mic_pre_enable(struct drm_bridge *bridge)
333{ 316{
334 struct exynos_mic *mic = bridge->driver_private; 317 struct exynos_mic *mic = bridge->driver_private;
335 int ret, i; 318 int ret;
336 319
337 mutex_lock(&mic_mutex); 320 mutex_lock(&mic_mutex);
338 if (mic->enabled) 321 if (mic->enabled)
339 goto already_enabled; 322 goto unlock;
340 323
341 for (i = 0; i < NUM_CLKS; i++) { 324 ret = pm_runtime_get_sync(mic->dev);
342 ret = clk_prepare_enable(mic->clks[i]); 325 if (ret < 0)
343 if (ret < 0) { 326 goto unlock;
344 DRM_ERROR("Failed to enable clock (%s)\n",
345 clk_names[i]);
346 goto turn_off_clks;
347 }
348 }
349 327
350 mic_set_path(mic, 1); 328 mic_set_path(mic, 1);
351 329
352 ret = mic_sw_reset(mic); 330 ret = mic_sw_reset(mic);
353 if (ret) { 331 if (ret) {
354 DRM_ERROR("Failed to reset\n"); 332 DRM_ERROR("Failed to reset\n");
355 goto turn_off_clks; 333 goto turn_off;
356 } 334 }
357 335
358 if (!mic->i80_mode) 336 if (!mic->i80_mode)
@@ -365,10 +343,9 @@ static void mic_pre_enable(struct drm_bridge *bridge)
365 343
366 return; 344 return;
367 345
368turn_off_clks: 346turn_off:
369 while (--i > -1) 347 pm_runtime_put(mic->dev);
370 clk_disable_unprepare(mic->clks[i]); 348unlock:
371already_enabled:
372 mutex_unlock(&mic_mutex); 349 mutex_unlock(&mic_mutex);
373} 350}
374 351
@@ -377,6 +354,7 @@ static void mic_enable(struct drm_bridge *bridge) { }
377static const struct drm_bridge_funcs mic_bridge_funcs = { 354static const struct drm_bridge_funcs mic_bridge_funcs = {
378 .disable = mic_disable, 355 .disable = mic_disable,
379 .post_disable = mic_post_disable, 356 .post_disable = mic_post_disable,
357 .mode_set = mic_mode_set,
380 .pre_enable = mic_pre_enable, 358 .pre_enable = mic_pre_enable,
381 .enable = mic_enable, 359 .enable = mic_enable,
382}; 360};
@@ -401,14 +379,12 @@ static void exynos_mic_unbind(struct device *dev, struct device *master,
401 void *data) 379 void *data)
402{ 380{
403 struct exynos_mic *mic = dev_get_drvdata(dev); 381 struct exynos_mic *mic = dev_get_drvdata(dev);
404 int i;
405 382
406 mutex_lock(&mic_mutex); 383 mutex_lock(&mic_mutex);
407 if (!mic->enabled) 384 if (!mic->enabled)
408 goto already_disabled; 385 goto already_disabled;
409 386
410 for (i = NUM_CLKS - 1; i > -1; i--) 387 pm_runtime_put(mic->dev);
411 clk_disable_unprepare(mic->clks[i]);
412 388
413already_disabled: 389already_disabled:
414 mutex_unlock(&mic_mutex); 390 mutex_unlock(&mic_mutex);
@@ -421,6 +397,41 @@ static const struct component_ops exynos_mic_component_ops = {
421 .unbind = exynos_mic_unbind, 397 .unbind = exynos_mic_unbind,
422}; 398};
423 399
400#ifdef CONFIG_PM
401static int exynos_mic_suspend(struct device *dev)
402{
403 struct exynos_mic *mic = dev_get_drvdata(dev);
404 int i;
405
406 for (i = NUM_CLKS - 1; i > -1; i--)
407 clk_disable_unprepare(mic->clks[i]);
408
409 return 0;
410}
411
412static int exynos_mic_resume(struct device *dev)
413{
414 struct exynos_mic *mic = dev_get_drvdata(dev);
415 int ret, i;
416
417 for (i = 0; i < NUM_CLKS; i++) {
418 ret = clk_prepare_enable(mic->clks[i]);
419 if (ret < 0) {
420 DRM_ERROR("Failed to enable clock (%s)\n",
421 clk_names[i]);
422 while (--i > -1)
423 clk_disable_unprepare(mic->clks[i]);
424 return ret;
425 }
426 }
427 return 0;
428}
429#endif
430
431static const struct dev_pm_ops exynos_mic_pm_ops = {
432 SET_RUNTIME_PM_OPS(exynos_mic_suspend, exynos_mic_resume, NULL)
433};
434
424static int exynos_mic_probe(struct platform_device *pdev) 435static int exynos_mic_probe(struct platform_device *pdev)
425{ 436{
426 struct device *dev = &pdev->dev; 437 struct device *dev = &pdev->dev;
@@ -473,9 +484,18 @@ static int exynos_mic_probe(struct platform_device *pdev)
473 484
474 platform_set_drvdata(pdev, mic); 485 platform_set_drvdata(pdev, mic);
475 486
487 pm_runtime_enable(dev);
488
489 ret = component_add(dev, &exynos_mic_component_ops);
490 if (ret)
491 goto err_pm;
492
476 DRM_DEBUG_KMS("MIC has been probed\n"); 493 DRM_DEBUG_KMS("MIC has been probed\n");
477 return component_add(dev, &exynos_mic_component_ops);
478 494
495 return 0;
496
497err_pm:
498 pm_runtime_disable(dev);
479err: 499err:
480 return ret; 500 return ret;
481} 501}
@@ -483,6 +503,7 @@ err:
483static int exynos_mic_remove(struct platform_device *pdev) 503static int exynos_mic_remove(struct platform_device *pdev)
484{ 504{
485 component_del(&pdev->dev, &exynos_mic_component_ops); 505 component_del(&pdev->dev, &exynos_mic_component_ops);
506 pm_runtime_disable(&pdev->dev);
486 return 0; 507 return 0;
487} 508}
488 509
@@ -497,6 +518,7 @@ struct platform_driver mic_driver = {
497 .remove = exynos_mic_remove, 518 .remove = exynos_mic_remove,
498 .driver = { 519 .driver = {
499 .name = "exynos-mic", 520 .name = "exynos-mic",
521 .pm = &exynos_mic_pm_ops,
500 .owner = THIS_MODULE, 522 .owner = THIS_MODULE,
501 .of_match_table = exynos_mic_of_match, 523 .of_match_table = exynos_mic_of_match,
502 }, 524 },
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index a106046e0c93..72143ac10525 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -701,7 +701,7 @@ static void vp_win_reset(struct mixer_context *ctx)
701 unsigned int tries = 100; 701 unsigned int tries = 100;
702 702
703 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING); 703 vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
704 while (tries--) { 704 while (--tries) {
705 /* waiting until VP_SRESET_PROCESSING is 0 */ 705 /* waiting until VP_SRESET_PROCESSING is 0 */
706 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING) 706 if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
707 break; 707 break;