File Index
Files and directories
Sign in
FILE

mgag200_g200wb.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/mgag200/mgag200_g200wb.c C
  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_print.h>
 11#include <drm/drm_probe_helper.h>
 12
 13#include "mgag200_drv.h"
 14
 15void 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
 41static 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
 92void 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
217static const struct drm_plane_helper_funcs mgag200_g200wb_primary_plane_helper_funcs = {
218	MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
219};
220
221static const struct drm_plane_funcs mgag200_g200wb_primary_plane_funcs = {
222	MGAG200_PRIMARY_PLANE_FUNCS,
223};
224
225static const struct drm_crtc_helper_funcs mgag200_g200wb_crtc_helper_funcs = {
226	MGAG200_CRTC_HELPER_FUNCS,
227};
228
229static const struct drm_crtc_funcs mgag200_g200wb_crtc_funcs = {
230	MGAG200_CRTC_FUNCS,
231};
232
233static 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
276static const struct mgag200_device_info mgag200_g200wb_device_info =
277	MGAG200_DEVICE_INFO_INIT(1280, 1024, 31877, true, 0, 1, false);
278
279static 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
284struct 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	return mdev;
327}
~/ Read-only file preview.