sunxi HDMI clock fix

-----BEGIN PGP SIGNATURE-----
 
 iGwEABECACwWIQSC4hxrSoIUVfFO0kRM6ATMmsalXAUCXJ6OeQ4cYWd1c3RAZGVu
 eC5kZQAKCRBM6ATMmsalXGvXAJ9jNK7cM9AO3JWL2g8ptvIHEPchcQCfT23338UU
 UhQU8vB5arkKl5jEWAk=
 =fayw
 -----END PGP SIGNATURE-----

Merge tag 'video-fixes-for-2019.04-rc4' of git://git.denx.de/u-boot-video

sunxi HDMI clock fix
This commit is contained in:
Tom Rini 2019-03-31 07:25:11 -04:00
commit 48cf0d8c6d

View File

@ -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;
for (div = 1; div <= 16; div++) {
int target = clk_khz * div;
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;
if (target < 192000)
continue;
if (target > 912000)
continue;
for (m = 1; m <= 16; m++) {
n = (m * target) / 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;
best_div = div;
}
}
}
}
*phy_div = best_div;
clock_set_pll3_factors(best_m, best_n);
debug("dotclock: %dkHz = %dkHz: (24MHz * %d) / %d / %d\n",
clk_khz, (clock_get_pll3() / 1000) / div,
best_n, best_m, div);
clk_khz, (clock_get_pll3() / 1000) / best_div,
best_n, best_m, best_div);
}
static void sunxi_dw_hdmi_lcdc_init(int mux, const struct display_timing *edid,
@ -244,7 +254,7 @@ static void sunxi_dw_hdmi_lcdc_init(int mux, const struct display_timing *edid,
{
struct sunxi_ccm_reg * const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
int div = sunxi_dw_hdmi_get_divider(edid->pixelclock.typ);
int div = clock_get_pll3() / edid->pixelclock.typ;
struct sunxi_lcdc_reg *lcdc;
if (mux == 0) {
@ -276,8 +286,10 @@ static void sunxi_dw_hdmi_lcdc_init(int mux, const struct display_timing *edid,
static int sunxi_dw_hdmi_phy_cfg(struct dw_hdmi *hdmi, uint mpixelclock)
{
sunxi_dw_hdmi_pll_set(mpixelclock/1000);
sunxi_dw_hdmi_phy_set(mpixelclock);
int phy_div;
sunxi_dw_hdmi_pll_set(mpixelclock / 1000, &phy_div);
sunxi_dw_hdmi_phy_set(mpixelclock, phy_div);
return 0;
}