[U-Boot] [PATCH] sunxi: video: HDMI: Fix clock setup
Jagan Teki
jagan at amarulasolutions.com
Thu Mar 28 07:52:48 UTC 2019
On Sun, Mar 24, 2019 at 11:56 PM Jernej Skrabec <jernej.skrabec at siol.net> wrote:
>
> Currently, HDMI driver doesn't consider minimum and maximum allowed rate
> of pll3 (video PLL). It works most of the time, but not always.
>
> Consider monitor with resolution 1920x1200, which has pixel clock rate
> of 154 MHz. Current code would determine that pll3 rate has to be set to
> 154 MHz. However, minimum supported rate is 192 MHz. In this case video
> output just won't work.
I set the monitor with same resolution, but not sure with the pixel
clock and unable to reproduce this with couple time. any specific
usage case that the issue will reproduce ?
>
> The reason why the driver is written in the way it is, is that at the
> time HDMI PHY and clock configuration wasn't fully understood. But now
> we have needed knowledge, so the issue can be fixed.
>
> With this fix, clock configuration routine uses full range (1-16) for
> clock divider instead of limited one (1, 2, 4, 11). It also considers
> minimum and maximum allowed rate for pll3.
>
> Fixes: 56009451d843 ("sunxi: video: Add A64/H3/H5 HDMI driver")
> Signed-off-by: Jernej Skrabec <jernej.skrabec at siol.net>
> ---
> Hi!
>
> Unfortunately, issue fixed with patch here has influence on Linux too.
> In Linux, minimum and maximum rate is considered only when changing rate.
> But because U-Boot already set PLL to "correct" value, Linux clock driver
> doesn't see the need to change it. I know that this is Linux driver issue
> but let's start at the source of the issue and fix it.
>
> It would be very nice if this can go in 2019.04 release.
>
> Best regards,
> Jernej
>
> drivers/video/sunxi/sunxi_dw_hdmi.c | 62 +++++++++++++++++------------
> 1 file changed, 37 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/video/sunxi/sunxi_dw_hdmi.c b/drivers/video/sunxi/sunxi_dw_hdmi.c
> index 9dbea649a0..6fe1aa7ee4 100644
> --- a/drivers/video/sunxi/sunxi_dw_hdmi.c
> +++ b/drivers/video/sunxi/sunxi_dw_hdmi.c
> @@ -132,7 +132,7 @@ static int sunxi_dw_hdmi_wait_for_hpd(void)
> return -1;
> }
>
> -static void sunxi_dw_hdmi_phy_set(uint clock)
> +static void sunxi_dw_hdmi_phy_set(uint clock, int phy_div)
> {
> struct sunxi_hdmi_phy * const phy =
> (struct sunxi_hdmi_phy *)(SUNXI_HDMI_BASE + HDMI_PHY_OFFS);
> @@ -146,7 +146,7 @@ static void sunxi_dw_hdmi_phy_set(uint clock)
> switch (div) {
> case 1:
> writel(0x30dc5fc0, &phy->pll);
> - writel(0x800863C0, &phy->clk);
> + writel(0x800863C0 | (phy_div - 1), &phy->clk);
> mdelay(10);
> writel(0x00000001, &phy->unk3);
> setbits_le32(&phy->pll, BIT(25));
> @@ -164,7 +164,7 @@ static void sunxi_dw_hdmi_phy_set(uint clock)
> break;
> case 2:
> writel(0x39dc5040, &phy->pll);
> - writel(0x80084381, &phy->clk);
> + writel(0x80084380 | (phy_div - 1), &phy->clk);
> mdelay(10);
> writel(0x00000001, &phy->unk3);
> setbits_le32(&phy->pll, BIT(25));
> @@ -178,7 +178,7 @@ static void sunxi_dw_hdmi_phy_set(uint clock)
> break;
> case 4:
> writel(0x39dc5040, &phy->pll);
> - writel(0x80084343, &phy->clk);
> + writel(0x80084340 | (phy_div - 1), &phy->clk);
> mdelay(10);
> writel(0x00000001, &phy->unk3);
> setbits_le32(&phy->pll, BIT(25));
> @@ -192,7 +192,7 @@ static void sunxi_dw_hdmi_phy_set(uint clock)
> break;
> case 11:
> writel(0x39dc5040, &phy->pll);
> - writel(0x8008430a, &phy->clk);
> + writel(0x80084300 | (phy_div - 1), &phy->clk);
> mdelay(10);
> writel(0x00000001, &phy->unk3);
> setbits_le32(&phy->pll, BIT(25));
> @@ -207,36 +207,46 @@ static void sunxi_dw_hdmi_phy_set(uint clock)
> }
> }
>
> -static void sunxi_dw_hdmi_pll_set(uint clk_khz)
> +static void sunxi_dw_hdmi_pll_set(uint clk_khz, int *phy_div)
> {
> - int value, n, m, div = 0, diff;
> - int best_n = 0, best_m = 0, best_diff = 0x0FFFFFFF;
> -
> - div = sunxi_dw_hdmi_get_divider(clk_khz * 1000);
> + int value, n, m, div, diff;
> + int best_n = 0, best_m = 0, best_div = 0, best_diff = 0x0FFFFFFF;
>
> /*
> * Find the lowest divider resulting in a matching clock. If there
> * is no match, pick the closest lower clock, as monitors tend to
> * not sync to higher frequencies.
> */
> - for (m = 1; m <= 16; m++) {
> - n = (m * div * clk_khz) / 24000;
> -
> - if ((n >= 1) && (n <= 128)) {
> - value = (24000 * n) / m / div;
> - diff = clk_khz - value;
> - if (diff < best_diff) {
> - best_diff = diff;
> - best_m = m;
> - best_n = n;
> + for (div = 1; div <= 16; div++) {
> + int target = clk_khz * div;
> +
> + if (target < 192000)
> + continue;
> + if (target > 912000)
> + continue;
I think this can be max allowed rate by PLL_VIDEO0 can't it be 1008 or 600 ?
More information about the U-Boot
mailing list