diff options
Diffstat (limited to 'drivers/gpu/drm/tilcdc/tilcdc_crtc.c')
-rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 36 |
1 files changed, 35 insertions, 1 deletions
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index c73588483be0..7d07733bdc86 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c | |||
@@ -37,6 +37,9 @@ struct tilcdc_crtc { | |||
37 | 37 | ||
38 | /* for deferred fb unref's: */ | 38 | /* for deferred fb unref's: */ |
39 | struct drm_flip_work unref_work; | 39 | struct drm_flip_work unref_work; |
40 | |||
41 | /* Only set if an external encoder is connected */ | ||
42 | bool simulate_vesa_sync; | ||
40 | }; | 43 | }; |
41 | #define to_tilcdc_crtc(x) container_of(x, struct tilcdc_crtc, base) | 44 | #define to_tilcdc_crtc(x) container_of(x, struct tilcdc_crtc, base) |
42 | 45 | ||
@@ -135,11 +138,12 @@ static void stop(struct drm_crtc *crtc) | |||
135 | tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE); | 138 | tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE); |
136 | } | 139 | } |
137 | 140 | ||
141 | static void tilcdc_crtc_dpms(struct drm_crtc *crtc, int mode); | ||
138 | static void tilcdc_crtc_destroy(struct drm_crtc *crtc) | 142 | static void tilcdc_crtc_destroy(struct drm_crtc *crtc) |
139 | { | 143 | { |
140 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); | 144 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); |
141 | 145 | ||
142 | WARN_ON(tilcdc_crtc->dpms == DRM_MODE_DPMS_ON); | 146 | tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); |
143 | 147 | ||
144 | drm_crtc_cleanup(crtc); | 148 | drm_crtc_cleanup(crtc); |
145 | drm_flip_work_cleanup(&tilcdc_crtc->unref_work); | 149 | drm_flip_work_cleanup(&tilcdc_crtc->unref_work); |
@@ -213,6 +217,28 @@ static bool tilcdc_crtc_mode_fixup(struct drm_crtc *crtc, | |||
213 | const struct drm_display_mode *mode, | 217 | const struct drm_display_mode *mode, |
214 | struct drm_display_mode *adjusted_mode) | 218 | struct drm_display_mode *adjusted_mode) |
215 | { | 219 | { |
220 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); | ||
221 | |||
222 | if (!tilcdc_crtc->simulate_vesa_sync) | ||
223 | return true; | ||
224 | |||
225 | /* | ||
226 | * tilcdc does not generate VESA-compliant sync but aligns | ||
227 | * VS on the second edge of HS instead of first edge. | ||
228 | * We use adjusted_mode, to fixup sync by aligning both rising | ||
229 | * edges and add HSKEW offset to fix the sync. | ||
230 | */ | ||
231 | adjusted_mode->hskew = mode->hsync_end - mode->hsync_start; | ||
232 | adjusted_mode->flags |= DRM_MODE_FLAG_HSKEW; | ||
233 | |||
234 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) { | ||
235 | adjusted_mode->flags |= DRM_MODE_FLAG_PHSYNC; | ||
236 | adjusted_mode->flags &= ~DRM_MODE_FLAG_NHSYNC; | ||
237 | } else { | ||
238 | adjusted_mode->flags |= DRM_MODE_FLAG_NHSYNC; | ||
239 | adjusted_mode->flags &= ~DRM_MODE_FLAG_PHSYNC; | ||
240 | } | ||
241 | |||
216 | return true; | 242 | return true; |
217 | } | 243 | } |
218 | 244 | ||
@@ -533,6 +559,14 @@ void tilcdc_crtc_set_panel_info(struct drm_crtc *crtc, | |||
533 | tilcdc_crtc->info = info; | 559 | tilcdc_crtc->info = info; |
534 | } | 560 | } |
535 | 561 | ||
562 | void tilcdc_crtc_set_simulate_vesa_sync(struct drm_crtc *crtc, | ||
563 | bool simulate_vesa_sync) | ||
564 | { | ||
565 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); | ||
566 | |||
567 | tilcdc_crtc->simulate_vesa_sync = simulate_vesa_sync; | ||
568 | } | ||
569 | |||
536 | void tilcdc_crtc_update_clk(struct drm_crtc *crtc) | 570 | void tilcdc_crtc_update_clk(struct drm_crtc *crtc) |
537 | { | 571 | { |
538 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); | 572 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); |