mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 23:24:38 +00:00
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:
commit
48cf0d8c6d
1 changed files with 36 additions and 24 deletions
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue