]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/hisilicon/hibmc: use clock to look up the PLL value
authorLin He <helin52@huawei.com>
Sat, 9 May 2026 03:23:02 +0000 (11:23 +0800)
committerThomas Zimmermann <tzimmermann@suse.de>
Wed, 13 May 2026 06:54:30 +0000 (08:54 +0200)
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: da52605eea8f ("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
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c

index e276b8ca213c094da42cb6d379471370cb606c10..3066dc9ebc64725b45e93bcc5ae807ef684a0c5f 100644 (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);
-
-       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;
-               }
+       int idx;
+
+       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);