drm/hisilicon/hibmc: use clock to look up the PLL value

In the past, we use width and height to look up our PLL value.
But actually the actual clock check is also necessnary. There are
some resolutions that width and height same, but its clock different.
Add the clock check when using pll_table to determine the PLL value.

Fixes: da52605eea ("drm/hisilicon/hibmc: Add support for display engine")
Signed-off-by: Lin He <helin52@huawei.com>
Signed-off-by: Yongbang Shi <shiyongbang@huawei.com>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patch.msgid.link/20260509032302.2057227-5-shiyongbang@huawei.com
This commit is contained in:
Lin He
2026-05-09 11:23:02 +08:00
committed by Thomas Zimmermann
parent de2a56c71f
commit 99ef3a4f1c

View File

@@ -32,26 +32,43 @@ struct hibmc_display_panel_pll {
struct hibmc_dislay_pll_config {
u64 hdisplay;
u64 vdisplay;
int clock;
u32 pll1_config_value;
u32 pll2_config_value;
};
static const struct hibmc_dislay_pll_config hibmc_pll_table[] = {
{640, 480, CRT_PLL1_HS_25MHZ, CRT_PLL2_HS_25MHZ},
{800, 600, CRT_PLL1_HS_40MHZ, CRT_PLL2_HS_40MHZ},
{1024, 768, CRT_PLL1_HS_65MHZ, CRT_PLL2_HS_65MHZ},
{1152, 864, CRT_PLL1_HS_80MHZ_1152, CRT_PLL2_HS_80MHZ},
{1280, 768, CRT_PLL1_HS_80MHZ, CRT_PLL2_HS_80MHZ},
{1280, 720, CRT_PLL1_HS_74MHZ, CRT_PLL2_HS_74MHZ},
{1280, 960, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ},
{1280, 1024, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ},
{1440, 900, CRT_PLL1_HS_106MHZ, CRT_PLL2_HS_106MHZ},
{1600, 900, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ},
{1600, 1200, CRT_PLL1_HS_162MHZ, CRT_PLL2_HS_162MHZ},
{1920, 1080, CRT_PLL1_HS_148MHZ, CRT_PLL2_HS_148MHZ},
{1920, 1200, CRT_PLL1_HS_193MHZ, CRT_PLL2_HS_193MHZ},
{640, 480, 25000, CRT_PLL1_HS_25MHZ, CRT_PLL2_HS_25MHZ},
{800, 600, 40000, CRT_PLL1_HS_40MHZ, CRT_PLL2_HS_40MHZ},
{1024, 768, 65000, CRT_PLL1_HS_65MHZ, CRT_PLL2_HS_65MHZ},
{1152, 864, 78750, CRT_PLL1_HS_80MHZ_1152, CRT_PLL2_HS_80MHZ},
{1280, 768, 80000, CRT_PLL1_HS_80MHZ, CRT_PLL2_HS_80MHZ},
{1280, 720, 74375, CRT_PLL1_HS_74MHZ, CRT_PLL2_HS_74MHZ},
{1280, 960, 108000, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ},
{1280, 1024, 108000, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ},
{1440, 900, 105952, CRT_PLL1_HS_106MHZ, CRT_PLL2_HS_106MHZ},
{1600, 900, 108000, CRT_PLL1_HS_108MHZ, CRT_PLL2_HS_108MHZ},
{1600, 1200, 162500, CRT_PLL1_HS_162MHZ, CRT_PLL2_HS_162MHZ},
{1920, 1080, 148750, CRT_PLL1_HS_148MHZ, CRT_PLL2_HS_148MHZ},
{1920, 1200, 193750, CRT_PLL1_HS_193MHZ, CRT_PLL2_HS_193MHZ},
};
static int hibmc_get_best_clock_idx(const struct drm_display_mode *mode)
{
int i, diff;
for (i = 0; i < ARRAY_SIZE(hibmc_pll_table); i++) {
if (hibmc_pll_table[i].hdisplay == mode->hdisplay &&
hibmc_pll_table[i].vdisplay == mode->vdisplay) {
diff = abs(mode->clock - hibmc_pll_table[i].clock);
if (diff < mode->clock / 100) /* tolerance 1/100 */
return i;
}
}
return -MODE_CLOCK_RANGE;
}
static int hibmc_plane_atomic_check(struct drm_plane *plane,
struct drm_atomic_commit *state)
{
@@ -214,19 +231,15 @@ static enum drm_mode_status
hibmc_crtc_mode_valid(struct drm_crtc *crtc,
const struct drm_display_mode *mode)
{
size_t i = 0;
int vrefresh = drm_mode_vrefresh(mode);
if (vrefresh < 59 || vrefresh > 61)
return MODE_NOCLOCK;
for (i = 0; i < ARRAY_SIZE(hibmc_pll_table); i++) {
if (hibmc_pll_table[i].hdisplay == mode->hdisplay &&
hibmc_pll_table[i].vdisplay == mode->vdisplay)
return MODE_OK;
}
if (hibmc_get_best_clock_idx(mode) >= 0)
return MODE_OK;
return MODE_BAD;
return MODE_CLOCK_RANGE;
}
static u32 format_pll_reg(void)
@@ -281,23 +294,20 @@ static void set_vclock_hisilicon(struct drm_device *dev, u64 pll)
writel(val, priv->mmio + CRT_PLL1_HS);
}
static void get_pll_config(u64 x, u64 y, u32 *pll1, u32 *pll2)
static void get_pll_config(struct drm_display_mode *mode, u32 *pll1, u32 *pll2)
{
size_t i;
size_t count = ARRAY_SIZE(hibmc_pll_table);
int idx;
for (i = 0; i < count; i++) {
if (hibmc_pll_table[i].hdisplay == x &&
hibmc_pll_table[i].vdisplay == y) {
*pll1 = hibmc_pll_table[i].pll1_config_value;
*pll2 = hibmc_pll_table[i].pll2_config_value;
return;
}
idx = hibmc_get_best_clock_idx(mode);
if (idx < 0) {
/* if found none, we use default value */
*pll1 = CRT_PLL1_HS_25MHZ;
*pll2 = CRT_PLL2_HS_25MHZ;
return;
}
/* if found none, we use default value */
*pll1 = CRT_PLL1_HS_25MHZ;
*pll2 = CRT_PLL2_HS_25MHZ;
*pll1 = hibmc_pll_table[idx].pll1_config_value;
*pll2 = hibmc_pll_table[idx].pll2_config_value;
}
/*
@@ -319,7 +329,7 @@ static u32 display_ctrl_adjust(struct drm_device *dev,
x = mode->hdisplay;
y = mode->vdisplay;
get_pll_config(x, y, &pll1, &pll2);
get_pll_config(mode, &pll1, &pll2);
writel(pll2, priv->mmio + CRT_PLL2_HS);
set_vclock_hisilicon(dev, pll1);