xref: /linux/drivers/gpu/drm/mgag200/mgag200_g200ew3.c (revision de848da12f752170c2ebe114804a985314fd5a6a)
1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 #include <linux/pci.h>
4 
5 #include <drm/drm_atomic.h>
6 #include <drm/drm_atomic_helper.h>
7 #include <drm/drm_drv.h>
8 #include <drm/drm_gem_atomic_helper.h>
9 #include <drm/drm_probe_helper.h>
10 #include <drm/drm_vblank.h>
11 
12 #include "mgag200_drv.h"
13 
14 static void mgag200_g200ew3_init_registers(struct mga_device *mdev)
15 {
16 	mgag200_g200wb_init_registers(mdev); // same as G200WB
17 
18 	WREG_ECRT(0x34, 0x5); // G200EW3 specific
19 }
20 
21 /*
22  * PIXPLLC
23  */
24 
25 static int mgag200_g200ew3_pixpllc_atomic_check(struct drm_crtc *crtc,
26 						struct drm_atomic_state *new_state)
27 {
28 	static const unsigned int vcomax = 800000;
29 	static const unsigned int vcomin = 400000;
30 	static const unsigned int pllreffreq = 25000;
31 
32 	struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
33 	struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
34 	long clock = new_crtc_state->mode.clock;
35 	struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
36 	unsigned int delta, tmpdelta;
37 	unsigned int testp, testm, testn, testp2;
38 	unsigned int p, m, n, s;
39 	unsigned int computed;
40 
41 	m = n = p = s = 0;
42 	delta = 0xffffffff;
43 
44 	for (testp = 1; testp < 8; testp++) {
45 		for (testp2 = 1; testp2 < 8; testp2++) {
46 			if (testp < testp2)
47 				continue;
48 			if ((clock * testp * testp2) > vcomax)
49 				continue;
50 			if ((clock * testp * testp2) < vcomin)
51 				continue;
52 			for (testm = 1; testm < 26; testm++) {
53 				for (testn = 32; testn < 2048 ; testn++) {
54 					computed = (pllreffreq * testn) / (testm * testp * testp2);
55 					if (computed > clock)
56 						tmpdelta = computed - clock;
57 					else
58 						tmpdelta = clock - computed;
59 					if (tmpdelta < delta) {
60 						delta = tmpdelta;
61 						m = testm + 1;
62 						n = testn + 1;
63 						p = testp + 1;
64 						s = testp2;
65 					}
66 				}
67 			}
68 		}
69 	}
70 
71 	pixpllc->m = m;
72 	pixpllc->n = n;
73 	pixpllc->p = p;
74 	pixpllc->s = s;
75 
76 	return 0;
77 }
78 
79 /*
80  * Mode-setting pipeline
81  */
82 
83 static const struct drm_plane_helper_funcs mgag200_g200ew3_primary_plane_helper_funcs = {
84 	MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
85 };
86 
87 static const struct drm_plane_funcs mgag200_g200ew3_primary_plane_funcs = {
88 	MGAG200_PRIMARY_PLANE_FUNCS,
89 };
90 
91 static const struct drm_crtc_helper_funcs mgag200_g200ew3_crtc_helper_funcs = {
92 	MGAG200_CRTC_HELPER_FUNCS,
93 };
94 
95 static const struct drm_crtc_funcs mgag200_g200ew3_crtc_funcs = {
96 	MGAG200_CRTC_FUNCS,
97 };
98 
99 static int mgag200_g200ew3_pipeline_init(struct mga_device *mdev)
100 {
101 	struct drm_device *dev = &mdev->base;
102 	struct drm_plane *primary_plane = &mdev->primary_plane;
103 	struct drm_crtc *crtc = &mdev->crtc;
104 	int ret;
105 
106 	ret = drm_universal_plane_init(dev, primary_plane, 0,
107 				       &mgag200_g200ew3_primary_plane_funcs,
108 				       mgag200_primary_plane_formats,
109 				       mgag200_primary_plane_formats_size,
110 				       mgag200_primary_plane_fmtmods,
111 				       DRM_PLANE_TYPE_PRIMARY, NULL);
112 	if (ret) {
113 		drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
114 		return ret;
115 	}
116 	drm_plane_helper_add(primary_plane, &mgag200_g200ew3_primary_plane_helper_funcs);
117 	drm_plane_enable_fb_damage_clips(primary_plane);
118 
119 	ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
120 					&mgag200_g200ew3_crtc_funcs, NULL);
121 	if (ret) {
122 		drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
123 		return ret;
124 	}
125 	drm_crtc_helper_add(crtc, &mgag200_g200ew3_crtc_helper_funcs);
126 
127 	/* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
128 	drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
129 	drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
130 
131 	ret = mgag200_vga_bmc_output_init(mdev);
132 	if (ret)
133 		return ret;
134 
135 	return 0;
136 }
137 
138 /*
139  * DRM device
140  */
141 
142 static const struct mgag200_device_info mgag200_g200ew3_device_info =
143 	MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, true, 0, 1, false);
144 
145 static const struct mgag200_device_funcs mgag200_g200ew3_device_funcs = {
146 	.pixpllc_atomic_check = mgag200_g200ew3_pixpllc_atomic_check,
147 	.pixpllc_atomic_update = mgag200_g200wb_pixpllc_atomic_update, // same as G200WB
148 };
149 
150 static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev)
151 {
152 	resource_size_t vram_size = resource_size(mdev->vram_res);
153 
154 	if (vram_size >= 0x1000000)
155 		vram_size = vram_size - 0x400000;
156 	return mgag200_probe_vram(mdev->vram, vram_size);
157 }
158 
159 struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev,
160 						 const struct drm_driver *drv)
161 {
162 	struct mga_device *mdev;
163 	struct drm_device *dev;
164 	resource_size_t vram_available;
165 	int ret;
166 
167 	mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base);
168 	if (IS_ERR(mdev))
169 		return mdev;
170 	dev = &mdev->base;
171 
172 	pci_set_drvdata(pdev, dev);
173 
174 	ret = mgag200_init_pci_options(pdev, 0x41049120, 0x0000b000);
175 	if (ret)
176 		return ERR_PTR(ret);
177 
178 	ret = mgag200_device_preinit(mdev);
179 	if (ret)
180 		return ERR_PTR(ret);
181 
182 	ret = mgag200_device_init(mdev, &mgag200_g200ew3_device_info,
183 				  &mgag200_g200ew3_device_funcs);
184 	if (ret)
185 		return ERR_PTR(ret);
186 
187 	mgag200_g200ew3_init_registers(mdev);
188 
189 	vram_available = mgag200_g200ew3_device_probe_vram(mdev);
190 
191 	ret = mgag200_mode_config_init(mdev, vram_available);
192 	if (ret)
193 		return ERR_PTR(ret);
194 
195 	ret = mgag200_g200ew3_pipeline_init(mdev);
196 	if (ret)
197 		return ERR_PTR(ret);
198 
199 	drm_mode_config_reset(dev);
200 	drm_kms_helper_poll_init(dev);
201 
202 	ret = drm_vblank_init(dev, 1);
203 	if (ret)
204 		return ERR_PTR(ret);
205 
206 	return mdev;
207 }
208