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_probe_helper.h> |
11 | |
12 | #include "mgag200_drv.h" |
13 | |
14 | static void mgag200_g200ev_init_registers(struct mga_device *mdev) |
15 | { |
16 | static const u8 dacvalue[] = { |
17 | MGAG200_DAC_DEFAULT(0x00, |
18 | MGA1064_PIX_CLK_CTL_SEL_PLL, |
19 | MGA1064_MISC_CTL_VGA8 | MGA1064_MISC_CTL_DAC_RAM_CS, |
20 | 0x00, 0x00, 0x00) |
21 | }; |
22 | |
23 | size_t i; |
24 | |
25 | for (i = 0; i < ARRAY_SIZE(dacvalue); i++) { |
26 | if ((i <= 0x17) || |
27 | (i == 0x1b) || |
28 | (i == 0x1c) || |
29 | ((i >= 0x1f) && (i <= 0x29)) || |
30 | ((i >= 0x30) && (i <= 0x37)) || |
31 | ((i >= 0x44) && (i <= 0x4e))) |
32 | continue; |
33 | WREG_DAC(i, dacvalue[i]); |
34 | } |
35 | |
36 | mgag200_init_registers(mdev); |
37 | } |
38 | |
39 | static void mgag200_g200ev_set_hiprilvl(struct mga_device *mdev) |
40 | { |
41 | WREG_ECRT(0x06, 0x00); |
42 | } |
43 | |
44 | /* |
45 | * PIXPLLC |
46 | */ |
47 | |
48 | static int mgag200_g200ev_pixpllc_atomic_check(struct drm_crtc *crtc, |
49 | struct drm_atomic_state *new_state) |
50 | { |
51 | static const unsigned int vcomax = 550000; |
52 | static const unsigned int vcomin = 150000; |
53 | static const unsigned int pllreffreq = 50000; |
54 | |
55 | struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(state: new_state, crtc); |
56 | struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(base: new_crtc_state); |
57 | long clock = new_crtc_state->mode.clock; |
58 | struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc; |
59 | unsigned int delta, tmpdelta; |
60 | unsigned int testp, testm, testn; |
61 | unsigned int p, m, n, s; |
62 | unsigned int computed; |
63 | |
64 | m = n = p = s = 0; |
65 | delta = 0xffffffff; |
66 | |
67 | for (testp = 16; testp > 0; testp--) { |
68 | if (clock * testp > vcomax) |
69 | continue; |
70 | if (clock * testp < vcomin) |
71 | continue; |
72 | |
73 | for (testn = 1; testn < 257; testn++) { |
74 | for (testm = 1; testm < 17; testm++) { |
75 | computed = (pllreffreq * testn) / |
76 | (testm * testp); |
77 | if (computed > clock) |
78 | tmpdelta = computed - clock; |
79 | else |
80 | tmpdelta = clock - computed; |
81 | if (tmpdelta < delta) { |
82 | delta = tmpdelta; |
83 | n = testn; |
84 | m = testm; |
85 | p = testp; |
86 | } |
87 | } |
88 | } |
89 | } |
90 | |
91 | pixpllc->m = m; |
92 | pixpllc->n = n; |
93 | pixpllc->p = p; |
94 | pixpllc->s = s; |
95 | |
96 | return 0; |
97 | } |
98 | |
99 | static void mgag200_g200ev_pixpllc_atomic_update(struct drm_crtc *crtc, |
100 | struct drm_atomic_state *old_state) |
101 | { |
102 | struct drm_device *dev = crtc->dev; |
103 | struct mga_device *mdev = to_mga_device(dev); |
104 | struct drm_crtc_state *crtc_state = crtc->state; |
105 | struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(base: crtc_state); |
106 | struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc; |
107 | unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; |
108 | u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; |
109 | |
110 | pixpllcm = pixpllc->m - 1; |
111 | pixpllcn = pixpllc->n - 1; |
112 | pixpllcp = pixpllc->p - 1; |
113 | pixpllcs = pixpllc->s; |
114 | |
115 | xpixpllcm = pixpllcm; |
116 | xpixpllcn = pixpllcn; |
117 | xpixpllcp = (pixpllcs << 3) | pixpllcp; |
118 | |
119 | WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK); |
120 | |
121 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); |
122 | tmp = RREG8(DAC_DATA); |
123 | tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; |
124 | WREG8(DAC_DATA, tmp); |
125 | |
126 | tmp = RREG8(MGAREG_MEM_MISC_READ); |
127 | tmp |= 0x3 << 2; |
128 | WREG8(MGAREG_MEM_MISC_WRITE, tmp); |
129 | |
130 | WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT); |
131 | tmp = RREG8(DAC_DATA); |
132 | WREG8(DAC_DATA, tmp & ~0x40); |
133 | |
134 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); |
135 | tmp = RREG8(DAC_DATA); |
136 | tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; |
137 | WREG8(DAC_DATA, tmp); |
138 | |
139 | WREG_DAC(MGA1064_EV_PIX_PLLC_M, xpixpllcm); |
140 | WREG_DAC(MGA1064_EV_PIX_PLLC_N, xpixpllcn); |
141 | WREG_DAC(MGA1064_EV_PIX_PLLC_P, xpixpllcp); |
142 | |
143 | udelay(50); |
144 | |
145 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); |
146 | tmp = RREG8(DAC_DATA); |
147 | tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; |
148 | WREG8(DAC_DATA, tmp); |
149 | |
150 | udelay(500); |
151 | |
152 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); |
153 | tmp = RREG8(DAC_DATA); |
154 | tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; |
155 | tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; |
156 | WREG8(DAC_DATA, tmp); |
157 | |
158 | WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT); |
159 | tmp = RREG8(DAC_DATA); |
160 | WREG8(DAC_DATA, tmp | 0x40); |
161 | |
162 | tmp = RREG8(MGAREG_MEM_MISC_READ); |
163 | tmp |= (0x3 << 2); |
164 | WREG8(MGAREG_MEM_MISC_WRITE, tmp); |
165 | |
166 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); |
167 | tmp = RREG8(DAC_DATA); |
168 | tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; |
169 | WREG8(DAC_DATA, tmp); |
170 | } |
171 | |
172 | /* |
173 | * Mode-setting pipeline |
174 | */ |
175 | |
176 | static const struct drm_plane_helper_funcs mgag200_g200ev_primary_plane_helper_funcs = { |
177 | MGAG200_PRIMARY_PLANE_HELPER_FUNCS, |
178 | }; |
179 | |
180 | static const struct drm_plane_funcs mgag200_g200ev_primary_plane_funcs = { |
181 | MGAG200_PRIMARY_PLANE_FUNCS, |
182 | }; |
183 | |
184 | static void mgag200_g200ev_crtc_helper_atomic_enable(struct drm_crtc *crtc, |
185 | struct drm_atomic_state *old_state) |
186 | { |
187 | struct drm_device *dev = crtc->dev; |
188 | struct mga_device *mdev = to_mga_device(dev); |
189 | const struct mgag200_device_funcs *funcs = mdev->funcs; |
190 | struct drm_crtc_state *crtc_state = crtc->state; |
191 | struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; |
192 | struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(base: crtc_state); |
193 | const struct drm_format_info *format = mgag200_crtc_state->format; |
194 | |
195 | if (funcs->disable_vidrst) |
196 | funcs->disable_vidrst(mdev); |
197 | |
198 | mgag200_set_format_regs(mdev, format); |
199 | mgag200_set_mode_regs(mdev, mode: adjusted_mode); |
200 | |
201 | if (funcs->pixpllc_atomic_update) |
202 | funcs->pixpllc_atomic_update(crtc, old_state); |
203 | |
204 | mgag200_g200ev_set_hiprilvl(mdev); |
205 | |
206 | if (crtc_state->gamma_lut) |
207 | mgag200_crtc_set_gamma(mdev, format, lut: crtc_state->gamma_lut->data); |
208 | else |
209 | mgag200_crtc_set_gamma_linear(mdev, format); |
210 | |
211 | mgag200_enable_display(mdev); |
212 | |
213 | if (funcs->enable_vidrst) |
214 | funcs->enable_vidrst(mdev); |
215 | } |
216 | |
217 | static const struct drm_crtc_helper_funcs mgag200_g200ev_crtc_helper_funcs = { |
218 | .mode_valid = mgag200_crtc_helper_mode_valid, |
219 | .atomic_check = mgag200_crtc_helper_atomic_check, |
220 | .atomic_flush = mgag200_crtc_helper_atomic_flush, |
221 | .atomic_enable = mgag200_g200ev_crtc_helper_atomic_enable, |
222 | .atomic_disable = mgag200_crtc_helper_atomic_disable |
223 | }; |
224 | |
225 | static const struct drm_crtc_funcs mgag200_g200ev_crtc_funcs = { |
226 | MGAG200_CRTC_FUNCS, |
227 | }; |
228 | |
229 | static const struct drm_encoder_funcs mgag200_g200ev_dac_encoder_funcs = { |
230 | MGAG200_DAC_ENCODER_FUNCS, |
231 | }; |
232 | |
233 | static const struct drm_connector_helper_funcs mgag200_g200ev_vga_connector_helper_funcs = { |
234 | MGAG200_VGA_CONNECTOR_HELPER_FUNCS, |
235 | }; |
236 | |
237 | static const struct drm_connector_funcs mgag200_g200ev_vga_connector_funcs = { |
238 | MGAG200_VGA_CONNECTOR_FUNCS, |
239 | }; |
240 | |
241 | static int mgag200_g200ev_pipeline_init(struct mga_device *mdev) |
242 | { |
243 | struct drm_device *dev = &mdev->base; |
244 | struct drm_plane *primary_plane = &mdev->primary_plane; |
245 | struct drm_crtc *crtc = &mdev->crtc; |
246 | struct drm_encoder *encoder = &mdev->encoder; |
247 | struct mga_i2c_chan *i2c = &mdev->i2c; |
248 | struct drm_connector *connector = &mdev->connector; |
249 | int ret; |
250 | |
251 | ret = drm_universal_plane_init(dev, plane: primary_plane, possible_crtcs: 0, |
252 | funcs: &mgag200_g200ev_primary_plane_funcs, |
253 | formats: mgag200_primary_plane_formats, |
254 | format_count: mgag200_primary_plane_formats_size, |
255 | format_modifiers: mgag200_primary_plane_fmtmods, |
256 | type: DRM_PLANE_TYPE_PRIMARY, NULL); |
257 | if (ret) { |
258 | drm_err(dev, "drm_universal_plane_init() failed: %d\n" , ret); |
259 | return ret; |
260 | } |
261 | drm_plane_helper_add(plane: primary_plane, funcs: &mgag200_g200ev_primary_plane_helper_funcs); |
262 | drm_plane_enable_fb_damage_clips(plane: primary_plane); |
263 | |
264 | ret = drm_crtc_init_with_planes(dev, crtc, primary: primary_plane, NULL, |
265 | funcs: &mgag200_g200ev_crtc_funcs, NULL); |
266 | if (ret) { |
267 | drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n" , ret); |
268 | return ret; |
269 | } |
270 | drm_crtc_helper_add(crtc, funcs: &mgag200_g200ev_crtc_helper_funcs); |
271 | |
272 | /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */ |
273 | drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE); |
274 | drm_crtc_enable_color_mgmt(crtc, degamma_lut_size: 0, has_ctm: false, MGAG200_LUT_SIZE); |
275 | |
276 | encoder->possible_crtcs = drm_crtc_mask(crtc); |
277 | ret = drm_encoder_init(dev, encoder, funcs: &mgag200_g200ev_dac_encoder_funcs, |
278 | DRM_MODE_ENCODER_DAC, NULL); |
279 | if (ret) { |
280 | drm_err(dev, "drm_encoder_init() failed: %d\n" , ret); |
281 | return ret; |
282 | } |
283 | |
284 | ret = mgag200_i2c_init(mdev, i2c); |
285 | if (ret) { |
286 | drm_err(dev, "failed to add DDC bus: %d\n" , ret); |
287 | return ret; |
288 | } |
289 | |
290 | ret = drm_connector_init_with_ddc(dev, connector, |
291 | funcs: &mgag200_g200ev_vga_connector_funcs, |
292 | DRM_MODE_CONNECTOR_VGA, |
293 | ddc: &i2c->adapter); |
294 | if (ret) { |
295 | drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n" , ret); |
296 | return ret; |
297 | } |
298 | drm_connector_helper_add(connector, funcs: &mgag200_g200ev_vga_connector_helper_funcs); |
299 | |
300 | ret = drm_connector_attach_encoder(connector, encoder); |
301 | if (ret) { |
302 | drm_err(dev, "drm_connector_attach_encoder() failed: %d\n" , ret); |
303 | return ret; |
304 | } |
305 | |
306 | return 0; |
307 | } |
308 | |
309 | /* |
310 | * DRM device |
311 | */ |
312 | |
313 | static const struct mgag200_device_info mgag200_g200ev_device_info = |
314 | MGAG200_DEVICE_INFO_INIT(2048, 2048, 32700, false, 0, 1, false); |
315 | |
316 | static const struct mgag200_device_funcs mgag200_g200ev_device_funcs = { |
317 | .pixpllc_atomic_check = mgag200_g200ev_pixpllc_atomic_check, |
318 | .pixpllc_atomic_update = mgag200_g200ev_pixpllc_atomic_update, |
319 | }; |
320 | |
321 | struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv) |
322 | { |
323 | struct mga_device *mdev; |
324 | struct drm_device *dev; |
325 | resource_size_t vram_available; |
326 | int ret; |
327 | |
328 | mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base); |
329 | if (IS_ERR(ptr: mdev)) |
330 | return mdev; |
331 | dev = &mdev->base; |
332 | |
333 | pci_set_drvdata(pdev, data: dev); |
334 | |
335 | ret = mgag200_init_pci_options(pdev, option: 0x00000120, option2: 0x0000b000); |
336 | if (ret) |
337 | return ERR_PTR(error: ret); |
338 | |
339 | ret = mgag200_device_preinit(mdev); |
340 | if (ret) |
341 | return ERR_PTR(error: ret); |
342 | |
343 | ret = mgag200_device_init(mdev, info: &mgag200_g200ev_device_info, |
344 | funcs: &mgag200_g200ev_device_funcs); |
345 | if (ret) |
346 | return ERR_PTR(error: ret); |
347 | |
348 | mgag200_g200ev_init_registers(mdev); |
349 | |
350 | vram_available = mgag200_device_probe_vram(mdev); |
351 | |
352 | ret = mgag200_mode_config_init(mdev, vram_available); |
353 | if (ret) |
354 | return ERR_PTR(error: ret); |
355 | |
356 | ret = mgag200_g200ev_pipeline_init(mdev); |
357 | if (ret) |
358 | return ERR_PTR(error: ret); |
359 | |
360 | drm_mode_config_reset(dev); |
361 | |
362 | return mdev; |
363 | } |
364 | |