diff options
Diffstat (limited to 'drivers/video/omap2/dss/hdmi.c')
-rw-r--r-- | drivers/video/omap2/dss/hdmi.c | 158 |
1 files changed, 114 insertions, 44 deletions
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 8c9b8b3b7f77..769d0828581c 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -60,6 +60,7 @@ static struct { struct mutex lock; struct platform_device *pdev; + struct hdmi_ip_data ip_data; struct clk *sys_clk; @@ -295,6 +296,12 @@ static const struct hdmi_config vesa_timings[] = { false, }, { 0x55, HDMI_DVI }, }, + { + { 1920, 1200, 154000, 32, 48, 80, 6, 3, 26, + OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, + false, }, + { 0x44, HDMI_DVI }, + }, }; static int hdmi_runtime_get(void) @@ -333,13 +340,17 @@ static int __init hdmi_init_display(struct omap_dss_device *dssdev) DSSDBG("init_display\n"); - dss_init_hdmi_ip_ops(&hdmi.ip_data); + dss_init_hdmi_ip_ops(&hdmi.ip_data, omapdss_get_version()); if (hdmi.vdda_hdmi_dac_reg == NULL) { struct regulator *reg; reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac"); + /* DT HACK: try VDAC to make omapdss work for o4 sdp/panda */ + if (IS_ERR(reg)) + reg = devm_regulator_get(&hdmi.pdev->dev, "VDAC"); + if (IS_ERR(reg)) { DSSERR("can't get VDDA_HDMI_DAC regulator\n"); return PTR_ERR(reg); @@ -355,7 +366,7 @@ static int __init hdmi_init_display(struct omap_dss_device *dssdev) return 0; } -static void __exit hdmi_uninit_display(struct omap_dss_device *dssdev) +static void hdmi_uninit_display(struct omap_dss_device *dssdev) { DSSDBG("uninit_display\n"); @@ -398,7 +409,8 @@ static bool hdmi_timings_compare(struct omap_video_timings *timing1, { int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync; - if ((timing2->pixel_clock == timing1->pixel_clock) && + if ((DIV_ROUND_CLOSEST(timing2->pixel_clock, 1000) == + DIV_ROUND_CLOSEST(timing1->pixel_clock, 1000)) && (timing2->x_res == timing1->x_res) && (timing2->y_res == timing1->y_res)) { @@ -500,12 +512,9 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd); } -static int hdmi_power_on(struct omap_dss_device *dssdev) +static int hdmi_power_on_core(struct omap_dss_device *dssdev) { int r; - struct omap_video_timings *p; - struct omap_overlay_manager *mgr = dssdev->output->manager; - unsigned long phy; gpio_set_value(hdmi.ct_cp_hpd_gpio, 1); gpio_set_value(hdmi.ls_oe_gpio, 1); @@ -521,6 +530,38 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) if (r) goto err_runtime_get; + /* Make selection of HDMI in DSS */ + dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); + + return 0; + +err_runtime_get: + regulator_disable(hdmi.vdda_hdmi_dac_reg); +err_vdac_enable: + gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); + gpio_set_value(hdmi.ls_oe_gpio, 0); + return r; +} + +static void hdmi_power_off_core(struct omap_dss_device *dssdev) +{ + hdmi_runtime_put(); + regulator_disable(hdmi.vdda_hdmi_dac_reg); + gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); + gpio_set_value(hdmi.ls_oe_gpio, 0); +} + +static int hdmi_power_on_full(struct omap_dss_device *dssdev) +{ + int r; + struct omap_video_timings *p; + struct omap_overlay_manager *mgr = dssdev->output->manager; + unsigned long phy; + + r = hdmi_power_on_core(dssdev); + if (r) + return r; + dss_mgr_disable(mgr); p = &hdmi.ip_data.cfg.timings; @@ -548,17 +589,6 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) hdmi.ip_data.ops->video_configure(&hdmi.ip_data); - /* Make selection of HDMI in DSS */ - dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); - - /* Select the dispc clock source as PRCM clock, to ensure that it is not - * DSI PLL source as the clock selected by DSI PLL might not be - * sufficient for the resolution selected / that can be changed - * dynamically by user. This can be moved to single location , say - * Boardfile. - */ - dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); - /* bypass TV gamma table */ dispc_enable_gamma_table(0); @@ -582,16 +612,11 @@ err_vid_enable: err_phy_enable: hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); err_pll_enable: - hdmi_runtime_put(); -err_runtime_get: - regulator_disable(hdmi.vdda_hdmi_dac_reg); -err_vdac_enable: - gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); - gpio_set_value(hdmi.ls_oe_gpio, 0); + hdmi_power_off_core(dssdev); return -EIO; } -static void hdmi_power_off(struct omap_dss_device *dssdev) +static void hdmi_power_off_full(struct omap_dss_device *dssdev) { struct omap_overlay_manager *mgr = dssdev->output->manager; @@ -600,12 +625,8 @@ static void hdmi_power_off(struct omap_dss_device *dssdev) hdmi.ip_data.ops->video_disable(&hdmi.ip_data); hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); - hdmi_runtime_put(); - - regulator_disable(hdmi.vdda_hdmi_dac_reg); - gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); - gpio_set_value(hdmi.ls_oe_gpio, 0); + hdmi_power_off_core(dssdev); } int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, @@ -715,7 +736,7 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) goto err0; } - r = hdmi_power_on(dssdev); + r = hdmi_power_on_full(dssdev); if (r) { DSSERR("failed to power on device\n"); goto err1; @@ -737,13 +758,48 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) mutex_lock(&hdmi.lock); - hdmi_power_off(dssdev); + hdmi_power_off_full(dssdev); omap_dss_stop_device(dssdev); mutex_unlock(&hdmi.lock); } +int omapdss_hdmi_core_enable(struct omap_dss_device *dssdev) +{ + int r = 0; + + DSSDBG("ENTER omapdss_hdmi_core_enable\n"); + + mutex_lock(&hdmi.lock); + + hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio; + + r = hdmi_power_on_core(dssdev); + if (r) { + DSSERR("failed to power on device\n"); + goto err0; + } + + mutex_unlock(&hdmi.lock); + return 0; + +err0: + mutex_unlock(&hdmi.lock); + return r; +} + +void omapdss_hdmi_core_disable(struct omap_dss_device *dssdev) +{ + DSSDBG("Enter omapdss_hdmi_core_disable\n"); + + mutex_lock(&hdmi.lock); + + hdmi_power_off_core(dssdev); + + mutex_unlock(&hdmi.lock); +} + static int hdmi_get_clocks(struct platform_device *pdev) { struct clk *clk; @@ -912,7 +968,7 @@ int hdmi_audio_config(struct omap_dss_audio *audio) static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - const char *def_disp_name = dss_get_default_display_name(); + const char *def_disp_name = omapdss_get_default_display_name(); struct omap_dss_device *def_dssdev; int i; @@ -970,9 +1026,19 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev) return; } + r = omapdss_output_set_device(&hdmi.output, dssdev); + if (r) { + DSSERR("failed to connect output to new device: %s\n", + dssdev->name); + dss_put_device(dssdev); + return; + } + r = dss_add_device(dssdev); if (r) { DSSERR("device %s register failed: %d\n", dssdev->name, r); + omapdss_output_unset_device(&hdmi.output); + hdmi_uninit_display(dssdev); dss_put_device(dssdev); return; } @@ -999,22 +1065,22 @@ static void __exit hdmi_uninit_output(struct platform_device *pdev) /* HDMI HW IP initialisation */ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) { - struct resource *hdmi_mem; + struct resource *res; int r; hdmi.pdev = pdev; mutex_init(&hdmi.lock); + mutex_init(&hdmi.ip_data.lock); - hdmi_mem = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0); - if (!hdmi_mem) { + res = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0); + if (!res) { DSSERR("can't get IORESOURCE_MEM HDMI\n"); return -EINVAL; } /* Base address taken from platform */ - hdmi.ip_data.base_wp = ioremap(hdmi_mem->start, - resource_size(hdmi_mem)); + hdmi.ip_data.base_wp = devm_request_and_ioremap(&pdev->dev, res); if (!hdmi.ip_data.base_wp) { DSSERR("can't ioremap WP\n"); return -ENOMEM; @@ -1022,7 +1088,7 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) r = hdmi_get_clocks(pdev); if (r) { - iounmap(hdmi.ip_data.base_wp); + DSSERR("can't get clocks\n"); return r; } @@ -1033,9 +1099,11 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) hdmi.ip_data.pll_offset = HDMI_PLLCTRL; hdmi.ip_data.phy_offset = HDMI_PHY; - mutex_init(&hdmi.ip_data.lock); - - hdmi_panel_init(); + r = hdmi_panel_init(); + if (r) { + DSSERR("can't init panel\n"); + goto err_panel_init; + } dss_debugfs_create_file("hdmi", hdmi_dump_regs); @@ -1044,6 +1112,10 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) hdmi_probe_pdata(pdev); return 0; + +err_panel_init: + hdmi_put_clocks(); + return r; } static int __exit hdmi_remove_child(struct device *dev, void *data) @@ -1067,8 +1139,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) hdmi_put_clocks(); - iounmap(hdmi.ip_data.base_wp); - return 0; } |