Skip to content

Commit 877507b

Browse files
committed
drm/mgag200: Provide per-device callbacks for PIXPLLC
Move the PIXPLLC code into per-model source files and wire it up with per-model callbacks. No functional changes. The PIXPLLC pixel-clock is part of the CRTC, but really separate hardware that varies with each model of the G200. Move the PIXPLLC code for each model into the per-model source file and call it from CRTC helpers via device functions. This allows to remove struct mgag200_pll and the related code. The new callbacks behave like the CRTC's atomic_check and atomic_enable functions. v3: * clean up style Signed-off-by: Thomas Zimmermann <[email protected]> Reviewed-by: Jocelyn Falempe <[email protected]> Tested-by: Jocelyn Falempe <[email protected]> Acked-by: Sam Ravnborg <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 8aeeb31 commit 877507b

12 files changed

Lines changed: 1026 additions & 1029 deletions

drivers/gpu/drm/mgag200/Makefile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ mgag200-y := \
1111
mgag200_g200se.o \
1212
mgag200_g200wb.o \
1313
mgag200_i2c.o \
14-
mgag200_mode.o \
15-
mgag200_pll.o
14+
mgag200_mode.o
1615

1716
obj-$(CONFIG_DRM_MGAG200) += mgag200.o

drivers/gpu/drm/mgag200/mgag200_drv.h

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,6 @@
156156
#define MGAG200_MAX_FB_WIDTH 4096
157157

158158
struct mga_device;
159-
struct mgag200_pll;
160159

161160
/*
162161
* Stores parameters for programming the PLLs
@@ -175,17 +174,6 @@ struct mgag200_pll_values {
175174
unsigned int s;
176175
};
177176

178-
struct mgag200_pll_funcs {
179-
int (*compute)(struct mgag200_pll *pll, long clock, struct mgag200_pll_values *pllc);
180-
void (*update)(struct mgag200_pll *pll, const struct mgag200_pll_values *pllc);
181-
};
182-
183-
struct mgag200_pll {
184-
struct mga_device *mdev;
185-
186-
const struct mgag200_pll_funcs *funcs;
187-
};
188-
189177
struct mgag200_crtc_state {
190178
struct drm_crtc_state base;
191179

@@ -274,6 +262,20 @@ struct mgag200_device_funcs {
274262
* a new display mode.
275263
*/
276264
void (*enable_vidrst)(struct mga_device *mdev);
265+
266+
/*
267+
* Validate that the given state can be programmed into PIXPLLC. On
268+
* success, the calculated parameters should be stored in the CRTC's
269+
* state in struct @mgag200_crtc_state.pixpllc.
270+
*/
271+
int (*pixpllc_atomic_check)(struct drm_crtc *crtc, struct drm_atomic_state *new_state);
272+
273+
/*
274+
* Program PIXPLLC from the CRTC state. The parameters should have been
275+
* stored in struct @mgag200_crtc_state.pixpllc by the corresponding
276+
* implementation of @pixpllc_atomic_check.
277+
*/
278+
void (*pixpllc_atomic_update)(struct drm_crtc *crtc, struct drm_atomic_state *old_state);
277279
};
278280

279281
struct mga_device {
@@ -292,7 +294,6 @@ struct mga_device {
292294

293295
enum mga_type type;
294296

295-
struct mgag200_pll pixpll;
296297
struct drm_plane primary_plane;
297298
struct drm_crtc crtc;
298299
struct drm_encoder encoder;
@@ -346,11 +347,13 @@ struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct
346347
struct mga_device *mgag200_g200se_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
347348
enum mga_type type);
348349
void mgag200_g200wb_init_registers(struct mga_device *mdev);
350+
void mgag200_g200wb_pixpllc_atomic_update(struct drm_crtc *crtc, struct drm_atomic_state *old_state);
349351
struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
350352
enum mga_type type);
351353
struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
352354
enum mga_type type);
353355
void mgag200_g200eh_init_registers(struct mga_device *mdev);
356+
void mgag200_g200eh_pixpllc_atomic_update(struct drm_crtc *crtc, struct drm_atomic_state *old_state);
354357
struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
355358
enum mga_type type);
356359
struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
@@ -372,7 +375,4 @@ void mgag200_bmc_enable_vidrst(struct mga_device *mdev);
372375
/* mgag200_i2c.c */
373376
int mgag200_i2c_init(struct mga_device *mdev, struct mga_i2c_chan *i2c);
374377

375-
/* mgag200_pll.c */
376-
int mgag200_pixpll_init(struct mgag200_pll *pixpll, struct mga_device *mdev);
377-
378378
#endif /* __MGAG200_DRV_H__ */

drivers/gpu/drm/mgag200/mgag200_g200.c

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <linux/pci.h>
44
#include <linux/vmalloc.h>
55

6+
#include <drm/drm_atomic.h>
67
#include <drm/drm_drv.h>
78

