Commit a4ae0ba8 authored by Tomi Valkeinen's avatar Tomi Valkeinen

Merge branch '3.8/dsi-pll-work'

Merge omapdss patches to enable using DSI PLL for DPI output.
parents 9296dbd7 0e8276ef
...@@ -510,6 +510,9 @@ static int __init omap_dss_bus_register(void) ...@@ -510,6 +510,9 @@ static int __init omap_dss_bus_register(void)
/* INIT */ /* INIT */
static int (*dss_output_drv_reg_funcs[])(void) __initdata = { static int (*dss_output_drv_reg_funcs[])(void) __initdata = {
#ifdef CONFIG_OMAP2_DSS_DSI
dsi_init_platform_driver,
#endif
#ifdef CONFIG_OMAP2_DSS_DPI #ifdef CONFIG_OMAP2_DSS_DPI
dpi_init_platform_driver, dpi_init_platform_driver,
#endif #endif
...@@ -522,15 +525,15 @@ static int (*dss_output_drv_reg_funcs[])(void) __initdata = { ...@@ -522,15 +525,15 @@ static int (*dss_output_drv_reg_funcs[])(void) __initdata = {
#ifdef CONFIG_OMAP2_DSS_VENC #ifdef CONFIG_OMAP2_DSS_VENC
venc_init_platform_driver, venc_init_platform_driver,
#endif #endif
#ifdef CONFIG_OMAP2_DSS_DSI
dsi_init_platform_driver,
#endif
#ifdef CONFIG_OMAP4_DSS_HDMI #ifdef CONFIG_OMAP4_DSS_HDMI
hdmi_init_platform_driver, hdmi_init_platform_driver,
#endif #endif
}; };
static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = { static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = {
#ifdef CONFIG_OMAP2_DSS_DSI
dsi_uninit_platform_driver,
#endif
#ifdef CONFIG_OMAP2_DSS_DPI #ifdef CONFIG_OMAP2_DSS_DPI
dpi_uninit_platform_driver, dpi_uninit_platform_driver,
#endif #endif
...@@ -543,9 +546,6 @@ static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = { ...@@ -543,9 +546,6 @@ static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = {
#ifdef CONFIG_OMAP2_DSS_VENC #ifdef CONFIG_OMAP2_DSS_VENC
venc_uninit_platform_driver, venc_uninit_platform_driver,
#endif #endif
#ifdef CONFIG_OMAP2_DSS_DSI
dsi_uninit_platform_driver,
#endif
#ifdef CONFIG_OMAP4_DSS_HDMI #ifdef CONFIG_OMAP4_DSS_HDMI
hdmi_uninit_platform_driver, hdmi_uninit_platform_driver,
#endif #endif
......
...@@ -49,34 +49,37 @@ static struct { ...@@ -49,34 +49,37 @@ static struct {
struct omap_dss_output output; struct omap_dss_output output;
} dpi; } 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; switch (channel) {
case OMAP_DSS_CHANNEL_LCD:
dsi_module = clk == OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ? 0 : 1; return dsi_get_dsidev_from_id(0);
case OMAP_DSS_CHANNEL_LCD2:
return dsi_get_dsidev_from_id(dsi_module); 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 == switch (channel) {
OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC || case OMAP_DSS_CHANNEL_LCD:
dssdev->clocks.dispc.dispc_fclk_src == return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC;
OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC || case OMAP_DSS_CHANNEL_LCD2:
dssdev->clocks.dispc.channel.lcd_clk_src == return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC || default:
dssdev->clocks.dispc.channel.lcd_clk_src == /* this shouldn't happen */
OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC) WARN_ON(1);
return true; return OMAP_DSS_CLK_SRC_FCK;
else }
return false;
} }
static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, static int dpi_set_dsi_clk(struct omap_dss_device *dssdev,
unsigned long pck_req, unsigned long *fck, int *lck_div, unsigned long pck_req, unsigned long *fck, int *lck_div,
int *pck_div) int *pck_div)
{ {
struct omap_overlay_manager *mgr = dssdev->output->manager;
struct dsi_clock_info dsi_cinfo; struct dsi_clock_info dsi_cinfo;
struct dispc_clock_info dispc_cinfo; struct dispc_clock_info dispc_cinfo;
int r; int r;
...@@ -90,7 +93,8 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, ...@@ -90,7 +93,8 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev,
if (r) if (r)
return 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; dpi.mgr_config.clock_info = dispc_cinfo;
...@@ -135,7 +139,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) ...@@ -135,7 +139,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
unsigned long pck; unsigned long pck;
int r = 0; int r = 0;
if (dpi_use_dsi_pll(dssdev)) if (dpi.dsidev)
r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck, r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck,
&lck_div, &pck_div); &lck_div, &pck_div);
else else
...@@ -214,7 +218,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) ...@@ -214,7 +218,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
if (r) if (r)
goto err_src_sel; goto err_src_sel;
if (dpi_use_dsi_pll(dssdev)) { if (dpi.dsidev) {
r = dsi_runtime_get(dpi.dsidev); r = dsi_runtime_get(dpi.dsidev);
if (r) if (r)
goto err_get_dsi; goto err_get_dsi;
...@@ -242,10 +246,10 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) ...@@ -242,10 +246,10 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
err_mgr_enable: err_mgr_enable:
err_set_mode: err_set_mode:
if (dpi_use_dsi_pll(dssdev)) if (dpi.dsidev)
dsi_pll_uninit(dpi.dsidev, true); dsi_pll_uninit(dpi.dsidev, true);
err_dsi_pll_init: err_dsi_pll_init:
if (dpi_use_dsi_pll(dssdev)) if (dpi.dsidev)
dsi_runtime_put(dpi.dsidev); dsi_runtime_put(dpi.dsidev);
err_get_dsi: err_get_dsi:
err_src_sel: err_src_sel:
...@@ -271,8 +275,8 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) ...@@ -271,8 +275,8 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
dss_mgr_disable(mgr); dss_mgr_disable(mgr);
if (dpi_use_dsi_pll(dssdev)) { if (dpi.dsidev) {
dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
dsi_pll_uninit(dpi.dsidev, true); dsi_pll_uninit(dpi.dsidev, true);
dsi_runtime_put(dpi.dsidev); dsi_runtime_put(dpi.dsidev);
} }
...@@ -317,7 +321,7 @@ int dpi_check_timings(struct omap_dss_device *dssdev, ...@@ -317,7 +321,7 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
if (timings->pixel_clock == 0) if (timings->pixel_clock == 0)
return -EINVAL; return -EINVAL;
if (dpi_use_dsi_pll(dssdev)) { if (dpi.dsidev) {
struct dsi_clock_info dsi_cinfo; struct dsi_clock_info dsi_cinfo;
r = dsi_pll_calc_clock_div_pck(dpi.dsidev, r = dsi_pll_calc_clock_div_pck(dpi.dsidev,
timings->pixel_clock * 1000, timings->pixel_clock * 1000,
...@@ -359,8 +363,32 @@ void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) ...@@ -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); 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) static int __init dpi_init_display(struct omap_dss_device *dssdev)
{ {
struct platform_device *dsidev;
DSSDBG("init_display\n"); DSSDBG("init_display\n");
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) &&
...@@ -377,12 +405,23 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev) ...@@ -377,12 +405,23 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev)
dpi.vdds_dsi_reg = vdds_dsi; dpi.vdds_dsi_reg = vdds_dsi;
} }
if (dpi_use_dsi_pll(dssdev)) { /*
enum omap_dss_clk_source dispc_fclk_src = * XXX We shouldn't need dssdev->channel for this. The dsi pll clock
dssdev->clocks.dispc.dispc_fclk_src; * source for DPI is SoC integration detail, not something that should
dpi.dsidev = dpi_get_dsidev(dispc_fclk_src); * 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; return 0;
} }
......
...@@ -1386,6 +1386,11 @@ int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, ...@@ -1386,6 +1386,11 @@ int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev,
cur.dsi_pll_hsdiv_dispc_clk = cur.dsi_pll_hsdiv_dispc_clk =
cur.clkin4ddr / cur.regm_dispc; 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, /* this will narrow down the search a bit,
* but still give pixclocks below what was * but still give pixclocks below what was
* requested */ * requested */
...@@ -1736,6 +1741,12 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, ...@@ -1736,6 +1741,12 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
DSSDBG("PLL init\n"); 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) { if (dsi->vdds_dsi_reg == NULL) {
struct regulator *vdds_dsi; struct regulator *vdds_dsi;
...@@ -4709,7 +4720,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) ...@@ -4709,7 +4720,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
if (r) if (r)
goto err1; 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_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src);
dss_select_lcd_clk_source(mgr->id, dss_select_lcd_clk_source(mgr->id,
dssdev->clocks.dispc.channel.lcd_clk_src); dssdev->clocks.dispc.channel.lcd_clk_src);
...@@ -4744,7 +4754,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) ...@@ -4744,7 +4754,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
err3: err3:
dsi_cio_uninit(dsidev); dsi_cio_uninit(dsidev);
err2: 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_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
dss_select_lcd_clk_source(mgr->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, ...@@ -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, 2, 0);
dsi_vc_enable(dsidev, 3, 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_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
dsi_cio_uninit(dsidev); dsi_cio_uninit(dsidev);
......
...@@ -304,7 +304,7 @@ static void dss_dump_regs(struct seq_file *s) ...@@ -304,7 +304,7 @@ static void dss_dump_regs(struct seq_file *s)
#undef DUMPREG #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; struct platform_device *dsidev;
int b; int b;
...@@ -375,8 +375,10 @@ void dss_select_lcd_clk_source(enum omap_channel channel, ...@@ -375,8 +375,10 @@ void dss_select_lcd_clk_source(enum omap_channel channel,
struct platform_device *dsidev; struct platform_device *dsidev;
int b, ix, pos; 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; return;
}
switch (clk_src) { switch (clk_src) {
case OMAP_DSS_CLK_SRC_FCK: case OMAP_DSS_CLK_SRC_FCK:
...@@ -432,6 +434,29 @@ enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) ...@@ -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) int dss_set_clock_div(struct dss_clock_info *cinfo)
{ {
if (dss.dpll4_m4_ck) { if (dss.dpll4_m4_ck) {
...@@ -462,6 +487,36 @@ unsigned long dss_get_dpll4_rate(void) ...@@ -462,6 +487,36 @@ unsigned long dss_get_dpll4_rate(void)
return 0; 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, int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
struct dispc_clock_info *dispc_cinfo) struct dispc_clock_info *dispc_cinfo)
{ {
...@@ -869,6 +924,10 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) ...@@ -869,6 +924,10 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
if (r) if (r)
return r; return r;
r = dss_setup_default_clock();
if (r)
goto err_setup_clocks;
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
r = dss_runtime_get(); r = dss_runtime_get();
...@@ -878,6 +937,8 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) ...@@ -878,6 +937,8 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
/* Select DPLL */ /* Select DPLL */
REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
#ifdef CONFIG_OMAP2_DSS_VENC #ifdef CONFIG_OMAP2_DSS_VENC
REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */
REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ 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) ...@@ -901,6 +962,7 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
err_runtime_get: err_runtime_get:
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
err_setup_clocks:
dss_put_clocks(); dss_put_clocks();
return r; return r;
} }
......
...@@ -283,7 +283,6 @@ void dss_sdi_init(int datapairs); ...@@ -283,7 +283,6 @@ void dss_sdi_init(int datapairs);
int dss_sdi_enable(void); int dss_sdi_enable(void);
void dss_sdi_disable(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, void dss_select_dsi_clk_source(int dsi_module,
enum omap_dss_clk_source clk_src); enum omap_dss_clk_source clk_src);
void dss_select_lcd_clk_source(enum omap_channel channel, 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); ...@@ -296,6 +295,7 @@ void dss_set_venc_output(enum omap_dss_venc_type type);
void dss_set_dac_pwrdn_bgz(bool enable); void dss_set_dac_pwrdn_bgz(bool enable);
unsigned long dss_get_dpll4_rate(void); 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_set_clock_div(struct dss_clock_info *cinfo);
int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo,
struct dispc_clock_info *dispc_cinfo); struct dispc_clock_info *dispc_cinfo);
......
...@@ -528,14 +528,6 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev) ...@@ -528,14 +528,6 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev)
/* Make selection of HDMI in DSS */ /* Make selection of HDMI in DSS */
dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); 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; return 0;
err_runtime_get: err_runtime_get:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment