File Index
Files and directories
Sign in
FILE

mgag200_g200.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/mgag200/mgag200_g200.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2
  3#include <linux/pci.h>
  4#include <linux/vmalloc.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
 15static int mgag200_g200_init_pci_options(struct pci_dev *pdev)
 16{
 17	struct device *dev = &pdev->dev;
 18	bool has_sgram;
 19	u32 option;
 20	int err;
 21
 22	err = pci_read_config_dword(pdev, PCI_MGA_OPTION, &option);
 23	if (err != PCIBIOS_SUCCESSFUL) {
 24		dev_err(dev, "pci_read_config_dword(PCI_MGA_OPTION) failed: %d\n", err);
 25		return pcibios_err_to_errno(err);
 26	}
 27
 28	has_sgram = !!(option & PCI_MGA_OPTION_HARDPWMSK);
 29
 30	if (has_sgram)
 31		option = 0x4049cd21;
 32	else
 33		option = 0x40499121;
 34
 35	return mgag200_init_pci_options(pdev, option, 0x00008000);
 36}
 37
 38static void mgag200_g200_init_registers(struct mgag200_g200_device *g200)
 39{
 40	static const u8 dacvalue[] = {
 41		MGAG200_DAC_DEFAULT(0x00, 0xc9, 0x1f,
 42				    0x04, 0x2d, 0x19)
 43	};
 44
 45	struct mga_device *mdev = &g200->base;
 46	size_t i;
 47
 48	for (i = 0; i < ARRAY_SIZE(dacvalue); ++i) {
 49		if ((i <= 0x17) ||
 50		    (i == 0x1b) ||
 51		    (i == 0x1c) ||
 52		    ((i >= 0x1f) && (i <= 0x29)) ||
 53		    ((i >= 0x30) && (i <= 0x37)))
 54			continue;
 55		WREG_DAC(i, dacvalue[i]);
 56	}
 57
 58	mgag200_init_registers(mdev);
 59}
 60
 61/*
 62 * PIXPLLC
 63 */
 64
 65static int mgag200_g200_pixpllc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *new_state)
 66{
 67	static const int post_div_max = 7;
 68	static const int in_div_min = 1;
 69	static const int in_div_max = 6;
 70	static const int feed_div_min = 7;
 71	static const int feed_div_max = 127;
 72
 73	struct drm_device *dev = crtc->dev;
 74	struct mgag200_g200_device *g200 = to_mgag200_g200_device(dev);
 75	struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
 76	struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
 77	long clock = new_crtc_state->mode.clock;
 78	struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
 79	u8 testp, testm, testn;
 80	u8 n = 0, m = 0, p, s;
 81	long f_vco;
 82	long computed;
 83	long delta, tmp_delta;
 84	long ref_clk = g200->ref_clk;
 85	long p_clk_min = g200->pclk_min;
 86	long p_clk_max = g200->pclk_max;
 87
 88	if (clock > p_clk_max) {
 89		drm_err(dev, "Pixel Clock %ld too high\n", clock);
 90		return -EINVAL;
 91	}
 92
 93	if (clock < p_clk_min >> 3)
 94		clock = p_clk_min >> 3;
 95
 96	f_vco = clock;
 97	for (testp = 0;
 98	     testp <= post_div_max && f_vco < p_clk_min;
 99	     testp = (testp << 1) + 1, f_vco <<= 1)
100		;
101	p = testp + 1;
102
103	delta = clock;
104
105	for (testm = in_div_min; testm <= in_div_max; testm++) {
106		for (testn = feed_div_min; testn <= feed_div_max; testn++) {
107			computed = ref_clk * (testn + 1) / (testm + 1);
108			if (computed < f_vco)
109				tmp_delta = f_vco - computed;
110			else
111				tmp_delta = computed - f_vco;
112			if (tmp_delta < delta) {
113				delta = tmp_delta;
114				m = testm + 1;
115				n = testn + 1;
116			}
117		}
118	}
119	f_vco = ref_clk * n / m;
120	if (f_vco < 100000)
121		s = 0;
122	else if (f_vco < 140000)
123		s = 1;
124	else if (f_vco < 180000)
125		s = 2;
126	else
127		s = 3;
128
129	drm_dbg_kms(dev, "clock: %ld vco: %ld m: %d n: %d p: %d s: %d\n",
130		    clock, f_vco, m, n, p, s);
131
132	pixpllc->m = m;
133	pixpllc->n = n;
134	pixpllc->p = p;
135	pixpllc->s = s;
136
137	return 0;
138}
139
140static void mgag200_g200_pixpllc_atomic_update(struct drm_crtc *crtc,
141					       struct drm_atomic_state *old_state)
142{
143	struct drm_device *dev = crtc->dev;
144	struct mga_device *mdev = to_mga_device(dev);
145	struct drm_crtc_state *crtc_state = crtc->state;
146	struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
147	struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
148	unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
149	u8 xpixpllcm, xpixpllcn, xpixpllcp;
150
151	pixpllcm = pixpllc->m - 1;
152	pixpllcn = pixpllc->n - 1;
153	pixpllcp = pixpllc->p - 1;
154	pixpllcs = pixpllc->s;
155
156	xpixpllcm = pixpllcm;
157	xpixpllcn = pixpllcn;
158	xpixpllcp = (pixpllcs << 3) | pixpllcp;
159
160	WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
161
162	WREG_DAC(MGA1064_PIX_PLLC_M, xpixpllcm);
163	WREG_DAC(MGA1064_PIX_PLLC_N, xpixpllcn);
164	WREG_DAC(MGA1064_PIX_PLLC_P, xpixpllcp);
165}
166
167/*
168 * Mode-setting pipeline
169 */
170
171static const struct drm_plane_helper_funcs mgag200_g200_primary_plane_helper_funcs = {
172	MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
173};
174
175static const struct drm_plane_funcs mgag200_g200_primary_plane_funcs = {
176	MGAG200_PRIMARY_PLANE_FUNCS,
177};
178
179static const struct drm_crtc_helper_funcs mgag200_g200_crtc_helper_funcs = {
180	MGAG200_CRTC_HELPER_FUNCS,
181};
182
183static const struct drm_crtc_funcs mgag200_g200_crtc_funcs = {
184	MGAG200_CRTC_FUNCS,
185};
186
187static int mgag200_g200_pipeline_init(struct mga_device *mdev)
188{
189	struct drm_device *dev = &mdev->base;
190	struct drm_plane *primary_plane = &mdev->primary_plane;
191	struct drm_crtc *crtc = &mdev->crtc;
192	int ret;
193
194	ret = drm_universal_plane_init(dev, primary_plane, 0,
195				       &mgag200_g200_primary_plane_funcs,
196				       mgag200_primary_plane_formats,
197				       mgag200_primary_plane_formats_size,
198				       mgag200_primary_plane_fmtmods,
199				       DRM_PLANE_TYPE_PRIMARY, NULL);
200	if (ret) {
201		drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
202		return ret;
203	}
204	drm_plane_helper_add(primary_plane, &mgag200_g200_primary_plane_helper_funcs);
205	drm_plane_enable_fb_damage_clips(primary_plane);
206
207	ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
208					&mgag200_g200_crtc_funcs, NULL);
209	if (ret) {
210		drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
211		return ret;
212	}
213	drm_crtc_helper_add(crtc, &mgag200_g200_crtc_helper_funcs);
214
215	/* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
216	drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
217	drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
218
219	ret = mgag200_vga_output_init(mdev);
220	if (ret)
221		return ret;
222
223	return 0;
224}
225
226/*
227 * DRM Device
228 */
229
230static const struct mgag200_device_info mgag200_g200_device_info =
231	MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false, 1, 3, false);
232
233static void mgag200_g200_interpret_bios(struct mgag200_g200_device *g200,
234					const unsigned char *bios, size_t size)
235{
236	static const char matrox[] = {'M', 'A', 'T', 'R', 'O', 'X'};
237	static const unsigned int expected_length[6] = {
238		0, 64, 64, 64, 128, 128
239	};
240	struct mga_device *mdev = &g200->base;
241	struct drm_device *dev = &mdev->base;
242	const unsigned char *pins;
243	unsigned int pins_len, version;
244	int offset;
245	int tmp;
246
247	/* Test for MATROX string. */
248	if (size < 45 + sizeof(matrox))
249		return;
250	if (memcmp(&bios[45], matrox, sizeof(matrox)) != 0)
251		return;
252
253	/* Get the PInS offset. */
254	if (size < MGA_BIOS_OFFSET + 2)
255		return;
256	offset = (bios[MGA_BIOS_OFFSET + 1] << 8) | bios[MGA_BIOS_OFFSET];
257
258	/* Get PInS data structure. */
259
260	if (size < offset + 6)
261		return;
262	pins = bios + offset;
263	if (pins[0] == 0x2e && pins[1] == 0x41) {
264		version = pins[5];
265		pins_len = pins[2];
266	} else {
267		version = 1;
268		pins_len = pins[0] + (pins[1] << 8);
269	}
270
271	if (version < 1 || version > 5) {
272		drm_warn(dev, "Unknown BIOS PInS version: %d\n", version);
273		return;
274	}
275	if (pins_len != expected_length[version]) {
276		drm_warn(dev, "Unexpected BIOS PInS size: %d expected: %d\n",
277			 pins_len, expected_length[version]);
278		return;
279	}
280	if (size < offset + pins_len)
281		return;
282
283	drm_dbg_kms(dev, "MATROX BIOS PInS version %d size: %d found\n", version, pins_len);
284
285	/* Extract the clock values */
286
287	switch (version) {
288	case 1:
289		tmp = pins[24] + (pins[25] << 8);
290		if (tmp)
291			g200->pclk_max = tmp * 10;
292		break;
293	case 2:
294		if (pins[41] != 0xff)
295			g200->pclk_max = (pins[41] + 100) * 1000;
296		break;
297	case 3:
298		if (pins[36] != 0xff)
299			g200->pclk_max = (pins[36] + 100) * 1000;
300		if (pins[52] & 0x20)
301			g200->ref_clk = 14318;
302		break;
303	case 4:
304		if (pins[39] != 0xff)
305			g200->pclk_max = pins[39] * 4 * 1000;
306		if (pins[92] & 0x01)
307			g200->ref_clk = 14318;
308		break;
309	case 5:
310		tmp = pins[4] ? 8000 : 6000;
311		if (pins[123] != 0xff)
312			g200->pclk_min = pins[123] * tmp;
313		if (pins[38] != 0xff)
314			g200->pclk_max = pins[38] * tmp;
315		if (pins[110] & 0x01)
316			g200->ref_clk = 14318;
317		break;
318	default:
319		break;
320	}
321}
322
323static void mgag200_g200_init_refclk(struct mgag200_g200_device *g200)
324{
325	struct mga_device *mdev = &g200->base;
326	struct drm_device *dev = &mdev->base;
327	struct pci_dev *pdev = to_pci_dev(dev->dev);
328	unsigned char __iomem *rom;
329	unsigned char *bios;
330	size_t size;
331
332	g200->pclk_min = 50000;
333	g200->pclk_max = 230000;
334	g200->ref_clk = 27050;
335
336	rom = pci_map_rom(pdev, &size);
337	if (!rom)
338		return;
339
340	bios = vmalloc(size);
341	if (!bios)
342		goto out;
343	memcpy_fromio(bios, rom, size);
344
345	if (size != 0 && bios[0] == 0x55 && bios[1] == 0xaa)
346		mgag200_g200_interpret_bios(g200, bios, size);
347
348	drm_dbg_kms(dev, "pclk_min: %ld pclk_max: %ld ref_clk: %ld\n",
349		    g200->pclk_min, g200->pclk_max, g200->ref_clk);
350
351	vfree(bios);
352out:
353	pci_unmap_rom(pdev, rom);
354}
355
356static const struct mgag200_device_funcs mgag200_g200_device_funcs = {
357	.pixpllc_atomic_check = mgag200_g200_pixpllc_atomic_check,
358	.pixpllc_atomic_update = mgag200_g200_pixpllc_atomic_update,
359};
360
361struct mga_device *mgag200_g200_device_create(struct pci_dev *pdev, const struct drm_driver *drv)
362{
363	struct mgag200_g200_device *g200;
364	struct mga_device *mdev;
365	struct drm_device *dev;
366	resource_size_t vram_available;
367	int ret;
368
369	g200 = devm_drm_dev_alloc(&pdev->dev, drv, struct mgag200_g200_device, base.base);
370	if (IS_ERR(g200))
371		return ERR_CAST(g200);
372	mdev = &g200->base;
373	dev = &mdev->base;
374
375	pci_set_drvdata(pdev, dev);
376
377	ret = mgag200_g200_init_pci_options(pdev);
378	if (ret)
379		return ERR_PTR(ret);
380
381	ret = mgag200_device_preinit(mdev);
382	if (ret)
383		return ERR_PTR(ret);
384
385	mgag200_g200_init_refclk(g200);
386
387	ret = mgag200_device_init(mdev, &mgag200_g200_device_info,
388				  &mgag200_g200_device_funcs);
389	if (ret)
390		return ERR_PTR(ret);
391
392	mgag200_g200_init_registers(g200);
393
394	vram_available = mgag200_device_probe_vram(mdev);
395
396	ret = mgag200_mode_config_init(mdev, vram_available);
397	if (ret)
398		return ERR_PTR(ret);
399
400	ret = mgag200_g200_pipeline_init(mdev);
401	if (ret)
402		return ERR_PTR(ret);
403
404	drm_mode_config_reset(dev);
405	drm_kms_helper_poll_init(dev);
406
407	return mdev;
408}
~/ Read-only file preview.