1ba55f2f5SFrançois Tigeot /*
2ba55f2f5SFrançois Tigeot * Copyright 2006 Dave Airlie <airlied@linux.ie>
3ba55f2f5SFrançois Tigeot * Copyright © 2006-2007 Intel Corporation
4ba55f2f5SFrançois Tigeot *
5ba55f2f5SFrançois Tigeot * Permission is hereby granted, free of charge, to any person obtaining a
6ba55f2f5SFrançois Tigeot * copy of this software and associated documentation files (the "Software"),
7ba55f2f5SFrançois Tigeot * to deal in the Software without restriction, including without limitation
8ba55f2f5SFrançois Tigeot * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9ba55f2f5SFrançois Tigeot * and/or sell copies of the Software, and to permit persons to whom the
10ba55f2f5SFrançois Tigeot * Software is furnished to do so, subject to the following conditions:
11ba55f2f5SFrançois Tigeot *
12ba55f2f5SFrançois Tigeot * The above copyright notice and this permission notice (including the next
13ba55f2f5SFrançois Tigeot * paragraph) shall be included in all copies or substantial portions of the
14ba55f2f5SFrançois Tigeot * Software.
15ba55f2f5SFrançois Tigeot *
16ba55f2f5SFrançois Tigeot * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17ba55f2f5SFrançois Tigeot * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18ba55f2f5SFrançois Tigeot * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19ba55f2f5SFrançois Tigeot * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20ba55f2f5SFrançois Tigeot * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21ba55f2f5SFrançois Tigeot * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22ba55f2f5SFrançois Tigeot * DEALINGS IN THE SOFTWARE.
23ba55f2f5SFrançois Tigeot *
24ba55f2f5SFrançois Tigeot * Authors:
25ba55f2f5SFrançois Tigeot * Eric Anholt <eric@anholt.net>
26ba55f2f5SFrançois Tigeot */
27ba55f2f5SFrançois Tigeot #include <linux/i2c.h>
28bf017597SFrançois Tigeot #include <linux/slab.h>
29ba55f2f5SFrançois Tigeot #include <drm/drmP.h>
302c9916cdSFrançois Tigeot #include <drm/drm_atomic_helper.h>
31ba55f2f5SFrançois Tigeot #include <drm/drm_crtc.h>
32ba55f2f5SFrançois Tigeot #include "intel_drv.h"
33ba55f2f5SFrançois Tigeot #include <drm/i915_drm.h>
34ba55f2f5SFrançois Tigeot #include "i915_drv.h"
35ba55f2f5SFrançois Tigeot #include "dvo.h"
36ba55f2f5SFrançois Tigeot
37ba55f2f5SFrançois Tigeot #define SIL164_ADDR 0x38
38ba55f2f5SFrançois Tigeot #define CH7xxx_ADDR 0x76
39ba55f2f5SFrançois Tigeot #define TFP410_ADDR 0x38
40ba55f2f5SFrançois Tigeot #define NS2501_ADDR 0x38
41ba55f2f5SFrançois Tigeot
42ba55f2f5SFrançois Tigeot static const struct intel_dvo_device intel_dvo_devices[] = {
43ba55f2f5SFrançois Tigeot {
44ba55f2f5SFrançois Tigeot .type = INTEL_DVO_CHIP_TMDS,
45ba55f2f5SFrançois Tigeot .name = "sil164",
46ba55f2f5SFrançois Tigeot .dvo_reg = DVOC,
47aee94f86SFrançois Tigeot .dvo_srcdim_reg = DVOC_SRCDIM,
48ba55f2f5SFrançois Tigeot .slave_addr = SIL164_ADDR,
49ba55f2f5SFrançois Tigeot .dev_ops = &sil164_ops,
50ba55f2f5SFrançois Tigeot },
51ba55f2f5SFrançois Tigeot {
52ba55f2f5SFrançois Tigeot .type = INTEL_DVO_CHIP_TMDS,
53ba55f2f5SFrançois Tigeot .name = "ch7xxx",
54ba55f2f5SFrançois Tigeot .dvo_reg = DVOC,
55aee94f86SFrançois Tigeot .dvo_srcdim_reg = DVOC_SRCDIM,
56ba55f2f5SFrançois Tigeot .slave_addr = CH7xxx_ADDR,
57ba55f2f5SFrançois Tigeot .dev_ops = &ch7xxx_ops,
58ba55f2f5SFrançois Tigeot },
59ba55f2f5SFrançois Tigeot {
60ba55f2f5SFrançois Tigeot .type = INTEL_DVO_CHIP_TMDS,
61ba55f2f5SFrançois Tigeot .name = "ch7xxx",
62ba55f2f5SFrançois Tigeot .dvo_reg = DVOC,
63aee94f86SFrançois Tigeot .dvo_srcdim_reg = DVOC_SRCDIM,
64ba55f2f5SFrançois Tigeot .slave_addr = 0x75, /* For some ch7010 */
65ba55f2f5SFrançois Tigeot .dev_ops = &ch7xxx_ops,
66ba55f2f5SFrançois Tigeot },
67ba55f2f5SFrançois Tigeot {
68ba55f2f5SFrançois Tigeot .type = INTEL_DVO_CHIP_LVDS,
69ba55f2f5SFrançois Tigeot .name = "ivch",
70ba55f2f5SFrançois Tigeot .dvo_reg = DVOA,
71aee94f86SFrançois Tigeot .dvo_srcdim_reg = DVOA_SRCDIM,
72ba55f2f5SFrançois Tigeot .slave_addr = 0x02, /* Might also be 0x44, 0x84, 0xc4 */
73ba55f2f5SFrançois Tigeot .dev_ops = &ivch_ops,
74ba55f2f5SFrançois Tigeot },
75ba55f2f5SFrançois Tigeot {
76ba55f2f5SFrançois Tigeot .type = INTEL_DVO_CHIP_TMDS,
77ba55f2f5SFrançois Tigeot .name = "tfp410",
78ba55f2f5SFrançois Tigeot .dvo_reg = DVOC,
79aee94f86SFrançois Tigeot .dvo_srcdim_reg = DVOC_SRCDIM,
80ba55f2f5SFrançois Tigeot .slave_addr = TFP410_ADDR,
81ba55f2f5SFrançois Tigeot .dev_ops = &tfp410_ops,
82ba55f2f5SFrançois Tigeot },
83ba55f2f5SFrançois Tigeot {
84ba55f2f5SFrançois Tigeot .type = INTEL_DVO_CHIP_LVDS,
85ba55f2f5SFrançois Tigeot .name = "ch7017",
86ba55f2f5SFrançois Tigeot .dvo_reg = DVOC,
87aee94f86SFrançois Tigeot .dvo_srcdim_reg = DVOC_SRCDIM,
88ba55f2f5SFrançois Tigeot .slave_addr = 0x75,
8919c468b4SFrançois Tigeot .gpio = GMBUS_PIN_DPB,
90ba55f2f5SFrançois Tigeot .dev_ops = &ch7017_ops,
91ba55f2f5SFrançois Tigeot },
92ba55f2f5SFrançois Tigeot {
93ba55f2f5SFrançois Tigeot .type = INTEL_DVO_CHIP_TMDS,
94ba55f2f5SFrançois Tigeot .name = "ns2501",
951b13d190SFrançois Tigeot .dvo_reg = DVOB,
96aee94f86SFrançois Tigeot .dvo_srcdim_reg = DVOB_SRCDIM,
97ba55f2f5SFrançois Tigeot .slave_addr = NS2501_ADDR,
98ba55f2f5SFrançois Tigeot .dev_ops = &ns2501_ops,
99ba55f2f5SFrançois Tigeot }
100ba55f2f5SFrançois Tigeot };
101ba55f2f5SFrançois Tigeot
102ba55f2f5SFrançois Tigeot struct intel_dvo {
103ba55f2f5SFrançois Tigeot struct intel_encoder base;
104ba55f2f5SFrançois Tigeot
105ba55f2f5SFrançois Tigeot struct intel_dvo_device dev;
106ba55f2f5SFrançois Tigeot
107352ff8bdSFrançois Tigeot struct intel_connector *attached_connector;
108352ff8bdSFrançois Tigeot
109ba55f2f5SFrançois Tigeot bool panel_wants_dither;
110ba55f2f5SFrançois Tigeot };
111ba55f2f5SFrançois Tigeot
enc_to_dvo(struct intel_encoder * encoder)112ba55f2f5SFrançois Tigeot static struct intel_dvo *enc_to_dvo(struct intel_encoder *encoder)
113ba55f2f5SFrançois Tigeot {
114ba55f2f5SFrançois Tigeot return container_of(encoder, struct intel_dvo, base);
115ba55f2f5SFrançois Tigeot }
116ba55f2f5SFrançois Tigeot
intel_attached_dvo(struct drm_connector * connector)117ba55f2f5SFrançois Tigeot static struct intel_dvo *intel_attached_dvo(struct drm_connector *connector)
118ba55f2f5SFrançois Tigeot {
119ba55f2f5SFrançois Tigeot return enc_to_dvo(intel_attached_encoder(connector));
120ba55f2f5SFrançois Tigeot }
121ba55f2f5SFrançois Tigeot
intel_dvo_connector_get_hw_state(struct intel_connector * connector)122ba55f2f5SFrançois Tigeot static bool intel_dvo_connector_get_hw_state(struct intel_connector *connector)
123ba55f2f5SFrançois Tigeot {
12424edb884SFrançois Tigeot struct drm_device *dev = connector->base.dev;
125303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
126ba55f2f5SFrançois Tigeot struct intel_dvo *intel_dvo = intel_attached_dvo(&connector->base);
12724edb884SFrançois Tigeot u32 tmp;
12824edb884SFrançois Tigeot
12924edb884SFrançois Tigeot tmp = I915_READ(intel_dvo->dev.dvo_reg);
13024edb884SFrançois Tigeot
13124edb884SFrançois Tigeot if (!(tmp & DVO_ENABLE))
13224edb884SFrançois Tigeot return false;
133ba55f2f5SFrançois Tigeot
134ba55f2f5SFrançois Tigeot return intel_dvo->dev.dev_ops->get_hw_state(&intel_dvo->dev);
135ba55f2f5SFrançois Tigeot }
136ba55f2f5SFrançois Tigeot
intel_dvo_get_hw_state(struct intel_encoder * encoder,enum i915_pipe * pipe)137ba55f2f5SFrançois Tigeot static bool intel_dvo_get_hw_state(struct intel_encoder *encoder,
138ba55f2f5SFrançois Tigeot enum i915_pipe *pipe)
139ba55f2f5SFrançois Tigeot {
140ba55f2f5SFrançois Tigeot struct drm_device *dev = encoder->base.dev;
141303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(dev);
142ba55f2f5SFrançois Tigeot struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
143ba55f2f5SFrançois Tigeot u32 tmp;
144ba55f2f5SFrançois Tigeot
145ba55f2f5SFrançois Tigeot tmp = I915_READ(intel_dvo->dev.dvo_reg);
146ba55f2f5SFrançois Tigeot
147ba55f2f5SFrançois Tigeot if (!(tmp & DVO_ENABLE))
148ba55f2f5SFrançois Tigeot return false;
149ba55f2f5SFrançois Tigeot
150ba55f2f5SFrançois Tigeot *pipe = PORT_TO_PIPE(tmp);
151ba55f2f5SFrançois Tigeot
152ba55f2f5SFrançois Tigeot return true;
153ba55f2f5SFrançois Tigeot }
154ba55f2f5SFrançois Tigeot
intel_dvo_get_config(struct intel_encoder * encoder,struct intel_crtc_state * pipe_config)155ba55f2f5SFrançois Tigeot static void intel_dvo_get_config(struct intel_encoder *encoder,
1562c9916cdSFrançois Tigeot struct intel_crtc_state *pipe_config)
157ba55f2f5SFrançois Tigeot {
158303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
159ba55f2f5SFrançois Tigeot struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
160ba55f2f5SFrançois Tigeot u32 tmp, flags = 0;
161ba55f2f5SFrançois Tigeot
162ba55f2f5SFrançois Tigeot tmp = I915_READ(intel_dvo->dev.dvo_reg);
163ba55f2f5SFrançois Tigeot if (tmp & DVO_HSYNC_ACTIVE_HIGH)
164ba55f2f5SFrançois Tigeot flags |= DRM_MODE_FLAG_PHSYNC;
165ba55f2f5SFrançois Tigeot else
166ba55f2f5SFrançois Tigeot flags |= DRM_MODE_FLAG_NHSYNC;
167ba55f2f5SFrançois Tigeot if (tmp & DVO_VSYNC_ACTIVE_HIGH)
168ba55f2f5SFrançois Tigeot flags |= DRM_MODE_FLAG_PVSYNC;
169ba55f2f5SFrançois Tigeot else
170ba55f2f5SFrançois Tigeot flags |= DRM_MODE_FLAG_NVSYNC;
171ba55f2f5SFrançois Tigeot
1722c9916cdSFrançois Tigeot pipe_config->base.adjusted_mode.flags |= flags;
173ba55f2f5SFrançois Tigeot
1742c9916cdSFrançois Tigeot pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
175ba55f2f5SFrançois Tigeot }
176ba55f2f5SFrançois Tigeot
intel_disable_dvo(struct intel_encoder * encoder,const struct intel_crtc_state * old_crtc_state,const struct drm_connector_state * old_conn_state)1771e12ee3bSFrançois Tigeot static void intel_disable_dvo(struct intel_encoder *encoder,
178*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *old_crtc_state,
179*3f2dd94aSFrançois Tigeot const struct drm_connector_state *old_conn_state)
180ba55f2f5SFrançois Tigeot {
181303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
182ba55f2f5SFrançois Tigeot struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
183aee94f86SFrançois Tigeot i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
184ba55f2f5SFrançois Tigeot u32 temp = I915_READ(dvo_reg);
185ba55f2f5SFrançois Tigeot
186ba55f2f5SFrançois Tigeot intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false);
187ba55f2f5SFrançois Tigeot I915_WRITE(dvo_reg, temp & ~DVO_ENABLE);
188ba55f2f5SFrançois Tigeot I915_READ(dvo_reg);
189ba55f2f5SFrançois Tigeot }
190ba55f2f5SFrançois Tigeot
intel_enable_dvo(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)1911e12ee3bSFrançois Tigeot static void intel_enable_dvo(struct intel_encoder *encoder,
192*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *pipe_config,
193*3f2dd94aSFrançois Tigeot const struct drm_connector_state *conn_state)
194ba55f2f5SFrançois Tigeot {
195303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
196ba55f2f5SFrançois Tigeot struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
197aee94f86SFrançois Tigeot i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
198ba55f2f5SFrançois Tigeot u32 temp = I915_READ(dvo_reg);
199ba55f2f5SFrançois Tigeot
200ba55f2f5SFrançois Tigeot intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev,
2011e12ee3bSFrançois Tigeot &pipe_config->base.mode,
2021e12ee3bSFrançois Tigeot &pipe_config->base.adjusted_mode);
203ba55f2f5SFrançois Tigeot
2041b13d190SFrançois Tigeot I915_WRITE(dvo_reg, temp | DVO_ENABLE);
2051b13d190SFrançois Tigeot I915_READ(dvo_reg);
2061b13d190SFrançois Tigeot
207ba55f2f5SFrançois Tigeot intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
208ba55f2f5SFrançois Tigeot }
209ba55f2f5SFrançois Tigeot
210ba55f2f5SFrançois Tigeot static enum drm_mode_status
intel_dvo_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)211ba55f2f5SFrançois Tigeot intel_dvo_mode_valid(struct drm_connector *connector,
212ba55f2f5SFrançois Tigeot struct drm_display_mode *mode)
213ba55f2f5SFrançois Tigeot {
214ba55f2f5SFrançois Tigeot struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
215352ff8bdSFrançois Tigeot const struct drm_display_mode *fixed_mode =
216352ff8bdSFrançois Tigeot to_intel_connector(connector)->panel.fixed_mode;
217352ff8bdSFrançois Tigeot int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
218352ff8bdSFrançois Tigeot int target_clock = mode->clock;
219ba55f2f5SFrançois Tigeot
220ba55f2f5SFrançois Tigeot if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
221ba55f2f5SFrançois Tigeot return MODE_NO_DBLESCAN;
222ba55f2f5SFrançois Tigeot
223ba55f2f5SFrançois Tigeot /* XXX: Validate clock range */
224ba55f2f5SFrançois Tigeot
225352ff8bdSFrançois Tigeot if (fixed_mode) {
226352ff8bdSFrançois Tigeot if (mode->hdisplay > fixed_mode->hdisplay)
227ba55f2f5SFrançois Tigeot return MODE_PANEL;
228352ff8bdSFrançois Tigeot if (mode->vdisplay > fixed_mode->vdisplay)
229ba55f2f5SFrançois Tigeot return MODE_PANEL;
230352ff8bdSFrançois Tigeot
231352ff8bdSFrançois Tigeot target_clock = fixed_mode->clock;
232ba55f2f5SFrançois Tigeot }
233ba55f2f5SFrançois Tigeot
234352ff8bdSFrançois Tigeot if (target_clock > max_dotclk)
235352ff8bdSFrançois Tigeot return MODE_CLOCK_HIGH;
236352ff8bdSFrançois Tigeot
237ba55f2f5SFrançois Tigeot return intel_dvo->dev.dev_ops->mode_valid(&intel_dvo->dev, mode);
238ba55f2f5SFrançois Tigeot }
239ba55f2f5SFrançois Tigeot
intel_dvo_compute_config(struct intel_encoder * encoder,struct intel_crtc_state * pipe_config,struct drm_connector_state * conn_state)240ba55f2f5SFrançois Tigeot static bool intel_dvo_compute_config(struct intel_encoder *encoder,
2411e12ee3bSFrançois Tigeot struct intel_crtc_state *pipe_config,
2421e12ee3bSFrançois Tigeot struct drm_connector_state *conn_state)
243ba55f2f5SFrançois Tigeot {
244ba55f2f5SFrançois Tigeot struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
245352ff8bdSFrançois Tigeot const struct drm_display_mode *fixed_mode =
246352ff8bdSFrançois Tigeot intel_dvo->attached_connector->panel.fixed_mode;
2472c9916cdSFrançois Tigeot struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
248ba55f2f5SFrançois Tigeot
249ba55f2f5SFrançois Tigeot /* If we have timings from the BIOS for the panel, put them in
250ba55f2f5SFrançois Tigeot * to the adjusted mode. The CRTC will be set up for this mode,
251ba55f2f5SFrançois Tigeot * with the panel scaling set up to source from the H/VDisplay
252ba55f2f5SFrançois Tigeot * of the original mode.
253ba55f2f5SFrançois Tigeot */
254352ff8bdSFrançois Tigeot if (fixed_mode)
255352ff8bdSFrançois Tigeot intel_fixed_panel_mode(fixed_mode, adjusted_mode);
256ba55f2f5SFrançois Tigeot
257ba55f2f5SFrançois Tigeot return true;
258ba55f2f5SFrançois Tigeot }
259ba55f2f5SFrançois Tigeot
intel_dvo_pre_enable(struct intel_encoder * encoder,const struct intel_crtc_state * pipe_config,const struct drm_connector_state * conn_state)2601e12ee3bSFrançois Tigeot static void intel_dvo_pre_enable(struct intel_encoder *encoder,
261*3f2dd94aSFrançois Tigeot const struct intel_crtc_state *pipe_config,
262*3f2dd94aSFrançois Tigeot const struct drm_connector_state *conn_state)
263ba55f2f5SFrançois Tigeot {
2641e12ee3bSFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
2651e12ee3bSFrançois Tigeot struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
2661e12ee3bSFrançois Tigeot const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
267ba55f2f5SFrançois Tigeot struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
268ba55f2f5SFrançois Tigeot int pipe = crtc->pipe;
269ba55f2f5SFrançois Tigeot u32 dvo_val;
270aee94f86SFrançois Tigeot i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
271aee94f86SFrançois Tigeot i915_reg_t dvo_srcdim_reg = intel_dvo->dev.dvo_srcdim_reg;
272ba55f2f5SFrançois Tigeot
273ba55f2f5SFrançois Tigeot /* Save the data order, since I don't know what it should be set to. */
274ba55f2f5SFrançois Tigeot dvo_val = I915_READ(dvo_reg) &
275ba55f2f5SFrançois Tigeot (DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG);
276ba55f2f5SFrançois Tigeot dvo_val |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE |
277ba55f2f5SFrançois Tigeot DVO_BLANK_ACTIVE_HIGH;
278ba55f2f5SFrançois Tigeot
279ba55f2f5SFrançois Tigeot if (pipe == 1)
280ba55f2f5SFrançois Tigeot dvo_val |= DVO_PIPE_B_SELECT;
281ba55f2f5SFrançois Tigeot dvo_val |= DVO_PIPE_STALL;
282ba55f2f5SFrançois Tigeot if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
283ba55f2f5SFrançois Tigeot dvo_val |= DVO_HSYNC_ACTIVE_HIGH;
284ba55f2f5SFrançois Tigeot if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
285ba55f2f5SFrançois Tigeot dvo_val |= DVO_VSYNC_ACTIVE_HIGH;
286ba55f2f5SFrançois Tigeot
287ba55f2f5SFrançois Tigeot /*I915_WRITE(DVOB_SRCDIM,
288352ff8bdSFrançois Tigeot (adjusted_mode->crtc_hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
289352ff8bdSFrançois Tigeot (adjusted_mode->crtc_vdisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/
290ba55f2f5SFrançois Tigeot I915_WRITE(dvo_srcdim_reg,
291352ff8bdSFrançois Tigeot (adjusted_mode->crtc_hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
292352ff8bdSFrançois Tigeot (adjusted_mode->crtc_vdisplay << DVO_SRCDIM_VERTICAL_SHIFT));
293ba55f2f5SFrançois Tigeot /*I915_WRITE(DVOB, dvo_val);*/
294ba55f2f5SFrançois Tigeot I915_WRITE(dvo_reg, dvo_val);
295ba55f2f5SFrançois Tigeot }
296ba55f2f5SFrançois Tigeot
297ba55f2f5SFrançois Tigeot /**
298ba55f2f5SFrançois Tigeot * Detect the output connection on our DVO device.
299ba55f2f5SFrançois Tigeot *
300ba55f2f5SFrançois Tigeot * Unimplemented.
301ba55f2f5SFrançois Tigeot */
302ba55f2f5SFrançois Tigeot static enum drm_connector_status
intel_dvo_detect(struct drm_connector * connector,bool force)303ba55f2f5SFrançois Tigeot intel_dvo_detect(struct drm_connector *connector, bool force)
304ba55f2f5SFrançois Tigeot {
305ba55f2f5SFrançois Tigeot struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
306ba55f2f5SFrançois Tigeot DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
307ba55f2f5SFrançois Tigeot connector->base.id, connector->name);
308ba55f2f5SFrançois Tigeot return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev);
309ba55f2f5SFrançois Tigeot }
310ba55f2f5SFrançois Tigeot
intel_dvo_get_modes(struct drm_connector * connector)311ba55f2f5SFrançois Tigeot static int intel_dvo_get_modes(struct drm_connector *connector)
312ba55f2f5SFrançois Tigeot {
313303bf270SFrançois Tigeot struct drm_i915_private *dev_priv = to_i915(connector->dev);
314352ff8bdSFrançois Tigeot const struct drm_display_mode *fixed_mode =
315352ff8bdSFrançois Tigeot to_intel_connector(connector)->panel.fixed_mode;
316ba55f2f5SFrançois Tigeot
317ba55f2f5SFrançois Tigeot /* We should probably have an i2c driver get_modes function for those
318ba55f2f5SFrançois Tigeot * devices which will have a fixed set of modes determined by the chip
319ba55f2f5SFrançois Tigeot * (TV-out, for example), but for now with just TMDS and LVDS,
320ba55f2f5SFrançois Tigeot * that's not the case.
321ba55f2f5SFrançois Tigeot */
322ba55f2f5SFrançois Tigeot intel_ddc_get_modes(connector,
32319c468b4SFrançois Tigeot intel_gmbus_get_adapter(dev_priv, GMBUS_PIN_DPC));
324ba55f2f5SFrançois Tigeot if (!list_empty(&connector->probed_modes))
325ba55f2f5SFrançois Tigeot return 1;
326ba55f2f5SFrançois Tigeot
327352ff8bdSFrançois Tigeot if (fixed_mode) {
328ba55f2f5SFrançois Tigeot struct drm_display_mode *mode;
329352ff8bdSFrançois Tigeot mode = drm_mode_duplicate(connector->dev, fixed_mode);
330ba55f2f5SFrançois Tigeot if (mode) {
331ba55f2f5SFrançois Tigeot drm_mode_probed_add(connector, mode);
332ba55f2f5SFrançois Tigeot return 1;
333ba55f2f5SFrançois Tigeot }
334ba55f2f5SFrançois Tigeot }
335ba55f2f5SFrançois Tigeot
336ba55f2f5SFrançois Tigeot return 0;
337ba55f2f5SFrançois Tigeot }
338ba55f2f5SFrançois Tigeot
intel_dvo_destroy(struct drm_connector * connector)339ba55f2f5SFrançois Tigeot static void intel_dvo_destroy(struct drm_connector *connector)
340ba55f2f5SFrançois Tigeot {
341ba55f2f5SFrançois Tigeot drm_connector_cleanup(connector);
342352ff8bdSFrançois Tigeot intel_panel_fini(&to_intel_connector(connector)->panel);
343ba55f2f5SFrançois Tigeot kfree(connector);
344ba55f2f5SFrançois Tigeot }
345ba55f2f5SFrançois Tigeot
346ba55f2f5SFrançois Tigeot static const struct drm_connector_funcs intel_dvo_connector_funcs = {
347ba55f2f5SFrançois Tigeot .detect = intel_dvo_detect,
3481487f786SFrançois Tigeot .late_register = intel_connector_register,
3491487f786SFrançois Tigeot .early_unregister = intel_connector_unregister,
350ba55f2f5SFrançois Tigeot .destroy = intel_dvo_destroy,
351ba55f2f5SFrançois Tigeot .fill_modes = drm_helper_probe_single_connector_modes,
3522c9916cdSFrançois Tigeot .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
353477eb7f9SFrançois Tigeot .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
354ba55f2f5SFrançois Tigeot };
355ba55f2f5SFrançois Tigeot
356ba55f2f5SFrançois Tigeot static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = {
357ba55f2f5SFrançois Tigeot .mode_valid = intel_dvo_mode_valid,
358ba55f2f5SFrançois Tigeot .get_modes = intel_dvo_get_modes,
359ba55f2f5SFrançois Tigeot };
360ba55f2f5SFrançois Tigeot
intel_dvo_enc_destroy(struct drm_encoder * encoder)361ba55f2f5SFrançois Tigeot static void intel_dvo_enc_destroy(struct drm_encoder *encoder)
362ba55f2f5SFrançois Tigeot {
363ba55f2f5SFrançois Tigeot struct intel_dvo *intel_dvo = enc_to_dvo(to_intel_encoder(encoder));
364ba55f2f5SFrançois Tigeot
365ba55f2f5SFrançois Tigeot if (intel_dvo->dev.dev_ops->destroy)
366ba55f2f5SFrançois Tigeot intel_dvo->dev.dev_ops->destroy(&intel_dvo->dev);
367ba55f2f5SFrançois Tigeot
368ba55f2f5SFrançois Tigeot intel_encoder_destroy(encoder);
369ba55f2f5SFrançois Tigeot }
370ba55f2f5SFrançois Tigeot
371ba55f2f5SFrançois Tigeot static const struct drm_encoder_funcs intel_dvo_enc_funcs = {
372ba55f2f5SFrançois Tigeot .destroy = intel_dvo_enc_destroy,
373ba55f2f5SFrançois Tigeot };
374ba55f2f5SFrançois Tigeot
375ba55f2f5SFrançois Tigeot /**
376ba55f2f5SFrançois Tigeot * Attempts to get a fixed panel timing for LVDS (currently only the i830).
377ba55f2f5SFrançois Tigeot *
378ba55f2f5SFrançois Tigeot * Other chips with DVO LVDS will need to extend this to deal with the LVDS
379ba55f2f5SFrançois Tigeot * chip being on DVOB/C and having multiple pipes.
380ba55f2f5SFrançois Tigeot */
381ba55f2f5SFrançois Tigeot static struct drm_display_mode *
intel_dvo_get_current_mode(struct intel_encoder * encoder)382*3f2dd94aSFrançois Tigeot intel_dvo_get_current_mode(struct intel_encoder *encoder)
383ba55f2f5SFrançois Tigeot {
384*3f2dd94aSFrançois Tigeot struct drm_display_mode *mode;
385ba55f2f5SFrançois Tigeot
386*3f2dd94aSFrançois Tigeot mode = intel_encoder_current_mode(encoder);
387ba55f2f5SFrançois Tigeot if (mode) {
388*3f2dd94aSFrançois Tigeot DRM_DEBUG_KMS("using current (BIOS) mode: ");
389*3f2dd94aSFrançois Tigeot drm_mode_debug_printmodeline(mode);
390ba55f2f5SFrançois Tigeot mode->type |= DRM_MODE_TYPE_PREFERRED;
391ba55f2f5SFrançois Tigeot }
392ba55f2f5SFrançois Tigeot
393ba55f2f5SFrançois Tigeot return mode;
394ba55f2f5SFrançois Tigeot }
395ba55f2f5SFrançois Tigeot
intel_dvo_port(i915_reg_t dvo_reg)3961e12ee3bSFrançois Tigeot static enum port intel_dvo_port(i915_reg_t dvo_reg)
3971487f786SFrançois Tigeot {
3981487f786SFrançois Tigeot if (i915_mmio_reg_equal(dvo_reg, DVOA))
3991e12ee3bSFrançois Tigeot return PORT_A;
4001487f786SFrançois Tigeot else if (i915_mmio_reg_equal(dvo_reg, DVOB))
4011e12ee3bSFrançois Tigeot return PORT_B;
4021487f786SFrançois Tigeot else
4031e12ee3bSFrançois Tigeot return PORT_C;
4041487f786SFrançois Tigeot }
4051487f786SFrançois Tigeot
intel_dvo_init(struct drm_i915_private * dev_priv)406a85cb24fSFrançois Tigeot void intel_dvo_init(struct drm_i915_private *dev_priv)
407ba55f2f5SFrançois Tigeot {
408ba55f2f5SFrançois Tigeot struct intel_encoder *intel_encoder;
409ba55f2f5SFrançois Tigeot struct intel_dvo *intel_dvo;
410ba55f2f5SFrançois Tigeot struct intel_connector *intel_connector;
411ba55f2f5SFrançois Tigeot int i;
412ba55f2f5SFrançois Tigeot int encoder_type = DRM_MODE_ENCODER_NONE;
413ba55f2f5SFrançois Tigeot
414ba55f2f5SFrançois Tigeot intel_dvo = kzalloc(sizeof(*intel_dvo), GFP_KERNEL);
415ba55f2f5SFrançois Tigeot if (!intel_dvo)
416ba55f2f5SFrançois Tigeot return;
417ba55f2f5SFrançois Tigeot
418477eb7f9SFrançois Tigeot intel_connector = intel_connector_alloc();
419ba55f2f5SFrançois Tigeot if (!intel_connector) {
420ba55f2f5SFrançois Tigeot kfree(intel_dvo);
421ba55f2f5SFrançois Tigeot return;
422ba55f2f5SFrançois Tigeot }
423ba55f2f5SFrançois Tigeot
424352ff8bdSFrançois Tigeot intel_dvo->attached_connector = intel_connector;
425352ff8bdSFrançois Tigeot
426ba55f2f5SFrançois Tigeot intel_encoder = &intel_dvo->base;
427ba55f2f5SFrançois Tigeot
428ba55f2f5SFrançois Tigeot intel_encoder->disable = intel_disable_dvo;
429ba55f2f5SFrançois Tigeot intel_encoder->enable = intel_enable_dvo;
430ba55f2f5SFrançois Tigeot intel_encoder->get_hw_state = intel_dvo_get_hw_state;
431ba55f2f5SFrançois Tigeot intel_encoder->get_config = intel_dvo_get_config;
432ba55f2f5SFrançois Tigeot intel_encoder->compute_config = intel_dvo_compute_config;
433ba55f2f5SFrançois Tigeot intel_encoder->pre_enable = intel_dvo_pre_enable;
434ba55f2f5SFrançois Tigeot intel_connector->get_hw_state = intel_dvo_connector_get_hw_state;
435ba55f2f5SFrançois Tigeot
436ba55f2f5SFrançois Tigeot /* Now, try to find a controller */
437ba55f2f5SFrançois Tigeot for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
438ba55f2f5SFrançois Tigeot struct drm_connector *connector = &intel_connector->base;
439ba55f2f5SFrançois Tigeot const struct intel_dvo_device *dvo = &intel_dvo_devices[i];
4405d302545SFrançois Tigeot struct i2c_adapter *i2c;
441ba55f2f5SFrançois Tigeot int gpio;
442ba55f2f5SFrançois Tigeot bool dvoinit;
44319c468b4SFrançois Tigeot enum i915_pipe pipe;
44419c468b4SFrançois Tigeot uint32_t dpll[I915_MAX_PIPES];
4451e12ee3bSFrançois Tigeot enum port port;
446ba55f2f5SFrançois Tigeot
447ba55f2f5SFrançois Tigeot /* Allow the I2C driver info to specify the GPIO to be used in
448ba55f2f5SFrançois Tigeot * special cases, but otherwise default to what's defined
449ba55f2f5SFrançois Tigeot * in the spec.
450ba55f2f5SFrançois Tigeot */
45119c468b4SFrançois Tigeot if (intel_gmbus_is_valid_pin(dev_priv, dvo->gpio))
452ba55f2f5SFrançois Tigeot gpio = dvo->gpio;
453ba55f2f5SFrançois Tigeot else if (dvo->type == INTEL_DVO_CHIP_LVDS)
45419c468b4SFrançois Tigeot gpio = GMBUS_PIN_SSC;
455ba55f2f5SFrançois Tigeot else
45619c468b4SFrançois Tigeot gpio = GMBUS_PIN_DPB;
457ba55f2f5SFrançois Tigeot
458ba55f2f5SFrançois Tigeot /* Set up the I2C bus necessary for the chip we're probing.
459ba55f2f5SFrançois Tigeot * It appears that everything is on GPIOE except for panels
460ba55f2f5SFrançois Tigeot * on i830 laptops, which are on GPIOB (DVOA).
461ba55f2f5SFrançois Tigeot */
462ba55f2f5SFrançois Tigeot i2c = intel_gmbus_get_adapter(dev_priv, gpio);
463ba55f2f5SFrançois Tigeot
464ba55f2f5SFrançois Tigeot intel_dvo->dev = *dvo;
465ba55f2f5SFrançois Tigeot
466ba55f2f5SFrançois Tigeot /* GMBUS NAK handling seems to be unstable, hence let the
467ba55f2f5SFrançois Tigeot * transmitter detection run in bit banging mode for now.
468ba55f2f5SFrançois Tigeot */
469ba55f2f5SFrançois Tigeot intel_gmbus_force_bit(i2c, true);
470ba55f2f5SFrançois Tigeot
47119c468b4SFrançois Tigeot /* ns2501 requires the DVO 2x clock before it will
47219c468b4SFrançois Tigeot * respond to i2c accesses, so make sure we have
47319c468b4SFrançois Tigeot * have the clock enabled before we attempt to
47419c468b4SFrançois Tigeot * initialize the device.
47519c468b4SFrançois Tigeot */
47619c468b4SFrançois Tigeot for_each_pipe(dev_priv, pipe) {
47719c468b4SFrançois Tigeot dpll[pipe] = I915_READ(DPLL(pipe));
47819c468b4SFrançois Tigeot I915_WRITE(DPLL(pipe), dpll[pipe] | DPLL_DVO_2X_MODE);
47919c468b4SFrançois Tigeot }
48019c468b4SFrançois Tigeot
481ba55f2f5SFrançois Tigeot dvoinit = dvo->dev_ops->init(&intel_dvo->dev, i2c);
482ba55f2f5SFrançois Tigeot
48319c468b4SFrançois Tigeot /* restore the DVO 2x clock state to original */
48419c468b4SFrançois Tigeot for_each_pipe(dev_priv, pipe) {
48519c468b4SFrançois Tigeot I915_WRITE(DPLL(pipe), dpll[pipe]);
48619c468b4SFrançois Tigeot }
48719c468b4SFrançois Tigeot
488ba55f2f5SFrançois Tigeot intel_gmbus_force_bit(i2c, false);
489ba55f2f5SFrançois Tigeot
490ba55f2f5SFrançois Tigeot if (!dvoinit)
491ba55f2f5SFrançois Tigeot continue;
492ba55f2f5SFrançois Tigeot
4931e12ee3bSFrançois Tigeot port = intel_dvo_port(dvo->dvo_reg);
494a85cb24fSFrançois Tigeot drm_encoder_init(&dev_priv->drm, &intel_encoder->base,
4951487f786SFrançois Tigeot &intel_dvo_enc_funcs, encoder_type,
4961e12ee3bSFrançois Tigeot "DVO %c", port_name(port));
4971487f786SFrançois Tigeot
498ba55f2f5SFrançois Tigeot intel_encoder->type = INTEL_OUTPUT_DVO;
499a85cb24fSFrançois Tigeot intel_encoder->power_domain = POWER_DOMAIN_PORT_OTHER;
5001e12ee3bSFrançois Tigeot intel_encoder->port = port;
501ba55f2f5SFrançois Tigeot intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
5021e12ee3bSFrançois Tigeot
503ba55f2f5SFrançois Tigeot switch (dvo->type) {
504ba55f2f5SFrançois Tigeot case INTEL_DVO_CHIP_TMDS:
505ba55f2f5SFrançois Tigeot intel_encoder->cloneable = (1 << INTEL_OUTPUT_ANALOG) |
506ba55f2f5SFrançois Tigeot (1 << INTEL_OUTPUT_DVO);
507a85cb24fSFrançois Tigeot drm_connector_init(&dev_priv->drm, connector,
508ba55f2f5SFrançois Tigeot &intel_dvo_connector_funcs,
509ba55f2f5SFrançois Tigeot DRM_MODE_CONNECTOR_DVII);
510ba55f2f5SFrançois Tigeot encoder_type = DRM_MODE_ENCODER_TMDS;
511ba55f2f5SFrançois Tigeot break;
512ba55f2f5SFrançois Tigeot case INTEL_DVO_CHIP_LVDS:
513ba55f2f5SFrançois Tigeot intel_encoder->cloneable = 0;
514a85cb24fSFrançois Tigeot drm_connector_init(&dev_priv->drm, connector,
515ba55f2f5SFrançois Tigeot &intel_dvo_connector_funcs,
516ba55f2f5SFrançois Tigeot DRM_MODE_CONNECTOR_LVDS);
517ba55f2f5SFrançois Tigeot encoder_type = DRM_MODE_ENCODER_LVDS;
518ba55f2f5SFrançois Tigeot break;
519ba55f2f5SFrançois Tigeot }
520ba55f2f5SFrançois Tigeot
521ba55f2f5SFrançois Tigeot drm_connector_helper_add(connector,
522ba55f2f5SFrançois Tigeot &intel_dvo_connector_helper_funcs);
523ba55f2f5SFrançois Tigeot connector->display_info.subpixel_order = SubPixelHorizontalRGB;
524ba55f2f5SFrançois Tigeot connector->interlace_allowed = false;
525ba55f2f5SFrançois Tigeot connector->doublescan_allowed = false;
526ba55f2f5SFrançois Tigeot
527ba55f2f5SFrançois Tigeot intel_connector_attach_encoder(intel_connector, intel_encoder);
528ba55f2f5SFrançois Tigeot if (dvo->type == INTEL_DVO_CHIP_LVDS) {
529ba55f2f5SFrançois Tigeot /* For our LVDS chipsets, we should hopefully be able
530ba55f2f5SFrançois Tigeot * to dig the fixed panel mode out of the BIOS data.
531ba55f2f5SFrançois Tigeot * However, it's in a different format from the BIOS
532ba55f2f5SFrançois Tigeot * data on chipsets with integrated LVDS (stored in AIM
533ba55f2f5SFrançois Tigeot * headers, likely), so for now, just get the current
534ba55f2f5SFrançois Tigeot * mode being output through DVO.
535ba55f2f5SFrançois Tigeot */
536352ff8bdSFrançois Tigeot intel_panel_init(&intel_connector->panel,
537*3f2dd94aSFrançois Tigeot intel_dvo_get_current_mode(intel_encoder),
538*3f2dd94aSFrançois Tigeot NULL, NULL);
539ba55f2f5SFrançois Tigeot intel_dvo->panel_wants_dither = true;
540ba55f2f5SFrançois Tigeot }
541ba55f2f5SFrançois Tigeot
542ba55f2f5SFrançois Tigeot return;
543ba55f2f5SFrançois Tigeot }
544ba55f2f5SFrançois Tigeot
545ba55f2f5SFrançois Tigeot kfree(intel_dvo);
546ba55f2f5SFrançois Tigeot kfree(intel_connector);
547ba55f2f5SFrançois Tigeot }
548