2 * Copyright 2007 Jérôme Glisse
3 * Copyright 2007 Alex Deucher
4 * Copyright 2007 Dave Airlie
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:
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.
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.
28 #include "radeon_ms.h"
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)
34 if (connector->outputs[i] < 0) {
37 if (connector->outputs[i] >= RADEON_MAX_OUTPUTS) {
40 i = connector->outputs[i];
41 if (dev_priv->outputs[i] == NULL) {
44 if (dev_priv->outputs[i]->connector == NULL) {
45 return dev_priv->outputs[i];
47 if (dev_priv->outputs[i]->connector == connector) {
48 return dev_priv->outputs[i];
53 static void radeon_ms_output_dpms(struct drm_output *output, int mode)
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;
60 if (connector == NULL) {
63 for (i = 0; i < RADEON_MAX_OUTPUTS; i++) {
64 routput = radeon_ms_connector_get_output(dev_priv,
68 routput->connector = connector;
69 routput->dpms(routput, mode);
72 radeon_ms_gpu_dpms(output->dev);
75 static int radeon_ms_output_mode_valid(struct drm_output *output,
76 struct drm_display_mode *mode)
78 struct radeon_ms_connector *connector = output->driver_private;
80 if (connector == NULL) {
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)
93 static void radeon_ms_output_prepare(struct drm_output *output)
95 if (output->funcs->dpms) {
96 output->funcs->dpms(output, DPMSModeOff);
100 static void radeon_ms_output_commit(struct drm_output *output)
102 if (output->funcs->dpms) {
103 output->funcs->dpms(output, DPMSModeOn);
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)
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;
117 if (connector == NULL) {
120 if (output->crtc == NULL) {
123 crtc = output->crtc->driver_private;
124 connector->crtc = crtc->crtc;
125 /* catch unknown crtc */
126 switch (connector->crtc) {
134 for (i = 0; i < RADEON_MAX_OUTPUTS; i++) {
135 routput = radeon_ms_connector_get_output(dev_priv,
138 routput->connector = connector;
139 routput->mode_set(routput, mode, adjusted_mode);
144 static enum drm_output_status radeon_ms_output_detect(struct drm_output *output)
146 struct radeon_ms_connector *connector = output->driver_private;
148 if (connector == NULL || connector->i2c == NULL) {
149 return output_status_unknown;
151 kfree(connector->edid);
152 connector->edid = drm_get_edid(output, &connector->i2c->adapter);
153 if (connector->edid == NULL) {
154 return output_status_unknown;
156 return output_status_connected;
159 static int radeon_ms_output_get_modes(struct drm_output *output)
161 struct radeon_ms_connector *connector = output->driver_private;
164 if (connector == NULL || connector->i2c == NULL) {
167 if (connector->edid == NULL) {
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;
177 static void radeon_ms_output_cleanup(struct drm_output *output)
179 struct radeon_ms_connector *connector = output->driver_private;
181 if (connector == NULL) {
184 if (connector->edid) {
185 kfree(connector->edid);
187 connector->edid = NULL;
188 connector->output = NULL;
189 output->driver_private = NULL;
192 const struct drm_output_funcs radeon_ms_output_funcs = {
193 .dpms = radeon_ms_output_dpms,
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,
206 void radeon_ms_connectors_destroy(struct drm_device *dev)
208 struct drm_radeon_private *dev_priv = dev->dev_private;
209 struct radeon_ms_connector *connector = NULL;
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;
220 if (connector->i2c) {
221 radeon_ms_i2c_destroy(connector->i2c);
222 connector->i2c = NULL;
225 sizeof(struct radeon_ms_connector),
231 int radeon_ms_connectors_from_properties(struct drm_device *dev)
233 struct drm_radeon_private *dev_priv = dev->dev_private;
234 struct radeon_ms_connector *connector = NULL;
235 struct drm_output *output = NULL;
238 radeon_ms_connectors_destroy(dev);
239 for (i = 0; i < RADEON_MAX_CONNECTORS; i++) {
240 if (dev_priv->properties.connectors[i]) {
242 drm_alloc(sizeof(struct radeon_ms_connector),
244 if (connector == NULL) {
245 radeon_ms_connectors_destroy(dev);
248 memcpy(connector, dev_priv->properties.connectors[i],
249 sizeof(struct radeon_ms_connector));
251 radeon_ms_i2c_create(dev, connector->i2c_reg,
253 if (connector->i2c == NULL) {
254 radeon_ms_connectors_destroy(dev);
257 output = drm_output_create(dev,
258 &radeon_ms_output_funcs,
260 if (output == NULL) {
261 radeon_ms_connectors_destroy(dev);
264 connector->output = output;
265 output->driver_private = connector;
266 output->possible_crtcs = 0x3;
267 dev_priv->connectors[c++] = connector;
273 int radeon_ms_connectors_from_rom(struct drm_device *dev)
275 struct drm_radeon_private *dev_priv = dev->dev_private;
277 switch (dev_priv->rom.type) {
279 return radeon_ms_connectors_from_combios(dev);
284 void radeon_ms_outputs_destroy(struct drm_device *dev)
286 struct drm_radeon_private *dev_priv = dev->dev_private;
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),
294 dev_priv->outputs[i] = NULL;
299 int radeon_ms_outputs_from_properties(struct drm_device *dev)
301 struct drm_radeon_private *dev_priv = dev->dev_private;
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),
311 if (dev_priv->outputs[i] == NULL) {
312 radeon_ms_outputs_destroy(dev);
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]);
326 int radeon_ms_outputs_from_rom(struct drm_device *dev)
328 struct drm_radeon_private *dev_priv = dev->dev_private;
330 switch (dev_priv->rom.type) {
332 return radeon_ms_outputs_from_combios(dev);
337 void radeon_ms_outputs_restore(struct drm_device *dev,
338 struct radeon_state *state)
340 struct drm_radeon_private *dev_priv = dev->dev_private;
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],
351 void radeon_ms_outputs_save(struct drm_device *dev, struct radeon_state *state)
353 struct drm_radeon_private *dev_priv = dev->dev_private;
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);