[PATCH v5 06/14] drm/exynos: fimd: support LCD I80 interface
Inki Dae
inki.dae at samsung.com
Tue Jul 8 09:10:28 PDT 2014
2014-07-08 9:39 GMT+09:00 YoungJun Cho <yj44.cho at samsung.com>:
> To support MIPI command mode based I80 interface panel,
> FIMD should do followings:
> - Sets LCD I80 interface timings configuration.
> - Uses "lcd_sys" as an IRQ resource and sets relevant IRQ configuration.
> - Sets LCD block configuration for I80 interface.
> - Sets ideal(pixel) clock is 2 times faster than the original one
> to generate frame done IRQ prior to the next TE signal.
> - Implements trigger feature that transfers image data if there is page
> flip request, and implements TE handler to call trigger function.
>
> Signed-off-by: YoungJun Cho <yj44.cho at samsung.com>
> Acked-by: Inki Dae <inki.dae at samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park at samsung.com>
> ---
> drivers/gpu/drm/exynos/Kconfig | 1 +
> drivers/gpu/drm/exynos/exynos_drm_fimd.c | 276 ++++++++++++++++++++++++++-----
> include/video/samsung_fimd.h | 3 +-
> 3 files changed, 235 insertions(+), 45 deletions(-)
>
> diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
> index 178d2a9..9ba1aae 100644
> --- a/drivers/gpu/drm/exynos/Kconfig
> +++ b/drivers/gpu/drm/exynos/Kconfig
> @@ -28,6 +28,7 @@ config DRM_EXYNOS_FIMD
> bool "Exynos DRM FIMD"
> depends on DRM_EXYNOS && !FB_S3C
> select FB_MODE_HELPERS
> + select MFD_SYSCON
> help
> Choose this option if you want to use Exynos FIMD for DRM.
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> index 33161ad..207872d 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> @@ -20,6 +20,8 @@
> #include <linux/of_device.h>
> #include <linux/pm_runtime.h>
> #include <linux/component.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/regmap.h>
>
> #include <video/of_display_timing.h>
> #include <video/of_videomode.h>
> @@ -61,6 +63,24 @@
> /* color key value register for hardware window 1 ~ 4. */
> #define WKEYCON1_BASE(x) ((WKEYCON1 + 0x140) + ((x - 1) * 8))
>
> +/* I80 / RGB trigger control register */
> +#define TRIGCON 0x1A4
> +#define TRGMODE_I80_RGB_ENABLE_I80 (1 << 0)
> +#define SWTRGCMD_I80_RGB_ENABLE (1 << 1)
> +
> +/* display mode change control register except exynos4 */
> +#define VIDOUT_CON 0x000
> +#define VIDOUT_CON_F_I80_LDI0 (0x2 << 8)
> +
> +/* I80 interface control for main LDI register */
> +#define I80IFCONFAx(x) (0x1B0 + (x) * 4)
> +#define I80IFCONFBx(x) (0x1B8 + (x) * 4)
> +#define LCD_CS_SETUP(x) ((x) << 16)
> +#define LCD_WR_SETUP(x) ((x) << 12)
> +#define LCD_WR_ACTIVE(x) ((x) << 8)
> +#define LCD_WR_HOLD(x) ((x) << 4)
> +#define I80IFEN_ENABLE (1 << 0)
> +
> /* FIMD has totally five hardware windows. */
> #define WINDOWS_NR 5
>
> @@ -68,10 +88,14 @@
>
> struct fimd_driver_data {
> unsigned int timing_base;
> + unsigned int lcdblk_offset;
> + unsigned int lcdblk_vt_shift;
> + unsigned int lcdblk_bypass_shift;
>
> unsigned int has_shadowcon:1;
> unsigned int has_clksel:1;
> unsigned int has_limited_fmt:1;
> + unsigned int has_vidoutcon:1;
> };
>
> static struct fimd_driver_data s3c64xx_fimd_driver_data = {
> @@ -82,12 +106,19 @@ static struct fimd_driver_data s3c64xx_fimd_driver_data = {
>
> static struct fimd_driver_data exynos4_fimd_driver_data = {
> .timing_base = 0x0,
> + .lcdblk_offset = 0x210,
> + .lcdblk_vt_shift = 10,
> + .lcdblk_bypass_shift = 1,
> .has_shadowcon = 1,
> };
>
> static struct fimd_driver_data exynos5_fimd_driver_data = {
> .timing_base = 0x20000,
> + .lcdblk_offset = 0x214,
> + .lcdblk_vt_shift = 24,
> + .lcdblk_bypass_shift = 15,
> .has_shadowcon = 1,
> + .has_vidoutcon = 1,
> };
>
> struct fimd_win_data {
> @@ -112,15 +143,22 @@ struct fimd_context {
> struct clk *bus_clk;
> struct clk *lcd_clk;
> void __iomem *regs;
> + struct regmap *sysreg;
> struct drm_display_mode mode;
> struct fimd_win_data win_data[WINDOWS_NR];
> unsigned int default_win;
> unsigned long irq_flags;
> + u32 vidcon0;
> u32 vidcon1;
> + u32 vidout_con;
> + u32 i80ifcon;
> + bool i80_if;
> bool suspended;
> int pipe;
> wait_queue_head_t wait_vsync_queue;
> atomic_t wait_vsync_event;
> + atomic_t win_updated;
> + atomic_t triggering;
>
> struct exynos_drm_panel_info panel;
> struct fimd_driver_data *driver_data;
> @@ -243,6 +281,14 @@ static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
> unsigned long ideal_clk = mode->htotal * mode->vtotal * mode->vrefresh;
> u32 clkdiv;
>
> + if (ctx->i80_if) {
> + /*
> + * The frame done interrupt should be occurred prior to the
> + * next TE signal.
> + */
> + ideal_clk *= 2;
> + }
> +
> /* Find the clock divider value that gets us closest to ideal_clk */
> clkdiv = DIV_ROUND_UP(clk_get_rate(ctx->lcd_clk), ideal_clk);
>
> @@ -271,11 +317,10 @@ static void fimd_commit(struct exynos_drm_manager *mgr)
> {
> struct fimd_context *ctx = mgr->ctx;
> struct drm_display_mode *mode = &ctx->mode;
> - struct fimd_driver_data *driver_data;
> - u32 val, clkdiv, vidcon1;
> - int vsync_len, vbpd, vfpd, hsync_len, hbpd, hfpd;
> + struct fimd_driver_data *driver_data = ctx->driver_data;
> + void *timing_base = ctx->regs + driver_data->timing_base;
> + u32 val, clkdiv;
>
> - driver_data = ctx->driver_data;
> if (ctx->suspended)
> return;
>
> @@ -283,33 +328,65 @@ static void fimd_commit(struct exynos_drm_manager *mgr)
> if (mode->htotal == 0 || mode->vtotal == 0)
> return;
>
> - /* setup polarity values */
> - vidcon1 = ctx->vidcon1;
> - if (mode->flags & DRM_MODE_FLAG_NVSYNC)
> - vidcon1 |= VIDCON1_INV_VSYNC;
> - if (mode->flags & DRM_MODE_FLAG_NHSYNC)
> - vidcon1 |= VIDCON1_INV_HSYNC;
> - writel(vidcon1, ctx->regs + driver_data->timing_base + VIDCON1);
> -
> - /* setup vertical timing values. */
> - vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
> - vbpd = mode->crtc_vtotal - mode->crtc_vsync_end;
> - vfpd = mode->crtc_vsync_start - mode->crtc_vdisplay;
> -
> - val = VIDTCON0_VBPD(vbpd - 1) |
> - VIDTCON0_VFPD(vfpd - 1) |
> - VIDTCON0_VSPW(vsync_len - 1);
> - writel(val, ctx->regs + driver_data->timing_base + VIDTCON0);
> -
> - /* setup horizontal timing values. */
> - hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
> - hbpd = mode->crtc_htotal - mode->crtc_hsync_end;
> - hfpd = mode->crtc_hsync_start - mode->crtc_hdisplay;
> -
> - val = VIDTCON1_HBPD(hbpd - 1) |
> - VIDTCON1_HFPD(hfpd - 1) |
> - VIDTCON1_HSPW(hsync_len - 1);
> - writel(val, ctx->regs + driver_data->timing_base + VIDTCON1);
> + if (ctx->i80_if) {
> + val = ctx->i80ifcon | I80IFEN_ENABLE;
> + writel(val, timing_base + I80IFCONFAx(0));
> +
> + /* disable auto frame rate */
> + writel(0, timing_base + I80IFCONFBx(0));
> +
> + if (ctx->vidout_con)
> + writel(ctx->vidout_con, timing_base + VIDOUT_CON);
VIDOUT_CON register should be set in case of video mode also if
has_vidoutcon is 1. Can you re-send only this patch fixing it up?
Thanks,
Inki Dae
More information about the dri-devel
mailing list