aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorInki Dae <inki.dae@samsung.com>2011-12-05 21:06:54 -0500
committerInki Dae <inki.dae@samsung.com>2011-12-21 01:14:17 -0500
commitec05da959acc5da8d51207060d9af672ae837321 (patch)
tree72fbc6c3d5b155877741a38441b308564d083427
parenta794d57da8031a45fed4e4cb71a999694ba02f7e (diff)
drm/exynos: updated crtc and encoder dpms framework.
With DPMS ON and OFF requests, crtc dpms would be in charge of just only device power such as fimd or hdmi and encoder dpms in charge of device setting(mode setting and register updating) and also lcd panel and digital TV power. Signed-off-by: Inki Dae <inki.dae@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c58
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h6
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_encoder.c109
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_encoder.h3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c113
5 files changed, 206 insertions, 83 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 7777d41d1cd..a435c339033 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -52,11 +52,13 @@
52 * drm framework doesn't support multiple irq yet. 52 * drm framework doesn't support multiple irq yet.
53 * we can refer to the crtc to current hardware interrupt occured through 53 * we can refer to the crtc to current hardware interrupt occured through
54 * this pipe value. 54 * this pipe value.
55 * @dpms: store the crtc dpms value
55 */ 56 */
56struct exynos_drm_crtc { 57struct exynos_drm_crtc {
57 struct drm_crtc drm_crtc; 58 struct drm_crtc drm_crtc;
58 struct exynos_drm_overlay overlay; 59 struct exynos_drm_overlay overlay;
59 unsigned int pipe; 60 unsigned int pipe;
61 unsigned int dpms;
60}; 62};
61 63
62static void exynos_drm_crtc_apply(struct drm_crtc *crtc) 64static void exynos_drm_crtc_apply(struct drm_crtc *crtc)
@@ -153,26 +155,37 @@ static int exynos_drm_crtc_update(struct drm_crtc *crtc)
153 155
154static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) 156static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
155{ 157{
158 struct drm_device *dev = crtc->dev;
156 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 159 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
157 160
158 DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode); 161 DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
159 162
163 if (exynos_crtc->dpms == mode) {
164 DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
165 return;
166 }
167
168 mutex_lock(&dev->struct_mutex);
169
160 switch (mode) { 170 switch (mode) {
161 case DRM_MODE_DPMS_ON: 171 case DRM_MODE_DPMS_ON:
162 exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe, 172 exynos_drm_fn_encoder(crtc, &mode,
163 exynos_drm_encoder_crtc_commit); 173 exynos_drm_encoder_crtc_dpms);
174 exynos_crtc->dpms = mode;
164 break; 175 break;
165 case DRM_MODE_DPMS_STANDBY: 176 case DRM_MODE_DPMS_STANDBY:
166 case DRM_MODE_DPMS_SUSPEND: 177 case DRM_MODE_DPMS_SUSPEND:
167 case DRM_MODE_DPMS_OFF: 178 case DRM_MODE_DPMS_OFF:
168 /* TODO */ 179 exynos_drm_fn_encoder(crtc, &mode,
169 exynos_drm_fn_encoder(crtc, NULL, 180 exynos_drm_encoder_crtc_dpms);
170 exynos_drm_encoder_crtc_disable); 181 exynos_crtc->dpms = mode;
171 break; 182 break;
172 default: 183 default:
173 DRM_DEBUG_KMS("unspecified mode %d\n", mode); 184 DRM_ERROR("unspecified mode %d\n", mode);
174 break; 185 break;
175 } 186 }
187
188 mutex_unlock(&dev->struct_mutex);
176} 189}
177 190
178static void exynos_drm_crtc_prepare(struct drm_crtc *crtc) 191static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
@@ -188,6 +201,28 @@ static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
188 201
189 DRM_DEBUG_KMS("%s\n", __FILE__); 202 DRM_DEBUG_KMS("%s\n", __FILE__);
190 203
204 /*
205 * when set_crtc is requested from user or at booting time,
206 * crtc->commit would be called without dpms call so if dpms is
207 * no power on then crtc->dpms should be called
208 * with DRM_MODE_DPMS_ON for the hardware power to be on.
209 */
210 if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) {
211 int mode = DRM_MODE_DPMS_ON;
212
213 /*
214 * enable hardware(power on) to all encoders hdmi connected
215 * to current crtc.
216 */
217 exynos_drm_crtc_dpms(crtc, mode);
218 /*
219 * enable dma to all encoders connected to current crtc and
220 * lcd panel.
221 */
222 exynos_drm_fn_encoder(crtc, &mode,
223 exynos_drm_encoder_dpms_from_crtc);
224 }
225
191 exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe, 226 exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe,
192 exynos_drm_encoder_crtc_commit); 227 exynos_drm_encoder_crtc_commit);
193} 228}
@@ -344,6 +379,7 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
344 } 379 }
345 380
346 exynos_crtc->pipe = nr; 381 exynos_crtc->pipe = nr;
382 exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
347 crtc = &exynos_crtc->drm_crtc; 383 crtc = &exynos_crtc->drm_crtc;
348 384
349 private->crtc[nr] = crtc; 385 private->crtc[nr] = crtc;
@@ -357,9 +393,14 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
357int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc) 393int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
358{ 394{
359 struct exynos_drm_private *private = dev->dev_private; 395 struct exynos_drm_private *private = dev->dev_private;
396 struct exynos_drm_crtc *exynos_crtc =
397 to_exynos_crtc(private->crtc[crtc]);
360 398
361 DRM_DEBUG_KMS("%s\n", __FILE__); 399 DRM_DEBUG_KMS("%s\n", __FILE__);
362 400
401 if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
402 return -EPERM;
403
363 exynos_drm_fn_encoder(private->crtc[crtc], &crtc, 404 exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
364 exynos_drm_enable_vblank); 405 exynos_drm_enable_vblank);
365 406
@@ -369,9 +410,14 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
369void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc) 410void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
370{ 411{
371 struct exynos_drm_private *private = dev->dev_private; 412 struct exynos_drm_private *private = dev->dev_private;
413 struct exynos_drm_crtc *exynos_crtc =
414 to_exynos_crtc(private->crtc[crtc]);
372 415
373 DRM_DEBUG_KMS("%s\n", __FILE__); 416 DRM_DEBUG_KMS("%s\n", __FILE__);
374 417
418 if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
419 return;
420
375 exynos_drm_fn_encoder(private->crtc[crtc], &crtc, 421 exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
376 exynos_drm_disable_vblank); 422 exynos_drm_disable_vblank);
377} 423}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 5e02e6ecc2e..8018798710d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -144,17 +144,19 @@ struct exynos_drm_display_ops {
144/* 144/*
145 * Exynos drm manager ops 145 * Exynos drm manager ops
146 * 146 *
147 * @dpms: control device power.
148 * @apply: set timing, vblank and overlay data to registers.
147 * @mode_set: convert drm_display_mode to hw specific display mode and 149 * @mode_set: convert drm_display_mode to hw specific display mode and
148 * would be called by encoder->mode_set(). 150 * would be called by encoder->mode_set().
149 * @commit: set current hw specific display mode to hw. 151 * @commit: set current hw specific display mode to hw.
150 * @disable: disable hardware specific display mode.
151 * @enable_vblank: specific driver callback for enabling vblank interrupt. 152 * @enable_vblank: specific driver callback for enabling vblank interrupt.
152 * @disable_vblank: specific driver callback for disabling vblank interrupt. 153 * @disable_vblank: specific driver callback for disabling vblank interrupt.
153 */ 154 */
154struct exynos_drm_manager_ops { 155struct exynos_drm_manager_ops {
156 void (*dpms)(struct device *subdrv_dev, int mode);
157 void (*apply)(struct device *subdrv_dev);
155 void (*mode_set)(struct device *subdrv_dev, void *mode); 158 void (*mode_set)(struct device *subdrv_dev, void *mode);
156 void (*commit)(struct device *subdrv_dev); 159 void (*commit)(struct device *subdrv_dev);
157 void (*disable)(struct device *subdrv_dev);
158 int (*enable_vblank)(struct device *subdrv_dev); 160 int (*enable_vblank)(struct device *subdrv_dev);
159 void (*disable_vblank)(struct device *subdrv_dev); 161 void (*disable_vblank)(struct device *subdrv_dev);
160}; 162};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 153061415ba..4ff4a217c1d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -42,49 +42,68 @@
42 * @drm_encoder: encoder object. 42 * @drm_encoder: encoder object.
43 * @manager: specific encoder has its own manager to control a hardware 43 * @manager: specific encoder has its own manager to control a hardware
44 * appropriately and we can access a hardware drawing on this manager. 44 * appropriately and we can access a hardware drawing on this manager.
45 * @dpms: store the encoder dpms value.
45 */ 46 */
46struct exynos_drm_encoder { 47struct exynos_drm_encoder {
47 struct drm_encoder drm_encoder; 48 struct drm_encoder drm_encoder;
48 struct exynos_drm_manager *manager; 49 struct exynos_drm_manager *manager;
50 int dpms;
49}; 51};
50 52
51static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode) 53static void exynos_drm_display_power(struct drm_encoder *encoder, int mode)
52{ 54{
53 struct drm_device *dev = encoder->dev; 55 struct drm_device *dev = encoder->dev;
54 struct drm_connector *connector; 56 struct drm_connector *connector;
55 struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); 57 struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
58
59 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
60 if (connector->encoder == encoder) {
61 struct exynos_drm_display_ops *display_ops =
62 manager->display_ops;
63
64 DRM_DEBUG_KMS("connector[%d] dpms[%d]\n",
65 connector->base.id, mode);
66 if (display_ops && display_ops->power_on)
67 display_ops->power_on(manager->dev, mode);
68 }
69 }
70}
71
72static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
73{
74 struct drm_device *dev = encoder->dev;
75 struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
56 struct exynos_drm_manager_ops *manager_ops = manager->ops; 76 struct exynos_drm_manager_ops *manager_ops = manager->ops;
77 struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
57 78
58 DRM_DEBUG_KMS("%s, encoder dpms: %d\n", __FILE__, mode); 79 DRM_DEBUG_KMS("%s, encoder dpms: %d\n", __FILE__, mode);
59 80
81 if (exynos_encoder->dpms == mode) {
82 DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
83 return;
84 }
85
86 mutex_lock(&dev->struct_mutex);
87
60 switch (mode) { 88 switch (mode) {
61 case DRM_MODE_DPMS_ON: 89 case DRM_MODE_DPMS_ON:
62 if (manager_ops && manager_ops->commit) 90 if (manager_ops && manager_ops->apply)
63 manager_ops->commit(manager->dev); 91 manager_ops->apply(manager->dev);
92 exynos_drm_display_power(encoder, mode);
93 exynos_encoder->dpms = mode;
64 break; 94 break;
65 case DRM_MODE_DPMS_STANDBY: 95 case DRM_MODE_DPMS_STANDBY:
66 case DRM_MODE_DPMS_SUSPEND: 96 case DRM_MODE_DPMS_SUSPEND:
67 case DRM_MODE_DPMS_OFF: 97 case DRM_MODE_DPMS_OFF:
68 /* TODO */ 98 exynos_drm_display_power(encoder, mode);
69 if (manager_ops && manager_ops->disable) 99 exynos_encoder->dpms = mode;
70 manager_ops->disable(manager->dev);
71 break; 100 break;
72 default: 101 default:
73 DRM_ERROR("unspecified mode %d\n", mode); 102 DRM_ERROR("unspecified mode %d\n", mode);
74 break; 103 break;
75 } 104 }
76 105
77 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 106 mutex_unlock(&dev->struct_mutex);
78 if (connector->encoder == encoder) {
79 struct exynos_drm_display_ops *display_ops =
80 manager->display_ops;
81
82 DRM_DEBUG_KMS("connector[%d] dpms[%d]\n",
83 connector->base.id, mode);
84 if (display_ops && display_ops->power_on)
85 display_ops->power_on(manager->dev, mode);
86 }
87 }
88} 107}
89 108
90static bool 109static bool
@@ -169,7 +188,6 @@ static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
169 exynos_encoder->manager->pipe = -1; 188 exynos_encoder->manager->pipe = -1;
170 189
171 drm_encoder_cleanup(encoder); 190 drm_encoder_cleanup(encoder);
172 encoder->dev->mode_config.num_encoder--;
173 kfree(exynos_encoder); 191 kfree(exynos_encoder);
174} 192}
175 193
@@ -199,6 +217,7 @@ exynos_drm_encoder_create(struct drm_device *dev,
199 return NULL; 217 return NULL;
200 } 218 }
201 219
220 exynos_encoder->dpms = DRM_MODE_DPMS_OFF;
202 exynos_encoder->manager = manager; 221 exynos_encoder->manager = manager;
203 encoder = &exynos_encoder->drm_encoder; 222 encoder = &exynos_encoder->drm_encoder;
204 encoder->possible_crtcs = possible_crtcs; 223 encoder->possible_crtcs = possible_crtcs;
@@ -294,6 +313,52 @@ void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data)
294 overlay_ops->commit(manager->dev); 313 overlay_ops->commit(manager->dev);
295} 314}
296 315
316void exynos_drm_encoder_dpms_from_crtc(struct drm_encoder *encoder, void *data)
317{
318 struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
319 int mode = *(int *)data;
320
321 DRM_DEBUG_KMS("%s\n", __FILE__);
322
323 exynos_drm_encoder_dpms(encoder, mode);
324
325 exynos_encoder->dpms = mode;
326}
327
328void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
329{
330 struct drm_device *dev = encoder->dev;
331 struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
332 struct exynos_drm_manager *manager = exynos_encoder->manager;
333 struct exynos_drm_manager_ops *manager_ops = manager->ops;
334 struct drm_connector *connector;
335 int mode = *(int *)data;
336
337 DRM_DEBUG_KMS("%s\n", __FILE__);
338
339 if (manager_ops && manager_ops->dpms)
340 manager_ops->dpms(manager->dev, mode);
341
342 /*
343 * set current dpms mode to the connector connected to
344 * current encoder. connector->dpms would be checked
345 * at drm_helper_connector_dpms()
346 */
347 list_for_each_entry(connector, &dev->mode_config.connector_list, head)
348 if (connector->encoder == encoder)
349 connector->dpms = mode;
350
351 /*
352 * if this condition is ok then it means that the crtc is already
353 * detached from encoder and last function for detaching is properly
354 * done, so clear pipe from manager to prevent repeated call.
355 */
356 if (mode > DRM_MODE_DPMS_ON) {
357 if (!encoder->crtc)
358 manager->pipe = -1;
359 }
360}
361
297void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data) 362void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data)
298{ 363{
299 struct exynos_drm_manager *manager = 364 struct exynos_drm_manager *manager =
@@ -315,14 +380,6 @@ void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data)
315 380
316 if (overlay_ops && overlay_ops->disable) 381 if (overlay_ops && overlay_ops->disable)
317 overlay_ops->disable(manager->dev); 382 overlay_ops->disable(manager->dev);
318
319 /*
320 * crtc is already detached from encoder and last
321 * function for detaching is properly done, so
322 * clear pipe from manager to prevent repeated call
323 */
324 if (!encoder->crtc)
325 manager->pipe = -1;
326} 383}
327 384
328MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); 385MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.h b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
index a22acfbf0e4..72f15b021c4 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
@@ -40,6 +40,9 @@ void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
40void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data); 40void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data);
41void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data); 41void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data);
42void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data); 42void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data);
43void exynos_drm_encoder_dpms_from_crtc(struct drm_encoder *encoder,
44 void *data);
45void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data);
43void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data); 46void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data);
44void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data); 47void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data);
45 48
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index db3b3d9e731..771800cc5f7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -68,6 +68,7 @@ struct fimd_win_data {
68 void __iomem *vaddr; 68 void __iomem *vaddr;
69 unsigned int buf_offsize; 69 unsigned int buf_offsize;
70 unsigned int line_size; /* bytes */ 70 unsigned int line_size; /* bytes */
71 bool enabled;
71}; 72};
72 73
73struct fimd_context { 74struct fimd_context {
@@ -119,7 +120,7 @@ static int fimd_display_power_on(struct device *dev, int mode)
119{ 120{
120 DRM_DEBUG_KMS("%s\n", __FILE__); 121 DRM_DEBUG_KMS("%s\n", __FILE__);
121 122
122 /* TODO. */ 123 /* TODO */
123 124
124 return 0; 125 return 0;
125} 126}
@@ -132,6 +133,31 @@ static struct exynos_drm_display_ops fimd_display_ops = {
132 .power_on = fimd_display_power_on, 133 .power_on = fimd_display_power_on,
133}; 134};
134 135
136static void fimd_dpms(struct device *subdrv_dev, int mode)
137{
138 DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
139
140 /* TODO */
141}
142
143static void fimd_apply(struct device *subdrv_dev)
144{
145 struct fimd_context *ctx = get_fimd_context(subdrv_dev);
146 struct exynos_drm_manager *mgr = &ctx->subdrv.manager;
147 struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
148 struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops;
149 struct fimd_win_data *win_data;
150
151 DRM_DEBUG_KMS("%s\n", __FILE__);
152
153 win_data = &ctx->win_data[ctx->default_win];
154 if (win_data->enabled && (ovl_ops && ovl_ops->commit))
155 ovl_ops->commit(subdrv_dev);
156
157 if (mgr_ops && mgr_ops->commit)
158 mgr_ops->commit(subdrv_dev);
159}
160
135static void fimd_commit(struct device *dev) 161static void fimd_commit(struct device *dev)
136{ 162{
137 struct fimd_context *ctx = get_fimd_context(dev); 163 struct fimd_context *ctx = get_fimd_context(dev);
@@ -177,40 +203,6 @@ static void fimd_commit(struct device *dev)
177 writel(val, ctx->regs + VIDCON0); 203 writel(val, ctx->regs + VIDCON0);
178} 204}
179 205
180static void fimd_disable(struct device *dev)
181{
182 struct fimd_context *ctx = get_fimd_context(dev);
183 struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
184 struct drm_device *drm_dev = subdrv->drm_dev;
185 struct exynos_drm_manager *manager = &subdrv->manager;
186 u32 val;
187
188 DRM_DEBUG_KMS("%s\n", __FILE__);
189
190 /* fimd dma off */
191 val = readl(ctx->regs + VIDCON0);
192 val &= ~(VIDCON0_ENVID | VIDCON0_ENVID_F);
193 writel(val, ctx->regs + VIDCON0);
194
195 /*
196 * if vblank is enabled status with dma off then
197 * it disables vsync interrupt.
198 */
199 if (drm_dev->vblank_enabled[manager->pipe] &&
200 atomic_read(&drm_dev->vblank_refcount[manager->pipe])) {
201 drm_vblank_put(drm_dev, manager->pipe);
202
203 /*
204 * if vblank_disable_allowed is 0 then disable
205 * vsync interrupt right now else the vsync interrupt
206 * would be disabled by drm timer once a current process
207 * gives up ownershop of vblank event.
208 */
209 if (!drm_dev->vblank_disable_allowed)
210 drm_vblank_off(drm_dev, manager->pipe);
211 }
212}
213
214static int fimd_enable_vblank(struct device *dev) 206static int fimd_enable_vblank(struct device *dev)
215{ 207{
216 struct fimd_context *ctx = get_fimd_context(dev); 208 struct fimd_context *ctx = get_fimd_context(dev);
@@ -253,8 +245,9 @@ static void fimd_disable_vblank(struct device *dev)
253} 245}
254 246
255static struct exynos_drm_manager_ops fimd_manager_ops = { 247static struct exynos_drm_manager_ops fimd_manager_ops = {
248 .dpms = fimd_dpms,
249 .apply = fimd_apply,
256 .commit = fimd_commit, 250 .commit = fimd_commit,
257 .disable = fimd_disable,
258 .enable_vblank = fimd_enable_vblank, 251 .enable_vblank = fimd_enable_vblank,
259 .disable_vblank = fimd_disable_vblank, 252 .disable_vblank = fimd_disable_vblank,
260}; 253};
@@ -472,16 +465,24 @@ static void fimd_win_commit(struct device *dev)
472 if (win != 0) 465 if (win != 0)
473 fimd_win_set_colkey(dev, win); 466 fimd_win_set_colkey(dev, win);
474 467
468 /* wincon */
469 val = readl(ctx->regs + WINCON(win));
470 val |= WINCONx_ENWIN;
471 writel(val, ctx->regs + WINCON(win));
472
475 /* Enable DMA channel and unprotect windows */ 473 /* Enable DMA channel and unprotect windows */
476 val = readl(ctx->regs + SHADOWCON); 474 val = readl(ctx->regs + SHADOWCON);
477 val |= SHADOWCON_CHx_ENABLE(win); 475 val |= SHADOWCON_CHx_ENABLE(win);
478 val &= ~SHADOWCON_WINx_PROTECT(win); 476 val &= ~SHADOWCON_WINx_PROTECT(win);
479 writel(val, ctx->regs + SHADOWCON); 477 writel(val, ctx->regs + SHADOWCON);
478
479 win_data->enabled = true;
480} 480}
481 481
482static void fimd_win_disable(struct device *dev) 482static void fimd_win_disable(struct device *dev)
483{ 483{
484 struct fimd_context *ctx = get_fimd_context(dev); 484 struct fimd_context *ctx = get_fimd_context(dev);
485 struct fimd_win_data *win_data;
485 int win = ctx->default_win; 486 int win = ctx->default_win;
486 u32 val; 487 u32 val;
487 488
@@ -490,6 +491,8 @@ static void fimd_win_disable(struct device *dev)
490 if (win < 0 || win > WINDOWS_NR) 491 if (win < 0 || win > WINDOWS_NR)
491 return; 492 return;
492 493
494 win_data = &ctx->win_data[win];
495
493 /* protect windows */ 496 /* protect windows */
494 val = readl(ctx->regs + SHADOWCON); 497 val = readl(ctx->regs + SHADOWCON);
495 val |= SHADOWCON_WINx_PROTECT(win); 498 val |= SHADOWCON_WINx_PROTECT(win);
@@ -505,6 +508,8 @@ static void fimd_win_disable(struct device *dev)
505 val &= ~SHADOWCON_CHx_ENABLE(win); 508 val &= ~SHADOWCON_CHx_ENABLE(win);
506 val &= ~SHADOWCON_WINx_PROTECT(win); 509 val &= ~SHADOWCON_WINx_PROTECT(win);
507 writel(val, ctx->regs + SHADOWCON); 510 writel(val, ctx->regs + SHADOWCON);
511
512 win_data->enabled = false;
508} 513}
509 514
510static struct exynos_drm_overlay_ops fimd_overlay_ops = { 515static struct exynos_drm_overlay_ops fimd_overlay_ops = {
@@ -540,9 +545,17 @@ static void fimd_finish_pageflip(struct drm_device *drm_dev, int crtc)
540 wake_up_interruptible(&e->base.file_priv->event_wait); 545 wake_up_interruptible(&e->base.file_priv->event_wait);
541 } 546 }
542 547
543 if (is_checked) 548 if (is_checked) {
544 drm_vblank_put(drm_dev, crtc); 549 drm_vblank_put(drm_dev, crtc);
545 550
551 /*
552 * don't off vblank if vblank_disable_allowed is 1,
553 * because vblank would be off by timer handler.
554 */
555 if (!drm_dev->vblank_disable_allowed)
556 drm_vblank_off(drm_dev, crtc);
557 }
558
546 spin_unlock_irqrestore(&drm_dev->event_lock, flags); 559 spin_unlock_irqrestore(&drm_dev->event_lock, flags);
547} 560}
548 561
@@ -560,19 +573,14 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
560 /* VSYNC interrupt */ 573 /* VSYNC interrupt */
561 writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1); 574 writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
562 575
563 /* 576 /* check the crtc is detached already from encoder */
564 * in case that vblank_disable_allowed is 1, it could induce 577 if (manager->pipe < 0)
565 * the problem that manager->pipe could be -1 because with 578 goto out;
566 * disable callback, vsync interrupt isn't disabled and at this moment,
567 * vsync interrupt could occur. the vsync interrupt would be disabled
568 * by timer handler later.
569 */
570 if (manager->pipe == -1)
571 return IRQ_HANDLED;
572 579
573 drm_handle_vblank(drm_dev, manager->pipe); 580 drm_handle_vblank(drm_dev, manager->pipe);
574 fimd_finish_pageflip(drm_dev, manager->pipe); 581 fimd_finish_pageflip(drm_dev, manager->pipe);
575 582
583out:
576 return IRQ_HANDLED; 584 return IRQ_HANDLED;
577} 585}
578 586
@@ -590,6 +598,13 @@ static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
590 */ 598 */
591 drm_dev->irq_enabled = 1; 599 drm_dev->irq_enabled = 1;
592 600
601 /*
602 * with vblank_disable_allowed = 1, vblank interrupt will be disabled
603 * by drm timer once a current process gives up ownership of
604 * vblank event.(after drm_vblank_put function is called)
605 */
606 drm_dev->vblank_disable_allowed = 1;
607
593 return 0; 608 return 0;
594} 609}
595 610
@@ -739,15 +754,15 @@ static int __devinit fimd_probe(struct platform_device *pdev)
739 754
740 ctx->irq = res->start; 755 ctx->irq = res->start;
741 756
742 for (win = 0; win < WINDOWS_NR; win++)
743 fimd_clear_win(ctx, win);
744
745 ret = request_irq(ctx->irq, fimd_irq_handler, 0, "drm_fimd", ctx); 757 ret = request_irq(ctx->irq, fimd_irq_handler, 0, "drm_fimd", ctx);
746 if (ret < 0) { 758 if (ret < 0) {
747 dev_err(dev, "irq request failed.\n"); 759 dev_err(dev, "irq request failed.\n");
748 goto err_req_irq; 760 goto err_req_irq;
749 } 761 }
750 762
763 for (win = 0; win < WINDOWS_NR; win++)
764 fimd_clear_win(ctx, win);
765
751 ctx->clkdiv = fimd_calc_clkdiv(ctx, timing); 766 ctx->clkdiv = fimd_calc_clkdiv(ctx, timing);
752 ctx->vidcon0 = pdata->vidcon0; 767 ctx->vidcon0 = pdata->vidcon0;
753 ctx->vidcon1 = pdata->vidcon1; 768 ctx->vidcon1 = pdata->vidcon1;