/[pkgs]/rpms/kernel/F-9/drm-modesetting-i915.patch
ViewVC logotype

Contents of /rpms/kernel/F-9/drm-modesetting-i915.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (show annotations) (download) (as text)
Mon Jan 12 19:54:16 2009 UTC (10 months, 1 week ago) by kyle
Branch: MAIN
CVS Tags: kernel-2_6_28-1_fc9, kernel-2_6_28-2_fc9, HEAD
File MIME type: text/x-patch
* Mon Jan 12 2009 Kyle McMartin <kyle@redhat.com>
- Rebase for Fedora 9.
- Turn off CONFIG_MAXSMP on x86_64.
1 diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
2 index 0ef9295..ebbf124 100644
3 --- a/drivers/gpu/drm/Kconfig
4 +++ b/drivers/gpu/drm/Kconfig
5 @@ -84,6 +84,15 @@ config DRM_I915
6
7 endchoice
8
9 +config DRM_I915_KMS
10 + bool "Enable modesetting on intel by default"
11 + depends on DRM_I915
12 + help
13 + Choose this option if you want kernel modesetting enabled by default,
14 + and you have a new enough userspace to support this. Running old
15 + userspaces with this enabled will cause pain.
16 +
17 +
18 config DRM_MGA
19 tristate "Matrox g200/g400"
20 depends on DRM
21 diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
22 index 217ad7d..367c590 100644
23 --- a/drivers/gpu/drm/drm_mm.c
24 +++ b/drivers/gpu/drm/drm_mm.c
25 @@ -296,3 +296,4 @@ void drm_mm_takedown(struct drm_mm * mm)
26
27 drm_free(entry, sizeof(*entry), DRM_MEM_MM);
28 }
29 +EXPORT_SYMBOL(drm_mm_takedown);
30 diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
31 index ce60285..3bbd73b 100644
32 --- a/drivers/gpu/drm/i915/Makefile
33 +++ b/drivers/gpu/drm/i915/Makefile
34 @@ -8,7 +8,12 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_init.o i915_opregion.
35 i915_gem.o \
36 i915_gem_debug.o \
37 i915_gem_proc.o \
38 - i915_gem_tiling.o
39 + i915_gem_tiling.o \
40 + intel_display.o intel_crt.o intel_lvds.o intel_bios.o \
41 + intel_sdvo.o intel_modes.o intel_i2c.o intel_fb.o \
42 + intel_tv.o intel_dvo.o dvo_ch7xxx.o \
43 + dvo_ch7017.o dvo_ivch.o dvo_tfp410.o dvo_sil164.o
44 +
45
46 i915-$(CONFIG_COMPAT) += i915_ioc32.o
47
48 diff --git a/drivers/gpu/drm/i915/dvo.h b/drivers/gpu/drm/i915/dvo.h
49 new file mode 100644
50 index 0000000..b122ea1
51 --- /dev/null
52 +++ b/drivers/gpu/drm/i915/dvo.h
53 @@ -0,0 +1,159 @@
54 +/*
55 + * Copyright © 2006 Eric Anholt
56 + *
57 + * Permission to use, copy, modify, distribute, and sell this software and its
58 + * documentation for any purpose is hereby granted without fee, provided that
59 + * the above copyright notice appear in all copies and that both that copyright
60 + * notice and this permission notice appear in supporting documentation, and
61 + * that the name of the copyright holders not be used in advertising or
62 + * publicity pertaining to distribution of the software without specific,
63 + * written prior permission. The copyright holders make no representations
64 + * about the suitability of this software for any purpose. It is provided "as
65 + * is" without express or implied warranty.
66 + *
67 + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
68 + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
69 + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
70 + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
71 + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
72 + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
73 + * OF THIS SOFTWARE.
74 + */
75 +
76 +#ifndef _INTEL_DVO_H
77 +#define _INTEL_DVO_H
78 +
79 +#include <linux/i2c.h>
80 +#include "drmP.h"
81 +#include "drm.h"
82 +#include "drm_crtc.h"
83 +#include "intel_drv.h"
84 +
85 +struct intel_dvo_device {
86 + char *name;
87 + int type;
88 + /* DVOA/B/C output register */
89 + u32 dvo_reg;
90 + /* GPIO register used for i2c bus to control this device */
91 + u32 gpio;
92 + int slave_addr;
93 + struct intel_i2c_chan *i2c_bus;
94 +
95 + const struct intel_dvo_dev_ops *dev_ops;
96 + void *dev_priv;
97 +
98 + struct drm_display_mode *panel_fixed_mode;
99 + bool panel_wants_dither;
100 +};
101 +
102 +struct intel_dvo_dev_ops {
103 + /*
104 + * Initialize the device at startup time.
105 + * Returns NULL if the device does not exist.
106 + */
107 + bool (*init)(struct intel_dvo_device *dvo,
108 + struct intel_i2c_chan *i2cbus);
109 +
110 + /*
111 + * Called to allow the output a chance to create properties after the
112 + * RandR objects have been created.
113 + */
114 + void (*create_resources)(struct intel_dvo_device *dvo);
115 +
116 + /*
117 + * Turn on/off output or set intermediate power levels if available.
118 + *
119 + * Unsupported intermediate modes drop to the lower power setting.
120 + * If the mode is DPMSModeOff, the output must be disabled,
121 + * as the DPLL may be disabled afterwards.
122 + */
123 + void (*dpms)(struct intel_dvo_device *dvo, int mode);
124 +
125 + /*
126 + * Saves the output's state for restoration on VT switch.
127 + */
128 + void (*save)(struct intel_dvo_device *dvo);
129 +
130 + /*
131 + * Restore's the output's state at VT switch.
132 + */
133 + void (*restore)(struct intel_dvo_device *dvo);
134 +
135 + /*
136 + * Callback for testing a video mode for a given output.
137 + *
138 + * This function should only check for cases where a mode can't
139 + * be supported on the output specifically, and not represent
140 + * generic CRTC limitations.
141 + *
142 + * \return MODE_OK if the mode is valid, or another MODE_* otherwise.
143 + */
144 + int (*mode_valid)(struct intel_dvo_device *dvo,
145 + struct drm_display_mode *mode);
146 +
147 + /*
148 + * Callback to adjust the mode to be set in the CRTC.
149 + *
150 + * This allows an output to adjust the clock or even the entire set of
151 + * timings, which is used for panels with fixed timings or for
152 + * buses with clock limitations.
153 + */
154 + bool (*mode_fixup)(struct intel_dvo_device *dvo,
155 + struct drm_display_mode *mode,
156 + struct drm_display_mode *adjusted_mode);
157 +
158 + /*
159 + * Callback for preparing mode changes on an output
160 + */
161 + void (*prepare)(struct intel_dvo_device *dvo);
162 +
163 + /*
164 + * Callback for committing mode changes on an output
165 + */
166 + void (*commit)(struct intel_dvo_device *dvo);
167 +
168 + /*
169 + * Callback for setting up a video mode after fixups have been made.
170 + *
171 + * This is only called while the output is disabled. The dpms callback
172 + * must be all that's necessary for the output, to turn the output on
173 + * after this function is called.
174 + */
175 + void (*mode_set)(struct intel_dvo_device *dvo,
176 + struct drm_display_mode *mode,
177 + struct drm_display_mode *adjusted_mode);
178 +
179 + /*
180 + * Probe for a connected output, and return detect_status.
181 + */
182 + enum drm_connector_status (*detect)(struct intel_dvo_device *dvo);
183 +
184 + /**
185 + * Query the device for the modes it provides.
186 + *
187 + * This function may also update MonInfo, mm_width, and mm_height.
188 + *
189 + * \return singly-linked list of modes or NULL if no modes found.
190 + */
191 + struct drm_display_mode *(*get_modes)(struct intel_dvo_device *dvo);
192 +
193 +#ifdef RANDR_12_INTERFACE
194 + /**
195 + * Callback when an output's property has changed.
196 + */
197 + bool (*set_property)(struct intel_dvo_device *dvo,
198 + struct drm_property *property, uint64_t val);
199 +#endif
200 +
201 + /**
202 + * Clean up driver-specific bits of the output
203 + */
204 + void (*destroy) (struct intel_dvo_device *dvo);
205 +
206 + /**
207 + * Debugging hook to dump device registers to log file
208 + */
209 + void (*dump_regs)(struct intel_dvo_device *dvo);
210 +};
211 +
212 +#endif /* _INTEL_DVO_H */
213 diff --git a/drivers/gpu/drm/i915/dvo_ch7017.c b/drivers/gpu/drm/i915/dvo_ch7017.c
214 new file mode 100644
215 index 0000000..b10e038
216 --- /dev/null
217 +++ b/drivers/gpu/drm/i915/dvo_ch7017.c
218 @@ -0,0 +1,454 @@
219 +/*
220 + * Copyright © 2006 Intel Corporation
221 + *
222 + * Permission is hereby granted, free of charge, to any person obtaining a
223 + * copy of this software and associated documentation files (the "Software"),
224 + * to deal in the Software without restriction, including without limitation
225 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
226 + * and/or sell copies of the Software, and to permit persons to whom the
227 + * Software is furnished to do so, subject to the following conditions:
228 + *
229 + * The above copyright notice and this permission notice (including the next
230 + * paragraph) shall be included in all copies or substantial portions of the
231 + * Software.
232 + *
233 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
234 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
235 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
236 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
237 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
238 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
239 + * DEALINGS IN THE SOFTWARE.
240 + *
241 + * Authors:
242 + * Eric Anholt <eric@anholt.net>
243 + *
244 + */
245 +
246 +#include "dvo.h"
247 +
248 +#define CH7017_TV_DISPLAY_MODE 0x00
249 +#define CH7017_FLICKER_FILTER 0x01
250 +#define CH7017_VIDEO_BANDWIDTH 0x02
251 +#define CH7017_TEXT_ENHANCEMENT 0x03
252 +#define CH7017_START_ACTIVE_VIDEO 0x04
253 +#define CH7017_HORIZONTAL_POSITION 0x05
254 +#define CH7017_VERTICAL_POSITION 0x06
255 +#define CH7017_BLACK_LEVEL 0x07
256 +#define CH7017_CONTRAST_ENHANCEMENT 0x08
257 +#define CH7017_TV_PLL 0x09
258 +#define CH7017_TV_PLL_M 0x0a
259 +#define CH7017_TV_PLL_N 0x0b
260 +#define CH7017_SUB_CARRIER_0 0x0c
261 +#define CH7017_CIV_CONTROL 0x10
262 +#define CH7017_CIV_0 0x11
263 +#define CH7017_CHROMA_BOOST 0x14
264 +#define CH7017_CLOCK_MODE 0x1c
265 +#define CH7017_INPUT_CLOCK 0x1d
266 +#define CH7017_GPIO_CONTROL 0x1e
267 +#define CH7017_INPUT_DATA_FORMAT 0x1f
268 +#define CH7017_CONNECTION_DETECT 0x20
269 +#define CH7017_DAC_CONTROL 0x21
270 +#define CH7017_BUFFERED_CLOCK_OUTPUT 0x22
271 +#define CH7017_DEFEAT_VSYNC 0x47
272 +#define CH7017_TEST_PATTERN 0x48
273 +
274 +#define CH7017_POWER_MANAGEMENT 0x49
275 +/** Enables the TV output path. */
276 +#define CH7017_TV_EN (1 << 0)
277 +#define CH7017_DAC0_POWER_DOWN (1 << 1)
278 +#define CH7017_DAC1_POWER_DOWN (1 << 2)
279 +#define CH7017_DAC2_POWER_DOWN (1 << 3)
280 +#define CH7017_DAC3_POWER_DOWN (1 << 4)
281 +/** Powers down the TV out block, and DAC0-3 */
282 +#define CH7017_TV_POWER_DOWN_EN (1 << 5)
283 +
284 +#define CH7017_VERSION_ID 0x4a
285 +
286 +#define CH7017_DEVICE_ID 0x4b
287 +#define CH7017_DEVICE_ID_VALUE 0x1b
288 +#define CH7018_DEVICE_ID_VALUE 0x1a
289 +#define CH7019_DEVICE_ID_VALUE 0x19
290 +
291 +#define CH7017_XCLK_D2_ADJUST 0x53
292 +#define CH7017_UP_SCALER_COEFF_0 0x55
293 +#define CH7017_UP_SCALER_COEFF_1 0x56
294 +#define CH7017_UP_SCALER_COEFF_2 0x57
295 +#define CH7017_UP_SCALER_COEFF_3 0x58
296 +#define CH7017_UP_SCALER_COEFF_4 0x59
297 +#define CH7017_UP_SCALER_VERTICAL_INC_0 0x5a
298 +#define CH7017_UP_SCALER_VERTICAL_INC_1 0x5b
299 +#define CH7017_GPIO_INVERT 0x5c
300 +#define CH7017_UP_SCALER_HORIZONTAL_INC_0 0x5d
301 +#define CH7017_UP_SCALER_HORIZONTAL_INC_1 0x5e
302 +
303 +#define CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT 0x5f
304 +/**< Low bits of horizontal active pixel input */
305 +
306 +#define CH7017_ACTIVE_INPUT_LINE_OUTPUT 0x60
307 +/** High bits of horizontal active pixel input */
308 +#define CH7017_LVDS_HAP_INPUT_MASK (0x7 << 0)
309 +/** High bits of vertical active line output */
310 +#define CH7017_LVDS_VAL_HIGH_MASK (0x7 << 3)
311 +
312 +#define CH7017_VERTICAL_ACTIVE_LINE_OUTPUT 0x61
313 +/**< Low bits of vertical active line output */
314 +
315 +#define CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT 0x62
316 +/**< Low bits of horizontal active pixel output */
317 +
318 +#define CH7017_LVDS_POWER_DOWN 0x63
319 +/** High bits of horizontal active pixel output */
320 +#define CH7017_LVDS_HAP_HIGH_MASK (0x7 << 0)
321 +/** Enables the LVDS power down state transition */
322 +#define CH7017_LVDS_POWER_DOWN_EN (1 << 6)
323 +/** Enables the LVDS upscaler */
324 +#define CH7017_LVDS_UPSCALER_EN (1 << 7)
325 +#define CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED 0x08
326 +
327 +#define CH7017_LVDS_ENCODING 0x64
328 +#define CH7017_LVDS_DITHER_2D (1 << 2)
329 +#define CH7017_LVDS_DITHER_DIS (1 << 3)
330 +#define CH7017_LVDS_DUAL_CHANNEL_EN (1 << 4)
331 +#define CH7017_LVDS_24_BIT (1 << 5)
332 +
333 +#define CH7017_LVDS_ENCODING_2 0x65
334 +
335 +#define CH7017_LVDS_PLL_CONTROL 0x66
336 +/** Enables the LVDS panel output path */
337 +#define CH7017_LVDS_PANEN (1 << 0)
338 +/** Enables the LVDS panel backlight */
339 +#define CH7017_LVDS_BKLEN (1 << 3)
340 +
341 +#define CH7017_POWER_SEQUENCING_T1 0x67
342 +#define CH7017_POWER_SEQUENCING_T2 0x68
343 +#define CH7017_POWER_SEQUENCING_T3 0x69
344 +#define CH7017_POWER_SEQUENCING_T4 0x6a
345 +#define CH7017_POWER_SEQUENCING_T5 0x6b
346 +#define CH7017_GPIO_DRIVER_TYPE 0x6c
347 +#define CH7017_GPIO_DATA 0x6d
348 +#define CH7017_GPIO_DIRECTION_CONTROL 0x6e
349 +
350 +#define CH7017_LVDS_PLL_FEEDBACK_DIV 0x71
351 +# define CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT 4
352 +# define CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT 0
353 +# define CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED 0x80
354 +
355 +#define CH7017_LVDS_PLL_VCO_CONTROL 0x72
356 +# define CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED 0x80
357 +# define CH7017_LVDS_PLL_VCO_SHIFT 4
358 +# define CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT 0
359 +
360 +#define CH7017_OUTPUTS_ENABLE 0x73
361 +# define CH7017_CHARGE_PUMP_LOW 0x0
362 +# define CH7017_CHARGE_PUMP_HIGH 0x3
363 +# define CH7017_LVDS_CHANNEL_A (1 << 3)
364 +# define CH7017_LVDS_CHANNEL_B (1 << 4)
365 +# define CH7017_TV_DAC_A (1 << 5)
366 +# define CH7017_TV_DAC_B (1 << 6)
367 +# define CH7017_DDC_SELECT_DC2 (1 << 7)
368 +
369 +#define CH7017_LVDS_OUTPUT_AMPLITUDE 0x74
370 +#define CH7017_LVDS_PLL_EMI_REDUCTION 0x75
371 +#define CH7017_LVDS_POWER_DOWN_FLICKER 0x76
372 +
373 +#define CH7017_LVDS_CONTROL_2 0x78
374 +# define CH7017_LOOP_FILTER_SHIFT 5
375 +# define CH7017_PHASE_DETECTOR_SHIFT 0
376 +
377 +#define CH7017_BANG_LIMIT_CONTROL 0x7f
378 +
379 +struct ch7017_priv {
380 + uint8_t save_hapi;
381 + uint8_t save_vali;
382 + uint8_t save_valo;
383 + uint8_t save_ailo;
384 + uint8_t save_lvds_pll_vco;
385 + uint8_t save_feedback_div;
386 + uint8_t save_lvds_control_2;
387 + uint8_t save_outputs_enable;
388 + uint8_t save_lvds_power_down;
389 + uint8_t save_power_management;
390 +};
391 +
392 +static void ch7017_dump_regs(struct intel_dvo_device *dvo);
393 +static void ch7017_dpms(struct intel_dvo_device *dvo, int mode);
394 +
395 +static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val)
396 +{
397 + struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
398 + u8 out_buf[2];
399 + u8 in_buf[2];
400 +
401 + struct i2c_msg msgs[] = {
402 + {
403 + .addr = i2cbus->slave_addr,
404 + .flags = 0,
405 + .len = 1,
406 + .buf = out_buf,
407 + },
408 + {
409 + .addr = i2cbus->slave_addr,
410 + .flags = I2C_M_RD,
411 + .len = 1,
412 + .buf = in_buf,
413 + }
414 + };
415 +
416 + out_buf[0] = addr;
417 + out_buf[1] = 0;
418 +
419 + if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
420 + *val= in_buf[0];
421 + return true;
422 + };
423 +
424 + return false;
425 +}
426 +
427 +static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val)
428 +{
429 + struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
430 + uint8_t out_buf[2];
431 + struct i2c_msg msg = {
432 + .addr = i2cbus->slave_addr,
433 + .flags = 0,
434 + .len = 2,
435 + .buf = out_buf,
436 + };
437 +
438 + out_buf[0] = addr;
439 + out_buf[1] = val;
440 +
441 + if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
442 + return true;
443 +
444 + return false;
445 +}
446 +
447 +/** Probes for a CH7017 on the given bus and slave address. */
448 +static bool ch7017_init(struct intel_dvo_device *dvo,
449 + struct intel_i2c_chan *i2cbus)
450 +{
451 + struct ch7017_priv *priv;
452 + uint8_t val;
453 +
454 + priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL);
455 + if (priv == NULL)
456 + return false;
457 +
458 + dvo->i2c_bus = i2cbus;
459 + dvo->i2c_bus->slave_addr = dvo->slave_addr;
460 + dvo->dev_priv = priv;
461 +
462 + if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val))
463 + goto fail;
464 +
465 + if (val != CH7017_DEVICE_ID_VALUE &&
466 + val != CH7018_DEVICE_ID_VALUE &&
467 + val != CH7019_DEVICE_ID_VALUE) {
468 + DRM_DEBUG("ch701x not detected, got %d: from %s Slave %d.\n",
469 + val, i2cbus->adapter.name,i2cbus->slave_addr);
470 + goto fail;
471 + }
472 +
473 + return true;
474 +fail:
475 + kfree(priv);
476 + return false;
477 +}
478 +
479 +static enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo)
480 +{
481 + return connector_status_unknown;
482 +}
483 +
484 +static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo,
485 + struct drm_display_mode *mode)
486 +{
487 + if (mode->clock > 160000)
488 + return MODE_CLOCK_HIGH;
489 +
490 + return MODE_OK;
491 +}
492 +
493 +static void ch7017_mode_set(struct intel_dvo_device *dvo,
494 + struct drm_display_mode *mode,
495 + struct drm_display_mode *adjusted_mode)
496 +{
497 + uint8_t lvds_pll_feedback_div, lvds_pll_vco_control;
498 + uint8_t outputs_enable, lvds_control_2, lvds_power_down;
499 + uint8_t horizontal_active_pixel_input;
500 + uint8_t horizontal_active_pixel_output, vertical_active_line_output;
501 + uint8_t active_input_line_output;
502 +
503 + DRM_DEBUG("Registers before mode setting\n");
504 + ch7017_dump_regs(dvo);
505 +
506 + /* LVDS PLL settings from page 75 of 7017-7017ds.pdf*/
507 + if (mode->clock < 100000) {
508 + outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_LOW;
509 + lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED |
510 + (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) |
511 + (13 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT);
512 + lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED |
513 + (2 << CH7017_LVDS_PLL_VCO_SHIFT) |
514 + (3 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT);
515 + lvds_control_2 = (1 << CH7017_LOOP_FILTER_SHIFT) |
516 + (0 << CH7017_PHASE_DETECTOR_SHIFT);
517 + } else {
518 + outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_HIGH;
519 + lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED |
520 + (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) |
521 + (3 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT);
522 + lvds_pll_feedback_div = 35;
523 + lvds_control_2 = (3 << CH7017_LOOP_FILTER_SHIFT) |
524 + (0 << CH7017_PHASE_DETECTOR_SHIFT);
525 + if (1) { /* XXX: dual channel panel detection. Assume yes for now. */
526 + outputs_enable |= CH7017_LVDS_CHANNEL_B;
527 + lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED |
528 + (2 << CH7017_LVDS_PLL_VCO_SHIFT) |
529 + (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT);
530 + } else {
531 + lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED |
532 + (1 << CH7017_LVDS_PLL_VCO_SHIFT) |
533 + (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT);
534 + }
535 + }
536 +
537 + horizontal_active_pixel_input = mode->hdisplay & 0x00ff;
538 +
539 + vertical_active_line_output = mode->vdisplay & 0x00ff;
540 + horizontal_active_pixel_output = mode->hdisplay & 0x00ff;
541 +
542 + active_input_line_output = ((mode->hdisplay & 0x0700) >> 8) |
543 + (((mode->vdisplay & 0x0700) >> 8) << 3);
544 +
545 + lvds_power_down = CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED |
546 + (mode->hdisplay & 0x0700) >> 8;
547 +
548 + ch7017_dpms(dvo, DRM_MODE_DPMS_OFF);
549 + ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT,
550 + horizontal_active_pixel_input);
551 + ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT,
552 + horizontal_active_pixel_output);
553 + ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT,
554 + vertical_active_line_output);
555 + ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT,
556 + active_input_line_output);
557 + ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, lvds_pll_vco_control);
558 + ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, lvds_pll_feedback_div);
559 + ch7017_write(dvo, CH7017_LVDS_CONTROL_2, lvds_control_2);
560 + ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, outputs_enable);
561 +
562 + /* Turn the LVDS back on with new settings. */
563 + ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, lvds_power_down);
564 +
565 + DRM_DEBUG("Registers after mode setting\n");
566 + ch7017_dump_regs(dvo);
567 +}
568 +
569 +/* set the CH7017 power state */
570 +static void ch7017_dpms(struct intel_dvo_device *dvo, int mode)
571 +{
572 + uint8_t val;
573 +
574 + ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val);
575 +
576 + /* Turn off TV/VGA, and never turn it on since we don't support it. */
577 + ch7017_write(dvo, CH7017_POWER_MANAGEMENT,
578 + CH7017_DAC0_POWER_DOWN |
579 + CH7017_DAC1_POWER_DOWN |
580 + CH7017_DAC2_POWER_DOWN |
581 + CH7017_DAC3_POWER_DOWN |
582 + CH7017_TV_POWER_DOWN_EN);
583 +
584 + if (mode == DRM_MODE_DPMS_ON) {
585 + /* Turn on the LVDS */
586 + ch7017_write(dvo, CH7017_LVDS_POWER_DOWN,
587 + val & ~CH7017_LVDS_POWER_DOWN_EN);
588 + } else {
589 + /* Turn off the LVDS */
590 + ch7017_write(dvo, CH7017_LVDS_POWER_DOWN,
591 + val | CH7017_LVDS_POWER_DOWN_EN);
592 + }
593 +
594 + /* XXX: Should actually wait for update power status somehow */
595 + udelay(20000);
596 +}
597 +
598 +static void ch7017_dump_regs(struct intel_dvo_device *dvo)
599 +{
600 + uint8_t val;
601 +
602 +#define DUMP(reg) \
603 +do { \
604 + ch7017_read(dvo, reg, &val); \
605 + DRM_DEBUG(#reg ": %02x\n", val); \
606 +} while (0)
607 +
608 + DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT);
609 + DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT);
610 + DUMP(CH7017_VERTICAL_ACTIVE_LINE_OUTPUT);
611 + DUMP(CH7017_ACTIVE_INPUT_LINE_OUTPUT);
612 + DUMP(CH7017_LVDS_PLL_VCO_CONTROL);
613 + DUMP(CH7017_LVDS_PLL_FEEDBACK_DIV);
614 + DUMP(CH7017_LVDS_CONTROL_2);
615 + DUMP(CH7017_OUTPUTS_ENABLE);
616 + DUMP(CH7017_LVDS_POWER_DOWN);
617 +}
618 +
619 +static void ch7017_save(struct intel_dvo_device *dvo)
620 +{
621 + struct ch7017_priv *priv = dvo->dev_priv;
622 +
623 + ch7017_read(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, &priv->save_hapi);
624 + ch7017_read(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, &priv->save_valo);
625 + ch7017_read(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, &priv->save_ailo);
626 + ch7017_read(dvo, CH7017_LVDS_PLL_VCO_CONTROL, &priv->save_lvds_pll_vco);
627 + ch7017_read(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, &priv->save_feedback_div);
628 + ch7017_read(dvo, CH7017_LVDS_CONTROL_2, &priv->save_lvds_control_2);
629 + ch7017_read(dvo, CH7017_OUTPUTS_ENABLE, &priv->save_outputs_enable);
630 + ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &priv->save_lvds_power_down);
631 + ch7017_read(dvo, CH7017_POWER_MANAGEMENT, &priv->save_power_management);
632 +}
633 +
634 +static void ch7017_restore(struct intel_dvo_device *dvo)
635 +{
636 + struct ch7017_priv *priv = dvo->dev_priv;
637 +
638 + /* Power down before changing mode */
639 + ch7017_dpms(dvo, DRM_MODE_DPMS_OFF);
640 +
641 + ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, priv->save_hapi);
642 + ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, priv->save_valo);
643 + ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, priv->save_ailo);
644 + ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, priv->save_lvds_pll_vco);
645 + ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, priv->save_feedback_div);
646 + ch7017_write(dvo, CH7017_LVDS_CONTROL_2, priv->save_lvds_control_2);
647 + ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, priv->save_outputs_enable);
648 + ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, priv->save_lvds_power_down);
649 + ch7017_write(dvo, CH7017_POWER_MANAGEMENT, priv->save_power_management);
650 +}
651 +
652 +static void ch7017_destroy(struct intel_dvo_device *dvo)
653 +{
654 + struct ch7017_priv *priv = dvo->dev_priv;
655 +
656 + if (priv) {
657 + kfree(priv);
658 + dvo->dev_priv = NULL;
659 + }
660 +}
661 +
662 +struct intel_dvo_dev_ops ch7017_ops = {
663 + .init = ch7017_init,
664 + .detect = ch7017_detect,
665 + .mode_valid = ch7017_mode_valid,
666 + .mode_set = ch7017_mode_set,
667 + .dpms = ch7017_dpms,
668 + .dump_regs = ch7017_dump_regs,
669 + .save = ch7017_save,
670 + .restore = ch7017_restore,
671 + .destroy = ch7017_destroy,
672 +};
673 diff --git a/drivers/gpu/drm/i915/dvo_ch7xxx.c b/drivers/gpu/drm/i915/dvo_ch7xxx.c
674 new file mode 100644
675 index 0000000..77c8639
676 --- /dev/null
677 +++ b/drivers/gpu/drm/i915/dvo_ch7xxx.c
678 @@ -0,0 +1,368 @@
679 +/**************************************************************************
680 +
681 +Copyright © 2006 Dave Airlie
682 +
683 +All Rights Reserved.
684 +
685 +Permission is hereby granted, free of charge, to any person obtaining a
686 +copy of this software and associated documentation files (the
687 +"Software"), to deal in the Software without restriction, including
688 +without limitation the rights to use, copy, modify, merge, publish,
689 +distribute, sub license, and/or sell copies of the Software, and to
690 +permit persons to whom the Software is furnished to do so, subject to
691 +the following conditions:
692 +
693 +The above copyright notice and this permission notice (including the
694 +next paragraph) shall be included in all copies or substantial portions
695 +of the Software.
696 +
697 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
698 +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
699 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
700 +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
701 +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
702 +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
703 +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
704 +
705 +**************************************************************************/
706 +
707 +#include "dvo.h"
708 +
709 +#define CH7xxx_REG_VID 0x4a
710 +#define CH7xxx_REG_DID 0x4b
711 +
712 +#define CH7011_VID 0x83 /* 7010 as well */
713 +#define CH7009A_VID 0x84
714 +#define CH7009B_VID 0x85
715 +#define CH7301_VID 0x95
716 +
717 +#define CH7xxx_VID 0x84
718 +#define CH7xxx_DID 0x17
719 +
720 +#define CH7xxx_NUM_REGS 0x4c
721 +
722 +#define CH7xxx_CM 0x1c
723 +#define CH7xxx_CM_XCM (1<<0)
724 +#define CH7xxx_CM_MCP (1<<2)
725 +#define CH7xxx_INPUT_CLOCK 0x1d
726 +#define CH7xxx_GPIO 0x1e
727 +#define CH7xxx_GPIO_HPIR (1<<3)
728 +#define CH7xxx_IDF 0x1f
729 +
730 +#define CH7xxx_IDF_HSP (1<<3)
731 +#define CH7xxx_IDF_VSP (1<<4)
732 +
733 +#define CH7xxx_CONNECTION_DETECT 0x20
734 +#define CH7xxx_CDET_DVI (1<<5)
735 +
736 +#define CH7301_DAC_CNTL 0x21
737 +#define CH7301_HOTPLUG 0x23
738 +#define CH7xxx_TCTL 0x31
739 +#define CH7xxx_TVCO 0x32
740 +#define CH7xxx_TPCP 0x33
741 +#define CH7xxx_TPD 0x34
742 +#define CH7xxx_TPVT 0x35
743 +#define CH7xxx_TLPF 0x36
744 +#define CH7xxx_TCT 0x37
745 +#define CH7301_TEST_PATTERN 0x48
746 +
747 +#define CH7xxx_PM 0x49
748 +#define CH7xxx_PM_FPD (1<<0)
749 +#define CH7301_PM_DACPD0 (1<<1)
750 +#define CH7301_PM_DACPD1 (1<<2)
751 +#define CH7301_PM_DACPD2 (1<<3)
752 +#define CH7xxx_PM_DVIL (1<<6)
753 +#define CH7xxx_PM_DVIP (1<<7)
754 +
755 +#define CH7301_SYNC_POLARITY 0x56
756 +#define CH7301_SYNC_RGB_YUV (1<<0)
757 +#define CH7301_SYNC_POL_DVI (1<<5)
758 +
759 +/** @file
760 + * driver for the Chrontel 7xxx DVI chip over DVO.
761 + */
762 +
763 +static struct ch7xxx_id_struct {
764 + uint8_t vid;
765 + char *name;
766 +} ch7xxx_ids[] = {
767 + { CH7011_VID, "CH7011" },
768 + { CH7009A_VID, "CH7009A" },
769 + { CH7009B_VID, "CH7009B" },
770 + { CH7301_VID, "CH7301" },
771 +};
772 +
773 +struct ch7xxx_reg_state {
774 + uint8_t regs[CH7xxx_NUM_REGS];
775 +};
776 +
777 +struct ch7xxx_priv {
778 + bool quiet;
779 +
780 + struct ch7xxx_reg_state save_reg;
781 + struct ch7xxx_reg_state mode_reg;
782 + uint8_t save_TCTL, save_TPCP, save_TPD, save_TPVT;
783 + uint8_t save_TLPF, save_TCT, save_PM, save_IDF;
784 +};
785 +
786 +static void ch7xxx_save(struct intel_dvo_device *dvo);
787 +
788 +static char *ch7xxx_get_id(uint8_t vid)
789 +{
790 + int i;
791 +
792 + for (i = 0; i < ARRAY_SIZE(ch7xxx_ids); i++) {
793 + if (ch7xxx_ids[i].vid == vid)
794 + return ch7xxx_ids[i].name;
795 + }
796 +
797 + return NULL;
798 +}
799 +
800 +/** Reads an 8 bit register */
801 +static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
802 +{
803 + struct ch7xxx_priv *ch7xxx= dvo->dev_priv;
804 + struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
805 + u8 out_buf[2];
806 + u8 in_buf[2];
807 +
808 + struct i2c_msg msgs[] = {
809 + {
810 + .addr = i2cbus->slave_addr,
811 + .flags = 0,
812 + .len = 1,
813 + .buf = out_buf,
814 + },
815 + {
816 + .addr = i2cbus->slave_addr,
817 + .flags = I2C_M_RD,
818 + .len = 1,
819 + .buf = in_buf,
820 + }
821 + };
822 +
823 + out_buf[0] = addr;
824 + out_buf[1] = 0;
825 +
826 + if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
827 + *ch = in_buf[0];
828 + return true;
829 + };
830 +
831 + if (!ch7xxx->quiet) {
832 + DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
833 + addr, i2cbus->adapter.name, i2cbus->slave_addr);
834 + }
835 + return false;
836 +}
837 +
838 +/** Writes an 8 bit register */
839 +static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
840 +{
841 + struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
842 + struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
843 + uint8_t out_buf[2];
844 + struct i2c_msg msg = {
845 + .addr = i2cbus->slave_addr,
846 + .flags = 0,
847 + .len = 2,
848 + .buf = out_buf,
849 + };
850 +
851 + out_buf[0] = addr;
852 + out_buf[1] = ch;
853 +
854 + if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
855 + return true;
856 +
857 + if (!ch7xxx->quiet) {
858 + DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
859 + addr, i2cbus->adapter.name, i2cbus->slave_addr);
860 + }
861 +
862 + return false;
863 +}
864 +
865 +static bool ch7xxx_init(struct intel_dvo_device *dvo,
866 + struct intel_i2c_chan *i2cbus)
867 +{
868 + /* this will detect the CH7xxx chip on the specified i2c bus */
869 + struct ch7xxx_priv *ch7xxx;
870 + uint8_t vendor, device;
871 + char *name;
872 +
873 + ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL);
874 + if (ch7xxx == NULL)
875 + return false;
876 +
877 + dvo->i2c_bus = i2cbus;
878 + dvo->i2c_bus->slave_addr = dvo->slave_addr;
879 + dvo->dev_priv = ch7xxx;
880 + ch7xxx->quiet = true;
881 +
882 + if (!ch7xxx_readb(dvo, CH7xxx_REG_VID, &vendor))
883 + goto out;
884 +
885 + name = ch7xxx_get_id(vendor);
886 + if (!name) {
887 + DRM_DEBUG("ch7xxx not detected; got 0x%02x from %s slave %d.\n",
888 + vendor, i2cbus->adapter.name, i2cbus->slave_addr);
889 + goto out;
890 + }
891 +
892 +
893 + if (!ch7xxx_readb(dvo, CH7xxx_REG_DID, &device))
894 + goto out;
895 +
896 + if (device != CH7xxx_DID) {
897 + DRM_DEBUG("ch7xxx not detected; got 0x%02x from %s slave %d.\n",
898 + vendor, i2cbus->adapter.name, i2cbus->slave_addr);
899 + goto out;
900 + }
901 +
902 + ch7xxx->quiet = false;
903 + DRM_DEBUG("Detected %s chipset, vendor/device ID 0x%02x/0x%02x\n",
904 + name, vendor, device);
905 + return true;
906 +out:
907 + kfree(ch7xxx);
908 + return false;
909 +}
910 +
911 +static enum drm_connector_status ch7xxx_detect(struct intel_dvo_device *dvo)
912 +{
913 + uint8_t cdet, orig_pm, pm;
914 +
915 + ch7xxx_readb(dvo, CH7xxx_PM, &orig_pm);
916 +
917 + pm = orig_pm;
918 + pm &= ~CH7xxx_PM_FPD;
919 + pm |= CH7xxx_PM_DVIL | CH7xxx_PM_DVIP;
920 +
921 + ch7xxx_writeb(dvo, CH7xxx_PM, pm);
922 +
923 + ch7xxx_readb(dvo, CH7xxx_CONNECTION_DETECT, &cdet);
924 +
925 + ch7xxx_writeb(dvo, CH7xxx_PM, orig_pm);
926 +
927 + if (cdet & CH7xxx_CDET_DVI)
928 + return connector_status_connected;
929 + return connector_status_disconnected;
930 +}
931 +
932 +static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo,
933 + struct drm_display_mode *mode)
934 +{
935 + if (mode->clock > 165000)
936 + return MODE_CLOCK_HIGH;
937 +
938 + return MODE_OK;
939 +}
940 +
941 +static void ch7xxx_mode_set(struct intel_dvo_device *dvo,
942 + struct drm_display_mode *mode,
943 + struct drm_display_mode *adjusted_mode)
944 +{
945 + uint8_t tvco, tpcp, tpd, tlpf, idf;
946 +
947 + if (mode->clock <= 65000) {
948 + tvco = 0x23;
949 + tpcp = 0x08;
950 + tpd = 0x16;
951 + tlpf = 0x60;
952 + } else {
953 + tvco = 0x2d;
954 + tpcp = 0x06;
955 + tpd = 0x26;
956 + tlpf = 0xa0;
957 + }
958 +
959 + ch7xxx_writeb(dvo, CH7xxx_TCTL, 0x00);
960 + ch7xxx_writeb(dvo, CH7xxx_TVCO, tvco);
961 + ch7xxx_writeb(dvo, CH7xxx_TPCP, tpcp);
962 + ch7xxx_writeb(dvo, CH7xxx_TPD, tpd);
963 + ch7xxx_writeb(dvo, CH7xxx_TPVT, 0x30);
964 + ch7xxx_writeb(dvo, CH7xxx_TLPF, tlpf);
965 + ch7xxx_writeb(dvo, CH7xxx_TCT, 0x00);
966 +
967 + ch7xxx_readb(dvo, CH7xxx_IDF, &idf);
968 +
969 + idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP);
970 + if (mode->flags & DRM_MODE_FLAG_PHSYNC)
971 + idf |= CH7xxx_IDF_HSP;
972 +
973 + if (mode->flags & DRM_MODE_FLAG_PVSYNC)
974 + idf |= CH7xxx_IDF_HSP;
975 +
976 + ch7xxx_writeb(dvo, CH7xxx_IDF, idf);
977 +}
978 +
979 +/* set the CH7xxx power state */
980 +static void ch7xxx_dpms(struct intel_dvo_device *dvo, int mode)
981 +{
982 + if (mode == DRM_MODE_DPMS_ON)
983 + ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP);
984 + else
985 + ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD);
986 +}
987 +
988 +static void ch7xxx_dump_regs(struct intel_dvo_device *dvo)
989 +{
990 + struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
991 + int i;
992 +
993 + for (i = 0; i < CH7xxx_NUM_REGS; i++) {
994 + if ((i % 8) == 0 )
995 + DRM_DEBUG("\n %02X: ", i);
996 + DRM_DEBUG("%02X ", ch7xxx->mode_reg.regs[i]);
997 + }
998 +}
999 +
1000 +static void ch7xxx_save(struct intel_dvo_device *dvo)
1001 +{
1002 + struct ch7xxx_priv *ch7xxx= dvo->dev_priv;
1003 +
1004 + ch7xxx_readb(dvo, CH7xxx_TCTL, &ch7xxx->save_TCTL);
1005 + ch7xxx_readb(dvo, CH7xxx_TPCP, &ch7xxx->save_TPCP);
1006 + ch7xxx_readb(dvo, CH7xxx_TPD, &ch7xxx->save_TPD);
1007 + ch7xxx_readb(dvo, CH7xxx_TPVT, &ch7xxx->save_TPVT);
1008 + ch7xxx_readb(dvo, CH7xxx_TLPF, &ch7xxx->save_TLPF);
1009 + ch7xxx_readb(dvo, CH7xxx_PM, &ch7xxx->save_PM);
1010 + ch7xxx_readb(dvo, CH7xxx_IDF, &ch7xxx->save_IDF);
1011 +}
1012 +
1013 +static void ch7xxx_restore(struct intel_dvo_device *dvo)
1014 +{
1015 + struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
1016 +
1017 + ch7xxx_writeb(dvo, CH7xxx_TCTL, ch7xxx->save_TCTL);
1018 + ch7xxx_writeb(dvo, CH7xxx_TPCP, ch7xxx->save_TPCP);
1019 + ch7xxx_writeb(dvo, CH7xxx_TPD, ch7xxx->save_TPD);
1020 + ch7xxx_writeb(dvo, CH7xxx_TPVT, ch7xxx->save_TPVT);
1021 + ch7xxx_writeb(dvo, CH7xxx_TLPF, ch7xxx->save_TLPF);
1022 + ch7xxx_writeb(dvo, CH7xxx_IDF, ch7xxx->save_IDF);
1023 + ch7xxx_writeb(dvo, CH7xxx_PM, ch7xxx->save_PM);
1024 +}
1025 +
1026 +static void ch7xxx_destroy(struct intel_dvo_device *dvo)
1027 +{
1028 + struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
1029 +
1030 + if (ch7xxx) {
1031 + kfree(ch7xxx);
1032 + dvo->dev_priv = NULL;
1033 + }
1034 +}
1035 +
1036 +struct intel_dvo_dev_ops ch7xxx_ops = {
1037 + .init = ch7xxx_init,
1038 + .detect = ch7xxx_detect,
1039 + .mode_valid = ch7xxx_mode_valid,
1040 + .mode_set = ch7xxx_mode_set,
1041 + .dpms = ch7xxx_dpms,
1042 + .dump_regs = ch7xxx_dump_regs,
1043 + .save = ch7xxx_save,
1044 + .restore = ch7xxx_restore,
1045 + .destroy = ch7xxx_destroy,
1046 +};
1047 diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c
1048 new file mode 100644
1049 index 0000000..5907fda
1050 --- /dev/null
1051 +++ b/drivers/gpu/drm/i915/dvo_ivch.c
1052 @@ -0,0 +1,442 @@
1053 +/*
1054 + * Copyright © 2006 Intel Corporation
1055 + *
1056 + * Permission is hereby granted, free of charge, to any person obtaining a
1057 + * copy of this software and associated documentation files (the "Software"),
1058 + * to deal in the Software without restriction, including without limitation
1059 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1060 + * and/or sell copies of the Software, and to permit persons to whom the
1061 + * Software is furnished to do so, subject to the following conditions:
1062 + *
1063 + * The above copyright notice and this permission notice (including the next
1064 + * paragraph) shall be included in all copies or substantial portions of the
1065 + * Software.
1066 + *
1067 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1068 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1069 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1070 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1071 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1072 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1073 + * DEALINGS IN THE SOFTWARE.
1074 + *
1075 + * Authors:
1076 + * Eric Anholt <eric@anholt.net>
1077 + *
1078 + */
1079 +
1080 +#include "dvo.h"
1081 +
1082 +/*
1083 + * register definitions for the i82807aa.
1084 + *
1085 + * Documentation on this chipset can be found in datasheet #29069001 at
1086 + * intel.com.
1087 + */
1088 +
1089 +/*
1090 + * VCH Revision & GMBus Base Addr
1091 + */
1092 +#define VR00 0x00
1093 +# define VR00_BASE_ADDRESS_MASK 0x007f
1094 +
1095 +/*
1096 + * Functionality Enable
1097 + */
1098 +#define VR01 0x01
1099 +
1100 +/*
1101 + * Enable the panel fitter
1102 + */
1103 +# define VR01_PANEL_FIT_ENABLE (1 << 3)
1104 +/*
1105 + * Enables the LCD display.
1106 + *
1107 + * This must not be set while VR01_DVO_BYPASS_ENABLE is set.
1108 + */
1109 +# define VR01_LCD_ENABLE (1 << 2)
1110 +/** Enables the DVO repeater. */
1111 +# define VR01_DVO_BYPASS_ENABLE (1 << 1)
1112 +/** Enables the DVO clock */
1113 +# define VR01_DVO_ENABLE (1 << 0)
1114 +
1115 +/*
1116 + * LCD Interface Format
1117 + */
1118 +#define VR10 0x10
1119 +/** Enables LVDS output instead of CMOS */
1120 +# define VR10_LVDS_ENABLE (1 << 4)
1121 +/** Enables 18-bit LVDS output. */
1122 +# define VR10_INTERFACE_1X18 (0 << 2)
1123 +/** Enables 24-bit LVDS or CMOS output */
1124 +# define VR10_INTERFACE_1X24 (1 << 2)
1125 +/** Enables 2x18-bit LVDS or CMOS output. */
1126 +# define VR10_INTERFACE_2X18 (2 << 2)
1127 +/** Enables 2x24-bit LVDS output */
1128 +# define VR10_INTERFACE_2X24 (3 << 2)
1129 +
1130 +/*
1131 + * VR20 LCD Horizontal Display Size
1132 + */
1133 +#define VR20 0x20
1134 +
1135 +/*
1136 + * LCD Vertical Display Size
1137 + */
1138 +#define VR21 0x20
1139 +
1140 +/*
1141 + * Panel power down status
1142 + */
1143 +#define VR30 0x30
1144 +/** Read only bit indicating that the panel is not in a safe poweroff state. */
1145 +# define VR30_PANEL_ON (1 << 15)
1146 +
1147 +#define VR40 0x40
1148 +# define VR40_STALL_ENABLE (1 << 13)
1149 +# define VR40_VERTICAL_INTERP_ENABLE (1 << 12)
1150 +# define VR40_ENHANCED_PANEL_FITTING (1 << 11)
1151 +# define VR40_HORIZONTAL_INTERP_ENABLE (1 << 10)
1152 +# define VR40_AUTO_RATIO_ENABLE (1 << 9)
1153 +# define VR40_CLOCK_GATING_ENABLE (1 << 8)
1154 +
1155 +/*
1156 + * Panel Fitting Vertical Ratio
1157 + * (((image_height - 1) << 16) / ((panel_height - 1))) >> 2
1158 + */
1159 +#define VR41 0x41
1160 +
1161 +/*
1162 + * Panel Fitting Horizontal Ratio
1163 + * (((image_width - 1) << 16) / ((panel_width - 1))) >> 2
1164 + */
1165 +#define VR42 0x42
1166 +
1167 +/*
1168 + * Horizontal Image Size
1169 + */
1170 +#define VR43 0x43
1171 +
1172 +/* VR80 GPIO 0
1173 + */
1174 +#define VR80 0x80
1175 +#define VR81 0x81
1176 +#define VR82 0x82
1177 +#define VR83 0x83
1178 +#define VR84 0x84
1179 +#define VR85 0x85
1180 +#define VR86 0x86
1181 +#define VR87 0x87
1182 +
1183 +/* VR88 GPIO 8
1184 + */
1185 +#define VR88 0x88
1186 +
1187 +/* Graphics BIOS scratch 0
1188 + */
1189 +#define VR8E 0x8E
1190 +# define VR8E_PANEL_TYPE_MASK (0xf << 0)
1191 +# define VR8E_PANEL_INTERFACE_CMOS (0 << 4)
1192 +# define VR8E_PANEL_INTERFACE_LVDS (1 << 4)
1193 +# define VR8E_FORCE_DEFAULT_PANEL (1 << 5)
1194 +
1195 +/* Graphics BIOS scratch 1
1196 + */
1197 +#define VR8F 0x8F
1198 +# define VR8F_VCH_PRESENT (1 << 0)
1199 +# define VR8F_DISPLAY_CONN (1 << 1)
1200 +# define VR8F_POWER_MASK (0x3c)
1201 +# define VR8F_POWER_POS (2)
1202 +
1203 +
1204 +struct ivch_priv {
1205 + bool quiet;
1206 +
1207 + uint16_t width, height;
1208 +
1209 + uint16_t save_VR01;
1210 + uint16_t save_VR40;
1211 +};
1212 +
1213 +
1214 +static void ivch_dump_regs(struct intel_dvo_device *dvo);
1215 +
1216 +/**
1217 + * Reads a register on the ivch.
1218 + *
1219 + * Each of the 256 registers are 16 bits long.
1220 + */
1221 +static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
1222 +{
1223 + struct ivch_priv *priv = dvo->dev_priv;
1224 + struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
1225 + u8 out_buf[1];
1226 + u8 in_buf[2];
1227 +
1228 + struct i2c_msg msgs[] = {
1229 + {
1230 + .addr = i2cbus->slave_addr,
1231 + .flags = I2C_M_RD,
1232 + .len = 0,
1233 + },
1234 + {
1235 + .addr = 0,
1236 + .flags = I2C_M_NOSTART,
1237 + .len = 1,
1238 + .buf = out_buf,
1239 + },
1240 + {
1241 + .addr = i2cbus->slave_addr,
1242 + .flags = I2C_M_RD | I2C_M_NOSTART,
1243 + .len = 2,
1244 + .buf = in_buf,
1245 + }
1246 + };
1247 +
1248 + out_buf[0] = addr;
1249 +
1250 + if (i2c_transfer(&i2cbus->adapter, msgs, 3) == 3) {
1251 + *data = (in_buf[1] << 8) | in_buf[0];
1252 + return true;
1253 + };
1254 +
1255 + if (!priv->quiet) {
1256 + DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
1257 + addr, i2cbus->adapter.name, i2cbus->slave_addr);
1258 + }
1259 + return false;
1260 +}
1261 +
1262 +/** Writes a 16-bit register on the ivch */
1263 +static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
1264 +{
1265 + struct ivch_priv *priv = dvo->dev_priv;
1266 + struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
1267 + u8 out_buf[3];
1268 + struct i2c_msg msg = {
1269 + .addr = i2cbus->slave_addr,
1270 + .flags = 0,
1271 + .len = 3,
1272 + .buf = out_buf,
1273 + };
1274 +
1275 + out_buf[0] = addr;
1276 + out_buf[1] = data & 0xff;
1277 + out_buf[2] = data >> 8;
1278 +
1279 + if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
1280 + return true;
1281 +
1282 + if (!priv->quiet) {
1283 + DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
1284 + addr, i2cbus->adapter.name, i2cbus->slave_addr);
1285 + }
1286 +
1287 + return false;
1288 +}
1289 +
1290 +/** Probes the given bus and slave address for an ivch */
1291 +static bool ivch_init(struct intel_dvo_device *dvo,
1292 + struct intel_i2c_chan *i2cbus)
1293 +{
1294 + struct ivch_priv *priv;
1295 + uint16_t temp;
1296 +
1297 + priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL);
1298 + if (priv == NULL)
1299 + return false;
1300 +
1301 + dvo->i2c_bus = i2cbus;
1302 + dvo->i2c_bus->slave_addr = dvo->slave_addr;
1303 + dvo->dev_priv = priv;
1304 + priv->quiet = true;
1305 +
1306 + if (!ivch_read(dvo, VR00, &temp))
1307 + goto out;
1308 + priv->quiet = false;
1309 +
1310 + /* Since the identification bits are probably zeroes, which doesn't seem
1311 + * very unique, check that the value in the base address field matches
1312 + * the address it's responding on.
1313 + */
1314 + if ((temp & VR00_BASE_ADDRESS_MASK) != dvo->slave_addr) {
1315 + DRM_DEBUG("ivch detect failed due to address mismatch "
1316 + "(%d vs %d)\n",
1317 + (temp & VR00_BASE_ADDRESS_MASK), dvo->slave_addr);
1318 + goto out;
1319 + }
1320 +
1321 + ivch_read(dvo, VR20, &priv->width);
1322 + ivch_read(dvo, VR21, &priv->height);
1323 +
1324 + return true;
1325 +
1326 +out:
1327 + kfree(priv);
1328 + return false;
1329 +}
1330 +
1331 +static enum drm_connector_status ivch_detect(struct intel_dvo_device *dvo)
1332 +{
1333 + return connector_status_connected;
1334 +}
1335 +
1336 +static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo,
1337 + struct drm_display_mode *mode)
1338 +{
1339 + if (mode->clock > 112000)
1340 + return MODE_CLOCK_HIGH;
1341 +
1342 + return MODE_OK;
1343 +}
1344 +
1345 +/** Sets the power state of the panel connected to the ivch */
1346 +static void ivch_dpms(struct intel_dvo_device *dvo, int mode)
1347 +{
1348 + int i;
1349 + uint16_t vr01, vr30, backlight;
1350 +
1351 + /* Set the new power state of the panel. */
1352 + if (!ivch_read(dvo, VR01, &vr01))
1353 + return;
1354 +
1355 + if (mode == DRM_MODE_DPMS_ON)
1356 + backlight = 1;
1357 + else
1358 + backlight = 0;
1359 + ivch_write(dvo, VR80, backlight);
1360 +
1361 + if (mode == DRM_MODE_DPMS_ON)
1362 + vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE;
1363 + else
1364 + vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE);
1365 +
1366 + ivch_write(dvo, VR01, vr01);
1367 +
1368 + /* Wait for the panel to make its state transition */
1369 + for (i = 0; i < 100; i++) {
1370 + if (!ivch_read(dvo, VR30, &vr30))
1371 + break;
1372 +
1373 + if (((vr30 & VR30_PANEL_ON) != 0) == (mode == DRM_MODE_DPMS_ON))
1374 + break;
1375 + udelay(1000);
1376 + }
1377 + /* wait some more; vch may fail to resync sometimes without this */
1378 + udelay(16 * 1000);
1379 +}
1380 +
1381 +static void ivch_mode_set(struct intel_dvo_device *dvo,
1382 + struct drm_display_mode *mode,
1383 + struct drm_display_mode *adjusted_mode)
1384 +{
1385 + uint16_t vr40 = 0;
1386 + uint16_t vr01;
1387 +
1388 + vr01 = 0;
1389 + vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE |
1390 + VR40_HORIZONTAL_INTERP_ENABLE);
1391 +
1392 + if (mode->hdisplay != adjusted_mode->hdisplay ||
1393 + mode->vdisplay != adjusted_mode->vdisplay) {
1394 + uint16_t x_ratio, y_ratio;
1395 +
1396 + vr01 |= VR01_PANEL_FIT_ENABLE;
1397 + vr40 |= VR40_CLOCK_GATING_ENABLE;
1398 + x_ratio = (((mode->hdisplay - 1) << 16) /
1399 + (adjusted_mode->hdisplay - 1)) >> 2;
1400 + y_ratio = (((mode->vdisplay - 1) << 16) /
1401 + (adjusted_mode->vdisplay - 1)) >> 2;
1402 + ivch_write (dvo, VR42, x_ratio);
1403 + ivch_write (dvo, VR41, y_ratio);
1404 + } else {
1405 + vr01 &= ~VR01_PANEL_FIT_ENABLE;
1406 + vr40 &= ~VR40_CLOCK_GATING_ENABLE;
1407 + }
1408 + vr40 &= ~VR40_AUTO_RATIO_ENABLE;
1409 +
1410 + ivch_write(dvo, VR01, vr01);
1411 + ivch_write(dvo, VR40, vr40);
1412 +
1413 + ivch_dump_regs(dvo);
1414 +}
1415 +
1416 +static void ivch_dump_regs(struct intel_dvo_device *dvo)
1417 +{
1418 + uint16_t val;
1419 +
1420 + ivch_read(dvo, VR00, &val);
1421 + DRM_DEBUG("VR00: 0x%04x\n", val);
1422 + ivch_read(dvo, VR01, &val);
1423 + DRM_DEBUG("VR01: 0x%04x\n", val);
1424 + ivch_read(dvo, VR30, &val);
1425 + DRM_DEBUG("VR30: 0x%04x\n", val);
1426 + ivch_read(dvo, VR40, &val);
1427 + DRM_DEBUG("VR40: 0x%04x\n", val);
1428 +
1429 + /* GPIO registers */
1430 + ivch_read(dvo, VR80, &val);
1431 + DRM_DEBUG("VR80: 0x%04x\n", val);
1432 + ivch_read(dvo, VR81, &val);
1433 + DRM_DEBUG("VR81: 0x%04x\n", val);
1434 + ivch_read(dvo, VR82, &val);
1435 + DRM_DEBUG("VR82: 0x%04x\n", val);
1436 + ivch_read(dvo, VR83, &val);
1437 + DRM_DEBUG("VR83: 0x%04x\n", val);
1438 + ivch_read(dvo, VR84, &val);
1439 + DRM_DEBUG("VR84: 0x%04x\n", val);
1440 + ivch_read(dvo, VR85, &val);
1441 + DRM_DEBUG("VR85: 0x%04x\n", val);
1442 + ivch_read(dvo, VR86, &val);
1443 + DRM_DEBUG("VR86: 0x%04x\n", val);
1444 + ivch_read(dvo, VR87, &val);
1445 + DRM_DEBUG("VR87: 0x%04x\n", val);
1446 + ivch_read(dvo, VR88, &val);
1447 + DRM_DEBUG("VR88: 0x%04x\n", val);
1448 +
1449 + /* Scratch register 0 - AIM Panel type */
1450 + ivch_read(dvo, VR8E, &val);
1451 + DRM_DEBUG("VR8E: 0x%04x\n", val);
1452 +
1453 + /* Scratch register 1 - Status register */
1454 + ivch_read(dvo, VR8F, &val);
1455 + DRM_DEBUG("VR8F: 0x%04x\n", val);
1456 +}
1457 +
1458 +static void ivch_save(struct intel_dvo_device *dvo)
1459 +{
1460 + struct ivch_priv *priv = dvo->dev_priv;
1461 +
1462 + ivch_read(dvo, VR01, &priv->save_VR01);
1463 + ivch_read(dvo, VR40, &priv->save_VR40);
1464 +}
1465 +
1466 +static void ivch_restore(struct intel_dvo_device *dvo)
1467 +{
1468 + struct ivch_priv *priv = dvo->dev_priv;
1469 +
1470 + ivch_write(dvo, VR01, priv->save_VR01);
1471 + ivch_write(dvo, VR40, priv->save_VR40);
1472 +}
1473 +
1474 +static void ivch_destroy(struct intel_dvo_device *dvo)
1475 +{
1476 + struct ivch_priv *priv = dvo->dev_priv;
1477 +
1478 + if (priv) {
1479 + kfree(priv);
1480 + dvo->dev_priv = NULL;
1481 + }
1482 +}
1483 +
1484 +struct intel_dvo_dev_ops ivch_ops= {
1485 + .init = ivch_init,
1486 + .dpms = ivch_dpms,
1487 + .save = ivch_save,
1488 + .restore = ivch_restore,
1489 + .mode_valid = ivch_mode_valid,
1490 + .mode_set = ivch_mode_set,
1491 + .detect = ivch_detect,
1492 + .dump_regs = ivch_dump_regs,
1493 + .destroy = ivch_destroy,
1494 +};
1495 diff --git a/drivers/gpu/drm/i915/dvo_sil164.c b/drivers/gpu/drm/i915/dvo_sil164.c
1496 new file mode 100644
1497 index 0000000..033a4bb
1498 --- /dev/null
1499 +++ b/drivers/gpu/drm/i915/dvo_sil164.c
1500 @@ -0,0 +1,302 @@
1501 +/**************************************************************************
1502 +
1503 +Copyright © 2006 Dave Airlie
1504 +
1505 +All Rights Reserved.
1506 +
1507 +Permission is hereby granted, free of charge, to any person obtaining a
1508 +copy of this software and associated documentation files (the
1509 +"Software"), to deal in the Software without restriction, including
1510 +without limitation the rights to use, copy, modify, merge, publish,
1511 +distribute, sub license, and/or sell copies of the Software, and to
1512 +permit persons to whom the Software is furnished to do so, subject to
1513 +the following conditions:
1514 +
1515 +The above copyright notice and this permission notice (including the
1516 +next paragraph) shall be included in all copies or substantial portions
1517 +of the Software.
1518 +
1519 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1520 +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1521 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
1522 +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1523 +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
1524 +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1525 +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1526 +
1527 +**************************************************************************/
1528 +
1529 +#include "dvo.h"
1530 +
1531 +#define SIL164_VID 0x0001
1532 +#define SIL164_DID 0x0006
1533 +
1534 +#define SIL164_VID_LO 0x00
1535 +#define SIL164_VID_HI 0x01
1536 +#define SIL164_DID_LO 0x02
1537 +#define SIL164_DID_HI 0x03
1538 +#define SIL164_REV 0x04
1539 +#define SIL164_RSVD 0x05
1540 +#define SIL164_FREQ_LO 0x06
1541 +#define SIL164_FREQ_HI 0x07
1542 +
1543 +#define SIL164_REG8 0x08
1544 +#define SIL164_8_VEN (1<<5)
1545 +#define SIL164_8_HEN (1<<4)
1546 +#define SIL164_8_DSEL (1<<3)
1547 +#define SIL164_8_BSEL (1<<2)
1548 +#define SIL164_8_EDGE (1<<1)
1549 +#define SIL164_8_PD (1<<0)
1550 +
1551 +#define SIL164_REG9 0x09
1552 +#define SIL164_9_VLOW (1<<7)
1553 +#define SIL164_9_MSEL_MASK (0x7<<4)
1554 +#define SIL164_9_TSEL (1<<3)
1555 +#define SIL164_9_RSEN (1<<2)
1556 +#define SIL164_9_HTPLG (1<<1)
1557 +#define SIL164_9_MDI (1<<0)
1558 +
1559 +#define SIL164_REGC 0x0c
1560 +
1561 +struct sil164_save_rec {
1562 + uint8_t reg8;
1563 + uint8_t reg9;
1564 + uint8_t regc;
1565 +};
1566 +
1567 +struct sil164_priv {
1568 + //I2CDevRec d;
1569 + bool quiet;
1570 + struct sil164_save_rec save_regs;
1571 + struct sil164_save_rec mode_regs;
1572 +};
1573 +
1574 +#define SILPTR(d) ((SIL164Ptr)(d->DriverPrivate.ptr))
1575 +
1576 +static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
1577 +{
1578 + struct sil164_priv *sil = dvo->dev_priv;
1579 + struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
1580 + u8 out_buf[2];
1581 + u8 in_buf[2];
1582 +
1583 + struct i2c_msg msgs[] = {
1584 + {
1585 + .addr = i2cbus->slave_addr,
1586 + .flags = 0,
1587 + .len = 1,
1588 + .buf = out_buf,
1589 + },
1590 + {
1591 + .addr = i2cbus->slave_addr,
1592 + .flags = I2C_M_RD,
1593 + .len = 1,
1594 + .buf = in_buf,
1595 + }
1596 + };
1597 +
1598 + out_buf[0] = addr;
1599 + out_buf[1] = 0;
1600 +
1601 + if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
1602 + *ch = in_buf[0];
1603 + return true;
1604 + };
1605 +
1606 + if (!sil->quiet) {
1607 + DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
1608 + addr, i2cbus->adapter.name, i2cbus->slave_addr);
1609 + }
1610 + return false;
1611 +}
1612 +
1613 +static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
1614 +{
1615 + struct sil164_priv *sil= dvo->dev_priv;
1616 + struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
1617 + uint8_t out_buf[2];
1618 + struct i2c_msg msg = {
1619 + .addr = i2cbus->slave_addr,
1620 + .flags = 0,
1621 + .len = 2,
1622 + .buf = out_buf,
1623 + };
1624 +
1625 + out_buf[0] = addr;
1626 + out_buf[1] = ch;
1627 +
1628 + if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
1629 + return true;
1630 +
1631 + if (!sil->quiet) {
1632 + DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
1633 + addr, i2cbus->adapter.name, i2cbus->slave_addr);
1634 + }
1635 +
1636 + return false;
1637 +}
1638 +
1639 +/* Silicon Image 164 driver for chip on i2c bus */
1640 +static bool sil164_init(struct intel_dvo_device *dvo,
1641 + struct intel_i2c_chan *i2cbus)
1642 +{
1643 + /* this will detect the SIL164 chip on the specified i2c bus */
1644 + struct sil164_priv *sil;
1645 + unsigned char ch;
1646 +
1647 + sil = kzalloc(sizeof(struct sil164_priv), GFP_KERNEL);
1648 + if (sil == NULL)
1649 + return false;
1650 +
1651 + dvo->i2c_bus = i2cbus;
1652 + dvo->i2c_bus->slave_addr = dvo->slave_addr;
1653 + dvo->dev_priv = sil;
1654 + sil->quiet = true;
1655 +
1656 + if (!sil164_readb(dvo, SIL164_VID_LO, &ch))
1657 + goto out;
1658 +
1659 + if (ch != (SIL164_VID & 0xff)) {
1660 + DRM_DEBUG("sil164 not detected got %d: from %s Slave %d.\n",
1661 + ch, i2cbus->adapter.name, i2cbus->slave_addr);
1662 + goto out;
1663 + }
1664 +
1665 + if (!sil164_readb(dvo, SIL164_DID_LO, &ch))
1666 + goto out;
1667 +
1668 + if (ch != (SIL164_DID & 0xff)) {
1669 + DRM_DEBUG("sil164 not detected got %d: from %s Slave %d.\n",
1670 + ch, i2cbus->adapter.name, i2cbus->slave_addr);
1671 + goto out;
1672 + }
1673 + sil->quiet = false;
1674 +
1675 + DRM_DEBUG("init sil164 dvo controller successfully!\n");
1676 + return true;
1677 +
1678 +out:
1679 + kfree(sil);
1680 + return false;
1681 +}
1682 +
1683 +static enum drm_connector_status sil164_detect(struct intel_dvo_device *dvo)
1684 +{
1685 + uint8_t reg9;
1686 +
1687 + sil164_readb(dvo, SIL164_REG9, &reg9);
1688 +
1689 + if (reg9 & SIL164_9_HTPLG)
1690 + return connector_status_connected;
1691 + else
1692 + return connector_status_disconnected;
1693 +}
1694 +
1695 +static enum drm_mode_status sil164_mode_valid(struct intel_dvo_device *dvo,
1696 + struct drm_display_mode *mode)
1697 +{
1698 + return MODE_OK;
1699 +}
1700 +
1701 +static void sil164_mode_set(struct intel_dvo_device *dvo,
1702 + struct drm_display_mode *mode,
1703 + struct drm_display_mode *adjusted_mode)
1704 +{
1705 + /* As long as the basics are set up, since we don't have clock
1706 + * dependencies in the mode setup, we can just leave the
1707 + * registers alone and everything will work fine.
1708 + */
1709 + /* recommended programming sequence from doc */
1710 + /*sil164_writeb(sil, 0x08, 0x30);
1711 + sil164_writeb(sil, 0x09, 0x00);
1712 + sil164_writeb(sil, 0x0a, 0x90);
1713 + sil164_writeb(sil, 0x0c, 0x89);
1714 + sil164_writeb(sil, 0x08, 0x31);*/
1715 + /* don't do much */
1716 + return;
1717 +}
1718 +
1719 +/* set the SIL164 power state */
1720 +static void sil164_dpms(struct intel_dvo_device *dvo, int mode)
1721 +{
1722 + int ret;
1723 + unsigned char ch;
1724 +
1725 + ret = sil164_readb(dvo, SIL164_REG8, &ch);
1726 + if (ret == false)
1727 + return;
1728 +
1729 + if (mode == DRM_MODE_DPMS_ON)
1730 + ch |= SIL164_8_PD;
1731 + else
1732 + ch &= ~SIL164_8_PD;
1733 +
1734 + sil164_writeb(dvo, SIL164_REG8, ch);
1735 + return;
1736 +}
1737 +
1738 +static void sil164_dump_regs(struct intel_dvo_device *dvo)
1739 +{
1740 + uint8_t val;
1741 +
1742 + sil164_readb(dvo, SIL164_FREQ_LO, &val);
1743 + DRM_DEBUG("SIL164_FREQ_LO: 0x%02x\n", val);
1744 + sil164_readb(dvo, SIL164_FREQ_HI, &val);
1745 + DRM_DEBUG("SIL164_FREQ_HI: 0x%02x\n", val);
1746 + sil164_readb(dvo, SIL164_REG8, &val);
1747 + DRM_DEBUG("SIL164_REG8: 0x%02x\n", val);
1748 + sil164_readb(dvo, SIL164_REG9, &val);
1749 + DRM_DEBUG("SIL164_REG9: 0x%02x\n", val);
1750 + sil164_readb(dvo, SIL164_REGC, &val);
1751 + DRM_DEBUG("SIL164_REGC: 0x%02x\n", val);
1752 +}
1753 +
1754 +static void sil164_save(struct intel_dvo_device *dvo)
1755 +{
1756 + struct sil164_priv *sil= dvo->dev_priv;
1757 +
1758 + if (!sil164_readb(dvo, SIL164_REG8, &sil->save_regs.reg8))
1759 + return;
1760 +
1761 + if (!sil164_readb(dvo, SIL164_REG9, &sil->save_regs.reg9))
1762 + return;
1763 +
1764 + if (!sil164_readb(dvo, SIL164_REGC, &sil->save_regs.regc))
1765 + return;
1766 +
1767 + return;
1768 +}
1769 +
1770 +static void sil164_restore(struct intel_dvo_device *dvo)
1771 +{
1772 + struct sil164_priv *sil = dvo->dev_priv;
1773 +
1774 + /* Restore it powered down initially */
1775 + sil164_writeb(dvo, SIL164_REG8, sil->save_regs.reg8 & ~0x1);
1776 +
1777 + sil164_writeb(dvo, SIL164_REG9, sil->save_regs.reg9);
1778 + sil164_writeb(dvo, SIL164_REGC, sil->save_regs.regc);
1779 + sil164_writeb(dvo, SIL164_REG8, sil->save_regs.reg8);
1780 +}
1781 +
1782 +static void sil164_destroy(struct intel_dvo_device *dvo)
1783 +{
1784 + struct sil164_priv *sil = dvo->dev_priv;
1785 +
1786 + if (sil) {
1787 + kfree(sil);
1788 + dvo->dev_priv = NULL;
1789 + }
1790 +}
1791 +
1792 +struct intel_dvo_dev_ops sil164_ops = {
1793 + .init = sil164_init,
1794 + .detect = sil164_detect,
1795 + .mode_valid = sil164_mode_valid,
1796 + .mode_set = sil164_mode_set,
1797 + .dpms = sil164_dpms,
1798 + .dump_regs = sil164_dump_regs,
1799 + .save = sil164_save,
1800 + .restore = sil164_restore,
1801 + .destroy = sil164_destroy,
1802 +};
1803 diff --git a/drivers/gpu/drm/i915/dvo_tfp410.c b/drivers/gpu/drm/i915/dvo_tfp410.c
1804 new file mode 100644
1805 index 0000000..207fda8
1806 --- /dev/null
1807 +++ b/drivers/gpu/drm/i915/dvo_tfp410.c
1808 @@ -0,0 +1,335 @@
1809 +/*
1810 + * Copyright © 2007 Dave Mueller
1811 + *
1812 + * Permission is hereby granted, free of charge, to any person obtaining a
1813 + * copy of this software and associated documentation files (the "Software"),
1814 + * to deal in the Software without restriction, including without limitation
1815 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1816 + * and/or sell copies of the Software, and to permit persons to whom the
1817 + * Software is furnished to do so, subject to the following conditions:
1818 + *
1819 + * The above copyright notice and this permission notice (including the next
1820 + * paragraph) shall be included in all copies or substantial portions of the
1821 + * Software.
1822 + *
1823 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1824 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1825 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1826 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1827 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1828 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
1829 + * IN THE SOFTWARE.
1830 + *
1831 + * Authors:
1832 + * Dave Mueller <dave.mueller@gmx.ch>
1833 + *
1834 + */
1835 +
1836 +#include "dvo.h"
1837 +
1838 +/* register definitions according to the TFP410 data sheet */
1839 +#define TFP410_VID 0x014C
1840 +#define TFP410_DID 0x0410
1841 +
1842 +#define TFP410_VID_LO 0x00
1843 +#define TFP410_VID_HI 0x01
1844 +#define TFP410_DID_LO 0x02
1845 +#define TFP410_DID_HI 0x03
1846 +#define TFP410_REV 0x04
1847 +
1848 +#define TFP410_CTL_1 0x08
1849 +#define TFP410_CTL_1_TDIS (1<<6)
1850 +#define TFP410_CTL_1_VEN (1<<5)
1851 +#define TFP410_CTL_1_HEN (1<<4)
1852 +#define TFP410_CTL_1_DSEL (1<<3)
1853 +#define TFP410_CTL_1_BSEL (1<<2)
1854 +#define TFP410_CTL_1_EDGE (1<<1)
1855 +#define TFP410_CTL_1_PD (1<<0)
1856 +
1857 +#define TFP410_CTL_2 0x09
1858 +#define TFP410_CTL_2_VLOW (1<<7)
1859 +#define TFP410_CTL_2_MSEL_MASK (0x7<<4)
1860 +#define TFP410_CTL_2_MSEL (1<<4)
1861 +#define TFP410_CTL_2_TSEL (1<<3)
1862 +#define TFP410_CTL_2_RSEN (1<<2)
1863 +#define TFP410_CTL_2_HTPLG (1<<1)
1864 +#define TFP410_CTL_2_MDI (1<<0)
1865 +
1866 +#define TFP410_CTL_3 0x0A
1867 +#define TFP410_CTL_3_DK_MASK (0x7<<5)
1868 +#define TFP410_CTL_3_DK (1<<5)
1869 +#define TFP410_CTL_3_DKEN (1<<4)
1870 +#define TFP410_CTL_3_CTL_MASK (0x7<<1)
1871 +#define TFP410_CTL_3_CTL (1<<1)
1872 +
1873 +#define TFP410_USERCFG 0x0B
1874 +
1875 +#define TFP410_DE_DLY 0x32
1876 +
1877 +#define TFP410_DE_CTL 0x33
1878 +#define TFP410_DE_CTL_DEGEN (1<<6)
1879 +#define TFP410_DE_CTL_VSPOL (1<<5)
1880 +#define TFP410_DE_CTL_HSPOL (1<<4)
1881 +#define TFP410_DE_CTL_DEDLY8 (1<<0)
1882 +
1883 +#define TFP410_DE_TOP 0x34
1884 +
1885 +#define TFP410_DE_CNT_LO 0x36
1886 +#define TFP410_DE_CNT_HI 0x37
1887 +
1888 +#define TFP410_DE_LIN_LO 0x38
1889 +#define TFP410_DE_LIN_HI 0x39
1890 +
1891 +#define TFP410_H_RES_LO 0x3A
1892 +#define TFP410_H_RES_HI 0x3B
1893 +
1894 +#define TFP410_V_RES_LO 0x3C
1895 +#define TFP410_V_RES_HI 0x3D
1896 +
1897 +struct tfp410_save_rec {
1898 + uint8_t ctl1;
1899 + uint8_t ctl2;
1900 +};
1901 +
1902 +struct tfp410_priv {
1903 + bool quiet;
1904 +
1905 + struct tfp410_save_rec saved_reg;
1906 + struct tfp410_save_rec mode_reg;
1907 +};
1908 +
1909 +static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
1910 +{
1911 + struct tfp410_priv *tfp = dvo->dev_priv;
1912 + struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
1913 + u8 out_buf[2];
1914 + u8 in_buf[2];
1915 +
1916 + struct i2c_msg msgs[] = {
1917 + {
1918 + .addr = i2cbus->slave_addr,
1919 + .flags = 0,
1920 + .len = 1,
1921 + .buf = out_buf,
1922 + },
1923 + {
1924 + .addr = i2cbus->slave_addr,
1925 + .flags = I2C_M_RD,
1926 + .len = 1,
1927 + .buf = in_buf,
1928 + }
1929 + };
1930 +
1931 + out_buf[0] = addr;
1932 + out_buf[1] = 0;
1933 +
1934 + if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
1935 + *ch = in_buf[0];
1936 + return true;
1937 + };
1938 +
1939 + if (!tfp->quiet) {
1940 + DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
1941 + addr, i2cbus->adapter.name, i2cbus->slave_addr);
1942 + }
1943 + return false;
1944 +}
1945 +
1946 +static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
1947 +{
1948 + struct tfp410_priv *tfp = dvo->dev_priv;
1949 + struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
1950 + uint8_t out_buf[2];
1951 + struct i2c_msg msg = {
1952 + .addr = i2cbus->slave_addr,
1953 + .flags = 0,
1954 + .len = 2,
1955 + .buf = out_buf,
1956 + };
1957 +
1958 + out_buf[0] = addr;
1959 + out_buf[1] = ch;
1960 +
1961 + if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
1962 + return true;
1963 +
1964 + if (!tfp->quiet) {
1965 + DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
1966 + addr, i2cbus->adapter.name, i2cbus->slave_addr);
1967 + }
1968 +
1969 + return false;
1970 +}
1971 +
1972 +static int tfp410_getid(struct intel_dvo_device *dvo, int addr)
1973 +{
1974 + uint8_t ch1, ch2;
1975 +
1976 + if (tfp410_readb(dvo, addr+0, &ch1) &&
1977 + tfp410_readb(dvo, addr+1, &ch2))
1978 + return ((ch2 << 8) & 0xFF00) | (ch1 & 0x00FF);
1979 +
1980 + return -1;
1981 +}
1982 +
1983 +/* Ti TFP410 driver for chip on i2c bus */
1984 +static bool tfp410_init(struct intel_dvo_device *dvo,
1985 + struct intel_i2c_chan *i2cbus)
1986 +{
1987 + /* this will detect the tfp410 chip on the specified i2c bus */
1988 + struct tfp410_priv *tfp;
1989 + int id;
1990 +
1991 + tfp = kzalloc(sizeof(struct tfp410_priv), GFP_KERNEL);
1992 + if (tfp == NULL)
1993 + return false;
1994 +
1995 + dvo->i2c_bus = i2cbus;
1996 + dvo->i2c_bus->slave_addr = dvo->slave_addr;
1997 + dvo->dev_priv = tfp;
1998 + tfp->quiet = true;
1999 +
2000 + if ((id = tfp410_getid(dvo, TFP410_VID_LO)) != TFP410_VID) {
2001 + DRM_DEBUG("tfp410 not detected got VID %X: from %s Slave %d.\n",
2002 + id, i2cbus->adapter.name, i2cbus->slave_addr);
2003 + goto out;
2004 + }
2005 +
2006 + if ((id = tfp410_getid(dvo, TFP410_DID_LO)) != TFP410_DID) {
2007 + DRM_DEBUG("tfp410 not detected got DID %X: from %s Slave %d.\n",
2008 + id, i2cbus->adapter.name, i2cbus->slave_addr);
2009 + goto out;
2010 + }
2011 + tfp->quiet = false;
2012 + return true;
2013 +out:
2014 + kfree(tfp);
2015 + return false;
2016 +}
2017 +
2018 +static enum drm_connector_status tfp410_detect(struct intel_dvo_device *dvo)
2019 +{
2020 + enum drm_connector_status ret = connector_status_disconnected;
2021 + uint8_t ctl2;
2022 +
2023 + if (tfp410_readb(dvo, TFP410_CTL_2, &ctl2)) {
2024 + if (ctl2 & TFP410_CTL_2_HTPLG)
2025 + ret = connector_status_connected;
2026 + else
2027 + ret = connector_status_disconnected;
2028 + }
2029 +
2030 + return ret;
2031 +}
2032 +
2033 +static enum drm_mode_status tfp410_mode_valid(struct intel_dvo_device *dvo,
2034 + struct drm_display_mode *mode)
2035 +{
2036 + return MODE_OK;
2037 +}
2038 +
2039 +static void tfp410_mode_set(struct intel_dvo_device *dvo,
2040 + struct drm_display_mode *mode,
2041 + struct drm_display_mode *adjusted_mode)
2042 +{
2043 + /* As long as the basics are set up, since we don't have clock dependencies
2044 + * in the mode setup, we can just leave the registers alone and everything
2045 + * will work fine.
2046 + */
2047 + /* don't do much */
2048 + return;
2049 +}
2050 +
2051 +/* set the tfp410 power state */
2052 +static void tfp410_dpms(struct intel_dvo_device *dvo, int mode)
2053 +{
2054 + uint8_t ctl1;
2055 +
2056 + if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1))
2057 + return;