OMAPDSS: DPI: use new clock calculation code
Use the new clock calculation code in the DPI driver. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
This commit is contained in:
Родитель
36816faadf
Коммит
100c826235
|
@ -105,31 +105,170 @@ static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct dpi_clk_calc_ctx {
|
||||||
|
struct platform_device *dsidev;
|
||||||
|
|
||||||
|
/* inputs */
|
||||||
|
|
||||||
|
unsigned long pck_min, pck_max;
|
||||||
|
|
||||||
|
/* outputs */
|
||||||
|
|
||||||
|
struct dsi_clock_info dsi_cinfo;
|
||||||
|
struct dss_clock_info dss_cinfo;
|
||||||
|
struct dispc_clock_info dispc_cinfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
|
||||||
|
unsigned long pck, void *data)
|
||||||
|
{
|
||||||
|
struct dpi_clk_calc_ctx *ctx = data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Odd dividers give us uneven duty cycle, causing problem when level
|
||||||
|
* shifted. So skip all odd dividers when the pixel clock is on the
|
||||||
|
* higher side.
|
||||||
|
*/
|
||||||
|
if (ctx->pck_min >= 1000000) {
|
||||||
|
if (lckd > 1 && lckd % 2 != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (pckd > 1 && pckd % 2 != 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->dispc_cinfo.lck_div = lckd;
|
||||||
|
ctx->dispc_cinfo.pck_div = pckd;
|
||||||
|
ctx->dispc_cinfo.lck = lck;
|
||||||
|
ctx->dispc_cinfo.pck = pck;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct dpi_clk_calc_ctx *ctx = data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Odd dividers give us uneven duty cycle, causing problem when level
|
||||||
|
* shifted. So skip all odd dividers when the pixel clock is on the
|
||||||
|
* higher side.
|
||||||
|
*/
|
||||||
|
if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 1000000)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ctx->dsi_cinfo.regm_dispc = regm_dispc;
|
||||||
|
ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
|
||||||
|
|
||||||
|
return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max,
|
||||||
|
dpi_calc_dispc_cb, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool dpi_calc_pll_cb(int regn, int regm, unsigned long fint,
|
||||||
|
unsigned long pll,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct dpi_clk_calc_ctx *ctx = data;
|
||||||
|
|
||||||
|
ctx->dsi_cinfo.regn = regn;
|
||||||
|
ctx->dsi_cinfo.regm = regm;
|
||||||
|
ctx->dsi_cinfo.fint = fint;
|
||||||
|
ctx->dsi_cinfo.clkin4ddr = pll;
|
||||||
|
|
||||||
|
return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->pck_min,
|
||||||
|
dpi_calc_hsdiv_cb, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool dpi_calc_dss_cb(int fckd, unsigned long fck, void *data)
|
||||||
|
{
|
||||||
|
struct dpi_clk_calc_ctx *ctx = data;
|
||||||
|
|
||||||
|
ctx->dss_cinfo.fck = fck;
|
||||||
|
ctx->dss_cinfo.fck_div = fckd;
|
||||||
|
|
||||||
|
return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
|
||||||
|
dpi_calc_dispc_cb, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool dpi_dsi_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
|
||||||
|
{
|
||||||
|
unsigned long clkin;
|
||||||
|
unsigned long pll_min, pll_max;
|
||||||
|
|
||||||
|
clkin = dsi_get_pll_clkin(dpi.dsidev);
|
||||||
|
|
||||||
|
memset(ctx, 0, sizeof(*ctx));
|
||||||
|
ctx->dsidev = dpi.dsidev;
|
||||||
|
ctx->pck_min = pck - 1000;
|
||||||
|
ctx->pck_max = pck + 1000;
|
||||||
|
ctx->dsi_cinfo.clkin = clkin;
|
||||||
|
|
||||||
|
pll_min = 0;
|
||||||
|
pll_max = 0;
|
||||||
|
|
||||||
|
return dsi_pll_calc(dpi.dsidev, clkin,
|
||||||
|
pll_min, pll_max,
|
||||||
|
dpi_calc_pll_cb, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DSS fck gives us very few possibilities, so finding a good pixel
|
||||||
|
* clock may not be possible. We try multiple times to find the clock,
|
||||||
|
* each time widening the pixel clock range we look for, up to
|
||||||
|
* +/- 1MHz.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (i = 0; i < 10; ++i) {
|
||||||
|
bool ok;
|
||||||
|
|
||||||
|
memset(ctx, 0, sizeof(*ctx));
|
||||||
|
if (pck > 1000 * i * i * i)
|
||||||
|
ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);
|
||||||
|
else
|
||||||
|
ctx->pck_min = 0;
|
||||||
|
ctx->pck_max = pck + 1000 * i * i * i;
|
||||||
|
|
||||||
|
ok = dss_div_calc(ctx->pck_min, dpi_calc_dss_cb, ctx);
|
||||||
|
if (ok)
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int dpi_set_dsi_clk(enum omap_channel channel,
|
static int dpi_set_dsi_clk(enum omap_channel channel,
|
||||||
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 dsi_clock_info dsi_cinfo;
|
struct dpi_clk_calc_ctx ctx;
|
||||||
struct dispc_clock_info dispc_cinfo;
|
|
||||||
int r;
|
int r;
|
||||||
|
bool ok;
|
||||||
|
|
||||||
r = dsi_pll_calc_clock_div_pck(dpi.dsidev, pck_req, &dsi_cinfo,
|
ok = dpi_dsi_clk_calc(pck_req, &ctx);
|
||||||
&dispc_cinfo);
|
if (!ok)
|
||||||
if (r)
|
return -EINVAL;
|
||||||
return r;
|
|
||||||
|
|
||||||
r = dsi_pll_set_clock_div(dpi.dsidev, &dsi_cinfo);
|
r = dsi_pll_set_clock_div(dpi.dsidev, &ctx.dsi_cinfo);
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
dss_select_lcd_clk_source(channel,
|
dss_select_lcd_clk_source(channel,
|
||||||
dpi_get_alt_clk_src(channel));
|
dpi_get_alt_clk_src(channel));
|
||||||
|
|
||||||
dpi.mgr_config.clock_info = dispc_cinfo;
|
dpi.mgr_config.clock_info = ctx.dispc_cinfo;
|
||||||
|
|
||||||
*fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
|
*fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
|
||||||
*lck_div = dispc_cinfo.lck_div;
|
*lck_div = ctx.dispc_cinfo.lck_div;
|
||||||
*pck_div = dispc_cinfo.pck_div;
|
*pck_div = ctx.dispc_cinfo.pck_div;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -137,23 +276,23 @@ static int dpi_set_dsi_clk(enum omap_channel channel,
|
||||||
static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
|
static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
|
||||||
int *lck_div, int *pck_div)
|
int *lck_div, int *pck_div)
|
||||||
{
|
{
|
||||||
struct dss_clock_info dss_cinfo;
|
struct dpi_clk_calc_ctx ctx;
|
||||||
struct dispc_clock_info dispc_cinfo;
|
|
||||||
int r;
|
int r;
|
||||||
|
bool ok;
|
||||||
|
|
||||||
r = dss_calc_clock_div(pck_req, &dss_cinfo, &dispc_cinfo);
|
ok = dpi_dss_clk_calc(pck_req, &ctx);
|
||||||
|
if (!ok)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
r = dss_set_clock_div(&ctx.dss_cinfo);
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = dss_set_clock_div(&dss_cinfo);
|
dpi.mgr_config.clock_info = ctx.dispc_cinfo;
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
dpi.mgr_config.clock_info = dispc_cinfo;
|
*fck = ctx.dss_cinfo.fck;
|
||||||
|
*lck_div = ctx.dispc_cinfo.lck_div;
|
||||||
*fck = dss_cinfo.fck;
|
*pck_div = ctx.dispc_cinfo.pck_div;
|
||||||
*lck_div = dispc_cinfo.lck_div;
|
|
||||||
*pck_div = dispc_cinfo.pck_div;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -333,12 +472,12 @@ EXPORT_SYMBOL(omapdss_dpi_set_timings);
|
||||||
int dpi_check_timings(struct omap_dss_device *dssdev,
|
int dpi_check_timings(struct omap_dss_device *dssdev,
|
||||||
struct omap_video_timings *timings)
|
struct omap_video_timings *timings)
|
||||||
{
|
{
|
||||||
int r;
|
|
||||||
struct omap_overlay_manager *mgr = dpi.output.manager;
|
struct omap_overlay_manager *mgr = dpi.output.manager;
|
||||||
int lck_div, pck_div;
|
int lck_div, pck_div;
|
||||||
unsigned long fck;
|
unsigned long fck;
|
||||||
unsigned long pck;
|
unsigned long pck;
|
||||||
struct dispc_clock_info dispc_cinfo;
|
struct dpi_clk_calc_ctx ctx;
|
||||||
|
bool ok;
|
||||||
|
|
||||||
if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
|
if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -347,28 +486,21 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (dpi.dsidev) {
|
if (dpi.dsidev) {
|
||||||
struct dsi_clock_info dsi_cinfo;
|
ok = dpi_dsi_clk_calc(timings->pixel_clock * 1000, &ctx);
|
||||||
r = dsi_pll_calc_clock_div_pck(dpi.dsidev,
|
if (!ok)
|
||||||
timings->pixel_clock * 1000,
|
return -EINVAL;
|
||||||
&dsi_cinfo, &dispc_cinfo);
|
|
||||||
|
|
||||||
if (r)
|
fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
|
||||||
return r;
|
|
||||||
|
|
||||||
fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
|
|
||||||
} else {
|
} else {
|
||||||
struct dss_clock_info dss_cinfo;
|
ok = dpi_dss_clk_calc(timings->pixel_clock * 1000, &ctx);
|
||||||
r = dss_calc_clock_div(timings->pixel_clock * 1000,
|
if (!ok)
|
||||||
&dss_cinfo, &dispc_cinfo);
|
return -EINVAL;
|
||||||
|
|
||||||
if (r)
|
fck = ctx.dss_cinfo.fck;
|
||||||
return r;
|
|
||||||
|
|
||||||
fck = dss_cinfo.fck;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lck_div = dispc_cinfo.lck_div;
|
lck_div = ctx.dispc_cinfo.lck_div;
|
||||||
pck_div = dispc_cinfo.pck_div;
|
pck_div = ctx.dispc_cinfo.pck_div;
|
||||||
|
|
||||||
pck = fck / lck_div / pck_div / 1000;
|
pck = fck / lck_div / pck_div / 1000;
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче