2 * Copyright (C) 2008 Maarten Maathuis.
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:
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.
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.
27 #include "nv50_connector.h"
29 static struct nv50_output *nv50_connector_to_output(struct nv50_connector *connector, bool digital)
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;
36 switch (connector->type) {
39 analog_possible = true;
42 analog_possible = true;
43 digital_possible = true;
47 digital_possible = true;
53 /* Return early on bad situations. */
54 if (!analog_possible && !digital_possible)
57 if (!analog_possible && !digital)
60 if (!digital_possible && digital)
63 list_for_each_entry(output, &display->outputs, item) {
64 if (connector->bus != output->bus)
66 if (digital && output->type == OUTPUT_TMDS)
68 if (digital && output->type == OUTPUT_LVDS)
70 if (!digital && output->type == OUTPUT_DAC)
72 if (!digital && output->type == OUTPUT_TV)
79 static int nv50_connector_hpd_detect(struct nv50_connector *connector)
81 struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
85 /* Assume connected for the moment. */
86 if (connector->type == CONNECTOR_LVDS) {
87 NV50_DEBUG("LVDS is defaulting to connected for the moment.\n");
91 /* No i2c port, no idea what to do for hotplug. */
92 if (connector->i2c_chan->index == 15) {
93 DRM_ERROR("You have a non-LVDS SOR with no i2c port, please report\n");
97 if (connector->i2c_chan->index > 3) {
98 DRM_ERROR("You have an unusual configuration, index is %d\n", connector->i2c_chan->index);
99 DRM_ERROR("Please report.\n");
103 /* Check hotplug pins. */
104 reg = NV_READ(NV50_PCONNECTOR_HOTPLUG_STATE);
105 if (reg & (NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C0 << (4 * connector->i2c_chan->index)))
109 NV50_DEBUG("Hotplug detect returned positive for bus %d\n", connector->bus);
111 NV50_DEBUG("Hotplug detect returned negative for bus %d\n", connector->bus);
116 static int nv50_connector_i2c_detect(struct nv50_connector *connector)
118 /* kindly borrrowed from the intel driver, hope it works. */
119 uint8_t out_buf[] = { 0x0, 0x0};
122 struct i2c_msg msgs[] = {
137 if (!connector->i2c_chan)
140 ret = i2c_transfer(&connector->i2c_chan->adapter, msgs, 2);
141 NV50_DEBUG("I2C detect returned %d\n", ret);
149 static int nv50_connector_destroy(struct nv50_connector *connector)
151 struct drm_device *dev = connector->dev;
152 struct drm_nouveau_private *dev_priv = dev->dev_private;
153 struct nv50_display *display = nv50_get_display(dev);
157 if (!display || !connector)
160 list_del(&connector->item);
162 if (connector->i2c_chan)
163 nv50_i2c_channel_destroy(connector->i2c_chan);
165 if (dev_priv->free_connector)
166 dev_priv->free_connector(connector);
171 int nv50_connector_create(struct drm_device *dev, int bus, int i2c_index, int type)
173 struct nv50_connector *connector = NULL;
174 struct drm_nouveau_private *dev_priv = dev->dev_private;
175 struct nv50_display *display = NULL;
179 /* This allows the public layer to do it's thing. */
180 if (dev_priv->alloc_connector)
181 connector = dev_priv->alloc_connector(dev);
186 connector->dev = dev;
188 display = nv50_get_display(dev);
192 if (type == CONNECTOR_UNKNOWN)
195 list_add_tail(&connector->item, &display->connectors);
197 connector->bus = bus;
198 connector->type = type;
202 DRM_INFO("Detected a VGA connector\n");
204 case CONNECTOR_DVI_D:
205 DRM_INFO("Detected a DVI-D connector\n");
207 case CONNECTOR_DVI_I:
208 DRM_INFO("Detected a DVI-I connector\n");
211 DRM_INFO("Detected a LVDS connector\n");
214 DRM_INFO("Detected a TV connector\n");
217 DRM_ERROR("Unknown connector, this is not good.\n");
221 /* some reasonable defaults */
222 if (type == CONNECTOR_DVI_D || type == CONNECTOR_DVI_I || type == CONNECTOR_LVDS)
223 connector->requested_scaling_mode = SCALE_FULLSCREEN;
225 connector->requested_scaling_mode = SCALE_NON_GPU;
227 connector->use_dithering = false;
230 connector->i2c_chan = nv50_i2c_channel_create(dev, i2c_index);
232 /* set function pointers */
233 connector->hpd_detect = nv50_connector_hpd_detect;
234 connector->i2c_detect = nv50_connector_i2c_detect;
235 connector->destroy = nv50_connector_destroy;
236 connector->to_output = nv50_connector_to_output;
241 if (dev_priv->free_connector)
242 dev_priv->free_connector(connector);