modesetting-101: rename modeflags, as to avoid conflicts with the xorg definitions
[platform/upstream/libdrm.git] / linux-core / nv50_connector.c
1 /*
2  * Copyright (C) 2008 Maarten Maathuis.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial
15  * portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  */
26
27 #include "nv50_connector.h"
28
29 static struct nv50_output *nv50_connector_to_output(struct nv50_connector *connector, bool digital)
30 {
31         struct nv50_display *display = nv50_get_display(connector->dev);
32         struct nv50_output *output = NULL;
33         bool digital_possible = false;
34         bool analog_possible = false;
35
36         switch (connector->type) {
37                 case CONNECTOR_VGA:
38                 case CONNECTOR_TV:
39                         analog_possible = true;
40                         break;
41                 case CONNECTOR_DVI_I:
42                         analog_possible = true;
43                         digital_possible = true;
44                         break;
45                 case CONNECTOR_DVI_D:
46                 case CONNECTOR_LVDS:
47                         digital_possible = true;
48                         break;
49                 default:
50                         break;
51         }
52
53         /* Return early on bad situations. */
54         if (!analog_possible && !digital_possible)
55                 return NULL;
56
57         if (!analog_possible && !digital)
58                 return NULL;
59
60         if (!digital_possible && digital)
61                 return NULL;
62
63         list_for_each_entry(output, &display->outputs, item) {
64                 if (connector->bus != output->bus)
65                         continue;
66                 if (digital && output->type == OUTPUT_TMDS)
67                         return output;
68                 if (digital && output->type == OUTPUT_LVDS)
69                         return output;
70                 if (!digital && output->type == OUTPUT_DAC)
71                         return output;
72                 if (!digital && output->type == OUTPUT_TV)
73                         return output;
74         }
75
76         return NULL;
77 }
78
79 static bool nv50_connector_detect(struct nv50_connector *connector)
80 {
81         /* kindly borrrowed from the intel driver, hope it works. */
82         uint8_t out_buf[] = { 0x0, 0x0};
83         uint8_t buf[2];
84         int ret;
85         struct i2c_msg msgs[] = {
86                 {
87                         .addr = 0x50,
88                         .flags = 0,
89                         .len = 1,
90                         .buf = out_buf,
91                 },
92                 {
93                         .addr = 0x50,
94                         .flags = I2C_M_RD,
95                         .len = 1,
96                         .buf = buf,
97                 }
98         };
99
100         NV50_DEBUG("\n");
101
102         if (!connector->i2c_chan)
103                 return false;
104
105         ret = i2c_transfer(&connector->i2c_chan->adapter, msgs, 2);
106         DRM_INFO("I2C detect returned %d\n", ret);
107
108         if (ret == 2)
109                 return true;
110
111         return false;
112 }
113
114 static int nv50_connector_destroy(struct nv50_connector *connector)
115 {
116         struct drm_device *dev = connector->dev;
117         struct drm_nouveau_private *dev_priv = dev->dev_private;
118         struct nv50_display *display = nv50_get_display(dev);
119
120         NV50_DEBUG("\n");
121
122         if (!display || !connector)
123                 return -EINVAL;
124
125         list_del(&connector->item);
126
127         if (connector->i2c_chan)
128                 nv50_i2c_channel_destroy(connector->i2c_chan);
129
130         if (dev_priv->free_connector)
131                 dev_priv->free_connector(connector);
132
133         return 0;
134 }
135
136 int nv50_connector_create(struct drm_device *dev, int bus, int i2c_index, int type)
137 {
138         struct nv50_connector *connector = NULL;
139         struct drm_nouveau_private *dev_priv = dev->dev_private;
140         struct nv50_display *display = NULL;
141
142         NV50_DEBUG("\n");
143
144         /* This allows the public layer to do it's thing. */
145         if (dev_priv->alloc_connector)
146                 connector = dev_priv->alloc_connector(dev);
147
148         if (!connector)
149                 return -ENOMEM;
150
151         connector->dev = dev;
152
153         display = nv50_get_display(dev);
154         if (!display)
155                 goto out;
156
157         if (type == CONNECTOR_UNKNOWN)
158                 goto out;
159
160         list_add_tail(&connector->item, &display->connectors);
161
162         connector->bus = bus;
163         connector->type = type;
164
165         switch (type) {
166                 case CONNECTOR_VGA:
167                         DRM_INFO("Detected a VGA connector\n");
168                         break;
169                 case CONNECTOR_DVI_D:
170                         DRM_INFO("Detected a DVI-D connector\n");
171                         break;
172                 case CONNECTOR_DVI_I:
173                         DRM_INFO("Detected a DVI-I connector\n");
174                         break;
175                 case CONNECTOR_LVDS:
176                         DRM_INFO("Detected a LVDS connector\n");
177                         break;
178                 case CONNECTOR_TV:
179                         DRM_INFO("Detected a TV connector\n");
180                         break;
181                 default:
182                         DRM_ERROR("Unknown connector, this is not good.\n");
183                         break;
184         }
185
186         /* some reasonable defaults */
187         if (type == CONNECTOR_DVI_D || type == CONNECTOR_DVI_I || type == CONNECTOR_LVDS)
188                 connector->scaling_mode = SCALE_FULLSCREEN;
189         else
190                 connector->scaling_mode = SCALE_PANEL;
191
192         if (i2c_index < 0xf)
193                 connector->i2c_chan = nv50_i2c_channel_create(dev, i2c_index);
194
195         /* set function pointers */
196         connector->detect = nv50_connector_detect;
197         connector->destroy = nv50_connector_destroy;
198         connector->to_output = nv50_connector_to_output;
199
200         return 0;
201
202 out:
203         if (dev_priv->free_connector)
204                 dev_priv->free_connector(connector);
205
206         return -EINVAL;
207 }