Skip to content

Commit

Permalink
Merge branch '3.8/dsi-pll-work'
Browse files Browse the repository at this point in the history
Merge omapdss patches to enable using DSI PLL for DPI output.
  • Loading branch information
Tomi Valkeinen committed Nov 5, 2012
2 parents 9296dbd + 0e8276e commit a4ae0ba
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 50 deletions.
12 changes: 6 additions & 6 deletions drivers/video/omap2/dss/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
99 changes: 69 additions & 30 deletions drivers/video/omap2/dss/dpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand All @@ -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);
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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) &&
Expand All @@ -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;
}

Expand Down
14 changes: 11 additions & 3 deletions drivers/video/omap2/dss/dsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand All @@ -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);
Expand Down
66 changes: 64 additions & 2 deletions drivers/video/omap2/dss/dss.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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();
Expand All @@ -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 */
Expand All @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/video/omap2/dss/dss.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);
Expand Down
Loading

0 comments on commit a4ae0ba

Please sign in to comment.