89
#include "mgag200_drv.h"
@@ -53,6 +54,112 @@ static void mgag200_g200_init_registers(struct mgag200_g200_device *g200)
5354
mgag200_init_registers(mdev);
5455
}
5556

57+
/*
58+
* PIXPLLC
59+
*/
60+
61+
static int mgag200_g200_pixpllc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state)
62+
{
63+
static const int post_div_max = 7;
64+
static const int in_div_min = 1;
65+
static const int in_div_max = 6;
66+
static const int feed_div_min = 7;
67+
static const int feed_div_max = 127;
68+
69+
struct drm_device *dev = crtc->dev;
70+
struct mgag200_g200_device *g200 = to_mgag200_g200_device(dev);
71+
struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
72+
struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
73+
long clock = new_crtc_state->mode.clock;
74+
struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
75+
u8 testp, testm, testn;
76+
u8 n = 0, m = 0, p, s;
77+
long f_vco;
78+
long computed;
79+
long delta, tmp_delta;
80+
long ref_clk = g200->ref_clk;
81+
long p_clk_min = g200->pclk_min;
82+
long p_clk_max = g200->pclk_max;
83+
84+
if (clock > p_clk_max) {
85+
drm_err(dev, "Pixel Clock %ld too high\n", clock);
86+
return -EINVAL;
87+
}
88+
89+
if (clock < p_clk_min >> 3)
90+
clock = p_clk_min >> 3;
91+
92+
f_vco = clock;
93+
for (testp = 0;
94+
testp <= post_div_max && f_vco < p_clk_min;
95+
testp = (testp << 1) + 1, f_vco <<= 1)
96+
;
97+
p = testp + 1;
98+
99+
delta = clock;
100+
101+
for (testm = in_div_min; testm <= in_div_max; testm++) {
102+
for (testn = feed_div_min; testn <= feed_div_max; testn++) {
103+
computed = ref_clk * (testn + 1) / (testm + 1);
104+
if (computed < f_vco)
105+
tmp_delta = f_vco - computed;
106+
else
107+
tmp_delta = computed - f_vco;
108+
if (tmp_delta < delta) {
109+
delta = tmp_delta;
110+
m = testm + 1;
111+
n = testn + 1;
112+
}
113+
}
114+
}
115+
f_vco = ref_clk * n / m;
116+
if (f_vco < 100000)
117+
s = 0;
118+
else if (f_vco < 140000)
119+
s = 1;
120+
else if (f_vco < 180000)
121+
s = 2;
122+
else
123+
s = 3;
124+
125+
drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n",
126+
clock, f_vco, m, n, p, s);
127+
128+
pixpllc->m = m;
129+
pixpllc->n = n;
130+
pixpllc->p = p;
131+
pixpllc->s = s;
132+
133+
return 0;
134+
}
135+
136+
static void mgag200_g200_pixpllc_atomic_update(struct drm_crtc *crtc,
137+
struct drm_atomic_state *old_state)
138+
{
139+
struct drm_device *dev = crtc->dev;
140+
struct mga_device *mdev = to_mga_device(dev);
141+
struct drm_crtc_state *crtc_state = crtc->state;
142+
struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
143+
struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
144+
unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
145+
u8 xpixpllcm, xpixpllcn, xpixpllcp;
146+
147+
pixpllcm = pixpllc->m - 1;
148+
pixpllcn = pixpllc->n - 1;
149+
pixpllcp = pixpllc->p - 1;
150+
pixpllcs = pixpllc->s;
151+
152+
xpixpllcm = pixpllcm;
153+
xpixpllcn = pixpllcn;
154+
xpixpllcp = (pixpllcs << 3) | pixpllcp;
155+
156+
WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
157+
158+
WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
159+
WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
160+
WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
161+
}
162+
56163
/*
57164
* DRM Device
58165
*/
@@ -184,6 +291,8 @@ static void mgag200_g200_init_refclk(struct mgag200_g200_device *g200)
184291
}
185292

186293
static const struct mgag200_device_funcs mgag200_g200_device_funcs = {
294+
.pixpllc_atomic_check = mgag200_g200_pixpllc_atomic_check,
295+
.pixpllc_atomic_update = mgag200_g200_pixpllc_atomic_update,
187296
};
188297

189298
struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct drm_driver *drv,

drivers/gpu/drm/mgag200/mgag200_g200eh.c

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
// SPDX-License-Identifier: GPL-2.0-only
22

3+
#include <linux/delay.h>
34
#include <linux/pci.h>
45

6+
#include <drm/drm_atomic.h>
57
#include <drm/drm_drv.h>
68

79
#include "mgag200_drv.h"
@@ -30,6 +32,133 @@ void mgag200_g200eh_init_registers(struct mga_device *mdev)
3032
mgag200_init_registers(mdev);
3133
}
3234

