1235783Skib/*
2235783Skib * Copyright 2006 Dave Airlie <airlied@linux.ie>
3235783Skib * Copyright �� 2006-2007 Intel Corporation
4235783Skib *   Jesse Barnes <jesse.barnes@intel.com>
5235783Skib *
6235783Skib * Permission is hereby granted, free of charge, to any person obtaining a
7235783Skib * copy of this software and associated documentation files (the "Software"),
8235783Skib * to deal in the Software without restriction, including without limitation
9235783Skib * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10235783Skib * and/or sell copies of the Software, and to permit persons to whom the
11235783Skib * Software is furnished to do so, subject to the following conditions:
12235783Skib *
13235783Skib * The above copyright notice and this permission notice (including the next
14235783Skib * paragraph) shall be included in all copies or substantial portions of the
15235783Skib * Software.
16235783Skib *
17235783Skib * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18235783Skib * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19235783Skib * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20235783Skib * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21235783Skib * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22235783Skib * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23235783Skib * DEALINGS IN THE SOFTWARE.
24235783Skib *
25235783Skib * Authors:
26235783Skib *	Eric Anholt <eric@anholt.net>
27235783Skib */
28235783Skib#include <sys/cdefs.h>
29235783Skib__FBSDID("$FreeBSD$");
30235783Skib
31235783Skib#include <dev/drm2/drmP.h>
32235783Skib#include <dev/drm2/drm_crtc.h>
33235783Skib#include <dev/drm2/drm_edid.h>
34296548Sdumbbell#include <dev/drm2/i915/intel_drv.h>
35235783Skib#include <dev/drm2/i915/i915_drm.h>
36235783Skib#include <dev/drm2/i915/i915_drv.h>
37235783Skib#include <dev/drm2/i915/intel_sdvo_regs.h>
38268564Srpaulo#include <dev/iicbus/iic.h>
39235783Skib#include <dev/iicbus/iiconf.h>
40235783Skib#include "iicbus_if.h"
41235783Skib
42235783Skib#define SDVO_TMDS_MASK (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)
43235783Skib#define SDVO_RGB_MASK  (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1)
44235783Skib#define SDVO_LVDS_MASK (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1)
45277487Skib#define SDVO_TV_MASK   (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_YPRPB0)
46235783Skib
47235783Skib#define SDVO_OUTPUT_MASK (SDVO_TMDS_MASK | SDVO_RGB_MASK | SDVO_LVDS_MASK |\
48235783Skib			SDVO_TV_MASK)
49235783Skib
50235783Skib#define IS_TV(c)	(c->output_flag & SDVO_TV_MASK)
51235783Skib#define IS_TMDS(c)	(c->output_flag & SDVO_TMDS_MASK)
52235783Skib#define IS_LVDS(c)	(c->output_flag & SDVO_LVDS_MASK)
53235783Skib#define IS_TV_OR_LVDS(c) (c->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK))
54235783Skib#define IS_DIGITAL(c) (c->output_flag & (SDVO_TMDS_MASK | SDVO_LVDS_MASK))
55235783Skib
56235783Skib
57235783Skibstatic const char *tv_format_names[] = {
58235783Skib	"NTSC_M"   , "NTSC_J"  , "NTSC_443",
59235783Skib	"PAL_B"    , "PAL_D"   , "PAL_G"   ,
60235783Skib	"PAL_H"    , "PAL_I"   , "PAL_M"   ,
61235783Skib	"PAL_N"    , "PAL_NC"  , "PAL_60"  ,
62235783Skib	"SECAM_B"  , "SECAM_D" , "SECAM_G" ,
63235783Skib	"SECAM_K"  , "SECAM_K1", "SECAM_L" ,
64235783Skib	"SECAM_60"
65235783Skib};
66235783Skib
67235783Skib#define TV_FORMAT_NUM  (sizeof(tv_format_names) / sizeof(*tv_format_names))
68235783Skib
69235783Skibstruct intel_sdvo {
70235783Skib	struct intel_encoder base;
71235783Skib
72235783Skib	device_t i2c;
73235783Skib	u8 slave_addr;
74235783Skib
75235783Skib	device_t ddc_iic_bus, ddc;
76235783Skib
77235783Skib	/* Register for the SDVO device: SDVOB or SDVOC */
78277487Skib	uint32_t sdvo_reg;
79235783Skib
80235783Skib	/* Active outputs controlled by this SDVO output */
81235783Skib	uint16_t controlled_output;
82235783Skib
83235783Skib	/*
84235783Skib	 * Capabilities of the SDVO device returned by
85235783Skib	 * i830_sdvo_get_capabilities()
86235783Skib	 */
87235783Skib	struct intel_sdvo_caps caps;
88235783Skib
89235783Skib	/* Pixel clock limitations reported by the SDVO device, in kHz */
90235783Skib	int pixel_clock_min, pixel_clock_max;
91235783Skib
92235783Skib	/*
93235783Skib	* For multiple function SDVO device,
94235783Skib	* this is for current attached outputs.
95235783Skib	*/
96235783Skib	uint16_t attached_output;
97235783Skib
98235783Skib	/*
99235783Skib	 * Hotplug activation bits for this device
100235783Skib	 */
101296548Sdumbbell	uint16_t hotplug_active;
102235783Skib
103235783Skib	/**
104235783Skib	 * This is used to select the color range of RBG outputs in HDMI mode.
105235783Skib	 * It is only valid when using TMDS encoding and 8 bit per color mode.
106235783Skib	 */
107235783Skib	uint32_t color_range;
108235783Skib
109235783Skib	/**
110235783Skib	 * This is set if we're going to treat the device as TV-out.
111235783Skib	 *
112235783Skib	 * While we have these nice friendly flags for output types that ought
113235783Skib	 * to decide this for us, the S-Video output on our HDMI+S-Video card
114235783Skib	 * shows up as RGB1 (VGA).
115235783Skib	 */
116235783Skib	bool is_tv;
117235783Skib
118277487Skib	/* On different gens SDVOB is at different places. */
119277487Skib	bool is_sdvob;
120277487Skib
121235783Skib	/* This is for current tv format name */
122235783Skib	int tv_format_index;
123235783Skib
124235783Skib	/**
125235783Skib	 * This is set if we treat the device as HDMI, instead of DVI.
126235783Skib	 */
127235783Skib	bool is_hdmi;
128235783Skib	bool has_hdmi_monitor;
129235783Skib	bool has_hdmi_audio;
130235783Skib
131235783Skib	/**
132235783Skib	 * This is set if we detect output of sdvo device as LVDS and
133235783Skib	 * have a valid fixed mode to use with the panel.
134235783Skib	 */
135235783Skib	bool is_lvds;
136235783Skib
137235783Skib	/**
138235783Skib	 * This is sdvo fixed pannel mode pointer
139235783Skib	 */
140235783Skib	struct drm_display_mode *sdvo_lvds_fixed_mode;
141235783Skib
142235783Skib	/* DDC bus used by this SDVO encoder */
143235783Skib	uint8_t ddc_bus;
144235783Skib
145296548Sdumbbell	/*
146296548Sdumbbell	 * the sdvo flag gets lost in round trip: dtd->adjusted_mode->dtd
147296548Sdumbbell	 */
148296548Sdumbbell	uint8_t dtd_sdvo_flags;
149235783Skib};
150235783Skib
151235783Skibstruct intel_sdvo_connector {
152235783Skib	struct intel_connector base;
153235783Skib
154235783Skib	/* Mark the type of connector */
155235783Skib	uint16_t output_flag;
156235783Skib
157235783Skib	enum hdmi_force_audio force_audio;
158235783Skib
159235783Skib	/* This contains all current supported TV format */
160235783Skib	u8 tv_format_supported[TV_FORMAT_NUM];
161235783Skib	int   format_supported_num;
162235783Skib	struct drm_property *tv_format;
163235783Skib
164235783Skib	/* add the property for the SDVO-TV */
165235783Skib	struct drm_property *left;
166235783Skib	struct drm_property *right;
167235783Skib	struct drm_property *top;
168235783Skib	struct drm_property *bottom;
169235783Skib	struct drm_property *hpos;
170235783Skib	struct drm_property *vpos;
171235783Skib	struct drm_property *contrast;
172235783Skib	struct drm_property *saturation;
173235783Skib	struct drm_property *hue;
174235783Skib	struct drm_property *sharpness;
175235783Skib	struct drm_property *flicker_filter;
176235783Skib	struct drm_property *flicker_filter_adaptive;
177235783Skib	struct drm_property *flicker_filter_2d;
178235783Skib	struct drm_property *tv_chroma_filter;
179235783Skib	struct drm_property *tv_luma_filter;
180235783Skib	struct drm_property *dot_crawl;
181235783Skib
182235783Skib	/* add the property for the SDVO-TV/LVDS */
183235783Skib	struct drm_property *brightness;
184235783Skib
185235783Skib	/* Add variable to record current setting for the above property */
186235783Skib	u32	left_margin, right_margin, top_margin, bottom_margin;
187235783Skib
188235783Skib	/* this is to get the range of margin.*/
189235783Skib	u32	max_hscan,  max_vscan;
190235783Skib	u32	max_hpos, cur_hpos;
191235783Skib	u32	max_vpos, cur_vpos;
192235783Skib	u32	cur_brightness, max_brightness;
193235783Skib	u32	cur_contrast,	max_contrast;
194235783Skib	u32	cur_saturation, max_saturation;
195235783Skib	u32	cur_hue,	max_hue;
196235783Skib	u32	cur_sharpness,	max_sharpness;
197235783Skib	u32	cur_flicker_filter,		max_flicker_filter;
198235783Skib	u32	cur_flicker_filter_adaptive,	max_flicker_filter_adaptive;
199235783Skib	u32	cur_flicker_filter_2d,		max_flicker_filter_2d;
200235783Skib	u32	cur_tv_chroma_filter,	max_tv_chroma_filter;
201235783Skib	u32	cur_tv_luma_filter,	max_tv_luma_filter;
202235783Skib	u32	cur_dot_crawl,	max_dot_crawl;
203235783Skib};
204235783Skib
205235783Skibstatic struct intel_sdvo *to_intel_sdvo(struct drm_encoder *encoder)
206235783Skib{
207235783Skib	return container_of(encoder, struct intel_sdvo, base.base);
208235783Skib}
209235783Skib
210235783Skibstatic struct intel_sdvo *intel_attached_sdvo(struct drm_connector *connector)
211235783Skib{
212235783Skib	return container_of(intel_attached_encoder(connector),
213235783Skib			    struct intel_sdvo, base);
214235783Skib}
215235783Skib
216235783Skibstatic struct intel_sdvo_connector *to_intel_sdvo_connector(struct drm_connector *connector)
217235783Skib{
218235783Skib	return container_of(to_intel_connector(connector), struct intel_sdvo_connector, base);
219235783Skib}
220235783Skib
221235783Skibstatic bool
222235783Skibintel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags);
223235783Skibstatic bool
224235783Skibintel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
225235783Skib			      struct intel_sdvo_connector *intel_sdvo_connector,
226235783Skib			      int type);
227235783Skibstatic bool
228235783Skibintel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,
229235783Skib				   struct intel_sdvo_connector *intel_sdvo_connector);
230235783Skib
231235783Skib/**
232235783Skib * Writes the SDVOB or SDVOC with the given value, but always writes both
233235783Skib * SDVOB and SDVOC to work around apparent hardware issues (according to
234235783Skib * comments in the BIOS).
235235783Skib */
236235783Skibstatic void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val)
237235783Skib{
238235783Skib	struct drm_device *dev = intel_sdvo->base.base.dev;
239235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
240235783Skib	u32 bval = val, cval = val;
241235783Skib	int i;
242235783Skib
243235783Skib	if (intel_sdvo->sdvo_reg == PCH_SDVOB) {
244235783Skib		I915_WRITE(intel_sdvo->sdvo_reg, val);
245235783Skib		I915_READ(intel_sdvo->sdvo_reg);
246235783Skib		return;
247235783Skib	}
248235783Skib
249235783Skib	if (intel_sdvo->sdvo_reg == SDVOB) {
250235783Skib		cval = I915_READ(SDVOC);
251235783Skib	} else {
252235783Skib		bval = I915_READ(SDVOB);
253235783Skib	}
254235783Skib	/*
255235783Skib	 * Write the registers twice for luck. Sometimes,
256235783Skib	 * writing them only once doesn't appear to 'stick'.
257235783Skib	 * The BIOS does this too. Yay, magic
258235783Skib	 */
259235783Skib	for (i = 0; i < 2; i++)
260235783Skib	{
261235783Skib		I915_WRITE(SDVOB, bval);
262235783Skib		I915_READ(SDVOB);
263235783Skib		I915_WRITE(SDVOC, cval);
264235783Skib		I915_READ(SDVOC);
265235783Skib	}
266235783Skib}
267235783Skib
268235783Skibstatic bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch)
269235783Skib{
270235783Skib	struct iic_msg msgs[] = {
271235783Skib		{
272249041Sdumbbell			.slave = intel_sdvo->slave_addr << 1,
273235783Skib			.flags = 0,
274235783Skib			.len = 1,
275235783Skib			.buf = &addr,
276235783Skib		},
277235783Skib		{
278249041Sdumbbell			.slave = intel_sdvo->slave_addr << 1,
279296548Sdumbbell			.flags = I2C_M_RD,
280235783Skib			.len = 1,
281235783Skib			.buf = ch,
282235783Skib		}
283235783Skib	};
284235783Skib	int ret;
285235783Skib
286296548Sdumbbell	if ((ret = -iicbus_transfer(intel_sdvo->i2c, msgs, 2)) == 0)
287235783Skib		return true;
288235783Skib
289235783Skib	DRM_DEBUG_KMS("i2c transfer returned %d\n", ret);
290235783Skib	return false;
291235783Skib}
292235783Skib
293235783Skib#define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd}
294235783Skib/** Mapping of command numbers to names, for debug output */
295235783Skibstatic const struct _sdvo_cmd_name {
296235783Skib	u8 cmd;
297235783Skib	const char *name;
298235783Skib} sdvo_cmd_names[] = {
299235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_RESET),
300235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DEVICE_CAPS),
301235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FIRMWARE_REV),
302235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TRAINED_INPUTS),
303235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_OUTPUTS),
304235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_OUTPUTS),
305235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_IN_OUT_MAP),
306235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_IN_OUT_MAP),
307235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ATTACHED_DISPLAYS),
308235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HOT_PLUG_SUPPORT),
309235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_HOT_PLUG),
310235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_HOT_PLUG),
311235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE),
312235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_INPUT),
313235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_OUTPUT),
314235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART1),
315235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART2),
316235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1),
317235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART2),
318235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1),
319235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART1),
320235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART2),
321235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART1),
322235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART2),
323235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING),
324235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1),
325235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2),
326235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE),
327235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE),
328235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS),
329235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CLOCK_RATE_MULT),
330235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CLOCK_RATE_MULT),
331235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_TV_FORMATS),
332235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_FORMAT),
333235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_FORMAT),
334235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_POWER_STATES),
335235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_POWER_STATE),
336235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ENCODER_POWER_STATE),
337235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_DISPLAY_POWER_STATE),
338235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTROL_BUS_SWITCH),
339235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT),
340235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SCALED_HDTV_RESOLUTION_SUPPORT),
341235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS),
342235783Skib
343235783Skib	/* Add the op code for SDVO enhancements */
344235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_HPOS),
345235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HPOS),
346235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HPOS),
347235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_VPOS),
348235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_VPOS),
349235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_VPOS),
350235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_SATURATION),
351235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SATURATION),
352235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_SATURATION),
353235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_HUE),
354235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HUE),
355235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HUE),
356235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_CONTRAST),
357235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CONTRAST),
358235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTRAST),
359235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_BRIGHTNESS),
360235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_BRIGHTNESS),
361235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_BRIGHTNESS),
362235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_OVERSCAN_H),
363235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OVERSCAN_H),
364235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OVERSCAN_H),
365235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_OVERSCAN_V),
366235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OVERSCAN_V),
367235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OVERSCAN_V),
368235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER),
369235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER),
370235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER),
371235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER_ADAPTIVE),
372235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER_ADAPTIVE),
373235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER_ADAPTIVE),
374235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_FLICKER_FILTER_2D),
375235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FLICKER_FILTER_2D),
376235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_FLICKER_FILTER_2D),
377235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_SHARPNESS),
378235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SHARPNESS),
379235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_SHARPNESS),
380235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DOT_CRAWL),
381235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_DOT_CRAWL),
382235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_TV_CHROMA_FILTER),
383235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_CHROMA_FILTER),
384235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_CHROMA_FILTER),
385235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_MAX_TV_LUMA_FILTER),
386235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_LUMA_FILTER),
387235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_LUMA_FILTER),
388235783Skib
389235783Skib	/* HDMI op code */
390235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPP_ENCODE),
391235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ENCODE),
392235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ENCODE),
393235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_PIXEL_REPLI),
394235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PIXEL_REPLI),
395235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_COLORIMETRY_CAP),
396235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_COLORIMETRY),
397235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_COLORIMETRY),
398235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER),
399235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_AUDIO_STAT),
400235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_AUDIO_STAT),
401235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_INDEX),
402235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_INDEX),
403235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_INFO),
404235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_AV_SPLIT),
405235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_AV_SPLIT),
406235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_TXRATE),
407235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_TXRATE),
408235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_HBUF_DATA),
409235783Skib	SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_DATA),
410235783Skib};
411235783Skib
412277487Skib#define SDVO_NAME(svdo) ((svdo)->is_sdvob ? "SDVOB" : "SDVOC")
413235783Skib
414277487Skibstatic void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd,
415277487Skib				   const void *args, int args_len)
416235783Skib{
417235783Skib	int i;
418235783Skib
419296548Sdumbbell	DRM_DEBUG_KMS("%s: W: %02X ",
420296548Sdumbbell				SDVO_NAME(intel_sdvo), cmd);
421235783Skib	for (i = 0; i < args_len; i++)
422296548Sdumbbell		DRM_LOG_KMS("%02X ", ((const u8 *)args)[i]);
423235783Skib	for (; i < 8; i++)
424296548Sdumbbell		DRM_LOG_KMS("   ");
425280183Sdumbbell	for (i = 0; i < ARRAY_SIZE(sdvo_cmd_names); i++) {
426235783Skib		if (cmd == sdvo_cmd_names[i].cmd) {
427296548Sdumbbell			DRM_LOG_KMS("(%s)", sdvo_cmd_names[i].name);
428235783Skib			break;
429235783Skib		}
430235783Skib	}
431280183Sdumbbell	if (i == ARRAY_SIZE(sdvo_cmd_names))
432296548Sdumbbell		DRM_LOG_KMS("(%02X)", cmd);
433296548Sdumbbell	DRM_LOG_KMS("\n");
434235783Skib}
435235783Skib
436235783Skibstatic const char *cmd_status_names[] = {
437235783Skib	"Power on",
438235783Skib	"Success",
439235783Skib	"Not supported",
440235783Skib	"Invalid arg",
441235783Skib	"Pending",
442235783Skib	"Target not specified",
443235783Skib	"Scaling not supported"
444235783Skib};
445235783Skib
446296548Sdumbbellstatic bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
447296548Sdumbbell				 const void *args, int args_len)
448235783Skib{
449296548Sdumbbell	u8 *buf, status;
450296548Sdumbbell	struct iic_msg *msgs;
451296548Sdumbbell	int i, ret = true;
452235783Skib
453296548Sdumbbell        /* Would be simpler to allocate both in one go ? */
454296548Sdumbbell	buf = (u8 *)malloc(args_len * 2 + 2, DRM_MEM_KMS, M_NOWAIT | M_ZERO);
455296548Sdumbbell	if (!buf)
456296548Sdumbbell		return false;
457296548Sdumbbell
458296548Sdumbbell	msgs = malloc(args_len + 3 * sizeof(*msgs), DRM_MEM_KMS, M_NOWAIT | M_ZERO);
459296548Sdumbbell	if (!msgs) {
460296548Sdumbbell	        free(buf, DRM_MEM_KMS);
461296548Sdumbbell		return false;
462296548Sdumbbell        }
463296548Sdumbbell
464235783Skib	intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len);
465235783Skib
466235783Skib	for (i = 0; i < args_len; i++) {
467249041Sdumbbell		msgs[i].slave = intel_sdvo->slave_addr << 1;
468235783Skib		msgs[i].flags = 0;
469235783Skib		msgs[i].len = 2;
470235783Skib		msgs[i].buf = buf + 2 *i;
471235783Skib		buf[2*i + 0] = SDVO_I2C_ARG_0 - i;
472235783Skib		buf[2*i + 1] = ((const u8*)args)[i];
473235783Skib	}
474249041Sdumbbell	msgs[i].slave = intel_sdvo->slave_addr << 1;
475235783Skib	msgs[i].flags = 0;
476235783Skib	msgs[i].len = 2;
477235783Skib	msgs[i].buf = buf + 2*i;
478235783Skib	buf[2*i + 0] = SDVO_I2C_OPCODE;
479235783Skib	buf[2*i + 1] = cmd;
480235783Skib
481235783Skib	/* the following two are to read the response */
482235783Skib	status = SDVO_I2C_CMD_STATUS;
483249041Sdumbbell	msgs[i+1].slave = intel_sdvo->slave_addr << 1;
484235783Skib	msgs[i+1].flags = 0;
485235783Skib	msgs[i+1].len = 1;
486235783Skib	msgs[i+1].buf = &status;
487235783Skib
488249041Sdumbbell	msgs[i+2].slave = intel_sdvo->slave_addr << 1;
489296548Sdumbbell	msgs[i+2].flags = I2C_M_RD;
490235783Skib	msgs[i+2].len = 1;
491235783Skib	msgs[i+2].buf = &status;
492235783Skib
493296548Sdumbbell	ret = -iicbus_transfer(intel_sdvo->i2c, msgs, i+3);
494296548Sdumbbell	if (ret < 0) {
495235783Skib		DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
496296548Sdumbbell		ret = false;
497296548Sdumbbell		goto out;
498235783Skib	}
499235783Skib
500296548Sdumbbellout:
501296548Sdumbbell	free(msgs, DRM_MEM_KMS);
502296548Sdumbbell	free(buf, DRM_MEM_KMS);
503296548Sdumbbell	return ret;
504235783Skib}
505235783Skib
506296548Sdumbbellstatic bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
507296548Sdumbbell				     void *response, int response_len)
508235783Skib{
509296548Sdumbbell	u8 retry = 15; /* 5 quick checks, followed by 10 long checks */
510235783Skib	u8 status;
511235783Skib	int i;
512235783Skib
513235783Skib	DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo));
514235783Skib
515235783Skib	/*
516235783Skib	 * The documentation states that all commands will be
517235783Skib	 * processed within 15��s, and that we need only poll
518235783Skib	 * the status byte a maximum of 3 times in order for the
519235783Skib	 * command to be complete.
520235783Skib	 *
521235783Skib	 * Check 5 times in case the hardware failed to read the docs.
522296548Sdumbbell	 *
523296548Sdumbbell	 * Also beware that the first response by many devices is to
524296548Sdumbbell	 * reply PENDING and stall for time. TVs are notorious for
525296548Sdumbbell	 * requiring longer than specified to complete their replies.
526296548Sdumbbell	 * Originally (in the DDX long ago), the delay was only ever 15ms
527296548Sdumbbell	 * with an additional delay of 30ms applied for TVs added later after
528296548Sdumbbell	 * many experiments. To accommodate both sets of delays, we do a
529296548Sdumbbell	 * sequence of slow checks if the device is falling behind and fails
530296548Sdumbbell	 * to reply within 5*15��s.
531235783Skib	 */
532296548Sdumbbell	if (!intel_sdvo_read_byte(intel_sdvo,
533296548Sdumbbell				  SDVO_I2C_CMD_STATUS,
534296548Sdumbbell				  &status))
535235783Skib		goto log_fail;
536235783Skib
537296548Sdumbbell	while (status == SDVO_CMD_STATUS_PENDING && --retry) {
538296548Sdumbbell		if (retry < 10)
539296548Sdumbbell			DRM_MSLEEP(15);
540296548Sdumbbell		else
541296548Sdumbbell			udelay(15);
542296548Sdumbbell
543235783Skib		if (!intel_sdvo_read_byte(intel_sdvo,
544296548Sdumbbell					  SDVO_I2C_CMD_STATUS,
545296548Sdumbbell					  &status))
546235783Skib			goto log_fail;
547235783Skib	}
548235783Skib
549296548Sdumbbell	if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
550296548Sdumbbell		DRM_LOG_KMS("(%s)", cmd_status_names[status]);
551296548Sdumbbell	else
552296548Sdumbbell		DRM_LOG_KMS("(??? %d)", status);
553235783Skib
554235783Skib	if (status != SDVO_CMD_STATUS_SUCCESS)
555235783Skib		goto log_fail;
556235783Skib
557235783Skib	/* Read the command response */
558235783Skib	for (i = 0; i < response_len; i++) {
559235783Skib		if (!intel_sdvo_read_byte(intel_sdvo,
560235783Skib					  SDVO_I2C_RETURN_0 + i,
561235783Skib					  &((u8 *)response)[i]))
562235783Skib			goto log_fail;
563296548Sdumbbell		DRM_LOG_KMS(" %02X", ((u8 *)response)[i]);
564235783Skib	}
565296548Sdumbbell	DRM_LOG_KMS("\n");
566296548Sdumbbell	return true;
567235783Skib
568235783Skiblog_fail:
569296548Sdumbbell	DRM_LOG_KMS("... failed\n");
570296548Sdumbbell	return false;
571235783Skib}
572235783Skib
573235783Skibstatic int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
574235783Skib{
575235783Skib	if (mode->clock >= 100000)
576235783Skib		return 1;
577235783Skib	else if (mode->clock >= 50000)
578235783Skib		return 2;
579235783Skib	else
580235783Skib		return 4;
581235783Skib}
582235783Skib
583235783Skibstatic bool intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
584235783Skib					      u8 ddc_bus)
585235783Skib{
586235783Skib	/* This must be the immediately preceding write before the i2c xfer */
587235783Skib	return intel_sdvo_write_cmd(intel_sdvo,
588235783Skib				    SDVO_CMD_SET_CONTROL_BUS_SWITCH,
589235783Skib				    &ddc_bus, 1);
590235783Skib}
591235783Skib
592235783Skibstatic bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len)
593235783Skib{
594235783Skib	if (!intel_sdvo_write_cmd(intel_sdvo, cmd, data, len))
595235783Skib		return false;
596235783Skib
597235783Skib	return intel_sdvo_read_response(intel_sdvo, NULL, 0);
598235783Skib}
599235783Skib
600235783Skibstatic bool
601235783Skibintel_sdvo_get_value(struct intel_sdvo *intel_sdvo, u8 cmd, void *value, int len)
602235783Skib{
603235783Skib	if (!intel_sdvo_write_cmd(intel_sdvo, cmd, NULL, 0))
604235783Skib		return false;
605235783Skib
606235783Skib	return intel_sdvo_read_response(intel_sdvo, value, len);
607235783Skib}
608235783Skib
609235783Skibstatic bool intel_sdvo_set_target_input(struct intel_sdvo *intel_sdvo)
610235783Skib{
611235783Skib	struct intel_sdvo_set_target_input_args targets = {0};
612235783Skib	return intel_sdvo_set_value(intel_sdvo,
613235783Skib				    SDVO_CMD_SET_TARGET_INPUT,
614235783Skib				    &targets, sizeof(targets));
615235783Skib}
616235783Skib
617235783Skib/**
618235783Skib * Return whether each input is trained.
619235783Skib *
620235783Skib * This function is making an assumption about the layout of the response,
621235783Skib * which should be checked against the docs.
622235783Skib */
623235783Skibstatic bool intel_sdvo_get_trained_inputs(struct intel_sdvo *intel_sdvo, bool *input_1, bool *input_2)
624235783Skib{
625235783Skib	struct intel_sdvo_get_trained_inputs_response response;
626235783Skib
627296548Sdumbbell	BUILD_BUG_ON(sizeof(response) != 1);
628235783Skib	if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_TRAINED_INPUTS,
629235783Skib				  &response, sizeof(response)))
630235783Skib		return false;
631235783Skib
632235783Skib	*input_1 = response.input0_trained;
633235783Skib	*input_2 = response.input1_trained;
634235783Skib	return true;
635235783Skib}
636235783Skib
637235783Skibstatic bool intel_sdvo_set_active_outputs(struct intel_sdvo *intel_sdvo,
638235783Skib					  u16 outputs)
639235783Skib{
640235783Skib	return intel_sdvo_set_value(intel_sdvo,
641235783Skib				    SDVO_CMD_SET_ACTIVE_OUTPUTS,
642235783Skib				    &outputs, sizeof(outputs));
643235783Skib}
644235783Skib
645296548Sdumbbellstatic bool intel_sdvo_get_active_outputs(struct intel_sdvo *intel_sdvo,
646296548Sdumbbell					  u16 *outputs)
647296548Sdumbbell{
648296548Sdumbbell	return intel_sdvo_get_value(intel_sdvo,
649296548Sdumbbell				    SDVO_CMD_GET_ACTIVE_OUTPUTS,
650296548Sdumbbell				    outputs, sizeof(*outputs));
651296548Sdumbbell}
652296548Sdumbbell
653235783Skibstatic bool intel_sdvo_set_encoder_power_state(struct intel_sdvo *intel_sdvo,
654235783Skib					       int mode)
655235783Skib{
656235783Skib	u8 state = SDVO_ENCODER_STATE_ON;
657235783Skib
658235783Skib	switch (mode) {
659235783Skib	case DRM_MODE_DPMS_ON:
660235783Skib		state = SDVO_ENCODER_STATE_ON;
661235783Skib		break;
662235783Skib	case DRM_MODE_DPMS_STANDBY:
663235783Skib		state = SDVO_ENCODER_STATE_STANDBY;
664235783Skib		break;
665235783Skib	case DRM_MODE_DPMS_SUSPEND:
666235783Skib		state = SDVO_ENCODER_STATE_SUSPEND;
667235783Skib		break;
668235783Skib	case DRM_MODE_DPMS_OFF:
669235783Skib		state = SDVO_ENCODER_STATE_OFF;
670235783Skib		break;
671235783Skib	}
672235783Skib
673235783Skib	return intel_sdvo_set_value(intel_sdvo,
674235783Skib				    SDVO_CMD_SET_ENCODER_POWER_STATE, &state, sizeof(state));
675235783Skib}
676235783Skib
677235783Skibstatic bool intel_sdvo_get_input_pixel_clock_range(struct intel_sdvo *intel_sdvo,
678235783Skib						   int *clock_min,
679235783Skib						   int *clock_max)
680235783Skib{
681235783Skib	struct intel_sdvo_pixel_clock_range clocks;
682235783Skib
683296548Sdumbbell	BUILD_BUG_ON(sizeof(clocks) != 4);
684235783Skib	if (!intel_sdvo_get_value(intel_sdvo,
685235783Skib				  SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE,
686235783Skib				  &clocks, sizeof(clocks)))
687235783Skib		return false;
688235783Skib
689235783Skib	/* Convert the values from units of 10 kHz to kHz. */
690235783Skib	*clock_min = clocks.min * 10;
691235783Skib	*clock_max = clocks.max * 10;
692235783Skib	return true;
693235783Skib}
694235783Skib
695235783Skibstatic bool intel_sdvo_set_target_output(struct intel_sdvo *intel_sdvo,
696235783Skib					 u16 outputs)
697235783Skib{
698235783Skib	return intel_sdvo_set_value(intel_sdvo,
699235783Skib				    SDVO_CMD_SET_TARGET_OUTPUT,
700235783Skib				    &outputs, sizeof(outputs));
701235783Skib}
702235783Skib
703235783Skibstatic bool intel_sdvo_set_timing(struct intel_sdvo *intel_sdvo, u8 cmd,
704235783Skib				  struct intel_sdvo_dtd *dtd)
705235783Skib{
706235783Skib	return intel_sdvo_set_value(intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)) &&
707235783Skib		intel_sdvo_set_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2));
708235783Skib}
709235783Skib
710235783Skibstatic bool intel_sdvo_set_input_timing(struct intel_sdvo *intel_sdvo,
711235783Skib					 struct intel_sdvo_dtd *dtd)
712235783Skib{
713235783Skib	return intel_sdvo_set_timing(intel_sdvo,
714235783Skib				     SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd);
715235783Skib}
716235783Skib
717235783Skibstatic bool intel_sdvo_set_output_timing(struct intel_sdvo *intel_sdvo,
718235783Skib					 struct intel_sdvo_dtd *dtd)
719235783Skib{
720235783Skib	return intel_sdvo_set_timing(intel_sdvo,
721235783Skib				     SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd);
722235783Skib}
723235783Skib
724235783Skibstatic bool
725235783Skibintel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo,
726235783Skib					 uint16_t clock,
727235783Skib					 uint16_t width,
728235783Skib					 uint16_t height)
729235783Skib{
730235783Skib	struct intel_sdvo_preferred_input_timing_args args;
731235783Skib
732235783Skib	memset(&args, 0, sizeof(args));
733235783Skib	args.clock = clock;
734235783Skib	args.width = width;
735235783Skib	args.height = height;
736235783Skib	args.interlace = 0;
737235783Skib
738235783Skib	if (intel_sdvo->is_lvds &&
739235783Skib	   (intel_sdvo->sdvo_lvds_fixed_mode->hdisplay != width ||
740235783Skib	    intel_sdvo->sdvo_lvds_fixed_mode->vdisplay != height))
741235783Skib		args.scaled = 1;
742235783Skib
743235783Skib	return intel_sdvo_set_value(intel_sdvo,
744235783Skib				    SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING,
745235783Skib				    &args, sizeof(args));
746235783Skib}
747235783Skib
748235783Skibstatic bool intel_sdvo_get_preferred_input_timing(struct intel_sdvo *intel_sdvo,
749235783Skib						  struct intel_sdvo_dtd *dtd)
750235783Skib{
751296548Sdumbbell	BUILD_BUG_ON(sizeof(dtd->part1) != 8);
752296548Sdumbbell	BUILD_BUG_ON(sizeof(dtd->part2) != 8);
753235783Skib	return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1,
754235783Skib				    &dtd->part1, sizeof(dtd->part1)) &&
755235783Skib		intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2,
756235783Skib				     &dtd->part2, sizeof(dtd->part2));
757235783Skib}
758235783Skib
759235783Skibstatic bool intel_sdvo_set_clock_rate_mult(struct intel_sdvo *intel_sdvo, u8 val)
760235783Skib{
761235783Skib	return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1);
762235783Skib}
763235783Skib
764235783Skibstatic void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd,
765235783Skib					 const struct drm_display_mode *mode)
766235783Skib{
767235783Skib	uint16_t width, height;
768235783Skib	uint16_t h_blank_len, h_sync_len, v_blank_len, v_sync_len;
769235783Skib	uint16_t h_sync_offset, v_sync_offset;
770235783Skib	int mode_clock;
771235783Skib
772277487Skib	width = mode->hdisplay;
773277487Skib	height = mode->vdisplay;
774235783Skib
775296548Sdumbbell	/* do some mode translations */
776277487Skib	h_blank_len = mode->htotal - mode->hdisplay;
777277487Skib	h_sync_len = mode->hsync_end - mode->hsync_start;
778235783Skib
779277487Skib	v_blank_len = mode->vtotal - mode->vdisplay;
780277487Skib	v_sync_len = mode->vsync_end - mode->vsync_start;
781235783Skib
782277487Skib	h_sync_offset = mode->hsync_start - mode->hdisplay;
783277487Skib	v_sync_offset = mode->vsync_start - mode->vdisplay;
784235783Skib
785235783Skib	mode_clock = mode->clock;
786235783Skib	mode_clock /= intel_mode_get_pixel_multiplier(mode) ?: 1;
787235783Skib	mode_clock /= 10;
788235783Skib	dtd->part1.clock = mode_clock;
789235783Skib
790235783Skib	dtd->part1.h_active = width & 0xff;
791235783Skib	dtd->part1.h_blank = h_blank_len & 0xff;
792235783Skib	dtd->part1.h_high = (((width >> 8) & 0xf) << 4) |
793235783Skib		((h_blank_len >> 8) & 0xf);
794235783Skib	dtd->part1.v_active = height & 0xff;
795235783Skib	dtd->part1.v_blank = v_blank_len & 0xff;
796235783Skib	dtd->part1.v_high = (((height >> 8) & 0xf) << 4) |
797235783Skib		((v_blank_len >> 8) & 0xf);
798235783Skib
799235783Skib	dtd->part2.h_sync_off = h_sync_offset & 0xff;
800235783Skib	dtd->part2.h_sync_width = h_sync_len & 0xff;
801235783Skib	dtd->part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 |
802235783Skib		(v_sync_len & 0xf);
803235783Skib	dtd->part2.sync_off_width_high = ((h_sync_offset & 0x300) >> 2) |
804235783Skib		((h_sync_len & 0x300) >> 4) | ((v_sync_offset & 0x30) >> 2) |
805235783Skib		((v_sync_len & 0x30) >> 4);
806235783Skib
807235783Skib	dtd->part2.dtd_flags = 0x18;
808296548Sdumbbell	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
809296548Sdumbbell		dtd->part2.dtd_flags |= DTD_FLAG_INTERLACE;
810235783Skib	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
811296548Sdumbbell		dtd->part2.dtd_flags |= DTD_FLAG_HSYNC_POSITIVE;
812235783Skib	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
813296548Sdumbbell		dtd->part2.dtd_flags |= DTD_FLAG_VSYNC_POSITIVE;
814235783Skib
815235783Skib	dtd->part2.sdvo_flags = 0;
816235783Skib	dtd->part2.v_sync_off_high = v_sync_offset & 0xc0;
817235783Skib	dtd->part2.reserved = 0;
818235783Skib}
819235783Skib
820235783Skibstatic void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode,
821235783Skib					 const struct intel_sdvo_dtd *dtd)
822235783Skib{
823235783Skib	mode->hdisplay = dtd->part1.h_active;
824235783Skib	mode->hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8;
825235783Skib	mode->hsync_start = mode->hdisplay + dtd->part2.h_sync_off;
826235783Skib	mode->hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2;
827235783Skib	mode->hsync_end = mode->hsync_start + dtd->part2.h_sync_width;
828235783Skib	mode->hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4;
829235783Skib	mode->htotal = mode->hdisplay + dtd->part1.h_blank;
830235783Skib	mode->htotal += (dtd->part1.h_high & 0xf) << 8;
831235783Skib
832235783Skib	mode->vdisplay = dtd->part1.v_active;
833235783Skib	mode->vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8;
834235783Skib	mode->vsync_start = mode->vdisplay;
835235783Skib	mode->vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf;
836235783Skib	mode->vsync_start += (dtd->part2.sync_off_width_high & 0x0c) << 2;
837235783Skib	mode->vsync_start += dtd->part2.v_sync_off_high & 0xc0;
838235783Skib	mode->vsync_end = mode->vsync_start +
839235783Skib		(dtd->part2.v_sync_off_width & 0xf);
840235783Skib	mode->vsync_end += (dtd->part2.sync_off_width_high & 0x3) << 4;
841235783Skib	mode->vtotal = mode->vdisplay + dtd->part1.v_blank;
842235783Skib	mode->vtotal += (dtd->part1.v_high & 0xf) << 8;
843235783Skib
844235783Skib	mode->clock = dtd->part1.clock * 10;
845235783Skib
846235783Skib	mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
847296548Sdumbbell	if (dtd->part2.dtd_flags & DTD_FLAG_INTERLACE)
848296548Sdumbbell		mode->flags |= DRM_MODE_FLAG_INTERLACE;
849296548Sdumbbell	if (dtd->part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE)
850235783Skib		mode->flags |= DRM_MODE_FLAG_PHSYNC;
851296548Sdumbbell	if (dtd->part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE)
852235783Skib		mode->flags |= DRM_MODE_FLAG_PVSYNC;
853235783Skib}
854235783Skib
855235783Skibstatic bool intel_sdvo_check_supp_encode(struct intel_sdvo *intel_sdvo)
856235783Skib{
857235783Skib	struct intel_sdvo_encode encode;
858235783Skib
859296548Sdumbbell	BUILD_BUG_ON(sizeof(encode) != 2);
860235783Skib	return intel_sdvo_get_value(intel_sdvo,
861235783Skib				  SDVO_CMD_GET_SUPP_ENCODE,
862235783Skib				  &encode, sizeof(encode));
863235783Skib}
864235783Skib
865235783Skibstatic bool intel_sdvo_set_encode(struct intel_sdvo *intel_sdvo,
866235783Skib				  uint8_t mode)
867235783Skib{
868235783Skib	return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_ENCODE, &mode, 1);
869235783Skib}
870235783Skib
871235783Skibstatic bool intel_sdvo_set_colorimetry(struct intel_sdvo *intel_sdvo,
872235783Skib				       uint8_t mode)
873235783Skib{
874235783Skib	return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_COLORIMETRY, &mode, 1);
875235783Skib}
876235783Skib
877235783Skib#if 0
878235783Skibstatic void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo)
879235783Skib{
880235783Skib	int i, j;
881235783Skib	uint8_t set_buf_index[2];
882235783Skib	uint8_t av_split;
883235783Skib	uint8_t buf_size;
884235783Skib	uint8_t buf[48];
885235783Skib	uint8_t *pos;
886235783Skib
887235783Skib	intel_sdvo_get_value(encoder, SDVO_CMD_GET_HBUF_AV_SPLIT, &av_split, 1);
888235783Skib
889235783Skib	for (i = 0; i <= av_split; i++) {
890235783Skib		set_buf_index[0] = i; set_buf_index[1] = 0;
891235783Skib		intel_sdvo_write_cmd(encoder, SDVO_CMD_SET_HBUF_INDEX,
892235783Skib				     set_buf_index, 2);
893235783Skib		intel_sdvo_write_cmd(encoder, SDVO_CMD_GET_HBUF_INFO, NULL, 0);
894235783Skib		intel_sdvo_read_response(encoder, &buf_size, 1);
895235783Skib
896235783Skib		pos = buf;
897235783Skib		for (j = 0; j <= buf_size; j += 8) {
898235783Skib			intel_sdvo_write_cmd(encoder, SDVO_CMD_GET_HBUF_DATA,
899235783Skib					     NULL, 0);
900235783Skib			intel_sdvo_read_response(encoder, pos, 8);
901235783Skib			pos += 8;
902235783Skib		}
903235783Skib	}
904235783Skib}
905235783Skib#endif
906235783Skib
907296548Sdumbbellstatic bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
908296548Sdumbbell				       unsigned if_index, uint8_t tx_rate,
909296548Sdumbbell				       uint8_t *data, unsigned length)
910296548Sdumbbell{
911296548Sdumbbell	uint8_t set_buf_index[2] = { if_index, 0 };
912296548Sdumbbell	uint8_t hbuf_size, tmp[8];
913296548Sdumbbell	int i;
914296548Sdumbbell
915296548Sdumbbell	if (!intel_sdvo_set_value(intel_sdvo,
916296548Sdumbbell				  SDVO_CMD_SET_HBUF_INDEX,
917296548Sdumbbell				  set_buf_index, 2))
918296548Sdumbbell		return false;
919296548Sdumbbell
920296548Sdumbbell	if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HBUF_INFO,
921296548Sdumbbell				  &hbuf_size, 1))
922296548Sdumbbell		return false;
923296548Sdumbbell
924296548Sdumbbell	/* Buffer size is 0 based, hooray! */
925296548Sdumbbell	hbuf_size++;
926296548Sdumbbell
927296548Sdumbbell	DRM_DEBUG_KMS("writing sdvo hbuf: %i, hbuf_size %i, hbuf_size: %i\n",
928296548Sdumbbell		      if_index, length, hbuf_size);
929296548Sdumbbell
930296548Sdumbbell	for (i = 0; i < hbuf_size; i += 8) {
931296548Sdumbbell		memset(tmp, 0, 8);
932296548Sdumbbell		if (i < length)
933296548Sdumbbell			memcpy(tmp, data + i, min_t(unsigned, 8, length - i));
934296548Sdumbbell
935296548Sdumbbell		if (!intel_sdvo_set_value(intel_sdvo,
936296548Sdumbbell					  SDVO_CMD_SET_HBUF_DATA,
937296548Sdumbbell					  tmp, 8))
938296548Sdumbbell			return false;
939296548Sdumbbell	}
940296548Sdumbbell
941296548Sdumbbell	return intel_sdvo_set_value(intel_sdvo,
942296548Sdumbbell				    SDVO_CMD_SET_HBUF_TXRATE,
943296548Sdumbbell				    &tx_rate, 1);
944296548Sdumbbell}
945296548Sdumbbell
946235783Skibstatic bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)
947235783Skib{
948235783Skib	struct dip_infoframe avi_if = {
949235783Skib		.type = DIP_TYPE_AVI,
950235783Skib		.ver = DIP_VERSION_AVI,
951235783Skib		.len = DIP_LEN_AVI,
952235783Skib	};
953277487Skib	uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)];
954235783Skib
955235783Skib	intel_dip_infoframe_csum(&avi_if);
956235783Skib
957277487Skib	/* sdvo spec says that the ecc is handled by the hw, and it looks like
958277487Skib	 * we must not send the ecc field, either. */
959277487Skib	memcpy(sdvo_data, &avi_if, 3);
960277487Skib	sdvo_data[3] = avi_if.checksum;
961277487Skib	memcpy(&sdvo_data[4], &avi_if.body, sizeof(avi_if.body.avi));
962277487Skib
963296548Sdumbbell	return intel_sdvo_write_infoframe(intel_sdvo, SDVO_HBUF_INDEX_AVI_IF,
964296548Sdumbbell					  SDVO_HBUF_TX_VSYNC,
965296548Sdumbbell					  sdvo_data, sizeof(sdvo_data));
966235783Skib}
967235783Skib
968235783Skibstatic bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo)
969235783Skib{
970235783Skib	struct intel_sdvo_tv_format format;
971235783Skib	uint32_t format_map;
972235783Skib
973235783Skib	format_map = 1 << intel_sdvo->tv_format_index;
974235783Skib	memset(&format, 0, sizeof(format));
975235783Skib	memcpy(&format, &format_map, min(sizeof(format), sizeof(format_map)));
976235783Skib
977296548Sdumbbell	BUILD_BUG_ON(sizeof(format) != 6);
978235783Skib	return intel_sdvo_set_value(intel_sdvo,
979235783Skib				    SDVO_CMD_SET_TV_FORMAT,
980235783Skib				    &format, sizeof(format));
981235783Skib}
982235783Skib
983235783Skibstatic bool
984235783Skibintel_sdvo_set_output_timings_from_mode(struct intel_sdvo *intel_sdvo,
985254797Sdumbbell					const struct drm_display_mode *mode)
986235783Skib{
987235783Skib	struct intel_sdvo_dtd output_dtd;
988235783Skib
989235783Skib	if (!intel_sdvo_set_target_output(intel_sdvo,
990235783Skib					  intel_sdvo->attached_output))
991235783Skib		return false;
992235783Skib
993235783Skib	intel_sdvo_get_dtd_from_mode(&output_dtd, mode);
994235783Skib	if (!intel_sdvo_set_output_timing(intel_sdvo, &output_dtd))
995235783Skib		return false;
996235783Skib
997235783Skib	return true;
998235783Skib}
999235783Skib
1000296548Sdumbbell/* Asks the sdvo controller for the preferred input mode given the output mode.
1001296548Sdumbbell * Unfortunately we have to set up the full output mode to do that. */
1002235783Skibstatic bool
1003296548Sdumbbellintel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo,
1004296548Sdumbbell				    const struct drm_display_mode *mode,
1005296548Sdumbbell				    struct drm_display_mode *adjusted_mode)
1006235783Skib{
1007296548Sdumbbell	struct intel_sdvo_dtd input_dtd;
1008296548Sdumbbell
1009235783Skib	/* Reset the input timing to the screen. Assume always input 0. */
1010235783Skib	if (!intel_sdvo_set_target_input(intel_sdvo))
1011235783Skib		return false;
1012235783Skib
1013235783Skib	if (!intel_sdvo_create_preferred_input_timing(intel_sdvo,
1014235783Skib						      mode->clock / 10,
1015235783Skib						      mode->hdisplay,
1016235783Skib						      mode->vdisplay))
1017235783Skib		return false;
1018235783Skib
1019235783Skib	if (!intel_sdvo_get_preferred_input_timing(intel_sdvo,
1020296548Sdumbbell						   &input_dtd))
1021235783Skib		return false;
1022235783Skib
1023296548Sdumbbell	intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
1024296548Sdumbbell	intel_sdvo->dtd_sdvo_flags = input_dtd.part2.sdvo_flags;
1025235783Skib
1026235783Skib	return true;
1027235783Skib}
1028235783Skib
1029235783Skibstatic bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
1030280183Sdumbbell				  const struct drm_display_mode *mode,
1031235783Skib				  struct drm_display_mode *adjusted_mode)
1032235783Skib{
1033235783Skib	struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
1034235783Skib	int multiplier;
1035235783Skib
1036235783Skib	/* We need to construct preferred input timings based on our
1037235783Skib	 * output timings.  To do that, we have to set the output
1038235783Skib	 * timings, even though this isn't really the right place in
1039235783Skib	 * the sequence to do it. Oh well.
1040235783Skib	 */
1041235783Skib	if (intel_sdvo->is_tv) {
1042235783Skib		if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo, mode))
1043235783Skib			return false;
1044235783Skib
1045296548Sdumbbell		(void) intel_sdvo_get_preferred_input_mode(intel_sdvo,
1046296548Sdumbbell							   mode,
1047296548Sdumbbell							   adjusted_mode);
1048235783Skib	} else if (intel_sdvo->is_lvds) {
1049235783Skib		if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,
1050235783Skib							     intel_sdvo->sdvo_lvds_fixed_mode))
1051235783Skib			return false;
1052235783Skib
1053296548Sdumbbell		(void) intel_sdvo_get_preferred_input_mode(intel_sdvo,
1054296548Sdumbbell							   mode,
1055296548Sdumbbell							   adjusted_mode);
1056235783Skib	}
1057235783Skib
1058235783Skib	/* Make the CRTC code factor in the SDVO pixel multiplier.  The
1059235783Skib	 * SDVO device will factor out the multiplier during mode_set.
1060235783Skib	 */
1061235783Skib	multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode);
1062235783Skib	intel_mode_set_pixel_multiplier(adjusted_mode, multiplier);
1063235783Skib
1064235783Skib	return true;
1065235783Skib}
1066235783Skib
1067235783Skibstatic void intel_sdvo_mode_set(struct drm_encoder *encoder,
1068235783Skib				struct drm_display_mode *mode,
1069235783Skib				struct drm_display_mode *adjusted_mode)
1070235783Skib{
1071235783Skib	struct drm_device *dev = encoder->dev;
1072235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
1073235783Skib	struct drm_crtc *crtc = encoder->crtc;
1074235783Skib	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1075235783Skib	struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
1076235783Skib	u32 sdvox;
1077235783Skib	struct intel_sdvo_in_out_map in_out;
1078235783Skib	struct intel_sdvo_dtd input_dtd, output_dtd;
1079235783Skib	int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
1080235783Skib	int rate;
1081235783Skib
1082235783Skib	if (!mode)
1083235783Skib		return;
1084235783Skib
1085235783Skib	/* First, set the input mapping for the first input to our controlled
1086235783Skib	 * output. This is only correct if we're a single-input device, in
1087235783Skib	 * which case the first input is the output from the appropriate SDVO
1088235783Skib	 * channel on the motherboard.  In a two-input device, the first input
1089235783Skib	 * will be SDVOB and the second SDVOC.
1090235783Skib	 */
1091235783Skib	in_out.in0 = intel_sdvo->attached_output;
1092235783Skib	in_out.in1 = 0;
1093235783Skib
1094235783Skib	intel_sdvo_set_value(intel_sdvo,
1095235783Skib			     SDVO_CMD_SET_IN_OUT_MAP,
1096235783Skib			     &in_out, sizeof(in_out));
1097235783Skib
1098235783Skib	/* Set the output timings to the screen */
1099235783Skib	if (!intel_sdvo_set_target_output(intel_sdvo,
1100235783Skib					  intel_sdvo->attached_output))
1101235783Skib		return;
1102235783Skib
1103235783Skib	/* lvds has a special fixed output timing. */
1104235783Skib	if (intel_sdvo->is_lvds)
1105235783Skib		intel_sdvo_get_dtd_from_mode(&output_dtd,
1106235783Skib					     intel_sdvo->sdvo_lvds_fixed_mode);
1107235783Skib	else
1108235783Skib		intel_sdvo_get_dtd_from_mode(&output_dtd, mode);
1109296548Sdumbbell	if (!intel_sdvo_set_output_timing(intel_sdvo, &output_dtd))
1110296548Sdumbbell		DRM_INFO("Setting output timings on %s failed\n",
1111296548Sdumbbell			 SDVO_NAME(intel_sdvo));
1112235783Skib
1113235783Skib	/* Set the input timing to the screen. Assume always input 0. */
1114235783Skib	if (!intel_sdvo_set_target_input(intel_sdvo))
1115235783Skib		return;
1116235783Skib
1117235783Skib	if (intel_sdvo->has_hdmi_monitor) {
1118235783Skib		intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI);
1119235783Skib		intel_sdvo_set_colorimetry(intel_sdvo,
1120235783Skib					   SDVO_COLORIMETRY_RGB256);
1121235783Skib		intel_sdvo_set_avi_infoframe(intel_sdvo);
1122235783Skib	} else
1123235783Skib		intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI);
1124235783Skib
1125235783Skib	if (intel_sdvo->is_tv &&
1126235783Skib	    !intel_sdvo_set_tv_format(intel_sdvo))
1127235783Skib		return;
1128235783Skib
1129235783Skib	/* We have tried to get input timing in mode_fixup, and filled into
1130235783Skib	 * adjusted_mode.
1131235783Skib	 */
1132235783Skib	intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
1133296548Sdumbbell	if (intel_sdvo->is_tv || intel_sdvo->is_lvds)
1134296548Sdumbbell		input_dtd.part2.sdvo_flags = intel_sdvo->dtd_sdvo_flags;
1135296548Sdumbbell	if (!intel_sdvo_set_input_timing(intel_sdvo, &input_dtd))
1136296548Sdumbbell		DRM_INFO("Setting input timings on %s failed\n",
1137296548Sdumbbell			 SDVO_NAME(intel_sdvo));
1138235783Skib
1139235783Skib	switch (pixel_multiplier) {
1140235783Skib	default:
1141235783Skib	case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;
1142235783Skib	case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break;
1143235783Skib	case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break;
1144235783Skib	}
1145235783Skib	if (!intel_sdvo_set_clock_rate_mult(intel_sdvo, rate))
1146235783Skib		return;
1147235783Skib
1148235783Skib	/* Set the SDVO control regs. */
1149235783Skib	if (INTEL_INFO(dev)->gen >= 4) {
1150235783Skib		/* The real mode polarity is set by the SDVO commands, using
1151235783Skib		 * struct intel_sdvo_dtd. */
1152235783Skib		sdvox = SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH;
1153235783Skib		if (intel_sdvo->is_hdmi)
1154235783Skib			sdvox |= intel_sdvo->color_range;
1155235783Skib		if (INTEL_INFO(dev)->gen < 5)
1156235783Skib			sdvox |= SDVO_BORDER_ENABLE;
1157235783Skib	} else {
1158235783Skib		sdvox = I915_READ(intel_sdvo->sdvo_reg);
1159235783Skib		switch (intel_sdvo->sdvo_reg) {
1160235783Skib		case SDVOB:
1161235783Skib			sdvox &= SDVOB_PRESERVE_MASK;
1162235783Skib			break;
1163235783Skib		case SDVOC:
1164235783Skib			sdvox &= SDVOC_PRESERVE_MASK;
1165235783Skib			break;
1166235783Skib		}
1167235783Skib		sdvox |= (9 << 19) | SDVO_BORDER_ENABLE;
1168235783Skib	}
1169235783Skib
1170235783Skib	if (INTEL_PCH_TYPE(dev) >= PCH_CPT)
1171235783Skib		sdvox |= TRANSCODER_CPT(intel_crtc->pipe);
1172235783Skib	else
1173235783Skib		sdvox |= TRANSCODER(intel_crtc->pipe);
1174235783Skib
1175235783Skib	if (intel_sdvo->has_hdmi_audio)
1176235783Skib		sdvox |= SDVO_AUDIO_ENABLE;
1177235783Skib
1178235783Skib	if (INTEL_INFO(dev)->gen >= 4) {
1179235783Skib		/* done in crtc_mode_set as the dpll_md reg must be written early */
1180235783Skib	} else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
1181235783Skib		/* done in crtc_mode_set as it lives inside the dpll register */
1182235783Skib	} else {
1183235783Skib		sdvox |= (pixel_multiplier - 1) << SDVO_PORT_MULTIPLY_SHIFT;
1184235783Skib	}
1185235783Skib
1186235783Skib	if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL &&
1187235783Skib	    INTEL_INFO(dev)->gen < 5)
1188235783Skib		sdvox |= SDVO_STALL_SELECT;
1189235783Skib	intel_sdvo_write_sdvox(intel_sdvo, sdvox);
1190235783Skib}
1191235783Skib
1192296548Sdumbbellstatic bool intel_sdvo_connector_get_hw_state(struct intel_connector *connector)
1193235783Skib{
1194296548Sdumbbell	struct intel_sdvo_connector *intel_sdvo_connector =
1195296548Sdumbbell		to_intel_sdvo_connector(&connector->base);
1196296548Sdumbbell	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(&connector->base);
1197296548Sdumbbell	u16 active_outputs;
1198296548Sdumbbell
1199296548Sdumbbell	intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs);
1200296548Sdumbbell
1201296548Sdumbbell	if (active_outputs & intel_sdvo_connector->output_flag)
1202296548Sdumbbell		return true;
1203296548Sdumbbell	else
1204296548Sdumbbell		return false;
1205296548Sdumbbell}
1206296548Sdumbbell
1207296548Sdumbbellstatic bool intel_sdvo_get_hw_state(struct intel_encoder *encoder,
1208296548Sdumbbell				    enum pipe *pipe)
1209296548Sdumbbell{
1210296548Sdumbbell	struct drm_device *dev = encoder->base.dev;
1211235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
1212296548Sdumbbell	struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
1213296548Sdumbbell	u16 active_outputs;
1214296548Sdumbbell	u32 tmp;
1215296548Sdumbbell
1216296548Sdumbbell	tmp = I915_READ(intel_sdvo->sdvo_reg);
1217296548Sdumbbell	intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs);
1218296548Sdumbbell
1219296548Sdumbbell	if (!(tmp & SDVO_ENABLE) && (active_outputs == 0))
1220296548Sdumbbell		return false;
1221296548Sdumbbell
1222296548Sdumbbell	if (HAS_PCH_CPT(dev))
1223296548Sdumbbell		*pipe = PORT_TO_PIPE_CPT(tmp);
1224296548Sdumbbell	else
1225296548Sdumbbell		*pipe = PORT_TO_PIPE(tmp);
1226296548Sdumbbell
1227296548Sdumbbell	return true;
1228296548Sdumbbell}
1229296548Sdumbbell
1230296548Sdumbbellstatic void intel_disable_sdvo(struct intel_encoder *encoder)
1231296548Sdumbbell{
1232296548Sdumbbell	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
1233296548Sdumbbell	struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
1234235783Skib	u32 temp;
1235235783Skib
1236296548Sdumbbell	intel_sdvo_set_active_outputs(intel_sdvo, 0);
1237296548Sdumbbell	if (0)
1238296548Sdumbbell		intel_sdvo_set_encoder_power_state(intel_sdvo,
1239296548Sdumbbell						   DRM_MODE_DPMS_OFF);
1240296548Sdumbbell
1241296548Sdumbbell	temp = I915_READ(intel_sdvo->sdvo_reg);
1242296548Sdumbbell	if ((temp & SDVO_ENABLE) != 0) {
1243296548Sdumbbell		/* HW workaround for IBX, we need to move the port to
1244296548Sdumbbell		 * transcoder A before disabling it. */
1245296548Sdumbbell		if (HAS_PCH_IBX(encoder->base.dev)) {
1246296548Sdumbbell			struct drm_crtc *crtc = encoder->base.crtc;
1247296548Sdumbbell			int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
1248296548Sdumbbell
1249296548Sdumbbell			if (temp & SDVO_PIPE_B_SELECT) {
1250296548Sdumbbell				temp &= ~SDVO_PIPE_B_SELECT;
1251296548Sdumbbell				I915_WRITE(intel_sdvo->sdvo_reg, temp);
1252296548Sdumbbell				POSTING_READ(intel_sdvo->sdvo_reg);
1253296548Sdumbbell
1254296548Sdumbbell				/* Again we need to write this twice. */
1255296548Sdumbbell				I915_WRITE(intel_sdvo->sdvo_reg, temp);
1256296548Sdumbbell				POSTING_READ(intel_sdvo->sdvo_reg);
1257296548Sdumbbell
1258296548Sdumbbell				/* Transcoder selection bits only update
1259296548Sdumbbell				 * effectively on vblank. */
1260296548Sdumbbell				if (crtc)
1261296548Sdumbbell					intel_wait_for_vblank(encoder->base.dev, pipe);
1262296548Sdumbbell				else
1263296548Sdumbbell					DRM_MSLEEP(50);
1264296548Sdumbbell			}
1265296548Sdumbbell		}
1266296548Sdumbbell
1267296548Sdumbbell		intel_sdvo_write_sdvox(intel_sdvo, temp & ~SDVO_ENABLE);
1268296548Sdumbbell	}
1269296548Sdumbbell}
1270296548Sdumbbell
1271296548Sdumbbellstatic void intel_enable_sdvo(struct intel_encoder *encoder)
1272296548Sdumbbell{
1273296548Sdumbbell	struct drm_device *dev = encoder->base.dev;
1274296548Sdumbbell	struct drm_i915_private *dev_priv = dev->dev_private;
1275296548Sdumbbell	struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
1276296548Sdumbbell	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
1277296548Sdumbbell	u32 temp;
1278296548Sdumbbell	bool input1, input2;
1279296548Sdumbbell	int i;
1280296548Sdumbbell	u8 status;
1281296548Sdumbbell
1282296548Sdumbbell	temp = I915_READ(intel_sdvo->sdvo_reg);
1283296548Sdumbbell	if ((temp & SDVO_ENABLE) == 0) {
1284296548Sdumbbell		/* HW workaround for IBX, we need to move the port
1285296548Sdumbbell		 * to transcoder A before disabling it. */
1286296548Sdumbbell		if (HAS_PCH_IBX(dev)) {
1287296548Sdumbbell			struct drm_crtc *crtc = encoder->base.crtc;
1288296548Sdumbbell			int pipe = crtc ? to_intel_crtc(crtc)->pipe : -1;
1289296548Sdumbbell
1290296548Sdumbbell			/* Restore the transcoder select bit. */
1291296548Sdumbbell			if (pipe == PIPE_B)
1292296548Sdumbbell				temp |= SDVO_PIPE_B_SELECT;
1293296548Sdumbbell		}
1294296548Sdumbbell
1295296548Sdumbbell		intel_sdvo_write_sdvox(intel_sdvo, temp | SDVO_ENABLE);
1296296548Sdumbbell	}
1297296548Sdumbbell	for (i = 0; i < 2; i++)
1298296548Sdumbbell		intel_wait_for_vblank(dev, intel_crtc->pipe);
1299296548Sdumbbell
1300296548Sdumbbell	status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2);
1301296548Sdumbbell	/* Warn if the device reported failure to sync.
1302296548Sdumbbell	 * A lot of SDVO devices fail to notify of sync, but it's
1303296548Sdumbbell	 * a given it the status is a success, we succeeded.
1304296548Sdumbbell	 */
1305296548Sdumbbell	if (status == SDVO_CMD_STATUS_SUCCESS && !input1) {
1306296548Sdumbbell		DRM_DEBUG_KMS("First %s output reported failure to "
1307296548Sdumbbell				"sync\n", SDVO_NAME(intel_sdvo));
1308296548Sdumbbell	}
1309296548Sdumbbell
1310296548Sdumbbell	if (0)
1311296548Sdumbbell		intel_sdvo_set_encoder_power_state(intel_sdvo,
1312296548Sdumbbell						   DRM_MODE_DPMS_ON);
1313296548Sdumbbell	intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
1314296548Sdumbbell}
1315296548Sdumbbell
1316296548Sdumbbellstatic void intel_sdvo_dpms(struct drm_connector *connector, int mode)
1317296548Sdumbbell{
1318296548Sdumbbell	struct drm_crtc *crtc;
1319296548Sdumbbell	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
1320296548Sdumbbell
1321296548Sdumbbell	/* dvo supports only 2 dpms states. */
1322296548Sdumbbell	if (mode != DRM_MODE_DPMS_ON)
1323296548Sdumbbell		mode = DRM_MODE_DPMS_OFF;
1324296548Sdumbbell
1325296548Sdumbbell	if (mode == connector->dpms)
1326296548Sdumbbell		return;
1327296548Sdumbbell
1328296548Sdumbbell	connector->dpms = mode;
1329296548Sdumbbell
1330296548Sdumbbell	/* Only need to change hw state when actually enabled */
1331296548Sdumbbell	crtc = intel_sdvo->base.base.crtc;
1332296548Sdumbbell	if (!crtc) {
1333296548Sdumbbell		intel_sdvo->base.connectors_active = false;
1334296548Sdumbbell		return;
1335296548Sdumbbell	}
1336296548Sdumbbell
1337235783Skib	if (mode != DRM_MODE_DPMS_ON) {
1338235783Skib		intel_sdvo_set_active_outputs(intel_sdvo, 0);
1339235783Skib		if (0)
1340235783Skib			intel_sdvo_set_encoder_power_state(intel_sdvo, mode);
1341235783Skib
1342296548Sdumbbell		intel_sdvo->base.connectors_active = false;
1343296548Sdumbbell
1344296548Sdumbbell		intel_crtc_update_dpms(crtc);
1345235783Skib	} else {
1346296548Sdumbbell		intel_sdvo->base.connectors_active = true;
1347235783Skib
1348296548Sdumbbell		intel_crtc_update_dpms(crtc);
1349235783Skib
1350235783Skib		if (0)
1351235783Skib			intel_sdvo_set_encoder_power_state(intel_sdvo, mode);
1352235783Skib		intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
1353235783Skib	}
1354296548Sdumbbell
1355296548Sdumbbell	intel_modeset_check_state(connector->dev);
1356235783Skib}
1357235783Skib
1358235783Skibstatic int intel_sdvo_mode_valid(struct drm_connector *connector,
1359235783Skib				 struct drm_display_mode *mode)
1360235783Skib{
1361235783Skib	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
1362235783Skib
1363235783Skib	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
1364235783Skib		return MODE_NO_DBLESCAN;
1365235783Skib
1366235783Skib	if (intel_sdvo->pixel_clock_min > mode->clock)
1367235783Skib		return MODE_CLOCK_LOW;
1368235783Skib
1369235783Skib	if (intel_sdvo->pixel_clock_max < mode->clock)
1370235783Skib		return MODE_CLOCK_HIGH;
1371235783Skib
1372235783Skib	if (intel_sdvo->is_lvds) {
1373235783Skib		if (mode->hdisplay > intel_sdvo->sdvo_lvds_fixed_mode->hdisplay)
1374235783Skib			return MODE_PANEL;
1375235783Skib
1376235783Skib		if (mode->vdisplay > intel_sdvo->sdvo_lvds_fixed_mode->vdisplay)
1377235783Skib			return MODE_PANEL;
1378235783Skib	}
1379235783Skib
1380235783Skib	return MODE_OK;
1381235783Skib}
1382235783Skib
1383235783Skibstatic bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps)
1384235783Skib{
1385296548Sdumbbell	BUILD_BUG_ON(sizeof(*caps) != 8);
1386235783Skib	if (!intel_sdvo_get_value(intel_sdvo,
1387235783Skib				  SDVO_CMD_GET_DEVICE_CAPS,
1388235783Skib				  caps, sizeof(*caps)))
1389235783Skib		return false;
1390235783Skib
1391235783Skib	DRM_DEBUG_KMS("SDVO capabilities:\n"
1392235783Skib		      "  vendor_id: %d\n"
1393235783Skib		      "  device_id: %d\n"
1394235783Skib		      "  device_rev_id: %d\n"
1395235783Skib		      "  sdvo_version_major: %d\n"
1396235783Skib		      "  sdvo_version_minor: %d\n"
1397235783Skib		      "  sdvo_inputs_mask: %d\n"
1398235783Skib		      "  smooth_scaling: %d\n"
1399235783Skib		      "  sharp_scaling: %d\n"
1400235783Skib		      "  up_scaling: %d\n"
1401235783Skib		      "  down_scaling: %d\n"
1402235783Skib		      "  stall_support: %d\n"
1403235783Skib		      "  output_flags: %d\n",
1404235783Skib		      caps->vendor_id,
1405235783Skib		      caps->device_id,
1406235783Skib		      caps->device_rev_id,
1407235783Skib		      caps->sdvo_version_major,
1408235783Skib		      caps->sdvo_version_minor,
1409235783Skib		      caps->sdvo_inputs_mask,
1410235783Skib		      caps->smooth_scaling,
1411235783Skib		      caps->sharp_scaling,
1412235783Skib		      caps->up_scaling,
1413235783Skib		      caps->down_scaling,
1414235783Skib		      caps->stall_support,
1415235783Skib		      caps->output_flags);
1416235783Skib
1417235783Skib	return true;
1418235783Skib}
1419235783Skib
1420296548Sdumbbellstatic uint16_t intel_sdvo_get_hotplug_support(struct intel_sdvo *intel_sdvo)
1421235783Skib{
1422235783Skib	struct drm_device *dev = intel_sdvo->base.base.dev;
1423296548Sdumbbell	uint16_t hotplug;
1424235783Skib
1425235783Skib	/* HW Erratum: SDVO Hotplug is broken on all i945G chips, there's noise
1426235783Skib	 * on the line. */
1427235783Skib	if (IS_I945G(dev) || IS_I945GM(dev))
1428296548Sdumbbell		return 0;
1429235783Skib
1430296548Sdumbbell	if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT,
1431296548Sdumbbell					&hotplug, sizeof(hotplug)))
1432296548Sdumbbell		return 0;
1433296548Sdumbbell
1434296548Sdumbbell	return hotplug;
1435235783Skib}
1436235783Skib
1437235783Skibstatic void intel_sdvo_enable_hotplug(struct intel_encoder *encoder)
1438235783Skib{
1439235783Skib	struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
1440235783Skib
1441235783Skib	intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG,
1442296548Sdumbbell			&intel_sdvo->hotplug_active, 2);
1443235783Skib}
1444235783Skib
1445235783Skibstatic bool
1446235783Skibintel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo)
1447235783Skib{
1448235783Skib	/* Is there more than one type of output? */
1449235783Skib	return bitcount16(intel_sdvo->caps.output_flags) > 1;
1450235783Skib}
1451235783Skib
1452235783Skibstatic struct edid *
1453235783Skibintel_sdvo_get_edid(struct drm_connector *connector)
1454235783Skib{
1455235783Skib	struct intel_sdvo *sdvo = intel_attached_sdvo(connector);
1456235783Skib	return drm_get_edid(connector, sdvo->ddc);
1457235783Skib}
1458235783Skib
1459235783Skib/* Mac mini hack -- use the same DDC as the analog connector */
1460235783Skibstatic struct edid *
1461235783Skibintel_sdvo_get_analog_edid(struct drm_connector *connector)
1462235783Skib{
1463235783Skib	struct drm_i915_private *dev_priv = connector->dev->dev_private;
1464235783Skib
1465235783Skib	return drm_get_edid(connector,
1466277487Skib			    intel_gmbus_get_adapter(dev_priv,
1467277487Skib						    dev_priv->crt_ddc_pin));
1468235783Skib}
1469235783Skib
1470235783Skibstatic enum drm_connector_status
1471235783Skibintel_sdvo_tmds_sink_detect(struct drm_connector *connector)
1472235783Skib{
1473235783Skib	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
1474235783Skib	enum drm_connector_status status;
1475235783Skib	struct edid *edid;
1476235783Skib
1477235783Skib	edid = intel_sdvo_get_edid(connector);
1478235783Skib
1479235783Skib	if (edid == NULL && intel_sdvo_multifunc_encoder(intel_sdvo)) {
1480235783Skib		u8 ddc, saved_ddc = intel_sdvo->ddc_bus;
1481235783Skib
1482235783Skib		/*
1483235783Skib		 * Don't use the 1 as the argument of DDC bus switch to get
1484235783Skib		 * the EDID. It is used for SDVO SPD ROM.
1485235783Skib		 */
1486235783Skib		for (ddc = intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) {
1487235783Skib			intel_sdvo->ddc_bus = ddc;
1488235783Skib			edid = intel_sdvo_get_edid(connector);
1489235783Skib			if (edid)
1490235783Skib				break;
1491235783Skib		}
1492235783Skib		/*
1493235783Skib		 * If we found the EDID on the other bus,
1494235783Skib		 * assume that is the correct DDC bus.
1495235783Skib		 */
1496235783Skib		if (edid == NULL)
1497235783Skib			intel_sdvo->ddc_bus = saved_ddc;
1498235783Skib	}
1499235783Skib
1500235783Skib	/*
1501235783Skib	 * When there is no edid and no monitor is connected with VGA
1502235783Skib	 * port, try to use the CRT ddc to read the EDID for DVI-connector.
1503235783Skib	 */
1504235783Skib	if (edid == NULL)
1505235783Skib		edid = intel_sdvo_get_analog_edid(connector);
1506235783Skib
1507235783Skib	status = connector_status_unknown;
1508235783Skib	if (edid != NULL) {
1509235783Skib		/* DDC bus is shared, match EDID to connector type */
1510235783Skib		if (edid->input & DRM_EDID_INPUT_DIGITAL) {
1511235783Skib			status = connector_status_connected;
1512235783Skib			if (intel_sdvo->is_hdmi) {
1513235783Skib				intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid);
1514235783Skib				intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid);
1515235783Skib			}
1516235783Skib		} else
1517235783Skib			status = connector_status_disconnected;
1518235783Skib		free(edid, DRM_MEM_KMS);
1519235783Skib	}
1520235783Skib
1521235783Skib	if (status == connector_status_connected) {
1522235783Skib		struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
1523235783Skib		if (intel_sdvo_connector->force_audio != HDMI_AUDIO_AUTO)
1524235783Skib			intel_sdvo->has_hdmi_audio = (intel_sdvo_connector->force_audio == HDMI_AUDIO_ON);
1525235783Skib	}
1526235783Skib
1527235783Skib	return status;
1528235783Skib}
1529235783Skib
1530235783Skibstatic bool
1531235783Skibintel_sdvo_connector_matches_edid(struct intel_sdvo_connector *sdvo,
1532235783Skib				  struct edid *edid)
1533235783Skib{
1534235783Skib	bool monitor_is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL);
1535235783Skib	bool connector_is_digital = !!IS_DIGITAL(sdvo);
1536235783Skib
1537235783Skib	DRM_DEBUG_KMS("connector_is_digital? %d, monitor_is_digital? %d\n",
1538235783Skib		      connector_is_digital, monitor_is_digital);
1539235783Skib	return connector_is_digital == monitor_is_digital;
1540235783Skib}
1541235783Skib
1542235783Skibstatic enum drm_connector_status
1543235783Skibintel_sdvo_detect(struct drm_connector *connector, bool force)
1544235783Skib{
1545235783Skib	uint16_t response;
1546235783Skib	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
1547235783Skib	struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
1548235783Skib	enum drm_connector_status ret;
1549235783Skib
1550296548Sdumbbell	if (!intel_sdvo_get_value(intel_sdvo,
1551296548Sdumbbell				  SDVO_CMD_GET_ATTACHED_DISPLAYS,
1552296548Sdumbbell				  &response, 2))
1553235783Skib		return connector_status_unknown;
1554235783Skib
1555235783Skib	DRM_DEBUG_KMS("SDVO response %d %d [%x]\n",
1556235783Skib		      response & 0xff, response >> 8,
1557235783Skib		      intel_sdvo_connector->output_flag);
1558235783Skib
1559235783Skib	if (response == 0)
1560235783Skib		return connector_status_disconnected;
1561235783Skib
1562235783Skib	intel_sdvo->attached_output = response;
1563235783Skib
1564235783Skib	intel_sdvo->has_hdmi_monitor = false;
1565235783Skib	intel_sdvo->has_hdmi_audio = false;
1566235783Skib
1567235783Skib	if ((intel_sdvo_connector->output_flag & response) == 0)
1568235783Skib		ret = connector_status_disconnected;
1569235783Skib	else if (IS_TMDS(intel_sdvo_connector))
1570235783Skib		ret = intel_sdvo_tmds_sink_detect(connector);
1571235783Skib	else {
1572235783Skib		struct edid *edid;
1573235783Skib
1574235783Skib		/* if we have an edid check it matches the connection */
1575235783Skib		edid = intel_sdvo_get_edid(connector);
1576235783Skib		if (edid == NULL)
1577235783Skib			edid = intel_sdvo_get_analog_edid(connector);
1578235783Skib		if (edid != NULL) {
1579235783Skib			if (intel_sdvo_connector_matches_edid(intel_sdvo_connector,
1580235783Skib							      edid))
1581235783Skib				ret = connector_status_connected;
1582235783Skib			else
1583235783Skib				ret = connector_status_disconnected;
1584235783Skib
1585235783Skib			free(edid, DRM_MEM_KMS);
1586235783Skib		} else
1587235783Skib			ret = connector_status_connected;
1588235783Skib	}
1589235783Skib
1590235783Skib	/* May update encoder flag for like clock for SDVO TV, etc.*/
1591235783Skib	if (ret == connector_status_connected) {
1592235783Skib		intel_sdvo->is_tv = false;
1593235783Skib		intel_sdvo->is_lvds = false;
1594235783Skib		intel_sdvo->base.needs_tv_clock = false;
1595235783Skib
1596235783Skib		if (response & SDVO_TV_MASK) {
1597235783Skib			intel_sdvo->is_tv = true;
1598235783Skib			intel_sdvo->base.needs_tv_clock = true;
1599235783Skib		}
1600235783Skib		if (response & SDVO_LVDS_MASK)
1601235783Skib			intel_sdvo->is_lvds = intel_sdvo->sdvo_lvds_fixed_mode != NULL;
1602235783Skib	}
1603235783Skib
1604235783Skib	return ret;
1605235783Skib}
1606235783Skib
1607235783Skibstatic void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
1608235783Skib{
1609235783Skib	struct edid *edid;
1610235783Skib
1611235783Skib	/* set the bus switch and get the modes */
1612235783Skib	edid = intel_sdvo_get_edid(connector);
1613235783Skib
1614235783Skib	/*
1615235783Skib	 * Mac mini hack.  On this device, the DVI-I connector shares one DDC
1616235783Skib	 * link between analog and digital outputs. So, if the regular SDVO
1617235783Skib	 * DDC fails, check to see if the analog output is disconnected, in
1618235783Skib	 * which case we'll look there for the digital DDC data.
1619235783Skib	 */
1620235783Skib	if (edid == NULL)
1621235783Skib		edid = intel_sdvo_get_analog_edid(connector);
1622235783Skib
1623235783Skib	if (edid != NULL) {
1624235783Skib		if (intel_sdvo_connector_matches_edid(to_intel_sdvo_connector(connector),
1625235783Skib						      edid)) {
1626235783Skib			drm_mode_connector_update_edid_property(connector, edid);
1627235783Skib			drm_add_edid_modes(connector, edid);
1628235783Skib		}
1629235783Skib
1630235783Skib		free(edid, DRM_MEM_KMS);
1631235783Skib	}
1632235783Skib}
1633235783Skib
1634235783Skib/*
1635235783Skib * Set of SDVO TV modes.
1636235783Skib * Note!  This is in reply order (see loop in get_tv_modes).
1637235783Skib * XXX: all 60Hz refresh?
1638235783Skib */
1639235783Skibstatic const struct drm_display_mode sdvo_tv_modes[] = {
1640235783Skib	{ DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 5815, 320, 321, 384,
1641235783Skib		   416, 0, 200, 201, 232, 233, 0,
1642235783Skib		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
1643235783Skib	{ DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 6814, 320, 321, 384,
1644235783Skib		   416, 0, 240, 241, 272, 273, 0,
1645235783Skib		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
1646235783Skib	{ DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 9910, 400, 401, 464,
1647235783Skib		   496, 0, 300, 301, 332, 333, 0,
1648235783Skib		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
1649235783Skib	{ DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 16913, 640, 641, 704,
1650235783Skib		   736, 0, 350, 351, 382, 383, 0,
1651235783Skib		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
1652235783Skib	{ DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121, 640, 641, 704,
1653235783Skib		   736, 0, 400, 401, 432, 433, 0,
1654235783Skib		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
1655235783Skib	{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 22654, 640, 641, 704,
1656235783Skib		   736, 0, 480, 481, 512, 513, 0,
1657235783Skib		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
1658235783Skib	{ DRM_MODE("704x480", DRM_MODE_TYPE_DRIVER, 24624, 704, 705, 768,
1659235783Skib		   800, 0, 480, 481, 512, 513, 0,
1660235783Skib		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
1661235783Skib	{ DRM_MODE("704x576", DRM_MODE_TYPE_DRIVER, 29232, 704, 705, 768,
1662235783Skib		   800, 0, 576, 577, 608, 609, 0,
1663235783Skib		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
1664235783Skib	{ DRM_MODE("720x350", DRM_MODE_TYPE_DRIVER, 18751, 720, 721, 784,
1665235783Skib		   816, 0, 350, 351, 382, 383, 0,
1666235783Skib		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
1667235783Skib	{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 21199, 720, 721, 784,
1668235783Skib		   816, 0, 400, 401, 432, 433, 0,
1669235783Skib		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
1670235783Skib	{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 25116, 720, 721, 784,
1671235783Skib		   816, 0, 480, 481, 512, 513, 0,
1672235783Skib		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
1673235783Skib	{ DRM_MODE("720x540", DRM_MODE_TYPE_DRIVER, 28054, 720, 721, 784,
1674235783Skib		   816, 0, 540, 541, 572, 573, 0,
1675235783Skib		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
1676235783Skib	{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 29816, 720, 721, 784,
1677235783Skib		   816, 0, 576, 577, 608, 609, 0,
1678235783Skib		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
1679235783Skib	{ DRM_MODE("768x576", DRM_MODE_TYPE_DRIVER, 31570, 768, 769, 832,
1680235783Skib		   864, 0, 576, 577, 608, 609, 0,
1681235783Skib		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
1682235783Skib	{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 34030, 800, 801, 864,
1683235783Skib		   896, 0, 600, 601, 632, 633, 0,
1684235783Skib		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
1685235783Skib	{ DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 36581, 832, 833, 896,
1686235783Skib		   928, 0, 624, 625, 656, 657, 0,
1687235783Skib		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
1688235783Skib	{ DRM_MODE("920x766", DRM_MODE_TYPE_DRIVER, 48707, 920, 921, 984,
1689235783Skib		   1016, 0, 766, 767, 798, 799, 0,
1690235783Skib		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
1691235783Skib	{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 53827, 1024, 1025, 1088,
1692235783Skib		   1120, 0, 768, 769, 800, 801, 0,
1693235783Skib		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
1694235783Skib	{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 87265, 1280, 1281, 1344,
1695235783Skib		   1376, 0, 1024, 1025, 1056, 1057, 0,
1696235783Skib		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
1697235783Skib};
1698235783Skib
1699235783Skibstatic void intel_sdvo_get_tv_modes(struct drm_connector *connector)
1700235783Skib{
1701235783Skib	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
1702235783Skib	struct intel_sdvo_sdtv_resolution_request tv_res;
1703235783Skib	uint32_t reply = 0, format_map = 0;
1704235783Skib	int i;
1705235783Skib
1706235783Skib	/* Read the list of supported input resolutions for the selected TV
1707235783Skib	 * format.
1708235783Skib	 */
1709235783Skib	format_map = 1 << intel_sdvo->tv_format_index;
1710235783Skib	memcpy(&tv_res, &format_map,
1711235783Skib	       min(sizeof(format_map), sizeof(struct intel_sdvo_sdtv_resolution_request)));
1712235783Skib
1713235783Skib	if (!intel_sdvo_set_target_output(intel_sdvo, intel_sdvo->attached_output))
1714235783Skib		return;
1715235783Skib
1716296548Sdumbbell	BUILD_BUG_ON(sizeof(tv_res) != 3);
1717235783Skib	if (!intel_sdvo_write_cmd(intel_sdvo,
1718235783Skib				  SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
1719235783Skib				  &tv_res, sizeof(tv_res)))
1720235783Skib		return;
1721235783Skib	if (!intel_sdvo_read_response(intel_sdvo, &reply, 3))
1722235783Skib		return;
1723235783Skib
1724280183Sdumbbell	for (i = 0; i < ARRAY_SIZE(sdvo_tv_modes); i++)
1725235783Skib		if (reply & (1 << i)) {
1726235783Skib			struct drm_display_mode *nmode;
1727235783Skib			nmode = drm_mode_duplicate(connector->dev,
1728235783Skib						   &sdvo_tv_modes[i]);
1729235783Skib			if (nmode)
1730235783Skib				drm_mode_probed_add(connector, nmode);
1731235783Skib		}
1732235783Skib}
1733235783Skib
1734235783Skibstatic void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
1735235783Skib{
1736235783Skib	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
1737235783Skib	struct drm_i915_private *dev_priv = connector->dev->dev_private;
1738235783Skib	struct drm_display_mode *newmode;
1739235783Skib
1740235783Skib	/*
1741235783Skib	 * Attempt to get the mode list from DDC.
1742235783Skib	 * Assume that the preferred modes are
1743235783Skib	 * arranged in priority order.
1744235783Skib	 */
1745235783Skib	intel_ddc_get_modes(connector, intel_sdvo->i2c);
1746296548Sdumbbell	if (list_empty(&connector->probed_modes) == false)
1747235783Skib		goto end;
1748235783Skib
1749235783Skib	/* Fetch modes from VBT */
1750235783Skib	if (dev_priv->sdvo_lvds_vbt_mode != NULL) {
1751235783Skib		newmode = drm_mode_duplicate(connector->dev,
1752235783Skib					     dev_priv->sdvo_lvds_vbt_mode);
1753235783Skib		if (newmode != NULL) {
1754235783Skib			/* Guarantee the mode is preferred */
1755235783Skib			newmode->type = (DRM_MODE_TYPE_PREFERRED |
1756235783Skib					 DRM_MODE_TYPE_DRIVER);
1757235783Skib			drm_mode_probed_add(connector, newmode);
1758235783Skib		}
1759235783Skib	}
1760235783Skib
1761235783Skibend:
1762235783Skib	list_for_each_entry(newmode, &connector->probed_modes, head) {
1763235783Skib		if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
1764235783Skib			intel_sdvo->sdvo_lvds_fixed_mode =
1765235783Skib				drm_mode_duplicate(connector->dev, newmode);
1766235783Skib
1767235783Skib			intel_sdvo->is_lvds = true;
1768235783Skib			break;
1769235783Skib		}
1770235783Skib	}
1771235783Skib
1772235783Skib}
1773235783Skib
1774235783Skibstatic int intel_sdvo_get_modes(struct drm_connector *connector)
1775235783Skib{
1776235783Skib	struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
1777235783Skib
1778235783Skib	if (IS_TV(intel_sdvo_connector))
1779235783Skib		intel_sdvo_get_tv_modes(connector);
1780235783Skib	else if (IS_LVDS(intel_sdvo_connector))
1781235783Skib		intel_sdvo_get_lvds_modes(connector);
1782235783Skib	else
1783235783Skib		intel_sdvo_get_ddc_modes(connector);
1784235783Skib
1785235783Skib	return !list_empty(&connector->probed_modes);
1786235783Skib}
1787235783Skib
1788235783Skibstatic void
1789235783Skibintel_sdvo_destroy_enhance_property(struct drm_connector *connector)
1790235783Skib{
1791235783Skib	struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
1792235783Skib	struct drm_device *dev = connector->dev;
1793235783Skib
1794235783Skib	if (intel_sdvo_connector->left)
1795235783Skib		drm_property_destroy(dev, intel_sdvo_connector->left);
1796235783Skib	if (intel_sdvo_connector->right)
1797235783Skib		drm_property_destroy(dev, intel_sdvo_connector->right);
1798235783Skib	if (intel_sdvo_connector->top)
1799235783Skib		drm_property_destroy(dev, intel_sdvo_connector->top);
1800235783Skib	if (intel_sdvo_connector->bottom)
1801235783Skib		drm_property_destroy(dev, intel_sdvo_connector->bottom);
1802235783Skib	if (intel_sdvo_connector->hpos)
1803235783Skib		drm_property_destroy(dev, intel_sdvo_connector->hpos);
1804235783Skib	if (intel_sdvo_connector->vpos)
1805235783Skib		drm_property_destroy(dev, intel_sdvo_connector->vpos);
1806235783Skib	if (intel_sdvo_connector->saturation)
1807235783Skib		drm_property_destroy(dev, intel_sdvo_connector->saturation);
1808235783Skib	if (intel_sdvo_connector->contrast)
1809235783Skib		drm_property_destroy(dev, intel_sdvo_connector->contrast);
1810235783Skib	if (intel_sdvo_connector->hue)
1811235783Skib		drm_property_destroy(dev, intel_sdvo_connector->hue);
1812235783Skib	if (intel_sdvo_connector->sharpness)
1813235783Skib		drm_property_destroy(dev, intel_sdvo_connector->sharpness);
1814235783Skib	if (intel_sdvo_connector->flicker_filter)
1815235783Skib		drm_property_destroy(dev, intel_sdvo_connector->flicker_filter);
1816235783Skib	if (intel_sdvo_connector->flicker_filter_2d)
1817235783Skib		drm_property_destroy(dev, intel_sdvo_connector->flicker_filter_2d);
1818235783Skib	if (intel_sdvo_connector->flicker_filter_adaptive)
1819235783Skib		drm_property_destroy(dev, intel_sdvo_connector->flicker_filter_adaptive);
1820235783Skib	if (intel_sdvo_connector->tv_luma_filter)
1821235783Skib		drm_property_destroy(dev, intel_sdvo_connector->tv_luma_filter);
1822235783Skib	if (intel_sdvo_connector->tv_chroma_filter)
1823235783Skib		drm_property_destroy(dev, intel_sdvo_connector->tv_chroma_filter);
1824235783Skib	if (intel_sdvo_connector->dot_crawl)
1825235783Skib		drm_property_destroy(dev, intel_sdvo_connector->dot_crawl);
1826235783Skib	if (intel_sdvo_connector->brightness)
1827235783Skib		drm_property_destroy(dev, intel_sdvo_connector->brightness);
1828235783Skib}
1829235783Skib
1830235783Skibstatic void intel_sdvo_destroy(struct drm_connector *connector)
1831235783Skib{
1832235783Skib	struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
1833235783Skib
1834235783Skib	if (intel_sdvo_connector->tv_format)
1835235783Skib		drm_property_destroy(connector->dev,
1836235783Skib				     intel_sdvo_connector->tv_format);
1837235783Skib
1838235783Skib	intel_sdvo_destroy_enhance_property(connector);
1839235783Skib	drm_connector_cleanup(connector);
1840296548Sdumbbell	free(intel_sdvo_connector, DRM_MEM_KMS);
1841235783Skib}
1842235783Skib
1843235783Skibstatic bool intel_sdvo_detect_hdmi_audio(struct drm_connector *connector)
1844235783Skib{
1845235783Skib	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
1846235783Skib	struct edid *edid;
1847235783Skib	bool has_audio = false;
1848235783Skib
1849235783Skib	if (!intel_sdvo->is_hdmi)
1850235783Skib		return false;
1851235783Skib
1852235783Skib	edid = intel_sdvo_get_edid(connector);
1853235783Skib	if (edid != NULL && edid->input & DRM_EDID_INPUT_DIGITAL)
1854235783Skib		has_audio = drm_detect_monitor_audio(edid);
1855296548Sdumbbell	free(edid, DRM_MEM_KMS);
1856235783Skib
1857235783Skib	return has_audio;
1858235783Skib}
1859235783Skib
1860235783Skibstatic int
1861235783Skibintel_sdvo_set_property(struct drm_connector *connector,
1862235783Skib			struct drm_property *property,
1863235783Skib			uint64_t val)
1864235783Skib{
1865235783Skib	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
1866235783Skib	struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
1867235783Skib	struct drm_i915_private *dev_priv = connector->dev->dev_private;
1868235783Skib	uint16_t temp_value;
1869235783Skib	uint8_t cmd;
1870235783Skib	int ret;
1871235783Skib
1872280183Sdumbbell	ret = drm_object_property_set_value(&connector->base, property, val);
1873235783Skib	if (ret)
1874235783Skib		return ret;
1875235783Skib
1876235783Skib	if (property == dev_priv->force_audio_property) {
1877235783Skib		int i = val;
1878235783Skib		bool has_audio;
1879235783Skib
1880235783Skib		if (i == intel_sdvo_connector->force_audio)
1881235783Skib			return 0;
1882235783Skib
1883235783Skib		intel_sdvo_connector->force_audio = i;
1884235783Skib
1885235783Skib		if (i == HDMI_AUDIO_AUTO)
1886235783Skib			has_audio = intel_sdvo_detect_hdmi_audio(connector);
1887235783Skib		else
1888235783Skib			has_audio = (i == HDMI_AUDIO_ON);
1889235783Skib
1890235783Skib		if (has_audio == intel_sdvo->has_hdmi_audio)
1891235783Skib			return 0;
1892235783Skib
1893235783Skib		intel_sdvo->has_hdmi_audio = has_audio;
1894235783Skib		goto done;
1895235783Skib	}
1896235783Skib
1897235783Skib	if (property == dev_priv->broadcast_rgb_property) {
1898235783Skib		if (val == !!intel_sdvo->color_range)
1899235783Skib			return 0;
1900235783Skib
1901235783Skib		intel_sdvo->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0;
1902235783Skib		goto done;
1903235783Skib	}
1904235783Skib
1905235783Skib#define CHECK_PROPERTY(name, NAME) \
1906235783Skib	if (intel_sdvo_connector->name == property) { \
1907235783Skib		if (intel_sdvo_connector->cur_##name == temp_value) return 0; \
1908235783Skib		if (intel_sdvo_connector->max_##name < temp_value) return -EINVAL; \
1909235783Skib		cmd = SDVO_CMD_SET_##NAME; \
1910235783Skib		intel_sdvo_connector->cur_##name = temp_value; \
1911235783Skib		goto set_value; \
1912235783Skib	}
1913235783Skib
1914235783Skib	if (property == intel_sdvo_connector->tv_format) {
1915235783Skib		if (val >= TV_FORMAT_NUM)
1916235783Skib			return -EINVAL;
1917235783Skib
1918235783Skib		if (intel_sdvo->tv_format_index ==
1919235783Skib		    intel_sdvo_connector->tv_format_supported[val])
1920235783Skib			return 0;
1921235783Skib
1922235783Skib		intel_sdvo->tv_format_index = intel_sdvo_connector->tv_format_supported[val];
1923235783Skib		goto done;
1924235783Skib	} else if (IS_TV_OR_LVDS(intel_sdvo_connector)) {
1925235783Skib		temp_value = val;
1926235783Skib		if (intel_sdvo_connector->left == property) {
1927280183Sdumbbell			drm_object_property_set_value(&connector->base,
1928235783Skib							 intel_sdvo_connector->right, val);
1929235783Skib			if (intel_sdvo_connector->left_margin == temp_value)
1930235783Skib				return 0;
1931235783Skib
1932235783Skib			intel_sdvo_connector->left_margin = temp_value;
1933235783Skib			intel_sdvo_connector->right_margin = temp_value;
1934235783Skib			temp_value = intel_sdvo_connector->max_hscan -
1935235783Skib				intel_sdvo_connector->left_margin;
1936235783Skib			cmd = SDVO_CMD_SET_OVERSCAN_H;
1937235783Skib			goto set_value;
1938235783Skib		} else if (intel_sdvo_connector->right == property) {
1939280183Sdumbbell			drm_object_property_set_value(&connector->base,
1940235783Skib							 intel_sdvo_connector->left, val);
1941235783Skib			if (intel_sdvo_connector->right_margin == temp_value)
1942235783Skib				return 0;
1943235783Skib
1944235783Skib			intel_sdvo_connector->left_margin = temp_value;
1945235783Skib			intel_sdvo_connector->right_margin = temp_value;
1946235783Skib			temp_value = intel_sdvo_connector->max_hscan -
1947235783Skib				intel_sdvo_connector->left_margin;
1948235783Skib			cmd = SDVO_CMD_SET_OVERSCAN_H;
1949235783Skib			goto set_value;
1950235783Skib		} else if (intel_sdvo_connector->top == property) {
1951280183Sdumbbell			drm_object_property_set_value(&connector->base,
1952235783Skib							 intel_sdvo_connector->bottom, val);
1953235783Skib			if (intel_sdvo_connector->top_margin == temp_value)
1954235783Skib				return 0;
1955235783Skib
1956235783Skib			intel_sdvo_connector->top_margin = temp_value;
1957235783Skib			intel_sdvo_connector->bottom_margin = temp_value;
1958235783Skib			temp_value = intel_sdvo_connector->max_vscan -
1959235783Skib				intel_sdvo_connector->top_margin;
1960235783Skib			cmd = SDVO_CMD_SET_OVERSCAN_V;
1961235783Skib			goto set_value;
1962235783Skib		} else if (intel_sdvo_connector->bottom == property) {
1963280183Sdumbbell			drm_object_property_set_value(&connector->base,
1964235783Skib							 intel_sdvo_connector->top, val);
1965235783Skib			if (intel_sdvo_connector->bottom_margin == temp_value)
1966235783Skib				return 0;
1967235783Skib
1968235783Skib			intel_sdvo_connector->top_margin = temp_value;
1969235783Skib			intel_sdvo_connector->bottom_margin = temp_value;
1970235783Skib			temp_value = intel_sdvo_connector->max_vscan -
1971235783Skib				intel_sdvo_connector->top_margin;
1972235783Skib			cmd = SDVO_CMD_SET_OVERSCAN_V;
1973235783Skib			goto set_value;
1974235783Skib		}
1975235783Skib		CHECK_PROPERTY(hpos, HPOS)
1976235783Skib		CHECK_PROPERTY(vpos, VPOS)
1977235783Skib		CHECK_PROPERTY(saturation, SATURATION)
1978235783Skib		CHECK_PROPERTY(contrast, CONTRAST)
1979235783Skib		CHECK_PROPERTY(hue, HUE)
1980235783Skib		CHECK_PROPERTY(brightness, BRIGHTNESS)
1981235783Skib		CHECK_PROPERTY(sharpness, SHARPNESS)
1982235783Skib		CHECK_PROPERTY(flicker_filter, FLICKER_FILTER)
1983235783Skib		CHECK_PROPERTY(flicker_filter_2d, FLICKER_FILTER_2D)
1984235783Skib		CHECK_PROPERTY(flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE)
1985235783Skib		CHECK_PROPERTY(tv_chroma_filter, TV_CHROMA_FILTER)
1986235783Skib		CHECK_PROPERTY(tv_luma_filter, TV_LUMA_FILTER)
1987235783Skib		CHECK_PROPERTY(dot_crawl, DOT_CRAWL)
1988235783Skib	}
1989235783Skib
1990235783Skib	return -EINVAL; /* unknown property */
1991235783Skib
1992235783Skibset_value:
1993235783Skib	if (!intel_sdvo_set_value(intel_sdvo, cmd, &temp_value, 2))
1994235783Skib		return -EIO;
1995235783Skib
1996235783Skib
1997235783Skibdone:
1998235783Skib	if (intel_sdvo->base.base.crtc) {
1999235783Skib		struct drm_crtc *crtc = intel_sdvo->base.base.crtc;
2000296548Sdumbbell		intel_set_mode(crtc, &crtc->mode,
2001296548Sdumbbell			       crtc->x, crtc->y, crtc->fb);
2002235783Skib	}
2003235783Skib
2004235783Skib	return 0;
2005235783Skib#undef CHECK_PROPERTY
2006235783Skib}
2007235783Skib
2008235783Skibstatic const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = {
2009235783Skib	.mode_fixup = intel_sdvo_mode_fixup,
2010235783Skib	.mode_set = intel_sdvo_mode_set,
2011296548Sdumbbell	.disable = intel_encoder_noop,
2012235783Skib};
2013235783Skib
2014235783Skibstatic const struct drm_connector_funcs intel_sdvo_connector_funcs = {
2015296548Sdumbbell	.dpms = intel_sdvo_dpms,
2016235783Skib	.detect = intel_sdvo_detect,
2017235783Skib	.fill_modes = drm_helper_probe_single_connector_modes,
2018235783Skib	.set_property = intel_sdvo_set_property,
2019235783Skib	.destroy = intel_sdvo_destroy,
2020235783Skib};
2021235783Skib
2022235783Skibstatic const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
2023235783Skib	.get_modes = intel_sdvo_get_modes,
2024235783Skib	.mode_valid = intel_sdvo_mode_valid,
2025235783Skib	.best_encoder = intel_best_encoder,
2026235783Skib};
2027235783Skib
2028235783Skibstatic void intel_sdvo_enc_destroy(struct drm_encoder *encoder)
2029235783Skib{
2030235783Skib	struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
2031235783Skib
2032235783Skib	if (intel_sdvo->sdvo_lvds_fixed_mode != NULL)
2033235783Skib		drm_mode_destroy(encoder->dev,
2034235783Skib				 intel_sdvo->sdvo_lvds_fixed_mode);
2035235783Skib
2036280183Sdumbbell	device_delete_child(intel_sdvo->base.base.dev->dev,
2037235783Skib	    intel_sdvo->ddc_iic_bus);
2038235783Skib	intel_encoder_destroy(encoder);
2039235783Skib}
2040235783Skib
2041235783Skibstatic const struct drm_encoder_funcs intel_sdvo_enc_funcs = {
2042235783Skib	.destroy = intel_sdvo_enc_destroy,
2043235783Skib};
2044235783Skib
2045235783Skibstatic void
2046235783Skibintel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo)
2047235783Skib{
2048235783Skib	uint16_t mask = 0;
2049235783Skib	unsigned int num_bits;
2050235783Skib
2051235783Skib	/* Make a mask of outputs less than or equal to our own priority in the
2052235783Skib	 * list.
2053235783Skib	 */
2054235783Skib	switch (sdvo->controlled_output) {
2055235783Skib	case SDVO_OUTPUT_LVDS1:
2056235783Skib		mask |= SDVO_OUTPUT_LVDS1;
2057235783Skib	case SDVO_OUTPUT_LVDS0:
2058235783Skib		mask |= SDVO_OUTPUT_LVDS0;
2059235783Skib	case SDVO_OUTPUT_TMDS1:
2060235783Skib		mask |= SDVO_OUTPUT_TMDS1;
2061235783Skib	case SDVO_OUTPUT_TMDS0:
2062235783Skib		mask |= SDVO_OUTPUT_TMDS0;
2063235783Skib	case SDVO_OUTPUT_RGB1:
2064235783Skib		mask |= SDVO_OUTPUT_RGB1;
2065235783Skib	case SDVO_OUTPUT_RGB0:
2066235783Skib		mask |= SDVO_OUTPUT_RGB0;
2067235783Skib		break;
2068235783Skib	}
2069235783Skib
2070235783Skib	/* Count bits to find what number we are in the priority list. */
2071235783Skib	mask &= sdvo->caps.output_flags;
2072235783Skib	num_bits = bitcount16(mask);
2073235783Skib	/* If more than 3 outputs, default to DDC bus 3 for now. */
2074235783Skib	if (num_bits > 3)
2075235783Skib		num_bits = 3;
2076235783Skib
2077235783Skib	/* Corresponds to SDVO_CONTROL_BUS_DDCx */
2078235783Skib	sdvo->ddc_bus = 1 << num_bits;
2079235783Skib}
2080235783Skib
2081235783Skib/**
2082235783Skib * Choose the appropriate DDC bus for control bus switch command for this
2083235783Skib * SDVO output based on the controlled output.
2084235783Skib *
2085235783Skib * DDC bus number assignment is in a priority order of RGB outputs, then TMDS
2086235783Skib * outputs, then LVDS outputs.
2087235783Skib */
2088235783Skibstatic void
2089235783Skibintel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv,
2090235783Skib			  struct intel_sdvo *sdvo, u32 reg)
2091235783Skib{
2092235783Skib	struct sdvo_device_mapping *mapping;
2093235783Skib
2094277487Skib	if (sdvo->is_sdvob)
2095235783Skib		mapping = &(dev_priv->sdvo_mappings[0]);
2096235783Skib	else
2097235783Skib		mapping = &(dev_priv->sdvo_mappings[1]);
2098235783Skib
2099235783Skib	if (mapping->initialized)
2100235783Skib		sdvo->ddc_bus = 1 << ((mapping->ddc_pin & 0xf0) >> 4);
2101235783Skib	else
2102235783Skib		intel_sdvo_guess_ddc_bus(sdvo);
2103235783Skib}
2104235783Skib
2105235783Skibstatic void
2106235783Skibintel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv,
2107235783Skib			  struct intel_sdvo *sdvo, u32 reg)
2108235783Skib{
2109235783Skib	struct sdvo_device_mapping *mapping;
2110235783Skib	u8 pin;
2111235783Skib
2112277487Skib	if (sdvo->is_sdvob)
2113235783Skib		mapping = &dev_priv->sdvo_mappings[0];
2114235783Skib	else
2115235783Skib		mapping = &dev_priv->sdvo_mappings[1];
2116235783Skib
2117296548Sdumbbell	if (mapping->initialized && intel_gmbus_is_port_valid(mapping->i2c_pin))
2118235783Skib		pin = mapping->i2c_pin;
2119296548Sdumbbell	else
2120296548Sdumbbell		pin = GMBUS_PORT_DPB;
2121235783Skib
2122296548Sdumbbell	sdvo->i2c = intel_gmbus_get_adapter(dev_priv, pin);
2123296548Sdumbbell
2124296548Sdumbbell	/* With gmbus we should be able to drive sdvo i2c at 2MHz, but somehow
2125296548Sdumbbell	 * our code totally fails once we start using gmbus. Hence fall back to
2126296548Sdumbbell	 * bit banging for now. */
2127296548Sdumbbell	intel_gmbus_force_bit(sdvo->i2c, true);
2128235783Skib}
2129235783Skib
2130296548Sdumbbell/* undo any changes intel_sdvo_select_i2c_bus() did to sdvo->i2c */
2131296548Sdumbbellstatic void
2132296548Sdumbbellintel_sdvo_unselect_i2c_bus(struct intel_sdvo *sdvo)
2133296548Sdumbbell{
2134296548Sdumbbell	intel_gmbus_force_bit(sdvo->i2c, false);
2135296548Sdumbbell}
2136296548Sdumbbell
2137235783Skibstatic bool
2138235783Skibintel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo, int device)
2139235783Skib{
2140235783Skib	return intel_sdvo_check_supp_encode(intel_sdvo);
2141235783Skib}
2142235783Skib
2143235783Skibstatic u8
2144277487Skibintel_sdvo_get_slave_addr(struct drm_device *dev, struct intel_sdvo *sdvo)
2145235783Skib{
2146235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
2147235783Skib	struct sdvo_device_mapping *my_mapping, *other_mapping;
2148235783Skib
2149277487Skib	if (sdvo->is_sdvob) {
2150235783Skib		my_mapping = &dev_priv->sdvo_mappings[0];
2151235783Skib		other_mapping = &dev_priv->sdvo_mappings[1];
2152235783Skib	} else {
2153235783Skib		my_mapping = &dev_priv->sdvo_mappings[1];
2154235783Skib		other_mapping = &dev_priv->sdvo_mappings[0];
2155235783Skib	}
2156235783Skib
2157235783Skib	/* If the BIOS described our SDVO device, take advantage of it. */
2158235783Skib	if (my_mapping->slave_addr)
2159235783Skib		return my_mapping->slave_addr;
2160235783Skib
2161235783Skib	/* If the BIOS only described a different SDVO device, use the
2162235783Skib	 * address that it isn't using.
2163235783Skib	 */
2164235783Skib	if (other_mapping->slave_addr) {
2165235783Skib		if (other_mapping->slave_addr == 0x70)
2166235783Skib			return 0x72;
2167235783Skib		else
2168235783Skib			return 0x70;
2169235783Skib	}
2170235783Skib
2171235783Skib	/* No SDVO device info is found for another DVO port,
2172235783Skib	 * so use mapping assumption we had before BIOS parsing.
2173235783Skib	 */
2174277487Skib	if (sdvo->is_sdvob)
2175235783Skib		return 0x70;
2176235783Skib	else
2177235783Skib		return 0x72;
2178235783Skib}
2179235783Skib
2180235783Skibstatic void
2181235783Skibintel_sdvo_connector_init(struct intel_sdvo_connector *connector,
2182235783Skib			  struct intel_sdvo *encoder)
2183235783Skib{
2184235783Skib	drm_connector_init(encoder->base.base.dev,
2185235783Skib			   &connector->base.base,
2186235783Skib			   &intel_sdvo_connector_funcs,
2187235783Skib			   connector->base.base.connector_type);
2188235783Skib
2189235783Skib	drm_connector_helper_add(&connector->base.base,
2190235783Skib				 &intel_sdvo_connector_helper_funcs);
2191235783Skib
2192235783Skib	connector->base.base.interlace_allowed = 1;
2193235783Skib	connector->base.base.doublescan_allowed = 0;
2194235783Skib	connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
2195296548Sdumbbell	connector->base.get_hw_state = intel_sdvo_connector_get_hw_state;
2196235783Skib
2197235783Skib	intel_connector_attach_encoder(&connector->base, &encoder->base);
2198235783Skib}
2199235783Skib
2200235783Skibstatic void
2201235783Skibintel_sdvo_add_hdmi_properties(struct intel_sdvo_connector *connector)
2202235783Skib{
2203235783Skib	struct drm_device *dev = connector->base.base.dev;
2204235783Skib
2205235783Skib	intel_attach_force_audio_property(&connector->base.base);
2206235783Skib	if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev))
2207235783Skib		intel_attach_broadcast_rgb_property(&connector->base.base);
2208235783Skib}
2209235783Skib
2210235783Skibstatic bool
2211235783Skibintel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
2212235783Skib{
2213235783Skib	struct drm_encoder *encoder = &intel_sdvo->base.base;
2214235783Skib	struct drm_connector *connector;
2215235783Skib	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
2216235783Skib	struct intel_connector *intel_connector;
2217235783Skib	struct intel_sdvo_connector *intel_sdvo_connector;
2218235783Skib
2219296548Sdumbbell	intel_sdvo_connector = malloc(sizeof(struct intel_sdvo_connector), DRM_MEM_KMS, M_WAITOK | M_ZERO);
2220296548Sdumbbell	if (!intel_sdvo_connector)
2221296548Sdumbbell		return false;
2222235783Skib
2223235783Skib	if (device == 0) {
2224235783Skib		intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS0;
2225235783Skib		intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS0;
2226235783Skib	} else if (device == 1) {
2227235783Skib		intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS1;
2228235783Skib		intel_sdvo_connector->output_flag = SDVO_OUTPUT_TMDS1;
2229235783Skib	}
2230235783Skib
2231235783Skib	intel_connector = &intel_sdvo_connector->base;
2232235783Skib	connector = &intel_connector->base;
2233296548Sdumbbell	if (intel_sdvo_get_hotplug_support(intel_sdvo) &
2234296548Sdumbbell		intel_sdvo_connector->output_flag) {
2235235783Skib		connector->polled = DRM_CONNECTOR_POLL_HPD;
2236296548Sdumbbell		intel_sdvo->hotplug_active |= intel_sdvo_connector->output_flag;
2237235783Skib		/* Some SDVO devices have one-shot hotplug interrupts.
2238235783Skib		 * Ensure that they get re-enabled when an interrupt happens.
2239235783Skib		 */
2240235783Skib		intel_encoder->hot_plug = intel_sdvo_enable_hotplug;
2241235783Skib		intel_sdvo_enable_hotplug(intel_encoder);
2242296548Sdumbbell	} else {
2243296548Sdumbbell		connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
2244235783Skib	}
2245235783Skib	encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
2246235783Skib	connector->connector_type = DRM_MODE_CONNECTOR_DVID;
2247235783Skib
2248235783Skib	if (intel_sdvo_is_hdmi_connector(intel_sdvo, device)) {
2249235783Skib		connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
2250235783Skib		intel_sdvo->is_hdmi = true;
2251235783Skib	}
2252235783Skib
2253235783Skib	intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
2254235783Skib	if (intel_sdvo->is_hdmi)
2255235783Skib		intel_sdvo_add_hdmi_properties(intel_sdvo_connector);
2256235783Skib
2257235783Skib	return true;
2258235783Skib}
2259235783Skib
2260235783Skibstatic bool
2261235783Skibintel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type)
2262235783Skib{
2263235783Skib	struct drm_encoder *encoder = &intel_sdvo->base.base;
2264235783Skib	struct drm_connector *connector;
2265235783Skib	struct intel_connector *intel_connector;
2266235783Skib	struct intel_sdvo_connector *intel_sdvo_connector;
2267235783Skib
2268296548Sdumbbell	intel_sdvo_connector = malloc(sizeof(struct intel_sdvo_connector), DRM_MEM_KMS, M_WAITOK | M_ZERO);
2269235783Skib	if (!intel_sdvo_connector)
2270235783Skib		return false;
2271235783Skib
2272235783Skib	intel_connector = &intel_sdvo_connector->base;
2273235783Skib	connector = &intel_connector->base;
2274235783Skib	encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
2275235783Skib	connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
2276235783Skib
2277235783Skib	intel_sdvo->controlled_output |= type;
2278235783Skib	intel_sdvo_connector->output_flag = type;
2279235783Skib
2280235783Skib	intel_sdvo->is_tv = true;
2281235783Skib	intel_sdvo->base.needs_tv_clock = true;
2282235783Skib
2283235783Skib	intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
2284235783Skib
2285235783Skib	if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type))
2286235783Skib		goto err;
2287235783Skib
2288235783Skib	if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
2289235783Skib		goto err;
2290235783Skib
2291235783Skib	return true;
2292235783Skib
2293235783Skiberr:
2294235783Skib	intel_sdvo_destroy(connector);
2295235783Skib	return false;
2296235783Skib}
2297235783Skib
2298235783Skibstatic bool
2299235783Skibintel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device)
2300235783Skib{
2301235783Skib	struct drm_encoder *encoder = &intel_sdvo->base.base;
2302235783Skib	struct drm_connector *connector;
2303235783Skib	struct intel_connector *intel_connector;
2304235783Skib	struct intel_sdvo_connector *intel_sdvo_connector;
2305235783Skib
2306296548Sdumbbell	intel_sdvo_connector = malloc(sizeof(struct intel_sdvo_connector), DRM_MEM_KMS, M_WAITOK | M_ZERO);
2307296548Sdumbbell	if (!intel_sdvo_connector)
2308296548Sdumbbell		return false;
2309235783Skib
2310235783Skib	intel_connector = &intel_sdvo_connector->base;
2311235783Skib	connector = &intel_connector->base;
2312235783Skib	connector->polled = DRM_CONNECTOR_POLL_CONNECT;
2313235783Skib	encoder->encoder_type = DRM_MODE_ENCODER_DAC;
2314235783Skib	connector->connector_type = DRM_MODE_CONNECTOR_VGA;
2315235783Skib
2316235783Skib	if (device == 0) {
2317235783Skib		intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0;
2318235783Skib		intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0;
2319235783Skib	} else if (device == 1) {
2320235783Skib		intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1;
2321235783Skib		intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
2322235783Skib	}
2323235783Skib
2324235783Skib	intel_sdvo_connector_init(intel_sdvo_connector,
2325235783Skib				  intel_sdvo);
2326235783Skib	return true;
2327235783Skib}
2328235783Skib
2329235783Skibstatic bool
2330235783Skibintel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
2331235783Skib{
2332235783Skib	struct drm_encoder *encoder = &intel_sdvo->base.base;
2333235783Skib	struct drm_connector *connector;
2334235783Skib	struct intel_connector *intel_connector;
2335235783Skib	struct intel_sdvo_connector *intel_sdvo_connector;
2336235783Skib
2337296548Sdumbbell	intel_sdvo_connector = malloc(sizeof(struct intel_sdvo_connector), DRM_MEM_KMS, M_WAITOK | M_ZERO);
2338296548Sdumbbell	if (!intel_sdvo_connector)
2339296548Sdumbbell		return false;
2340235783Skib
2341235783Skib	intel_connector = &intel_sdvo_connector->base;
2342235783Skib	connector = &intel_connector->base;
2343235783Skib	encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
2344235783Skib	connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
2345235783Skib
2346235783Skib	if (device == 0) {
2347235783Skib		intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0;
2348235783Skib		intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0;
2349235783Skib	} else if (device == 1) {
2350235783Skib		intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1;
2351235783Skib		intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
2352235783Skib	}
2353235783Skib
2354235783Skib	intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
2355235783Skib	if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
2356235783Skib		goto err;
2357235783Skib
2358235783Skib	return true;
2359235783Skib
2360235783Skiberr:
2361235783Skib	intel_sdvo_destroy(connector);
2362235783Skib	return false;
2363235783Skib}
2364235783Skib
2365235783Skibstatic bool
2366235783Skibintel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags)
2367235783Skib{
2368235783Skib	intel_sdvo->is_tv = false;
2369235783Skib	intel_sdvo->base.needs_tv_clock = false;
2370235783Skib	intel_sdvo->is_lvds = false;
2371235783Skib
2372235783Skib	/* SDVO requires XXX1 function may not exist unless it has XXX0 function.*/
2373235783Skib
2374235783Skib	if (flags & SDVO_OUTPUT_TMDS0)
2375235783Skib		if (!intel_sdvo_dvi_init(intel_sdvo, 0))
2376235783Skib			return false;
2377235783Skib
2378235783Skib	if ((flags & SDVO_TMDS_MASK) == SDVO_TMDS_MASK)
2379235783Skib		if (!intel_sdvo_dvi_init(intel_sdvo, 1))
2380235783Skib			return false;
2381235783Skib
2382235783Skib	/* TV has no XXX1 function block */
2383235783Skib	if (flags & SDVO_OUTPUT_SVID0)
2384235783Skib		if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_SVID0))
2385235783Skib			return false;
2386235783Skib
2387235783Skib	if (flags & SDVO_OUTPUT_CVBS0)
2388235783Skib		if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_CVBS0))
2389235783Skib			return false;
2390235783Skib
2391277487Skib	if (flags & SDVO_OUTPUT_YPRPB0)
2392277487Skib		if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_YPRPB0))
2393277487Skib			return false;
2394277487Skib
2395235783Skib	if (flags & SDVO_OUTPUT_RGB0)
2396235783Skib		if (!intel_sdvo_analog_init(intel_sdvo, 0))
2397235783Skib			return false;
2398235783Skib
2399235783Skib	if ((flags & SDVO_RGB_MASK) == SDVO_RGB_MASK)
2400235783Skib		if (!intel_sdvo_analog_init(intel_sdvo, 1))
2401235783Skib			return false;
2402235783Skib
2403235783Skib	if (flags & SDVO_OUTPUT_LVDS0)
2404235783Skib		if (!intel_sdvo_lvds_init(intel_sdvo, 0))
2405235783Skib			return false;
2406235783Skib
2407235783Skib	if ((flags & SDVO_LVDS_MASK) == SDVO_LVDS_MASK)
2408235783Skib		if (!intel_sdvo_lvds_init(intel_sdvo, 1))
2409235783Skib			return false;
2410235783Skib
2411235783Skib	if ((flags & SDVO_OUTPUT_MASK) == 0) {
2412235783Skib		unsigned char bytes[2];
2413235783Skib
2414235783Skib		intel_sdvo->controlled_output = 0;
2415235783Skib		memcpy(bytes, &intel_sdvo->caps.output_flags, 2);
2416235783Skib		DRM_DEBUG_KMS("%s: Unknown SDVO output type (0x%02x%02x)\n",
2417235783Skib			      SDVO_NAME(intel_sdvo),
2418235783Skib			      bytes[0], bytes[1]);
2419235783Skib		return false;
2420235783Skib	}
2421235783Skib	intel_sdvo->base.crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
2422235783Skib
2423235783Skib	return true;
2424235783Skib}
2425235783Skib
2426296548Sdumbbellstatic void intel_sdvo_output_cleanup(struct intel_sdvo *intel_sdvo)
2427296548Sdumbbell{
2428296548Sdumbbell	struct drm_device *dev = intel_sdvo->base.base.dev;
2429296548Sdumbbell	struct drm_connector *connector, *tmp;
2430296548Sdumbbell
2431296548Sdumbbell	list_for_each_entry_safe(connector, tmp,
2432296548Sdumbbell				 &dev->mode_config.connector_list, head) {
2433296548Sdumbbell		if (intel_attached_encoder(connector) == &intel_sdvo->base)
2434296548Sdumbbell			intel_sdvo_destroy(connector);
2435296548Sdumbbell	}
2436296548Sdumbbell}
2437296548Sdumbbell
2438235783Skibstatic bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
2439235783Skib					  struct intel_sdvo_connector *intel_sdvo_connector,
2440235783Skib					  int type)
2441235783Skib{
2442235783Skib	struct drm_device *dev = intel_sdvo->base.base.dev;
2443235783Skib	struct intel_sdvo_tv_format format;
2444235783Skib	uint32_t format_map, i;
2445235783Skib
2446235783Skib	if (!intel_sdvo_set_target_output(intel_sdvo, type))
2447235783Skib		return false;
2448235783Skib
2449296548Sdumbbell	BUILD_BUG_ON(sizeof(format) != 6);
2450235783Skib	if (!intel_sdvo_get_value(intel_sdvo,
2451235783Skib				  SDVO_CMD_GET_SUPPORTED_TV_FORMATS,
2452235783Skib				  &format, sizeof(format)))
2453235783Skib		return false;
2454235783Skib
2455235783Skib	memcpy(&format_map, &format, min(sizeof(format_map), sizeof(format)));
2456235783Skib
2457235783Skib	if (format_map == 0)
2458235783Skib		return false;
2459235783Skib
2460235783Skib	intel_sdvo_connector->format_supported_num = 0;
2461235783Skib	for (i = 0 ; i < TV_FORMAT_NUM; i++)
2462235783Skib		if (format_map & (1 << i))
2463235783Skib			intel_sdvo_connector->tv_format_supported[intel_sdvo_connector->format_supported_num++] = i;
2464235783Skib
2465235783Skib
2466235783Skib	intel_sdvo_connector->tv_format =
2467235783Skib			drm_property_create(dev, DRM_MODE_PROP_ENUM,
2468235783Skib					    "mode", intel_sdvo_connector->format_supported_num);
2469235783Skib	if (!intel_sdvo_connector->tv_format)
2470235783Skib		return false;
2471235783Skib
2472235783Skib	for (i = 0; i < intel_sdvo_connector->format_supported_num; i++)
2473235783Skib		drm_property_add_enum(
2474235783Skib				intel_sdvo_connector->tv_format, i,
2475235783Skib				i, tv_format_names[intel_sdvo_connector->tv_format_supported[i]]);
2476235783Skib
2477235783Skib	intel_sdvo->tv_format_index = intel_sdvo_connector->tv_format_supported[0];
2478280183Sdumbbell	drm_object_attach_property(&intel_sdvo_connector->base.base.base,
2479235783Skib				      intel_sdvo_connector->tv_format, 0);
2480235783Skib	return true;
2481235783Skib
2482235783Skib}
2483235783Skib
2484235783Skib#define ENHANCEMENT(name, NAME) do { \
2485235783Skib	if (enhancements.name) { \
2486235783Skib		if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_MAX_##NAME, &data_value, 4) || \
2487235783Skib		    !intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_##NAME, &response, 2)) \
2488235783Skib			return false; \
2489235783Skib		intel_sdvo_connector->max_##name = data_value[0]; \
2490235783Skib		intel_sdvo_connector->cur_##name = response; \
2491235783Skib		intel_sdvo_connector->name = \
2492235783Skib			drm_property_create_range(dev, 0, #name, 0, data_value[0]); \
2493235783Skib		if (!intel_sdvo_connector->name) return false; \
2494280183Sdumbbell		drm_object_attach_property(&connector->base, \
2495235783Skib					      intel_sdvo_connector->name, \
2496235783Skib					      intel_sdvo_connector->cur_##name); \
2497235783Skib		DRM_DEBUG_KMS(#name ": max %d, default %d, current %d\n", \
2498235783Skib			      data_value[0], data_value[1], response); \
2499235783Skib	} \
2500235783Skib} while (0)
2501235783Skib
2502235783Skibstatic bool
2503235783Skibintel_sdvo_create_enhance_property_tv(struct intel_sdvo *intel_sdvo,
2504235783Skib				      struct intel_sdvo_connector *intel_sdvo_connector,
2505235783Skib				      struct intel_sdvo_enhancements_reply enhancements)
2506235783Skib{
2507235783Skib	struct drm_device *dev = intel_sdvo->base.base.dev;
2508235783Skib	struct drm_connector *connector = &intel_sdvo_connector->base.base;
2509235783Skib	uint16_t response, data_value[2];
2510235783Skib
2511235783Skib	/* when horizontal overscan is supported, Add the left/right  property */
2512235783Skib	if (enhancements.overscan_h) {
2513235783Skib		if (!intel_sdvo_get_value(intel_sdvo,
2514235783Skib					  SDVO_CMD_GET_MAX_OVERSCAN_H,
2515235783Skib					  &data_value, 4))
2516235783Skib			return false;
2517235783Skib
2518235783Skib		if (!intel_sdvo_get_value(intel_sdvo,
2519235783Skib					  SDVO_CMD_GET_OVERSCAN_H,
2520235783Skib					  &response, 2))
2521235783Skib			return false;
2522235783Skib
2523235783Skib		intel_sdvo_connector->max_hscan = data_value[0];
2524235783Skib		intel_sdvo_connector->left_margin = data_value[0] - response;
2525235783Skib		intel_sdvo_connector->right_margin = intel_sdvo_connector->left_margin;
2526235783Skib		intel_sdvo_connector->left =
2527235783Skib			drm_property_create_range(dev, 0, "left_margin", 0, data_value[0]);
2528235783Skib		if (!intel_sdvo_connector->left)
2529235783Skib			return false;
2530235783Skib
2531280183Sdumbbell		drm_object_attach_property(&connector->base,
2532235783Skib					      intel_sdvo_connector->left,
2533235783Skib					      intel_sdvo_connector->left_margin);
2534235783Skib
2535235783Skib		intel_sdvo_connector->right =
2536235783Skib			drm_property_create_range(dev, 0, "right_margin", 0, data_value[0]);
2537235783Skib		if (!intel_sdvo_connector->right)
2538235783Skib			return false;
2539235783Skib
2540280183Sdumbbell		drm_object_attach_property(&connector->base,
2541235783Skib					      intel_sdvo_connector->right,
2542235783Skib					      intel_sdvo_connector->right_margin);
2543235783Skib		DRM_DEBUG_KMS("h_overscan: max %d, "
2544235783Skib			      "default %d, current %d\n",
2545235783Skib			      data_value[0], data_value[1], response);
2546235783Skib	}
2547235783Skib
2548235783Skib	if (enhancements.overscan_v) {
2549235783Skib		if (!intel_sdvo_get_value(intel_sdvo,
2550235783Skib					  SDVO_CMD_GET_MAX_OVERSCAN_V,
2551235783Skib					  &data_value, 4))
2552235783Skib			return false;
2553235783Skib
2554235783Skib		if (!intel_sdvo_get_value(intel_sdvo,
2555235783Skib					  SDVO_CMD_GET_OVERSCAN_V,
2556235783Skib					  &response, 2))
2557235783Skib			return false;
2558235783Skib
2559235783Skib		intel_sdvo_connector->max_vscan = data_value[0];
2560235783Skib		intel_sdvo_connector->top_margin = data_value[0] - response;
2561235783Skib		intel_sdvo_connector->bottom_margin = intel_sdvo_connector->top_margin;
2562235783Skib		intel_sdvo_connector->top =
2563235783Skib			drm_property_create_range(dev, 0,
2564235783Skib					    "top_margin", 0, data_value[0]);
2565235783Skib		if (!intel_sdvo_connector->top)
2566235783Skib			return false;
2567235783Skib
2568280183Sdumbbell		drm_object_attach_property(&connector->base,
2569235783Skib					      intel_sdvo_connector->top,
2570235783Skib					      intel_sdvo_connector->top_margin);
2571235783Skib
2572235783Skib		intel_sdvo_connector->bottom =
2573235783Skib			drm_property_create_range(dev, 0,
2574235783Skib					    "bottom_margin", 0, data_value[0]);
2575235783Skib		if (!intel_sdvo_connector->bottom)
2576235783Skib			return false;
2577235783Skib
2578280183Sdumbbell		drm_object_attach_property(&connector->base,
2579235783Skib					      intel_sdvo_connector->bottom,
2580235783Skib					      intel_sdvo_connector->bottom_margin);
2581235783Skib		DRM_DEBUG_KMS("v_overscan: max %d, "
2582235783Skib			      "default %d, current %d\n",
2583235783Skib			      data_value[0], data_value[1], response);
2584235783Skib	}
2585235783Skib
2586235783Skib	ENHANCEMENT(hpos, HPOS);
2587235783Skib	ENHANCEMENT(vpos, VPOS);
2588235783Skib	ENHANCEMENT(saturation, SATURATION);
2589235783Skib	ENHANCEMENT(contrast, CONTRAST);
2590235783Skib	ENHANCEMENT(hue, HUE);
2591235783Skib	ENHANCEMENT(sharpness, SHARPNESS);
2592235783Skib	ENHANCEMENT(brightness, BRIGHTNESS);
2593235783Skib	ENHANCEMENT(flicker_filter, FLICKER_FILTER);
2594235783Skib	ENHANCEMENT(flicker_filter_adaptive, FLICKER_FILTER_ADAPTIVE);
2595235783Skib	ENHANCEMENT(flicker_filter_2d, FLICKER_FILTER_2D);
2596235783Skib	ENHANCEMENT(tv_chroma_filter, TV_CHROMA_FILTER);
2597235783Skib	ENHANCEMENT(tv_luma_filter, TV_LUMA_FILTER);
2598235783Skib
2599235783Skib	if (enhancements.dot_crawl) {
2600235783Skib		if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DOT_CRAWL, &response, 2))
2601235783Skib			return false;
2602235783Skib
2603235783Skib		intel_sdvo_connector->max_dot_crawl = 1;
2604235783Skib		intel_sdvo_connector->cur_dot_crawl = response & 0x1;
2605235783Skib		intel_sdvo_connector->dot_crawl =
2606235783Skib			drm_property_create_range(dev, 0, "dot_crawl", 0, 1);
2607235783Skib		if (!intel_sdvo_connector->dot_crawl)
2608235783Skib			return false;
2609235783Skib
2610280183Sdumbbell		drm_object_attach_property(&connector->base,
2611235783Skib					      intel_sdvo_connector->dot_crawl,
2612235783Skib					      intel_sdvo_connector->cur_dot_crawl);
2613235783Skib		DRM_DEBUG_KMS("dot crawl: current %d\n", response);
2614235783Skib	}
2615235783Skib
2616235783Skib	return true;
2617235783Skib}
2618235783Skib
2619235783Skibstatic bool
2620235783Skibintel_sdvo_create_enhance_property_lvds(struct intel_sdvo *intel_sdvo,
2621235783Skib					struct intel_sdvo_connector *intel_sdvo_connector,
2622235783Skib					struct intel_sdvo_enhancements_reply enhancements)
2623235783Skib{
2624235783Skib	struct drm_device *dev = intel_sdvo->base.base.dev;
2625235783Skib	struct drm_connector *connector = &intel_sdvo_connector->base.base;
2626235783Skib	uint16_t response, data_value[2];
2627235783Skib
2628235783Skib	ENHANCEMENT(brightness, BRIGHTNESS);
2629235783Skib
2630235783Skib	return true;
2631235783Skib}
2632235783Skib#undef ENHANCEMENT
2633235783Skib
2634235783Skibstatic bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo,
2635235783Skib					       struct intel_sdvo_connector *intel_sdvo_connector)
2636235783Skib{
2637235783Skib	union {
2638235783Skib		struct intel_sdvo_enhancements_reply reply;
2639235783Skib		uint16_t response;
2640235783Skib	} enhancements;
2641235783Skib
2642296548Sdumbbell	BUILD_BUG_ON(sizeof(enhancements) != 2);
2643235783Skib
2644235783Skib	enhancements.response = 0;
2645235783Skib	intel_sdvo_get_value(intel_sdvo,
2646235783Skib			     SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS,
2647235783Skib			     &enhancements, sizeof(enhancements));
2648235783Skib	if (enhancements.response == 0) {
2649235783Skib		DRM_DEBUG_KMS("No enhancement is supported\n");
2650235783Skib		return true;
2651235783Skib	}
2652235783Skib
2653235783Skib	if (IS_TV(intel_sdvo_connector))
2654235783Skib		return intel_sdvo_create_enhance_property_tv(intel_sdvo, intel_sdvo_connector, enhancements.reply);
2655235783Skib	else if (IS_LVDS(intel_sdvo_connector))
2656235783Skib		return intel_sdvo_create_enhance_property_lvds(intel_sdvo, intel_sdvo_connector, enhancements.reply);
2657235783Skib	else
2658235783Skib		return true;
2659235783Skib}
2660235783Skib
2661235783Skibstruct intel_sdvo_ddc_proxy_sc {
2662235783Skib	struct intel_sdvo *intel_sdvo;
2663235783Skib	device_t port;
2664235783Skib};
2665235783Skib
2666235783Skibstatic int
2667235783Skibintel_sdvo_ddc_proxy_probe(device_t idev)
2668235783Skib{
2669235783Skib
2670235783Skib	return (BUS_PROBE_DEFAULT);
2671235783Skib}
2672235783Skib
2673235783Skibstatic int
2674235783Skibintel_sdvo_ddc_proxy_attach(device_t idev)
2675235783Skib{
2676235783Skib	struct intel_sdvo_ddc_proxy_sc *sc;
2677235783Skib
2678235783Skib	sc = device_get_softc(idev);
2679235783Skib	sc->port = device_add_child(idev, "iicbus", -1);
2680235783Skib	if (sc->port == NULL)
2681235783Skib		return (ENXIO);
2682235783Skib	device_quiet(sc->port);
2683235783Skib	bus_generic_attach(idev);
2684235783Skib	return (0);
2685235783Skib}
2686235783Skib
2687235783Skibstatic int
2688235783Skibintel_sdvo_ddc_proxy_detach(device_t idev)
2689235783Skib{
2690235783Skib
2691235783Skib	bus_generic_detach(idev);
2692296548Sdumbbell	device_delete_children(idev);
2693296548Sdumbbell
2694235783Skib	return (0);
2695235783Skib}
2696235783Skib
2697235783Skibstatic int
2698235783Skibintel_sdvo_ddc_proxy_reset(device_t idev, u_char speed, u_char addr,
2699235783Skib    u_char *oldaddr)
2700235783Skib{
2701235783Skib	struct intel_sdvo_ddc_proxy_sc *sc;
2702235783Skib	struct intel_sdvo *sdvo;
2703296548Sdumbbell
2704235783Skib	sc = device_get_softc(idev);
2705235783Skib	sdvo = sc->intel_sdvo;
2706235783Skib
2707235783Skib	return (IICBUS_RESET(device_get_parent(sdvo->i2c), speed, addr,
2708235783Skib	    oldaddr));
2709235783Skib}
2710235783Skib
2711296548Sdumbbellstatic int intel_sdvo_ddc_proxy_xfer(device_t adapter,
2712296548Sdumbbell				     struct iic_msg *msgs,
2713296548Sdumbbell				     uint32_t num)
2714235783Skib{
2715235783Skib	struct intel_sdvo_ddc_proxy_sc *sc;
2716235783Skib	struct intel_sdvo *sdvo;
2717296548Sdumbbell
2718296548Sdumbbell	sc = device_get_softc(adapter);
2719235783Skib	sdvo = sc->intel_sdvo;
2720235783Skib
2721235783Skib	if (!intel_sdvo_set_control_bus_switch(sdvo, sdvo->ddc_bus))
2722296548Sdumbbell		return EIO;
2723235783Skib
2724235783Skib	return (iicbus_transfer(sdvo->i2c, msgs, num));
2725235783Skib}
2726235783Skib
2727296548Sdumbbellstatic device_method_t intel_sdvo_ddc_proxy_methods[] = {
2728296548Sdumbbell	DEVMETHOD(device_probe,		intel_sdvo_ddc_proxy_probe),
2729296548Sdumbbell	DEVMETHOD(device_attach,	intel_sdvo_ddc_proxy_attach),
2730296548Sdumbbell	DEVMETHOD(device_detach,	intel_sdvo_ddc_proxy_detach),
2731296548Sdumbbell	DEVMETHOD(iicbus_reset,		intel_sdvo_ddc_proxy_reset),
2732296548Sdumbbell	DEVMETHOD(iicbus_transfer,	intel_sdvo_ddc_proxy_xfer),
2733296548Sdumbbell	DEVMETHOD_END
2734296548Sdumbbell};
2735296548Sdumbbellstatic driver_t intel_sdvo_ddc_proxy_driver = {
2736296548Sdumbbell	"intel_sdvo_ddc_proxy",
2737296548Sdumbbell	intel_sdvo_ddc_proxy_methods,
2738296548Sdumbbell	sizeof(struct intel_sdvo_ddc_proxy_sc)
2739296548Sdumbbell};
2740296548Sdumbbellstatic devclass_t intel_sdvo_devclass;
2741296548SdumbbellDRIVER_MODULE_ORDERED(intel_sdvo_ddc_proxy, drmn, intel_sdvo_ddc_proxy_driver,
2742296548Sdumbbell    intel_sdvo_devclass, 0, 0, SI_ORDER_FIRST);
2743296548Sdumbbell
2744235783Skibstatic bool
2745296548Sdumbbellintel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo,
2746296548Sdumbbell			  struct drm_device *dev)
2747235783Skib{
2748235783Skib	struct intel_sdvo_ddc_proxy_sc *sc;
2749235783Skib	int ret;
2750235783Skib
2751280183Sdumbbell	sdvo->ddc_iic_bus = device_add_child(dev->dev,
2752296548Sdumbbell	    "intel_sdvo_ddc_proxy", sdvo->sdvo_reg);
2753235783Skib	if (sdvo->ddc_iic_bus == NULL) {
2754296548Sdumbbell		DRM_ERROR("cannot create ddc proxy bus %d\n", sdvo->sdvo_reg);
2755235783Skib		return (false);
2756235783Skib	}
2757235783Skib	device_quiet(sdvo->ddc_iic_bus);
2758235783Skib	ret = device_probe_and_attach(sdvo->ddc_iic_bus);
2759235783Skib	if (ret != 0) {
2760235783Skib		DRM_ERROR("cannot attach proxy bus %d error %d\n",
2761296548Sdumbbell		    sdvo->sdvo_reg, ret);
2762280183Sdumbbell		device_delete_child(dev->dev, sdvo->ddc_iic_bus);
2763235783Skib		return (false);
2764235783Skib	}
2765235783Skib	sc = device_get_softc(sdvo->ddc_iic_bus);
2766235783Skib	sc->intel_sdvo = sdvo;
2767235783Skib
2768235783Skib	sdvo->ddc = sc->port;
2769296548Sdumbbell
2770296548Sdumbbell	return true;
2771235783Skib}
2772235783Skib
2773277487Skibbool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
2774235783Skib{
2775235783Skib	struct drm_i915_private *dev_priv = dev->dev_private;
2776235783Skib	struct intel_encoder *intel_encoder;
2777235783Skib	struct intel_sdvo *intel_sdvo;
2778296548Sdumbbell	u32 hotplug_mask;
2779235783Skib	int i;
2780296548Sdumbbell	intel_sdvo = malloc(sizeof(struct intel_sdvo), DRM_MEM_KMS, M_WAITOK | M_ZERO);
2781296548Sdumbbell	if (!intel_sdvo)
2782296548Sdumbbell		return false;
2783235783Skib
2784235783Skib	intel_sdvo->sdvo_reg = sdvo_reg;
2785277487Skib	intel_sdvo->is_sdvob = is_sdvob;
2786277487Skib	intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, intel_sdvo) >> 1;
2787235783Skib	intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg);
2788296548Sdumbbell	if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev))
2789296548Sdumbbell		goto err_i2c_bus;
2790235783Skib
2791235783Skib	/* encoder type will be decided later */
2792235783Skib	intel_encoder = &intel_sdvo->base;
2793235783Skib	intel_encoder->type = INTEL_OUTPUT_SDVO;
2794235783Skib	drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0);
2795235783Skib
2796235783Skib	/* Read the regs to test if we can talk to the device */
2797235783Skib	for (i = 0; i < 0x40; i++) {
2798235783Skib		u8 byte;
2799235783Skib
2800235783Skib		if (!intel_sdvo_read_byte(intel_sdvo, i, &byte)) {
2801277487Skib			DRM_DEBUG_KMS("No SDVO device found on %s\n",
2802277487Skib				      SDVO_NAME(intel_sdvo));
2803235783Skib			goto err;
2804235783Skib		}
2805235783Skib	}
2806235783Skib
2807296548Sdumbbell	hotplug_mask = 0;
2808296548Sdumbbell	if (IS_G4X(dev)) {
2809296548Sdumbbell		hotplug_mask = intel_sdvo->is_sdvob ?
2810296548Sdumbbell			SDVOB_HOTPLUG_INT_STATUS_G4X : SDVOC_HOTPLUG_INT_STATUS_G4X;
2811296548Sdumbbell	} else if (IS_GEN4(dev)) {
2812296548Sdumbbell		hotplug_mask = intel_sdvo->is_sdvob ?
2813296548Sdumbbell			SDVOB_HOTPLUG_INT_STATUS_I965 : SDVOC_HOTPLUG_INT_STATUS_I965;
2814296548Sdumbbell	} else {
2815296548Sdumbbell		hotplug_mask = intel_sdvo->is_sdvob ?
2816296548Sdumbbell			SDVOB_HOTPLUG_INT_STATUS_I915 : SDVOC_HOTPLUG_INT_STATUS_I915;
2817296548Sdumbbell	}
2818235783Skib
2819235783Skib	drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs);
2820235783Skib
2821296548Sdumbbell	intel_encoder->disable = intel_disable_sdvo;
2822296548Sdumbbell	intel_encoder->enable = intel_enable_sdvo;
2823296548Sdumbbell	intel_encoder->get_hw_state = intel_sdvo_get_hw_state;
2824296548Sdumbbell
2825235783Skib	/* In default case sdvo lvds is false */
2826235783Skib	if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
2827235783Skib		goto err;
2828235783Skib
2829296548Sdumbbell	if (intel_sdvo_output_setup(intel_sdvo,
2830296548Sdumbbell				    intel_sdvo->caps.output_flags) != true) {
2831277487Skib		DRM_DEBUG_KMS("SDVO output failed to setup on %s\n",
2832277487Skib			      SDVO_NAME(intel_sdvo));
2833296548Sdumbbell		/* Output_setup can leave behind connectors! */
2834296548Sdumbbell		goto err_output;
2835296548Sdumbbell	}
2836235783Skib
2837296548Sdumbbell	/*
2838296548Sdumbbell	 * Cloning SDVO with anything is often impossible, since the SDVO
2839296548Sdumbbell	 * encoder can request a special input timing mode. And even if that's
2840296548Sdumbbell	 * not the case we have evidence that cloning a plain unscaled mode with
2841296548Sdumbbell	 * VGA doesn't really work. Furthermore the cloning flags are way too
2842296548Sdumbbell	 * simplistic anyway to express such constraints, so just give up on
2843296548Sdumbbell	 * cloning for SDVO encoders.
2844296548Sdumbbell	 */
2845296548Sdumbbell	intel_sdvo->base.cloneable = false;
2846296548Sdumbbell
2847296548Sdumbbell	/* Only enable the hotplug irq if we need it, to work around noisy
2848296548Sdumbbell	 * hotplug lines.
2849296548Sdumbbell	 */
2850296548Sdumbbell	if (intel_sdvo->hotplug_active)
2851296548Sdumbbell		dev_priv->hotplug_supported_mask |= hotplug_mask;
2852296548Sdumbbell
2853235783Skib	intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg);
2854235783Skib
2855235783Skib	/* Set the input timing to the screen. Assume always input 0. */
2856235783Skib	if (!intel_sdvo_set_target_input(intel_sdvo))
2857296548Sdumbbell		goto err_output;
2858235783Skib
2859235783Skib	if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo,
2860235783Skib						    &intel_sdvo->pixel_clock_min,
2861235783Skib						    &intel_sdvo->pixel_clock_max))
2862296548Sdumbbell		goto err_output;
2863235783Skib
2864235783Skib	DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, "
2865235783Skib			"clock range %dMHz - %dMHz, "
2866235783Skib			"input 1: %c, input 2: %c, "
2867235783Skib			"output 1: %c, output 2: %c\n",
2868235783Skib			SDVO_NAME(intel_sdvo),
2869235783Skib			intel_sdvo->caps.vendor_id, intel_sdvo->caps.device_id,
2870235783Skib			intel_sdvo->caps.device_rev_id,
2871235783Skib			intel_sdvo->pixel_clock_min / 1000,
2872235783Skib			intel_sdvo->pixel_clock_max / 1000,
2873235783Skib			(intel_sdvo->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',
2874235783Skib			(intel_sdvo->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
2875235783Skib			/* check currently supported outputs */
2876235783Skib			intel_sdvo->caps.output_flags &
2877235783Skib			(SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N',
2878235783Skib			intel_sdvo->caps.output_flags &
2879235783Skib			(SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
2880235783Skib	return true;
2881235783Skib
2882296548Sdumbbellerr_output:
2883296548Sdumbbell	intel_sdvo_output_cleanup(intel_sdvo);
2884296548Sdumbbell
2885235783Skiberr:
2886235783Skib	drm_encoder_cleanup(&intel_encoder->base);
2887296548Sdumbbell	device_delete_child(dev->dev, intel_sdvo->ddc_iic_bus);
2888296548Sdumbbellerr_i2c_bus:
2889296548Sdumbbell	intel_sdvo_unselect_i2c_bus(intel_sdvo);
2890235783Skib	free(intel_sdvo, DRM_MEM_KMS);
2891235783Skib
2892235783Skib	return false;
2893235783Skib}
2894