drm: userspace rip out TTM API
[platform/upstream/libdrm.git] / shared-core / radeon_ms_output.c
1 /*
2  * Copyright 2007 Jérôme Glisse
3  * Copyright 2007 Alex Deucher
4  * Copyright 2007 Dave Airlie
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining
8  * a copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation on the rights to use, copy, modify, merge,
11  * publish, distribute, sublicense, and/or sell copies of the Software,
12  * and to permit persons to whom the Software is furnished to do so,
13  * subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the
16  * next paragraph) shall be included in all copies or substantial
17  * portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22  * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
23  * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  */
28 #include "radeon_ms.h"
29
30 static struct radeon_ms_output *radeon_ms_connector_get_output(
31                 struct drm_radeon_private *dev_priv,
32                 struct radeon_ms_connector *connector, int i)
33 {
34         if (connector->outputs[i] < 0) {
35                 return NULL;
36         }
37         if (connector->outputs[i] >= RADEON_MAX_OUTPUTS) {
38                 return NULL;
39         }
40         i = connector->outputs[i];
41         if (dev_priv->outputs[i] == NULL) {
42                 return NULL;
43         }
44         if (dev_priv->outputs[i]->connector == NULL) {
45                 return dev_priv->outputs[i];
46         }
47         if (dev_priv->outputs[i]->connector == connector) {
48                 return dev_priv->outputs[i];
49         }
50         return NULL;
51 }
52
53 static void radeon_ms_output_dpms(struct drm_output *output, int mode)
54 {
55         struct drm_radeon_private *dev_priv = output->dev->dev_private;
56         struct radeon_ms_connector *connector = output->driver_private;
57         struct radeon_ms_output *routput = NULL;
58         int i;
59
60         if (connector == NULL) {
61                 return;
62         }
63         for (i = 0; i < RADEON_MAX_OUTPUTS; i++) {
64                 routput = radeon_ms_connector_get_output(dev_priv,
65                                 connector, i);
66
67                 if (routput) {
68                         routput->connector = connector;
69                         routput->dpms(routput, mode);
70                 }
71         }
72         radeon_ms_gpu_dpms(output->dev);
73 }
74
75 static int radeon_ms_output_mode_valid(struct drm_output *output,
76                 struct drm_display_mode *mode)
77 {
78         struct radeon_ms_connector *connector = output->driver_private;
79
80         if (connector == NULL) {
81                 return MODE_ERROR;
82         }
83         return MODE_OK;
84 }
85
86 static bool radeon_ms_output_mode_fixup(struct drm_output *output,
87                 struct drm_display_mode *mode,
88                 struct drm_display_mode *adjusted_mode)
89 {
90         return true;
91 }
92
93 static void radeon_ms_output_prepare(struct drm_output *output)
94 {
95         if (output->funcs->dpms) {
96                 output->funcs->dpms(output, DPMSModeOff);
97         }
98 }
99
100 static void radeon_ms_output_commit(struct drm_output *output)
101 {
102         if (output->funcs->dpms) {
103                 output->funcs->dpms(output, DPMSModeOn);
104         }
105 }
106
107 static void radeon_ms_output_mode_set(struct drm_output *output,
108                 struct drm_display_mode *mode,
109                 struct drm_display_mode *adjusted_mode)
110 {
111         struct drm_radeon_private *dev_priv = output->dev->dev_private;
112         struct radeon_ms_connector *connector = output->driver_private;
113         struct radeon_ms_crtc *crtc;
114         struct radeon_ms_output *routput = NULL;
115         int i;
116
117         if (connector == NULL) {
118                 return;
119         }
120         if (output->crtc == NULL) {
121                 return;
122         }
123         crtc = output->crtc->driver_private;
124         connector->crtc = crtc->crtc;
125         /* catch unknown crtc */
126         switch (connector->crtc) {
127                 case 1:
128                 case 2:
129                         break;
130                 default:
131                         /* error */
132                         return;
133         }
134         for (i = 0; i < RADEON_MAX_OUTPUTS; i++) {
135                 routput = radeon_ms_connector_get_output(dev_priv,
136                                 connector, i);
137                 if (routput) {
138                         routput->connector = connector;
139                         routput->mode_set(routput, mode, adjusted_mode);
140                 }
141         }
142 }
143
144 static enum drm_output_status radeon_ms_output_detect(struct drm_output *output)
145 {
146         struct radeon_ms_connector *connector = output->driver_private;
147
148         if (connector == NULL || connector->i2c == NULL) {
149                 return output_status_unknown;
150         }
151         kfree(connector->edid);
152         connector->edid = drm_get_edid(output, &connector->i2c->adapter);
153         if (connector->edid == NULL) {
154                 return output_status_unknown;
155         }
156         return output_status_connected;
157 }
158
159 static int radeon_ms_output_get_modes(struct drm_output *output)
160 {
161         struct radeon_ms_connector *connector = output->driver_private;
162         int ret = 0;
163
164         if (connector == NULL || connector->i2c == NULL) {
165                 return 0;
166         }
167         if (connector->edid == NULL) {
168                 return 0;
169         }
170         drm_mode_output_update_edid_property(output, connector->edid);
171         ret = drm_add_edid_modes(output, connector->edid);
172         kfree(connector->edid);
173         connector->edid = NULL;
174         return ret;
175 }
176
177 static void radeon_ms_output_cleanup(struct drm_output *output)
178 {
179         struct radeon_ms_connector *connector = output->driver_private;
180
181         if (connector == NULL) {
182                 return;
183         }
184         if (connector->edid) {
185                 kfree(connector->edid);
186         }
187         connector->edid = NULL;
188         connector->output = NULL;
189         output->driver_private = NULL;
190 }
191
192 const struct drm_output_funcs radeon_ms_output_funcs = {
193         .dpms = radeon_ms_output_dpms,
194         .save = NULL,
195         .restore = NULL,
196         .mode_valid = radeon_ms_output_mode_valid,
197         .mode_fixup = radeon_ms_output_mode_fixup,
198         .prepare = radeon_ms_output_prepare,
199         .mode_set = radeon_ms_output_mode_set,
200         .commit = radeon_ms_output_commit,
201         .detect = radeon_ms_output_detect,
202         .get_modes = radeon_ms_output_get_modes,
203         .cleanup = radeon_ms_output_cleanup,
204 };
205
206 void radeon_ms_connectors_destroy(struct drm_device *dev)
207 {
208         struct drm_radeon_private *dev_priv = dev->dev_private;
209         struct radeon_ms_connector *connector = NULL;
210         int i = 0;
211
212         for (i = 0; i < RADEON_MAX_CONNECTORS; i++) {
213                 if (dev_priv->connectors[i]) {
214                         connector = dev_priv->connectors[i];
215                         dev_priv->connectors[i] = NULL;
216                         if (connector->output) {
217                                 drm_output_destroy(connector->output);
218                                 connector->output = NULL;
219                         }
220                         if (connector->i2c) {
221                                 radeon_ms_i2c_destroy(connector->i2c);
222                                 connector->i2c = NULL;
223                         }
224                         drm_free(connector,
225                                         sizeof(struct radeon_ms_connector),
226                                         DRM_MEM_DRIVER);
227                 }
228         }
229 }
230
231 int radeon_ms_connectors_from_properties(struct drm_device *dev)
232 {
233         struct drm_radeon_private *dev_priv = dev->dev_private;
234         struct radeon_ms_connector *connector = NULL;
235         struct drm_output *output = NULL;
236         int i = 0, c = 0;
237
238         radeon_ms_connectors_destroy(dev);
239         for (i = 0; i < RADEON_MAX_CONNECTORS; i++) {
240                 if (dev_priv->properties.connectors[i]) {
241                         connector =
242                                 drm_alloc(sizeof(struct radeon_ms_connector),
243                                                 DRM_MEM_DRIVER);
244                         if (connector == NULL) {
245                                 radeon_ms_connectors_destroy(dev);
246                                 return -ENOMEM;
247                         }
248                         memcpy(connector, dev_priv->properties.connectors[i],
249                                sizeof(struct radeon_ms_connector));
250                         connector->i2c =
251                                 radeon_ms_i2c_create(dev, connector->i2c_reg,
252                                                      connector->name);
253                         if (connector->i2c == NULL) {
254                                 radeon_ms_connectors_destroy(dev);
255                                 return -ENOMEM;
256                         }
257                         output = drm_output_create(dev,
258                                                    &radeon_ms_output_funcs,
259                                                    connector->type);
260                         if (output == NULL) {
261                                 radeon_ms_connectors_destroy(dev);
262                                 return -EINVAL;
263                         }
264                         connector->output = output;
265                         output->driver_private = connector;
266                         output->possible_crtcs = 0x3;
267                         dev_priv->connectors[c++] = connector;
268                 }
269         }
270         return c;
271 }
272
273 int radeon_ms_connectors_from_rom(struct drm_device *dev)
274 {
275         struct drm_radeon_private *dev_priv = dev->dev_private;
276
277         switch (dev_priv->rom.type) {
278         case ROM_COMBIOS:
279                 return radeon_ms_connectors_from_combios(dev);
280         }
281         return 0;
282 }
283
284 void radeon_ms_outputs_destroy(struct drm_device *dev)
285 {
286         struct drm_radeon_private *dev_priv = dev->dev_private;
287         int i = 0;
288
289         for (i = 0; i < RADEON_MAX_OUTPUTS; i++) {
290                 if (dev_priv->outputs[i]) {
291                         drm_free(dev_priv->outputs[i],
292                                         sizeof(struct radeon_ms_output),
293                                         DRM_MEM_DRIVER);
294                         dev_priv->outputs[i] = NULL;
295                 }
296         }
297 }
298
299 int radeon_ms_outputs_from_properties(struct drm_device *dev)
300 {
301         struct drm_radeon_private *dev_priv = dev->dev_private;
302         int i = 0;
303         int c = 0;
304
305         radeon_ms_outputs_destroy(dev);
306         for (i = 0; i < RADEON_MAX_OUTPUTS; i++) {
307                 if (dev_priv->properties.outputs[i]) {
308                         dev_priv->outputs[i] =
309                                 drm_alloc(sizeof(struct radeon_ms_output),
310                                           DRM_MEM_DRIVER);
311                         if (dev_priv->outputs[i] == NULL) {
312                                 radeon_ms_outputs_destroy(dev);
313                                 return -ENOMEM;
314                         }
315                         memcpy(dev_priv->outputs[i],
316                                dev_priv->properties.outputs[i],
317                                sizeof(struct radeon_ms_output));
318                         dev_priv->outputs[i]->dev = dev;
319                         dev_priv->outputs[i]->initialize(dev_priv->outputs[i]);
320                         c++;
321                 }
322         }
323         return c;
324 }
325
326 int radeon_ms_outputs_from_rom(struct drm_device *dev)
327 {
328         struct drm_radeon_private *dev_priv = dev->dev_private;
329
330         switch (dev_priv->rom.type) {
331         case ROM_COMBIOS:
332                 return radeon_ms_outputs_from_combios(dev);
333         }
334         return 0;
335 }
336
337 void radeon_ms_outputs_restore(struct drm_device *dev,
338                 struct radeon_state *state)
339 {
340         struct drm_radeon_private *dev_priv = dev->dev_private;
341         int i;
342
343         for (i = 0; i < RADEON_MAX_OUTPUTS; i++) {
344                 if (dev_priv->outputs[i]) {
345                         dev_priv->outputs[i]->restore(dev_priv->outputs[i],
346                                         state);
347                 }
348         }
349 }
350
351 void radeon_ms_outputs_save(struct drm_device *dev, struct radeon_state *state)
352 {
353         struct drm_radeon_private *dev_priv = dev->dev_private;
354         int i;
355
356         for (i = 0; i < RADEON_MAX_OUTPUTS; i++) {
357                 if (dev_priv->outputs[i]) {
358                         dev_priv->outputs[i]->save(dev_priv->outputs[i], state);
359                 }
360         }
361 }