drm/mgag200: Move mode-config to model-specific code
[linux-2.6-microblaze.git] / drivers / gpu / drm / mgag200 / mgag200_g200ew3.c
1 // SPDX-License-Identifier: GPL-2.0-only
2
3 #include <linux/pci.h>
4
5 #include <drm/drm_atomic.h>
6 #include <drm/drm_atomic_helper.h>
7 #include <drm/drm_drv.h>
8 #include <drm/drm_gem_atomic_helper.h>
9 #include <drm/drm_probe_helper.h>
10
11 #include "mgag200_drv.h"
12
13 static void mgag200_g200ew3_init_registers(struct mga_device *mdev)
14 {
15         mgag200_g200wb_init_registers(mdev); // same as G200WB
16
17         WREG_ECRT(0x34, 0x5); // G200EW3 specific
18 }
19
20 /*
21  * PIXPLLC
22  */
23
24 static int mgag200_g200ew3_pixpllc_atomic_check(struct drm_crtc *crtc,
25                                                 struct drm_atomic_state *new_state)
26 {
27         static const unsigned int vcomax = 800000;
28         static const unsigned int vcomin = 400000;
29         static const unsigned int pllreffreq = 25000;
30
31         struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(new_state, crtc);
32         struct mgag200_crtc_state *new_mgag200_crtc_state = to_mgag200_crtc_state(new_crtc_state);
33         long clock = new_crtc_state->mode.clock;
34         struct mgag200_pll_values *pixpllc = &new_mgag200_crtc_state->pixpllc;
35         unsigned int delta, tmpdelta;
36         unsigned int testp, testm, testn, testp2;
37         unsigned int p, m, n, s;
38         unsigned int computed;
39
40         m = n = p = s = 0;
41         delta = 0xffffffff;
42
43         for (testp = 1; testp < 8; testp++) {
44                 for (testp2 = 1; testp2 < 8; testp2++) {
45                         if (testp < testp2)
46                                 continue;
47                         if ((clock * testp * testp2) > vcomax)
48                                 continue;
49                         if ((clock * testp * testp2) < vcomin)
50                                 continue;
51                         for (testm = 1; testm < 26; testm++) {
52                                 for (testn = 32; testn < 2048 ; testn++) {
53                                         computed = (pllreffreq * testn) / (testm * testp * testp2);
54                                         if (computed > clock)
55                                                 tmpdelta = computed - clock;
56                                         else
57                                                 tmpdelta = clock - computed;
58                                         if (tmpdelta < delta) {
59                                                 delta = tmpdelta;
60                                                 m = testm + 1;
61                                                 n = testn + 1;
62                                                 p = testp + 1;
63                                                 s = testp2;
64                                         }
65                                 }
66                         }
67                 }
68         }
69
70         pixpllc->m = m;
71         pixpllc->n = n;
72         pixpllc->p = p;
73         pixpllc->s = s;
74
75         return 0;
76 }
77
78 /*
79  * Mode-setting pipeline
80  */
81
82 static const struct drm_plane_helper_funcs mgag200_g200ew3_primary_plane_helper_funcs = {
83         MGAG200_PRIMARY_PLANE_HELPER_FUNCS,
84 };
85
86 static const struct drm_plane_funcs mgag200_g200ew3_primary_plane_funcs = {
87         MGAG200_PRIMARY_PLANE_FUNCS,
88 };
89
90 static const struct drm_crtc_helper_funcs mgag200_g200ew3_crtc_helper_funcs = {
91         MGAG200_CRTC_HELPER_FUNCS,
92 };
93
94 static const struct drm_crtc_funcs mgag200_g200ew3_crtc_funcs = {
95         MGAG200_CRTC_FUNCS,
96 };
97
98 static const struct drm_encoder_funcs mgag200_g200ew3_dac_encoder_funcs = {
99         MGAG200_DAC_ENCODER_FUNCS,
100 };
101
102 static const struct drm_connector_helper_funcs mgag200_g200ew3_vga_connector_helper_funcs = {
103         MGAG200_VGA_CONNECTOR_HELPER_FUNCS,
104 };
105
106 static const struct drm_connector_funcs mgag200_g200ew3_vga_connector_funcs = {
107         MGAG200_VGA_CONNECTOR_FUNCS,
108 };
109
110 static int mgag200_g200ew3_pipeline_init(struct mga_device *mdev)
111 {
112         struct drm_device *dev = &mdev->base;
113         struct drm_plane *primary_plane = &mdev->primary_plane;
114         struct drm_crtc *crtc = &mdev->crtc;
115         struct drm_encoder *encoder = &mdev->encoder;
116         struct mga_i2c_chan *i2c = &mdev->i2c;
117         struct drm_connector *connector = &mdev->connector;
118         int ret;
119
120         ret = drm_universal_plane_init(dev, primary_plane, 0,
121                                        &mgag200_g200ew3_primary_plane_funcs,
122                                        mgag200_primary_plane_formats,
123                                        mgag200_primary_plane_formats_size,
124                                        mgag200_primary_plane_fmtmods,
125                                        DRM_PLANE_TYPE_PRIMARY, NULL);
126         if (ret) {
127                 drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret);
128                 return ret;
129         }
130         drm_plane_helper_add(primary_plane, &mgag200_g200ew3_primary_plane_helper_funcs);
131         drm_plane_enable_fb_damage_clips(primary_plane);
132
133         ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL,
134                                         &mgag200_g200ew3_crtc_funcs, NULL);
135         if (ret) {
136                 drm_err(dev, "drm_crtc_init_with_planes() failed: %d\n", ret);
137                 return ret;
138         }
139         drm_crtc_helper_add(crtc, &mgag200_g200ew3_crtc_helper_funcs);
140
141         /* FIXME: legacy gamma tables, but atomic gamma doesn't work without */
142         drm_mode_crtc_set_gamma_size(crtc, MGAG200_LUT_SIZE);
143         drm_crtc_enable_color_mgmt(crtc, 0, false, MGAG200_LUT_SIZE);
144
145         encoder->possible_crtcs = drm_crtc_mask(crtc);
146         ret = drm_encoder_init(dev, encoder, &mgag200_g200ew3_dac_encoder_funcs,
147                                DRM_MODE_ENCODER_DAC, NULL);
148         if (ret) {
149                 drm_err(dev, "drm_encoder_init() failed: %d\n", ret);
150                 return ret;
151         }
152
153         ret = mgag200_i2c_init(mdev, i2c);
154         if (ret) {
155                 drm_err(dev, "failed to add DDC bus: %d\n", ret);
156                 return ret;
157         }
158
159         ret = drm_connector_init_with_ddc(dev, connector,
160                                           &mgag200_g200ew3_vga_connector_funcs,
161                                           DRM_MODE_CONNECTOR_VGA,
162                                           &i2c->adapter);
163         if (ret) {
164                 drm_err(dev, "drm_connector_init_with_ddc() failed: %d\n", ret);
165                 return ret;
166         }
167         drm_connector_helper_add(connector, &mgag200_g200ew3_vga_connector_helper_funcs);
168
169         ret = drm_connector_attach_encoder(connector, encoder);
170         if (ret) {
171                 drm_err(dev, "drm_connector_attach_encoder() failed: %d\n", ret);
172                 return ret;
173         }
174
175         return 0;
176 }
177
178 /*
179  * DRM device
180  */
181
182 static const struct mgag200_device_info mgag200_g200ew3_device_info =
183         MGAG200_DEVICE_INFO_INIT(2048, 2048, 0, true, 0, 1, false);
184
185 static const struct mgag200_device_funcs mgag200_g200ew3_device_funcs = {
186         .disable_vidrst = mgag200_bmc_disable_vidrst,
187         .enable_vidrst = mgag200_bmc_enable_vidrst,
188         .pixpllc_atomic_check = mgag200_g200ew3_pixpllc_atomic_check,
189         .pixpllc_atomic_update = mgag200_g200wb_pixpllc_atomic_update, // same as G200WB
190 };
191
192 static resource_size_t mgag200_g200ew3_device_probe_vram(struct mga_device *mdev)
193 {
194         resource_size_t vram_size = resource_size(mdev->vram_res);
195
196         if (vram_size >= 0x1000000)
197                 vram_size = vram_size - 0x400000;
198         return mgag200_probe_vram(mdev->vram, vram_size);
199 }
200
201 struct mga_device *mgag200_g200ew3_device_create(struct pci_dev *pdev,
202                                                  const struct drm_driver *drv,
203                                                  enum mga_type type)
204 {
205         struct mga_device *mdev;
206         struct drm_device *dev;
207         resource_size_t vram_available;
208         int ret;
209
210         mdev = devm_drm_dev_alloc(&pdev->dev, drv, struct mga_device, base);
211         if (IS_ERR(mdev))
212                 return mdev;
213         dev = &mdev->base;
214
215         pci_set_drvdata(pdev, dev);
216
217         ret = mgag200_init_pci_options(pdev, 0x41049120, 0x0000b000);
218         if (ret)
219                 return ERR_PTR(ret);
220
221         ret = mgag200_device_preinit(mdev);
222         if (ret)
223                 return ERR_PTR(ret);
224
225         ret = mgag200_device_init(mdev, type, &mgag200_g200ew3_device_info,
226                                   &mgag200_g200ew3_device_funcs);
227         if (ret)
228                 return ERR_PTR(ret);
229
230         mgag200_g200ew3_init_registers(mdev);
231
232         vram_available = mgag200_g200ew3_device_probe_vram(mdev);
233
234         ret = mgag200_mode_config_init(mdev, vram_available);
235         if (ret)
236                 return ERR_PTR(ret);
237
238         ret = mgag200_g200ew3_pipeline_init(mdev);
239         if (ret)
240                 return ERR_PTR(ret);
241
242         drm_mode_config_reset(dev);
243
244         return mdev;
245 }