xref: /linux/drivers/gpu/drm/mgag200/mgag200_g200ew3.c (revision de848da12f752170c2ebe114804a985314fd5a6a)
185397f6bSThomas Zimmermann // SPDX-License-Identifier: GPL-2.0-only
285397f6bSThomas Zimmermann 
385397f6bSThomas Zimmermann #include <linux/pci.h>
485397f6bSThomas Zimmermann 
5877507bbSThomas Zimmermann #include <drm/drm_atomic.h>
6bc835040SThomas Zimmermann #include <drm/drm_atomic_helper.h>
785397f6bSThomas Zimmermann #include <drm/drm_drv.h>
8bc835040SThomas Zimmermann #include <drm/drm_gem_atomic_helper.h>
9bc835040SThomas Zimmermann #include <drm/drm_probe_helper.h>
1089c6ea20SThomas Zimmermann #include <drm/drm_vblank.h>
1185397f6bSThomas Zimmermann 
1285397f6bSThomas Zimmermann #include "mgag200_drv.h"
1385397f6bSThomas Zimmermann 
149382ec27SThomas Zimmermann static void mgag200_g200ew3_init_registers(struct mga_device *mdev)
159382ec27SThomas Zimmermann {
169382ec27SThomas Zimmermann 	mgag200_g200wb_init_registers(mdev); // same as G200WB
179382ec27SThomas Zimmermann 
189382ec27SThomas Zimmermann 	WREG_ECRT(0x34, 0x5); // G200EW3 specific
199382ec27SThomas Zimmermann }
209382ec27SThomas Zimmermann 
2185397f6bSThomas Zimmermann /*
22877507bbSThomas Zimmermann  * PIXPLLC
23877507bbSThomas Zimmermann  */
24877507bbSThomas Zimmermann 
25877507bbSThomas Zimmermann static int mgag200_g200ew3_pixpllc_atomic_check(struct drm_crtc *crtc,
26877507bbSThomas Zimmermann 						struct drm_atomic_state *new_state)
27877507bbSThomas Zimmermann {
28877507bbSThomas Zimmermann 	static const unsigned int vcomax = 800000;
29877507bbSThomas Zimmermann 	static const unsigned int vcomin = 400000;
30877507bbSThomas Zimmermann 	static const unsigned int pllreffreq = 25000;
31877507bbSThomas Zimmermann 
32877507bbSThomas Zimmermann 	struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
33877507bbSThomas Zimmermann 	struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
34877507bbSThomas Zimmermann 	long clock = new_crtc_state->mode.clock;
35877507bbSThomas Zimmermann 	struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
36877507bbSThomas Zimmermann 	unsigned int delta, tmpdelta;
37877507bbSThomas Zimmermann 	unsigned int testp, testm, testn, testp2;
38877507bbSThomas Zimmermann 	unsigned int p, m, n, s;
39877507bbSThomas Zimmermann 	unsigned int computed;
40877507bbSThomas Zimmermann 
41877507bbSThomas Zimmermann 	m = n = p = s = 0;
42877507bbSThomas Zimmermann 	delta = 0xffffffff;
43877507bbSThomas Zimmermann 
44877507bbSThomas Zimmermann 	for (testp = 1; testp < 8; testp++) {
45877507bbSThomas Zimmermann 		for (testp2 = 1; testp2 < 8; testp2++) {
46877507bbSThomas Zimmermann 			if (testp < testp2)
47877507bbSThomas Zimmermann 				continue;
48877507bbSThomas Zimmermann 			if ((clock * testp * testp2) > vcomax)
49877507bbSThomas Zimmermann 				continue;
50877507bbSThomas Zimmermann 			if ((clock * testp * testp2) < vcomin)
51877507bbSThomas Zimmermann 				continue;
52877507bbSThomas Zimmermann 			for (testm = 1; testm < 26; testm++) {
53877507bbSThomas Zimmermann 				for (testn = 32; testn < 2048 ; testn++) {
54877507bbSThomas Zimmermann 					computed = (pllreffreq * testn) / (testm * testp * testp2);
55877507bbSThomas Zimmermann 					if (computed > clock)
56877507bbSThomas Zimmermann 						tmpdelta = computed - clock;
57877507bbSThomas Zimmermann 					else
58877507bbSThomas Zimmermann 						tmpdelta = clock - computed;
59877507bbSThomas Zimmermann 					if (tmpdelta < delta) {
60877507bbSThomas Zimmermann 						delta = tmpdelta;
61877507bbSThomas Zimmermann 						m = testm + 1;
62877507bbSThomas Zimmermann 						n = testn + 1;
63877507bbSThomas Zimmermann 						p = testp + 1;
64877507bbSThomas Zimmermann 						s = testp2;
65877507bbSThomas Zimmermann 					}
66877507bbSThomas Zimmermann 				}
67877507bbSThomas Zimmermann 			}
68877507bbSThomas Zimmermann 		}
69877507bbSThomas Zimmermann 	}
70877507bbSThomas Zimmermann 
71877507bbSThomas Zimmermann 	pixpllc->m = m;
72877507bbSThomas Zimmermann 	pixpllc->n = n;
73877507bbSThomas Zimmermann 	pixpllc->p = p;
74877507bbSThomas Zimmermann 	pixpllc->s = s;
75877507bbSThomas Zimmermann 
76877507bbSThomas Zimmermann 	return 0;
77877507bbSThomas Zimmermann }
78877507bbSThomas Zimmermann 
79877507bbSThomas Zimmermann /*
80bc835040SThomas Zimmermann  * Mode-setting pipeline
81bc835040SThomas Zimmermann  */
82bc835040SThomas Zimmermann 
83bc835040SThomas Zimmermann static const struct drm_plane_helper_funcs mgag200_g200ew3_primary_plane_helper_funcs = {
84bc835040SThomas Zimmermann 	MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
85bc835040SThomas Zimmermann };
86bc835040SThomas Zimmermann 
87bc835040SThomas Zimmermann static const struct drm_plane_funcs mgag200_g200ew3_primary_plane_funcs = {
88bc835040SThomas Zimmermann 	MGAG200_PRIMARY_PLANE_FUNCS,
89bc835040SThomas Zimmermann };
90bc835040SThomas Zimmermann 
91bc835040SThomas Zimmermann static const struct drm_crtc_helper_funcs mgag200_g200ew3_crtc_helper_funcs = {
92bc835040SThomas Zimmermann 	MGAG200_CRTC_HELPER_FUNCS,
93bc835040SThomas Zimmermann };
94bc835040SThomas Zimmermann 
95bc835040SThomas Zimmermann static const struct drm_crtc_funcs mgag200_g200ew3_crtc_funcs = {
96bc835040SThomas Zimmermann 	MGAG200_CRTC_FUNCS,
97bc835040SThomas Zimmermann };
98bc835040SThomas Zimmermann 
99bc835040SThomas Zimmermann static int mgag200_g200ew3_pipeline_init(struct mga_device *mdev)
100bc835040SThomas Zimmermann {
101bc835040SThomas Zimmermann 	struct drm_device *dev = &mdev->base;
102bc835040SThomas Zimmermann 	struct drm_plane *primary_plane = &mdev->primary_plane;
103bc835040SThomas Zimmermann 	struct drm_crtc *crtc = &mdev->crtc;
104bc835040SThomas Zimmermann 	int ret;
105bc835040SThomas Zimmermann 
106bc835040SThomas Zimmermann 	ret = drm_universal_plane_init(dev, primary_plane, 0,
107bc835040SThomas Zimmermann 				       &mgag200_g200ew3_primary_plane_funcs,
108bc835040SThomas Zimmermann 				       mgag200_primary_plane_formats,
109bc835040SThomas Zimmermann 				       mgag200_primary_plane_formats_size,
110bc835040SThomas Zimmermann 				       mgag200_primary_plane_fmtmods,
111bc835040SThomas Zimmermann 				       DRM_PLANE_TYPE_PRIMARY, NULL);
112bc835040SThomas Zimmermann 	if (ret) {
113bc835040SThomas Zimmermann 		drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
114bc835040SThomas Zimmermann 		return ret;
115bc835040SThomas Zimmermann 	}
116bc835040SThomas Zimmermann 	drm_plane_helper_add(primary_plane, &mgag200_g200ew3_primary_plane_helper_funcs);
117bc835040SThomas Zimmermann 	drm_plane_enable_fb_damage_clips(primary_plane);
118bc835040SThomas Zimmermann 
119bc835040SThomas Zimmermann 	ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
120bc835040SThomas Zimmermann 					&mgag200_g200ew3_crtc_funcs, NULL);
121bc835040SThomas Zimmermann 	if (ret) {
122bc835040SThomas Zimmermann 		drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
123bc835040SThomas Zimmermann 		return ret;
124bc835040SThomas Zimmermann 	}
125bc835040SThomas Zimmermann 	drm_crtc_helper_add(crtc, &mgag200_g200ew3_crtc_helper_funcs);
126bc835040SThomas Zimmermann 
127bc835040SThomas Zimmermann 	/* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
128bc835040SThomas Zimmermann 	drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
129bc835040SThomas Zimmermann 	drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
130bc835040SThomas Zimmermann 
131*f5510726SThomas Zimmermann 	ret = mgag200_vga_bmc_output_init(mdev);
132579d4783SThomas Zimmermann 	if (ret)
133bc835040SThomas Zimmermann 		return ret;
134bc835040SThomas Zimmermann 
135bc835040SThomas Zimmermann 	return 0;
136bc835040SThomas Zimmermann }
137bc835040SThomas Zimmermann 
138bc835040SThomas Zimmermann /*
13985397f6bSThomas Zimmermann  * DRM device
14085397f6bSThomas Zimmermann  */
14185397f6bSThomas Zimmermann 
142b9a577a4SThomas Zimmermann static const struct mgag200_device_info mgag200_g200ew3_device_info =
143da1efdb2SThomas Zimmermann 	MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, true, 0, 1, false);
144b9a577a4SThomas Zimmermann 
145f639f74aSThomas Zimmermann static const struct mgag200_device_funcs mgag200_g200ew3_device_funcs = {
146877507bbSThomas Zimmermann 	.pixpllc_atomic_check = mgag200_g200ew3_pixpllc_atomic_check,
147877507bbSThomas Zimmermann 	.pixpllc_atomic_update = mgag200_g200wb_pixpllc_atomic_update, // same as G200WB
148f639f74aSThomas Zimmermann };
149f639f74aSThomas Zimmermann 
150d45e32c9SThomas Zimmermann static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev)
151d45e32c9SThomas Zimmermann {
152b62d943eSThomas Zimmermann 	resource_size_t vram_size = resource_size(mdev->vram_res);
153d45e32c9SThomas Zimmermann 
154d45e32c9SThomas Zimmermann 	if (vram_size >= 0x1000000)
155d45e32c9SThomas Zimmermann 		vram_size = vram_size - 0x400000;
156d45e32c9SThomas Zimmermann 	return mgag200_probe_vram(mdev->vram, vram_size);
157d45e32c9SThomas Zimmermann }
158d45e32c9SThomas Zimmermann 
15985397f6bSThomas Zimmermann struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev,
160d4a3e50fSThomas Zimmermann 						 const struct drm_driver *drv)
16185397f6bSThomas Zimmermann {
16285397f6bSThomas Zimmermann 	struct mga_device *mdev;
16385397f6bSThomas Zimmermann 	struct drm_device *dev;
164d45e32c9SThomas Zimmermann 	resource_size_t vram_available;
16585397f6bSThomas Zimmermann 	int ret;
16685397f6bSThomas Zimmermann 
16785397f6bSThomas Zimmermann 	mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base);
16885397f6bSThomas Zimmermann 	if (IS_ERR(mdev))
16985397f6bSThomas Zimmermann 		return mdev;
17085397f6bSThomas Zimmermann 	dev = &mdev->base;
17185397f6bSThomas Zimmermann 
17285397f6bSThomas Zimmermann 	pci_set_drvdata(pdev, dev);
17385397f6bSThomas Zimmermann 
174ce19021fSThomas Zimmermann 	ret = mgag200_init_pci_options(pdev, 0x41049120, 0x0000b000);
175ce19021fSThomas Zimmermann 	if (ret)
176ce19021fSThomas Zimmermann 		return ERR_PTR(ret);
177ce19021fSThomas Zimmermann 
178b62d943eSThomas Zimmermann 	ret = mgag200_device_preinit(mdev);
17985397f6bSThomas Zimmermann 	if (ret)
18085397f6bSThomas Zimmermann 		return ERR_PTR(ret);
18185397f6bSThomas Zimmermann 
182d4a3e50fSThomas Zimmermann 	ret = mgag200_device_init(mdev, &mgag200_g200ew3_device_info,
183f639f74aSThomas Zimmermann 				  &mgag200_g200ew3_device_funcs);
18485397f6bSThomas Zimmermann 	if (ret)
18585397f6bSThomas Zimmermann 		return ERR_PTR(ret);
18685397f6bSThomas Zimmermann 
1879382ec27SThomas Zimmermann 	mgag200_g200ew3_init_registers(mdev);
1881ee181feSThomas Zimmermann 
189d45e32c9SThomas Zimmermann 	vram_available = mgag200_g200ew3_device_probe_vram(mdev);
190d45e32c9SThomas Zimmermann 
191bc835040SThomas Zimmermann 	ret = mgag200_mode_config_init(mdev, vram_available);
19285397f6bSThomas Zimmermann 	if (ret)
19385397f6bSThomas Zimmermann 		return ERR_PTR(ret);
19485397f6bSThomas Zimmermann 
195bc835040SThomas Zimmermann 	ret = mgag200_g200ew3_pipeline_init(mdev);
196bc835040SThomas Zimmermann 	if (ret)
197bc835040SThomas Zimmermann 		return ERR_PTR(ret);
198bc835040SThomas Zimmermann 
199bc835040SThomas Zimmermann 	drm_mode_config_reset(dev);
2002bae076fSThomas Zimmermann 	drm_kms_helper_poll_init(dev);
201bc835040SThomas Zimmermann 
20289c6ea20SThomas Zimmermann 	ret = drm_vblank_init(dev, 1);
20389c6ea20SThomas Zimmermann 	if (ret)
20489c6ea20SThomas Zimmermann 		return ERR_PTR(ret);
20589c6ea20SThomas Zimmermann 
20685397f6bSThomas Zimmermann 	return mdev;
20785397f6bSThomas Zimmermann }
208