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) { 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); 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); 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); } diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index bafe3b153510d1..2e7ac427c52408 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; @@ -1755,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); @@ -1812,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 */ @@ -1844,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 */ @@ -1943,6 +1953,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 +2005,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 +2018,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 +2221,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 +2334,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 */ 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; 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[] = {