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 | void mgag200_g200eh_init_registers(struct mga_device *mdev) |
15 | { |
16 | static const u8 dacvalue[] = { |
17 | MGAG200_DAC_DEFAULT(0x00, 0xc9, |
18 | MGA1064_MISC_CTL_VGA8 | MGA1064_MISC_CTL_DAC_RAM_CS, |
19 | 0x00, 0x00, 0x00) |
20 | }; |
21 | |
22 | size_t i; |
23 | |
24 | for (i = 0; i < ARRAY_SIZE(dacvalue); i++) { |
25 | if ((i <= 0x17) || |
26 | (i == 0x1b) || |
27 | (i == 0x1c) || |
28 | ((i >= 0x1f) && (i <= 0x29)) || |
29 | ((i >= 0x30) && (i <= 0x37)) || |
30 | ((i >= 0x44) && (i <= 0x4e))) |
31 | continue; |
32 | WREG_DAC(i, dacvalue[i]); |
33 | } |
34 | |
35 | mgag200_init_registers(mdev); |
36 | } |
37 | |
38 | /* |
39 | * PIXPLLC |
40 | */ |
41 | |
42 | static int mgag200_g200eh_pixpllc_atomic_check(struct drm_crtc *crtc, |
43 | struct drm_atomic_state *new_state) |
44 | { |
45 | static const unsigned int vcomax = 800000; |
46 | static const unsigned int vcomin = 400000; |
47 | static const unsigned int pllreffreq = 33333; |
48 | |
49 | struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(state: new_state, crtc); |
50 | struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(base: new_crtc_state); |
51 | long clock = new_crtc_state->mode.clock; |
52 | struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc; |
53 | unsigned int delta, tmpdelta; |
54 | unsigned int testp, testm, testn; |
55 | unsigned int p, m, n, s; |
56 | unsigned int computed; |
57 | |
58 | m = n = p = s = 0; |
59 | delta = 0xffffffff; |
60 | |
61 | for (testp = 16; testp > 0; testp >>= 1) { |
62 | if (clock * testp > vcomax) |
63 | continue; |
64 | if (clock * testp < vcomin) |
65 | continue; |
66 | |
67 | for (testm = 1; testm < 33; testm++) { |
68 | for (testn = 17; testn < 257; testn++) { |
69 | computed = (pllreffreq * testn) / (testm * testp); |
70 | if (computed > clock) |
71 | tmpdelta = computed - clock; |
72 | else |
73 | tmpdelta = clock - computed; |
74 | if (tmpdelta < delta) { |
75 | delta = tmpdelta; |
76 | n = testn; |
77 | m = testm; |
78 | p = testp; |
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 | |
92 | void mgag200_g200eh_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(base: crtc_state); |
99 | struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc; |
100 | unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs; |
101 | u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp; |
102 | int i, j, tmpcount, vcount; |
103 | bool pll_locked = false; |
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 = (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 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); |
118 | tmp = RREG8(DAC_DATA); |
119 | tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS; |
120 | WREG8(DAC_DATA, tmp); |
121 | |
122 | tmp = RREG8(MGAREG_MEM_MISC_READ); |
123 | tmp |= 0x3 << 2; |
124 | WREG8(MGAREG_MEM_MISC_WRITE, tmp); |
125 | |
126 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); |
127 | tmp = RREG8(DAC_DATA); |
128 | tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; |
129 | WREG8(DAC_DATA, tmp); |
130 | |
131 | udelay(500); |
132 | |
133 | WREG_DAC(MGA1064_EH_PIX_PLLC_M, xpixpllcm); |
134 | WREG_DAC(MGA1064_EH_PIX_PLLC_N, xpixpllcn); |
135 | WREG_DAC(MGA1064_EH_PIX_PLLC_P, xpixpllcp); |
136 | |
137 | udelay(500); |
138 | |
139 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); |
140 | tmp = RREG8(DAC_DATA); |
141 | tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK; |
142 | tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL; |
143 | WREG8(DAC_DATA, tmp); |
144 | |
145 | WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL); |
146 | tmp = RREG8(DAC_DATA); |
147 | tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS; |
148 | tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN; |
149 | WREG8(DAC_DATA, tmp); |
150 | |
151 | vcount = RREG8(MGAREG_VCOUNT); |
152 | |
153 | for (j = 0; j < 30 && pll_locked == false; j++) { |
154 | tmpcount = RREG8(MGAREG_VCOUNT); |
155 | if (tmpcount < vcount) |
156 | vcount = 0; |
157 | if ((tmpcount - vcount) > 2) |
158 | pll_locked = true; |
159 | else |
160 | udelay(5); |
161 | } |
162 | } |
163 | } |
164 | |
165 | /* |
166 | * Mode-setting pipeline |
167 | */ |
168 | |
169 | static const struct drm_plane_helper_funcs mgag200_g200eh_primary_plane_helper_funcs = { |
170 | MGAG200_PRIMARY_PLANE_HELPER_FUNCS, |
171 | }; |
172 | |
173 | static const struct drm_plane_funcs mgag200_g200eh_primary_plane_funcs = { |
174 | MGAG200_PRIMARY_PLANE_FUNCS, |
175 | }; |
176 | |
177 | static const struct drm_crtc_helper_funcs mgag200_g200eh_crtc_helper_funcs = { |
178 | MGAG200_CRTC_HELPER_FUNCS, |
179 | }; |
180 | |
181 | static const struct drm_crtc_funcs mgag200_g200eh_crtc_funcs = { |
182 | MGAG200_CRTC_FUNCS, |
183 | }; |
184 | |
185 | static const struct drm_encoder_funcs mgag200_g200eh_dac_encoder_funcs = { |
186 | MGAG200_DAC_ENCODER_FUNCS, |
187 | }; |
188 | |
189 | static const struct drm_connector_helper_funcs mgag200_g200eh_vga_connector_helper_funcs = { |
190 | MGAG200_VGA_CONNECTOR_HELPER_FUNCS, |
191 | }; |
192 | |
193 | static const struct drm_connector_funcs mgag200_g200eh_vga_connector_funcs = { |
194 | MGAG200_VGA_CONNECTOR_FUNCS, |
195 | }; |
196 | |
197 | static int mgag200_g200eh_pipeline_init(struct mga_device *mdev) |
198 | { |
199 | struct drm_device *dev = &mdev->base; |
200 | struct drm_plane *primary_plane = &mdev->primary_plane; |
201 | struct drm_crtc *crtc = &mdev->crtc; |
202 | struct drm_encoder *encoder = &mdev->encoder; |
203 | struct mga_i2c_chan *i2c = &mdev->i2c; |
204 | struct drm_connector *connector = &mdev->connector; |
205 | int ret; |
206 | |
207 | ret = drm_universal_plane_init(dev, plane: primary_plane, possible_crtcs: 0, |
208 | funcs: &mgag200_g200eh_primary_plane_funcs, |
209 | formats: mgag200_primary_plane_formats, |
210 | format_count: mgag200_primary_plane_formats_size, |
211 | format_modifiers: mgag200_primary_plane_fmtmods, |
212 | type: DRM_PLANE_TYPE_PRIMARY, NULL); |
213 | if (ret) { |
214 | drm_err(dev, "drm_universal_plane_init() failed: %d\n" , ret); |
215 | return ret; |
216 | } |
217 | drm_plane_helper_add(plane: primary_plane, funcs: &mgag200_g200eh_primary_plane_helper_funcs); |
218 | drm_plane_enable_fb_damage_clips(plane: primary_plane); |
219 | |
220 | ret = drm_crtc_init_with_planes(dev, crtc, primary: primary_plane, NULL, |
221 | funcs: &mgag200_g200eh_crtc_funcs, NULL); |
222 | if (ret) { |
223 | drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n" , ret); |
224 | return ret; |
225 | } |
226 | drm_crtc_helper_add(crtc, funcs: &mgag200_g200eh_crtc_helper_funcs); |
227 | |
228 | /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */ |
229 | drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE); |
230 | drm_crtc_enable_color_mgmt(crtc, degamma_lut_size: 0, has_ctm: false, MGAG200_LUT_SIZE); |
231 | |
232 | encoder->possible_crtcs = drm_crtc_mask(crtc); |
233 | ret = drm_encoder_init(dev, encoder, funcs: &mgag200_g200eh_dac_encoder_funcs, |
234 | DRM_MODE_ENCODER_DAC, NULL); |
235 | if (ret) { |
236 | drm_err(dev, "drm_encoder_init() failed: %d\n" , ret); |
237 | return ret; |
238 | } |
239 | |
240 | ret = mgag200_i2c_init(mdev, i2c); |
241 | if (ret) { |
242 | drm_err(dev, "failed to add DDC bus: %d\n" , ret); |
243 | return ret; |
244 | } |
245 | |
246 | ret = drm_connector_init_with_ddc(dev, connector, |
247 | funcs: &mgag200_g200eh_vga_connector_funcs, |
248 | DRM_MODE_CONNECTOR_VGA, |
249 | ddc: &i2c->adapter); |
250 | if (ret) { |
251 | drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n" , ret); |
252 | return ret; |
253 | } |
254 | drm_connector_helper_add(connector, funcs: &mgag200_g200eh_vga_connector_helper_funcs); |
255 | |
256 | ret = drm_connector_attach_encoder(connector, encoder); |
257 | if (ret) { |
258 | drm_err(dev, "drm_connector_attach_encoder() failed: %d\n" , ret); |
259 | return ret; |
260 | } |
261 | |
262 | return 0; |
263 | } |
264 | |
265 | /* |
266 | * DRM device |
267 | */ |
268 | |
269 | static const struct mgag200_device_info mgag200_g200eh_device_info = |
270 | MGAG200_DEVICE_INFO_INIT(2048, 2048, 37500, false, 1, 0, false); |
271 | |
272 | static const struct mgag200_device_funcs mgag200_g200eh_device_funcs = { |
273 | .pixpllc_atomic_check = mgag200_g200eh_pixpllc_atomic_check, |
274 | .pixpllc_atomic_update = mgag200_g200eh_pixpllc_atomic_update, |
275 | }; |
276 | |
277 | struct mga_device *mgag200_g200eh_device_create(struct pci_dev *pdev, const struct drm_driver *drv) |
278 | { |
279 | struct mga_device *mdev; |
280 | struct drm_device *dev; |
281 | resource_size_t vram_available; |
282 | int ret; |
283 | |
284 | mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base); |
285 | if (IS_ERR(ptr: mdev)) |
286 | return mdev; |
287 | dev = &mdev->base; |
288 | |
289 | pci_set_drvdata(pdev, data: dev); |
290 | |
291 | ret = mgag200_init_pci_options(pdev, option: 0x00000120, option2: 0x0000b000); |
292 | if (ret) |
293 | return ERR_PTR(error: ret); |
294 | |
295 | ret = mgag200_device_preinit(mdev); |
296 | if (ret) |
297 | return ERR_PTR(error: ret); |
298 | |
299 | ret = mgag200_device_init(mdev, info: &mgag200_g200eh_device_info, |
300 | funcs: &mgag200_g200eh_device_funcs); |
301 | if (ret) |
302 | return ERR_PTR(error: ret); |
303 | |
304 | mgag200_g200eh_init_registers(mdev); |
305 | |
306 | vram_available = mgag200_device_probe_vram(mdev); |
307 | |
308 | ret = mgag200_mode_config_init(mdev, vram_available); |
309 | if (ret) |
310 | return ERR_PTR(error: ret); |
311 | |
312 | ret = mgag200_g200eh_pipeline_init(mdev); |
313 | if (ret) |
314 | return ERR_PTR(error: ret); |
315 | |
316 | drm_mode_config_reset(dev); |
317 | |
318 | return mdev; |
319 | } |
320 | |