.hs_wdth_shift = 24,
.has_overlay = false,
.has_ctrl2 = false,
+ .has_crc32 = false,
},
[MXSFB_V4] = {
.transfer_count = LCDC_V4_TRANSFER_COUNT,
.hs_wdth_shift = 18,
.has_overlay = false,
.has_ctrl2 = true,
+ .has_crc32 = true,
},
[MXSFB_V6] = {
.transfer_count = LCDC_V4_TRANSFER_COUNT,
.hs_wdth_shift = 18,
.has_overlay = true,
.has_ctrl2 = true,
+ .has_crc32 = true,
},
};
{
struct drm_device *drm = data;
struct mxsfb_drm_private *mxsfb = drm->dev_private;
- u32 reg;
+ u32 reg, crc;
+ u64 vbc;
reg = readl(mxsfb->base + LCDC_CTRL1);
- if (reg & CTRL1_CUR_FRAME_DONE_IRQ)
+ if (reg & CTRL1_CUR_FRAME_DONE_IRQ) {
drm_crtc_handle_vblank(&mxsfb->crtc);
+ if (mxsfb->crc_active) {
+ crc = readl(mxsfb->base + LCDC_V4_CRC_STAT);
+ vbc = drm_crtc_accurate_vblank_count(&mxsfb->crtc);
+ drm_crtc_add_crc_entry(&mxsfb->crtc, true, vbc, &crc);
+ }
+ }
writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
}
+static int mxsfb_crtc_set_crc_source(struct drm_crtc *crtc, const char *source)
+{
+ struct mxsfb_drm_private *mxsfb;
+
+ if (!crtc)
+ return -ENODEV;
+
+ mxsfb = to_mxsfb_drm_private(crtc->dev);
+
+ if (source && strcmp(source, "auto") == 0)
+ mxsfb->crc_active = true;
+ else if (!source)
+ mxsfb->crc_active = false;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static int mxsfb_crtc_verify_crc_source(struct drm_crtc *crtc,
+ const char *source, size_t *values_cnt)
+{
+ if (!crtc)
+ return -ENODEV;
+
+ if (source && strcmp(source, "auto") != 0) {
+ DRM_DEBUG_DRIVER("Unknown CRC source %s for %s\n",
+ source, crtc->name);
+ return -EINVAL;
+ }
+
+ *values_cnt = 1;
+ return 0;
+}
+
static const struct drm_crtc_helper_funcs mxsfb_crtc_helper_funcs = {
.atomic_check = mxsfb_crtc_atomic_check,
.atomic_flush = mxsfb_crtc_atomic_flush,
.disable_vblank = mxsfb_crtc_disable_vblank,
};
+static const struct drm_crtc_funcs mxsfb_crtc_with_crc_funcs = {
+ .reset = drm_atomic_helper_crtc_reset,
+ .destroy = drm_crtc_cleanup,
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+ .enable_vblank = mxsfb_crtc_enable_vblank,
+ .disable_vblank = mxsfb_crtc_disable_vblank,
+ .set_crc_source = mxsfb_crtc_set_crc_source,
+ .verify_crc_source = mxsfb_crtc_verify_crc_source,
+};
+
/* -----------------------------------------------------------------------------
* Encoder
*/
}
drm_crtc_helper_add(crtc, &mxsfb_crtc_helper_funcs);
- ret = drm_crtc_init_with_planes(mxsfb->drm, crtc,
- &mxsfb->planes.primary, NULL,
- &mxsfb_crtc_funcs, NULL);
+ if (mxsfb->devdata->has_crc32) {
+ ret = drm_crtc_init_with_planes(mxsfb->drm, crtc,
+ &mxsfb->planes.primary, NULL,
+ &mxsfb_crtc_with_crc_funcs,
+ NULL);
+ } else {
+ ret = drm_crtc_init_with_planes(mxsfb->drm, crtc,
+ &mxsfb->planes.primary, NULL,
+ &mxsfb_crtc_funcs, NULL);
+ }
if (ret)
return ret;