]> Git Repo - linux.git/blob - drivers/gpu/drm/mgag200/mgag200_g200er.c
Linux 6.14-rc3
[linux.git] / drivers / gpu / drm / mgag200 / mgag200_g200er.c
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_g200er_init_registers(struct mga_device *mdev)
15 {
16         static const u8 dacvalue[] = {
17                 MGAG200_DAC_DEFAULT(0x00, 0xc9, 0x1f, 0x00, 0x00, 0x00)
18         };
19
20         size_t i;
21
22         for (i = 0; i < ARRAY_SIZE(dacvalue); i++) {
23                 if ((i <= 0x17) ||
24                     (i == 0x1b) ||
25                     (i == 0x1c) ||
26                     ((i >= 0x1f) && (i <= 0x29)) ||
27                     ((i >= 0x30) && (i <= 0x37)))
28                         continue;
29                 WREG_DAC(i, dacvalue[i]);
30         }
31
32         WREG_DAC(0x90, 0); /* G200ER specific */
33
34         mgag200_init_registers(mdev);
35
36         WREG_ECRT(0x24, 0x5); /* G200ER specific */
37 }
38
39 static void mgag200_g200er_reset_tagfifo(struct mga_device *mdev)
40 {
41         static const uint32_t RESET_FLAG = 0x00200000; /* undocumented magic value */
42         u32 memctl;
43
44         memctl = RREG32(MGAREG_MEMCTL);
45
46         memctl |= RESET_FLAG;
47         WREG32(MGAREG_MEMCTL, memctl);
48
49         udelay(1000);
50
51         memctl &= ~RESET_FLAG;
52         WREG32(MGAREG_MEMCTL, memctl);
53 }
54
55 /*
56  * PIXPLLC
57  */
58
59 static int mgag200_g200er_pixpllc_atomic_check(struct drm_crtc *crtc,
60                                                struct drm_atomic_state *new_state)
61 {
62         static const unsigned int vcomax = 1488000;
63         static const unsigned int vcomin = 1056000;
64         static const unsigned int pllreffreq = 48000;
65         static const unsigned int m_div_val[] = { 1, 2, 4, 8 };
66
67         struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
68         struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
69         long clock = new_crtc_state->mode.clock;
70         struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
71         unsigned int delta, tmpdelta;
72         int testr, testn, testm, testo;
73         unsigned int p, m, n, s;
74         unsigned int computed, vco;
75
76         m = n = p = s = 0;
77         delta = 0xffffffff;
78
79         for (testr = 0; testr < 4; testr++) {
80                 if (delta == 0)
81                         break;
82                 for (testn = 5; testn < 129; testn++) {
83                         if (delta == 0)
84                                 break;
85                         for (testm = 3; testm >= 0; testm--) {
86                                 if (delta == 0)
87                                         break;
88                                 for (testo = 5; testo < 33; testo++) {
89                                         vco = pllreffreq * (testn + 1) /
90                                                 (testr + 1);
91                                         if (vco < vcomin)
92                                                 continue;
93                                         if (vco > vcomax)
94                                                 continue;
95                                         computed = vco / (m_div_val[testm] * (testo + 1));
96                                         if (computed > clock)
97                                                 tmpdelta = computed - clock;
98                                         else
99                                                 tmpdelta = clock - computed;
100                                         if (tmpdelta < delta) {
101                                                 delta = tmpdelta;
102                                                 m = (testm | (testo << 3)) + 1;
103                                                 n = testn + 1;
104                                                 p = testr + 1;
105                                                 s = testr;
106                                         }
107                                 }
108                         }
109                 }
110         }
111
112         pixpllc->m = m;
113         pixpllc->n = n;
114         pixpllc->p = p;
115         pixpllc->s = s;
116
117         return 0;
118 }
119
120 static void mgag200_g200er_pixpllc_atomic_update(struct drm_crtc *crtc,
121                                                  struct drm_atomic_state *old_state)
122 {
123         struct drm_device *dev = crtc->dev;
124         struct mga_device *mdev = to_mga_device(dev);
125         struct drm_crtc_state *crtc_state = crtc->state;
126         struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
127         struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
128         unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
129         u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
130
131         pixpllcm = pixpllc->m - 1;
132         pixpllcn = pixpllc->n - 1;
133         pixpllcp = pixpllc->p - 1;
134         pixpllcs = pixpllc->s;
135
136         xpixpllcm = pixpllcm;
137         xpixpllcn = pixpllcn;
138         xpixpllcp = (pixpllcs << 3) | pixpllcp;
139
140         WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
141
142         WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
143         tmp = RREG8(DAC_DATA);
144         tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
145         WREG8(DAC_DATA, tmp);
146
147         WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
148         tmp = RREG8(DAC_DATA);
149         tmp |= MGA1064_REMHEADCTL_CLKDIS;
150         WREG8(DAC_DATA, tmp);
151
152         tmp = RREG8(MGAREG_MEM_MISC_READ);
153         tmp |= (0x3<<2) | 0xc0;
154         WREG8(MGAREG_MEM_MISC_WRITE, tmp);
155
156         WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
157         tmp = RREG8(DAC_DATA);
158         tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
159         tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
160         WREG8(DAC_DATA, tmp);
161
162         udelay(500);
163
164         WREG_DAC(MGA1064_ER_PIX_PLLC_N, xpixpllcn);
165         WREG_DAC(MGA1064_ER_PIX_PLLC_M, xpixpllcm);
166         WREG_DAC(MGA1064_ER_PIX_PLLC_P, xpixpllcp);
167
168         udelay(50);
169 }
170
171 /*
172  * Mode-setting pipeline
173  */
174
175 static const struct drm_plane_helper_funcs mgag200_g200er_primary_plane_helper_funcs = {
176         MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
177 };
178
179 static const struct drm_plane_funcs mgag200_g200er_primary_plane_funcs = {
180         MGAG200_PRIMARY_PLANE_FUNCS,
181 };
182
183 static void mgag200_g200er_crtc_helper_atomic_enable(struct drm_crtc *crtc,
184                                                      struct drm_atomic_state *old_state)
185 {
186         struct drm_device *dev = crtc->dev;
187         struct mga_device *mdev = to_mga_device(dev);
188         const struct mgag200_device_funcs *funcs = mdev->funcs;
189         struct drm_crtc_state *crtc_state = crtc->state;
190         struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
191         struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
192         const struct drm_format_info *format = mgag200_crtc_state->format;
193
194         mgag200_set_format_regs(mdev, format);
195         mgag200_set_mode_regs(mdev, adjusted_mode, mgag200_crtc_state->set_vidrst);
196
197         if (funcs->pixpllc_atomic_update)
198                 funcs->pixpllc_atomic_update(crtc, old_state);
199
200         mgag200_g200er_reset_tagfifo(mdev);
201
202         if (crtc_state->gamma_lut)
203                 mgag200_crtc_set_gamma(mdev, format, crtc_state->gamma_lut->data);
204         else
205                 mgag200_crtc_set_gamma_linear(mdev, format);
206
207         mgag200_enable_display(mdev);
208 }
209
210 static const struct drm_crtc_helper_funcs mgag200_g200er_crtc_helper_funcs = {
211         .mode_valid = mgag200_crtc_helper_mode_valid,
212         .atomic_check = mgag200_crtc_helper_atomic_check,
213         .atomic_flush = mgag200_crtc_helper_atomic_flush,
214         .atomic_enable = mgag200_g200er_crtc_helper_atomic_enable,
215         .atomic_disable = mgag200_crtc_helper_atomic_disable
216 };
217
218 static const struct drm_crtc_funcs mgag200_g200er_crtc_funcs = {
219         MGAG200_CRTC_FUNCS,
220 };
221
222 static int mgag200_g200er_pipeline_init(struct mga_device *mdev)
223 {
224         struct drm_device *dev = &mdev->base;
225         struct drm_plane *primary_plane = &mdev->primary_plane;
226         struct drm_crtc *crtc = &mdev->crtc;
227         int ret;
228
229         ret = drm_universal_plane_init(dev, primary_plane, 0,
230                                        &mgag200_g200er_primary_plane_funcs,
231                                        mgag200_primary_plane_formats,
232                                        mgag200_primary_plane_formats_size,
233                                        mgag200_primary_plane_fmtmods,
234                                        DRM_PLANE_TYPE_PRIMARY, NULL);
235         if (ret) {
236                 drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
237                 return ret;
238         }
239         drm_plane_helper_add(primary_plane, &mgag200_g200er_primary_plane_helper_funcs);
240         drm_plane_enable_fb_damage_clips(primary_plane);
241
242         ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
243                                         &mgag200_g200er_crtc_funcs, NULL);
244         if (ret) {
245                 drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
246                 return ret;
247         }
248         drm_crtc_helper_add(crtc, &mgag200_g200er_crtc_helper_funcs);
249
250         /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
251         drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
252         drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
253
254         ret = mgag200_vga_bmc_output_init(mdev);
255         if (ret)
256                 return ret;
257
258         return 0;
259 }
260
261 /*
262  * DRM device
263  */
264
265 static const struct mgag200_device_info mgag200_g200er_device_info =
266         MGAG200_DEVICE_INFO_INIT(2048, 2048, 55000, false, 1, 0, false);
267
268 static const struct mgag200_device_funcs mgag200_g200er_device_funcs = {
269         .pixpllc_atomic_check = mgag200_g200er_pixpllc_atomic_check,
270         .pixpllc_atomic_update = mgag200_g200er_pixpllc_atomic_update,
271 };
272
273 struct mga_device *mgag200_g200er_device_create(struct pci_dev *pdev, const struct drm_driver *drv)
274 {
275         struct mga_device *mdev;
276         struct drm_device *dev;
277         resource_size_t vram_available;
278         int ret;
279
280         mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base);
281         if (IS_ERR(mdev))
282                 return mdev;
283         dev = &mdev->base;
284
285         pci_set_drvdata(pdev, dev);
286
287         ret = mgag200_device_preinit(mdev);
288         if (ret)
289                 return ERR_PTR(ret);
290
291         ret = mgag200_device_init(mdev, &mgag200_g200er_device_info,
292                                   &mgag200_g200er_device_funcs);
293         if (ret)
294                 return ERR_PTR(ret);
295
296         mgag200_g200er_init_registers(mdev);
297
298         vram_available = mgag200_device_probe_vram(mdev);
299
300         ret = mgag200_mode_config_init(mdev, vram_available);
301         if (ret)
302                 return ERR_PTR(ret);
303
304         ret = mgag200_g200er_pipeline_init(mdev);
305         if (ret)
306                 return ERR_PTR(ret);
307
308         drm_mode_config_reset(dev);
309         drm_kms_helper_poll_init(dev);
310
311         return mdev;
312 }
This page took 0.048852 seconds and 4 git commands to generate.