From 22c151bc4ca58375a68548cebe1a20bbaee58366 Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Tue, 15 Jan 2013 08:11:07 -0500 Subject: [PATCH 1/8] 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 0bbfc056650db9..54f0f90b1e002b 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; From c35da51bbbab531771da9b1957a915a0b9534f41 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Thu, 18 Apr 2013 14:04:17 +0900 Subject: [PATCH 2/8] drm/exynos: do not use generic flags to dumb This patch removes the use of dumb flags from driver. As Dave pointed out, the dumb flags are not driver specific so this should be removed from driver. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_gem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 4731807765287a..c58249e04d9a13 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -652,7 +652,8 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv, args->pitch = args->width * ((args->bpp + 7) / 8); args->size = args->pitch * args->height; - exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size); + exynos_gem_obj = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG | + EXYNOS_BO_WC, args->size); if (IS_ERR(exynos_gem_obj)) return PTR_ERR(exynos_gem_obj); From f9ef4b86042e8ae0d38c896d17d9c3ec67b0267b Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Fri, 26 Apr 2013 16:06:43 -0400 Subject: [PATCH 3/8] drm/exynos: Debounce HDMI hotplug interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch debounces hotplug interrupts generated by the HDMI hotplug gpio. The reason this is needed is that we get multiple (5) interrupts every time a monitor is inserted which causes us to needlessly enable and disable the IP block. BUG=chromium:220033 TEST=Many hotplugs without any 20s freeze Change-Id: I2d9a57e0a9206b2739de5234ba024b964afd038c Signed-off-by: Sean Paul Reviewed-on: https://gerrit.chromium.org/gerrit/56289 Reviewed-by: Stéphane Marchesin [rebased for 3.8 by Daniel Drake, eos-shell #1610] --- drivers/gpu/drm/exynos/exynos_hdmi.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index bafe3b153510d1..0f00d5c915254b 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -45,6 +45,7 @@ #include #include +#define HOTPLUG_DEBOUNCE_MS 1100 #define MAX_WIDTH 1920 #define MAX_HEIGHT 1080 #define get_hdmi_context(dev) platform_get_drvdata(to_platform_device(dev)) @@ -165,6 +166,7 @@ struct hdmi_context { void __iomem *regs; void *parent_ctx; int irq; + struct delayed_work hotplug_work; struct i2c_client *ddc_port; struct i2c_client *hdmiphy_port; @@ -1943,6 +1945,8 @@ static void hdmi_poweroff(struct hdmi_context *hdata) hdmiphy_conf_reset(hdata); hdmiphy_poweroff(hdata); + cancel_delayed_work(&hdata->hotplug_work); + clk_disable(res->sclk_hdmi); clk_disable(res->hdmi); clk_disable(res->hdmiphy); @@ -1993,10 +1997,12 @@ static struct exynos_hdmi_ops hdmi_ops = { .dpms = hdmi_dpms, }; -static irqreturn_t hdmi_irq_thread(int irq, void *arg) +static void hdmi_hotplug_work_func(struct work_struct *work) { - struct exynos_drm_hdmi_context *ctx = arg; - struct hdmi_context *hdata = ctx->ctx; + struct hdmi_context *hdata = container_of(work, struct hdmi_context, + hotplug_work.work); + struct exynos_drm_hdmi_context *ctx = + (struct exynos_drm_hdmi_context *) hdata->parent_ctx; mutex_lock(&hdata->hdmi_mutex); hdata->hpd = gpio_get_value(hdata->hpd_gpio); @@ -2004,6 +2010,15 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg) if (ctx->drm_dev) drm_helper_hpd_irq_event(ctx->drm_dev); +} + +static irqreturn_t hdmi_irq_thread(int irq, void *arg) +{ + struct exynos_drm_hdmi_context *ctx = arg; + struct hdmi_context *hdata = ctx->ctx; + + mod_delayed_work(system_wq, &hdata->hotplug_work, + msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); return IRQ_HANDLED; } @@ -2198,6 +2213,7 @@ static int hdmi_probe(struct platform_device *pdev) } mutex_init(&hdata->hdmi_mutex); + INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func); drm_hdmi_ctx->ctx = (void *)hdata; hdata->parent_ctx = (void *)drm_hdmi_ctx; @@ -2310,6 +2326,7 @@ static int hdmi_remove(struct platform_device *pdev) pm_runtime_disable(dev); free_irq(hdata->irq, hdata); + cancel_delayed_work_sync(&hdata->hotplug_work); /* hdmiphy i2c driver */ From d99483ad51f9126db7423ef01fd999f3f56d1230 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Tue, 21 May 2013 16:55:58 +0900 Subject: [PATCH 4/8] drm/exynos: wait for the completion of pending page flip This patch fixes the issue that drm_vblank_get() is failed. The issus occurs when next page flip request is tried if previous page flip event wasn't completed yet and then dpms became off. So this patch make sure that page flip event is completed before dpms goes to off. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park Conflicts: drivers/gpu/drm/exynos/exynos_drm_crtc.c --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index e8894bc9e6d5ed..1847f1d9b3fb46 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -48,6 +48,8 @@ struct exynos_drm_crtc { unsigned int pipe; unsigned int dpms; enum exynos_crtc_mode mode; + wait_queue_head_t pending_flip_queue; + atomic_t pending_flip; }; static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) @@ -61,6 +63,13 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) return; } + if (mode > DRM_MODE_DPMS_ON) { + /* wait for the completion of page flip. */ + wait_event(exynos_crtc->pending_flip_queue, + atomic_read(&exynos_crtc->pending_flip) == 0); + drm_vblank_off(crtc->dev, exynos_crtc->pipe); + } + exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_crtc_dpms); exynos_crtc->dpms = mode; } @@ -225,6 +234,7 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, spin_lock_irq(&dev->event_lock); list_add_tail(&event->base.link, &dev_priv->pageflip_event_list); + atomic_set(&exynos_crtc->pending_flip, 1); spin_unlock_irq(&dev->event_lock); crtc->fb = fb; @@ -344,6 +354,8 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr) exynos_crtc->pipe = nr; exynos_crtc->dpms = DRM_MODE_DPMS_OFF; + init_waitqueue_head(&exynos_crtc->pending_flip_queue); + atomic_set(&exynos_crtc->pending_flip, 0); exynos_crtc->plane = exynos_plane_init(dev, 1 << nr, true); if (!exynos_crtc->plane) { kfree(exynos_crtc); @@ -399,6 +411,8 @@ void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc) struct exynos_drm_private *dev_priv = dev->dev_private; struct drm_pending_vblank_event *e, *t; struct timeval now; + struct drm_crtc *drm_crtc = dev_priv->crtc[crtc]; + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc); unsigned long flags; DRM_DEBUG_KMS("%s\n", __FILE__); @@ -419,6 +433,8 @@ void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc) list_move_tail(&e->base.link, &e->base.file_priv->event_list); wake_up_interruptible(&e->base.file_priv->event_wait); drm_vblank_put(dev, crtc); + atomic_set(&exynos_crtc->pending_flip, 0); + wake_up(&exynos_crtc->pending_flip_queue); } spin_unlock_irqrestore(&dev->event_lock, flags); From 6c8c56636abdf923d9cff0cb085643bd5bf5cfa2 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Fri, 21 Feb 2014 14:23:44 -0600 Subject: [PATCH 5/8] drm/exynos: power up HDMI before mixer Testing on Exynos4412, when changing screen resolution under GNOME/X11, first DPMS is set to OFF via drm_mode_obj_set_property_ioctl. This is done via drm_hdmi_dpms which powers down the mixer then the HDMI component. Then the mode change happens. We then see this call chain, powering things back on: exynos_drm_crtc_commit exynos_drm_crtc_dpms exynos_drm_encoder_crtc_dpms drm_hdmi_dpms And at this point, drm_hdmi_dpms first powers on the mixer, then the HDMI component. Strangely enough, this works fine on the first resolution change, but on the second it hangs in mixer_poweron() in: mixer_reg_write(res, MXR_INT_EN, ctx->int_en); Through some experiments I determined that this register write will hang the machine here unless the hdmi_resources.hdmi clock is running. I can't explain why there is a difference between the first and second time; I did check that the underlying clock gating register has the same value in both cases. Anyway, the mixer clearly has some kind of dependency on the HDMI component, so lets make sure we power that up first. Signed-off-by: Daniel Drake --- drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c index 28644539b30566..6f6166ef96558f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c @@ -239,10 +239,17 @@ static void drm_hdmi_dpms(struct device *subdrv_dev, int mode) DRM_DEBUG_KMS("%s\n", __FILE__); + /* When powering up, we must first power up the HDMI component, as + * otherwise mixer register accesses will sometimes hang. + * When powering down, we do the opposite: mixer off, HDMI off. */ + + if (mode == DRM_MODE_DPMS_ON && hdmi_ops && hdmi_ops->dpms) + hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode); + if (mixer_ops && mixer_ops->dpms) mixer_ops->dpms(ctx->mixer_ctx->ctx, mode); - if (hdmi_ops && hdmi_ops->dpms) + if (mode != DRM_MODE_DPMS_ON && hdmi_ops && hdmi_ops->dpms) hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode); } From 0476a8ac498d9190e8ff60d12f737974ef254983 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Fri, 21 Feb 2014 15:33:52 -0600 Subject: [PATCH 6/8] media/mfc: use shipped firmware paths linux-firmware ships these files in /lib/firmware/s5p-mfc. Use these paths. --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 0da338ced8d1ee..6a1cef5df48cd6 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1293,7 +1293,7 @@ static struct s5p_mfc_variant mfc_drvdata_v5 = { .buf_size = &buf_size_v5, .buf_align = &mfc_buf_align_v5, .mclk_name = "sclk_mfc", - .fw_name = "s5p-mfc.fw", + .fw_name = "s5p-mfc/s5p-mfc.fw", }; struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = { @@ -1320,7 +1320,7 @@ static struct s5p_mfc_variant mfc_drvdata_v6 = { .buf_size = &buf_size_v6, .buf_align = &mfc_buf_align_v6, .mclk_name = "aclk_333", - .fw_name = "s5p-mfc-v6.fw", + .fw_name = "s5p-mfc/s5p-mfc-v6.fw", }; static struct platform_device_id mfc_driver_ids[] = { From f0e64777610641084343874b0a8a1d7f06cc828e Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Fri, 21 Feb 2014 16:49:05 -0600 Subject: [PATCH 7/8] Revert "HDMI_DDC I2C2 bus uses GPIO based bitbanging" This reverts commit 98b6c57b1d1a92223044762577eac4a682f48f27. The hardware offers us I2C capabilities directly. Why drive it as a GPIO and use CPU bit-banging to convert it back to I2C? http://forum.odroid.com/viewtopic.php?f=8&t=3850 --- arch/arm/mach-exynos/Kconfig | 2 ++ arch/arm/mach-exynos/mach-hkdk4412.c | 21 ++------------------- drivers/cpufreq/exynos4x12-cpufreq.c | 1 - 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 286bc9d2885c51..c065b8b3b6d643 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -436,6 +436,8 @@ config MACH_HKDK4412 select EXYNOS_DEV_DMA select EXYNOS_DEV_DRM select EXYNOS_DEV_SYSMMU + select EXYNOS4_SETUP_I2C2 + select S3C_DEV_I2C2 select S3C_DEV_HSMMC select S3C_DEV_HSMMC1 select S3C_DEV_USB_HSOTG diff --git a/arch/arm/mach-exynos/mach-hkdk4412.c b/arch/arm/mach-exynos/mach-hkdk4412.c index 9e9dfa8f82ddc6..d364e68668f7a0 100644 --- a/arch/arm/mach-exynos/mach-hkdk4412.c +++ b/arch/arm/mach-exynos/mach-hkdk4412.c @@ -158,24 +158,6 @@ static struct i2c_board_info hkdk4412_i2c_devs1[] __initdata = { #endif }; -/* I2C2 bus GPIO-Bitbanging */ -#define GPIO_I2C2_SDA EXYNOS4_GPA0(6) -#define GPIO_I2C2_SCL EXYNOS4_GPA0(7) -static struct i2c_gpio_platform_data i2c2_gpio_platdata = { - .sda_pin = GPIO_I2C2_SDA, - .scl_pin = GPIO_I2C2_SCL, - .udelay = 5, - .sda_is_open_drain = 0, - .scl_is_open_drain = 0, - .scl_is_output_only = 0 -}; - -static struct platform_device gpio_device_i2c2 = { - .name = "i2c-gpio", - .id = 2, // adepter number - .dev.platform_data = &i2c2_gpio_platdata, -}; - /* Odroid-O2 schematics show the DDC of the remote HDMI device connected to * I2C2. HDMI specs state that DDC always sits at bus address 0x50. */ static struct i2c_board_info hkdk4412_i2c_devs2[] __initdata = { @@ -485,7 +467,7 @@ static struct platform_device *hkdk4412_devices[] __initdata = { &s3c_device_hsmmc2, &s3c_device_i2c0, &s3c_device_i2c1, - &gpio_device_i2c2, + &s3c_device_i2c2, &s3c_device_i2c3, #if defined(CONFIG_ODROID_U2) &gpio_device_i2c4, @@ -622,6 +604,7 @@ static void __init hkdk4412_machine_init(void) i2c_register_board_info(1, hkdk4412_i2c_devs1, ARRAY_SIZE(hkdk4412_i2c_devs1)); + s3c_i2c2_set_platdata(NULL); i2c_register_board_info(2, hkdk4412_i2c_devs2, ARRAY_SIZE(hkdk4412_i2c_devs2)); diff --git a/drivers/cpufreq/exynos4x12-cpufreq.c b/drivers/cpufreq/exynos4x12-cpufreq.c index 85f701adf93195..6af3c3d6fedb5b 100644 --- a/drivers/cpufreq/exynos4x12-cpufreq.c +++ b/drivers/cpufreq/exynos4x12-cpufreq.c @@ -414,7 +414,6 @@ static const unsigned int asv_voltage_4x12[CPUFREQ_LEVEL_END] = { 925000, 925000, 925000, -}; #endif static void exynos4x12_set_clkdiv(unsigned int div_index) { From 94df6b2279c067d96d80a9714481e52ef2f1ae5d Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Fri, 13 Dec 2013 11:24:06 -0600 Subject: [PATCH 8/8] exynos-drm: hack in timing fixes for 1024x768 As discussed at http://article.gmane.org/gmane.linux.kernel.samsung-soc/25135 the 1024x768 timings don't quite work out of the box, for unknown reasons. However, massaging of the values in the way implemented in this patch makes the system usable, although it is missing the top row of pixels, and the rightmost column too. (to be fixed later, hopefully) Fix up 1280x1024 in the same way. [endlessm/eos-shell#1592] --- drivers/gpu/drm/exynos/exynos_hdmi.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 0f00d5c915254b..2e7ac427c52408 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1757,6 +1757,14 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata, { struct hdmi_core_regs *core = &hdata->mode_conf.core; struct hdmi_tg_regs *tg = &hdata->mode_conf.tg; + int hcorrect = 0; + int vcorrect = 0; + + if ((m->vdisplay == 768 && m->hdisplay == 1024) || (m->vdisplay == 1024 && m->hdisplay == 1280)) { + pr_info("exynos-drm: Applying 257px timings hack\n"); + hcorrect = 257; + vcorrect = 1; + } hdata->mode_conf.cea_video_id = drm_match_cea_mode(m); @@ -1814,8 +1822,8 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata, 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_st, 2, (m->vtotal - m->vdisplay) - vcorrect); + hdmi_set_reg(tg->vact_sz, 2, m->vdisplay + vcorrect); 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 */ @@ -1846,8 +1854,8 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata, /* 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->hact_st, 2, (m->htotal - m->hdisplay) - hcorrect); + hdmi_set_reg(tg->hact_sz, 2, m->hdisplay + hcorrect); 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 */