Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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_print.h>
11#include <drm/drm_probe_helper.h>
12
13#include "mgag200_drv.h"
14
15void mgag200_g200wb_init_registers(struct mga_device *mdev)
16{
17 static const u8 dacvalue[] = {
18 MGAG200_DAC_DEFAULT(0x07, 0xc9, 0x1f, 0x00, 0x00, 0x00)
19 };
20
21 size_t i;
22
23 for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {
24 if ((i <= 0x17) ||
25 (i == 0x1b) ||
26 (i == 0x1c) ||
27 ((i >= 0x1f) && (i <= 0x29)) ||
28 ((i >= 0x30) && (i <= 0x37)) ||
29 ((i >= 0x44) && (i <= 0x4e)))
30 continue;
31 WREG_DAC(i, dacvalue[i]);
32 }
33
34 mgag200_init_registers(mdev);
35}
36
37/*
38 * PIXPLLC
39 */
40
41static int mgag200_g200wb_pixpllc_atomic_check(struct drm_crtc *crtc,
42 struct drm_atomic_state *new_state)
43{
44 static const unsigned int vcomax = 550000;
45 static const unsigned int vcomin = 150000;
46 static const unsigned int pllreffreq = 48000;
47
48 struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
49 struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
50 long clock = new_crtc_state->mode.clock;
51 struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
52 unsigned int delta, tmpdelta;
53 unsigned int testp, testm, testn;
54 unsigned int p, m, n, s;
55 unsigned int computed;
56
57 m = n = p = s = 0;
58 delta = 0xffffffff;
59
60 for (testp = 1; testp < 9; testp++) {
61 if (clock * testp > vcomax)
62 continue;
63 if (clock * testp < vcomin)
64 continue;
65
66 for (testm = 1; testm < 17; testm++) {
67 for (testn = 1; testn < 151; testn++) {
68 computed = (pllreffreq * testn) / (testm * testp);
69 if (computed > clock)
70 tmpdelta = computed - clock;
71 else
72 tmpdelta = clock - computed;
73 if (tmpdelta < delta) {
74 delta = tmpdelta;
75 n = testn;
76 m = testm;
77 p = testp;
78 s = 0;
79 }
80 }
81 }
82 }
83
84 pixpllc->m = m;
85 pixpllc->n = n;
86 pixpllc->p = p;
87 pixpllc->s = s;
88
89 return 0;
90}
91
92void mgag200_g200wb_pixpllc_atomic_update(struct drm_crtc *crtc,
93 struct drm_atomic_state *old_state)
94{
95 struct drm_device *dev = crtc->dev;
96 struct mga_device *mdev = to_mga_device(dev);
97 struct drm_crtc_state *crtc_state = crtc->state;
98 struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
99 struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
100 bool pll_locked = false;
101 unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
102 u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
103 int i, j, tmpcount, vcount;
104
105 pixpllcm = pixpllc->m - 1;
106 pixpllcn = pixpllc->n - 1;
107 pixpllcp = pixpllc->p - 1;
108 pixpllcs = pixpllc->s;
109
110 xpixpllcm = ((pixpllcn & BIT(8)) >> 1) | pixpllcm;
111 xpixpllcn = pixpllcn;
112 xpixpllcp = ((pixpllcn & GENMASK(10, 9)) >> 3) | (pixpllcs << 3) | pixpllcp;
113
114 WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
115
116 for (i = 0; i <= 32 && pll_locked == false; i++) {
117 if (i > 0) {
118 WREG8(MGAREG_CRTC_INDEX, 0x1e);
119 tmp = RREG8(MGAREG_CRTC_DATA);
120 if (tmp < 0xff)
121 WREG8(MGAREG_CRTC_DATA, tmp+1);
122 }
123
124 /* set pixclkdis to 1 */
125 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
126 tmp = RREG8(DAC_DATA);
127 tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
128 WREG8(DAC_DATA, tmp);
129
130 WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
131 tmp = RREG8(DAC_DATA);
132 tmp |= MGA1064_REMHEADCTL_CLKDIS;
133 WREG8(DAC_DATA, tmp);
134
135 /* select PLL Set C */
136 tmp = RREG8(MGAREG_MEM_MISC_READ);
137 tmp |= 0x3 << 2;
138 WREG8(MGAREG_MEM_MISC_WRITE, tmp);
139
140 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
141 tmp = RREG8(DAC_DATA);
142 tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80;
143 WREG8(DAC_DATA, tmp);
144
145 udelay(500);
146
147 /* reset the PLL */
148 WREG8(DAC_INDEX, MGA1064_VREF_CTL);
149 tmp = RREG8(DAC_DATA);
150 tmp &= ~0x04;
151 WREG8(DAC_DATA, tmp);
152
153 udelay(50);
154
155 /* program pixel pll register */
156 WREG_DAC(MGA1064_WB_PIX_PLLC_N, xpixpllcn);
157 WREG_DAC(MGA1064_WB_PIX_PLLC_M, xpixpllcm);
158 WREG_DAC(MGA1064_WB_PIX_PLLC_P, xpixpllcp);
159
160 udelay(50);
161
162 /* turn pll on */
163 WREG8(DAC_INDEX, MGA1064_VREF_CTL);
164 tmp = RREG8(DAC_DATA);
165 tmp |= 0x04;
166 WREG_DAC(MGA1064_VREF_CTL, tmp);
167
168 udelay(500);
169
170 /* select the pixel pll */
171 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
172 tmp = RREG8(DAC_DATA);
173 tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
174 tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
175 WREG8(DAC_DATA, tmp);
176
177 WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
178 tmp = RREG8(DAC_DATA);
179 tmp &= ~MGA1064_REMHEADCTL_CLKSL_MSK;
180 tmp |= MGA1064_REMHEADCTL_CLKSL_PLL;
181 WREG8(DAC_DATA, tmp);
182
183 /* reset dotclock rate bit */
184 WREG8(MGAREG_SEQ_INDEX, 1);
185 tmp = RREG8(MGAREG_SEQ_DATA);
186 tmp &= ~0x8;
187 WREG8(MGAREG_SEQ_DATA, tmp);
188
189 WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
190 tmp = RREG8(DAC_DATA);
191 tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
192 WREG8(DAC_DATA, tmp);
193
194 vcount = RREG8(MGAREG_VCOUNT);
195
196 for (j = 0; j < 30 && pll_locked == false; j++) {
197 tmpcount = RREG8(MGAREG_VCOUNT);
198 if (tmpcount < vcount)
199 vcount = 0;
200 if ((tmpcount - vcount) > 2)
201 pll_locked = true;
202 else
203 udelay(5);
204 }
205 }
206
207 WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
208 tmp = RREG8(DAC_DATA);
209 tmp &= ~MGA1064_REMHEADCTL_CLKDIS;
210 WREG_DAC(MGA1064_REMHEADCTL, tmp);
211}
212
213/*
214 * Mode-setting pipeline
215 */
216
217static const struct drm_plane_helper_funcs mgag200_g200wb_primary_plane_helper_funcs = {
218 MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
219};
220
221static const struct drm_plane_funcs mgag200_g200wb_primary_plane_funcs = {
222 MGAG200_PRIMARY_PLANE_FUNCS,
223};
224
225static const struct drm_crtc_helper_funcs mgag200_g200wb_crtc_helper_funcs = {
226 MGAG200_CRTC_HELPER_FUNCS,
227};
228
229static const struct drm_crtc_funcs mgag200_g200wb_crtc_funcs = {
230 MGAG200_CRTC_FUNCS,
231};
232
233static int mgag200_g200wb_pipeline_init(struct mga_device *mdev)
234{
235 struct drm_device *dev = &mdev->base;
236 struct drm_plane *primary_plane = &mdev->primary_plane;
237 struct drm_crtc *crtc = &mdev->crtc;
238 int ret;
239
240 ret = drm_universal_plane_init(dev, primary_plane, 0,
241 &mgag200_g200wb_primary_plane_funcs,
242 mgag200_primary_plane_formats,
243 mgag200_primary_plane_formats_size,
244 mgag200_primary_plane_fmtmods,
245 DRM_PLANE_TYPE_PRIMARY, NULL);
246 if (ret) {
247 drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
248 return ret;
249 }
250 drm_plane_helper_add(primary_plane, &mgag200_g200wb_primary_plane_helper_funcs);
251 drm_plane_enable_fb_damage_clips(primary_plane);
252
253 ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
254 &mgag200_g200wb_crtc_funcs, NULL);
255 if (ret) {
256 drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
257 return ret;
258 }
259 drm_crtc_helper_add(crtc, &mgag200_g200wb_crtc_helper_funcs);
260
261 /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
262 drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
263 drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
264
265 ret = mgag200_vga_bmc_output_init(mdev);
266 if (ret)
267 return ret;
268
269 return 0;
270}
271
272/*
273 * DRM device
274 */
275
276static const struct mgag200_device_info mgag200_g200wb_device_info =
277 MGAG200_DEVICE_INFO_INIT(1280, 1024, 31877, true, 0, 1, false);
278
279static const struct mgag200_device_funcs mgag200_g200wb_device_funcs = {
280 .pixpllc_atomic_check = mgag200_g200wb_pixpllc_atomic_check,
281 .pixpllc_atomic_update = mgag200_g200wb_pixpllc_atomic_update,
282};
283
284struct mga_device *mgag200_g200wb_device_create(struct pci_dev *pdev, const struct drm_driver *drv)
285{
286 struct mga_device *mdev;
287 struct drm_device *dev;
288 resource_size_t vram_available;
289 int ret;
290
291 mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base);
292 if (IS_ERR(mdev))
293 return mdev;
294 dev = &mdev->base;
295
296 pci_set_drvdata(pdev, dev);
297
298 ret = mgag200_init_pci_options(pdev, 0x41049120, 0x0000b000);
299 if (ret)
300 return ERR_PTR(ret);
301
302 ret = mgag200_device_preinit(mdev);
303 if (ret)
304 return ERR_PTR(ret);
305
306 ret = mgag200_device_init(mdev, &mgag200_g200wb_device_info,
307 &mgag200_g200wb_device_funcs);
308 if (ret)
309 return ERR_PTR(ret);
310
311 mgag200_g200wb_init_registers(mdev);
312
313 vram_available = mgag200_device_probe_vram(mdev);
314
315 ret = mgag200_mode_config_init(mdev, vram_available);
316 if (ret)
317 return ERR_PTR(ret);
318
319 ret = mgag200_g200wb_pipeline_init(mdev);
320 if (ret)
321 return ERR_PTR(ret);
322
323 drm_mode_config_reset(dev);
324 drm_kms_helper_poll_init(dev);
325
326 return mdev;
327}