diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index a2ea684169e99aedc8cc2080a363813cc91543d0..b1a9ce1188fb86ce6ad14e39b2f0ba9795286a57 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -510,6 +510,9 @@ static int __init omap_dss_bus_register(void) /* INIT */ static int (*dss_output_drv_reg_funcs[])(void) __initdata = { +#ifdef CONFIG_OMAP2_DSS_DSI + dsi_init_platform_driver, +#endif #ifdef CONFIG_OMAP2_DSS_DPI dpi_init_platform_driver, #endif @@ -522,15 +525,15 @@ static int (*dss_output_drv_reg_funcs[])(void) __initdata = { #ifdef CONFIG_OMAP2_DSS_VENC venc_init_platform_driver, #endif -#ifdef CONFIG_OMAP2_DSS_DSI - dsi_init_platform_driver, -#endif #ifdef CONFIG_OMAP4_DSS_HDMI hdmi_init_platform_driver, #endif }; static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = { +#ifdef CONFIG_OMAP2_DSS_DSI + dsi_uninit_platform_driver, +#endif #ifdef CONFIG_OMAP2_DSS_DPI dpi_uninit_platform_driver, #endif @@ -543,9 +546,6 @@ static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = { #ifdef CONFIG_OMAP2_DSS_VENC venc_uninit_platform_driver, #endif -#ifdef CONFIG_OMAP2_DSS_DSI - dsi_uninit_platform_driver, -#endif #ifdef CONFIG_OMAP4_DSS_HDMI hdmi_uninit_platform_driver, #endif diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 11d64b09cffec3fab33aa203544eb86dcab50eac..1e103b3135b97856dcd771f5b6a6a89a5becbe8c 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -49,34 +49,37 @@ static struct { struct omap_dss_output output; } dpi; -static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk) +static struct platform_device *dpi_get_dsidev(enum omap_channel channel) { - int dsi_module; - - dsi_module = clk == OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ? 0 : 1; - - return dsi_get_dsidev_from_id(dsi_module); + switch (channel) { + case OMAP_DSS_CHANNEL_LCD: + return dsi_get_dsidev_from_id(0); + case OMAP_DSS_CHANNEL_LCD2: + return dsi_get_dsidev_from_id(1); + default: + return NULL; + } } -static bool dpi_use_dsi_pll(struct omap_dss_device *dssdev) +static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel) { - if (dssdev->clocks.dispc.dispc_fclk_src == - OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC || - dssdev->clocks.dispc.dispc_fclk_src == - OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC || - dssdev->clocks.dispc.channel.lcd_clk_src == - OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC || - dssdev->clocks.dispc.channel.lcd_clk_src == - OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC) - return true; - else - return false; + switch (channel) { + case OMAP_DSS_CHANNEL_LCD: + return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC; + case OMAP_DSS_CHANNEL_LCD2: + return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC; + default: + /* this shouldn't happen */ + WARN_ON(1); + return OMAP_DSS_CLK_SRC_FCK; + } } static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, unsigned long pck_req, unsigned long *fck, int *lck_div, int *pck_div) { + struct omap_overlay_manager *mgr = dssdev->output->manager; struct dsi_clock_info dsi_cinfo; struct dispc_clock_info dispc_cinfo; int r; @@ -90,7 +93,8 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, if (r) return r; - dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); + dss_select_lcd_clk_source(mgr->id, + dpi_get_alt_clk_src(mgr->id)); dpi.mgr_config.clock_info = dispc_cinfo; @@ -135,7 +139,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) unsigned long pck; int r = 0; - if (dpi_use_dsi_pll(dssdev)) + if (dpi.dsidev) r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck, &lck_div, &pck_div); else @@ -214,7 +218,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) if (r) goto err_src_sel; - if (dpi_use_dsi_pll(dssdev)) { + if (dpi.dsidev) { r = dsi_runtime_get(dpi.dsidev); if (r) goto err_get_dsi; @@ -242,10 +246,10 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) err_mgr_enable: err_set_mode: - if (dpi_use_dsi_pll(dssdev)) + if (dpi.dsidev) dsi_pll_uninit(dpi.dsidev, true); err_dsi_pll_init: - if (dpi_use_dsi_pll(dssdev)) + if (dpi.dsidev) dsi_runtime_put(dpi.dsidev); err_get_dsi: err_src_sel: @@ -271,8 +275,8 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) dss_mgr_disable(mgr); - if (dpi_use_dsi_pll(dssdev)) { - dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); + if (dpi.dsidev) { + dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); dsi_pll_uninit(dpi.dsidev, true); dsi_runtime_put(dpi.dsidev); } @@ -317,7 +321,7 @@ int dpi_check_timings(struct omap_dss_device *dssdev, if (timings->pixel_clock == 0) return -EINVAL; - if (dpi_use_dsi_pll(dssdev)) { + if (dpi.dsidev) { struct dsi_clock_info dsi_cinfo; r = dsi_pll_calc_clock_div_pck(dpi.dsidev, timings->pixel_clock * 1000, @@ -359,8 +363,32 @@ void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) } EXPORT_SYMBOL(omapdss_dpi_set_data_lines); +static int __init dpi_verify_dsi_pll(struct platform_device *dsidev) +{ + int r; + + /* do initial setup with the PLL to see if it is operational */ + + r = dsi_runtime_get(dsidev); + if (r) + return r; + + r = dsi_pll_init(dsidev, 0, 1); + if (r) { + dsi_runtime_put(dsidev); + return r; + } + + dsi_pll_uninit(dsidev, true); + dsi_runtime_put(dsidev); + + return 0; +} + static int __init dpi_init_display(struct omap_dss_device *dssdev) { + struct platform_device *dsidev; + DSSDBG("init_display\n"); if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && @@ -377,12 +405,23 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev) dpi.vdds_dsi_reg = vdds_dsi; } - if (dpi_use_dsi_pll(dssdev)) { - enum omap_dss_clk_source dispc_fclk_src = - dssdev->clocks.dispc.dispc_fclk_src; - dpi.dsidev = dpi_get_dsidev(dispc_fclk_src); + /* + * XXX We shouldn't need dssdev->channel for this. The dsi pll clock + * source for DPI is SoC integration detail, not something that should + * be configured in the dssdev + */ + dsidev = dpi_get_dsidev(dssdev->channel); + + if (dpi_verify_dsi_pll(dsidev)) { + dsidev = NULL; + DSSWARN("DSI PLL not operational\n"); } + if (dsidev) + DSSDBG("using DSI PLL for DPI clock\n"); + + dpi.dsidev = dsidev; + return 0; } diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 2ba505b33153fe33a6a4825b67c136df63d5bc46..d9797da39e69dae6313cdb81454c1274eff46ef7 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -1386,6 +1386,11 @@ int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, cur.dsi_pll_hsdiv_dispc_clk = cur.clkin4ddr / cur.regm_dispc; + if (cur.regm_dispc > 1 && + cur.regm_dispc % 2 != 0 && + req_pck >= 1000000) + continue; + /* this will narrow down the search a bit, * but still give pixclocks below what was * requested */ @@ -1736,6 +1741,12 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, DSSDBG("PLL init\n"); + /* + * It seems that on many OMAPs we need to enable both to have a + * functional HSDivider. + */ + enable_hsclk = enable_hsdiv = true; + if (dsi->vdds_dsi_reg == NULL) { struct regulator *vdds_dsi; @@ -4709,7 +4720,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) if (r) goto err1; - dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src); dss_select_lcd_clk_source(mgr->id, dssdev->clocks.dispc.channel.lcd_clk_src); @@ -4744,7 +4754,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) err3: dsi_cio_uninit(dsidev); err2: - dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); @@ -4771,7 +4780,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, dsi_vc_enable(dsidev, 2, 0); dsi_vc_enable(dsidev, 3, 0); - dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); dsi_cio_uninit(dsidev); diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 456118beb1f8bb942eed5a33eda5eed657568a2a..df3d89a8c8a993667ea78a8bd9cf239fdae0e63b 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -304,7 +304,7 @@ static void dss_dump_regs(struct seq_file *s) #undef DUMPREG } -void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) +static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) { struct platform_device *dsidev; int b; @@ -375,8 +375,10 @@ void dss_select_lcd_clk_source(enum omap_channel channel, struct platform_device *dsidev; int b, ix, pos; - if (!dss_has_feature(FEAT_LCD_CLK_SRC)) + if (!dss_has_feature(FEAT_LCD_CLK_SRC)) { + dss_select_dispc_clk_source(clk_src); return; + } switch (clk_src) { case OMAP_DSS_CLK_SRC_FCK: @@ -432,6 +434,29 @@ enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) } } +/* calculate clock rates using dividers in cinfo */ +int dss_calc_clock_rates(struct dss_clock_info *cinfo) +{ + if (dss.dpll4_m4_ck) { + unsigned long prate; + + if (cinfo->fck_div > dss.feat->fck_div_max || + cinfo->fck_div == 0) + return -EINVAL; + + prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); + + cinfo->fck = prate / cinfo->fck_div * + dss.feat->dss_fck_multiplier; + } else { + if (cinfo->fck_div != 0) + return -EINVAL; + cinfo->fck = clk_get_rate(dss.dss_clk); + } + + return 0; +} + int dss_set_clock_div(struct dss_clock_info *cinfo) { if (dss.dpll4_m4_ck) { @@ -462,6 +487,36 @@ unsigned long dss_get_dpll4_rate(void) return 0; } +static int dss_setup_default_clock(void) +{ + unsigned long max_dss_fck, prate; + unsigned fck_div; + struct dss_clock_info dss_cinfo = { 0 }; + int r; + + if (dss.dpll4_m4_ck == NULL) + return 0; + + max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); + + prate = dss_get_dpll4_rate(); + + fck_div = DIV_ROUND_UP(prate * dss.feat->dss_fck_multiplier, + max_dss_fck); + + dss_cinfo.fck_div = fck_div; + + r = dss_calc_clock_rates(&dss_cinfo); + if (r) + return r; + + r = dss_set_clock_div(&dss_cinfo); + if (r) + return r; + + return 0; +} + int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, struct dispc_clock_info *dispc_cinfo) { @@ -869,6 +924,10 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) if (r) return r; + r = dss_setup_default_clock(); + if (r) + goto err_setup_clocks; + pm_runtime_enable(&pdev->dev); r = dss_runtime_get(); @@ -878,6 +937,8 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) /* Select DPLL */ REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); + dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); + #ifdef CONFIG_OMAP2_DSS_VENC REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ @@ -901,6 +962,7 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) err_runtime_get: pm_runtime_disable(&pdev->dev); +err_setup_clocks: dss_put_clocks(); return r; } diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index ff7a55b54b8e6e3d03b61a58e3e70c11ab0452cd..84a7f6a2bfc4221ee6d10e45a476b10ace201eb9 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -283,7 +283,6 @@ void dss_sdi_init(int datapairs); int dss_sdi_enable(void); void dss_sdi_disable(void); -void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src); void dss_select_dsi_clk_source(int dsi_module, enum omap_dss_clk_source clk_src); void dss_select_lcd_clk_source(enum omap_channel channel, @@ -296,6 +295,7 @@ void dss_set_venc_output(enum omap_dss_venc_type type); void dss_set_dac_pwrdn_bgz(bool enable); unsigned long dss_get_dpll4_rate(void); +int dss_calc_clock_rates(struct dss_clock_info *cinfo); int dss_set_clock_div(struct dss_clock_info *cinfo); int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, struct dispc_clock_info *dispc_cinfo); diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 2aada9db0a04493c460e17b6b5e07eeb2c6e4925..a43ac3f2a48c1205338b2ee92d57c6ba39c1cfd7 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -528,14 +528,6 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev) /* 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); - return 0; err_runtime_get: