From fe9e3137cffc880b5162f2cc039df48712c496bb Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Tue, 29 Jan 2013 16:28:30 +0900 Subject: drm/exynos: fix iommu address allocation order This patch modifies iommu address allocation order from 64k to 4k. 64k order causes waste of the io space and this was our mistakes. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_iommu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_iommu.h b/drivers/gpu/drm/exynos/exynos_drm_iommu.h index 53b7dee..598e60f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_iommu.h +++ b/drivers/gpu/drm/exynos/exynos_drm_iommu.h @@ -14,7 +14,7 @@ #define EXYNOS_DEV_ADDR_START 0x20000000 #define EXYNOS_DEV_ADDR_SIZE 0x40000000 -#define EXYNOS_DEV_ADDR_ORDER 0x4 +#define EXYNOS_DEV_ADDR_ORDER 0x0 #ifdef CONFIG_DRM_EXYNOS_IOMMU -- cgit v1.1 From b9ede277e15916a9ec3c6c1932c390e4768e71a9 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Tue, 29 Jan 2013 17:51:09 +0900 Subject: drm/exynos: consider exception case to fb handle creation GETFB ioctl request creates a new handle to only one gem object so it should check if the given fb has one gem object. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_fb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 294c051..31d4cb1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -99,6 +99,10 @@ static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb, DRM_DEBUG_KMS("%s\n", __FILE__); + /* This fb should have only one gem object. */ + if (WARN_ON(exynos_fb->buf_cnt != 1)) + return -EINVAL; + return drm_gem_handle_create(file_priv, &exynos_fb->exynos_gem_obj[0]->base, handle); } -- cgit v1.1 From e44a5c00169df634c152bdba65c7b735eb3a7a81 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 25 Jan 2013 14:45:42 +0530 Subject: drm/exynos: Add missing braces around sizeof Fixes the following checkpatch warning: WARNING: sizeof *sgt should be sizeof(*sgt) Signed-off-by: Sachin Kamat Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 9a4c08e..ddcfb5d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -429,7 +429,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev, g2d_userptr->pages = pages; - sgt = kzalloc(sizeof *sgt, GFP_KERNEL); + sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); if (!sgt) { DRM_ERROR("failed to allocate sg table.\n"); ret = -ENOMEM; -- cgit v1.1 From 5af9f116e6a0e1de675da979a19f95a74ce2aa2e Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Thu, 7 Feb 2013 16:17:54 +0900 Subject: drm/exynos: fix wrong pointer access at vm close. This patch fixes wrong pointer access issue to filp->f_op and filp->private_data. The exynos_drm_gem_mmap_ioctl() changes filp->f_op and filp->private_data temporarily and restore them to use original ones in exynos_drm_gem_mmap_buffer() but there was no lock between the changing and the restoring so wrong pointer access to filp->f_op and filp->private_data was induced by vm close callback. So this patch uses mutex lock properly to resolve this issue. Signed-off-by: YoungJun Cho Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_gem.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 4731807..67e17ce 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -329,17 +329,11 @@ static struct drm_file *exynos_drm_find_drm_file(struct drm_device *drm_dev, { struct drm_file *file_priv; - mutex_lock(&drm_dev->struct_mutex); - /* find current process's drm_file from filelist. */ - list_for_each_entry(file_priv, &drm_dev->filelist, lhead) { - if (file_priv->filp == filp) { - mutex_unlock(&drm_dev->struct_mutex); + list_for_each_entry(file_priv, &drm_dev->filelist, lhead) + if (file_priv->filp == filp) return file_priv; - } - } - mutex_unlock(&drm_dev->struct_mutex); WARN_ON(1); return ERR_PTR(-EFAULT); @@ -400,9 +394,7 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp, */ drm_gem_object_reference(obj); - mutex_lock(&drm_dev->struct_mutex); drm_vm_open_locked(drm_dev, vma); - mutex_unlock(&drm_dev->struct_mutex); return 0; } @@ -432,6 +424,16 @@ int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data, } /* + * We have to use gem object and its fops for specific mmaper, + * but vm_mmap() can deliver only filp. So we have to change + * filp->f_op and filp->private_data temporarily, then restore + * again. So it is important to keep lock until restoration the + * settings to prevent others from misuse of filp->f_op or + * filp->private_data. + */ + mutex_lock(&dev->struct_mutex); + + /* * Set specific mmper's fops. And it will be restored by * exynos_drm_gem_mmap_buffer to dev->driver->fops. * This is used to call specific mapper temporarily. @@ -448,13 +450,20 @@ int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data, addr = vm_mmap(file_priv->filp, 0, args->size, PROT_READ | PROT_WRITE, MAP_SHARED, 0); - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_unreference(obj); if (IS_ERR((void *)addr)) { - file_priv->filp->private_data = file_priv; + /* check filp->f_op, filp->private_data are restored */ + if (file_priv->filp->f_op == &exynos_drm_gem_fops) { + file_priv->filp->f_op = fops_get(dev->driver->fops); + file_priv->filp->private_data = file_priv; + } + mutex_unlock(&dev->struct_mutex); return PTR_ERR((void *)addr); } + mutex_unlock(&dev->struct_mutex); + args->mapped = addr; DRM_DEBUG_KMS("mapped = 0x%lx\n", (unsigned long)args->mapped); -- cgit v1.1 From 979c0c7eb0fb969f0621c7017a6a87e6a0e36a4c Mon Sep 17 00:00:00 2001 From: YoungJun Cho Date: Tue, 12 Feb 2013 21:23:54 +0900 Subject: drm/exynos: release resources properly when fb creation is failed. This patch releases allocated resources properly when exynos_user_fb_create() is failed. Signed-off-by: YoungJun Cho Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_fb.c | 51 ++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 31d4cb1..0e04f4e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -221,23 +221,25 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_gem_object *obj; + struct exynos_drm_gem_obj *exynos_gem_obj; struct exynos_drm_fb *exynos_fb; int i, ret; DRM_DEBUG_KMS("%s\n", __FILE__); - obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]); - if (!obj) { - DRM_ERROR("failed to lookup gem object\n"); - return ERR_PTR(-ENOENT); - } - exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL); if (!exynos_fb) { DRM_ERROR("failed to allocate exynos drm framebuffer\n"); return ERR_PTR(-ENOMEM); } + obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]); + if (!obj) { + DRM_ERROR("failed to lookup gem object\n"); + ret = -ENOENT; + goto err_free; + } + drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd); exynos_fb->exynos_gem_obj[0] = to_exynos_gem_obj(obj); exynos_fb->buf_cnt = exynos_drm_format_num_buffers(mode_cmd); @@ -245,43 +247,44 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, DRM_DEBUG_KMS("buf_cnt = %d\n", exynos_fb->buf_cnt); for (i = 1; i < exynos_fb->buf_cnt; i++) { - struct exynos_drm_gem_obj *exynos_gem_obj; - int ret; - obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[i]); if (!obj) { DRM_ERROR("failed to lookup gem object\n"); - kfree(exynos_fb); - return ERR_PTR(-ENOENT); + ret = -ENOENT; + exynos_fb->buf_cnt = i; + goto err_unreference; } exynos_gem_obj = to_exynos_gem_obj(obj); + exynos_fb->exynos_gem_obj[i] = exynos_gem_obj; ret = check_fb_gem_memory_type(dev, exynos_gem_obj); if (ret < 0) { DRM_ERROR("cannot use this gem memory type for fb.\n"); - kfree(exynos_fb); - return ERR_PTR(ret); + goto err_unreference; } - - exynos_fb->exynos_gem_obj[i] = to_exynos_gem_obj(obj); } ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs); if (ret) { - for (i = 0; i < exynos_fb->buf_cnt; i++) { - struct exynos_drm_gem_obj *gem_obj; - - gem_obj = exynos_fb->exynos_gem_obj[i]; - drm_gem_object_unreference_unlocked(&gem_obj->base); - } - - kfree(exynos_fb); - return ERR_PTR(ret); + DRM_ERROR("failed to init framebuffer.\n"); + goto err_unreference; } return &exynos_fb->fb; + +err_unreference: + for (i = 0; i < exynos_fb->buf_cnt; i++) { + struct drm_gem_object *obj; + + obj = &exynos_fb->exynos_gem_obj[i]->base; + if (obj) + drm_gem_object_unreference_unlocked(obj); + } +err_free: + kfree(exynos_fb); + return ERR_PTR(ret); } struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb, -- cgit v1.1 From 438c0f85cbbe6e7025e2375f97f5223b6eac5cd7 Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Tue, 15 Jan 2013 08:11:05 -0500 Subject: drm/exynos: add display-mode-check operation to exynos_mixer_ops struct This patch adds the display mode check operation to exynos_mixer_ops in drm-common-hdmi. In Exynos SoCs, mixer IP can put certain restrictions on the proposed display modes. These restriction needs to be considered during mode negotiation, which happens immediately after edid parsing. Both, mixer check-mode and hdmi check-timing callbacks are called one after another and ANDed result is returned back. Signed-off-by: Rahul Sharma Reviewed-by: Sean Paul Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 12 ++++++++++++ drivers/gpu/drm/exynos/exynos_drm_hdmi.h | 5 ++++- drivers/gpu/drm/exynos/exynos_hdmi.c | 13 ++++++------- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c index 2864453..7c27df0 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c @@ -124,9 +124,21 @@ static struct edid *drm_hdmi_get_edid(struct device *dev, static int drm_hdmi_check_timing(struct device *dev, void *timing) { struct drm_hdmi_context *ctx = to_context(dev); + int ret = 0; DRM_DEBUG_KMS("%s\n", __FILE__); + /* + * Both, mixer and hdmi should be able to handle the requested mode. + * If any of the two fails, return mode as BAD. + */ + + if (mixer_ops && mixer_ops->check_timing) + ret = mixer_ops->check_timing(ctx->mixer_ctx->ctx, timing); + + if (ret) + return ret; + if (hdmi_ops && hdmi_ops->check_timing) return hdmi_ops->check_timing(ctx->hdmi_ctx->ctx, timing); diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h index d80516f..b7faa36 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h @@ -32,7 +32,7 @@ struct exynos_hdmi_ops { bool (*is_connected)(void *ctx); struct edid *(*get_edid)(void *ctx, struct drm_connector *connector); - int (*check_timing)(void *ctx, void *timing); + int (*check_timing)(void *ctx, struct fb_videomode *timing); int (*power_on)(void *ctx, int mode); /* manager */ @@ -58,6 +58,9 @@ struct exynos_mixer_ops { void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay); void (*win_commit)(void *ctx, int zpos); void (*win_disable)(void *ctx, int zpos); + + /* display */ + int (*check_timing)(void *ctx, struct fb_videomode *timing); }; void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx); diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index fbab3c4..ba33015 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1457,21 +1457,20 @@ static int hdmi_v14_check_timing(struct fb_videomode *check_timing) return -EINVAL; } -static int hdmi_check_timing(void *ctx, void *timing) +static int hdmi_check_timing(void *ctx, struct fb_videomode *timing) { struct hdmi_context *hdata = ctx; - struct fb_videomode *check_timing = timing; DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); - DRM_DEBUG_KMS("[%d]x[%d] [%d]Hz [%x]\n", check_timing->xres, - check_timing->yres, check_timing->refresh, - check_timing->vmode); + DRM_DEBUG_KMS("[%d]x[%d] [%d]Hz [%x]\n", timing->xres, + timing->yres, timing->refresh, + timing->vmode); if (hdata->type == HDMI_TYPE13) - return hdmi_v13_check_timing(check_timing); + return hdmi_v13_check_timing(timing); else - return hdmi_v14_check_timing(check_timing); + return hdmi_v14_check_timing(timing); } static void hdmi_set_acr(u32 freq, u8 *acr) -- cgit v1.1 From 0ea6822f5215b1771949e8b278f66ed787ba83f1 Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Tue, 15 Jan 2013 08:11:06 -0500 Subject: drm/exynos: implement display-mode-check callback in mixer driver This patch adds the implementation of check_timing callback in the mixer driver. Based on the mixer version, correct set of restrictions will be exposed by the mixer driver. A resolution will be acceptable only if passes the criteria set by mixer and hdmi IPs. Signed-off-by: Rahul Sharma Signed-off-by: Sean Paul Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_mixer.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index c414584..cc809ca 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -818,6 +818,29 @@ static void mixer_win_disable(void *ctx, int win) mixer_ctx->win_data[win].enabled = false; } +int mixer_check_timing(void *ctx, struct fb_videomode *timing) +{ + struct mixer_context *mixer_ctx = ctx; + u32 w, h; + + w = timing->xres; + h = timing->yres; + + DRM_DEBUG_KMS("%s : xres=%d, yres=%d, refresh=%d, intl=%d\n", + __func__, timing->xres, timing->yres, + timing->refresh, (timing->vmode & + FB_VMODE_INTERLACED) ? true : false); + + if (mixer_ctx->mxr_ver == MXR_VER_0_0_0_16) + return 0; + + if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) || + (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) || + (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080)) + return 0; + + return -EINVAL; +} static void mixer_wait_for_vblank(void *ctx) { struct mixer_context *mixer_ctx = ctx; @@ -955,6 +978,9 @@ static struct exynos_mixer_ops mixer_ops = { .win_mode_set = mixer_win_mode_set, .win_commit = mixer_win_commit, .win_disable = mixer_win_disable, + + /* display */ + .check_timing = mixer_check_timing, }; static irqreturn_t mixer_irq_handler(int irq, void *arg) -- cgit v1.1 From 29630743c97cc4c395c308ea9d0c12bf55c55a92 Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Tue, 15 Jan 2013 08:11:07 -0500 Subject: drm/exynos: mixer: set correct mode for range of resolutions With this patch, mixer driver find the correct resolution mode for the range of resolutions, upto 1080 vertical lines. Resolution will be categorized to NTSC SD, PAL SD or HD and the correct mode is set to the mixer configuration register. Signed-off-by: Rahul Sharma Signed-off-by: Sean Paul Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_mixer.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index cc809ca..e919aba 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -284,13 +284,13 @@ static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height) MXR_CFG_SCAN_PROGRASSIVE); /* choosing between porper HD and SD mode */ - if (height == 480) + if (height <= 480) val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD; - else if (height == 576) + else if (height <= 576) val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD; - else if (height == 720) + else if (height <= 720) val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD; - else if (height == 1080) + else if (height <= 1080) val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD; else val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD; -- cgit v1.1 From 2f7e2ed073f629405a8054f14bd001dc68b0e17a Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Tue, 15 Jan 2013 08:11:08 -0500 Subject: drm/exynos: hdmi: support extra resolutions using drm_display_mode timings This patch programs the core and timing generator registers using the timing data provided in drm_display_mode and not using hard-coded configurations. Additional PHY configs has been added. This allows us to support more permissible resolutions and refresh rates. Signed-off-by: Rahul Sharma Signed-off-by: Sean Paul Signed-off-by: Shirish S Signed-off-by: Akshay Saraswat Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_hdmi.c | 1022 +++++++++++++--------------------- 1 file changed, 374 insertions(+), 648 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index ba33015..6d63f90 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -87,6 +87,73 @@ struct hdmi_resources { int regul_count; }; +struct hdmi_tg_regs { + u8 cmd[1]; + u8 h_fsz[2]; + u8 hact_st[2]; + u8 hact_sz[2]; + u8 v_fsz[2]; + u8 vsync[2]; + u8 vsync2[2]; + u8 vact_st[2]; + u8 vact_sz[2]; + u8 field_chg[2]; + u8 vact_st2[2]; + u8 vact_st3[2]; + u8 vact_st4[2]; + u8 vsync_top_hdmi[2]; + u8 vsync_bot_hdmi[2]; + u8 field_top_hdmi[2]; + u8 field_bot_hdmi[2]; + u8 tg_3d[1]; +}; + +struct hdmi_core_regs { + u8 h_blank[2]; + u8 v2_blank[2]; + u8 v1_blank[2]; + u8 v_line[2]; + u8 h_line[2]; + u8 hsync_pol[1]; + u8 vsync_pol[1]; + u8 int_pro_mode[1]; + u8 v_blank_f0[2]; + u8 v_blank_f1[2]; + u8 h_sync_start[2]; + u8 h_sync_end[2]; + u8 v_sync_line_bef_2[2]; + u8 v_sync_line_bef_1[2]; + u8 v_sync_line_aft_2[2]; + u8 v_sync_line_aft_1[2]; + u8 v_sync_line_aft_pxl_2[2]; + u8 v_sync_line_aft_pxl_1[2]; + u8 v_blank_f2[2]; /* for 3D mode */ + u8 v_blank_f3[2]; /* for 3D mode */ + u8 v_blank_f4[2]; /* for 3D mode */ + u8 v_blank_f5[2]; /* for 3D mode */ + u8 v_sync_line_aft_3[2]; + u8 v_sync_line_aft_4[2]; + u8 v_sync_line_aft_5[2]; + u8 v_sync_line_aft_6[2]; + u8 v_sync_line_aft_pxl_3[2]; + u8 v_sync_line_aft_pxl_4[2]; + u8 v_sync_line_aft_pxl_5[2]; + u8 v_sync_line_aft_pxl_6[2]; + u8 vact_space_1[2]; + u8 vact_space_2[2]; + u8 vact_space_3[2]; + u8 vact_space_4[2]; + u8 vact_space_5[2]; + u8 vact_space_6[2]; +}; + +struct hdmi_v14_conf { + int pixel_clock; + struct hdmi_core_regs core; + struct hdmi_tg_regs tg; + int cea_video_id; +}; + struct hdmi_context { struct device *dev; struct drm_device *drm_dev; @@ -104,6 +171,7 @@ struct hdmi_context { /* current hdmiphy conf index */ int cur_conf; + struct hdmi_v14_conf mode_conf; struct hdmi_resources res; @@ -392,586 +460,132 @@ static const struct hdmi_v13_conf hdmi_v13_confs[] = { }; /* HDMI Version 1.4 */ -static const u8 hdmiphy_conf27_027[32] = { - 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08, - 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80, - 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, - 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, -}; - -static const u8 hdmiphy_conf74_176[32] = { - 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x5b, 0xef, 0x08, - 0x81, 0xa0, 0xb9, 0xd8, 0x45, 0xa0, 0xac, 0x80, - 0x5a, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, - 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, -}; - -static const u8 hdmiphy_conf74_25[32] = { - 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08, - 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80, - 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, - 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, -}; - -static const u8 hdmiphy_conf148_5[32] = { - 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08, - 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80, - 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, - 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00, -}; - -struct hdmi_tg_regs { - u8 cmd; - u8 h_fsz_l; - u8 h_fsz_h; - u8 hact_st_l; - u8 hact_st_h; - u8 hact_sz_l; - u8 hact_sz_h; - u8 v_fsz_l; - u8 v_fsz_h; - u8 vsync_l; - u8 vsync_h; - u8 vsync2_l; - u8 vsync2_h; - u8 vact_st_l; - u8 vact_st_h; - u8 vact_sz_l; - u8 vact_sz_h; - u8 field_chg_l; - u8 field_chg_h; - u8 vact_st2_l; - u8 vact_st2_h; - u8 vact_st3_l; - u8 vact_st3_h; - u8 vact_st4_l; - u8 vact_st4_h; - u8 vsync_top_hdmi_l; - u8 vsync_top_hdmi_h; - u8 vsync_bot_hdmi_l; - u8 vsync_bot_hdmi_h; - u8 field_top_hdmi_l; - u8 field_top_hdmi_h; - u8 field_bot_hdmi_l; - u8 field_bot_hdmi_h; - u8 tg_3d; -}; - -struct hdmi_core_regs { - u8 h_blank[2]; - u8 v2_blank[2]; - u8 v1_blank[2]; - u8 v_line[2]; - u8 h_line[2]; - u8 hsync_pol[1]; - u8 vsync_pol[1]; - u8 int_pro_mode[1]; - u8 v_blank_f0[2]; - u8 v_blank_f1[2]; - u8 h_sync_start[2]; - u8 h_sync_end[2]; - u8 v_sync_line_bef_2[2]; - u8 v_sync_line_bef_1[2]; - u8 v_sync_line_aft_2[2]; - u8 v_sync_line_aft_1[2]; - u8 v_sync_line_aft_pxl_2[2]; - u8 v_sync_line_aft_pxl_1[2]; - u8 v_blank_f2[2]; /* for 3D mode */ - u8 v_blank_f3[2]; /* for 3D mode */ - u8 v_blank_f4[2]; /* for 3D mode */ - u8 v_blank_f5[2]; /* for 3D mode */ - u8 v_sync_line_aft_3[2]; - u8 v_sync_line_aft_4[2]; - u8 v_sync_line_aft_5[2]; - u8 v_sync_line_aft_6[2]; - u8 v_sync_line_aft_pxl_3[2]; - u8 v_sync_line_aft_pxl_4[2]; - u8 v_sync_line_aft_pxl_5[2]; - u8 v_sync_line_aft_pxl_6[2]; - u8 vact_space_1[2]; - u8 vact_space_2[2]; - u8 vact_space_3[2]; - u8 vact_space_4[2]; - u8 vact_space_5[2]; - u8 vact_space_6[2]; -}; - -struct hdmi_preset_conf { - struct hdmi_core_regs core; - struct hdmi_tg_regs tg; -}; - -struct hdmi_conf { - int width; - int height; - int vrefresh; - bool interlace; - int cea_video_id; - const u8 *hdmiphy_data; - const struct hdmi_preset_conf *conf; -}; - -static const struct hdmi_preset_conf hdmi_conf_480p60 = { - .core = { - .h_blank = {0x8a, 0x00}, - .v2_blank = {0x0d, 0x02}, - .v1_blank = {0x2d, 0x00}, - .v_line = {0x0d, 0x02}, - .h_line = {0x5a, 0x03}, - .hsync_pol = {0x01}, - .vsync_pol = {0x01}, - .int_pro_mode = {0x00}, - .v_blank_f0 = {0xff, 0xff}, - .v_blank_f1 = {0xff, 0xff}, - .h_sync_start = {0x0e, 0x00}, - .h_sync_end = {0x4c, 0x00}, - .v_sync_line_bef_2 = {0x0f, 0x00}, - .v_sync_line_bef_1 = {0x09, 0x00}, - .v_sync_line_aft_2 = {0xff, 0xff}, - .v_sync_line_aft_1 = {0xff, 0xff}, - .v_sync_line_aft_pxl_2 = {0xff, 0xff}, - .v_sync_line_aft_pxl_1 = {0xff, 0xff}, - .v_blank_f2 = {0xff, 0xff}, - .v_blank_f3 = {0xff, 0xff}, - .v_blank_f4 = {0xff, 0xff}, - .v_blank_f5 = {0xff, 0xff}, - .v_sync_line_aft_3 = {0xff, 0xff}, - .v_sync_line_aft_4 = {0xff, 0xff}, - .v_sync_line_aft_5 = {0xff, 0xff}, - .v_sync_line_aft_6 = {0xff, 0xff}, - .v_sync_line_aft_pxl_3 = {0xff, 0xff}, - .v_sync_line_aft_pxl_4 = {0xff, 0xff}, - .v_sync_line_aft_pxl_5 = {0xff, 0xff}, - .v_sync_line_aft_pxl_6 = {0xff, 0xff}, - .vact_space_1 = {0xff, 0xff}, - .vact_space_2 = {0xff, 0xff}, - .vact_space_3 = {0xff, 0xff}, - .vact_space_4 = {0xff, 0xff}, - .vact_space_5 = {0xff, 0xff}, - .vact_space_6 = {0xff, 0xff}, - /* other don't care */ - }, - .tg = { - 0x00, /* cmd */ - 0x5a, 0x03, /* h_fsz */ - 0x8a, 0x00, 0xd0, 0x02, /* hact */ - 0x0d, 0x02, /* v_fsz */ - 0x01, 0x00, 0x33, 0x02, /* vsync */ - 0x2d, 0x00, 0xe0, 0x01, /* vact */ - 0x33, 0x02, /* field_chg */ - 0x48, 0x02, /* vact_st2 */ - 0x00, 0x00, /* vact_st3 */ - 0x00, 0x00, /* vact_st4 */ - 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */ - 0x01, 0x00, 0x33, 0x02, /* field top/bot */ - 0x00, /* 3d FP */ - }, +struct hdmiphy_config { + int pixel_clock; + u8 conf[32]; }; -static const struct hdmi_preset_conf hdmi_conf_720p50 = { - .core = { - .h_blank = {0xbc, 0x02}, - .v2_blank = {0xee, 0x02}, - .v1_blank = {0x1e, 0x00}, - .v_line = {0xee, 0x02}, - .h_line = {0xbc, 0x07}, - .hsync_pol = {0x00}, - .vsync_pol = {0x00}, - .int_pro_mode = {0x00}, - .v_blank_f0 = {0xff, 0xff}, - .v_blank_f1 = {0xff, 0xff}, - .h_sync_start = {0xb6, 0x01}, - .h_sync_end = {0xde, 0x01}, - .v_sync_line_bef_2 = {0x0a, 0x00}, - .v_sync_line_bef_1 = {0x05, 0x00}, - .v_sync_line_aft_2 = {0xff, 0xff}, - .v_sync_line_aft_1 = {0xff, 0xff}, - .v_sync_line_aft_pxl_2 = {0xff, 0xff}, - .v_sync_line_aft_pxl_1 = {0xff, 0xff}, - .v_blank_f2 = {0xff, 0xff}, - .v_blank_f3 = {0xff, 0xff}, - .v_blank_f4 = {0xff, 0xff}, - .v_blank_f5 = {0xff, 0xff}, - .v_sync_line_aft_3 = {0xff, 0xff}, - .v_sync_line_aft_4 = {0xff, 0xff}, - .v_sync_line_aft_5 = {0xff, 0xff}, - .v_sync_line_aft_6 = {0xff, 0xff}, - .v_sync_line_aft_pxl_3 = {0xff, 0xff}, - .v_sync_line_aft_pxl_4 = {0xff, 0xff}, - .v_sync_line_aft_pxl_5 = {0xff, 0xff}, - .v_sync_line_aft_pxl_6 = {0xff, 0xff}, - .vact_space_1 = {0xff, 0xff}, - .vact_space_2 = {0xff, 0xff}, - .vact_space_3 = {0xff, 0xff}, - .vact_space_4 = {0xff, 0xff}, - .vact_space_5 = {0xff, 0xff}, - .vact_space_6 = {0xff, 0xff}, - /* other don't care */ - }, - .tg = { - 0x00, /* cmd */ - 0xbc, 0x07, /* h_fsz */ - 0xbc, 0x02, 0x00, 0x05, /* hact */ - 0xee, 0x02, /* v_fsz */ - 0x01, 0x00, 0x33, 0x02, /* vsync */ - 0x1e, 0x00, 0xd0, 0x02, /* vact */ - 0x33, 0x02, /* field_chg */ - 0x48, 0x02, /* vact_st2 */ - 0x00, 0x00, /* vact_st3 */ - 0x00, 0x00, /* vact_st4 */ - 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */ - 0x01, 0x00, 0x33, 0x02, /* field top/bot */ - 0x00, /* 3d FP */ +/* list of all required phy config settings */ +static const struct hdmiphy_config hdmiphy_v14_configs[] = { + { + .pixel_clock = 25200000, + .conf = { + 0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08, + 0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80, + 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, + 0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, + }, }, -}; - -static const struct hdmi_preset_conf hdmi_conf_720p60 = { - .core = { - .h_blank = {0x72, 0x01}, - .v2_blank = {0xee, 0x02}, - .v1_blank = {0x1e, 0x00}, - .v_line = {0xee, 0x02}, - .h_line = {0x72, 0x06}, - .hsync_pol = {0x00}, - .vsync_pol = {0x00}, - .int_pro_mode = {0x00}, - .v_blank_f0 = {0xff, 0xff}, - .v_blank_f1 = {0xff, 0xff}, - .h_sync_start = {0x6c, 0x00}, - .h_sync_end = {0x94, 0x00}, - .v_sync_line_bef_2 = {0x0a, 0x00}, - .v_sync_line_bef_1 = {0x05, 0x00}, - .v_sync_line_aft_2 = {0xff, 0xff}, - .v_sync_line_aft_1 = {0xff, 0xff}, - .v_sync_line_aft_pxl_2 = {0xff, 0xff}, - .v_sync_line_aft_pxl_1 = {0xff, 0xff}, - .v_blank_f2 = {0xff, 0xff}, - .v_blank_f3 = {0xff, 0xff}, - .v_blank_f4 = {0xff, 0xff}, - .v_blank_f5 = {0xff, 0xff}, - .v_sync_line_aft_3 = {0xff, 0xff}, - .v_sync_line_aft_4 = {0xff, 0xff}, - .v_sync_line_aft_5 = {0xff, 0xff}, - .v_sync_line_aft_6 = {0xff, 0xff}, - .v_sync_line_aft_pxl_3 = {0xff, 0xff}, - .v_sync_line_aft_pxl_4 = {0xff, 0xff}, - .v_sync_line_aft_pxl_5 = {0xff, 0xff}, - .v_sync_line_aft_pxl_6 = {0xff, 0xff}, - .vact_space_1 = {0xff, 0xff}, - .vact_space_2 = {0xff, 0xff}, - .vact_space_3 = {0xff, 0xff}, - .vact_space_4 = {0xff, 0xff}, - .vact_space_5 = {0xff, 0xff}, - .vact_space_6 = {0xff, 0xff}, - /* other don't care */ + { + .pixel_clock = 27000000, + .conf = { + 0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20, + 0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80, + 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, + 0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, + }, }, - .tg = { - 0x00, /* cmd */ - 0x72, 0x06, /* h_fsz */ - 0x72, 0x01, 0x00, 0x05, /* hact */ - 0xee, 0x02, /* v_fsz */ - 0x01, 0x00, 0x33, 0x02, /* vsync */ - 0x1e, 0x00, 0xd0, 0x02, /* vact */ - 0x33, 0x02, /* field_chg */ - 0x48, 0x02, /* vact_st2 */ - 0x00, 0x00, /* vact_st3 */ - 0x00, 0x00, /* vact_st4 */ - 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */ - 0x01, 0x00, 0x33, 0x02, /* field top/bot */ - 0x00, /* 3d FP */ + { + .pixel_clock = 27027000, + .conf = { + 0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08, + 0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80, + 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, + 0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, + }, }, -}; - -static const struct hdmi_preset_conf hdmi_conf_1080i50 = { - .core = { - .h_blank = {0xd0, 0x02}, - .v2_blank = {0x32, 0x02}, - .v1_blank = {0x16, 0x00}, - .v_line = {0x65, 0x04}, - .h_line = {0x50, 0x0a}, - .hsync_pol = {0x00}, - .vsync_pol = {0x00}, - .int_pro_mode = {0x01}, - .v_blank_f0 = {0x49, 0x02}, - .v_blank_f1 = {0x65, 0x04}, - .h_sync_start = {0x0e, 0x02}, - .h_sync_end = {0x3a, 0x02}, - .v_sync_line_bef_2 = {0x07, 0x00}, - .v_sync_line_bef_1 = {0x02, 0x00}, - .v_sync_line_aft_2 = {0x39, 0x02}, - .v_sync_line_aft_1 = {0x34, 0x02}, - .v_sync_line_aft_pxl_2 = {0x38, 0x07}, - .v_sync_line_aft_pxl_1 = {0x38, 0x07}, - .v_blank_f2 = {0xff, 0xff}, - .v_blank_f3 = {0xff, 0xff}, - .v_blank_f4 = {0xff, 0xff}, - .v_blank_f5 = {0xff, 0xff}, - .v_sync_line_aft_3 = {0xff, 0xff}, - .v_sync_line_aft_4 = {0xff, 0xff}, - .v_sync_line_aft_5 = {0xff, 0xff}, - .v_sync_line_aft_6 = {0xff, 0xff}, - .v_sync_line_aft_pxl_3 = {0xff, 0xff}, - .v_sync_line_aft_pxl_4 = {0xff, 0xff}, - .v_sync_line_aft_pxl_5 = {0xff, 0xff}, - .v_sync_line_aft_pxl_6 = {0xff, 0xff}, - .vact_space_1 = {0xff, 0xff}, - .vact_space_2 = {0xff, 0xff}, - .vact_space_3 = {0xff, 0xff}, - .vact_space_4 = {0xff, 0xff}, - .vact_space_5 = {0xff, 0xff}, - .vact_space_6 = {0xff, 0xff}, - /* other don't care */ + { + .pixel_clock = 36000000, + .conf = { + 0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08, + 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80, + 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, + 0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, + }, }, - .tg = { - 0x00, /* cmd */ - 0x50, 0x0a, /* h_fsz */ - 0xd0, 0x02, 0x80, 0x07, /* hact */ - 0x65, 0x04, /* v_fsz */ - 0x01, 0x00, 0x33, 0x02, /* vsync */ - 0x16, 0x00, 0x1c, 0x02, /* vact */ - 0x33, 0x02, /* field_chg */ - 0x49, 0x02, /* vact_st2 */ - 0x00, 0x00, /* vact_st3 */ - 0x00, 0x00, /* vact_st4 */ - 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */ - 0x01, 0x00, 0x33, 0x02, /* field top/bot */ - 0x00, /* 3d FP */ + { + .pixel_clock = 40000000, + .conf = { + 0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08, + 0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80, + 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, + 0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80, + }, }, -}; - -static const struct hdmi_preset_conf hdmi_conf_1080i60 = { - .core = { - .h_blank = {0x18, 0x01}, - .v2_blank = {0x32, 0x02}, - .v1_blank = {0x16, 0x00}, - .v_line = {0x65, 0x04}, - .h_line = {0x98, 0x08}, - .hsync_pol = {0x00}, - .vsync_pol = {0x00}, - .int_pro_mode = {0x01}, - .v_blank_f0 = {0x49, 0x02}, - .v_blank_f1 = {0x65, 0x04}, - .h_sync_start = {0x56, 0x00}, - .h_sync_end = {0x82, 0x00}, - .v_sync_line_bef_2 = {0x07, 0x00}, - .v_sync_line_bef_1 = {0x02, 0x00}, - .v_sync_line_aft_2 = {0x39, 0x02}, - .v_sync_line_aft_1 = {0x34, 0x02}, - .v_sync_line_aft_pxl_2 = {0xa4, 0x04}, - .v_sync_line_aft_pxl_1 = {0xa4, 0x04}, - .v_blank_f2 = {0xff, 0xff}, - .v_blank_f3 = {0xff, 0xff}, - .v_blank_f4 = {0xff, 0xff}, - .v_blank_f5 = {0xff, 0xff}, - .v_sync_line_aft_3 = {0xff, 0xff}, - .v_sync_line_aft_4 = {0xff, 0xff}, - .v_sync_line_aft_5 = {0xff, 0xff}, - .v_sync_line_aft_6 = {0xff, 0xff}, - .v_sync_line_aft_pxl_3 = {0xff, 0xff}, - .v_sync_line_aft_pxl_4 = {0xff, 0xff}, - .v_sync_line_aft_pxl_5 = {0xff, 0xff}, - .v_sync_line_aft_pxl_6 = {0xff, 0xff}, - .vact_space_1 = {0xff, 0xff}, - .vact_space_2 = {0xff, 0xff}, - .vact_space_3 = {0xff, 0xff}, - .vact_space_4 = {0xff, 0xff}, - .vact_space_5 = {0xff, 0xff}, - .vact_space_6 = {0xff, 0xff}, - /* other don't care */ + { + .pixel_clock = 65000000, + .conf = { + 0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08, + 0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80, + 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, + 0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, + }, }, - .tg = { - 0x00, /* cmd */ - 0x98, 0x08, /* h_fsz */ - 0x18, 0x01, 0x80, 0x07, /* hact */ - 0x65, 0x04, /* v_fsz */ - 0x01, 0x00, 0x33, 0x02, /* vsync */ - 0x16, 0x00, 0x1c, 0x02, /* vact */ - 0x33, 0x02, /* field_chg */ - 0x49, 0x02, /* vact_st2 */ - 0x00, 0x00, /* vact_st3 */ - 0x00, 0x00, /* vact_st4 */ - 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */ - 0x01, 0x00, 0x33, 0x02, /* field top/bot */ - 0x00, /* 3d FP */ + { + .pixel_clock = 74176000, + .conf = { + 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08, + 0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80, + 0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, + 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, + }, }, -}; - -static const struct hdmi_preset_conf hdmi_conf_1080p30 = { - .core = { - .h_blank = {0x18, 0x01}, - .v2_blank = {0x65, 0x04}, - .v1_blank = {0x2d, 0x00}, - .v_line = {0x65, 0x04}, - .h_line = {0x98, 0x08}, - .hsync_pol = {0x00}, - .vsync_pol = {0x00}, - .int_pro_mode = {0x00}, - .v_blank_f0 = {0xff, 0xff}, - .v_blank_f1 = {0xff, 0xff}, - .h_sync_start = {0x56, 0x00}, - .h_sync_end = {0x82, 0x00}, - .v_sync_line_bef_2 = {0x09, 0x00}, - .v_sync_line_bef_1 = {0x04, 0x00}, - .v_sync_line_aft_2 = {0xff, 0xff}, - .v_sync_line_aft_1 = {0xff, 0xff}, - .v_sync_line_aft_pxl_2 = {0xff, 0xff}, - .v_sync_line_aft_pxl_1 = {0xff, 0xff}, - .v_blank_f2 = {0xff, 0xff}, - .v_blank_f3 = {0xff, 0xff}, - .v_blank_f4 = {0xff, 0xff}, - .v_blank_f5 = {0xff, 0xff}, - .v_sync_line_aft_3 = {0xff, 0xff}, - .v_sync_line_aft_4 = {0xff, 0xff}, - .v_sync_line_aft_5 = {0xff, 0xff}, - .v_sync_line_aft_6 = {0xff, 0xff}, - .v_sync_line_aft_pxl_3 = {0xff, 0xff}, - .v_sync_line_aft_pxl_4 = {0xff, 0xff}, - .v_sync_line_aft_pxl_5 = {0xff, 0xff}, - .v_sync_line_aft_pxl_6 = {0xff, 0xff}, - .vact_space_1 = {0xff, 0xff}, - .vact_space_2 = {0xff, 0xff}, - .vact_space_3 = {0xff, 0xff}, - .vact_space_4 = {0xff, 0xff}, - .vact_space_5 = {0xff, 0xff}, - .vact_space_6 = {0xff, 0xff}, - /* other don't care */ + { + .pixel_clock = 74250000, + .conf = { + 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08, + 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80, + 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, + 0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, + }, }, - .tg = { - 0x00, /* cmd */ - 0x98, 0x08, /* h_fsz */ - 0x18, 0x01, 0x80, 0x07, /* hact */ - 0x65, 0x04, /* v_fsz */ - 0x01, 0x00, 0x33, 0x02, /* vsync */ - 0x2d, 0x00, 0x38, 0x04, /* vact */ - 0x33, 0x02, /* field_chg */ - 0x48, 0x02, /* vact_st2 */ - 0x00, 0x00, /* vact_st3 */ - 0x00, 0x00, /* vact_st4 */ - 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */ - 0x01, 0x00, 0x33, 0x02, /* field top/bot */ - 0x00, /* 3d FP */ + { + .pixel_clock = 83500000, + .conf = { + 0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08, + 0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80, + 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, + 0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, + }, }, -}; - -static const struct hdmi_preset_conf hdmi_conf_1080p50 = { - .core = { - .h_blank = {0xd0, 0x02}, - .v2_blank = {0x65, 0x04}, - .v1_blank = {0x2d, 0x00}, - .v_line = {0x65, 0x04}, - .h_line = {0x50, 0x0a}, - .hsync_pol = {0x00}, - .vsync_pol = {0x00}, - .int_pro_mode = {0x00}, - .v_blank_f0 = {0xff, 0xff}, - .v_blank_f1 = {0xff, 0xff}, - .h_sync_start = {0x0e, 0x02}, - .h_sync_end = {0x3a, 0x02}, - .v_sync_line_bef_2 = {0x09, 0x00}, - .v_sync_line_bef_1 = {0x04, 0x00}, - .v_sync_line_aft_2 = {0xff, 0xff}, - .v_sync_line_aft_1 = {0xff, 0xff}, - .v_sync_line_aft_pxl_2 = {0xff, 0xff}, - .v_sync_line_aft_pxl_1 = {0xff, 0xff}, - .v_blank_f2 = {0xff, 0xff}, - .v_blank_f3 = {0xff, 0xff}, - .v_blank_f4 = {0xff, 0xff}, - .v_blank_f5 = {0xff, 0xff}, - .v_sync_line_aft_3 = {0xff, 0xff}, - .v_sync_line_aft_4 = {0xff, 0xff}, - .v_sync_line_aft_5 = {0xff, 0xff}, - .v_sync_line_aft_6 = {0xff, 0xff}, - .v_sync_line_aft_pxl_3 = {0xff, 0xff}, - .v_sync_line_aft_pxl_4 = {0xff, 0xff}, - .v_sync_line_aft_pxl_5 = {0xff, 0xff}, - .v_sync_line_aft_pxl_6 = {0xff, 0xff}, - .vact_space_1 = {0xff, 0xff}, - .vact_space_2 = {0xff, 0xff}, - .vact_space_3 = {0xff, 0xff}, - .vact_space_4 = {0xff, 0xff}, - .vact_space_5 = {0xff, 0xff}, - .vact_space_6 = {0xff, 0xff}, - /* other don't care */ + { + .pixel_clock = 106500000, + .conf = { + 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08, + 0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80, + 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, + 0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, + }, }, - .tg = { - 0x00, /* cmd */ - 0x50, 0x0a, /* h_fsz */ - 0xd0, 0x02, 0x80, 0x07, /* hact */ - 0x65, 0x04, /* v_fsz */ - 0x01, 0x00, 0x33, 0x02, /* vsync */ - 0x2d, 0x00, 0x38, 0x04, /* vact */ - 0x33, 0x02, /* field_chg */ - 0x48, 0x02, /* vact_st2 */ - 0x00, 0x00, /* vact_st3 */ - 0x00, 0x00, /* vact_st4 */ - 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */ - 0x01, 0x00, 0x33, 0x02, /* field top/bot */ - 0x00, /* 3d FP */ + { + .pixel_clock = 108000000, + .conf = { + 0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08, + 0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80, + 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, + 0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80, + }, }, -}; - -static const struct hdmi_preset_conf hdmi_conf_1080p60 = { - .core = { - .h_blank = {0x18, 0x01}, - .v2_blank = {0x65, 0x04}, - .v1_blank = {0x2d, 0x00}, - .v_line = {0x65, 0x04}, - .h_line = {0x98, 0x08}, - .hsync_pol = {0x00}, - .vsync_pol = {0x00}, - .int_pro_mode = {0x00}, - .v_blank_f0 = {0xff, 0xff}, - .v_blank_f1 = {0xff, 0xff}, - .h_sync_start = {0x56, 0x00}, - .h_sync_end = {0x82, 0x00}, - .v_sync_line_bef_2 = {0x09, 0x00}, - .v_sync_line_bef_1 = {0x04, 0x00}, - .v_sync_line_aft_2 = {0xff, 0xff}, - .v_sync_line_aft_1 = {0xff, 0xff}, - .v_sync_line_aft_pxl_2 = {0xff, 0xff}, - .v_sync_line_aft_pxl_1 = {0xff, 0xff}, - .v_blank_f2 = {0xff, 0xff}, - .v_blank_f3 = {0xff, 0xff}, - .v_blank_f4 = {0xff, 0xff}, - .v_blank_f5 = {0xff, 0xff}, - .v_sync_line_aft_3 = {0xff, 0xff}, - .v_sync_line_aft_4 = {0xff, 0xff}, - .v_sync_line_aft_5 = {0xff, 0xff}, - .v_sync_line_aft_6 = {0xff, 0xff}, - .v_sync_line_aft_pxl_3 = {0xff, 0xff}, - .v_sync_line_aft_pxl_4 = {0xff, 0xff}, - .v_sync_line_aft_pxl_5 = {0xff, 0xff}, - .v_sync_line_aft_pxl_6 = {0xff, 0xff}, - /* other don't care */ + { + .pixel_clock = 146250000, + .conf = { + 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08, + 0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80, + 0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, + 0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80, + }, }, - .tg = { - 0x00, /* cmd */ - 0x98, 0x08, /* h_fsz */ - 0x18, 0x01, 0x80, 0x07, /* hact */ - 0x65, 0x04, /* v_fsz */ - 0x01, 0x00, 0x33, 0x02, /* vsync */ - 0x2d, 0x00, 0x38, 0x04, /* vact */ - 0x33, 0x02, /* field_chg */ - 0x48, 0x02, /* vact_st2 */ - 0x00, 0x00, /* vact_st3 */ - 0x00, 0x00, /* vact_st4 */ - 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */ - 0x01, 0x00, 0x33, 0x02, /* field top/bot */ - 0x00, /* 3d FP */ + { + .pixel_clock = 148500000, + .conf = { + 0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08, + 0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80, + 0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, + 0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00, + }, }, }; -static const struct hdmi_conf hdmi_confs[] = { - { 720, 480, 60, false, 3, hdmiphy_conf27_027, &hdmi_conf_480p60 }, - { 1280, 720, 50, false, 19, hdmiphy_conf74_25, &hdmi_conf_720p50 }, - { 1280, 720, 60, false, 4, hdmiphy_conf74_25, &hdmi_conf_720p60 }, - { 1920, 1080, 50, true, 20, hdmiphy_conf74_25, &hdmi_conf_1080i50 }, - { 1920, 1080, 60, true, 5, hdmiphy_conf74_25, &hdmi_conf_1080i60 }, - { 1920, 1080, 30, false, 34, hdmiphy_conf74_176, &hdmi_conf_1080p30 }, - { 1920, 1080, 50, false, 31, hdmiphy_conf148_5, &hdmi_conf_1080p50 }, - { 1920, 1080, 60, false, 16, hdmiphy_conf148_5, &hdmi_conf_1080p60 }, -}; - struct hdmi_infoframe { enum HDMI_PACKET_TYPE type; u8 ver; @@ -1275,31 +889,6 @@ static int hdmi_v13_conf_index(struct drm_display_mode *mode) return -EINVAL; } -static int hdmi_v14_conf_index(struct drm_display_mode *mode) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(hdmi_confs); ++i) - if (hdmi_confs[i].width == mode->hdisplay && - hdmi_confs[i].height == mode->vdisplay && - hdmi_confs[i].vrefresh == mode->vrefresh && - hdmi_confs[i].interlace == - ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? - true : false)) - return i; - - return -EINVAL; -} - -static int hdmi_conf_index(struct hdmi_context *hdata, - struct drm_display_mode *mode) -{ - if (hdata->type == HDMI_TYPE13) - return hdmi_v13_conf_index(mode); - - return hdmi_v14_conf_index(mode); -} - static u8 hdmi_chksum(struct hdmi_context *hdata, u32 start, u8 len, u32 hdr_sum) { @@ -1357,7 +946,7 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata, if (hdata->type == HDMI_TYPE13) vic = hdmi_v13_confs[hdata->cur_conf].cea_video_id; else - vic = hdmi_confs[hdata->cur_conf].cea_video_id; + vic = hdata->mode_conf.cea_video_id; hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic); @@ -1434,25 +1023,33 @@ static int hdmi_v13_check_timing(struct fb_videomode *check_timing) return -EINVAL; } +static int hdmi_v14_find_phy_conf(int pixel_clock) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hdmiphy_v14_configs); i++) { + if (hdmiphy_v14_configs[i].pixel_clock == pixel_clock) + return i; + } + + DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock); + return -EINVAL; +} + static int hdmi_v14_check_timing(struct fb_videomode *check_timing) { int i; - DRM_DEBUG_KMS("valid mode : xres=%d, yres=%d, refresh=%d, intl=%d\n", + DRM_DEBUG_KMS("mode: xres=%d, yres=%d, refresh=%d, clock=%d, intl=%d\n", check_timing->xres, check_timing->yres, - check_timing->refresh, (check_timing->vmode & - FB_VMODE_INTERLACED) ? true : false); + check_timing->refresh, check_timing->pixclock, + (check_timing->vmode & FB_VMODE_INTERLACED) ? + true : false); - for (i = 0; i < ARRAY_SIZE(hdmi_confs); i++) - if (hdmi_confs[i].width == check_timing->xres && - hdmi_confs[i].height == check_timing->yres && - hdmi_confs[i].vrefresh == check_timing->refresh && - hdmi_confs[i].interlace == - ((check_timing->vmode & FB_VMODE_INTERLACED) ? - true : false)) - return 0; - - /* TODO */ + for (i = 0; i < ARRAY_SIZE(hdmiphy_v14_configs); i++) + if (hdmiphy_v14_configs[i].pixel_clock == + check_timing->pixclock) + return 0; return -EINVAL; } @@ -1794,9 +1391,8 @@ static void hdmi_v13_timing_apply(struct hdmi_context *hdata) static void hdmi_v14_timing_apply(struct hdmi_context *hdata) { - const struct hdmi_preset_conf *conf = hdmi_confs[hdata->cur_conf].conf; - const struct hdmi_core_regs *core = &conf->core; - const struct hdmi_tg_regs *tg = &conf->tg; + struct hdmi_core_regs *core = &hdata->mode_conf.core; + struct hdmi_tg_regs *tg = &hdata->mode_conf.tg; int tries; /* setting core registers */ @@ -1899,39 +1495,39 @@ static void hdmi_v14_timing_apply(struct hdmi_context *hdata) hdmi_reg_writeb(hdata, HDMI_VACT_SPACE_6_1, core->vact_space_6[1]); /* Timing generator registers */ - hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz_l); - hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz_h); - hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st_l); - hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st_h); - hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz_l); - hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz_h); - hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz_l); - hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz_h); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync_l); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync_h); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2_l); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2_h); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st_l); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st_h); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz_l); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz_h); - hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg_l); - hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg_h); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2_l); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2_h); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3_l); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3_h); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4_l); - hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4_h); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l); - hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h); - hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l); - hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h); - hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l); - hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h); - hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d); + hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]); + hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]); + hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]); + hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]); + hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]); + hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]); + hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]); + hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]); + hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]); + hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]); + hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]); + hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]); + hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]); + hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]); + hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]); + hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]); + hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]); + hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]); + hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]); + hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]); + hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_L, tg->vact_st3[0]); + hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST3_H, tg->vact_st3[1]); + hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_L, tg->vact_st4[0]); + hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST4_H, tg->vact_st4[1]); + hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]); + hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]); + hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]); + hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]); + hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]); + hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]); + hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]); + hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]); + hdmi_reg_writeb(hdata, HDMI_TG_3D, tg->tg_3d[0]); /* waiting for HDMIPHY's PLL to get to steady state */ for (tries = 100; tries; --tries) { @@ -2028,10 +1624,17 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata) } /* pixel clock */ - if (hdata->type == HDMI_TYPE13) + if (hdata->type == HDMI_TYPE13) { hdmiphy_data = hdmi_v13_confs[hdata->cur_conf].hdmiphy_data; - else - hdmiphy_data = hdmi_confs[hdata->cur_conf].hdmiphy_data; + } else { + i = hdmi_v14_find_phy_conf(hdata->mode_conf.pixel_clock); + if (i < 0) { + DRM_ERROR("failed to find hdmiphy conf\n"); + return; + } + + hdmiphy_data = hdmiphy_v14_configs[i].conf; + } memcpy(buffer, hdmiphy_data, 32); ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32); @@ -2099,7 +1702,7 @@ static void hdmi_mode_fixup(void *ctx, struct drm_connector *connector, if (hdata->type == HDMI_TYPE13) index = hdmi_v13_conf_index(adjusted_mode); else - index = hdmi_v14_conf_index(adjusted_mode); + index = hdmi_v14_find_phy_conf(adjusted_mode->clock * 1000); /* just return if user desired mode exists. */ if (index >= 0) @@ -2113,7 +1716,7 @@ static void hdmi_mode_fixup(void *ctx, struct drm_connector *connector, if (hdata->type == HDMI_TYPE13) index = hdmi_v13_conf_index(m); else - index = hdmi_v14_conf_index(m); + index = hdmi_v14_find_phy_conf(m->clock * 1000); if (index >= 0) { struct drm_mode_object base; @@ -2122,6 +1725,9 @@ static void hdmi_mode_fixup(void *ctx, struct drm_connector *connector, DRM_INFO("desired mode doesn't exist so\n"); DRM_INFO("use the most suitable mode among modes.\n"); + DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n", + m->hdisplay, m->vdisplay, m->vrefresh); + /* preserve display mode header while copying. */ head = adjusted_mode->head; base = adjusted_mode->base; @@ -2133,6 +1739,122 @@ static void hdmi_mode_fixup(void *ctx, struct drm_connector *connector, } } +static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value) +{ + int i; + BUG_ON(num_bytes > 4); + for (i = 0; i < num_bytes; i++) + reg_pair[i] = (value >> (8 * i)) & 0xff; +} + +static void hdmi_v14_mode_set(struct hdmi_context *hdata, + struct drm_display_mode *m) +{ + struct hdmi_core_regs *core = &hdata->mode_conf.core; + struct hdmi_tg_regs *tg = &hdata->mode_conf.tg; + + hdata->mode_conf.cea_video_id = drm_match_cea_mode(m); + + hdata->mode_conf.pixel_clock = m->clock * 1000; + hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay); + hdmi_set_reg(core->v_line, 2, m->vtotal); + hdmi_set_reg(core->h_line, 2, m->htotal); + hdmi_set_reg(core->hsync_pol, 1, + (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0); + hdmi_set_reg(core->vsync_pol, 1, + (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0); + hdmi_set_reg(core->int_pro_mode, 1, + (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0); + + /* + * Quirk requirement for exynos 5 HDMI IP design, + * 2 pixels less than the actual calculation for hsync_start + * and end. + */ + + /* Following values & calculations differ for different type of modes */ + if (m->flags & DRM_MODE_FLAG_INTERLACE) { + /* Interlaced Mode */ + hdmi_set_reg(core->v_sync_line_bef_2, 2, + (m->vsync_end - m->vdisplay) / 2); + hdmi_set_reg(core->v_sync_line_bef_1, 2, + (m->vsync_start - m->vdisplay) / 2); + hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2); + hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2); + hdmi_set_reg(core->v_blank_f0, 2, (m->vtotal + + ((m->vsync_end - m->vsync_start) * 4) + 5) / 2); + hdmi_set_reg(core->v_blank_f1, 2, m->vtotal); + hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7); + hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2); + hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, + (m->htotal / 2) + (m->hsync_start - m->hdisplay)); + hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, + (m->htotal / 2) + (m->hsync_start - m->hdisplay)); + hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2); + hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2); + hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/ + hdmi_set_reg(tg->vact_st3, 2, 0x0); + hdmi_set_reg(tg->vact_st4, 2, 0x0); + } else { + /* Progressive Mode */ + hdmi_set_reg(core->v_sync_line_bef_2, 2, + m->vsync_end - m->vdisplay); + hdmi_set_reg(core->v_sync_line_bef_1, 2, + m->vsync_start - m->vdisplay); + hdmi_set_reg(core->v2_blank, 2, m->vtotal); + hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay); + hdmi_set_reg(core->v_blank_f0, 2, 0xffff); + hdmi_set_reg(core->v_blank_f1, 2, 0xffff); + hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff); + hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff); + hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff); + hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff); + hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay); + hdmi_set_reg(tg->vact_sz, 2, m->vdisplay); + hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */ + hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */ + hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */ + } + + /* Following values & calculations are same irrespective of mode type */ + hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2); + hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2); + hdmi_set_reg(core->vact_space_1, 2, 0xffff); + hdmi_set_reg(core->vact_space_2, 2, 0xffff); + hdmi_set_reg(core->vact_space_3, 2, 0xffff); + hdmi_set_reg(core->vact_space_4, 2, 0xffff); + hdmi_set_reg(core->vact_space_5, 2, 0xffff); + hdmi_set_reg(core->vact_space_6, 2, 0xffff); + hdmi_set_reg(core->v_blank_f2, 2, 0xffff); + hdmi_set_reg(core->v_blank_f3, 2, 0xffff); + hdmi_set_reg(core->v_blank_f4, 2, 0xffff); + hdmi_set_reg(core->v_blank_f5, 2, 0xffff); + hdmi_set_reg(core->v_sync_line_aft_3, 2, 0xffff); + hdmi_set_reg(core->v_sync_line_aft_4, 2, 0xffff); + hdmi_set_reg(core->v_sync_line_aft_5, 2, 0xffff); + hdmi_set_reg(core->v_sync_line_aft_6, 2, 0xffff); + hdmi_set_reg(core->v_sync_line_aft_pxl_3, 2, 0xffff); + hdmi_set_reg(core->v_sync_line_aft_pxl_4, 2, 0xffff); + hdmi_set_reg(core->v_sync_line_aft_pxl_5, 2, 0xffff); + hdmi_set_reg(core->v_sync_line_aft_pxl_6, 2, 0xffff); + + /* Timing generator registers */ + hdmi_set_reg(tg->cmd, 1, 0x0); + hdmi_set_reg(tg->h_fsz, 2, m->htotal); + hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay); + hdmi_set_reg(tg->hact_sz, 2, m->hdisplay); + hdmi_set_reg(tg->v_fsz, 2, m->vtotal); + hdmi_set_reg(tg->vsync, 2, 0x1); + hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */ + hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */ + hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */ + hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */ + hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */ + hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */ + hdmi_set_reg(tg->tg_3d, 1, 0x0); + +} + static void hdmi_mode_set(void *ctx, void *mode) { struct hdmi_context *hdata = ctx; @@ -2140,11 +1862,15 @@ static void hdmi_mode_set(void *ctx, void *mode) DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); - conf_idx = hdmi_conf_index(hdata, mode); - if (conf_idx >= 0) - hdata->cur_conf = conf_idx; - else - DRM_DEBUG_KMS("not supported mode\n"); + if (hdata->type == HDMI_TYPE13) { + conf_idx = hdmi_v13_conf_index(mode); + if (conf_idx >= 0) + hdata->cur_conf = conf_idx; + else + DRM_DEBUG_KMS("not supported mode\n"); + } else { + hdmi_v14_mode_set(hdata, mode); + } } static void hdmi_get_max_resol(void *ctx, unsigned int *width, -- cgit v1.1 From 95fc633735331b3404d0ae65a3bb08d02640dbd0 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Wed, 6 Feb 2013 10:59:44 +0530 Subject: drm/exynos: Add device tree based discovery support for G2D This patch adds device tree match table for Exynos G2D controller. Signed-off-by: Ajay Kumar Signed-off-by: Sachin Kamat Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index ddcfb5d..0fcfbe4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -1240,6 +1241,14 @@ static int g2d_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(g2d_pm_ops, g2d_suspend, g2d_resume); +#ifdef CONFIG_OF +static const struct of_device_id exynos_g2d_match[] = { + { .compatible = "samsung,exynos5250-g2d" }, + {}, +}; +MODULE_DEVICE_TABLE(of, exynos_g2d_match); +#endif + struct platform_driver g2d_driver = { .probe = g2d_probe, .remove = g2d_remove, @@ -1247,5 +1256,6 @@ struct platform_driver g2d_driver = { .name = "s5p-g2d", .owner = THIS_MODULE, .pm = &g2d_pm_ops, + .of_match_table = of_match_ptr(exynos_g2d_match), }, }; -- cgit v1.1