drm/mgag200: Move mode-config to model-specific code
[linux-2.6-microblaze.git] / drivers / gpu / drm / mgag200 / mgag200_g200ev.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_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 /*
40  * PIXPLLC
41  */
42
43 static int mgag200_g200ev_pixpllc_atomic_check(struct drm_crtc *crtc,
44                                                struct drm_atomic_state *new_state)
45 {
46         static const unsigned int vcomax = 550000;
47         static const unsigned int vcomin = 150000;
48         static const unsigned int pllreffreq = 50000;
49
50         struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
51         struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
52         long clock = new_crtc_state->mode.clock;
53         struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
54         unsigned int delta, tmpdelta;
55         unsigned int testp, testm, testn;
56         unsigned int p, m, n, s;
57         unsigned int computed;
58
59         m = n = p = s = 0;
60         delta = 0xffffffff;
61
62         for (testp = 16; testp > 0; testp--) {
63                 if (clock * testp > vcomax)
64                         continue;
65                 if (clock * testp < vcomin)
66                         continue;
67
68                 for (testn = 1; testn < 257; testn++) {
69                         for (testm = 1; testm < 17; testm++) {
70                                 computed = (pllreffreq * testn) /
71                                         (testm * testp);
72                                 if (computed > clock)
73                                         tmpdelta = computed - clock;
74                                 else
75                                         tmpdelta = clock - computed;
76                                 if (tmpdelta < delta) {
77                                         delta = tmpdelta;
78                                         n = testn;
79                                         m = testm;
80                                         p = testp;
81                                 }
82                         }
83                 }
84         }
85
86         pixpllc->m = m;
87         pixpllc->n = n;
88         pixpllc->p = p;
89         pixpllc->s = s;
90
91         return 0;
92 }
93
94 static void mgag200_g200ev_pixpllc_atomic_update(struct drm_crtc *crtc,
95                                                  struct drm_atomic_state *old_state)
96 {
97         struct drm_device *dev = crtc->dev;
98         struct mga_device *mdev = to_mga_device(dev);
99         struct drm_crtc_state *crtc_state = crtc->state;
100         struct mgag200_crtc_state *mgag200_crtc_state = to_mgag200_crtc_state(crtc_state);
101         struct mgag200_pll_values *pixpllc = &mgag200_crtc_state->pixpllc;
102         unsigned int pixpllcm, pixpllcn, pixpllcp, pixpllcs;
103         u8 xpixpllcm, xpixpllcn, xpixpllcp, tmp;
104
105         pixpllcm = pixpllc->m - 1;
106         pixpllcn = pixpllc->n - 1;
107         pixpllcp = pixpllc->p - 1;
108         pixpllcs = pixpllc->s;
109
110         xpixpllcm = pixpllcm;
111         xpixpllcn = pixpllcn;
112         xpixpllcp = (pixpllcs << 3) | pixpllcp;
113
114         WREG_MISC_MASKED(MGAREG_MISC_CLKSEL_MGA, MGAREG_MISC_CLKSEL_MASK);
115
116         WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
117         tmp = RREG8(DAC_DATA);
118         tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
119         WREG8(DAC_DATA, tmp);
120
121         tmp = RREG8(MGAREG_MEM_MISC_READ);
122         tmp |= 0x3 << 2;
123         WREG8(MGAREG_MEM_MISC_WRITE, tmp);
124
125         WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);
126         tmp = RREG8(DAC_DATA);
127         WREG8(DAC_DATA, tmp & ~0x40);
128
129         WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
130         tmp = RREG8(DAC_DATA);
131         tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
132         WREG8(DAC_DATA, tmp);
133
134         WREG_DAC(MGA1064_EV_PIX_PLLC_M, xpixpllcm);
135         WREG_DAC(MGA1064_EV_PIX_PLLC_N, xpixpllcn);
136         WREG_DAC(MGA1064_EV_PIX_PLLC_P, xpixpllcp);
137
138         udelay(50);
139
140         WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
141         tmp = RREG8(DAC_DATA);
142         tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
143         WREG8(DAC_DATA, tmp);
144
145         udelay(500);
146
147         WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
148         tmp = RREG8(DAC_DATA);
149         tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
150         tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
151         WREG8(DAC_DATA, tmp);
152
153         WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);
154         tmp = RREG8(DAC_DATA);
155         WREG8(DAC_DATA, tmp | 0x40);
156
157         tmp = RREG8(MGAREG_MEM_MISC_READ);
158         tmp |= (0x3 << 2);
159         WREG8(MGAREG_MEM_MISC_WRITE, tmp);
160
161         WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
162         tmp = RREG8(DAC_DATA);
163         tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
164         WREG8(DAC_DATA, tmp);
165 }
166
167 /*
168  * Mode-setting pipeline
169  */
170
171 static const struct drm_plane_helper_funcs mgag200_g200ev_primary_plane_helper_funcs = {
172         MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
173 };
174
175 static const struct drm_plane_funcs mgag200_g200ev_primary_plane_funcs = {
176         MGAG200_PRIMARY_PLANE_FUNCS,
177 };
178
179 static const struct drm_crtc_helper_funcs mgag200_g200ev_crtc_helper_funcs = {
180         MGAG200_CRTC_HELPER_FUNCS,
181 };
182
183 static const struct drm_crtc_funcs mgag200_g200ev_crtc_funcs = {
184         MGAG200_CRTC_FUNCS,
185 };
186
187 static const struct drm_encoder_funcs mgag200_g200ev_dac_encoder_funcs = {
188         MGAG200_DAC_ENCODER_FUNCS,
189 };
190
191 static const struct drm_connector_helper_funcs mgag200_g200ev_vga_connector_helper_funcs = {
192         MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
193 };
194
195 static const struct drm_connector_funcs mgag200_g200ev_vga_connector_funcs = {
196         MGAG200_VGA_CONNECTOR_FUNCS,
197 };
198
199 static int mgag200_g200ev_pipeline_init(struct mga_device *mdev)
200 {
201         struct drm_device *dev = &mdev->base;
202         struct drm_plane *primary_plane = &mdev->primary_plane;
203         struct drm_crtc *crtc = &mdev->crtc;
204         struct drm_encoder *encoder = &mdev->encoder;
205         struct mga_i2c_chan *i2c = &mdev->i2c;
206         struct drm_connector *connector = &mdev->connector;
207         int ret;
208
209         ret = drm_universal_plane_init(dev, primary_plane, 0,
210                                        &mgag200_g200ev_primary_plane_funcs,
211                                        mgag200_primary_plane_formats,
212                                        mgag200_primary_plane_formats_size,
213                                        mgag200_primary_plane_fmtmods,
214                                        DRM_PLANE_TYPE_PRIMARY, NULL);
215         if (ret) {
216                 drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
217                 return ret;
218         }
219         drm_plane_helper_add(primary_plane, &mgag200_g200ev_primary_plane_helper_funcs);
220         drm_plane_enable_fb_damage_clips(primary_plane);
221
222         ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
223                                         &mgag200_g200ev_crtc_funcs, NULL);
224         if (ret) {
225                 drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
226                 return ret;
227         }
228         drm_crtc_helper_add(crtc, &mgag200_g200ev_crtc_helper_funcs);
229
230         /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
231         drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
232         drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
233
234         encoder->possible_crtcs = drm_crtc_mask(crtc);
235         ret = drm_encoder_init(dev, encoder, &mgag200_g200ev_dac_encoder_funcs,
236                                DRM_MODE_ENCODER_DAC, NULL);
237         if (ret) {
238                 drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
239                 return ret;
240         }
241
242         ret = mgag200_i2c_init(mdev, i2c);
243         if (ret) {
244                 drm_err(dev, "failed to add DDC bus: %d\n", ret);
245                 return ret;
246         }
247
248         ret = drm_connector_init_with_ddc(dev, connector,
249                                           &mgag200_g200ev_vga_connector_funcs,
250                                           DRM_MODE_CONNECTOR_VGA,
251                                           &i2c->adapter);
252         if (ret) {
253                 drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
254                 return ret;
255         }
256         drm_connector_helper_add(connector, &mgag200_g200ev_vga_connector_helper_funcs);
257
258         ret = drm_connector_attach_encoder(connector, encoder);
259         if (ret) {
260                 drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
261                 return ret;
262         }
263
264         return 0;
265 }
266
267 /*
268  * DRM device
269  */
270
271 static const struct mgag200_device_info mgag200_g200ev_device_info =
272         MGAG200_DEVICE_INFO_INIT(2048, 2048, 32700, false, 0, 1, false);
273
274 static const struct mgag200_device_funcs mgag200_g200ev_device_funcs = {
275         .pixpllc_atomic_check = mgag200_g200ev_pixpllc_atomic_check,
276         .pixpllc_atomic_update = mgag200_g200ev_pixpllc_atomic_update,
277 };
278
279 struct mga_device *mgag200_g200ev_device_create(struct pci_dev *pdev, const struct drm_driver *drv,
280                                                 enum mga_type type)
281 {
282         struct mga_device *mdev;
283         struct drm_device *dev;
284         resource_size_t vram_available;
285         int ret;
286
287         mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base);
288         if (IS_ERR(mdev))
289                 return mdev;
290         dev = &mdev->base;
291
292         pci_set_drvdata(pdev, dev);
293
294         ret = mgag200_init_pci_options(pdev, 0x00000120, 0x0000b000);
295         if (ret)
296                 return ERR_PTR(ret);
297
298         ret = mgag200_device_preinit(mdev);
299         if (ret)
300                 return ERR_PTR(ret);
301
302         ret = mgag200_device_init(mdev, type, &mgag200_g200ev_device_info,
303                                   &mgag200_g200ev_device_funcs);
304         if (ret)
305                 return ERR_PTR(ret);
306
307         mgag200_g200ev_init_registers(mdev);
308
309         vram_available = mgag200_device_probe_vram(mdev);
310
311         ret = mgag200_mode_config_init(mdev, vram_available);
312         if (ret)
313                 return ERR_PTR(ret);
314
315         ret = mgag200_g200ev_pipeline_init(mdev);
316         if (ret)
317                 return ERR_PTR(ret);
318
319         drm_mode_config_reset(dev);
320
321         return mdev;
322 }