/*
- * Copyright 2017 NXP
+ * Copyright 2017-2018 NXP
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
tcon_set_operation_mode(dpu_crtc->tcon);
}
-static void dpu_crtc_disable(struct drm_crtc *crtc)
+static void dpu_crtc_atomic_disable(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state)
{
struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
framegen_disable(dpu_crtc->fg);
- framegen_wait_done(dpu_crtc->fg);
+ framegen_wait_done(dpu_crtc->fg, &old_crtc_state->adjusted_mode);
framegen_disable_clock(dpu_crtc->fg);
WARN_ON(!crtc->state->event);
.atomic_begin = dpu_crtc_atomic_begin,
.atomic_flush = dpu_crtc_atomic_flush,
.enable = dpu_crtc_enable,
- .disable = dpu_crtc_disable,
+ .atomic_disable = dpu_crtc_atomic_disable,
};
static int dpu_enable_vblank(struct drm_crtc *crtc)
/*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
- * Copyright 2017 NXP
+ * Copyright 2017-2018 NXP
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
#define FGSREPD 0x90
#define FGSRFTD 0x94
+#define KHZ 1000
+
struct dpu_framegen {
void __iomem *base;
struct clk *clk_pll;
}
EXPORT_SYMBOL_GPL(framegen_panic_displaymode);
-void framegen_wait_done(struct dpu_framegen *fg)
+void framegen_wait_done(struct dpu_framegen *fg, struct drm_display_mode *m)
{
- unsigned long timeout = jiffies + msecs_to_jiffies(60);
+ unsigned long timeout, pending_framedur_jiffies;
+ int frame_size = m->crtc_htotal * m->crtc_vtotal;
+ int dotclock, pending_framedur_ns;
u32 val;
+ dotclock = clk_get_rate(fg->clk_disp) / KHZ;
+ if (dotclock == 0) {
+ /* fall back to display mode's clock */
+ dotclock = m->crtc_clock;
+
+ dev_warn(fg->dpu->dev,
+ "pixel clock for FrameGen%d is zero\n", fg->id);
+ }
+
+ /*
+ * The SoC designer indicates that there are two pending frames
+ * to complete in the worst case.
+ * So, three pending frames are enough for sure.
+ */
+ pending_framedur_ns = div_u64((u64) 3 * frame_size * 1000000, dotclock);
+ pending_framedur_jiffies = nsecs_to_jiffies(pending_framedur_ns);
+ if (pending_framedur_jiffies > (3 * HZ)) {
+ pending_framedur_jiffies = 3 * HZ;
+
+ dev_warn(fg->dpu->dev,
+ "truncate FrameGen%d pending frame duration to 3sec\n",
+ fg->id);
+ }
+ timeout = jiffies + pending_framedur_jiffies;
+
mutex_lock(&fg->mutex);
do {
val = dpu_fg_read(fg, FGENSTS);
} while ((val & ENSTS) && time_before(jiffies, timeout));
mutex_unlock(&fg->mutex);
+ dev_dbg(fg->dpu->dev, "FrameGen%d pending frame duration is %ums\n",
+ fg->id, jiffies_to_msecs(pending_framedur_jiffies));
+
if (val & ENSTS)
dev_err(fg->dpu->dev, "failed to wait for FrameGen%d done\n",
fg->id);
/*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
- * Copyright 2017 NXP
+ * Copyright 2017-2018 NXP
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
void framegen_sacfg(struct dpu_framegen *fg, unsigned int x, unsigned int y);
void framegen_displaymode(struct dpu_framegen *fg, fgdm_t mode);
void framegen_panic_displaymode(struct dpu_framegen *fg, fgdm_t mode);
-void framegen_wait_done(struct dpu_framegen *fg);
+void framegen_wait_done(struct dpu_framegen *fg, struct drm_display_mode *m);
void framegen_read_timestamp(struct dpu_framegen *fg,
u32 *frame_index, u32 *line_index);
void framegen_wait_for_frame_counter_moving(struct dpu_framegen *fg);