xref: /linux/drivers/gpu/drm/mgag200/mgag200_g200eh3.c (revision 75079df919efcc30eb5bf0427c83fb578f4fe4fc)
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 
11 #include "mgag200_ddc.h"
12 #include "mgag200_drv.h"
13 
14 /*
15  * PIXPLLC
16  */
17 
18 static int mgag200_g200eh3_pixpllc_atomic_check(struct drm_crtc *crtc,
19 						struct drm_atomic_state *new_state)
20 {
21 	static const unsigned int vcomax = 3000000;
22 	static const unsigned int vcomin = 1500000;
23 	static const unsigned int pllreffreq = 25000;
24 
25 	struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
26 	struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
27 	long clock = new_crtc_state->mode.clock;
28 	struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
29 	unsigned int delta, tmpdelta;
30 	unsigned int testp, testm, testn;
31 	unsigned int p, m, n, s;
32 	unsigned int computed;
33 
34 	m = n = p = s = 0;
35 	delta = 0xffffffff;
36 	testp = 0;
37 
38 	for (testm = 150; testm >= 6; testm--) {
39 		if (clock * testm > vcomax)
40 			continue;
41 		if (clock * testm < vcomin)
42 			continue;
43 		for (testn = 120; testn >= 60; testn--) {
44 			computed = (pllreffreq * testn) / testm;
45 			if (computed > clock)
46 				tmpdelta = computed - clock;
47 			else
48 				tmpdelta = clock - computed;
49 			if (tmpdelta < delta) {
50 				delta = tmpdelta;
51 				n = testn + 1;
52 				m = testm + 1;
53 				p = testp + 1;
54 			}
55 			if (delta == 0)
56 				break;
57 		}
58 		if (delta == 0)
59 			break;
60 	}
61 
62 	pixpllc->m = m;
63 	pixpllc->n = n;
64 	pixpllc->p = p;
65 	pixpllc->s = s;
66 
67 	return 0;
68 }
69 
70 /*
71  * Mode-setting pipeline
72  */
73 
74 static const struct drm_plane_helper_funcs mgag200_g200eh3_primary_plane_helper_funcs = {
75 	MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
76 };
77 
78 static const struct drm_plane_funcs mgag200_g200eh3_primary_plane_funcs = {
79 	MGAG200_PRIMARY_PLANE_FUNCS,
80 };
81 
82 static const struct drm_crtc_helper_funcs mgag200_g200eh3_crtc_helper_funcs = {
83 	MGAG200_CRTC_HELPER_FUNCS,
84 };
85 
86 static const struct drm_crtc_funcs mgag200_g200eh3_crtc_funcs = {
87 	MGAG200_CRTC_FUNCS,
88 };
89 
90 static const struct drm_encoder_funcs mgag200_g200eh3_dac_encoder_funcs = {
91 	MGAG200_DAC_ENCODER_FUNCS,
92 };
93 
94 static const struct drm_connector_helper_funcs mgag200_g200eh3_vga_connector_helper_funcs = {
95 	MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
96 };
97 
98 static const struct drm_connector_funcs mgag200_g200eh3_vga_connector_funcs = {
99 	MGAG200_VGA_CONNECTOR_FUNCS,
100 };
101 
102 static int mgag200_g200eh3_pipeline_init(struct mga_device *mdev)
103 {
104 	struct drm_device *dev = &mdev->base;
105 	struct drm_plane *primary_plane = &mdev->primary_plane;
106 	struct drm_crtc *crtc = &mdev->crtc;
107 	struct drm_encoder *encoder = &mdev->encoder;
108 	struct drm_connector *connector = &mdev->connector;
109 	struct i2c_adapter *ddc;
110 	int ret;
111 
112 	ret = drm_universal_plane_init(dev, primary_plane, 0,
113 				       &mgag200_g200eh3_primary_plane_funcs,
114 				       mgag200_primary_plane_formats,
115 				       mgag200_primary_plane_formats_size,
116 				       mgag200_primary_plane_fmtmods,
117 				       DRM_PLANE_TYPE_PRIMARY, NULL);
118 	if (ret) {
119 		drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
120 		return ret;
121 	}
122 	drm_plane_helper_add(primary_plane, &mgag200_g200eh3_primary_plane_helper_funcs);
123 	drm_plane_enable_fb_damage_clips(primary_plane);
124 
125 	ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
126 					&mgag200_g200eh3_crtc_funcs, NULL);
127 	if (ret) {
128 		drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
129 		return ret;
130 	}
131 	drm_crtc_helper_add(crtc, &mgag200_g200eh3_crtc_helper_funcs);
132 
133 	/* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
134 	drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
135 	drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
136 
137 	encoder->possible_crtcs = drm_crtc_mask(crtc);
138 	ret = drm_encoder_init(dev, encoder, &mgag200_g200eh3_dac_encoder_funcs,
139 			       DRM_MODE_ENCODER_DAC, NULL);
140 	if (ret) {
141 		drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
142 		return ret;
143 	}
144 
145 	ddc = mgag200_ddc_create(mdev);
146 	if (IS_ERR(ddc)) {
147 		ret = PTR_ERR(ddc);
148 		drm_err(dev, "failed to add DDC bus: %d\n", ret);
149 		return ret;
150 	}
151 
152 	ret = drm_connector_init_with_ddc(dev, connector,
153 					  &mgag200_g200eh3_vga_connector_funcs,
154 					  DRM_MODE_CONNECTOR_VGA, ddc);
155 	if (ret) {
156 		drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
157 		return ret;
158 	}
159 	drm_connector_helper_add(connector, &mgag200_g200eh3_vga_connector_helper_funcs);
160 
161 	ret = drm_connector_attach_encoder(connector, encoder);
162 	if (ret) {
163 		drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
164 		return ret;
165 	}
166 
167 	return 0;
168 }
169 
170 /*
171  * DRM device
172  */
173 
174 static const struct mgag200_device_info mgag200_g200eh3_device_info =
175 	MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, false, 1, 0, false);
176 
177 static const struct mgag200_device_funcs mgag200_g200eh3_device_funcs = {
178 	.pixpllc_atomic_check = mgag200_g200eh3_pixpllc_atomic_check,
179 	.pixpllc_atomic_update = mgag200_g200eh_pixpllc_atomic_update, // same as G200EH
180 };
181 
182 struct mga_device *mgag200_g200eh3_device_create(struct pci_dev *pdev,
183 						 const struct drm_driver *drv)
184 {
185 	struct mga_device *mdev;
186 	struct drm_device *dev;
187 	resource_size_t vram_available;
188 	int ret;
189 
190 	mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base);
191 	if (IS_ERR(mdev))
192 		return mdev;
193 	dev = &mdev->base;
194 
195 	pci_set_drvdata(pdev, dev);
196 
197 	ret = mgag200_init_pci_options(pdev, 0x00000120, 0x0000b000);
198 	if (ret)
199 		return ERR_PTR(ret);
200 
201 	ret = mgag200_device_preinit(mdev);
202 	if (ret)
203 		return ERR_PTR(ret);
204 
205 	ret = mgag200_device_init(mdev, &mgag200_g200eh3_device_info,
206 				  &mgag200_g200eh3_device_funcs);
207 	if (ret)
208 		return ERR_PTR(ret);
209 
210 	mgag200_g200eh_init_registers(mdev); // same as G200EH
211 
212 	vram_available = mgag200_device_probe_vram(mdev);
213 
214 	ret = mgag200_mode_config_init(mdev, vram_available);
215 	if (ret)
216 		return ERR_PTR(ret);
217 
218 	ret = mgag200_g200eh3_pipeline_init(mdev);
219 	if (ret)
220 		return ERR_PTR(ret);
221 
222 	drm_mode_config_reset(dev);
223 
224 	return mdev;
225 }
226