[PATCH 04/12] drm/mgag200: Split PLL setup into compute and update functions
Sam Ravnborg
sam at ravnborg.org
Fri Jul 9 19:12:35 UTC 2021
Ho Thomas,
On Mon, Jul 05, 2021 at 02:45:07PM +0200, Thomas Zimmermann wrote:
> 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 a update functions, and
> call them one after the other. Computed PLL values are store in
> struct mgag200_pll_values. No functional changes.
>
> Signed-off-by: Thomas Zimmermann <tzimmermann at suse.de>
> ---
> drivers/gpu/drm/mgag200/mgag200_drv.h | 17 ++
> drivers/gpu/drm/mgag200/mgag200_mode.c | 234 +++++++++++++++++++------
> 2 files changed, 196 insertions(+), 55 deletions(-)
>
> diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h
> index f7a0537c0d0a..fca3904fde0c 100644
> --- a/drivers/gpu/drm/mgag200/mgag200_drv.h
> +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
> @@ -110,6 +110,23 @@
> #define MGAG200_MAX_FB_HEIGHT 4096
> #define MGAG200_MAX_FB_WIDTH 4096
>
> +/*
> + * Stores parameters for programming the PLLs
> + *
> + * Fref: reference frequency (A: 25.175 Mhz, B: 28.361, C: XX Mhz)
> + * Fo: output frequency
> + * Fvco = Fref * (N / M)
> + * Fo = Fvco / P
> + *
> + * S = [0..3]
> + */
> +struct mgag200_pll_values {
> + unsigned int m;
Why not u8?
> + unsigned int n;
Why not u8?
> + unsigned int p;
Why not u8?
> + unsigned int s;
> +};
> +
> #define to_mga_connector(x) container_of(x, struct mga_connector, base)
>
> struct mga_i2c_chan {
> diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
> index fa06f1994d68..961bd128fea3 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;
> @@ -130,7 +131,6 @@ static int mgag200_g200_set_plls(struct mga_device *mdev, long clock)
> 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;
> - u8 misc;
>
> if (clock > p_clk_max) {
> drm_err(dev, "Pixel Clock %ld too high\n", clock);
> @@ -175,19 +175,34 @@ 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);
>
> + 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)
> +{
> + u8 misc, xpixpllcm, xpixpllcn, xpixpllcp;
Strange names, but whatever.
> +
> misc = RREG8(MGA_MISC_IN);
> misc &= ~MGAREG_MISC_CLK_SEL_MASK;
> misc |= MGAREG_MISC_CLK_SEL_MGA_MSK;
> WREG8(MGA_MISC_OUT, misc);
>
> - WREG_DAC(MGA1064_PIX_PLLC_M, m);
> - WREG_DAC(MGA1064_PIX_PLLC_N, n);
> - WREG_DAC(MGA1064_PIX_PLLC_P, (p | (s << 3)));
> -
> - return 0;
> + xpixpllcm = pixpllc->m;
> + xpixpllcn = pixpllc->n;
> + xpixpllcp = pixpllc->p | (pixpllc->s << 3);
> + WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
> + WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
> + WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
I cannot see why this code does not look like this:
WREG_DAC(MGA1064_PIX_PLLC_M, pixpllc->m);
WREG_DAC(MGA1064_PIX_PLLC_N, pixpllc->n);
WREG_DAC(MGA1064_PIX_PLLC_P, pixpllc->p | (pixpllc->s << 3));
Same goes for all the functions in the following.
> }
>
> -static int mga_g200se_set_plls(struct mga_device *mdev, long clock)
> +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};
>
> @@ -199,7 +214,6 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock)
> unsigned int computed;
> unsigned int fvv;
> unsigned int i;
> - u8 misc;
>
> if (unique_rev_id <= 0x03) {
>
> @@ -295,35 +309,47 @@ 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 misc, xpixpllcm, xpixpllcn, xpixpllcp;
> +
> misc = RREG8(MGA_MISC_IN);
> misc &= ~MGAREG_MISC_CLK_SEL_MASK;
> misc |= MGAREG_MISC_CLK_SEL_MGA_MSK;
> WREG8(MGA_MISC_OUT, misc);
>
> - WREG_DAC(MGA1064_PIX_PLLC_M, m);
> - WREG_DAC(MGA1064_PIX_PLLC_N, n);
> - WREG_DAC(MGA1064_PIX_PLLC_P, p);
> + xpixpllcm = pixpllc->m;
> + xpixpllcn = pixpllc->n;
> + xpixpllcp = pixpllc->p | (pixpllc->s << 3);
The "(pixpllc->s << 3)" look like a copy error. No harm as s is 0 but
confusing.
> + 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, misc;
>
> m = n = p = 0;
>
> @@ -396,11 +422,30 @@ 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 misc, xpixpllcm, xpixpllcn, xpixpllcp, tmp;
> + int i, j, tmpcount, vcount;
> + bool pll_locked = false;
> +
> misc = RREG8(MGA_MISC_IN);
> misc &= ~MGAREG_MISC_CLK_SEL_MASK;
> misc |= MGAREG_MISC_CLK_SEL_MGA_MSK;
> WREG8(MGA_MISC_OUT, misc);
>
> + xpixpllcm = pixpllc->m;
> + xpixpllcn = pixpllc->n;
> + xpixpllcp = pixpllc->p | (pixpllc->s << 3);
The (pixpllc->s << 3) looks wrong here too.
> +
> for (i = 0; i <= 32 && pll_locked == false; i++) {
> if (i > 0) {
> WREG8(MGAREG_CRTC_INDEX, 0x1e);
> @@ -441,9 +486,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);
>
> @@ -491,21 +536,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, misc;
>
> m = n = p = 0;
> vcomax = 550000;
> @@ -538,11 +583,28 @@ 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 misc, xpixpllcm, xpixpllcn, xpixpllcp, tmp;
> +
> misc = RREG8(MGA_MISC_IN);
> misc &= ~MGAREG_MISC_CLK_SEL_MASK;
> misc |= MGAREG_MISC_CLK_SEL_MGA_MSK;
> WREG8(MGA_MISC_OUT, misc);
>
> + xpixpllcm = pixpllc->m;
> + xpixpllcn = pixpllc->n;
> + xpixpllcp = pixpllc->p | (pixpllc->s << 3);
> +
> WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
> tmp = RREG8(DAC_DATA);
> tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
> @@ -561,9 +623,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);
>
> @@ -592,20 +654,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, misc;
> - bool pll_locked = false;
>
> m = n = p = 0;
>
> @@ -676,11 +734,30 @@ 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 misc, xpixpllcm, xpixpllcn, xpixpllcp, tmp;
> + int i, j, tmpcount, vcount;
> + bool pll_locked = false;
> +
> misc = RREG8(MGA_MISC_IN);
> misc &= ~MGAREG_MISC_CLK_SEL_MASK;
> misc |= MGAREG_MISC_CLK_SEL_MGA_MSK;
> WREG8(MGA_MISC_OUT, misc);
>
> + xpixpllcm = pixpllc->m;
> + xpixpllcn = pixpllc->n;
> + xpixpllcp = pixpllc->p | (pixpllc->s << 3);
Again (pixpllc->s << 3)
> +
> for (i = 0; i <= 32 && pll_locked == false; i++) {
> WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
> tmp = RREG8(DAC_DATA);
> @@ -698,9 +775,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);
>
> @@ -728,11 +805,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;
> @@ -740,8 +816,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;
> - u8 misc;
>
> m = n = p = 0;
> vcomax = 1488000;
> @@ -782,11 +856,28 @@ 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 misc, xpixpllcm, xpixpllcn, xpixpllcp, tmp;
> +
> misc = RREG8(MGA_MISC_IN);
> misc &= ~MGAREG_MISC_CLK_SEL_MASK;
> misc |= MGAREG_MISC_CLK_SEL_MGA_MSK;
> WREG8(MGA_MISC_OUT, misc);
>
> + xpixpllcm = pixpllc->m;
> + xpixpllcn = pixpllc->n;
> + xpixpllcp = pixpllc->p | (pixpllc->s << 3);
Again (pixpllc->s << 3)
> +
> WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
> tmp = RREG8(DAC_DATA);
> tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
> @@ -809,37 +900,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)
> {
Makes sense, you can forget my earlier comment about return 0 in this
function.
> + 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)
> --
> 2.32.0
More information about the dri-devel
mailing list