From: Archit Taneja <a0393947@ti.com>
To: Tomi Valkeinen <tomi.valkeinen@ti.com>
Cc: linux-omap@vger.kernel.org, linux-fbdev@vger.kernel.org
Subject: Re: [PATCH 6/8] OMAPDSS: DSI: calculate dsi clock
Date: Fri, 24 Aug 2012 06:28:39 +0000 [thread overview]
Message-ID: <50371C47.30708@ti.com> (raw)
In-Reply-To: <1345729514-2441-7-git-send-email-tomi.valkeinen@ti.com>
On Thursday 23 August 2012 07:15 PM, Tomi Valkeinen wrote:
> Currently the way to configure clocks related to DSI (both DSI and DISPC
> clocks) happens via omapdss platform data. The reason for this is that
> configuring the DSS clocks is a very complex problem, and it's
> impossible for the SW to know requirements about things like
> interference.
>
> However, for general cases it should be fine to calculate the dividers
> for clocks in the SW. The calculated clocks are probably not perfect,
> but should work.
>
> This patch adds support to calculate the dividers when using DSI command
> mode panels. The panel gives the required DDR clock rate and LP clock
> rate, and the DSI driver configures itself and DISPC accordingly.
>
> This patch is somewhat ugly, though. The code does its job by modifying
> the platform data where the clock dividers would be if the board file
> gave them. This is not how it's going to be in the future, but allows us
> to have quite simple patch and keep the backward compatibility.
>
> It also allows the developer to still give the exact dividers from the
> board file when there's need for that, as long as the panel driver does
> not override them.
>
> There are also other areas for improvement. For example, it would be
> better if the panel driver could ask for a DSI clock in a certain range,
> as, at least command mode panels, the panel can work fine with many
> different clock speeds.
>
> While the patch is not perfect, it allows us to remove the hardcoded
> clock dividers from the board file, making it easier to bring up a new
> panel and to use device tree from omapdss.
>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
> ---
> drivers/video/omap2/displays/panel-taal.c | 6 ++
> drivers/video/omap2/dss/dsi.c | 126 +++++++++++++++++++++++++++++
> include/video/omapdss.h | 2 +
> 3 files changed, 134 insertions(+)
>
> diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
> index 77aed0e..ddda96a 100644
> --- a/drivers/video/omap2/displays/panel-taal.c
> +++ b/drivers/video/omap2/displays/panel-taal.c
> @@ -1065,6 +1065,12 @@ static int taal_power_on(struct omap_dss_device *dssdev)
> omapdss_dsi_set_pixel_format(dssdev, OMAP_DSS_DSI_FMT_RGB888);
> omapdss_dsi_set_operation_mode(dssdev, OMAP_DSS_DSI_CMD_MODE);
>
> + r = omapdss_dsi_set_clocks(dssdev, 216000000, 10000000);
> + if (r) {
> + dev_err(&dssdev->dev, "failed to set HS and LP clocks\n");
> + goto err0;
> + }
> +
> r = omapdss_dsi_display_enable(dssdev);
> if (r) {
> dev_err(&dssdev->dev, "failed to enable DSI\n");
> diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
> index 96d0024..340c832 100644
> --- a/drivers/video/omap2/dss/dsi.c
> +++ b/drivers/video/omap2/dss/dsi.c
> @@ -1454,6 +1454,68 @@ found:
> return 0;
> }
>
> +static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev,
> + unsigned long req_clk, struct dsi_clock_info *cinfo)
> +{
> + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
> + struct dsi_clock_info cur, best;
> + unsigned long dss_sys_clk, max_dss_fck, max_dsi_fck;
> + unsigned long req_clkin4ddr;
> +
> + DSSDBG("dsi_pll_calc_ddrfreq\n");
> +
> + dss_sys_clk = clk_get_rate(dsi->sys_clk);
> +
> + max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
> + max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK);
> +
> + memset(&best, 0, sizeof(best));
> + memset(&cur, 0, sizeof(cur));
> +
> + cur.clkin = dss_sys_clk;
> +
> + req_clkin4ddr = req_clk * 4;
> +
> + for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) {
> + cur.fint = cur.clkin / cur.regn;
> +
> + if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min)
> + continue;
> +
> + /* DSIPHY(MHz) = (2 * regm / regn) * clkin */
> + for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) {
> + unsigned long a, b;
> +
> + a = 2 * cur.regm * (cur.clkin/1000);
> + b = cur.regn;
> + cur.clkin4ddr = a / b * 1000;
> +
> + if (cur.clkin4ddr > 1800 * 1000 * 1000)
> + break;
> +
> + if (abs(cur.clkin4ddr - req_clkin4ddr) <
> + abs(best.clkin4ddr - req_clkin4ddr)) {
> + best = cur;
> + DSSDBG("best %ld\n", best.clkin4ddr);
> + }
> +
> + if (cur.clkin4ddr = req_clkin4ddr)
> + goto found;
> + }
> + }
> +found:
> + best.regm_dispc = DIV_ROUND_UP(best.clkin4ddr, max_dss_fck);
> + best.dsi_pll_hsdiv_dispc_clk = best.clkin4ddr / best.regm_dispc;
> +
> + best.regm_dsi = DIV_ROUND_UP(best.clkin4ddr, max_dsi_fck);
> + best.dsi_pll_hsdiv_dsi_clk = best.clkin4ddr / best.regm_dsi;
> +
> + if (cinfo)
> + *cinfo = best;
> +
> + return 0;
> +}
> +
> int dsi_pll_set_clock_div(struct platform_device *dsidev,
> struct dsi_clock_info *cinfo)
> {
> @@ -4110,6 +4172,70 @@ int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev,
> }
> EXPORT_SYMBOL(omapdss_dsi_configure_pins);
>
> +int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev,
> + unsigned long ddr_clk, unsigned long lp_clk)
> +{
> + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
> + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
> + struct dsi_clock_info cinfo;
> + struct dispc_clock_info dispc_cinfo;
> + unsigned lp_clk_div;
> + unsigned long dsi_fclk;
> + int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
> + unsigned long pck;
> + int r;
> +
> + DSSDBGF("ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk);
> +
> + mutex_lock(&dsi->lock);
> +
> + r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk, &cinfo);
> + if (r)
> + goto err;
> +
> + dssdev->clocks.dsi.regn = cinfo.regn;
> + dssdev->clocks.dsi.regm = cinfo.regm;
> + dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc;
> + dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi;
> +
> +
> + dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk;
> + lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2);
> +
> + dssdev->clocks.dsi.lp_clk_div = lp_clk_div;
> +
> + /* pck = TxByteClkHS * datalanes * 8 / bitsperpixel */
This formula looks a bit simplified, we aren't considering the header
and footers of long packets that will add to the DDR clock. But I guess
not considering these would only give a higher pixel clock than needed,
which isn't that bad.
> +
> + pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp;
> +
> + DSSDBG("finding dispc dividers for pck %lu\n", pck);
> +
> + dispc_find_clk_divs(pck, cinfo.dsi_pll_hsdiv_dispc_clk, &dispc_cinfo);
> +
> + dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div;
> + dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div;
> +
> +
one unnecessary new line above.
<snip>
Archit
WARNING: multiple messages have this Message-ID (diff)
From: Archit Taneja <a0393947@ti.com>
To: Tomi Valkeinen <tomi.valkeinen@ti.com>
Cc: linux-omap@vger.kernel.org, linux-fbdev@vger.kernel.org
Subject: Re: [PATCH 6/8] OMAPDSS: DSI: calculate dsi clock
Date: Fri, 24 Aug 2012 11:46:39 +0530 [thread overview]
Message-ID: <50371C47.30708@ti.com> (raw)
In-Reply-To: <1345729514-2441-7-git-send-email-tomi.valkeinen@ti.com>
On Thursday 23 August 2012 07:15 PM, Tomi Valkeinen wrote:
> Currently the way to configure clocks related to DSI (both DSI and DISPC
> clocks) happens via omapdss platform data. The reason for this is that
> configuring the DSS clocks is a very complex problem, and it's
> impossible for the SW to know requirements about things like
> interference.
>
> However, for general cases it should be fine to calculate the dividers
> for clocks in the SW. The calculated clocks are probably not perfect,
> but should work.
>
> This patch adds support to calculate the dividers when using DSI command
> mode panels. The panel gives the required DDR clock rate and LP clock
> rate, and the DSI driver configures itself and DISPC accordingly.
>
> This patch is somewhat ugly, though. The code does its job by modifying
> the platform data where the clock dividers would be if the board file
> gave them. This is not how it's going to be in the future, but allows us
> to have quite simple patch and keep the backward compatibility.
>
> It also allows the developer to still give the exact dividers from the
> board file when there's need for that, as long as the panel driver does
> not override them.
>
> There are also other areas for improvement. For example, it would be
> better if the panel driver could ask for a DSI clock in a certain range,
> as, at least command mode panels, the panel can work fine with many
> different clock speeds.
>
> While the patch is not perfect, it allows us to remove the hardcoded
> clock dividers from the board file, making it easier to bring up a new
> panel and to use device tree from omapdss.
>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
> ---
> drivers/video/omap2/displays/panel-taal.c | 6 ++
> drivers/video/omap2/dss/dsi.c | 126 +++++++++++++++++++++++++++++
> include/video/omapdss.h | 2 +
> 3 files changed, 134 insertions(+)
>
> diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
> index 77aed0e..ddda96a 100644
> --- a/drivers/video/omap2/displays/panel-taal.c
> +++ b/drivers/video/omap2/displays/panel-taal.c
> @@ -1065,6 +1065,12 @@ static int taal_power_on(struct omap_dss_device *dssdev)
> omapdss_dsi_set_pixel_format(dssdev, OMAP_DSS_DSI_FMT_RGB888);
> omapdss_dsi_set_operation_mode(dssdev, OMAP_DSS_DSI_CMD_MODE);
>
> + r = omapdss_dsi_set_clocks(dssdev, 216000000, 10000000);
> + if (r) {
> + dev_err(&dssdev->dev, "failed to set HS and LP clocks\n");
> + goto err0;
> + }
> +
> r = omapdss_dsi_display_enable(dssdev);
> if (r) {
> dev_err(&dssdev->dev, "failed to enable DSI\n");
> diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
> index 96d0024..340c832 100644
> --- a/drivers/video/omap2/dss/dsi.c
> +++ b/drivers/video/omap2/dss/dsi.c
> @@ -1454,6 +1454,68 @@ found:
> return 0;
> }
>
> +static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev,
> + unsigned long req_clk, struct dsi_clock_info *cinfo)
> +{
> + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
> + struct dsi_clock_info cur, best;
> + unsigned long dss_sys_clk, max_dss_fck, max_dsi_fck;
> + unsigned long req_clkin4ddr;
> +
> + DSSDBG("dsi_pll_calc_ddrfreq\n");
> +
> + dss_sys_clk = clk_get_rate(dsi->sys_clk);
> +
> + max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
> + max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK);
> +
> + memset(&best, 0, sizeof(best));
> + memset(&cur, 0, sizeof(cur));
> +
> + cur.clkin = dss_sys_clk;
> +
> + req_clkin4ddr = req_clk * 4;
> +
> + for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) {
> + cur.fint = cur.clkin / cur.regn;
> +
> + if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min)
> + continue;
> +
> + /* DSIPHY(MHz) = (2 * regm / regn) * clkin */
> + for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) {
> + unsigned long a, b;
> +
> + a = 2 * cur.regm * (cur.clkin/1000);
> + b = cur.regn;
> + cur.clkin4ddr = a / b * 1000;
> +
> + if (cur.clkin4ddr > 1800 * 1000 * 1000)
> + break;
> +
> + if (abs(cur.clkin4ddr - req_clkin4ddr) <
> + abs(best.clkin4ddr - req_clkin4ddr)) {
> + best = cur;
> + DSSDBG("best %ld\n", best.clkin4ddr);
> + }
> +
> + if (cur.clkin4ddr == req_clkin4ddr)
> + goto found;
> + }
> + }
> +found:
> + best.regm_dispc = DIV_ROUND_UP(best.clkin4ddr, max_dss_fck);
> + best.dsi_pll_hsdiv_dispc_clk = best.clkin4ddr / best.regm_dispc;
> +
> + best.regm_dsi = DIV_ROUND_UP(best.clkin4ddr, max_dsi_fck);
> + best.dsi_pll_hsdiv_dsi_clk = best.clkin4ddr / best.regm_dsi;
> +
> + if (cinfo)
> + *cinfo = best;
> +
> + return 0;
> +}
> +
> int dsi_pll_set_clock_div(struct platform_device *dsidev,
> struct dsi_clock_info *cinfo)
> {
> @@ -4110,6 +4172,70 @@ int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev,
> }
> EXPORT_SYMBOL(omapdss_dsi_configure_pins);
>
> +int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev,
> + unsigned long ddr_clk, unsigned long lp_clk)
> +{
> + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
> + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
> + struct dsi_clock_info cinfo;
> + struct dispc_clock_info dispc_cinfo;
> + unsigned lp_clk_div;
> + unsigned long dsi_fclk;
> + int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
> + unsigned long pck;
> + int r;
> +
> + DSSDBGF("ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk);
> +
> + mutex_lock(&dsi->lock);
> +
> + r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk, &cinfo);
> + if (r)
> + goto err;
> +
> + dssdev->clocks.dsi.regn = cinfo.regn;
> + dssdev->clocks.dsi.regm = cinfo.regm;
> + dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc;
> + dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi;
> +
> +
> + dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk;
> + lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2);
> +
> + dssdev->clocks.dsi.lp_clk_div = lp_clk_div;
> +
> + /* pck = TxByteClkHS * datalanes * 8 / bitsperpixel */
This formula looks a bit simplified, we aren't considering the header
and footers of long packets that will add to the DDR clock. But I guess
not considering these would only give a higher pixel clock than needed,
which isn't that bad.
> +
> + pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp;
> +
> + DSSDBG("finding dispc dividers for pck %lu\n", pck);
> +
> + dispc_find_clk_divs(pck, cinfo.dsi_pll_hsdiv_dispc_clk, &dispc_cinfo);
> +
> + dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div;
> + dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div;
> +
> +
one unnecessary new line above.
<snip>
Archit
next prev parent reply other threads:[~2012-08-24 6:28 UTC|newest]
Thread overview: 50+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-08-23 13:45 [PATCH 0/8] OMAPDSS: Misc improvements Tomi Valkeinen
2012-08-23 13:45 ` Tomi Valkeinen
2012-08-23 13:45 ` [PATCH 1/8] OMAPDSS: HDMI: Move GPIO handling to HDMI driver Tomi Valkeinen
2012-08-23 13:45 ` Tomi Valkeinen
2012-08-24 6:00 ` Archit Taneja
2012-08-24 6:12 ` Archit Taneja
2012-08-24 6:28 ` Tomi Valkeinen
2012-08-24 6:28 ` Tomi Valkeinen
2012-09-07 16:21 ` Tony Lindgren
2012-09-07 16:21 ` Tony Lindgren
2012-08-23 13:45 ` [PATCH 2/8] OMAPDSS: HDMI: Add delay to wait for 5V power Tomi Valkeinen
2012-08-23 13:45 ` Tomi Valkeinen
2012-08-23 13:45 ` [PATCH 3/8] OMAP4: TWL: add vdda_hdmi_dac regulator supply Tomi Valkeinen
2012-08-23 13:45 ` Tomi Valkeinen
2012-09-06 20:12 ` Tony Lindgren
2012-09-06 20:12 ` Tony Lindgren
2012-08-23 13:45 ` [PATCH 4/8] OMAPDSS: HDMI: use vdda_hdmi_dac Tomi Valkeinen
2012-08-23 13:45 ` Tomi Valkeinen
2012-08-24 6:20 ` Archit Taneja
2012-08-24 6:32 ` Archit Taneja
2012-08-24 6:41 ` Tomi Valkeinen
2012-08-24 6:41 ` Tomi Valkeinen
2012-08-23 13:45 ` [PATCH 5/8] OMAPDSS: Add DSI fclk maximum to dss_features Tomi Valkeinen
2012-08-23 13:45 ` Tomi Valkeinen
2012-08-23 13:45 ` [PATCH 6/8] OMAPDSS: DSI: calculate dsi clock Tomi Valkeinen
2012-08-23 13:45 ` Tomi Valkeinen
2012-08-24 6:16 ` Archit Taneja [this message]
2012-08-24 6:28 ` Archit Taneja
2012-08-24 8:55 ` Tomi Valkeinen
2012-08-24 8:55 ` Tomi Valkeinen
2012-08-24 9:17 ` Archit Taneja
2012-08-24 9:29 ` Archit Taneja
2012-08-23 13:45 ` [PATCH 7/8] OMAP: 4430SDP: remove DSI clock config from board file Tomi Valkeinen
2012-08-23 13:45 ` Tomi Valkeinen
2012-09-06 20:11 ` Tony Lindgren
2012-09-06 20:11 ` Tony Lindgren
2012-08-23 13:45 ` [PATCH 8/8] OMAPDSS: fix use of dssdev->caps Tomi Valkeinen
2012-08-23 13:45 ` Tomi Valkeinen
2012-08-24 5:51 ` Archit Taneja
2012-08-24 5:52 ` Archit Taneja
2012-09-04 7:22 ` [PATCH 0/8] OMAPDSS: Misc improvements Tomi Valkeinen
2012-09-04 7:22 ` Tomi Valkeinen
2012-09-06 20:13 ` Tony Lindgren
2012-09-06 20:13 ` Tony Lindgren
2012-09-07 10:16 ` Tomi Valkeinen
2012-09-07 10:16 ` Tomi Valkeinen
2012-09-07 16:22 ` Tony Lindgren
2012-09-07 16:22 ` Tony Lindgren
2012-09-07 16:59 ` Tomi Valkeinen
2012-09-07 16:59 ` Tomi Valkeinen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=50371C47.30708@ti.com \
--to=a0393947@ti.com \
--cc=linux-fbdev@vger.kernel.org \
--cc=linux-omap@vger.kernel.org \
--cc=tomi.valkeinen@ti.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.