From d9cc564bf3aee6fcc1c717a19f9a207114510671 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 2 Jul 2021 09:56:42 +0200 Subject: drm/mgag200: Constify LUT for programming bpp Declare constant LUT for bpp programming as static const. Removes mutable data from device structure. Signed-off-by: Thomas Zimmermann Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210702075642.27834-5-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_mode.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers/gpu/drm/mgag200/mgag200_mode.c') diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 9d576240faed..3b3059f471c2 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -1137,10 +1137,11 @@ static void mgag200_set_mode_regs(struct mga_device *mdev, WREG8(MGA_MISC_OUT, misc); } -static u8 mgag200_get_bpp_shift(struct mga_device *mdev, - const struct drm_format_info *format) +static u8 mgag200_get_bpp_shift(const struct drm_format_info *format) { - return mdev->bpp_shifts[format->cpp[0] - 1]; + static const u8 bpp_shift[] = {0, 1, 0, 2}; + + return bpp_shift[format->cpp[0] - 1]; } /* @@ -1152,7 +1153,7 @@ static u32 mgag200_calculate_offset(struct mga_device *mdev, const struct drm_framebuffer *fb) { u32 offset = fb->pitches[0] / fb->format->cpp[0]; - u8 bppshift = mgag200_get_bpp_shift(mdev, fb->format); + u8 bppshift = mgag200_get_bpp_shift(fb->format); if (fb->format->cpp[0] * 8 == 24) offset = (offset * 3) >> (4 - bppshift); @@ -1189,7 +1190,7 @@ static void mgag200_set_format_regs(struct mga_device *mdev, bpp = format->cpp[0] * 8; - bppshift = mgag200_get_bpp_shift(mdev, format); + bppshift = mgag200_get_bpp_shift(format); switch (bpp) { case 24: scale = ((1 << bppshift) * 3) - 1; @@ -1699,11 +1700,6 @@ int mgag200_modeset_init(struct mga_device *mdev) size_t format_count = ARRAY_SIZE(mgag200_simple_display_pipe_formats); int ret; - mdev->bpp_shifts[0] = 0; - mdev->bpp_shifts[1] = 1; - mdev->bpp_shifts[2] = 0; - mdev->bpp_shifts[3] = 2; - mgag200_init_regs(mdev); ret = drmm_mode_config_init(dev); -- cgit From 147696720eca12ae48d020726208b9a61cdd80bc Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 14 Jul 2021 16:22:28 +0200 Subject: drm/mgag200: Select clock in PLL update functions Put the clock-selection code into each of the PLL-update functions to make them select the correct pixel clock. Instead of copying the code, introduce a new helper WREG_MISC_MASKED, which does masked writes into . Use it from each individual PLL update function. The pixel clock for video output was not actually set before programming the clock's values. It worked because the device had the correct clock pre-set. v2: * don't duplicate update code (Sam) Signed-off-by: Thomas Zimmermann Fixes: db05f8d3dc87 ("drm/mgag200: Split MISC register update into PLL selection, SYNC and I/O") Acked-by: Sam Ravnborg Cc: Sam Ravnborg Cc: Emil Velikov Cc: Dave Airlie Cc: dri-devel@lists.freedesktop.org Cc: # v5.9+ Link: https://patchwork.freedesktop.org/patch/msgid/20210714142240.21979-2-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_mode.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'drivers/gpu/drm/mgag200/mgag200_mode.c') diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 3b3059f471c2..1bdf21474bcb 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -174,6 +174,8 @@ static int mgag200_g200_set_plls(struct mga_device *mdev, long clock) drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n", clock, f_vco, m, n, p, s); + WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); + WREG_DAC(MGA1064_PIX_PLLC_M, m); WREG_DAC(MGA1064_PIX_PLLC_N, n); WREG_DAC(MGA1064_PIX_PLLC_P, (p | (s << 3))); @@ -289,6 +291,8 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock) return 1; } + WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); + WREG_DAC(MGA1064_PIX_PLLC_M, m); WREG_DAC(MGA1064_PIX_PLLC_N, n); WREG_DAC(MGA1064_PIX_PLLC_P, p); @@ -385,6 +389,8 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) } } + WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); + for (i = 0; i <= 32 && pll_locked == false; i++) { if (i > 0) { WREG8(MGAREG_CRTC_INDEX, 0x1e); @@ -522,6 +528,8 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) } } + WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); + WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); tmp = RREG8(DAC_DATA); tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; @@ -654,6 +662,9 @@ static int mga_g200eh_set_plls(struct mga_device *mdev, long clock) } } } + + WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); + for (i = 0; i <= 32 && pll_locked == false; i++) { WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); tmp = RREG8(DAC_DATA); @@ -754,6 +765,8 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock) } } + WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); + WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); tmp = RREG8(DAC_DATA); tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; @@ -787,8 +800,6 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock) static int mgag200_crtc_set_plls(struct mga_device *mdev, long clock) { - u8 misc; - switch(mdev->type) { case G200_PCI: case G200_AGP: @@ -808,11 +819,6 @@ static int mgag200_crtc_set_plls(struct mga_device *mdev, long clock) return mga_g200er_set_plls(mdev, clock); } - misc = RREG8(MGA_MISC_IN); - misc &= ~MGAREG_MISC_CLK_SEL_MASK; - misc |= MGAREG_MISC_CLK_SEL_MGA_MSK; - WREG8(MGA_MISC_OUT, misc); - return 0; } -- cgit From 08a709467c17e89c824a36cae76626527a4ccbbe Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 14 Jul 2021 16:22:29 +0200 Subject: drm/mgag200: Return errno codes from PLL compute functions Return -EINVAL if there's no PLL configuration for the given pixel clock. The returned errors are currently ignored by the caller, but the errno codes will become useful when the compute functions run during atomic checks. v2: * give a rational for this change (Sam) Signed-off-by: Thomas Zimmermann Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210714142240.21979-3-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_mode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/mgag200/mgag200_mode.c') diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 1bdf21474bcb..69daa0fd73c9 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -133,7 +133,7 @@ static int mgag200_g200_set_plls(struct mga_device *mdev, long clock) if (clock > p_clk_max) { drm_err(dev, "Pixel Clock %ld too high\n", clock); - return 1; + return -EINVAL; } if (clock < p_clk_min >> 3) @@ -288,7 +288,7 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock) if (delta > permitteddelta) { pr_warn("PLL delta too large\n"); - return 1; + return -EINVAL; } WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); -- cgit From 83c90cdb7525e9ebb7d0083e2c107601a7a86a39 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 14 Jul 2021 16:22:30 +0200 Subject: drm/mgag200: Remove P_ARRAY_SIZE Replace P_ARRAY_SIZE by array pre-initializing and ARRAY_SIZE(). No functional changes. Signed-off-by: Thomas Zimmermann Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210714142240.21979-4-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_mode.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/mgag200/mgag200_mode.c') diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 69daa0fd73c9..549595b1daba 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -183,17 +183,16 @@ static int mgag200_g200_set_plls(struct mga_device *mdev, long clock) return 0; } -#define P_ARRAY_SIZE 9 - static int mga_g200se_set_plls(struct mga_device *mdev, long clock) { + static const unsigned int pvalues_e4[] = {16, 14, 12, 10, 8, 6, 4, 2, 1}; + u32 unique_rev_id = mdev->model.g200se.unique_rev_id; unsigned int vcomax, vcomin, pllreffreq; unsigned int delta, tmpdelta, permitteddelta; unsigned int testp, testm, testn; unsigned int p, m, n; unsigned int computed; - unsigned int pvalues_e4[P_ARRAY_SIZE] = {16, 14, 12, 10, 8, 6, 4, 2, 1}; unsigned int fvv; unsigned int i; @@ -247,7 +246,7 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock) /* Permited delta is 0.5% as VESA Specification */ permitteddelta = clock * 5 / 1000; - for (i = 0 ; i < P_ARRAY_SIZE ; i++) { + for (i = 0 ; i < ARRAY_SIZE(pvalues_e4); i++) { testp = pvalues_e4[i]; if ((clock * testp) > vcomax) -- cgit From f86c3ed55920ca1d874758cc290890902a6cffc4 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 14 Jul 2021 16:22:31 +0200 Subject: drm/mgag200: Split PLL setup into compute and update functions The _set_plls() functions compute a pixel clock's PLL values and program the hardware accordingly. This happens during atomic commits. For atomic modesetting, it's better to separate computation and programming from each other. This will allow to compute the PLL value during atomic checks and catch unsupported modes early. Split the PLL setup into a compute and an update functions, and call them one after the other. Computed PLL values are store in struct mgag200_pll_values. There are four parameters for the PLL, m, n, p and s. Every compute function stores a value for each of these parameters, and the rsp update function makes the register bits from them. The values stored by the compute function are either plain values or register bits. An additional change is required to always store plain values. No functional changes. Signed-off-by: Thomas Zimmermann Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210714142240.21979-5-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_mode.c | 233 +++++++++++++++++++++++++-------- 1 file changed, 181 insertions(+), 52 deletions(-) (limited to 'drivers/gpu/drm/mgag200/mgag200_mode.c') diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 549595b1daba..c9eb044bcb7d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -114,7 +114,8 @@ static inline void mga_wait_busy(struct mga_device *mdev) * PLL setup */ -static int mgag200_g200_set_plls(struct mga_device *mdev, long clock) +static int mgag200_compute_pixpll_values_g200(struct mga_device *mdev, long clock, + struct mgag200_pll_values *pixpllc) { struct drm_device *dev = &mdev->base; const int post_div_max = 7; @@ -174,16 +175,32 @@ static int mgag200_g200_set_plls(struct mga_device *mdev, long clock) drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n", clock, f_vco, m, n, p, s); - WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); - - WREG_DAC(MGA1064_PIX_PLLC_M, m); - WREG_DAC(MGA1064_PIX_PLLC_N, n); - WREG_DAC(MGA1064_PIX_PLLC_P, (p | (s << 3))); + pixpllc->m = m; + pixpllc->n = n; + pixpllc->p = p; + pixpllc->s = s; return 0; } -static int mga_g200se_set_plls(struct mga_device *mdev, long clock) +static void mgag200_set_pixpll_g200(struct mga_device *mdev, + const struct mgag200_pll_values *pixpllc) +{ + u8 xpixpllcm, xpixpllcn, xpixpllcp; + + xpixpllcm = pixpllc->m; + xpixpllcn = pixpllc->n; + xpixpllcp = pixpllc->p | (pixpllc->s << 3); + + WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); + + WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm); + WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn); + WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp); +} + +static int mgag200_compute_pixpll_values_g200se(struct mga_device *mdev, long clock, + struct mgag200_pll_values *pixpllc) { static const unsigned int pvalues_e4[] = {16, 14, 12, 10, 8, 6, 4, 2, 1}; @@ -290,32 +307,45 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock) return -EINVAL; } + pixpllc->m = m; + pixpllc->n = n; + pixpllc->p = p; + pixpllc->s = 0; + + return 0; +} + +static void mgag200_set_pixpll_g200se(struct mga_device *mdev, + const struct mgag200_pll_values *pixpllc) +{ + u32 unique_rev_id = mdev->model.g200se.unique_rev_id; + u8 xpixpllcm, xpixpllcn, xpixpllcp; + + xpixpllcm = pixpllc->m; + xpixpllcn = pixpllc->n; + xpixpllcp = pixpllc->p | (pixpllc->s << 3); + WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); - WREG_DAC(MGA1064_PIX_PLLC_M, m); - WREG_DAC(MGA1064_PIX_PLLC_N, n); - WREG_DAC(MGA1064_PIX_PLLC_P, p); + WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm); + WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn); + WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp); if (unique_rev_id >= 0x04) { WREG_DAC(0x1a, 0x09); msleep(20); WREG_DAC(0x1a, 0x01); - } - - return 0; } -static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) +static int mgag200_compute_pixpll_values_g200wb(struct mga_device *mdev, long clock, + struct mgag200_pll_values *pixpllc) { unsigned int vcomax, vcomin, pllreffreq; unsigned int delta, tmpdelta; unsigned int testp, testm, testn, testp2; unsigned int p, m, n; unsigned int computed; - int i, j, tmpcount, vcount; - bool pll_locked = false; - u8 tmp; m = n = p = 0; @@ -388,6 +418,25 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) } } + pixpllc->m = m; + pixpllc->n = n; + pixpllc->p = p; + pixpllc->s = 0; + + return 0; +} + +static void mgag200_set_pixpll_g200wb(struct mga_device *mdev, + const struct mgag200_pll_values *pixpllc) +{ + u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; + int i, j, tmpcount, vcount; + bool pll_locked = false; + + xpixpllcm = pixpllc->m; + xpixpllcn = pixpllc->n; + xpixpllcp = pixpllc->p | (pixpllc->s << 3); + WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); for (i = 0; i <= 32 && pll_locked == false; i++) { @@ -430,9 +479,9 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) udelay(50); /* program pixel pll register */ - WREG_DAC(MGA1064_WB_PIX_PLLC_N, n); - WREG_DAC(MGA1064_WB_PIX_PLLC_M, m); - WREG_DAC(MGA1064_WB_PIX_PLLC_P, p); + WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn); + WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm); + WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp); udelay(50); @@ -480,21 +529,21 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) udelay(5); } } + WREG8(DAC_INDEX, MGA1064_REMHEADCTL); tmp = RREG8(DAC_DATA); tmp &= ~MGA1064_REMHEADCTL_CLKDIS; WREG_DAC(MGA1064_REMHEADCTL, tmp); - return 0; } -static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) +static int mgag200_compute_pixpll_values_g200ev(struct mga_device *mdev, long clock, + struct mgag200_pll_values *pixpllc) { unsigned int vcomax, vcomin, pllreffreq; unsigned int delta, tmpdelta; unsigned int testp, testm, testn; unsigned int p, m, n; unsigned int computed; - u8 tmp; m = n = p = 0; vcomax = 550000; @@ -527,6 +576,23 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) } } + pixpllc->m = m; + pixpllc->n = n; + pixpllc->p = p; + pixpllc->s = 0; + + return 0; +} + +static void mgag200_set_pixpll_g200ev(struct mga_device *mdev, + const struct mgag200_pll_values *pixpllc) +{ + u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; + + xpixpllcm = pixpllc->m; + xpixpllcn = pixpllc->n; + xpixpllcp = pixpllc->p | (pixpllc->s << 3); + WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); @@ -547,9 +613,9 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; WREG8(DAC_DATA, tmp); - WREG_DAC(MGA1064_EV_PIX_PLLC_M, m); - WREG_DAC(MGA1064_EV_PIX_PLLC_N, n); - WREG_DAC(MGA1064_EV_PIX_PLLC_P, p); + WREG_DAC(MGA1064_EV_PIX_PLLC_M, xpixpllcm); + WREG_DAC(MGA1064_EV_PIX_PLLC_N, xpixpllcn); + WREG_DAC(MGA1064_EV_PIX_PLLC_P, xpixpllcp); udelay(50); @@ -578,20 +644,16 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) tmp = RREG8(DAC_DATA); tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; WREG8(DAC_DATA, tmp); - - return 0; } -static int mga_g200eh_set_plls(struct mga_device *mdev, long clock) +static int mgag200_compute_pixpll_values_g200eh(struct mga_device *mdev, long clock, + struct mgag200_pll_values *pixpllc) { unsigned int vcomax, vcomin, pllreffreq; unsigned int delta, tmpdelta; unsigned int testp, testm, testn; unsigned int p, m, n; unsigned int computed; - int i, j, tmpcount, vcount; - u8 tmp; - bool pll_locked = false; m = n = p = 0; @@ -662,6 +724,25 @@ static int mga_g200eh_set_plls(struct mga_device *mdev, long clock) } } + pixpllc->m = m; + pixpllc->n = n; + pixpllc->p = p; + pixpllc->s = 0; + + return 0; +} + +static void mgag200_set_pixpll_g200eh(struct mga_device *mdev, + const struct mgag200_pll_values *pixpllc) +{ + u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; + int i, j, tmpcount, vcount; + bool pll_locked = false; + + xpixpllcm = pixpllc->m; + xpixpllcn = pixpllc->n; + xpixpllcp = pixpllc->p | (pixpllc->s << 3); + WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); for (i = 0; i <= 32 && pll_locked == false; i++) { @@ -681,9 +762,9 @@ static int mga_g200eh_set_plls(struct mga_device *mdev, long clock) udelay(500); - WREG_DAC(MGA1064_EH_PIX_PLLC_M, m); - WREG_DAC(MGA1064_EH_PIX_PLLC_N, n); - WREG_DAC(MGA1064_EH_PIX_PLLC_P, p); + WREG_DAC(MGA1064_EH_PIX_PLLC_M, xpixpllcm); + WREG_DAC(MGA1064_EH_PIX_PLLC_N, xpixpllcn); + WREG_DAC(MGA1064_EH_PIX_PLLC_P, xpixpllcp); udelay(500); @@ -711,11 +792,10 @@ static int mga_g200eh_set_plls(struct mga_device *mdev, long clock) udelay(5); } } - - return 0; } -static int mga_g200er_set_plls(struct mga_device *mdev, long clock) +static int mgag200_compute_pixpll_values_g200er(struct mga_device *mdev, long clock, + struct mgag200_pll_values *pixpllc) { static const unsigned int m_div_val[] = { 1, 2, 4, 8 }; unsigned int vcomax, vcomin, pllreffreq; @@ -723,7 +803,6 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock) int testr, testn, testm, testo; unsigned int p, m, n; unsigned int computed, vco; - int tmp; m = n = p = 0; vcomax = 1488000; @@ -764,6 +843,23 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock) } } + pixpllc->m = m; + pixpllc->n = n; + pixpllc->p = p; + pixpllc->s = 0; + + return 0; +} + +static void mgag200_set_pixpll_g200er(struct mga_device *mdev, + const struct mgag200_pll_values *pixpllc) +{ + u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; + + xpixpllcm = pixpllc->m; + xpixpllcn = pixpllc->n; + xpixpllcp = pixpllc->p | (pixpllc->s << 3); + WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); @@ -788,37 +884,70 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock) udelay(500); - WREG_DAC(MGA1064_ER_PIX_PLLC_N, n); - WREG_DAC(MGA1064_ER_PIX_PLLC_M, m); - WREG_DAC(MGA1064_ER_PIX_PLLC_P, p); + WREG_DAC(MGA1064_ER_PIX_PLLC_N, xpixpllcn); + WREG_DAC(MGA1064_ER_PIX_PLLC_M, xpixpllcm); + WREG_DAC(MGA1064_ER_PIX_PLLC_P, xpixpllcp); udelay(50); - - return 0; } -static int mgag200_crtc_set_plls(struct mga_device *mdev, long clock) +static void mgag200_crtc_set_plls(struct mga_device *mdev, long clock) { + struct mgag200_pll_values pixpll; + int ret; + switch(mdev->type) { case G200_PCI: case G200_AGP: - return mgag200_g200_set_plls(mdev, clock); + ret = mgag200_compute_pixpll_values_g200(mdev, clock, &pixpll); + break; case G200_SE_A: case G200_SE_B: - return mga_g200se_set_plls(mdev, clock); + ret = mgag200_compute_pixpll_values_g200se(mdev, clock, &pixpll); + break; case G200_WB: case G200_EW3: - return mga_g200wb_set_plls(mdev, clock); + ret = mgag200_compute_pixpll_values_g200wb(mdev, clock, &pixpll); + break; case G200_EV: - return mga_g200ev_set_plls(mdev, clock); + ret = mgag200_compute_pixpll_values_g200ev(mdev, clock, &pixpll); + break; case G200_EH: case G200_EH3: - return mga_g200eh_set_plls(mdev, clock); + ret = mgag200_compute_pixpll_values_g200eh(mdev, clock, &pixpll); + break; case G200_ER: - return mga_g200er_set_plls(mdev, clock); + ret = mgag200_compute_pixpll_values_g200er(mdev, clock, &pixpll); + break; } - return 0; + if (ret) + return; + + switch (mdev->type) { + case G200_PCI: + case G200_AGP: + mgag200_set_pixpll_g200(mdev, &pixpll); + break; + case G200_SE_A: + case G200_SE_B: + mgag200_set_pixpll_g200se(mdev, &pixpll); + break; + case G200_WB: + case G200_EW3: + mgag200_set_pixpll_g200wb(mdev, &pixpll); + break; + case G200_EV: + mgag200_set_pixpll_g200ev(mdev, &pixpll); + break; + case G200_EH: + case G200_EH3: + mgag200_set_pixpll_g200eh(mdev, &pixpll); + break; + case G200_ER: + mgag200_set_pixpll_g200er(mdev, &pixpll); + break; + } } static void mgag200_g200wb_hold_bmc(struct mga_device *mdev) -- cgit From d9d992238a5aaf1a1e2ba013dd37dccf7b48c0a7 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 14 Jul 2021 16:22:32 +0200 Subject: drm/mgag200: Introduce separate variable for PLL S parameter The S parameter is controls the loop filter bandwidth when programming the PLL. It's currently stored as part of P (i.e., the clock divider.) Add a separate variable for S prepares the PLL code for further refactoring. The value of s is currently 0, so it has not yet an effect on the programming. v2: * add a note on the current value of s to commit message Signed-off-by: Thomas Zimmermann Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210714142240.21979-6-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_mode.c | 36 +++++++++++++++------------------- 1 file changed, 16 insertions(+), 20 deletions(-) (limited to 'drivers/gpu/drm/mgag200/mgag200_mode.c') diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index c9eb044bcb7d..6085d807bb20 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -208,18 +208,17 @@ static int mgag200_compute_pixpll_values_g200se(struct mga_device *mdev, long cl unsigned int vcomax, vcomin, pllreffreq; unsigned int delta, tmpdelta, permitteddelta; unsigned int testp, testm, testn; - unsigned int p, m, n; + unsigned int p, m, n, s; unsigned int computed; unsigned int fvv; unsigned int i; - if (unique_rev_id <= 0x03) { + m = n = p = s = 0; - m = n = p = 0; + if (unique_rev_id <= 0x03) { vcomax = 320000; vcomin = 160000; pllreffreq = 25000; - delta = 0xffffffff; permitteddelta = clock * 5 / 1000; @@ -247,9 +246,6 @@ static int mgag200_compute_pixpll_values_g200se(struct mga_device *mdev, long cl } } } else { - - - m = n = p = 0; vcomax = 1600000; vcomin = 800000; pllreffreq = 25000; @@ -310,7 +306,7 @@ static int mgag200_compute_pixpll_values_g200se(struct mga_device *mdev, long cl pixpllc->m = m; pixpllc->n = n; pixpllc->p = p; - pixpllc->s = 0; + pixpllc->s = s; return 0; } @@ -344,10 +340,10 @@ static int mgag200_compute_pixpll_values_g200wb(struct mga_device *mdev, long cl unsigned int vcomax, vcomin, pllreffreq; unsigned int delta, tmpdelta; unsigned int testp, testm, testn, testp2; - unsigned int p, m, n; + unsigned int p, m, n, s; unsigned int computed; - m = n = p = 0; + m = n = p = s = 0; delta = 0xffffffff; @@ -421,7 +417,7 @@ static int mgag200_compute_pixpll_values_g200wb(struct mga_device *mdev, long cl pixpllc->m = m; pixpllc->n = n; pixpllc->p = p; - pixpllc->s = 0; + pixpllc->s = s; return 0; } @@ -542,10 +538,10 @@ static int mgag200_compute_pixpll_values_g200ev(struct mga_device *mdev, long cl unsigned int vcomax, vcomin, pllreffreq; unsigned int delta, tmpdelta; unsigned int testp, testm, testn; - unsigned int p, m, n; + unsigned int p, m, n, s; unsigned int computed; - m = n = p = 0; + m = n = p = s = 0; vcomax = 550000; vcomin = 150000; pllreffreq = 50000; @@ -579,7 +575,7 @@ static int mgag200_compute_pixpll_values_g200ev(struct mga_device *mdev, long cl pixpllc->m = m; pixpllc->n = n; pixpllc->p = p; - pixpllc->s = 0; + pixpllc->s = s; return 0; } @@ -652,10 +648,10 @@ static int mgag200_compute_pixpll_values_g200eh(struct mga_device *mdev, long cl unsigned int vcomax, vcomin, pllreffreq; unsigned int delta, tmpdelta; unsigned int testp, testm, testn; - unsigned int p, m, n; + unsigned int p, m, n, s; unsigned int computed; - m = n = p = 0; + m = n = p = s = 0; if (mdev->type == G200_EH3) { vcomax = 3000000; @@ -727,7 +723,7 @@ static int mgag200_compute_pixpll_values_g200eh(struct mga_device *mdev, long cl pixpllc->m = m; pixpllc->n = n; pixpllc->p = p; - pixpllc->s = 0; + pixpllc->s = s; return 0; } @@ -801,10 +797,10 @@ static int mgag200_compute_pixpll_values_g200er(struct mga_device *mdev, long cl unsigned int vcomax, vcomin, pllreffreq; unsigned int delta, tmpdelta; int testr, testn, testm, testo; - unsigned int p, m, n; + unsigned int p, m, n, s; unsigned int computed, vco; - m = n = p = 0; + m = n = p = s = 0; vcomax = 1488000; vcomin = 1056000; pllreffreq = 48000; @@ -846,7 +842,7 @@ static int mgag200_compute_pixpll_values_g200er(struct mga_device *mdev, long cl pixpllc->m = m; pixpllc->n = n; pixpllc->p = p; - pixpllc->s = 0; + pixpllc->s = s; return 0; } -- cgit From 2dd040946ecfa5434fb0084fb5b5c2ba55639ea1 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 14 Jul 2021 16:22:33 +0200 Subject: drm/mgag200: Store values (not bits) in struct mgag200_pll_values The fields in struct mgag200_pll_values currently hold the bits of each register. Store the PLL values instead and let the PLL-update code figure out the bits for each register. Until now, the compute function either stored plain values or register bits in struct mgag200_pll_values. The rsp update function used the values as-is. This made it very hard to correctly interpret the stored values (e.g., for logging or debugging). With the cleanup, the stored values now have a clear meaning. v2: * add a bit more context in the commit message (Sam) Signed-off-by: Thomas Zimmermann Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210714142240.21979-7-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_mode.c | 153 ++++++++++++++++++++------------- 1 file changed, 91 insertions(+), 62 deletions(-) (limited to 'drivers/gpu/drm/mgag200/mgag200_mode.c') diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 6085d807bb20..6e730435357d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -123,7 +123,7 @@ static int mgag200_compute_pixpll_values_g200(struct mga_device *mdev, long cloc const int in_div_max = 6; const int feed_div_min = 7; const int feed_div_max = 127; - u8 testm, testn; + u8 testp, testm, testn; u8 n = 0, m = 0, p, s; long f_vco; long computed; @@ -141,10 +141,11 @@ static int mgag200_compute_pixpll_values_g200(struct mga_device *mdev, long cloc clock = p_clk_min >> 3; f_vco = clock; - for (p = 0; - p <= post_div_max && f_vco < p_clk_min; - p = (p << 1) + 1, f_vco <<= 1) + for (testp = 0; + testp <= post_div_max && f_vco < p_clk_min; + testp = (testp << 1) + 1, f_vco <<= 1) ; + p = testp + 1; delta = clock; @@ -157,12 +158,12 @@ static int mgag200_compute_pixpll_values_g200(struct mga_device *mdev, long cloc tmp_delta = computed - f_vco; if (tmp_delta < delta) { delta = tmp_delta; - m = testm; - n = testn; + m = testm + 1; + n = testn + 1; } } } - f_vco = ref_clk * (n + 1) / (m + 1); + f_vco = ref_clk * n / m; if (f_vco < 100000) s = 0; else if (f_vco < 140000) @@ -186,11 +187,17 @@ static int mgag200_compute_pixpll_values_g200(struct mga_device *mdev, long cloc static void mgag200_set_pixpll_g200(struct mga_device *mdev, const struct mgag200_pll_values *pixpllc) { + unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; u8 xpixpllcm, xpixpllcn, xpixpllcp; - xpixpllcm = pixpllc->m; - xpixpllcn = pixpllc->n; - xpixpllcp = pixpllc->p | (pixpllc->s << 3); + pixpllcm = pixpllc->m - 1; + pixpllcn = pixpllc->n - 1; + pixpllcp = pixpllc->p - 1; + pixpllcs = pixpllc->s; + + xpixpllcm = pixpllcm; + xpixpllcn = pixpllcn; + xpixpllcp = (pixpllcs << 3) | pixpllcp; WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); @@ -238,9 +245,9 @@ static int mgag200_compute_pixpll_values_g200se(struct mga_device *mdev, long cl tmpdelta = clock - computed; if (tmpdelta < delta) { delta = tmpdelta; - m = testm - 1; - n = testn - 1; - p = testp - 1; + m = testm; + n = testn; + p = testp; } } } @@ -278,22 +285,19 @@ static int mgag200_compute_pixpll_values_g200se(struct mga_device *mdev, long cl if (tmpdelta < delta) { delta = tmpdelta; - m = testm - 1; - n = testn - 1; - p = testp - 1; + m = testm; + n = testn; + p = testp; } } } } - fvv = pllreffreq * (n + 1) / (m + 1); + fvv = pllreffreq * n / m; fvv = (fvv - 800000) / 50000; - if (fvv > 15) fvv = 15; - - p |= (fvv << 4); - m |= 0x80; + s = fvv << 1; clock = clock / 2; } @@ -315,11 +319,17 @@ static void mgag200_set_pixpll_g200se(struct mga_device *mdev, const struct mgag200_pll_values *pixpllc) { u32 unique_rev_id = mdev->model.g200se.unique_rev_id; + unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; u8 xpixpllcm, xpixpllcn, xpixpllcp; - xpixpllcm = pixpllc->m; - xpixpllcn = pixpllc->n; - xpixpllcp = pixpllc->p | (pixpllc->s << 3); + pixpllcm = pixpllc->m - 1; + pixpllcn = pixpllc->n - 1; + pixpllcp = pixpllc->p - 1; + pixpllcs = pixpllc->s; + + xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1); + xpixpllcn = pixpllcn; + xpixpllcp = (pixpllcs << 3) | pixpllcp; WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); @@ -348,7 +358,6 @@ static int mgag200_compute_pixpll_values_g200wb(struct mga_device *mdev, long cl delta = 0xffffffff; if (mdev->type == G200_EW3) { - vcomax = 800000; vcomin = 400000; pllreffreq = 25000; @@ -371,19 +380,16 @@ static int mgag200_compute_pixpll_values_g200wb(struct mga_device *mdev, long cl tmpdelta = clock - computed; if (tmpdelta < delta) { delta = tmpdelta; - m = ((testn & 0x100) >> 1) | - (testm); - n = (testn & 0xFF); - p = ((testn & 0x600) >> 3) | - (testp2 << 3) | - (testp); + m = testm + 1; + n = testn + 1; + p = testp + 1; + s = testp2; } } } } } } else { - vcomax = 550000; vcomin = 150000; pllreffreq = 48000; @@ -404,10 +410,10 @@ static int mgag200_compute_pixpll_values_g200wb(struct mga_device *mdev, long cl tmpdelta = clock - computed; if (tmpdelta < delta) { delta = tmpdelta; - n = testn - 1; - m = (testm - 1) | - ((n >> 1) & 0x80); - p = testp - 1; + n = testn; + m = testm; + p = testp; + s = 0; } } } @@ -425,13 +431,19 @@ static int mgag200_compute_pixpll_values_g200wb(struct mga_device *mdev, long cl static void mgag200_set_pixpll_g200wb(struct mga_device *mdev, const struct mgag200_pll_values *pixpllc) { + unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; int i, j, tmpcount, vcount; bool pll_locked = false; - xpixpllcm = pixpllc->m; - xpixpllcn = pixpllc->n; - xpixpllcp = pixpllc->p | (pixpllc->s << 3); + pixpllcm = pixpllc->m - 1; + pixpllcn = pixpllc->n - 1; + pixpllcp = pixpllc->p - 1; + pixpllcs = pixpllc->s; + + xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm; + xpixpllcn = pixpllcn; + xpixpllcp = ((pixpllcn & GENMASK(10, 9)) >> 3) | (pixpllcs << 3) | pixpllcp; WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); @@ -564,9 +576,9 @@ static int mgag200_compute_pixpll_values_g200ev(struct mga_device *mdev, long cl tmpdelta = clock - computed; if (tmpdelta < delta) { delta = tmpdelta; - n = testn - 1; - m = testm - 1; - p = testp - 1; + n = testn; + m = testm; + p = testp; } } } @@ -583,11 +595,17 @@ static int mgag200_compute_pixpll_values_g200ev(struct mga_device *mdev, long cl static void mgag200_set_pixpll_g200ev(struct mga_device *mdev, const struct mgag200_pll_values *pixpllc) { + unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; - xpixpllcm = pixpllc->m; - xpixpllcn = pixpllc->n; - xpixpllcp = pixpllc->p | (pixpllc->s << 3); + pixpllcm = pixpllc->m - 1; + pixpllcn = pixpllc->n - 1; + pixpllcp = pixpllc->p - 1; + pixpllcs = pixpllc->s; + + xpixpllcm = pixpllcm; + xpixpllcn = pixpllcn; + xpixpllcp = (pixpllcs << 3) | pixpllcp; WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); @@ -675,9 +693,9 @@ static int mgag200_compute_pixpll_values_g200eh(struct mga_device *mdev, long cl tmpdelta = clock - computed; if (tmpdelta < delta) { delta = tmpdelta; - n = testn; - m = testm; - p = testp; + n = testn + 1; + m = testm + 1; + p = testp + 1; } if (delta == 0) break; @@ -709,12 +727,10 @@ static int mgag200_compute_pixpll_values_g200eh(struct mga_device *mdev, long cl tmpdelta = clock - computed; if (tmpdelta < delta) { delta = tmpdelta; - n = testn - 1; - m = (testm - 1); - p = testp - 1; + n = testn; + m = testm; + p = testp; } - if ((clock * testp) >= 600000) - p |= 0x80; } } } @@ -731,13 +747,19 @@ static int mgag200_compute_pixpll_values_g200eh(struct mga_device *mdev, long cl static void mgag200_set_pixpll_g200eh(struct mga_device *mdev, const struct mgag200_pll_values *pixpllc) { + unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; int i, j, tmpcount, vcount; bool pll_locked = false; - xpixpllcm = pixpllc->m; - xpixpllcn = pixpllc->n; - xpixpllcp = pixpllc->p | (pixpllc->s << 3); + pixpllcm = pixpllc->m - 1; + pixpllcn = pixpllc->n - 1; + pixpllcp = pixpllc->p - 1; + pixpllcs = pixpllc->s; + + xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm; + xpixpllcn = pixpllcn; + xpixpllcp = (pixpllcs << 3) | pixpllcp; WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); @@ -830,9 +852,10 @@ static int mgag200_compute_pixpll_values_g200er(struct mga_device *mdev, long cl tmpdelta = clock - computed; if (tmpdelta < delta) { delta = tmpdelta; - m = testm | (testo << 3); - n = testn; - p = testr | (testr << 3); + m = (testm | (testo << 3)) + 1; + n = testn + 1; + p = testr + 1; + s = testr; } } } @@ -850,11 +873,17 @@ static int mgag200_compute_pixpll_values_g200er(struct mga_device *mdev, long cl static void mgag200_set_pixpll_g200er(struct mga_device *mdev, const struct mgag200_pll_values *pixpllc) { + unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; - xpixpllcm = pixpllc->m; - xpixpllcn = pixpllc->n; - xpixpllcp = pixpllc->p | (pixpllc->s << 3); + pixpllcm = pixpllc->m - 1; + pixpllcn = pixpllc->n - 1; + pixpllcp = pixpllc->p - 1; + pixpllcs = pixpllc->s; + + xpixpllcm = pixpllcm; + xpixpllcn = pixpllcn; + xpixpllcp = (pixpllcs << 3) | pixpllcp; WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); -- cgit From 35b36ff4495a4b6f872f304cb97d47b13197874b Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 14 Jul 2021 16:22:34 +0200 Subject: drm/mgag200: Split PLL compute functions by device type Several PLL functions compute values for different device types. Split them up to make the code more readable. No functional changes. Signed-off-by: Thomas Zimmermann Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210714142240.21979-8-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_mode.c | 256 +++++++++++++++++++-------------- 1 file changed, 146 insertions(+), 110 deletions(-) (limited to 'drivers/gpu/drm/mgag200/mgag200_mode.c') diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 6e730435357d..45ba4fb83601 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -349,7 +349,7 @@ static int mgag200_compute_pixpll_values_g200wb(struct mga_device *mdev, long cl { unsigned int vcomax, vcomin, pllreffreq; unsigned int delta, tmpdelta; - unsigned int testp, testm, testn, testp2; + unsigned int testp, testm, testn; unsigned int p, m, n, s; unsigned int computed; @@ -357,64 +357,29 @@ static int mgag200_compute_pixpll_values_g200wb(struct mga_device *mdev, long cl delta = 0xffffffff; - if (mdev->type == G200_EW3) { - vcomax = 800000; - vcomin = 400000; - pllreffreq = 25000; - - for (testp = 1; testp < 8; testp++) { - for (testp2 = 1; testp2 < 8; testp2++) { - if (testp < testp2) - continue; - if ((clock * testp * testp2) > vcomax) - continue; - if ((clock * testp * testp2) < vcomin) - continue; - for (testm = 1; testm < 26; testm++) { - for (testn = 32; testn < 2048 ; testn++) { - computed = (pllreffreq * testn) / - (testm * testp * testp2); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - m = testm + 1; - n = testn + 1; - p = testp + 1; - s = testp2; - } - } - } - } - } - } else { - vcomax = 550000; - vcomin = 150000; - pllreffreq = 48000; + vcomax = 550000; + vcomin = 150000; + pllreffreq = 48000; - for (testp = 1; testp < 9; testp++) { - if (clock * testp > vcomax) - continue; - if (clock * testp < vcomin) - continue; + for (testp = 1; testp < 9; testp++) { + if (clock * testp > vcomax) + continue; + if (clock * testp < vcomin) + continue; - for (testm = 1; testm < 17; testm++) { - for (testn = 1; testn < 151; testn++) { - computed = (pllreffreq * testn) / - (testm * testp); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - n = testn; - m = testm; - p = testp; - s = 0; - } + for (testm = 1; testm < 17; testm++) { + for (testn = 1; testn < 151; testn++) { + computed = (pllreffreq * testn) / (testm * testp); + if (computed > clock) + tmpdelta = computed - clock; + else + tmpdelta = clock - computed; + if (tmpdelta < delta) { + delta = tmpdelta; + n = testn; + m = testm; + p = testp; + s = 0; } } } @@ -671,66 +636,30 @@ static int mgag200_compute_pixpll_values_g200eh(struct mga_device *mdev, long cl m = n = p = s = 0; - if (mdev->type == G200_EH3) { - vcomax = 3000000; - vcomin = 1500000; - pllreffreq = 25000; + vcomax = 800000; + vcomin = 400000; + pllreffreq = 33333; - delta = 0xffffffff; + delta = 0xffffffff; - testp = 0; + for (testp = 16; testp > 0; testp >>= 1) { + if (clock * testp > vcomax) + continue; + if (clock * testp < vcomin) + continue; - for (testm = 150; testm >= 6; testm--) { - if (clock * testm > vcomax) - continue; - if (clock * testm < vcomin) - continue; - for (testn = 120; testn >= 60; testn--) { - computed = (pllreffreq * testn) / testm; + for (testm = 1; testm < 33; testm++) { + for (testn = 17; testn < 257; testn++) { + computed = (pllreffreq * testn) / (testm * testp); if (computed > clock) tmpdelta = computed - clock; else tmpdelta = clock - computed; if (tmpdelta < delta) { delta = tmpdelta; - n = testn + 1; - m = testm + 1; - p = testp + 1; - } - if (delta == 0) - break; - } - if (delta == 0) - break; - } - } else { - - vcomax = 800000; - vcomin = 400000; - pllreffreq = 33333; - - delta = 0xffffffff; - - for (testp = 16; testp > 0; testp >>= 1) { - if (clock * testp > vcomax) - continue; - if (clock * testp < vcomin) - continue; - - for (testm = 1; testm < 33; testm++) { - for (testn = 17; testn < 257; testn++) { - computed = (pllreffreq * testn) / - (testm * testp); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - n = testn; - m = testm; - p = testp; - } + n = testn; + m = testm; + p = testp; } } } @@ -812,6 +741,57 @@ static void mgag200_set_pixpll_g200eh(struct mga_device *mdev, } } +static int mgag200_compute_pixpll_values_g200eh3(struct mga_device *mdev, long clock, + struct mgag200_pll_values *pixpllc) +{ + unsigned int vcomax, vcomin, pllreffreq; + unsigned int delta, tmpdelta; + unsigned int testp, testm, testn; + unsigned int p, m, n, s; + unsigned int computed; + + m = n = p = s = 0; + + vcomax = 3000000; + vcomin = 1500000; + pllreffreq = 25000; + + delta = 0xffffffff; + + testp = 0; + + for (testm = 150; testm >= 6; testm--) { + if (clock * testm > vcomax) + continue; + if (clock * testm < vcomin) + continue; + for (testn = 120; testn >= 60; testn--) { + computed = (pllreffreq * testn) / testm; + if (computed > clock) + tmpdelta = computed - clock; + else + tmpdelta = clock - computed; + if (tmpdelta < delta) { + delta = tmpdelta; + n = testn + 1; + m = testm + 1; + p = testp + 1; + } + if (delta == 0) + break; + } + if (delta == 0) + break; + } + + pixpllc->m = m; + pixpllc->n = n; + pixpllc->p = p; + pixpllc->s = s; + + return 0; +} + static int mgag200_compute_pixpll_values_g200er(struct mga_device *mdev, long clock, struct mgag200_pll_values *pixpllc) { @@ -916,6 +896,58 @@ static void mgag200_set_pixpll_g200er(struct mga_device *mdev, udelay(50); } +static int mgag200_compute_pixpll_values_g200ew3(struct mga_device *mdev, long clock, + struct mgag200_pll_values *pixpllc) +{ + unsigned int vcomax, vcomin, pllreffreq; + unsigned int delta, tmpdelta; + unsigned int testp, testm, testn, testp2; + unsigned int p, m, n, s; + unsigned int computed; + + m = n = p = s = 0; + + delta = 0xffffffff; + + vcomax = 800000; + vcomin = 400000; + pllreffreq = 25000; + + for (testp = 1; testp < 8; testp++) { + for (testp2 = 1; testp2 < 8; testp2++) { + if (testp < testp2) + continue; + if ((clock * testp * testp2) > vcomax) + continue; + if ((clock * testp * testp2) < vcomin) + continue; + for (testm = 1; testm < 26; testm++) { + for (testn = 32; testn < 2048 ; testn++) { + computed = (pllreffreq * testn) / (testm * testp * testp2); + if (computed > clock) + tmpdelta = computed - clock; + else + tmpdelta = clock - computed; + if (tmpdelta < delta) { + delta = tmpdelta; + m = testm + 1; + n = testn + 1; + p = testp + 1; + s = testp2; + } + } + } + } + } + + pixpllc->m = m; + pixpllc->n = n; + pixpllc->p = p; + pixpllc->s = s; + + return 0; +} + static void mgag200_crtc_set_plls(struct mga_device *mdev, long clock) { struct mgag200_pll_values pixpll; @@ -931,19 +963,23 @@ static void mgag200_crtc_set_plls(struct mga_device *mdev, long clock) ret = mgag200_compute_pixpll_values_g200se(mdev, clock, &pixpll); break; case G200_WB: - case G200_EW3: ret = mgag200_compute_pixpll_values_g200wb(mdev, clock, &pixpll); break; case G200_EV: ret = mgag200_compute_pixpll_values_g200ev(mdev, clock, &pixpll); break; case G200_EH: - case G200_EH3: ret = mgag200_compute_pixpll_values_g200eh(mdev, clock, &pixpll); break; + case G200_EH3: + ret = mgag200_compute_pixpll_values_g200eh3(mdev, clock, &pixpll); + break; case G200_ER: ret = mgag200_compute_pixpll_values_g200er(mdev, clock, &pixpll); break; + case G200_EW3: + ret = mgag200_compute_pixpll_values_g200ew3(mdev, clock, &pixpll); + break; } if (ret) -- cgit From ac643ccd3023e967cad895f7eb7ff4a02135020a Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 14 Jul 2021 16:22:35 +0200 Subject: drm/mgag200: Split PLL compute function for G200SE by rev The compute function for G200SE pixel PLLs handles two revisions with different algorithms. Split it accordingly to make it readable. No functional changes. Signed-off-by: Thomas Zimmermann Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210714142240.21979-9-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_mode.c | 166 +++++++++++++++++++-------------- 1 file changed, 96 insertions(+), 70 deletions(-) (limited to 'drivers/gpu/drm/mgag200/mgag200_mode.c') diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 45ba4fb83601..3ef8b9f7e455 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -206,102 +206,117 @@ static void mgag200_set_pixpll_g200(struct mga_device *mdev, WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp); } -static int mgag200_compute_pixpll_values_g200se(struct mga_device *mdev, long clock, - struct mgag200_pll_values *pixpllc) +static int mgag200_compute_pixpll_values_g200se_00(struct mga_device *mdev, long clock, + struct mgag200_pll_values *pixpllc) { - static const unsigned int pvalues_e4[] = {16, 14, 12, 10, 8, 6, 4, 2, 1}; - - u32 unique_rev_id = mdev->model.g200se.unique_rev_id; unsigned int vcomax, vcomin, pllreffreq; unsigned int delta, tmpdelta, permitteddelta; unsigned int testp, testm, testn; unsigned int p, m, n, s; unsigned int computed; - unsigned int fvv; - unsigned int i; m = n = p = s = 0; - if (unique_rev_id <= 0x03) { - vcomax = 320000; - vcomin = 160000; - pllreffreq = 25000; - delta = 0xffffffff; - permitteddelta = clock * 5 / 1000; + vcomax = 320000; + vcomin = 160000; + pllreffreq = 25000; + permitteddelta = clock * 5 / 1000; - for (testp = 8; testp > 0; testp /= 2) { - if (clock * testp > vcomax) - continue; - if (clock * testp < vcomin) - continue; + for (testp = 8; testp > 0; testp /= 2) { + if (clock * testp > vcomax) + continue; + if (clock * testp < vcomin) + continue; - for (testn = 17; testn < 256; testn++) { - for (testm = 1; testm < 32; testm++) { - computed = (pllreffreq * testn) / - (testm * testp); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - m = testm; - n = testn; - p = testp; - } + for (testn = 17; testn < 256; testn++) { + for (testm = 1; testm < 32; testm++) { + computed = (pllreffreq * testn) / (testm * testp); + if (computed > clock) + tmpdelta = computed - clock; + else + tmpdelta = clock - computed; + if (tmpdelta < delta) { + delta = tmpdelta; + m = testm; + n = testn; + p = testp; } } } - } else { - vcomax = 1600000; - vcomin = 800000; - pllreffreq = 25000; + } - if (clock < 25000) - clock = 25000; + if (delta > permitteddelta) { + pr_warn("PLL delta too large\n"); + return -EINVAL; + } - clock = clock * 2; + pixpllc->m = m; + pixpllc->n = n; + pixpllc->p = p; + pixpllc->s = s; - delta = 0xFFFFFFFF; - /* Permited delta is 0.5% as VESA Specification */ - permitteddelta = clock * 5 / 1000; + return 0; +} - for (i = 0 ; i < ARRAY_SIZE(pvalues_e4); i++) { - testp = pvalues_e4[i]; +static int mgag200_compute_pixpll_values_g200se_04(struct mga_device *mdev, long clock, + struct mgag200_pll_values *pixpllc) +{ + static const unsigned int pvalues_e4[] = {16, 14, 12, 10, 8, 6, 4, 2, 1}; - if ((clock * testp) > vcomax) - continue; - if ((clock * testp) < vcomin) - continue; + unsigned int vcomax, vcomin, pllreffreq; + unsigned int delta, tmpdelta, permitteddelta; + unsigned int testp, testm, testn; + unsigned int p, m, n, s; + unsigned int computed; + unsigned int fvv; + unsigned int i; - for (testn = 50; testn <= 256; testn++) { - for (testm = 1; testm <= 32; testm++) { - computed = (pllreffreq * testn) / - (testm * testp); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; + m = n = p = s = 0; + delta = 0xffffffff; - if (tmpdelta < delta) { - delta = tmpdelta; - m = testm; - n = testn; - p = testp; - } + vcomax = 1600000; + vcomin = 800000; + pllreffreq = 25000; + + if (clock < 25000) + clock = 25000; + clock = clock * 2; + + /* Permited delta is 0.5% as VESA Specification */ + permitteddelta = clock * 5 / 1000; + + for (i = 0 ; i < ARRAY_SIZE(pvalues_e4); i++) { + testp = pvalues_e4[i]; + + if ((clock * testp) > vcomax) + continue; + if ((clock * testp) < vcomin) + continue; + + for (testn = 50; testn <= 256; testn++) { + for (testm = 1; testm <= 32; testm++) { + computed = (pllreffreq * testn) / (testm * testp); + if (computed > clock) + tmpdelta = computed - clock; + else + tmpdelta = clock - computed; + + if (tmpdelta < delta) { + delta = tmpdelta; + m = testm; + n = testn; + p = testp; } } } - - fvv = pllreffreq * n / m; - fvv = (fvv - 800000) / 50000; - if (fvv > 15) - fvv = 15; - s = fvv << 1; - - clock = clock / 2; } + fvv = pllreffreq * n / m; + fvv = (fvv - 800000) / 50000; + if (fvv > 15) + fvv = 15; + s = fvv << 1; + if (delta > permitteddelta) { pr_warn("PLL delta too large\n"); return -EINVAL; @@ -315,6 +330,17 @@ static int mgag200_compute_pixpll_values_g200se(struct mga_device *mdev, long cl return 0; } +static int mgag200_compute_pixpll_values_g200se(struct mga_device *mdev, long clock, + struct mgag200_pll_values *pixpllc) +{ + u32 unique_rev_id = mdev->model.g200se.unique_rev_id; + + if (unique_rev_id >= 0x04) + return mgag200_compute_pixpll_values_g200se_04(mdev, clock, pixpllc); + else + return mgag200_compute_pixpll_values_g200se_00(mdev, clock, pixpllc); +} + static void mgag200_set_pixpll_g200se(struct mga_device *mdev, const struct mgag200_pll_values *pixpllc) { -- cgit From 8fb60d1bcd90d995af7e7a497795b8d77ad44721 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 14 Jul 2021 16:22:36 +0200 Subject: drm/mgag200: Declare PLL clock constants static const Move the PLL constants to the RO data section by declaring them as static const. No functional changes. Signed-off-by: Thomas Zimmermann Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210714142240.21979-10-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_mode.c | 75 ++++++++++++++-------------------- 1 file changed, 31 insertions(+), 44 deletions(-) (limited to 'drivers/gpu/drm/mgag200/mgag200_mode.c') diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 3ef8b9f7e455..8c11a4c41ed5 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -209,17 +209,16 @@ static void mgag200_set_pixpll_g200(struct mga_device *mdev, static int mgag200_compute_pixpll_values_g200se_00(struct mga_device *mdev, long clock, struct mgag200_pll_values *pixpllc) { - unsigned int vcomax, vcomin, pllreffreq; + static const unsigned int vcomax = 320000; + static const unsigned int vcomin = 160000; + static const unsigned int pllreffreq = 25000; + unsigned int delta, tmpdelta, permitteddelta; unsigned int testp, testm, testn; unsigned int p, m, n, s; unsigned int computed; m = n = p = s = 0; - - vcomax = 320000; - vcomin = 160000; - pllreffreq = 25000; permitteddelta = clock * 5 / 1000; for (testp = 8; testp > 0; testp /= 2) { @@ -261,9 +260,11 @@ static int mgag200_compute_pixpll_values_g200se_00(struct mga_device *mdev, long static int mgag200_compute_pixpll_values_g200se_04(struct mga_device *mdev, long clock, struct mgag200_pll_values *pixpllc) { + static const unsigned int vcomax = 1600000; + static const unsigned int vcomin = 800000; + static const unsigned int pllreffreq = 25000; static const unsigned int pvalues_e4[] = {16, 14, 12, 10, 8, 6, 4, 2, 1}; - unsigned int vcomax, vcomin, pllreffreq; unsigned int delta, tmpdelta, permitteddelta; unsigned int testp, testm, testn; unsigned int p, m, n, s; @@ -274,10 +275,6 @@ static int mgag200_compute_pixpll_values_g200se_04(struct mga_device *mdev, long m = n = p = s = 0; delta = 0xffffffff; - vcomax = 1600000; - vcomin = 800000; - pllreffreq = 25000; - if (clock < 25000) clock = 25000; clock = clock * 2; @@ -373,7 +370,10 @@ static void mgag200_set_pixpll_g200se(struct mga_device *mdev, static int mgag200_compute_pixpll_values_g200wb(struct mga_device *mdev, long clock, struct mgag200_pll_values *pixpllc) { - unsigned int vcomax, vcomin, pllreffreq; + static const unsigned int vcomax = 550000; + static const unsigned int vcomin = 150000; + static const unsigned int pllreffreq = 48000; + unsigned int delta, tmpdelta; unsigned int testp, testm, testn; unsigned int p, m, n, s; @@ -383,10 +383,6 @@ static int mgag200_compute_pixpll_values_g200wb(struct mga_device *mdev, long cl delta = 0xffffffff; - vcomax = 550000; - vcomin = 150000; - pllreffreq = 48000; - for (testp = 1; testp < 9; testp++) { if (clock * testp > vcomax) continue; @@ -538,17 +534,16 @@ static void mgag200_set_pixpll_g200wb(struct mga_device *mdev, static int mgag200_compute_pixpll_values_g200ev(struct mga_device *mdev, long clock, struct mgag200_pll_values *pixpllc) { - unsigned int vcomax, vcomin, pllreffreq; + static const unsigned int vcomax = 550000; + static const unsigned int vcomin = 150000; + static const unsigned int pllreffreq = 50000; + unsigned int delta, tmpdelta; unsigned int testp, testm, testn; unsigned int p, m, n, s; unsigned int computed; m = n = p = s = 0; - vcomax = 550000; - vcomin = 150000; - pllreffreq = 50000; - delta = 0xffffffff; for (testp = 16; testp > 0; testp--) { @@ -654,18 +649,16 @@ static void mgag200_set_pixpll_g200ev(struct mga_device *mdev, static int mgag200_compute_pixpll_values_g200eh(struct mga_device *mdev, long clock, struct mgag200_pll_values *pixpllc) { - unsigned int vcomax, vcomin, pllreffreq; + static const unsigned int vcomax = 800000; + static const unsigned int vcomin = 400000; + static const unsigned int pllreffreq = 33333; + unsigned int delta, tmpdelta; unsigned int testp, testm, testn; unsigned int p, m, n, s; unsigned int computed; m = n = p = s = 0; - - vcomax = 800000; - vcomin = 400000; - pllreffreq = 33333; - delta = 0xffffffff; for (testp = 16; testp > 0; testp >>= 1) { @@ -770,20 +763,17 @@ static void mgag200_set_pixpll_g200eh(struct mga_device *mdev, static int mgag200_compute_pixpll_values_g200eh3(struct mga_device *mdev, long clock, struct mgag200_pll_values *pixpllc) { - unsigned int vcomax, vcomin, pllreffreq; + static const unsigned int vcomax = 3000000; + static const unsigned int vcomin = 1500000; + static const unsigned int pllreffreq = 25000; + unsigned int delta, tmpdelta; unsigned int testp, testm, testn; unsigned int p, m, n, s; unsigned int computed; m = n = p = s = 0; - - vcomax = 3000000; - vcomin = 1500000; - pllreffreq = 25000; - delta = 0xffffffff; - testp = 0; for (testm = 150; testm >= 6; testm--) { @@ -821,18 +811,17 @@ static int mgag200_compute_pixpll_values_g200eh3(struct mga_device *mdev, long c static int mgag200_compute_pixpll_values_g200er(struct mga_device *mdev, long clock, struct mgag200_pll_values *pixpllc) { + static const unsigned int vcomax = 1488000; + static const unsigned int vcomin = 1056000; + static const unsigned int pllreffreq = 48000; static const unsigned int m_div_val[] = { 1, 2, 4, 8 }; - unsigned int vcomax, vcomin, pllreffreq; + unsigned int delta, tmpdelta; int testr, testn, testm, testo; unsigned int p, m, n, s; unsigned int computed, vco; m = n = p = s = 0; - vcomax = 1488000; - vcomin = 1056000; - pllreffreq = 48000; - delta = 0xffffffff; for (testr = 0; testr < 4; testr++) { @@ -925,20 +914,18 @@ static void mgag200_set_pixpll_g200er(struct mga_device *mdev, static int mgag200_compute_pixpll_values_g200ew3(struct mga_device *mdev, long clock, struct mgag200_pll_values *pixpllc) { - unsigned int vcomax, vcomin, pllreffreq; + static const unsigned int vcomax = 800000; + static const unsigned int vcomin = 400000; + static const unsigned int pllreffreq = 25000; + unsigned int delta, tmpdelta; unsigned int testp, testm, testn, testp2; unsigned int p, m, n, s; unsigned int computed; m = n = p = s = 0; - delta = 0xffffffff; - vcomax = 800000; - vcomin = 400000; - pllreffreq = 25000; - for (testp = 1; testp < 8; testp++) { for (testp2 = 1; testp2 < 8; testp2++) { if (testp < testp2) -- cgit From 2545ac960364d0395802a27374b46f13827b4cf5 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 14 Jul 2021 16:22:37 +0200 Subject: drm/mgag200: Abstract pixel PLL via struct mgag200_pll Move all PLL compute and update functions into mgag200_pll.c. No functional changes to the rsp algorithms. Introduce struct mgag200_pll and mgag200_pll_funcs. The data strutures abstract the details of each revision's PLL. Perform calls to compute and update functionality via function pointers. Init the PLL once as part of the driver initialization. Signed-off-by: Thomas Zimmermann Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210714142240.21979-11-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_mode.c | 909 +-------------------------------- 1 file changed, 8 insertions(+), 901 deletions(-) (limited to 'drivers/gpu/drm/mgag200/mgag200_mode.c') diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 8c11a4c41ed5..ea068addbc74 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -114,914 +114,17 @@ static inline void mga_wait_busy(struct mga_device *mdev) * PLL setup */ -static int mgag200_compute_pixpll_values_g200(struct mga_device *mdev, long clock, - struct mgag200_pll_values *pixpllc) -{ - struct drm_device *dev = &mdev->base; - const int post_div_max = 7; - const int in_div_min = 1; - const int in_div_max = 6; - const int feed_div_min = 7; - const int feed_div_max = 127; - u8 testp, testm, testn; - u8 n = 0, m = 0, p, s; - long f_vco; - long computed; - long delta, tmp_delta; - long ref_clk = mdev->model.g200.ref_clk; - long p_clk_min = mdev->model.g200.pclk_min; - long p_clk_max = mdev->model.g200.pclk_max; - - if (clock > p_clk_max) { - drm_err(dev, "Pixel Clock %ld too high\n", clock); - return -EINVAL; - } - - if (clock < p_clk_min >> 3) - clock = p_clk_min >> 3; - - f_vco = clock; - for (testp = 0; - testp <= post_div_max && f_vco < p_clk_min; - testp = (testp << 1) + 1, f_vco <<= 1) - ; - p = testp + 1; - - delta = clock; - - for (testm = in_div_min; testm <= in_div_max; testm++) { - for (testn = feed_div_min; testn <= feed_div_max; testn++) { - computed = ref_clk * (testn + 1) / (testm + 1); - if (computed < f_vco) - tmp_delta = f_vco - computed; - else - tmp_delta = computed - f_vco; - if (tmp_delta < delta) { - delta = tmp_delta; - m = testm + 1; - n = testn + 1; - } - } - } - f_vco = ref_clk * n / m; - if (f_vco < 100000) - s = 0; - else if (f_vco < 140000) - s = 1; - else if (f_vco < 180000) - s = 2; - else - s = 3; - - drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n", - clock, f_vco, m, n, p, s); - - pixpllc->m = m; - pixpllc->n = n; - pixpllc->p = p; - pixpllc->s = s; - - return 0; -} - -static void mgag200_set_pixpll_g200(struct mga_device *mdev, - const struct mgag200_pll_values *pixpllc) -{ - unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; - u8 xpixpllcm, xpixpllcn, xpixpllcp; - - pixpllcm = pixpllc->m - 1; - pixpllcn = pixpllc->n - 1; - pixpllcp = pixpllc->p - 1; - pixpllcs = pixpllc->s; - - xpixpllcm = pixpllcm; - xpixpllcn = pixpllcn; - xpixpllcp = (pixpllcs << 3) | pixpllcp; - - WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); - - WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm); - WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn); - WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp); -} - -static int mgag200_compute_pixpll_values_g200se_00(struct mga_device *mdev, long clock, - struct mgag200_pll_values *pixpllc) -{ - static const unsigned int vcomax = 320000; - static const unsigned int vcomin = 160000; - static const unsigned int pllreffreq = 25000; - - unsigned int delta, tmpdelta, permitteddelta; - unsigned int testp, testm, testn; - unsigned int p, m, n, s; - unsigned int computed; - - m = n = p = s = 0; - permitteddelta = clock * 5 / 1000; - - for (testp = 8; testp > 0; testp /= 2) { - if (clock * testp > vcomax) - continue; - if (clock * testp < vcomin) - continue; - - for (testn = 17; testn < 256; testn++) { - for (testm = 1; testm < 32; testm++) { - computed = (pllreffreq * testn) / (testm * testp); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - m = testm; - n = testn; - p = testp; - } - } - } - } - - if (delta > permitteddelta) { - pr_warn("PLL delta too large\n"); - return -EINVAL; - } - - pixpllc->m = m; - pixpllc->n = n; - pixpllc->p = p; - pixpllc->s = s; - - return 0; -} - -static int mgag200_compute_pixpll_values_g200se_04(struct mga_device *mdev, long clock, - struct mgag200_pll_values *pixpllc) -{ - static const unsigned int vcomax = 1600000; - static const unsigned int vcomin = 800000; - static const unsigned int pllreffreq = 25000; - static const unsigned int pvalues_e4[] = {16, 14, 12, 10, 8, 6, 4, 2, 1}; - - unsigned int delta, tmpdelta, permitteddelta; - unsigned int testp, testm, testn; - unsigned int p, m, n, s; - unsigned int computed; - unsigned int fvv; - unsigned int i; - - m = n = p = s = 0; - delta = 0xffffffff; - - if (clock < 25000) - clock = 25000; - clock = clock * 2; - - /* Permited delta is 0.5% as VESA Specification */ - permitteddelta = clock * 5 / 1000; - - for (i = 0 ; i < ARRAY_SIZE(pvalues_e4); i++) { - testp = pvalues_e4[i]; - - if ((clock * testp) > vcomax) - continue; - if ((clock * testp) < vcomin) - continue; - - for (testn = 50; testn <= 256; testn++) { - for (testm = 1; testm <= 32; testm++) { - computed = (pllreffreq * testn) / (testm * testp); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - - if (tmpdelta < delta) { - delta = tmpdelta; - m = testm; - n = testn; - p = testp; - } - } - } - } - - fvv = pllreffreq * n / m; - fvv = (fvv - 800000) / 50000; - if (fvv > 15) - fvv = 15; - s = fvv << 1; - - if (delta > permitteddelta) { - pr_warn("PLL delta too large\n"); - return -EINVAL; - } - - pixpllc->m = m; - pixpllc->n = n; - pixpllc->p = p; - pixpllc->s = s; - - return 0; -} - -static int mgag200_compute_pixpll_values_g200se(struct mga_device *mdev, long clock, - struct mgag200_pll_values *pixpllc) -{ - u32 unique_rev_id = mdev->model.g200se.unique_rev_id; - - if (unique_rev_id >= 0x04) - return mgag200_compute_pixpll_values_g200se_04(mdev, clock, pixpllc); - else - return mgag200_compute_pixpll_values_g200se_00(mdev, clock, pixpllc); -} - -static void mgag200_set_pixpll_g200se(struct mga_device *mdev, - const struct mgag200_pll_values *pixpllc) -{ - u32 unique_rev_id = mdev->model.g200se.unique_rev_id; - unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; - u8 xpixpllcm, xpixpllcn, xpixpllcp; - - pixpllcm = pixpllc->m - 1; - pixpllcn = pixpllc->n - 1; - pixpllcp = pixpllc->p - 1; - pixpllcs = pixpllc->s; - - xpixpllcm = pixpllcm | ((pixpllcn & BIT(8)) >> 1); - xpixpllcn = pixpllcn; - xpixpllcp = (pixpllcs << 3) | pixpllcp; - - WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); - - WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm); - WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn); - WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp); - - if (unique_rev_id >= 0x04) { - WREG_DAC(0x1a, 0x09); - msleep(20); - WREG_DAC(0x1a, 0x01); - } -} - -static int mgag200_compute_pixpll_values_g200wb(struct mga_device *mdev, long clock, - struct mgag200_pll_values *pixpllc) -{ - static const unsigned int vcomax = 550000; - static const unsigned int vcomin = 150000; - static const unsigned int pllreffreq = 48000; - - unsigned int delta, tmpdelta; - unsigned int testp, testm, testn; - unsigned int p, m, n, s; - unsigned int computed; - - m = n = p = s = 0; - - delta = 0xffffffff; - - for (testp = 1; testp < 9; testp++) { - if (clock * testp > vcomax) - continue; - if (clock * testp < vcomin) - continue; - - for (testm = 1; testm < 17; testm++) { - for (testn = 1; testn < 151; testn++) { - computed = (pllreffreq * testn) / (testm * testp); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - n = testn; - m = testm; - p = testp; - s = 0; - } - } - } - } - - pixpllc->m = m; - pixpllc->n = n; - pixpllc->p = p; - pixpllc->s = s; - - return 0; -} - -static void mgag200_set_pixpll_g200wb(struct mga_device *mdev, - const struct mgag200_pll_values *pixpllc) -{ - unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; - u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; - int i, j, tmpcount, vcount; - bool pll_locked = false; - - pixpllcm = pixpllc->m - 1; - pixpllcn = pixpllc->n - 1; - pixpllcp = pixpllc->p - 1; - pixpllcs = pixpllc->s; - - xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm; - xpixpllcn = pixpllcn; - xpixpllcp = ((pixpllcn & GENMASK(10, 9)) >> 3) | (pixpllcs << 3) | pixpllcp; - - WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); - - for (i = 0; i <= 32 && pll_locked == false; i++) { - if (i > 0) { - WREG8(MGAREG_CRTC_INDEX, 0x1e); - tmp = RREG8(MGAREG_CRTC_DATA); - if (tmp < 0xff) - WREG8(MGAREG_CRTC_DATA, tmp+1); - } - - /* set pixclkdis to 1 */ - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; - WREG8(DAC_DATA, tmp); - - WREG8(DAC_INDEX, MGA1064_REMHEADCTL); - tmp = RREG8(DAC_DATA); - tmp |= MGA1064_REMHEADCTL_CLKDIS; - WREG8(DAC_DATA, tmp); - - /* select PLL Set C */ - tmp = RREG8(MGAREG_MEM_MISC_READ); - tmp |= 0x3 << 2; - WREG8(MGAREG_MEM_MISC_WRITE, tmp); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80; - WREG8(DAC_DATA, tmp); - - udelay(500); - - /* reset the PLL */ - WREG8(DAC_INDEX, MGA1064_VREF_CTL); - tmp = RREG8(DAC_DATA); - tmp &= ~0x04; - WREG8(DAC_DATA, tmp); - - udelay(50); - - /* program pixel pll register */ - WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn); - WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm); - WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp); - - udelay(50); - - /* turn pll on */ - WREG8(DAC_INDEX, MGA1064_VREF_CTL); - tmp = RREG8(DAC_DATA); - tmp |= 0x04; - WREG_DAC(MGA1064_VREF_CTL, tmp); - - udelay(500); - - /* select the pixel pll */ - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; - tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; - WREG8(DAC_DATA, tmp); - - WREG8(DAC_INDEX, MGA1064_REMHEADCTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_REMHEADCTL_CLKSL_MSK; - tmp |= MGA1064_REMHEADCTL_CLKSL_PLL; - WREG8(DAC_DATA, tmp); - - /* reset dotclock rate bit */ - WREG8(MGAREG_SEQ_INDEX, 1); - tmp = RREG8(MGAREG_SEQ_DATA); - tmp &= ~0x8; - WREG8(MGAREG_SEQ_DATA, tmp); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; - WREG8(DAC_DATA, tmp); - - vcount = RREG8(MGAREG_VCOUNT); - - for (j = 0; j < 30 && pll_locked == false; j++) { - tmpcount = RREG8(MGAREG_VCOUNT); - if (tmpcount < vcount) - vcount = 0; - if ((tmpcount - vcount) > 2) - pll_locked = true; - else - udelay(5); - } - } - - WREG8(DAC_INDEX, MGA1064_REMHEADCTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_REMHEADCTL_CLKDIS; - WREG_DAC(MGA1064_REMHEADCTL, tmp); -} - -static int mgag200_compute_pixpll_values_g200ev(struct mga_device *mdev, long clock, - struct mgag200_pll_values *pixpllc) -{ - static const unsigned int vcomax = 550000; - static const unsigned int vcomin = 150000; - static const unsigned int pllreffreq = 50000; - - unsigned int delta, tmpdelta; - unsigned int testp, testm, testn; - unsigned int p, m, n, s; - unsigned int computed; - - m = n = p = s = 0; - delta = 0xffffffff; - - for (testp = 16; testp > 0; testp--) { - if (clock * testp > vcomax) - continue; - if (clock * testp < vcomin) - continue; - - for (testn = 1; testn < 257; testn++) { - for (testm = 1; testm < 17; testm++) { - computed = (pllreffreq * testn) / - (testm * testp); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - n = testn; - m = testm; - p = testp; - } - } - } - } - - pixpllc->m = m; - pixpllc->n = n; - pixpllc->p = p; - pixpllc->s = s; - - return 0; -} - -static void mgag200_set_pixpll_g200ev(struct mga_device *mdev, - const struct mgag200_pll_values *pixpllc) -{ - unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; - u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; - - pixpllcm = pixpllc->m - 1; - pixpllcn = pixpllc->n - 1; - pixpllcp = pixpllc->p - 1; - pixpllcs = pixpllc->s; - - xpixpllcm = pixpllcm; - xpixpllcn = pixpllcn; - xpixpllcp = (pixpllcs << 3) | pixpllcp; - - WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; - WREG8(DAC_DATA, tmp); - - tmp = RREG8(MGAREG_MEM_MISC_READ); - tmp |= 0x3 << 2; - WREG8(MGAREG_MEM_MISC_WRITE, tmp); - - WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT); - tmp = RREG8(DAC_DATA); - WREG8(DAC_DATA, tmp & ~0x40); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; - WREG8(DAC_DATA, tmp); - - WREG_DAC(MGA1064_EV_PIX_PLLC_M, xpixpllcm); - WREG_DAC(MGA1064_EV_PIX_PLLC_N, xpixpllcn); - WREG_DAC(MGA1064_EV_PIX_PLLC_P, xpixpllcp); - - udelay(50); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; - WREG8(DAC_DATA, tmp); - - udelay(500); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; - tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; - WREG8(DAC_DATA, tmp); - - WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT); - tmp = RREG8(DAC_DATA); - WREG8(DAC_DATA, tmp | 0x40); - - tmp = RREG8(MGAREG_MEM_MISC_READ); - tmp |= (0x3 << 2); - WREG8(MGAREG_MEM_MISC_WRITE, tmp); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; - WREG8(DAC_DATA, tmp); -} - -static int mgag200_compute_pixpll_values_g200eh(struct mga_device *mdev, long clock, - struct mgag200_pll_values *pixpllc) -{ - static const unsigned int vcomax = 800000; - static const unsigned int vcomin = 400000; - static const unsigned int pllreffreq = 33333; - - unsigned int delta, tmpdelta; - unsigned int testp, testm, testn; - unsigned int p, m, n, s; - unsigned int computed; - - m = n = p = s = 0; - delta = 0xffffffff; - - for (testp = 16; testp > 0; testp >>= 1) { - if (clock * testp > vcomax) - continue; - if (clock * testp < vcomin) - continue; - - for (testm = 1; testm < 33; testm++) { - for (testn = 17; testn < 257; testn++) { - computed = (pllreffreq * testn) / (testm * testp); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - n = testn; - m = testm; - p = testp; - } - } - } - } - - pixpllc->m = m; - pixpllc->n = n; - pixpllc->p = p; - pixpllc->s = s; - - return 0; -} - -static void mgag200_set_pixpll_g200eh(struct mga_device *mdev, - const struct mgag200_pll_values *pixpllc) -{ - unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; - u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; - int i, j, tmpcount, vcount; - bool pll_locked = false; - - pixpllcm = pixpllc->m - 1; - pixpllcn = pixpllc->n - 1; - pixpllcp = pixpllc->p - 1; - pixpllcs = pixpllc->s; - - xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm; - xpixpllcn = pixpllcn; - xpixpllcp = (pixpllcs << 3) | pixpllcp; - - WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); - - for (i = 0; i <= 32 && pll_locked == false; i++) { - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; - WREG8(DAC_DATA, tmp); - - tmp = RREG8(MGAREG_MEM_MISC_READ); - tmp |= 0x3 << 2; - WREG8(MGAREG_MEM_MISC_WRITE, tmp); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; - WREG8(DAC_DATA, tmp); - - udelay(500); - - WREG_DAC(MGA1064_EH_PIX_PLLC_M, xpixpllcm); - WREG_DAC(MGA1064_EH_PIX_PLLC_N, xpixpllcn); - WREG_DAC(MGA1064_EH_PIX_PLLC_P, xpixpllcp); - - udelay(500); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; - tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; - WREG8(DAC_DATA, tmp); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; - tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; - WREG8(DAC_DATA, tmp); - - vcount = RREG8(MGAREG_VCOUNT); - - for (j = 0; j < 30 && pll_locked == false; j++) { - tmpcount = RREG8(MGAREG_VCOUNT); - if (tmpcount < vcount) - vcount = 0; - if ((tmpcount - vcount) > 2) - pll_locked = true; - else - udelay(5); - } - } -} - -static int mgag200_compute_pixpll_values_g200eh3(struct mga_device *mdev, long clock, - struct mgag200_pll_values *pixpllc) -{ - static const unsigned int vcomax = 3000000; - static const unsigned int vcomin = 1500000; - static const unsigned int pllreffreq = 25000; - - unsigned int delta, tmpdelta; - unsigned int testp, testm, testn; - unsigned int p, m, n, s; - unsigned int computed; - - m = n = p = s = 0; - delta = 0xffffffff; - testp = 0; - - for (testm = 150; testm >= 6; testm--) { - if (clock * testm > vcomax) - continue; - if (clock * testm < vcomin) - continue; - for (testn = 120; testn >= 60; testn--) { - computed = (pllreffreq * testn) / testm; - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - n = testn + 1; - m = testm + 1; - p = testp + 1; - } - if (delta == 0) - break; - } - if (delta == 0) - break; - } - - pixpllc->m = m; - pixpllc->n = n; - pixpllc->p = p; - pixpllc->s = s; - - return 0; -} - -static int mgag200_compute_pixpll_values_g200er(struct mga_device *mdev, long clock, - struct mgag200_pll_values *pixpllc) -{ - static const unsigned int vcomax = 1488000; - static const unsigned int vcomin = 1056000; - static const unsigned int pllreffreq = 48000; - static const unsigned int m_div_val[] = { 1, 2, 4, 8 }; - - unsigned int delta, tmpdelta; - int testr, testn, testm, testo; - unsigned int p, m, n, s; - unsigned int computed, vco; - - m = n = p = s = 0; - delta = 0xffffffff; - - for (testr = 0; testr < 4; testr++) { - if (delta == 0) - break; - for (testn = 5; testn < 129; testn++) { - if (delta == 0) - break; - for (testm = 3; testm >= 0; testm--) { - if (delta == 0) - break; - for (testo = 5; testo < 33; testo++) { - vco = pllreffreq * (testn + 1) / - (testr + 1); - if (vco < vcomin) - continue; - if (vco > vcomax) - continue; - computed = vco / (m_div_val[testm] * (testo + 1)); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - m = (testm | (testo << 3)) + 1; - n = testn + 1; - p = testr + 1; - s = testr; - } - } - } - } - } - - pixpllc->m = m; - pixpllc->n = n; - pixpllc->p = p; - pixpllc->s = s; - - return 0; -} - -static void mgag200_set_pixpll_g200er(struct mga_device *mdev, - const struct mgag200_pll_values *pixpllc) -{ - unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; - u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; - - pixpllcm = pixpllc->m - 1; - pixpllcn = pixpllc->n - 1; - pixpllcp = pixpllc->p - 1; - pixpllcs = pixpllc->s; - - xpixpllcm = pixpllcm; - xpixpllcn = pixpllcn; - xpixpllcp = (pixpllcs << 3) | pixpllcp; - - WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; - WREG8(DAC_DATA, tmp); - - WREG8(DAC_INDEX, MGA1064_REMHEADCTL); - tmp = RREG8(DAC_DATA); - tmp |= MGA1064_REMHEADCTL_CLKDIS; - WREG8(DAC_DATA, tmp); - - tmp = RREG8(MGAREG_MEM_MISC_READ); - tmp |= (0x3<<2) | 0xc0; - WREG8(MGAREG_MEM_MISC_WRITE, tmp); - - WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); - tmp = RREG8(DAC_DATA); - tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; - tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; - WREG8(DAC_DATA, tmp); - - udelay(500); - - WREG_DAC(MGA1064_ER_PIX_PLLC_N, xpixpllcn); - WREG_DAC(MGA1064_ER_PIX_PLLC_M, xpixpllcm); - WREG_DAC(MGA1064_ER_PIX_PLLC_P, xpixpllcp); - - udelay(50); -} - -static int mgag200_compute_pixpll_values_g200ew3(struct mga_device *mdev, long clock, - struct mgag200_pll_values *pixpllc) -{ - static const unsigned int vcomax = 800000; - static const unsigned int vcomin = 400000; - static const unsigned int pllreffreq = 25000; - - unsigned int delta, tmpdelta; - unsigned int testp, testm, testn, testp2; - unsigned int p, m, n, s; - unsigned int computed; - - m = n = p = s = 0; - delta = 0xffffffff; - - for (testp = 1; testp < 8; testp++) { - for (testp2 = 1; testp2 < 8; testp2++) { - if (testp < testp2) - continue; - if ((clock * testp * testp2) > vcomax) - continue; - if ((clock * testp * testp2) < vcomin) - continue; - for (testm = 1; testm < 26; testm++) { - for (testn = 32; testn < 2048 ; testn++) { - computed = (pllreffreq * testn) / (testm * testp * testp2); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - m = testm + 1; - n = testn + 1; - p = testp + 1; - s = testp2; - } - } - } - } - } - - pixpllc->m = m; - pixpllc->n = n; - pixpllc->p = p; - pixpllc->s = s; - - return 0; -} - static void mgag200_crtc_set_plls(struct mga_device *mdev, long clock) { - struct mgag200_pll_values pixpll; + struct mgag200_pll *pixpll = &mdev->pixpll; + struct mgag200_pll_values pixpllc; int ret; - switch(mdev->type) { - case G200_PCI: - case G200_AGP: - ret = mgag200_compute_pixpll_values_g200(mdev, clock, &pixpll); - break; - case G200_SE_A: - case G200_SE_B: - ret = mgag200_compute_pixpll_values_g200se(mdev, clock, &pixpll); - break; - case G200_WB: - ret = mgag200_compute_pixpll_values_g200wb(mdev, clock, &pixpll); - break; - case G200_EV: - ret = mgag200_compute_pixpll_values_g200ev(mdev, clock, &pixpll); - break; - case G200_EH: - ret = mgag200_compute_pixpll_values_g200eh(mdev, clock, &pixpll); - break; - case G200_EH3: - ret = mgag200_compute_pixpll_values_g200eh3(mdev, clock, &pixpll); - break; - case G200_ER: - ret = mgag200_compute_pixpll_values_g200er(mdev, clock, &pixpll); - break; - case G200_EW3: - ret = mgag200_compute_pixpll_values_g200ew3(mdev, clock, &pixpll); - break; - } - + ret = pixpll->funcs->compute(pixpll, clock, &pixpllc); if (ret) return; - switch (mdev->type) { - case G200_PCI: - case G200_AGP: - mgag200_set_pixpll_g200(mdev, &pixpll); - break; - case G200_SE_A: - case G200_SE_B: - mgag200_set_pixpll_g200se(mdev, &pixpll); - break; - case G200_WB: - case G200_EW3: - mgag200_set_pixpll_g200wb(mdev, &pixpll); - break; - case G200_EV: - mgag200_set_pixpll_g200ev(mdev, &pixpll); - break; - case G200_EH: - case G200_EH3: - mgag200_set_pixpll_g200eh(mdev, &pixpll); - break; - case G200_ER: - mgag200_set_pixpll_g200er(mdev, &pixpll); - break; - } + pixpll->funcs->update(pixpll, &pixpllc); } static void mgag200_g200wb_hold_bmc(struct mga_device *mdev) @@ -1934,6 +1037,10 @@ int mgag200_modeset_init(struct mga_device *mdev) return ret; } + ret = mgag200_pixpll_init(&mdev->pixpll, mdev); + if (ret) + return ret; + ret = drm_simple_display_pipe_init(dev, pipe, &mgag200_simple_display_pipe_funcs, mgag200_simple_display_pipe_formats, -- cgit From 51b569394b47018132edde01b50e77a4e5f3919d Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 14 Jul 2021 16:22:39 +0200 Subject: drm/mgag200: Introduce custom CRTC state Inherit from struct drm_crtc_state by embeding it and providing the rsp callbacks for simple-kms helpers. No functional changes. The new state struct mgag200_crtc_state will hold PLL values for modeset operations. v2: * move the simple-kms changes into a separate patch (Sam) Signed-off-by: Thomas Zimmermann Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210714142240.21979-13-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_mode.c | 46 ++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'drivers/gpu/drm/mgag200/mgag200_mode.c') diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index ea068addbc74..6e8b0db1ffa0 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -964,6 +964,49 @@ mgag200_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, mgag200_handle_damage(mdev, fb, &damage, &shadow_plane_state->map[0]); } +static struct drm_crtc_state * +mgag200_simple_display_pipe_duplicate_crtc_state(struct drm_simple_display_pipe *pipe) +{ + struct drm_crtc *crtc = &pipe->crtc; + struct drm_crtc_state *crtc_state = crtc->state; + struct mgag200_crtc_state *new_mgag200_crtc_state; + + if (!crtc_state) + return NULL; + + new_mgag200_crtc_state = kzalloc(sizeof(*new_mgag200_crtc_state), GFP_KERNEL); + if (!new_mgag200_crtc_state) + return NULL; + __drm_atomic_helper_crtc_duplicate_state(crtc, &new_mgag200_crtc_state->base); + + return &new_mgag200_crtc_state->base; +} + +static void mgag200_simple_display_pipe_destroy_crtc_state(struct drm_simple_display_pipe *pipe, + struct drm_crtc_state *crtc_state) +{ + struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); + + __drm_atomic_helper_crtc_destroy_state(&mgag200_crtc_state->base); + kfree(mgag200_crtc_state); +} + +static void mgag200_simple_display_pipe_reset_crtc(struct drm_simple_display_pipe *pipe) +{ + struct drm_crtc *crtc = &pipe->crtc; + struct mgag200_crtc_state *mgag200_crtc_state; + + if (crtc->state) { + mgag200_simple_display_pipe_destroy_crtc_state(pipe, crtc->state); + crtc->state = NULL; /* must be set to NULL here */ + } + + mgag200_crtc_state = kzalloc(sizeof(*mgag200_crtc_state), GFP_KERNEL); + if (!mgag200_crtc_state) + return; + __drm_atomic_helper_crtc_reset(crtc, &mgag200_crtc_state->base); +} + static const struct drm_simple_display_pipe_funcs mgag200_simple_display_pipe_funcs = { .mode_valid = mgag200_simple_display_pipe_mode_valid, @@ -971,6 +1014,9 @@ mgag200_simple_display_pipe_funcs = { .disable = mgag200_simple_display_pipe_disable, .check = mgag200_simple_display_pipe_check, .update = mgag200_simple_display_pipe_update, + .reset_crtc = mgag200_simple_display_pipe_reset_crtc, + .duplicate_crtc_state = mgag200_simple_display_pipe_duplicate_crtc_state, + .destroy_crtc_state = mgag200_simple_display_pipe_destroy_crtc_state, DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, }; -- cgit From 0a6dab7d07d25c6d1e6dff0c31bac11ef1803f8a Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Wed, 14 Jul 2021 16:22:40 +0200 Subject: drm/mgag200: Compute PLL values during atomic check PLL setup can fail if the display mode's clock is not supported by any PLL configuration. Compute the PLL values during atomic check, so that atomic commits can fail at the appropriate time. If successful, use the values in the atomic-update phase. Signed-off-by: Thomas Zimmermann Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210714142240.21979-14-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_mode.c | 38 ++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'drivers/gpu/drm/mgag200/mgag200_mode.c') diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 6e8b0db1ffa0..6cb24a4b76b8 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -110,23 +110,6 @@ static inline void mga_wait_busy(struct mga_device *mdev) } while ((status & 0x01) && time_before(jiffies, timeout)); } -/* - * PLL setup - */ - -static void mgag200_crtc_set_plls(struct mga_device *mdev, long clock) -{ - struct mgag200_pll *pixpll = &mdev->pixpll; - struct mgag200_pll_values pixpllc; - int ret; - - ret = pixpll->funcs->compute(pixpll, clock, &pixpllc); - if (ret) - return; - - pixpll->funcs->update(pixpll, &pixpllc); -} - static void mgag200_g200wb_hold_bmc(struct mga_device *mdev) { u8 tmp; @@ -881,7 +864,9 @@ mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, struct drm_crtc *crtc = &pipe->crtc; struct drm_device *dev = crtc->dev; struct mga_device *mdev = to_mga_device(dev); + struct mgag200_pll *pixpll = &mdev->pixpll; struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; + struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); struct drm_framebuffer *fb = plane_state->fb; struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); struct drm_rect fullscreen = { @@ -896,7 +881,8 @@ mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, mgag200_set_format_regs(mdev, fb); mgag200_set_mode_regs(mdev, adjusted_mode); - mgag200_crtc_set_plls(mdev, adjusted_mode->clock); + + pixpll->funcs->update(pixpll, &mgag200_crtc_state->pixpllc); if (mdev->type == G200_ER) mgag200_g200er_reset_tagfifo(mdev); @@ -930,8 +916,13 @@ mgag200_simple_display_pipe_check(struct drm_simple_display_pipe *pipe, struct drm_crtc_state *crtc_state) { struct drm_plane *plane = plane_state->plane; + struct drm_device *dev = plane->dev; + struct mga_device *mdev = to_mga_device(dev); + struct mgag200_pll *pixpll = &mdev->pixpll; + struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); struct drm_framebuffer *new_fb = plane_state->fb; struct drm_framebuffer *fb = NULL; + int ret; if (!new_fb) return 0; @@ -942,6 +933,13 @@ mgag200_simple_display_pipe_check(struct drm_simple_display_pipe *pipe, if (!fb || (fb->format != new_fb->format)) crtc_state->mode_changed = true; /* update PLL settings */ + if (crtc_state->mode_changed) { + ret = pixpll->funcs->compute(pixpll, crtc_state->mode.clock, + &mgag200_crtc_state->pixpllc); + if (ret) + return ret; + } + return 0; } @@ -969,6 +967,7 @@ mgag200_simple_display_pipe_duplicate_crtc_state(struct drm_simple_display_pipe { struct drm_crtc *crtc = &pipe->crtc; struct drm_crtc_state *crtc_state = crtc->state; + struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state); struct mgag200_crtc_state *new_mgag200_crtc_state; if (!crtc_state) @@ -979,6 +978,9 @@ mgag200_simple_display_pipe_duplicate_crtc_state(struct drm_simple_display_pipe return NULL; __drm_atomic_helper_crtc_duplicate_state(crtc, &new_mgag200_crtc_state->base); + memcpy(&new_mgag200_crtc_state->pixpllc, &mgag200_crtc_state->pixpllc, + sizeof(new_mgag200_crtc_state->pixpllc)); + return &new_mgag200_crtc_state->base; } -- cgit From af022daf08a41a68e787cca2f66bce39945e7558 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 3 Aug 2021 14:59:22 +0200 Subject: drm/mgag200: Use offset-adjusted shadow-plane mappings For framebuffers with non-zero offset fields, shadow-plane helpers provide a pointer to the first byte of the contained data. Use it in mgag200. Signed-off-by: Thomas Zimmermann Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20210803125928.27780-6-tzimmermann@suse.de --- drivers/gpu/drm/mgag200/mgag200_mode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/mgag200/mgag200_mode.c') diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 6cb24a4b76b8..fd98e8bbc550 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -898,7 +898,7 @@ mgag200_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, mga_crtc_load_lut(crtc); mgag200_enable_display(mdev); - mgag200_handle_damage(mdev, fb, &fullscreen, &shadow_plane_state->map[0]); + mgag200_handle_damage(mdev, fb, &fullscreen, &shadow_plane_state->data[0]); } static void @@ -959,7 +959,7 @@ mgag200_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, return; if (drm_atomic_helper_damage_merged(old_state, state, &damage)) - mgag200_handle_damage(mdev, fb, &damage, &shadow_plane_state->map[0]); + mgag200_handle_damage(mdev, fb, &damage, &shadow_plane_state->data[0]); } static struct drm_crtc_state * -- cgit