Merge branch '3.8/dsi-pll-work'
Merge omapdss patches to enable using DSI PLL for DPI output.
This commit is contained in:
commit
a4ae0ba80b
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -1386,6 +1386,11 @@ retry:
|
||||
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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user