// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/video/omap2/dss/dpi.c * * Copyright (C) 2009 Nokia Corporation * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak.
*/
/* only used in non-DT mode */ staticstruct dpi_data *dpi_get_data_from_pdev(struct platform_device *pdev)
{ return platform_get_drvdata(pdev);
}
staticstruct dss_pll *dpi_get_pll(enum omap_channel channel)
{ /* * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL * would also be used for DISPC fclk. Meaning, when the DPI output is * disabled, DISPC clock will be disabled, and TV out will stop.
*/ switch (omapdss_get_version()) { case OMAPDSS_VER_OMAP24xx: case OMAPDSS_VER_OMAP34xx_ES1: case OMAPDSS_VER_OMAP34xx_ES3: case OMAPDSS_VER_OMAP3630: case OMAPDSS_VER_AM35xx: case OMAPDSS_VER_AM43xx: return NULL;
case OMAPDSS_VER_OMAP4430_ES1: case OMAPDSS_VER_OMAP4430_ES2: case OMAPDSS_VER_OMAP4: switch (channel) { case OMAP_DSS_CHANNEL_LCD: return dss_pll_find("dsi0"); case OMAP_DSS_CHANNEL_LCD2: return dss_pll_find("dsi1"); default: return NULL;
}
case OMAPDSS_VER_OMAP5: switch (channel) { case OMAP_DSS_CHANNEL_LCD: return dss_pll_find("dsi0"); case OMAP_DSS_CHANNEL_LCD3: return dss_pll_find("dsi1"); default: return NULL;
}
case OMAPDSS_VER_DRA7xx: switch (channel) { case OMAP_DSS_CHANNEL_LCD: case OMAP_DSS_CHANNEL_LCD2: return dss_pll_find("video0"); case OMAP_DSS_CHANNEL_LCD3: return dss_pll_find("video1"); default: return NULL;
}
default: return NULL;
}
}
staticenum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
{ 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; case OMAP_DSS_CHANNEL_LCD3: return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC; default: /* this shouldn't happen */
WARN_ON(1); return OMAP_DSS_CLK_SRC_FCK;
}
}
/* * 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 >= 100000000) { if (lckd > 1 && lckd % 2 != 0) returnfalse;
/* * 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 (m_dispc > 1 && m_dispc % 2 != 0 && ctx->pck_min >= 100000000) returnfalse;
staticbool dpi_dss_clk_calc(unsignedlong 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 * +/- ~15MHz.
*/
for (i = 0; i < 25; ++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(pck, ctx->pck_min, dpi_calc_dss_cb, ctx); if (ok) return ok;
}
returnfalse;
}
staticint dpi_set_dsi_clk(struct dpi_data *dpi, enum omap_channel channel, unsignedlong pck_req, unsignedlong *fck, int *lck_div, int *pck_div)
{ struct dpi_clk_calc_ctx ctx; int r; bool ok;
ok = dpi_dsi_clk_calc(dpi, pck_req, &ctx); if (!ok) return -EINVAL;
r = dss_pll_set_config(dpi->pll, &ctx.dsi_cinfo); if (r) return r;
pll = dpi_get_pll(dpi->output.dispc_channel); if (!pll) return;
/* On DRA7 we need to set a mux to use the PLL */ if (omapdss_get_version() == OMAPDSS_VER_DRA7xx)
dss_ctrl_pll_set_control_mux(pll->id, dpi->output.dispc_channel);
if (dpi_verify_dsi_pll(pll)) {
DSSWARN("DSI PLL not operational\n"); return;
}
dpi->pll = pll;
}
/* * Return a hardcoded channel for the DPI output. This should work for * current use cases, but this can be later expanded to either resolve * the channel in some more dynamic manner, or get the channel as a user * parameter.
*/ staticenum omap_channel dpi_get_channel(int port_num)
{ switch (omapdss_get_version()) { case OMAPDSS_VER_OMAP24xx: case OMAPDSS_VER_OMAP34xx_ES1: case OMAPDSS_VER_OMAP34xx_ES3: case OMAPDSS_VER_OMAP3630: case OMAPDSS_VER_AM35xx: case OMAPDSS_VER_AM43xx: return OMAP_DSS_CHANNEL_LCD;
case OMAPDSS_VER_DRA7xx: switch (port_num) { case 2: return OMAP_DSS_CHANNEL_LCD3; case 1: return OMAP_DSS_CHANNEL_LCD2; case 0: default: return OMAP_DSS_CHANNEL_LCD;
}
case OMAPDSS_VER_OMAP4430_ES1: case OMAPDSS_VER_OMAP4430_ES2: case OMAPDSS_VER_OMAP4: return OMAP_DSS_CHANNEL_LCD2;
case OMAPDSS_VER_OMAP5: return OMAP_DSS_CHANNEL_LCD3;
mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); if (!mgr) return -ENODEV;
r = dss_mgr_connect(mgr, dssdev); if (r) return r;
r = omapdss_output_set_device(dssdev, dst); if (r) {
DSSERR("failed to connect output to new device: %s\n",
dst->name);
dss_mgr_disconnect(mgr, dssdev); return r;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.