35+
/*
36+
* PIXPLLC
37+
*/
38+
39+
static int mgag200_g200eh_pixpllc_atomic_check(struct drm_crtc *crtc,
40+
struct drm_atomic_state *new_state)
41+
{
42+
static const unsigned int vcomax = 800000;
43+
static const unsigned int vcomin = 400000;
44+
static const unsigned int pllreffreq = 33333;
45+
46+
struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
47+
struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
48+
long clock = new_crtc_state->mode.clock;
49+
struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
50+
unsigned int delta, tmpdelta;
51+
unsigned int testp, testm, testn;
52+
unsigned int p, m, n, s;
53+
unsigned int computed;
54+
55+
m = n = p = s = 0;
56+
delta = 0xffffffff;
57+
58+
for (testp = 16; testp > 0; testp >>= 1) {
59+
if (clock * testp > vcomax)
60+
continue;
61+
if (clock * testp < vcomin)
62+
continue;
63+
64+
for (testm = 1; testm < 33; testm++) {
65+
for (testn = 17; testn < 257; testn++) {
66+
computed = (pllreffreq * testn) / (testm * testp);
67+
if (computed > clock)
68+
tmpdelta = computed - clock;
69+
else
70+
tmpdelta = clock - computed;
71+
if (tmpdelta < delta) {
72+
delta = tmpdelta;
73+
n = testn;
74+
m = testm;
75+
p = testp;
76+
}
77+
}
78+
}
79+
}
80+
81+
pixpllc->m = m;
82+
pixpllc->n = n;
83+
pixpllc->p = p;
84+
pixpllc->s = s;
85+
86+
return 0;
87+
}
88+
89+
void mgag200_g200eh_pixpllc_atomic_update(struct drm_crtc *crtc,
90+
struct drm_atomic_state *old_state)
91+
{
92+
struct drm_device *dev = crtc->dev;
93+
struct mga_device *mdev = to_mga_device(dev);
94+
struct drm_crtc_state *crtc_state = crtc->state;
95+
struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
96+
struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
97+
unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
98+
u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
99+
int i, j, tmpcount, vcount;
100+
bool pll_locked = false;
101+
102+
pixpllcm = pixpllc->m - 1;
103+
pixpllcn = pixpllc->n - 1;
104+
pixpllcp = pixpllc->p - 1;
105+
pixpllcs = pixpllc->s;
106+
107+
xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm;
108+
xpixpllcn = pixpllcn;
109+
xpixpllcp = (pixpllcs << 3) | pixpllcp;
110+
111+
WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
112+
113+
for (i = 0; i <= 32 && pll_locked == false; i++) {
114+
WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
115+
tmp = RREG8(DAC_DATA);
116+
tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
117+
WREG8(DAC_DATA, tmp);
118+
119+
tmp = RREG8(MGAREG_MEM_MISC_READ);
120+
tmp |= 0x3 << 2;
121+
WREG8(MGAREG_MEM_MISC_WRITE, tmp);
122+
123+
WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
124+
tmp = RREG8(DAC_DATA);
125+
tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
126+
WREG8(DAC_DATA, tmp);
127+
128+
udelay(500);
129+
130+
WREG_DAC(MGA1064_EH_PIX_PLLC_M, xpixpllcm);
131+
WREG_DAC(MGA1064_EH_PIX_PLLC_N, xpixpllcn);
132+
WREG_DAC(MGA1064_EH_PIX_PLLC_P, xpixpllcp);
133+
134+
udelay(500);
135+
136+
WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
137+
tmp = RREG8(DAC_DATA);
138+
tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
139+
tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
140+
WREG8(DAC_DATA, tmp);
141+
142+
WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
143+
tmp = RREG8(DAC_DATA);
144+
tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
145+
tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
146+
WREG8(DAC_DATA, tmp);
147+
148+
vcount = RREG8(MGAREG_VCOUNT);
149+
150+
for (j = 0; j < 30 && pll_locked == false; j++) {
151+
tmpcount = RREG8(MGAREG_VCOUNT);
152+
if (tmpcount < vcount)
153+
vcount = 0;
154+
if ((tmpcount - vcount) > 2)
155+
pll_locked = true;
156+
else
157+
udelay(5);
158+
}
159+
}
160+
}
161+
33162
/*
34163
* DRM device
35164
*/
@@ -38,6 +167,8 @@ static const struct mgag200_device_info mgag200_g200eh_device_info =
38167
MGAG200_DEVICE_INFO_INIT(2048, 2048, 37500, false, 1, 0, false);
39168

40169
static const struct mgag200_device_funcs mgag200_g200eh_device_funcs = {
170+
.pixpllc_atomic_check = mgag200_g200eh_pixpllc_atomic_check,
171+
.pixpllc_atomic_update = mgag200_g200eh_pixpllc_atomic_update,
41172
};
42173

43174
struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv,

0 commit comments

Comments
 (0)