xref: /linux/drivers/gpu/drm/mgag200/mgag200_g200wb.c (revision f858cc9eed5b05cbe38d7ffd2787c21e3718eb7d)
1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 #include <linux/delay.h>
4 #include <linux/pci.h>
5 
6 #include <drm/drm_atomic.h>
7 #include <drm/drm_atomic_helper.h>
8 #include <drm/drm_drv.h>
9 #include <drm/drm_gem_atomic_helper.h>
10 #include <drm/drm_probe_helper.h>
11 #include <drm/drm_vblank.h>
12 
13 #include "mgag200_drv.h"
14 
15 void mgag200_g200wb_init_registers(struct mga_device *mdev)
16 {
17 	static const u8 dacvalue[] = {
18 		MGAG200_DAC_DEFAULT(0x07, 0xc9, 0x1f, 0x00, 0x00, 0x00)
19 	};
20 
21 	size_t i;
22 
23 	for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {
24 		if ((i <= 0x17) ||
25 		    (i == 0x1b) ||
26 		    (i == 0x1c) ||
27 		    ((i >= 0x1f) && (i <= 0x29)) ||
28 		    ((i >= 0x30) && (i <= 0x37)) ||
29 		    ((i >= 0x44) && (i <= 0x4e)))
30 			continue;
31 		WREG_DAC(i, dacvalue[i]);
32 	}
33 
34 	mgag200_init_registers(mdev);
35 }
36 
37 /*
38  * PIXPLLC
39  */
40 
41 static int mgag200_g200wb_pixpllc_atomic_check(struct drm_crtc *crtc,
42 					       struct drm_atomic_state *new_state)
43 {
44 	static const unsigned int vcomax = 550000;
45 	static const unsigned int vcomin = 150000;
46 	static const unsigned int pllreffreq = 48000;
47 
48 	struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
49 	struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
50 	long clock = new_crtc_state->mode.clock;
51 	struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
52 	unsigned int delta, tmpdelta;
53 	unsigned int testp, testm, testn;
54 	unsigned int p, m, n, s;
55 	unsigned int computed;
56 
57 	m = n = p = s = 0;
58 	delta = 0xffffffff;
59 
60 	for (testp = 1; testp < 9; testp++) {
61 		if (clock * testp > vcomax)
62 			continue;
63 		if (clock * testp < vcomin)
64 			continue;
65 
66 		for (testm = 1; testm < 17; testm++) {
67 			for (testn = 1; testn < 151; testn++) {
68 				computed = (pllreffreq * testn) / (testm * testp);
69 				if (computed > clock)
70 					tmpdelta = computed - clock;
71 				else
72 					tmpdelta = clock - computed;
73 				if (tmpdelta < delta) {
74 					delta = tmpdelta;
75 					n = testn;
76 					m = testm;
77 					p = testp;
78 					s = 0;
79 				}
80 			}
81 		}
82 	}
83 
84 	pixpllc->m = m;
85 	pixpllc->n = n;
86 	pixpllc->p = p;
87 	pixpllc->s = s;
88 
89 	return 0;
90 }
91 
92 void mgag200_g200wb_pixpllc_atomic_update(struct drm_crtc *crtc,
93 					  struct drm_atomic_state *old_state)
94 {
95 	struct drm_device *dev = crtc->dev;
96 	struct mga_device *mdev = to_mga_device(dev);
97 	struct drm_crtc_state *crtc_state = crtc->state;
98 	struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
99 	struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
100 	bool pll_locked = false;
101 	unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
102 	u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
103 	int i, j, tmpcount, vcount;
104 
105 	pixpllcm = pixpllc->m - 1;
106 	pixpllcn = pixpllc->n - 1;
107 	pixpllcp = pixpllc->p - 1;
108 	pixpllcs = pixpllc->s;
109 
110 	xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm;
111 	xpixpllcn = pixpllcn;
112 	xpixpllcp = ((pixpllcn & GENMASK(10, 9)) >> 3) | (pixpllcs << 3) | pixpllcp;
113 
114 	WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
115 
116 	for (i = 0; i <= 32 && pll_locked == false; i++) {
117 		if (i > 0) {
118 			WREG8(MGAREG_CRTC_INDEX, 0x1e);
119 			tmp = RREG8(MGAREG_CRTC_DATA);
120 			if (tmp < 0xff)
121 				WREG8(MGAREG_CRTC_DATA, tmp+1);
122 		}
123 
124 		/* set pixclkdis to 1 */
125 		WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
126 		tmp = RREG8(DAC_DATA);
127 		tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
128 		WREG8(DAC_DATA, tmp);
129 
130 		WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
131 		tmp = RREG8(DAC_DATA);
132 		tmp |= MGA1064_REMHEADCTL_CLKDIS;
133 		WREG8(DAC_DATA, tmp);
134 
135 		/* select PLL Set C */
136 		tmp = RREG8(MGAREG_MEM_MISC_READ);
137 		tmp |= 0x3 << 2;
138 		WREG8(MGAREG_MEM_MISC_WRITE, tmp);
139 
140 		WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
141 		tmp = RREG8(DAC_DATA);
142 		tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80;
143 		WREG8(DAC_DATA, tmp);
144 
145 		udelay(500);
146 
147 		/* reset the PLL */
148 		WREG8(DAC_INDEX, MGA1064_VREF_CTL);
149 		tmp = RREG8(DAC_DATA);
150 		tmp &= ~0x04;
151 		WREG8(DAC_DATA, tmp);
152 
153 		udelay(50);
154 
155 		/* program pixel pll register */
156 		WREG_DAC(MGA1064_WB_PIX_PLLC_N, xpixpllcn);
157 		WREG_DAC(MGA1064_WB_PIX_PLLC_M, xpixpllcm);
158 		WREG_DAC(MGA1064_WB_PIX_PLLC_P, xpixpllcp);
159 
160 		udelay(50);
161 
162 		/* turn pll on */
163 		WREG8(DAC_INDEX, MGA1064_VREF_CTL);
164 		tmp = RREG8(DAC_DATA);
165 		tmp |= 0x04;
166 		WREG_DAC(MGA1064_VREF_CTL, tmp);
167 
168 		udelay(500);
169 
170 		/* select the pixel pll */
171 		WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
172 		tmp = RREG8(DAC_DATA);
173 		tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
174 		tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
175 		WREG8(DAC_DATA, tmp);
176 
177 		WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
178 		tmp = RREG8(DAC_DATA);
179 		tmp &= ~MGA1064_REMHEADCTL_CLKSL_MSK;
180 		tmp |= MGA1064_REMHEADCTL_CLKSL_PLL;
181 		WREG8(DAC_DATA, tmp);
182 
183 		/* reset dotclock rate bit */
184 		WREG8(MGAREG_SEQ_INDEX, 1);
185 		tmp = RREG8(MGAREG_SEQ_DATA);
186 		tmp &= ~0x8;
187 		WREG8(MGAREG_SEQ_DATA, tmp);
188 
189 		WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
190 		tmp = RREG8(DAC_DATA);
191 		tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
192 		WREG8(DAC_DATA, tmp);
193 
194 		vcount = RREG8(MGAREG_VCOUNT);
195 
196 		for (j = 0; j < 30 && pll_locked == false; j++) {
197 			tmpcount = RREG8(MGAREG_VCOUNT);
198 			if (tmpcount < vcount)
199 				vcount = 0;
200 			if ((tmpcount - vcount) > 2)
201 				pll_locked = true;
202 			else
203 				udelay(5);
204 		}
205 	}
206 
207 	WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
208 	tmp = RREG8(DAC_DATA);
209 	tmp &= ~MGA1064_REMHEADCTL_CLKDIS;
210 	WREG_DAC(MGA1064_REMHEADCTL, tmp);
211 }
212 
213 /*
214  * Mode-setting pipeline
215  */
216 
217 static const struct drm_plane_helper_funcs mgag200_g200wb_primary_plane_helper_funcs = {
218 	MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
219 };
220 
221 static const struct drm_plane_funcs mgag200_g200wb_primary_plane_funcs = {
222 	MGAG200_PRIMARY_PLANE_FUNCS,
223 };
224 
225 static const struct drm_crtc_helper_funcs mgag200_g200wb_crtc_helper_funcs = {
226 	MGAG200_CRTC_HELPER_FUNCS,
227 };
228 
229 static const struct drm_crtc_funcs mgag200_g200wb_crtc_funcs = {
230 	MGAG200_CRTC_FUNCS,
231 };
232 
233 static int mgag200_g200wb_pipeline_init(struct mga_device *mdev)
234 {
235 	struct drm_device *dev = &mdev->base;
236 	struct drm_plane *primary_plane = &mdev->primary_plane;
237 	struct drm_crtc *crtc = &mdev->crtc;
238 	int ret;
239 
240 	ret = drm_universal_plane_init(dev, primary_plane, 0,
241 				       &mgag200_g200wb_primary_plane_funcs,
242 				       mgag200_primary_plane_formats,
243 				       mgag200_primary_plane_formats_size,
244 				       mgag200_primary_plane_fmtmods,
245 				       DRM_PLANE_TYPE_PRIMARY, NULL);
246 	if (ret) {
247 		drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
248 		return ret;
249 	}
250 	drm_plane_helper_add(primary_plane, &mgag200_g200wb_primary_plane_helper_funcs);
251 	drm_plane_enable_fb_damage_clips(primary_plane);
252 
253 	ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
254 					&mgag200_g200wb_crtc_funcs, NULL);
255 	if (ret) {
256 		drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
257 		return ret;
258 	}
259 	drm_crtc_helper_add(crtc, &mgag200_g200wb_crtc_helper_funcs);
260 
261 	/* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
262 	drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
263 	drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
264 
265 	ret = mgag200_vga_bmc_output_init(mdev);
266 	if (ret)
267 		return ret;
268 
269 	return 0;
270 }
271 
272 /*
273  * DRM device
274  */
275 
276 static const struct mgag200_device_info mgag200_g200wb_device_info =
277 	MGAG200_DEVICE_INFO_INIT(1280, 1024, 31877, true, 0, 1, false);
278 
279 static const struct mgag200_device_funcs mgag200_g200wb_device_funcs = {
280 	.pixpllc_atomic_check = mgag200_g200wb_pixpllc_atomic_check,
281 	.pixpllc_atomic_update = mgag200_g200wb_pixpllc_atomic_update,
282 };
283 
284 struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv)
285 {
286 	struct mga_device *mdev;
287 	struct drm_device *dev;
288 	resource_size_t vram_available;
289 	int ret;
290 
291 	mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base);
292 	if (IS_ERR(mdev))
293 		return mdev;
294 	dev = &mdev->base;
295 
296 	pci_set_drvdata(pdev, dev);
297 
298 	ret = mgag200_init_pci_options(pdev, 0x41049120, 0x0000b000);
299 	if (ret)
300 		return ERR_PTR(ret);
301 
302 	ret = mgag200_device_preinit(mdev);
303 	if (ret)
304 		return ERR_PTR(ret);
305 
306 	ret = mgag200_device_init(mdev, &mgag200_g200wb_device_info,
307 				  &mgag200_g200wb_device_funcs);
308 	if (ret)
309 		return ERR_PTR(ret);
310 
311 	mgag200_g200wb_init_registers(mdev);
312 
313 	vram_available = mgag200_device_probe_vram(mdev);
314 
315 	ret = mgag200_mode_config_init(mdev, vram_available);
316 	if (ret)
317 		return ERR_PTR(ret);
318 
319 	ret = mgag200_g200wb_pipeline_init(mdev);
320 	if (ret)
321 		return ERR_PTR(ret);
322 
323 	drm_mode_config_reset(dev);
324 	drm_kms_helper_poll_init(dev);
325 
326 	ret = drm_vblank_init(dev, 1);
327 	if (ret)
328 		return ERR_PTR(ret);
329 
330 	return mdev;
331 }
332