/* for deferred fb unref's: */
struct drm_flip_work unref_work;
+
+ /* Only set if an external encoder is connected */
+ bool simulate_vesa_sync;
};
#define to_tilcdc_crtc(x) container_of(x, struct tilcdc_crtc, base)
tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
}
+static void tilcdc_crtc_dpms(struct drm_crtc *crtc, int mode);
static void tilcdc_crtc_destroy(struct drm_crtc *crtc)
{
struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
- WARN_ON(tilcdc_crtc->dpms == DRM_MODE_DPMS_ON);
+ tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
drm_crtc_cleanup(crtc);
drm_flip_work_cleanup(&tilcdc_crtc->unref_work);
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
+ struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
+
+ if (!tilcdc_crtc->simulate_vesa_sync)
+ return true;
+
+ /*
+ * tilcdc does not generate VESA-compliant sync but aligns
+ * VS on the second edge of HS instead of first edge.
+ * We use adjusted_mode, to fixup sync by aligning both rising
+ * edges and add HSKEW offset to fix the sync.
+ */
+ adjusted_mode->hskew = mode->hsync_end - mode->hsync_start;
+ adjusted_mode->flags |= DRM_MODE_FLAG_HSKEW;
+
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC) {
+ adjusted_mode->flags |= DRM_MODE_FLAG_PHSYNC;
+ adjusted_mode->flags &= ~DRM_MODE_FLAG_NHSYNC;
+ } else {
+ adjusted_mode->flags |= DRM_MODE_FLAG_NHSYNC;
+ adjusted_mode->flags &= ~DRM_MODE_FLAG_PHSYNC;
+ }
+
return true;
}
tilcdc_crtc->info = info;
}
+void tilcdc_crtc_set_simulate_vesa_sync(struct drm_crtc *crtc,
+ bool simulate_vesa_sync)
+{
+ struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
+
+ tilcdc_crtc->simulate_vesa_sync = simulate_vesa_sync;
+}
+
void tilcdc_crtc_update_clk(struct drm_crtc *crtc)
{
struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);