diff options
Diffstat (limited to 'drivers/gpu/drm')
26 files changed, 10566 insertions, 50 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index a8b33c2ec8d2..5f26d6c840de 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig | |||
@@ -76,6 +76,17 @@ config DRM_I915 | |||
76 | 76 | ||
77 | endchoice | 77 | endchoice |
78 | 78 | ||
79 | config DRM_I915_KMS | ||
80 | bool "Enable modesetting on intel by default" | ||
81 | depends on DRM_I915 | ||
82 | help | ||
83 | Choose this option if you want kernel modesetting enabled by default, | ||
84 | and you have a new enough userspace to support this. Running old | ||
85 | userspaces with this enabled will cause pain. Note that this causes | ||
86 | the driver to bind to PCI devices, which precludes loading things | ||
87 | like intelfb. | ||
88 | |||
89 | |||
79 | config DRM_MGA | 90 | config DRM_MGA |
80 | tristate "Matrox g200/g400" | 91 | tristate "Matrox g200/g400" |
81 | depends on DRM | 92 | depends on DRM |
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index d8fb5d8ee7ea..dd57a5bd4572 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile | |||
@@ -8,7 +8,22 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \ | |||
8 | i915_gem.o \ | 8 | i915_gem.o \ |
9 | i915_gem_debug.o \ | 9 | i915_gem_debug.o \ |
10 | i915_gem_proc.o \ | 10 | i915_gem_proc.o \ |
11 | i915_gem_tiling.o | 11 | i915_gem_tiling.o \ |
12 | intel_display.o \ | ||
13 | intel_crt.o \ | ||
14 | intel_lvds.o \ | ||
15 | intel_bios.o \ | ||
16 | intel_sdvo.o \ | ||
17 | intel_modes.o \ | ||
18 | intel_i2c.o \ | ||
19 | intel_fb.o \ | ||
20 | intel_tv.o \ | ||
21 | intel_dvo.o \ | ||
22 | dvo_ch7xxx.o \ | ||
23 | dvo_ch7017.o \ | ||
24 | dvo_ivch.o \ | ||
25 | dvo_tfp410.o \ | ||
26 | dvo_sil164.o | ||
12 | 27 | ||
13 | i915-$(CONFIG_ACPI) += i915_opregion.o | 28 | i915-$(CONFIG_ACPI) += i915_opregion.o |
14 | i915-$(CONFIG_COMPAT) += i915_ioc32.o | 29 | i915-$(CONFIG_COMPAT) += i915_ioc32.o |
diff --git a/drivers/gpu/drm/i915/dvo.h b/drivers/gpu/drm/i915/dvo.h new file mode 100644 index 000000000000..e80866c5e1ae --- /dev/null +++ b/drivers/gpu/drm/i915/dvo.h | |||
@@ -0,0 +1,151 @@ | |||
1 | /* | ||
2 | * Copyright © 2006 Eric Anholt | ||
3 | * | ||
4 | * Permission to use, copy, modify, distribute, and sell this software and its | ||
5 | * documentation for any purpose is hereby granted without fee, provided that | ||
6 | * the above copyright notice appear in all copies and that both that copyright | ||
7 | * notice and this permission notice appear in supporting documentation, and | ||
8 | * that the name of the copyright holders not be used in advertising or | ||
9 | * publicity pertaining to distribution of the software without specific, | ||
10 | * written prior permission. The copyright holders make no representations | ||
11 | * about the suitability of this software for any purpose. It is provided "as | ||
12 | * is" without express or implied warranty. | ||
13 | * | ||
14 | * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | ||
15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | ||
16 | * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR | ||
17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | ||
18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | ||
19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | ||
20 | * OF THIS SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #ifndef _INTEL_DVO_H | ||
24 | #define _INTEL_DVO_H | ||
25 | |||
26 | #include <linux/i2c.h> | ||
27 | #include "drmP.h" | ||
28 | #include "drm.h" | ||
29 | #include "drm_crtc.h" | ||
30 | #include "intel_drv.h" | ||
31 | |||
32 | struct intel_dvo_device { | ||
33 | char *name; | ||
34 | int type; | ||
35 | /* DVOA/B/C output register */ | ||
36 | u32 dvo_reg; | ||
37 | /* GPIO register used for i2c bus to control this device */ | ||
38 | u32 gpio; | ||
39 | int slave_addr; | ||
40 | struct intel_i2c_chan *i2c_bus; | ||
41 | |||
42 | const struct intel_dvo_dev_ops *dev_ops; | ||
43 | void *dev_priv; | ||
44 | |||
45 | struct drm_display_mode *panel_fixed_mode; | ||
46 | bool panel_wants_dither; | ||
47 | }; | ||
48 | |||
49 | struct intel_dvo_dev_ops { | ||
50 | /* | ||
51 | * Initialize the device at startup time. | ||
52 | * Returns NULL if the device does not exist. | ||
53 | */ | ||
54 | bool (*init)(struct intel_dvo_device *dvo, | ||
55 | struct intel_i2c_chan *i2cbus); | ||
56 | |||
57 | /* | ||
58 | * Called to allow the output a chance to create properties after the | ||
59 | * RandR objects have been created. | ||
60 | */ | ||
61 | void (*create_resources)(struct intel_dvo_device *dvo); | ||
62 | |||
63 | /* | ||
64 | * Turn on/off output or set intermediate power levels if available. | ||
65 | * | ||
66 | * Unsupported intermediate modes drop to the lower power setting. | ||
67 | * If the mode is DPMSModeOff, the output must be disabled, | ||
68 | * as the DPLL may be disabled afterwards. | ||
69 | */ | ||
70 | void (*dpms)(struct intel_dvo_device *dvo, int mode); | ||
71 | |||
72 | /* | ||
73 | * Saves the output's state for restoration on VT switch. | ||
74 | */ | ||
75 | void (*save)(struct intel_dvo_device *dvo); | ||
76 | |||
77 | /* | ||
78 | * Restore's the output's state at VT switch. | ||
79 | */ | ||
80 | void (*restore)(struct intel_dvo_device *dvo); | ||
81 | |||
82 | /* | ||
83 | * Callback for testing a video mode for a given output. | ||
84 | * | ||
85 | * This function should only check for cases where a mode can't | ||
86 | * be supported on the output specifically, and not represent | ||
87 | * generic CRTC limitations. | ||
88 | * | ||
89 | * \return MODE_OK if the mode is valid, or another MODE_* otherwise. | ||
90 | */ | ||
91 | int (*mode_valid)(struct intel_dvo_device *dvo, | ||
92 | struct drm_display_mode *mode); | ||
93 | |||
94 | /* | ||
95 | * Callback to adjust the mode to be set in the CRTC. | ||
96 | * | ||
97 | * This allows an output to adjust the clock or even the entire set of | ||
98 | * timings, which is used for panels with fixed timings or for | ||
99 | * buses with clock limitations. | ||
100 | */ | ||
101 | bool (*mode_fixup)(struct intel_dvo_device *dvo, | ||
102 | struct drm_display_mode *mode, | ||
103 | struct drm_display_mode *adjusted_mode); | ||
104 | |||
105 | /* | ||
106 | * Callback for preparing mode changes on an output | ||
107 | */ | ||
108 | void (*prepare)(struct intel_dvo_device *dvo); | ||
109 | |||
110 | /* | ||
111 | * Callback for committing mode changes on an output | ||
112 | */ | ||
113 | void (*commit)(struct intel_dvo_device *dvo); | ||
114 | |||
115 | /* | ||
116 | * Callback for setting up a video mode after fixups have been made. | ||
117 | * | ||
118 | * This is only called while the output is disabled. The dpms callback | ||
119 | * must be all that's necessary for the output, to turn the output on | ||
120 | * after this function is called. | ||
121 | */ | ||
122 | void (*mode_set)(struct intel_dvo_device *dvo, | ||
123 | struct drm_display_mode *mode, | ||
124 | struct drm_display_mode *adjusted_mode); | ||
125 | |||
126 | /* | ||
127 | * Probe for a connected output, and return detect_status. | ||
128 | */ | ||
129 | enum drm_connector_status (*detect)(struct intel_dvo_device *dvo); | ||
130 | |||
131 | /** | ||
132 | * Query the device for the modes it provides. | ||
133 | * | ||
134 | * This function may also update MonInfo, mm_width, and mm_height. | ||
135 | * | ||
136 | * \return singly-linked list of modes or NULL if no modes found. | ||
137 | */ | ||
138 | struct drm_display_mode *(*get_modes)(struct intel_dvo_device *dvo); | ||
139 | |||
140 | /** | ||
141 | * Clean up driver-specific bits of the output | ||
142 | */ | ||
143 | void (*destroy) (struct intel_dvo_device *dvo); | ||
144 | |||
145 | /** | ||
146 | * Debugging hook to dump device registers to log file | ||
147 | */ | ||
148 | void (*dump_regs)(struct intel_dvo_device *dvo); | ||
149 | }; | ||
150 | |||
151 | #endif /* _INTEL_DVO_H */ | ||
diff --git a/drivers/gpu/drm/i915/dvo_ch7017.c b/drivers/gpu/drm/i915/dvo_ch7017.c new file mode 100644 index 000000000000..03d4b4973b02 --- /dev/null +++ b/drivers/gpu/drm/i915/dvo_ch7017.c | |||
@@ -0,0 +1,454 @@ | |||
1 | /* | ||
2 | * Copyright © 2006 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Eric Anholt <eric@anholt.net> | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include "dvo.h" | ||
29 | |||
30 | #define CH7017_TV_DISPLAY_MODE 0x00 | ||
31 | #define CH7017_FLICKER_FILTER 0x01 | ||
32 | #define CH7017_VIDEO_BANDWIDTH 0x02 | ||
33 | #define CH7017_TEXT_ENHANCEMENT 0x03 | ||
34 | #define CH7017_START_ACTIVE_VIDEO 0x04 | ||
35 | #define CH7017_HORIZONTAL_POSITION 0x05 | ||
36 | #define CH7017_VERTICAL_POSITION 0x06 | ||
37 | #define CH7017_BLACK_LEVEL 0x07 | ||
38 | #define CH7017_CONTRAST_ENHANCEMENT 0x08 | ||
39 | #define CH7017_TV_PLL 0x09 | ||
40 | #define CH7017_TV_PLL_M 0x0a | ||
41 | #define CH7017_TV_PLL_N 0x0b | ||
42 | #define CH7017_SUB_CARRIER_0 0x0c | ||
43 | #define CH7017_CIV_CONTROL 0x10 | ||
44 | #define CH7017_CIV_0 0x11 | ||
45 | #define CH7017_CHROMA_BOOST 0x14 | ||
46 | #define CH7017_CLOCK_MODE 0x1c | ||
47 | #define CH7017_INPUT_CLOCK 0x1d | ||
48 | #define CH7017_GPIO_CONTROL 0x1e | ||
49 | #define CH7017_INPUT_DATA_FORMAT 0x1f | ||
50 | #define CH7017_CONNECTION_DETECT 0x20 | ||
51 | #define CH7017_DAC_CONTROL 0x21 | ||
52 | #define CH7017_BUFFERED_CLOCK_OUTPUT 0x22 | ||
53 | #define CH7017_DEFEAT_VSYNC 0x47 | ||
54 | #define CH7017_TEST_PATTERN 0x48 | ||
55 | |||
56 | #define CH7017_POWER_MANAGEMENT 0x49 | ||
57 | /** Enables the TV output path. */ | ||
58 | #define CH7017_TV_EN (1 << 0) | ||
59 | #define CH7017_DAC0_POWER_DOWN (1 << 1) | ||
60 | #define CH7017_DAC1_POWER_DOWN (1 << 2) | ||
61 | #define CH7017_DAC2_POWER_DOWN (1 << 3) | ||
62 | #define CH7017_DAC3_POWER_DOWN (1 << 4) | ||
63 | /** Powers down the TV out block, and DAC0-3 */ | ||
64 | #define CH7017_TV_POWER_DOWN_EN (1 << 5) | ||
65 | |||
66 | #define CH7017_VERSION_ID 0x4a | ||
67 | |||
68 | #define CH7017_DEVICE_ID 0x4b | ||
69 | #define CH7017_DEVICE_ID_VALUE 0x1b | ||
70 | #define CH7018_DEVICE_ID_VALUE 0x1a | ||
71 | #define CH7019_DEVICE_ID_VALUE 0x19 | ||
72 | |||
73 | #define CH7017_XCLK_D2_ADJUST 0x53 | ||
74 | #define CH7017_UP_SCALER_COEFF_0 0x55 | ||
75 | #define CH7017_UP_SCALER_COEFF_1 0x56 | ||
76 | #define CH7017_UP_SCALER_COEFF_2 0x57 | ||
77 | #define CH7017_UP_SCALER_COEFF_3 0x58 | ||
78 | #define CH7017_UP_SCALER_COEFF_4 0x59 | ||
79 | #define CH7017_UP_SCALER_VERTICAL_INC_0 0x5a | ||
80 | #define CH7017_UP_SCALER_VERTICAL_INC_1 0x5b | ||
81 | #define CH7017_GPIO_INVERT 0x5c | ||
82 | #define CH7017_UP_SCALER_HORIZONTAL_INC_0 0x5d | ||
83 | #define CH7017_UP_SCALER_HORIZONTAL_INC_1 0x5e | ||
84 | |||
85 | #define CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT 0x5f | ||
86 | /**< Low bits of horizontal active pixel input */ | ||
87 | |||
88 | #define CH7017_ACTIVE_INPUT_LINE_OUTPUT 0x60 | ||
89 | /** High bits of horizontal active pixel input */ | ||
90 | #define CH7017_LVDS_HAP_INPUT_MASK (0x7 << 0) | ||
91 | /** High bits of vertical active line output */ | ||
92 | #define CH7017_LVDS_VAL_HIGH_MASK (0x7 << 3) | ||
93 | |||
94 | #define CH7017_VERTICAL_ACTIVE_LINE_OUTPUT 0x61 | ||
95 | /**< Low bits of vertical active line output */ | ||
96 | |||
97 | #define CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT 0x62 | ||
98 | /**< Low bits of horizontal active pixel output */ | ||
99 | |||
100 | #define CH7017_LVDS_POWER_DOWN 0x63 | ||
101 | /** High bits of horizontal active pixel output */ | ||
102 | #define CH7017_LVDS_HAP_HIGH_MASK (0x7 << 0) | ||
103 | /** Enables the LVDS power down state transition */ | ||
104 | #define CH7017_LVDS_POWER_DOWN_EN (1 << 6) | ||
105 | /** Enables the LVDS upscaler */ | ||
106 | #define CH7017_LVDS_UPSCALER_EN (1 << 7) | ||
107 | #define CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED 0x08 | ||
108 | |||
109 | #define CH7017_LVDS_ENCODING 0x64 | ||
110 | #define CH7017_LVDS_DITHER_2D (1 << 2) | ||
111 | #define CH7017_LVDS_DITHER_DIS (1 << 3) | ||
112 | #define CH7017_LVDS_DUAL_CHANNEL_EN (1 << 4) | ||
113 | #define CH7017_LVDS_24_BIT (1 << 5) | ||
114 | |||
115 | #define CH7017_LVDS_ENCODING_2 0x65 | ||
116 | |||
117 | #define CH7017_LVDS_PLL_CONTROL 0x66 | ||
118 | /** Enables the LVDS panel output path */ | ||
119 | #define CH7017_LVDS_PANEN (1 << 0) | ||
120 | /** Enables the LVDS panel backlight */ | ||
121 | #define CH7017_LVDS_BKLEN (1 << 3) | ||
122 | |||
123 | #define CH7017_POWER_SEQUENCING_T1 0x67 | ||
124 | #define CH7017_POWER_SEQUENCING_T2 0x68 | ||
125 | #define CH7017_POWER_SEQUENCING_T3 0x69 | ||
126 | #define CH7017_POWER_SEQUENCING_T4 0x6a | ||
127 | #define CH7017_POWER_SEQUENCING_T5 0x6b | ||
128 | #define CH7017_GPIO_DRIVER_TYPE 0x6c | ||
129 | #define CH7017_GPIO_DATA 0x6d | ||
130 | #define CH7017_GPIO_DIRECTION_CONTROL 0x6e | ||
131 | |||
132 | #define CH7017_LVDS_PLL_FEEDBACK_DIV 0x71 | ||
133 | # define CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT 4 | ||
134 | # define CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT 0 | ||
135 | # define CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED 0x80 | ||
136 | |||
137 | #define CH7017_LVDS_PLL_VCO_CONTROL 0x72 | ||
138 | # define CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED 0x80 | ||
139 | # define CH7017_LVDS_PLL_VCO_SHIFT 4 | ||
140 | # define CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT 0 | ||
141 | |||
142 | #define CH7017_OUTPUTS_ENABLE 0x73 | ||
143 | # define CH7017_CHARGE_PUMP_LOW 0x0 | ||
144 | # define CH7017_CHARGE_PUMP_HIGH 0x3 | ||
145 | # define CH7017_LVDS_CHANNEL_A (1 << 3) | ||
146 | # define CH7017_LVDS_CHANNEL_B (1 << 4) | ||
147 | # define CH7017_TV_DAC_A (1 << 5) | ||
148 | # define CH7017_TV_DAC_B (1 << 6) | ||
149 | # define CH7017_DDC_SELECT_DC2 (1 << 7) | ||
150 | |||
151 | #define CH7017_LVDS_OUTPUT_AMPLITUDE 0x74 | ||
152 | #define CH7017_LVDS_PLL_EMI_REDUCTION 0x75 | ||
153 | #define CH7017_LVDS_POWER_DOWN_FLICKER 0x76 | ||
154 | |||
155 | #define CH7017_LVDS_CONTROL_2 0x78 | ||
156 | # define CH7017_LOOP_FILTER_SHIFT 5 | ||
157 | # define CH7017_PHASE_DETECTOR_SHIFT 0 | ||
158 | |||
159 | #define CH7017_BANG_LIMIT_CONTROL 0x7f | ||
160 | |||
161 | struct ch7017_priv { | ||
162 | uint8_t save_hapi; | ||
163 | uint8_t save_vali; | ||
164 | uint8_t save_valo; | ||
165 | uint8_t save_ailo; | ||
166 | uint8_t save_lvds_pll_vco; | ||
167 | uint8_t save_feedback_div; | ||
168 | uint8_t save_lvds_control_2; | ||
169 | uint8_t save_outputs_enable; | ||
170 | uint8_t save_lvds_power_down; | ||
171 | uint8_t save_power_management; | ||
172 | }; | ||
173 | |||
174 | static void ch7017_dump_regs(struct intel_dvo_device *dvo); | ||
175 | static void ch7017_dpms(struct intel_dvo_device *dvo, int mode); | ||
176 | |||
177 | static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val) | ||
178 | { | ||
179 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
180 | u8 out_buf[2]; | ||
181 | u8 in_buf[2]; | ||
182 | |||
183 | struct i2c_msg msgs[] = { | ||
184 | { | ||
185 | .addr = i2cbus->slave_addr, | ||
186 | .flags = 0, | ||
187 | .len = 1, | ||
188 | .buf = out_buf, | ||
189 | }, | ||
190 | { | ||
191 | .addr = i2cbus->slave_addr, | ||
192 | .flags = I2C_M_RD, | ||
193 | .len = 1, | ||
194 | .buf = in_buf, | ||
195 | } | ||
196 | }; | ||
197 | |||
198 | out_buf[0] = addr; | ||
199 | out_buf[1] = 0; | ||
200 | |||
201 | if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { | ||
202 | *val= in_buf[0]; | ||
203 | return true; | ||
204 | }; | ||
205 | |||
206 | return false; | ||
207 | } | ||
208 | |||
209 | static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val) | ||
210 | { | ||
211 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
212 | uint8_t out_buf[2]; | ||
213 | struct i2c_msg msg = { | ||
214 | .addr = i2cbus->slave_addr, | ||
215 | .flags = 0, | ||
216 | .len = 2, | ||
217 | .buf = out_buf, | ||
218 | }; | ||
219 | |||
220 | out_buf[0] = addr; | ||
221 | out_buf[1] = val; | ||
222 | |||
223 | if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) | ||
224 | return true; | ||
225 | |||
226 | return false; | ||
227 | } | ||
228 | |||
229 | /** Probes for a CH7017 on the given bus and slave address. */ | ||
230 | static bool ch7017_init(struct intel_dvo_device *dvo, | ||
231 | struct intel_i2c_chan *i2cbus) | ||
232 | { | ||
233 | struct ch7017_priv *priv; | ||
234 | uint8_t val; | ||
235 | |||
236 | priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL); | ||
237 | if (priv == NULL) | ||
238 | return false; | ||
239 | |||
240 | dvo->i2c_bus = i2cbus; | ||
241 | dvo->i2c_bus->slave_addr = dvo->slave_addr; | ||
242 | dvo->dev_priv = priv; | ||
243 | |||
244 | if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val)) | ||
245 | goto fail; | ||
246 | |||
247 | if (val != CH7017_DEVICE_ID_VALUE && | ||
248 | val != CH7018_DEVICE_ID_VALUE && | ||
249 | val != CH7019_DEVICE_ID_VALUE) { | ||
250 | DRM_DEBUG("ch701x not detected, got %d: from %s Slave %d.\n", | ||
251 | val, i2cbus->adapter.name,i2cbus->slave_addr); | ||
252 | goto fail; | ||
253 | } | ||
254 | |||
255 | return true; | ||
256 | fail: | ||
257 | kfree(priv); | ||
258 | return false; | ||
259 | } | ||
260 | |||
261 | static enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo) | ||
262 | { | ||
263 | return connector_status_unknown; | ||
264 | } | ||
265 | |||
266 | static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo, | ||
267 | struct drm_display_mode *mode) | ||
268 | { | ||
269 | if (mode->clock > 160000) | ||
270 | return MODE_CLOCK_HIGH; | ||
271 | |||
272 | return MODE_OK; | ||
273 | } | ||
274 | |||
275 | static void ch7017_mode_set(struct intel_dvo_device *dvo, | ||
276 | struct drm_display_mode *mode, | ||
277 | struct drm_display_mode *adjusted_mode) | ||
278 | { | ||
279 | uint8_t lvds_pll_feedback_div, lvds_pll_vco_control; | ||
280 | uint8_t outputs_enable, lvds_control_2, lvds_power_down; | ||
281 | uint8_t horizontal_active_pixel_input; | ||
282 | uint8_t horizontal_active_pixel_output, vertical_active_line_output; | ||
283 | uint8_t active_input_line_output; | ||
284 | |||
285 | DRM_DEBUG("Registers before mode setting\n"); | ||
286 | ch7017_dump_regs(dvo); | ||
287 | |||
288 | /* LVDS PLL settings from page 75 of 7017-7017ds.pdf*/ | ||
289 | if (mode->clock < 100000) { | ||
290 | outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_LOW; | ||
291 | lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED | | ||
292 | (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) | | ||
293 | (13 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT); | ||
294 | lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | | ||
295 | (2 << CH7017_LVDS_PLL_VCO_SHIFT) | | ||
296 | (3 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); | ||
297 | lvds_control_2 = (1 << CH7017_LOOP_FILTER_SHIFT) | | ||
298 | (0 << CH7017_PHASE_DETECTOR_SHIFT); | ||
299 | } else { | ||
300 | outputs_enable = CH7017_LVDS_CHANNEL_A | CH7017_CHARGE_PUMP_HIGH; | ||
301 | lvds_pll_feedback_div = CH7017_LVDS_PLL_FEEDBACK_DEFAULT_RESERVED | | ||
302 | (2 << CH7017_LVDS_PLL_FEED_BACK_DIVIDER_SHIFT) | | ||
303 | (3 << CH7017_LVDS_PLL_FEED_FORWARD_DIVIDER_SHIFT); | ||
304 | lvds_pll_feedback_div = 35; | ||
305 | lvds_control_2 = (3 << CH7017_LOOP_FILTER_SHIFT) | | ||
306 | (0 << CH7017_PHASE_DETECTOR_SHIFT); | ||
307 | if (1) { /* XXX: dual channel panel detection. Assume yes for now. */ | ||
308 | outputs_enable |= CH7017_LVDS_CHANNEL_B; | ||
309 | lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | | ||
310 | (2 << CH7017_LVDS_PLL_VCO_SHIFT) | | ||
311 | (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); | ||
312 | } else { | ||
313 | lvds_pll_vco_control = CH7017_LVDS_PLL_VCO_DEFAULT_RESERVED | | ||
314 | (1 << CH7017_LVDS_PLL_VCO_SHIFT) | | ||
315 | (13 << CH7017_LVDS_PLL_POST_SCALE_DIV_SHIFT); | ||
316 | } | ||
317 | } | ||
318 | |||
319 | horizontal_active_pixel_input = mode->hdisplay & 0x00ff; | ||
320 | |||
321 | vertical_active_line_output = mode->vdisplay & 0x00ff; | ||
322 | horizontal_active_pixel_output = mode->hdisplay & 0x00ff; | ||
323 | |||
324 | active_input_line_output = ((mode->hdisplay & 0x0700) >> 8) | | ||
325 | (((mode->vdisplay & 0x0700) >> 8) << 3); | ||
326 | |||
327 | lvds_power_down = CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED | | ||
328 | (mode->hdisplay & 0x0700) >> 8; | ||
329 | |||
330 | ch7017_dpms(dvo, DRM_MODE_DPMS_OFF); | ||
331 | ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, | ||
332 | horizontal_active_pixel_input); | ||
333 | ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT, | ||
334 | horizontal_active_pixel_output); | ||
335 | ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, | ||
336 | vertical_active_line_output); | ||
337 | ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, | ||
338 | active_input_line_output); | ||
339 | ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, lvds_pll_vco_control); | ||
340 | ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, lvds_pll_feedback_div); | ||
341 | ch7017_write(dvo, CH7017_LVDS_CONTROL_2, lvds_control_2); | ||
342 | ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, outputs_enable); | ||
343 | |||
344 | /* Turn the LVDS back on with new settings. */ | ||
345 | ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, lvds_power_down); | ||
346 | |||
347 | DRM_DEBUG("Registers after mode setting\n"); | ||
348 | ch7017_dump_regs(dvo); | ||
349 | } | ||
350 | |||
351 | /* set the CH7017 power state */ | ||
352 | static void ch7017_dpms(struct intel_dvo_device *dvo, int mode) | ||
353 | { | ||
354 | uint8_t val; | ||
355 | |||
356 | ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &val); | ||
357 | |||
358 | /* Turn off TV/VGA, and never turn it on since we don't support it. */ | ||
359 | ch7017_write(dvo, CH7017_POWER_MANAGEMENT, | ||
360 | CH7017_DAC0_POWER_DOWN | | ||
361 | CH7017_DAC1_POWER_DOWN | | ||
362 | CH7017_DAC2_POWER_DOWN | | ||
363 | CH7017_DAC3_POWER_DOWN | | ||
364 | CH7017_TV_POWER_DOWN_EN); | ||
365 | |||
366 | if (mode == DRM_MODE_DPMS_ON) { | ||
367 | /* Turn on the LVDS */ | ||
368 | ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, | ||
369 | val & ~CH7017_LVDS_POWER_DOWN_EN); | ||
370 | } else { | ||
371 | /* Turn off the LVDS */ | ||
372 | ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, | ||
373 | val | CH7017_LVDS_POWER_DOWN_EN); | ||
374 | } | ||
375 | |||
376 | /* XXX: Should actually wait for update power status somehow */ | ||
377 | udelay(20000); | ||
378 | } | ||
379 | |||
380 | static void ch7017_dump_regs(struct intel_dvo_device *dvo) | ||
381 | { | ||
382 | uint8_t val; | ||
383 | |||
384 | #define DUMP(reg) \ | ||
385 | do { \ | ||
386 | ch7017_read(dvo, reg, &val); \ | ||
387 | DRM_DEBUG(#reg ": %02x\n", val); \ | ||
388 | } while (0) | ||
389 | |||
390 | DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT); | ||
391 | DUMP(CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT); | ||
392 | DUMP(CH7017_VERTICAL_ACTIVE_LINE_OUTPUT); | ||
393 | DUMP(CH7017_ACTIVE_INPUT_LINE_OUTPUT); | ||
394 | DUMP(CH7017_LVDS_PLL_VCO_CONTROL); | ||
395 | DUMP(CH7017_LVDS_PLL_FEEDBACK_DIV); | ||
396 | DUMP(CH7017_LVDS_CONTROL_2); | ||
397 | DUMP(CH7017_OUTPUTS_ENABLE); | ||
398 | DUMP(CH7017_LVDS_POWER_DOWN); | ||
399 | } | ||
400 | |||
401 | static void ch7017_save(struct intel_dvo_device *dvo) | ||
402 | { | ||
403 | struct ch7017_priv *priv = dvo->dev_priv; | ||
404 | |||
405 | ch7017_read(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, &priv->save_hapi); | ||
406 | ch7017_read(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, &priv->save_valo); | ||
407 | ch7017_read(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, &priv->save_ailo); | ||
408 | ch7017_read(dvo, CH7017_LVDS_PLL_VCO_CONTROL, &priv->save_lvds_pll_vco); | ||
409 | ch7017_read(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, &priv->save_feedback_div); | ||
410 | ch7017_read(dvo, CH7017_LVDS_CONTROL_2, &priv->save_lvds_control_2); | ||
411 | ch7017_read(dvo, CH7017_OUTPUTS_ENABLE, &priv->save_outputs_enable); | ||
412 | ch7017_read(dvo, CH7017_LVDS_POWER_DOWN, &priv->save_lvds_power_down); | ||
413 | ch7017_read(dvo, CH7017_POWER_MANAGEMENT, &priv->save_power_management); | ||
414 | } | ||
415 | |||
416 | static void ch7017_restore(struct intel_dvo_device *dvo) | ||
417 | { | ||
418 | struct ch7017_priv *priv = dvo->dev_priv; | ||
419 | |||
420 | /* Power down before changing mode */ | ||
421 | ch7017_dpms(dvo, DRM_MODE_DPMS_OFF); | ||
422 | |||
423 | ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, priv->save_hapi); | ||
424 | ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, priv->save_valo); | ||
425 | ch7017_write(dvo, CH7017_ACTIVE_INPUT_LINE_OUTPUT, priv->save_ailo); | ||
426 | ch7017_write(dvo, CH7017_LVDS_PLL_VCO_CONTROL, priv->save_lvds_pll_vco); | ||
427 | ch7017_write(dvo, CH7017_LVDS_PLL_FEEDBACK_DIV, priv->save_feedback_div); | ||
428 | ch7017_write(dvo, CH7017_LVDS_CONTROL_2, priv->save_lvds_control_2); | ||
429 | ch7017_write(dvo, CH7017_OUTPUTS_ENABLE, priv->save_outputs_enable); | ||
430 | ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, priv->save_lvds_power_down); | ||
431 | ch7017_write(dvo, CH7017_POWER_MANAGEMENT, priv->save_power_management); | ||
432 | } | ||
433 | |||
434 | static void ch7017_destroy(struct intel_dvo_device *dvo) | ||
435 | { | ||
436 | struct ch7017_priv *priv = dvo->dev_priv; | ||
437 | |||
438 | if (priv) { | ||
439 | kfree(priv); | ||
440 | dvo->dev_priv = NULL; | ||
441 | } | ||
442 | } | ||
443 | |||
444 | struct intel_dvo_dev_ops ch7017_ops = { | ||
445 | .init = ch7017_init, | ||
446 | .detect = ch7017_detect, | ||
447 | .mode_valid = ch7017_mode_valid, | ||
448 | .mode_set = ch7017_mode_set, | ||
449 | .dpms = ch7017_dpms, | ||
450 | .dump_regs = ch7017_dump_regs, | ||
451 | .save = ch7017_save, | ||
452 | .restore = ch7017_restore, | ||
453 | .destroy = ch7017_destroy, | ||
454 | }; | ||
diff --git a/drivers/gpu/drm/i915/dvo_ch7xxx.c b/drivers/gpu/drm/i915/dvo_ch7xxx.c new file mode 100644 index 000000000000..d2fd95dbd034 --- /dev/null +++ b/drivers/gpu/drm/i915/dvo_ch7xxx.c | |||
@@ -0,0 +1,368 @@ | |||
1 | /************************************************************************** | ||
2 | |||
3 | Copyright © 2006 Dave Airlie | ||
4 | |||
5 | All Rights Reserved. | ||
6 | |||
7 | Permission is hereby granted, free of charge, to any person obtaining a | ||
8 | copy of this software and associated documentation files (the | ||
9 | "Software"), to deal in the Software without restriction, including | ||
10 | without limitation the rights to use, copy, modify, merge, publish, | ||
11 | distribute, sub license, and/or sell copies of the Software, and to | ||
12 | permit persons to whom the Software is furnished to do so, subject to | ||
13 | the following conditions: | ||
14 | |||
15 | The above copyright notice and this permission notice (including the | ||
16 | next paragraph) shall be included in all copies or substantial portions | ||
17 | of the Software. | ||
18 | |||
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
20 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. | ||
22 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
23 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
24 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
25 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
26 | |||
27 | **************************************************************************/ | ||
28 | |||
29 | #include "dvo.h" | ||
30 | |||
31 | #define CH7xxx_REG_VID 0x4a | ||
32 | #define CH7xxx_REG_DID 0x4b | ||
33 | |||
34 | #define CH7011_VID 0x83 /* 7010 as well */ | ||
35 | #define CH7009A_VID 0x84 | ||
36 | #define CH7009B_VID 0x85 | ||
37 | #define CH7301_VID 0x95 | ||
38 | |||
39 | #define CH7xxx_VID 0x84 | ||
40 | #define CH7xxx_DID 0x17 | ||
41 | |||
42 | #define CH7xxx_NUM_REGS 0x4c | ||
43 | |||
44 | #define CH7xxx_CM 0x1c | ||
45 | #define CH7xxx_CM_XCM (1<<0) | ||
46 | #define CH7xxx_CM_MCP (1<<2) | ||
47 | #define CH7xxx_INPUT_CLOCK 0x1d | ||
48 | #define CH7xxx_GPIO 0x1e | ||
49 | #define CH7xxx_GPIO_HPIR (1<<3) | ||
50 | #define CH7xxx_IDF 0x1f | ||
51 | |||
52 | #define CH7xxx_IDF_HSP (1<<3) | ||
53 | #define CH7xxx_IDF_VSP (1<<4) | ||
54 | |||
55 | #define CH7xxx_CONNECTION_DETECT 0x20 | ||
56 | #define CH7xxx_CDET_DVI (1<<5) | ||
57 | |||
58 | #define CH7301_DAC_CNTL 0x21 | ||
59 | #define CH7301_HOTPLUG 0x23 | ||
60 | #define CH7xxx_TCTL 0x31 | ||
61 | #define CH7xxx_TVCO 0x32 | ||
62 | #define CH7xxx_TPCP 0x33 | ||
63 | #define CH7xxx_TPD 0x34 | ||
64 | #define CH7xxx_TPVT 0x35 | ||
65 | #define CH7xxx_TLPF 0x36 | ||
66 | #define CH7xxx_TCT 0x37 | ||
67 | #define CH7301_TEST_PATTERN 0x48 | ||
68 | |||
69 | #define CH7xxx_PM 0x49 | ||
70 | #define CH7xxx_PM_FPD (1<<0) | ||
71 | #define CH7301_PM_DACPD0 (1<<1) | ||
72 | #define CH7301_PM_DACPD1 (1<<2) | ||
73 | #define CH7301_PM_DACPD2 (1<<3) | ||
74 | #define CH7xxx_PM_DVIL (1<<6) | ||
75 | #define CH7xxx_PM_DVIP (1<<7) | ||
76 | |||
77 | #define CH7301_SYNC_POLARITY 0x56 | ||
78 | #define CH7301_SYNC_RGB_YUV (1<<0) | ||
79 | #define CH7301_SYNC_POL_DVI (1<<5) | ||
80 | |||
81 | /** @file | ||
82 | * driver for the Chrontel 7xxx DVI chip over DVO. | ||
83 | */ | ||
84 | |||
85 | static struct ch7xxx_id_struct { | ||
86 | uint8_t vid; | ||
87 | char *name; | ||
88 | } ch7xxx_ids[] = { | ||
89 | { CH7011_VID, "CH7011" }, | ||
90 | { CH7009A_VID, "CH7009A" }, | ||
91 | { CH7009B_VID, "CH7009B" }, | ||
92 | { CH7301_VID, "CH7301" }, | ||
93 | }; | ||
94 | |||
95 | struct ch7xxx_reg_state { | ||
96 | uint8_t regs[CH7xxx_NUM_REGS]; | ||
97 | }; | ||
98 | |||
99 | struct ch7xxx_priv { | ||
100 | bool quiet; | ||
101 | |||
102 | struct ch7xxx_reg_state save_reg; | ||
103 | struct ch7xxx_reg_state mode_reg; | ||
104 | uint8_t save_TCTL, save_TPCP, save_TPD, save_TPVT; | ||
105 | uint8_t save_TLPF, save_TCT, save_PM, save_IDF; | ||
106 | }; | ||
107 | |||
108 | static void ch7xxx_save(struct intel_dvo_device *dvo); | ||
109 | |||
110 | static char *ch7xxx_get_id(uint8_t vid) | ||
111 | { | ||
112 | int i; | ||
113 | |||
114 | for (i = 0; i < ARRAY_SIZE(ch7xxx_ids); i++) { | ||
115 | if (ch7xxx_ids[i].vid == vid) | ||
116 | return ch7xxx_ids[i].name; | ||
117 | } | ||
118 | |||
119 | return NULL; | ||
120 | } | ||
121 | |||
122 | /** Reads an 8 bit register */ | ||
123 | static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) | ||
124 | { | ||
125 | struct ch7xxx_priv *ch7xxx= dvo->dev_priv; | ||
126 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
127 | u8 out_buf[2]; | ||
128 | u8 in_buf[2]; | ||
129 | |||
130 | struct i2c_msg msgs[] = { | ||
131 | { | ||
132 | .addr = i2cbus->slave_addr, | ||
133 | .flags = 0, | ||
134 | .len = 1, | ||
135 | .buf = out_buf, | ||
136 | }, | ||
137 | { | ||
138 | .addr = i2cbus->slave_addr, | ||
139 | .flags = I2C_M_RD, | ||
140 | .len = 1, | ||
141 | .buf = in_buf, | ||
142 | } | ||
143 | }; | ||
144 | |||
145 | out_buf[0] = addr; | ||
146 | out_buf[1] = 0; | ||
147 | |||
148 | if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { | ||
149 | *ch = in_buf[0]; | ||
150 | return true; | ||
151 | }; | ||
152 | |||
153 | if (!ch7xxx->quiet) { | ||
154 | DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n", | ||
155 | addr, i2cbus->adapter.name, i2cbus->slave_addr); | ||
156 | } | ||
157 | return false; | ||
158 | } | ||
159 | |||
160 | /** Writes an 8 bit register */ | ||
161 | static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) | ||
162 | { | ||
163 | struct ch7xxx_priv *ch7xxx = dvo->dev_priv; | ||
164 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
165 | uint8_t out_buf[2]; | ||
166 | struct i2c_msg msg = { | ||
167 | .addr = i2cbus->slave_addr, | ||
168 | .flags = 0, | ||
169 | .len = 2, | ||
170 | .buf = out_buf, | ||
171 | }; | ||
172 | |||
173 | out_buf[0] = addr; | ||
174 | out_buf[1] = ch; | ||
175 | |||
176 | if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) | ||
177 | return true; | ||
178 | |||
179 | if (!ch7xxx->quiet) { | ||
180 | DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n", | ||
181 | addr, i2cbus->adapter.name, i2cbus->slave_addr); | ||
182 | } | ||
183 | |||
184 | return false; | ||
185 | } | ||
186 | |||
187 | static bool ch7xxx_init(struct intel_dvo_device *dvo, | ||
188 | struct intel_i2c_chan *i2cbus) | ||
189 | { | ||
190 | /* this will detect the CH7xxx chip on the specified i2c bus */ | ||
191 | struct ch7xxx_priv *ch7xxx; | ||
192 | uint8_t vendor, device; | ||
193 | char *name; | ||
194 | |||
195 | ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL); | ||
196 | if (ch7xxx == NULL) | ||
197 | return false; | ||
198 | |||
199 | dvo->i2c_bus = i2cbus; | ||
200 | dvo->i2c_bus->slave_addr = dvo->slave_addr; | ||
201 | dvo->dev_priv = ch7xxx; | ||
202 | ch7xxx->quiet = true; | ||
203 | |||
204 | if (!ch7xxx_readb(dvo, CH7xxx_REG_VID, &vendor)) | ||
205 | goto out; | ||
206 | |||
207 | name = ch7xxx_get_id(vendor); | ||
208 | if (!name) { | ||
209 | DRM_DEBUG("ch7xxx not detected; got 0x%02x from %s slave %d.\n", | ||
210 | vendor, i2cbus->adapter.name, i2cbus->slave_addr); | ||
211 | goto out; | ||
212 | } | ||
213 | |||
214 | |||
215 | if (!ch7xxx_readb(dvo, CH7xxx_REG_DID, &device)) | ||
216 | goto out; | ||
217 | |||
218 | if (device != CH7xxx_DID) { | ||
219 | DRM_DEBUG("ch7xxx not detected; got 0x%02x from %s slave %d.\n", | ||
220 | vendor, i2cbus->adapter.name, i2cbus->slave_addr); | ||
221 | goto out; | ||
222 | } | ||
223 | |||
224 | ch7xxx->quiet = false; | ||
225 | DRM_DEBUG("Detected %s chipset, vendor/device ID 0x%02x/0x%02x\n", | ||
226 | name, vendor, device); | ||
227 | return true; | ||
228 | out: | ||
229 | kfree(ch7xxx); | ||
230 | return false; | ||
231 | } | ||
232 | |||
233 | static enum drm_connector_status ch7xxx_detect(struct intel_dvo_device *dvo) | ||
234 | { | ||
235 | uint8_t cdet, orig_pm, pm; | ||
236 | |||
237 | ch7xxx_readb(dvo, CH7xxx_PM, &orig_pm); | ||
238 | |||
239 | pm = orig_pm; | ||
240 | pm &= ~CH7xxx_PM_FPD; | ||
241 | pm |= CH7xxx_PM_DVIL | CH7xxx_PM_DVIP; | ||
242 | |||
243 | ch7xxx_writeb(dvo, CH7xxx_PM, pm); | ||
244 | |||
245 | ch7xxx_readb(dvo, CH7xxx_CONNECTION_DETECT, &cdet); | ||
246 | |||
247 | ch7xxx_writeb(dvo, CH7xxx_PM, orig_pm); | ||
248 | |||
249 | if (cdet & CH7xxx_CDET_DVI) | ||
250 | return connector_status_connected; | ||
251 | return connector_status_disconnected; | ||
252 | } | ||
253 | |||
254 | static enum drm_mode_status ch7xxx_mode_valid(struct intel_dvo_device *dvo, | ||
255 | struct drm_display_mode *mode) | ||
256 | { | ||
257 | if (mode->clock > 165000) | ||
258 | return MODE_CLOCK_HIGH; | ||
259 | |||
260 | return MODE_OK; | ||
261 | } | ||
262 | |||
263 | static void ch7xxx_mode_set(struct intel_dvo_device *dvo, | ||
264 | struct drm_display_mode *mode, | ||
265 | struct drm_display_mode *adjusted_mode) | ||
266 | { | ||
267 | uint8_t tvco, tpcp, tpd, tlpf, idf; | ||
268 | |||
269 | if (mode->clock <= 65000) { | ||
270 | tvco = 0x23; | ||
271 | tpcp = 0x08; | ||
272 | tpd = 0x16; | ||
273 | tlpf = 0x60; | ||
274 | } else { | ||
275 | tvco = 0x2d; | ||
276 | tpcp = 0x06; | ||
277 | tpd = 0x26; | ||
278 | tlpf = 0xa0; | ||
279 | } | ||
280 | |||
281 | ch7xxx_writeb(dvo, CH7xxx_TCTL, 0x00); | ||
282 | ch7xxx_writeb(dvo, CH7xxx_TVCO, tvco); | ||
283 | ch7xxx_writeb(dvo, CH7xxx_TPCP, tpcp); | ||
284 | ch7xxx_writeb(dvo, CH7xxx_TPD, tpd); | ||
285 | ch7xxx_writeb(dvo, CH7xxx_TPVT, 0x30); | ||
286 | ch7xxx_writeb(dvo, CH7xxx_TLPF, tlpf); | ||
287 | ch7xxx_writeb(dvo, CH7xxx_TCT, 0x00); | ||
288 | |||
289 | ch7xxx_readb(dvo, CH7xxx_IDF, &idf); | ||
290 | |||
291 | idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP); | ||
292 | if (mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
293 | idf |= CH7xxx_IDF_HSP; | ||
294 | |||
295 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
296 | idf |= CH7xxx_IDF_HSP; | ||
297 | |||
298 | ch7xxx_writeb(dvo, CH7xxx_IDF, idf); | ||
299 | } | ||
300 | |||
301 | /* set the CH7xxx power state */ | ||
302 | static void ch7xxx_dpms(struct intel_dvo_device *dvo, int mode) | ||
303 | { | ||
304 | if (mode == DRM_MODE_DPMS_ON) | ||
305 | ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP); | ||
306 | else | ||
307 | ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD); | ||
308 | } | ||
309 | |||
310 | static void ch7xxx_dump_regs(struct intel_dvo_device *dvo) | ||
311 | { | ||
312 | struct ch7xxx_priv *ch7xxx = dvo->dev_priv; | ||
313 | int i; | ||
314 | |||
315 | for (i = 0; i < CH7xxx_NUM_REGS; i++) { | ||
316 | if ((i % 8) == 0 ) | ||
317 | DRM_DEBUG("\n %02X: ", i); | ||
318 | DRM_DEBUG("%02X ", ch7xxx->mode_reg.regs[i]); | ||
319 | } | ||
320 | } | ||
321 | |||
322 | static void ch7xxx_save(struct intel_dvo_device *dvo) | ||
323 | { | ||
324 | struct ch7xxx_priv *ch7xxx= dvo->dev_priv; | ||
325 | |||
326 | ch7xxx_readb(dvo, CH7xxx_TCTL, &ch7xxx->save_TCTL); | ||
327 | ch7xxx_readb(dvo, CH7xxx_TPCP, &ch7xxx->save_TPCP); | ||
328 | ch7xxx_readb(dvo, CH7xxx_TPD, &ch7xxx->save_TPD); | ||
329 | ch7xxx_readb(dvo, CH7xxx_TPVT, &ch7xxx->save_TPVT); | ||
330 | ch7xxx_readb(dvo, CH7xxx_TLPF, &ch7xxx->save_TLPF); | ||
331 | ch7xxx_readb(dvo, CH7xxx_PM, &ch7xxx->save_PM); | ||
332 | ch7xxx_readb(dvo, CH7xxx_IDF, &ch7xxx->save_IDF); | ||
333 | } | ||
334 | |||
335 | static void ch7xxx_restore(struct intel_dvo_device *dvo) | ||
336 | { | ||
337 | struct ch7xxx_priv *ch7xxx = dvo->dev_priv; | ||
338 | |||
339 | ch7xxx_writeb(dvo, CH7xxx_TCTL, ch7xxx->save_TCTL); | ||
340 | ch7xxx_writeb(dvo, CH7xxx_TPCP, ch7xxx->save_TPCP); | ||
341 | ch7xxx_writeb(dvo, CH7xxx_TPD, ch7xxx->save_TPD); | ||
342 | ch7xxx_writeb(dvo, CH7xxx_TPVT, ch7xxx->save_TPVT); | ||
343 | ch7xxx_writeb(dvo, CH7xxx_TLPF, ch7xxx->save_TLPF); | ||
344 | ch7xxx_writeb(dvo, CH7xxx_IDF, ch7xxx->save_IDF); | ||
345 | ch7xxx_writeb(dvo, CH7xxx_PM, ch7xxx->save_PM); | ||
346 | } | ||
347 | |||
348 | static void ch7xxx_destroy(struct intel_dvo_device *dvo) | ||
349 | { | ||
350 | struct ch7xxx_priv *ch7xxx = dvo->dev_priv; | ||
351 | |||
352 | if (ch7xxx) { | ||
353 | kfree(ch7xxx); | ||
354 | dvo->dev_priv = NULL; | ||
355 | } | ||
356 | } | ||
357 | |||
358 | struct intel_dvo_dev_ops ch7xxx_ops = { | ||
359 | .init = ch7xxx_init, | ||
360 | .detect = ch7xxx_detect, | ||
361 | .mode_valid = ch7xxx_mode_valid, | ||
362 | .mode_set = ch7xxx_mode_set, | ||
363 | .dpms = ch7xxx_dpms, | ||
364 | .dump_regs = ch7xxx_dump_regs, | ||
365 | .save = ch7xxx_save, | ||
366 | .restore = ch7xxx_restore, | ||
367 | .destroy = ch7xxx_destroy, | ||
368 | }; | ||
diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c new file mode 100644 index 000000000000..0c8d375e8e37 --- /dev/null +++ b/drivers/gpu/drm/i915/dvo_ivch.c | |||
@@ -0,0 +1,442 @@ | |||
1 | /* | ||
2 | * Copyright © 2006 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Eric Anholt <eric@anholt.net> | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include "dvo.h" | ||
29 | |||
30 | /* | ||
31 | * register definitions for the i82807aa. | ||
32 | * | ||
33 | * Documentation on this chipset can be found in datasheet #29069001 at | ||
34 | * intel.com. | ||
35 | */ | ||
36 | |||
37 | /* | ||
38 | * VCH Revision & GMBus Base Addr | ||
39 | */ | ||
40 | #define VR00 0x00 | ||
41 | # define VR00_BASE_ADDRESS_MASK 0x007f | ||
42 | |||
43 | /* | ||
44 | * Functionality Enable | ||
45 | */ | ||
46 | #define VR01 0x01 | ||
47 | |||
48 | /* | ||
49 | * Enable the panel fitter | ||
50 | */ | ||
51 | # define VR01_PANEL_FIT_ENABLE (1 << 3) | ||
52 | /* | ||
53 | * Enables the LCD display. | ||
54 | * | ||
55 | * This must not be set while VR01_DVO_BYPASS_ENABLE is set. | ||
56 | */ | ||
57 | # define VR01_LCD_ENABLE (1 << 2) | ||
58 | /** Enables the DVO repeater. */ | ||
59 | # define VR01_DVO_BYPASS_ENABLE (1 << 1) | ||
60 | /** Enables the DVO clock */ | ||
61 | # define VR01_DVO_ENABLE (1 << 0) | ||
62 | |||
63 | /* | ||
64 | * LCD Interface Format | ||
65 | */ | ||
66 | #define VR10 0x10 | ||
67 | /** Enables LVDS output instead of CMOS */ | ||
68 | # define VR10_LVDS_ENABLE (1 << 4) | ||
69 | /** Enables 18-bit LVDS output. */ | ||
70 | # define VR10_INTERFACE_1X18 (0 << 2) | ||
71 | /** Enables 24-bit LVDS or CMOS output */ | ||
72 | # define VR10_INTERFACE_1X24 (1 << 2) | ||
73 | /** Enables 2x18-bit LVDS or CMOS output. */ | ||
74 | # define VR10_INTERFACE_2X18 (2 << 2) | ||
75 | /** Enables 2x24-bit LVDS output */ | ||
76 | # define VR10_INTERFACE_2X24 (3 << 2) | ||
77 | |||
78 | /* | ||
79 | * VR20 LCD Horizontal Display Size | ||
80 | */ | ||
81 | #define VR20 0x20 | ||
82 | |||
83 | /* | ||
84 | * LCD Vertical Display Size | ||
85 | */ | ||
86 | #define VR21 0x20 | ||
87 | |||
88 | /* | ||
89 | * Panel power down status | ||
90 | */ | ||
91 | #define VR30 0x30 | ||
92 | /** Read only bit indicating that the panel is not in a safe poweroff state. */ | ||
93 | # define VR30_PANEL_ON (1 << 15) | ||
94 | |||
95 | #define VR40 0x40 | ||
96 | # define VR40_STALL_ENABLE (1 << 13) | ||
97 | # define VR40_VERTICAL_INTERP_ENABLE (1 << 12) | ||
98 | # define VR40_ENHANCED_PANEL_FITTING (1 << 11) | ||
99 | # define VR40_HORIZONTAL_INTERP_ENABLE (1 << 10) | ||
100 | # define VR40_AUTO_RATIO_ENABLE (1 << 9) | ||
101 | # define VR40_CLOCK_GATING_ENABLE (1 << 8) | ||
102 | |||
103 | /* | ||
104 | * Panel Fitting Vertical Ratio | ||
105 | * (((image_height - 1) << 16) / ((panel_height - 1))) >> 2 | ||
106 | */ | ||
107 | #define VR41 0x41 | ||
108 | |||
109 | /* | ||
110 | * Panel Fitting Horizontal Ratio | ||
111 | * (((image_width - 1) << 16) / ((panel_width - 1))) >> 2 | ||
112 | */ | ||
113 | #define VR42 0x42 | ||
114 | |||
115 | /* | ||
116 | * Horizontal Image Size | ||
117 | */ | ||
118 | #define VR43 0x43 | ||
119 | |||
120 | /* VR80 GPIO 0 | ||
121 | */ | ||
122 | #define VR80 0x80 | ||
123 | #define VR81 0x81 | ||
124 | #define VR82 0x82 | ||
125 | #define VR83 0x83 | ||
126 | #define VR84 0x84 | ||
127 | #define VR85 0x85 | ||
128 | #define VR86 0x86 | ||
129 | #define VR87 0x87 | ||
130 | |||
131 | /* VR88 GPIO 8 | ||
132 | */ | ||
133 | #define VR88 0x88 | ||
134 | |||
135 | /* Graphics BIOS scratch 0 | ||
136 | */ | ||
137 | #define VR8E 0x8E | ||
138 | # define VR8E_PANEL_TYPE_MASK (0xf << 0) | ||
139 | # define VR8E_PANEL_INTERFACE_CMOS (0 << 4) | ||
140 | # define VR8E_PANEL_INTERFACE_LVDS (1 << 4) | ||
141 | # define VR8E_FORCE_DEFAULT_PANEL (1 << 5) | ||
142 | |||
143 | /* Graphics BIOS scratch 1 | ||
144 | */ | ||
145 | #define VR8F 0x8F | ||
146 | # define VR8F_VCH_PRESENT (1 << 0) | ||
147 | # define VR8F_DISPLAY_CONN (1 << 1) | ||
148 | # define VR8F_POWER_MASK (0x3c) | ||
149 | # define VR8F_POWER_POS (2) | ||
150 | |||
151 | |||
152 | struct ivch_priv { | ||
153 | bool quiet; | ||
154 | |||
155 | uint16_t width, height; | ||
156 | |||
157 | uint16_t save_VR01; | ||
158 | uint16_t save_VR40; | ||
159 | }; | ||
160 | |||
161 | |||
162 | static void ivch_dump_regs(struct intel_dvo_device *dvo); | ||
163 | |||
164 | /** | ||
165 | * Reads a register on the ivch. | ||
166 | * | ||
167 | * Each of the 256 registers are 16 bits long. | ||
168 | */ | ||
169 | static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data) | ||
170 | { | ||
171 | struct ivch_priv *priv = dvo->dev_priv; | ||
172 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
173 | u8 out_buf[1]; | ||
174 | u8 in_buf[2]; | ||
175 | |||
176 | struct i2c_msg msgs[] = { | ||
177 | { | ||
178 | .addr = i2cbus->slave_addr, | ||
179 | .flags = I2C_M_RD, | ||
180 | .len = 0, | ||
181 | }, | ||
182 | { | ||
183 | .addr = 0, | ||
184 | .flags = I2C_M_NOSTART, | ||
185 | .len = 1, | ||
186 | .buf = out_buf, | ||
187 | }, | ||
188 | { | ||
189 | .addr = i2cbus->slave_addr, | ||
190 | .flags = I2C_M_RD | I2C_M_NOSTART, | ||
191 | .len = 2, | ||
192 | .buf = in_buf, | ||
193 | } | ||
194 | }; | ||
195 | |||
196 | out_buf[0] = addr; | ||
197 | |||
198 | if (i2c_transfer(&i2cbus->adapter, msgs, 3) == 3) { | ||
199 | *data = (in_buf[1] << 8) | in_buf[0]; | ||
200 | return true; | ||
201 | }; | ||
202 | |||
203 | if (!priv->quiet) { | ||
204 | DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n", | ||
205 | addr, i2cbus->adapter.name, i2cbus->slave_addr); | ||
206 | } | ||
207 | return false; | ||
208 | } | ||
209 | |||
210 | /** Writes a 16-bit register on the ivch */ | ||
211 | static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data) | ||
212 | { | ||
213 | struct ivch_priv *priv = dvo->dev_priv; | ||
214 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
215 | u8 out_buf[3]; | ||
216 | struct i2c_msg msg = { | ||
217 | .addr = i2cbus->slave_addr, | ||
218 | .flags = 0, | ||
219 | .len = 3, | ||
220 | .buf = out_buf, | ||
221 | }; | ||
222 | |||
223 | out_buf[0] = addr; | ||
224 | out_buf[1] = data & 0xff; | ||
225 | out_buf[2] = data >> 8; | ||
226 | |||
227 | if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) | ||
228 | return true; | ||
229 | |||
230 | if (!priv->quiet) { | ||
231 | DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n", | ||
232 | addr, i2cbus->adapter.name, i2cbus->slave_addr); | ||
233 | } | ||
234 | |||
235 | return false; | ||
236 | } | ||
237 | |||
238 | /** Probes the given bus and slave address for an ivch */ | ||
239 | static bool ivch_init(struct intel_dvo_device *dvo, | ||
240 | struct intel_i2c_chan *i2cbus) | ||
241 | { | ||
242 | struct ivch_priv *priv; | ||
243 | uint16_t temp; | ||
244 | |||
245 | priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL); | ||
246 | if (priv == NULL) | ||
247 | return false; | ||
248 | |||
249 | dvo->i2c_bus = i2cbus; | ||
250 | dvo->i2c_bus->slave_addr = dvo->slave_addr; | ||
251 | dvo->dev_priv = priv; | ||
252 | priv->quiet = true; | ||
253 | |||
254 | if (!ivch_read(dvo, VR00, &temp)) | ||
255 | goto out; | ||
256 | priv->quiet = false; | ||
257 | |||
258 | /* Since the identification bits are probably zeroes, which doesn't seem | ||
259 | * very unique, check that the value in the base address field matches | ||
260 | * the address it's responding on. | ||
261 | */ | ||
262 | if ((temp & VR00_BASE_ADDRESS_MASK) != dvo->slave_addr) { | ||
263 | DRM_DEBUG("ivch detect failed due to address mismatch " | ||
264 | "(%d vs %d)\n", | ||
265 | (temp & VR00_BASE_ADDRESS_MASK), dvo->slave_addr); | ||
266 | goto out; | ||
267 | } | ||
268 | |||
269 | ivch_read(dvo, VR20, &priv->width); | ||
270 | ivch_read(dvo, VR21, &priv->height); | ||
271 | |||
272 | return true; | ||
273 | |||
274 | out: | ||
275 | kfree(priv); | ||
276 | return false; | ||
277 | } | ||
278 | |||
279 | static enum drm_connector_status ivch_detect(struct intel_dvo_device *dvo) | ||
280 | { | ||
281 | return connector_status_connected; | ||
282 | } | ||
283 | |||
284 | static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo, | ||
285 | struct drm_display_mode *mode) | ||
286 | { | ||
287 | if (mode->clock > 112000) | ||
288 | return MODE_CLOCK_HIGH; | ||
289 | |||
290 | return MODE_OK; | ||
291 | } | ||
292 | |||
293 | /** Sets the power state of the panel connected to the ivch */ | ||
294 | static void ivch_dpms(struct intel_dvo_device *dvo, int mode) | ||
295 | { | ||
296 | int i; | ||
297 | uint16_t vr01, vr30, backlight; | ||
298 | |||
299 | /* Set the new power state of the panel. */ | ||
300 | if (!ivch_read(dvo, VR01, &vr01)) | ||
301 | return; | ||
302 | |||
303 | if (mode == DRM_MODE_DPMS_ON) | ||
304 | backlight = 1; | ||
305 | else | ||
306 | backlight = 0; | ||
307 | ivch_write(dvo, VR80, backlight); | ||
308 | |||
309 | if (mode == DRM_MODE_DPMS_ON) | ||
310 | vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE; | ||
311 | else | ||
312 | vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE); | ||
313 | |||
314 | ivch_write(dvo, VR01, vr01); | ||
315 | |||
316 | /* Wait for the panel to make its state transition */ | ||
317 | for (i = 0; i < 100; i++) { | ||
318 | if (!ivch_read(dvo, VR30, &vr30)) | ||
319 | break; | ||
320 | |||
321 | if (((vr30 & VR30_PANEL_ON) != 0) == (mode == DRM_MODE_DPMS_ON)) | ||
322 | break; | ||
323 | udelay(1000); | ||
324 | } | ||
325 | /* wait some more; vch may fail to resync sometimes without this */ | ||
326 | udelay(16 * 1000); | ||
327 | } | ||
328 | |||
329 | static void ivch_mode_set(struct intel_dvo_device *dvo, | ||
330 | struct drm_display_mode *mode, | ||
331 | struct drm_display_mode *adjusted_mode) | ||
332 | { | ||
333 | uint16_t vr40 = 0; | ||
334 | uint16_t vr01; | ||
335 | |||
336 | vr01 = 0; | ||
337 | vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE | | ||
338 | VR40_HORIZONTAL_INTERP_ENABLE); | ||
339 | |||
340 | if (mode->hdisplay != adjusted_mode->hdisplay || | ||
341 | mode->vdisplay != adjusted_mode->vdisplay) { | ||
342 | uint16_t x_ratio, y_ratio; | ||
343 | |||
344 | vr01 |= VR01_PANEL_FIT_ENABLE; | ||
345 | vr40 |= VR40_CLOCK_GATING_ENABLE; | ||
346 | x_ratio = (((mode->hdisplay - 1) << 16) / | ||
347 | (adjusted_mode->hdisplay - 1)) >> 2; | ||
348 | y_ratio = (((mode->vdisplay - 1) << 16) / | ||
349 | (adjusted_mode->vdisplay - 1)) >> 2; | ||
350 | ivch_write (dvo, VR42, x_ratio); | ||
351 | ivch_write (dvo, VR41, y_ratio); | ||
352 | } else { | ||
353 | vr01 &= ~VR01_PANEL_FIT_ENABLE; | ||
354 | vr40 &= ~VR40_CLOCK_GATING_ENABLE; | ||
355 | } | ||
356 | vr40 &= ~VR40_AUTO_RATIO_ENABLE; | ||
357 | |||
358 | ivch_write(dvo, VR01, vr01); | ||
359 | ivch_write(dvo, VR40, vr40); | ||
360 | |||
361 | ivch_dump_regs(dvo); | ||
362 | } | ||
363 | |||
364 | static void ivch_dump_regs(struct intel_dvo_device *dvo) | ||
365 | { | ||
366 | uint16_t val; | ||
367 | |||
368 | ivch_read(dvo, VR00, &val); | ||
369 | DRM_DEBUG("VR00: 0x%04x\n", val); | ||
370 | ivch_read(dvo, VR01, &val); | ||
371 | DRM_DEBUG("VR01: 0x%04x\n", val); | ||
372 | ivch_read(dvo, VR30, &val); | ||
373 | DRM_DEBUG("VR30: 0x%04x\n", val); | ||
374 | ivch_read(dvo, VR40, &val); | ||
375 | DRM_DEBUG("VR40: 0x%04x\n", val); | ||
376 | |||
377 | /* GPIO registers */ | ||
378 | ivch_read(dvo, VR80, &val); | ||
379 | DRM_DEBUG("VR80: 0x%04x\n", val); | ||
380 | ivch_read(dvo, VR81, &val); | ||
381 | DRM_DEBUG("VR81: 0x%04x\n", val); | ||
382 | ivch_read(dvo, VR82, &val); | ||
383 | DRM_DEBUG("VR82: 0x%04x\n", val); | ||
384 | ivch_read(dvo, VR83, &val); | ||
385 | DRM_DEBUG("VR83: 0x%04x\n", val); | ||
386 | ivch_read(dvo, VR84, &val); | ||
387 | DRM_DEBUG("VR84: 0x%04x\n", val); | ||
388 | ivch_read(dvo, VR85, &val); | ||
389 | DRM_DEBUG("VR85: 0x%04x\n", val); | ||
390 | ivch_read(dvo, VR86, &val); | ||
391 | DRM_DEBUG("VR86: 0x%04x\n", val); | ||
392 | ivch_read(dvo, VR87, &val); | ||
393 | DRM_DEBUG("VR87: 0x%04x\n", val); | ||
394 | ivch_read(dvo, VR88, &val); | ||
395 | DRM_DEBUG("VR88: 0x%04x\n", val); | ||
396 | |||
397 | /* Scratch register 0 - AIM Panel type */ | ||
398 | ivch_read(dvo, VR8E, &val); | ||
399 | DRM_DEBUG("VR8E: 0x%04x\n", val); | ||
400 | |||
401 | /* Scratch register 1 - Status register */ | ||
402 | ivch_read(dvo, VR8F, &val); | ||
403 | DRM_DEBUG("VR8F: 0x%04x\n", val); | ||
404 | } | ||
405 | |||
406 | static void ivch_save(struct intel_dvo_device *dvo) | ||
407 | { | ||
408 | struct ivch_priv *priv = dvo->dev_priv; | ||
409 | |||
410 | ivch_read(dvo, VR01, &priv->save_VR01); | ||
411 | ivch_read(dvo, VR40, &priv->save_VR40); | ||
412 | } | ||
413 | |||
414 | static void ivch_restore(struct intel_dvo_device *dvo) | ||
415 | { | ||
416 | struct ivch_priv *priv = dvo->dev_priv; | ||
417 | |||
418 | ivch_write(dvo, VR01, priv->save_VR01); | ||
419 | ivch_write(dvo, VR40, priv->save_VR40); | ||
420 | } | ||
421 | |||
422 | static void ivch_destroy(struct intel_dvo_device *dvo) | ||
423 | { | ||
424 | struct ivch_priv *priv = dvo->dev_priv; | ||
425 | |||
426 | if (priv) { | ||
427 | kfree(priv); | ||
428 | dvo->dev_priv = NULL; | ||
429 | } | ||
430 | } | ||
431 | |||
432 | struct intel_dvo_dev_ops ivch_ops= { | ||
433 | .init = ivch_init, | ||
434 | .dpms = ivch_dpms, | ||
435 | .save = ivch_save, | ||
436 | .restore = ivch_restore, | ||
437 | .mode_valid = ivch_mode_valid, | ||
438 | .mode_set = ivch_mode_set, | ||
439 | .detect = ivch_detect, | ||
440 | .dump_regs = ivch_dump_regs, | ||
441 | .destroy = ivch_destroy, | ||
442 | }; | ||
diff --git a/drivers/gpu/drm/i915/dvo_sil164.c b/drivers/gpu/drm/i915/dvo_sil164.c new file mode 100644 index 000000000000..033a4bb070b2 --- /dev/null +++ b/drivers/gpu/drm/i915/dvo_sil164.c | |||
@@ -0,0 +1,302 @@ | |||
1 | /************************************************************************** | ||
2 | |||
3 | Copyright © 2006 Dave Airlie | ||
4 | |||
5 | All Rights Reserved. | ||
6 | |||
7 | Permission is hereby granted, free of charge, to any person obtaining a | ||
8 | copy of this software and associated documentation files (the | ||
9 | "Software"), to deal in the Software without restriction, including | ||
10 | without limitation the rights to use, copy, modify, merge, publish, | ||
11 | distribute, sub license, and/or sell copies of the Software, and to | ||
12 | permit persons to whom the Software is furnished to do so, subject to | ||
13 | the following conditions: | ||
14 | |||
15 | The above copyright notice and this permission notice (including the | ||
16 | next paragraph) shall be included in all copies or substantial portions | ||
17 | of the Software. | ||
18 | |||
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||
20 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. | ||
22 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
23 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
24 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
25 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
26 | |||
27 | **************************************************************************/ | ||
28 | |||
29 | #include "dvo.h" | ||
30 | |||
31 | #define SIL164_VID 0x0001 | ||
32 | #define SIL164_DID 0x0006 | ||
33 | |||
34 | #define SIL164_VID_LO 0x00 | ||
35 | #define SIL164_VID_HI 0x01 | ||
36 | #define SIL164_DID_LO 0x02 | ||
37 | #define SIL164_DID_HI 0x03 | ||
38 | #define SIL164_REV 0x04 | ||
39 | #define SIL164_RSVD 0x05 | ||
40 | #define SIL164_FREQ_LO 0x06 | ||
41 | #define SIL164_FREQ_HI 0x07 | ||
42 | |||
43 | #define SIL164_REG8 0x08 | ||
44 | #define SIL164_8_VEN (1<<5) | ||
45 | #define SIL164_8_HEN (1<<4) | ||
46 | #define SIL164_8_DSEL (1<<3) | ||
47 | #define SIL164_8_BSEL (1<<2) | ||
48 | #define SIL164_8_EDGE (1<<1) | ||
49 | #define SIL164_8_PD (1<<0) | ||
50 | |||
51 | #define SIL164_REG9 0x09 | ||
52 | #define SIL164_9_VLOW (1<<7) | ||
53 | #define SIL164_9_MSEL_MASK (0x7<<4) | ||
54 | #define SIL164_9_TSEL (1<<3) | ||
55 | #define SIL164_9_RSEN (1<<2) | ||
56 | #define SIL164_9_HTPLG (1<<1) | ||
57 | #define SIL164_9_MDI (1<<0) | ||
58 | |||
59 | #define SIL164_REGC 0x0c | ||
60 | |||
61 | struct sil164_save_rec { | ||
62 | uint8_t reg8; | ||
63 | uint8_t reg9; | ||
64 | uint8_t regc; | ||
65 | }; | ||
66 | |||
67 | struct sil164_priv { | ||
68 | //I2CDevRec d; | ||
69 | bool quiet; | ||
70 | struct sil164_save_rec save_regs; | ||
71 | struct sil164_save_rec mode_regs; | ||
72 | }; | ||
73 | |||
74 | #define SILPTR(d) ((SIL164Ptr)(d->DriverPrivate.ptr)) | ||
75 | |||
76 | static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) | ||
77 | { | ||
78 | struct sil164_priv *sil = dvo->dev_priv; | ||
79 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
80 | u8 out_buf[2]; | ||
81 | u8 in_buf[2]; | ||
82 | |||
83 | struct i2c_msg msgs[] = { | ||
84 | { | ||
85 | .addr = i2cbus->slave_addr, | ||
86 | .flags = 0, | ||
87 | .len = 1, | ||
88 | .buf = out_buf, | ||
89 | }, | ||
90 | { | ||
91 | .addr = i2cbus->slave_addr, | ||
92 | .flags = I2C_M_RD, | ||
93 | .len = 1, | ||
94 | .buf = in_buf, | ||
95 | } | ||
96 | }; | ||
97 | |||
98 | out_buf[0] = addr; | ||
99 | out_buf[1] = 0; | ||
100 | |||
101 | if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { | ||
102 | *ch = in_buf[0]; | ||
103 | return true; | ||
104 | }; | ||
105 | |||
106 | if (!sil->quiet) { | ||
107 | DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n", | ||
108 | addr, i2cbus->adapter.name, i2cbus->slave_addr); | ||
109 | } | ||
110 | return false; | ||
111 | } | ||
112 | |||
113 | static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) | ||
114 | { | ||
115 | struct sil164_priv *sil= dvo->dev_priv; | ||
116 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
117 | uint8_t out_buf[2]; | ||
118 | struct i2c_msg msg = { | ||
119 | .addr = i2cbus->slave_addr, | ||
120 | .flags = 0, | ||
121 | .len = 2, | ||
122 | .buf = out_buf, | ||
123 | }; | ||
124 | |||
125 | out_buf[0] = addr; | ||
126 | out_buf[1] = ch; | ||
127 | |||
128 | if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) | ||
129 | return true; | ||
130 | |||
131 | if (!sil->quiet) { | ||
132 | DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n", | ||
133 | addr, i2cbus->adapter.name, i2cbus->slave_addr); | ||
134 | } | ||
135 | |||
136 | return false; | ||
137 | } | ||
138 | |||
139 | /* Silicon Image 164 driver for chip on i2c bus */ | ||
140 | static bool sil164_init(struct intel_dvo_device *dvo, | ||
141 | struct intel_i2c_chan *i2cbus) | ||
142 | { | ||
143 | /* this will detect the SIL164 chip on the specified i2c bus */ | ||
144 | struct sil164_priv *sil; | ||
145 | unsigned char ch; | ||
146 | |||
147 | sil = kzalloc(sizeof(struct sil164_priv), GFP_KERNEL); | ||
148 | if (sil == NULL) | ||
149 | return false; | ||
150 | |||
151 | dvo->i2c_bus = i2cbus; | ||
152 | dvo->i2c_bus->slave_addr = dvo->slave_addr; | ||
153 | dvo->dev_priv = sil; | ||
154 | sil->quiet = true; | ||
155 | |||
156 | if (!sil164_readb(dvo, SIL164_VID_LO, &ch)) | ||
157 | goto out; | ||
158 | |||
159 | if (ch != (SIL164_VID & 0xff)) { | ||
160 | DRM_DEBUG("sil164 not detected got %d: from %s Slave %d.\n", | ||
161 | ch, i2cbus->adapter.name, i2cbus->slave_addr); | ||
162 | goto out; | ||
163 | } | ||
164 | |||
165 | if (!sil164_readb(dvo, SIL164_DID_LO, &ch)) | ||
166 | goto out; | ||
167 | |||
168 | if (ch != (SIL164_DID & 0xff)) { | ||
169 | DRM_DEBUG("sil164 not detected got %d: from %s Slave %d.\n", | ||
170 | ch, i2cbus->adapter.name, i2cbus->slave_addr); | ||
171 | goto out; | ||
172 | } | ||
173 | sil->quiet = false; | ||
174 | |||
175 | DRM_DEBUG("init sil164 dvo controller successfully!\n"); | ||
176 | return true; | ||
177 | |||
178 | out: | ||
179 | kfree(sil); | ||
180 | return false; | ||
181 | } | ||
182 | |||
183 | static enum drm_connector_status sil164_detect(struct intel_dvo_device *dvo) | ||
184 | { | ||
185 | uint8_t reg9; | ||
186 | |||
187 | sil164_readb(dvo, SIL164_REG9, ®9); | ||
188 | |||
189 | if (reg9 & SIL164_9_HTPLG) | ||
190 | return connector_status_connected; | ||
191 | else | ||
192 | return connector_status_disconnected; | ||
193 | } | ||
194 | |||
195 | static enum drm_mode_status sil164_mode_valid(struct intel_dvo_device *dvo, | ||
196 | struct drm_display_mode *mode) | ||
197 | { | ||
198 | return MODE_OK; | ||
199 | } | ||
200 | |||
201 | static void sil164_mode_set(struct intel_dvo_device *dvo, | ||
202 | struct drm_display_mode *mode, | ||
203 | struct drm_display_mode *adjusted_mode) | ||
204 | { | ||
205 | /* As long as the basics are set up, since we don't have clock | ||
206 | * dependencies in the mode setup, we can just leave the | ||
207 | * registers alone and everything will work fine. | ||
208 | */ | ||
209 | /* recommended programming sequence from doc */ | ||
210 | /*sil164_writeb(sil, 0x08, 0x30); | ||
211 | sil164_writeb(sil, 0x09, 0x00); | ||
212 | sil164_writeb(sil, 0x0a, 0x90); | ||
213 | sil164_writeb(sil, 0x0c, 0x89); | ||
214 | sil164_writeb(sil, 0x08, 0x31);*/ | ||
215 | /* don't do much */ | ||
216 | return; | ||
217 | } | ||
218 | |||
219 | /* set the SIL164 power state */ | ||
220 | static void sil164_dpms(struct intel_dvo_device *dvo, int mode) | ||
221 | { | ||
222 | int ret; | ||
223 | unsigned char ch; | ||
224 | |||
225 | ret = sil164_readb(dvo, SIL164_REG8, &ch); | ||
226 | if (ret == false) | ||
227 | return; | ||
228 | |||
229 | if (mode == DRM_MODE_DPMS_ON) | ||
230 | ch |= SIL164_8_PD; | ||
231 | else | ||
232 | ch &= ~SIL164_8_PD; | ||
233 | |||
234 | sil164_writeb(dvo, SIL164_REG8, ch); | ||
235 | return; | ||
236 | } | ||
237 | |||
238 | static void sil164_dump_regs(struct intel_dvo_device *dvo) | ||
239 | { | ||
240 | uint8_t val; | ||
241 | |||
242 | sil164_readb(dvo, SIL164_FREQ_LO, &val); | ||
243 | DRM_DEBUG("SIL164_FREQ_LO: 0x%02x\n", val); | ||
244 | sil164_readb(dvo, SIL164_FREQ_HI, &val); | ||
245 | DRM_DEBUG("SIL164_FREQ_HI: 0x%02x\n", val); | ||
246 | sil164_readb(dvo, SIL164_REG8, &val); | ||
247 | DRM_DEBUG("SIL164_REG8: 0x%02x\n", val); | ||
248 | sil164_readb(dvo, SIL164_REG9, &val); | ||
249 | DRM_DEBUG("SIL164_REG9: 0x%02x\n", val); | ||
250 | sil164_readb(dvo, SIL164_REGC, &val); | ||
251 | DRM_DEBUG("SIL164_REGC: 0x%02x\n", val); | ||
252 | } | ||
253 | |||
254 | static void sil164_save(struct intel_dvo_device *dvo) | ||
255 | { | ||
256 | struct sil164_priv *sil= dvo->dev_priv; | ||
257 | |||
258 | if (!sil164_readb(dvo, SIL164_REG8, &sil->save_regs.reg8)) | ||
259 | return; | ||
260 | |||
261 | if (!sil164_readb(dvo, SIL164_REG9, &sil->save_regs.reg9)) | ||
262 | return; | ||
263 | |||
264 | if (!sil164_readb(dvo, SIL164_REGC, &sil->save_regs.regc)) | ||
265 | return; | ||
266 | |||
267 | return; | ||
268 | } | ||
269 | |||
270 | static void sil164_restore(struct intel_dvo_device *dvo) | ||
271 | { | ||
272 | struct sil164_priv *sil = dvo->dev_priv; | ||
273 | |||
274 | /* Restore it powered down initially */ | ||
275 | sil164_writeb(dvo, SIL164_REG8, sil->save_regs.reg8 & ~0x1); | ||
276 | |||
277 | sil164_writeb(dvo, SIL164_REG9, sil->save_regs.reg9); | ||
278 | sil164_writeb(dvo, SIL164_REGC, sil->save_regs.regc); | ||
279 | sil164_writeb(dvo, SIL164_REG8, sil->save_regs.reg8); | ||
280 | } | ||
281 | |||
282 | static void sil164_destroy(struct intel_dvo_device *dvo) | ||
283 | { | ||
284 | struct sil164_priv *sil = dvo->dev_priv; | ||
285 | |||
286 | if (sil) { | ||
287 | kfree(sil); | ||
288 | dvo->dev_priv = NULL; | ||
289 | } | ||
290 | } | ||
291 | |||
292 | struct intel_dvo_dev_ops sil164_ops = { | ||
293 | .init = sil164_init, | ||
294 | .detect = sil164_detect, | ||
295 | .mode_valid = sil164_mode_valid, | ||
296 | .mode_set = sil164_mode_set, | ||
297 | .dpms = sil164_dpms, | ||
298 | .dump_regs = sil164_dump_regs, | ||
299 | .save = sil164_save, | ||
300 | .restore = sil164_restore, | ||
301 | .destroy = sil164_destroy, | ||
302 | }; | ||
diff --git a/drivers/gpu/drm/i915/dvo_tfp410.c b/drivers/gpu/drm/i915/dvo_tfp410.c new file mode 100644 index 000000000000..207fda806ebf --- /dev/null +++ b/drivers/gpu/drm/i915/dvo_tfp410.c | |||
@@ -0,0 +1,335 @@ | |||
1 | /* | ||
2 | * Copyright © 2007 Dave Mueller | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
21 | * IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Dave Mueller <dave.mueller@gmx.ch> | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include "dvo.h" | ||
29 | |||
30 | /* register definitions according to the TFP410 data sheet */ | ||
31 | #define TFP410_VID 0x014C | ||
32 | #define TFP410_DID 0x0410 | ||
33 | |||
34 | #define TFP410_VID_LO 0x00 | ||
35 | #define TFP410_VID_HI 0x01 | ||
36 | #define TFP410_DID_LO 0x02 | ||
37 | #define TFP410_DID_HI 0x03 | ||
38 | #define TFP410_REV 0x04 | ||
39 | |||
40 | #define TFP410_CTL_1 0x08 | ||
41 | #define TFP410_CTL_1_TDIS (1<<6) | ||
42 | #define TFP410_CTL_1_VEN (1<<5) | ||
43 | #define TFP410_CTL_1_HEN (1<<4) | ||
44 | #define TFP410_CTL_1_DSEL (1<<3) | ||
45 | #define TFP410_CTL_1_BSEL (1<<2) | ||
46 | #define TFP410_CTL_1_EDGE (1<<1) | ||
47 | #define TFP410_CTL_1_PD (1<<0) | ||
48 | |||
49 | #define TFP410_CTL_2 0x09 | ||
50 | #define TFP410_CTL_2_VLOW (1<<7) | ||
51 | #define TFP410_CTL_2_MSEL_MASK (0x7<<4) | ||
52 | #define TFP410_CTL_2_MSEL (1<<4) | ||
53 | #define TFP410_CTL_2_TSEL (1<<3) | ||
54 | #define TFP410_CTL_2_RSEN (1<<2) | ||
55 | #define TFP410_CTL_2_HTPLG (1<<1) | ||
56 | #define TFP410_CTL_2_MDI (1<<0) | ||
57 | |||
58 | #define TFP410_CTL_3 0x0A | ||
59 | #define TFP410_CTL_3_DK_MASK (0x7<<5) | ||
60 | #define TFP410_CTL_3_DK (1<<5) | ||
61 | #define TFP410_CTL_3_DKEN (1<<4) | ||
62 | #define TFP410_CTL_3_CTL_MASK (0x7<<1) | ||
63 | #define TFP410_CTL_3_CTL (1<<1) | ||
64 | |||
65 | #define TFP410_USERCFG 0x0B | ||
66 | |||
67 | #define TFP410_DE_DLY 0x32 | ||
68 | |||
69 | #define TFP410_DE_CTL 0x33 | ||
70 | #define TFP410_DE_CTL_DEGEN (1<<6) | ||
71 | #define TFP410_DE_CTL_VSPOL (1<<5) | ||
72 | #define TFP410_DE_CTL_HSPOL (1<<4) | ||
73 | #define TFP410_DE_CTL_DEDLY8 (1<<0) | ||
74 | |||
75 | #define TFP410_DE_TOP 0x34 | ||
76 | |||
77 | #define TFP410_DE_CNT_LO 0x36 | ||
78 | #define TFP410_DE_CNT_HI 0x37 | ||
79 | |||
80 | #define TFP410_DE_LIN_LO 0x38 | ||
81 | #define TFP410_DE_LIN_HI 0x39 | ||
82 | |||
83 | #define TFP410_H_RES_LO 0x3A | ||
84 | #define TFP410_H_RES_HI 0x3B | ||
85 | |||
86 | #define TFP410_V_RES_LO 0x3C | ||
87 | #define TFP410_V_RES_HI 0x3D | ||
88 | |||
89 | struct tfp410_save_rec { | ||
90 | uint8_t ctl1; | ||
91 | uint8_t ctl2; | ||
92 | }; | ||
93 | |||
94 | struct tfp410_priv { | ||
95 | bool quiet; | ||
96 | |||
97 | struct tfp410_save_rec saved_reg; | ||
98 | struct tfp410_save_rec mode_reg; | ||
99 | }; | ||
100 | |||
101 | static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch) | ||
102 | { | ||
103 | struct tfp410_priv *tfp = dvo->dev_priv; | ||
104 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
105 | u8 out_buf[2]; | ||
106 | u8 in_buf[2]; | ||
107 | |||
108 | struct i2c_msg msgs[] = { | ||
109 | { | ||
110 | .addr = i2cbus->slave_addr, | ||
111 | .flags = 0, | ||
112 | .len = 1, | ||
113 | .buf = out_buf, | ||
114 | }, | ||
115 | { | ||
116 | .addr = i2cbus->slave_addr, | ||
117 | .flags = I2C_M_RD, | ||
118 | .len = 1, | ||
119 | .buf = in_buf, | ||
120 | } | ||
121 | }; | ||
122 | |||
123 | out_buf[0] = addr; | ||
124 | out_buf[1] = 0; | ||
125 | |||
126 | if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) { | ||
127 | *ch = in_buf[0]; | ||
128 | return true; | ||
129 | }; | ||
130 | |||
131 | if (!tfp->quiet) { | ||
132 | DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n", | ||
133 | addr, i2cbus->adapter.name, i2cbus->slave_addr); | ||
134 | } | ||
135 | return false; | ||
136 | } | ||
137 | |||
138 | static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch) | ||
139 | { | ||
140 | struct tfp410_priv *tfp = dvo->dev_priv; | ||
141 | struct intel_i2c_chan *i2cbus = dvo->i2c_bus; | ||
142 | uint8_t out_buf[2]; | ||
143 | struct i2c_msg msg = { | ||
144 | .addr = i2cbus->slave_addr, | ||
145 | .flags = 0, | ||
146 | .len = 2, | ||
147 | .buf = out_buf, | ||
148 | }; | ||
149 | |||
150 | out_buf[0] = addr; | ||
151 | out_buf[1] = ch; | ||
152 | |||
153 | if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1) | ||
154 | return true; | ||
155 | |||
156 | if (!tfp->quiet) { | ||
157 | DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n", | ||
158 | addr, i2cbus->adapter.name, i2cbus->slave_addr); | ||
159 | } | ||
160 | |||
161 | return false; | ||
162 | } | ||
163 | |||
164 | static int tfp410_getid(struct intel_dvo_device *dvo, int addr) | ||
165 | { | ||
166 | uint8_t ch1, ch2; | ||
167 | |||
168 | if (tfp410_readb(dvo, addr+0, &ch1) && | ||
169 | tfp410_readb(dvo, addr+1, &ch2)) | ||
170 | return ((ch2 << 8) & 0xFF00) | (ch1 & 0x00FF); | ||
171 | |||
172 | return -1; | ||
173 | } | ||
174 | |||
175 | /* Ti TFP410 driver for chip on i2c bus */ | ||
176 | static bool tfp410_init(struct intel_dvo_device *dvo, | ||
177 | struct intel_i2c_chan *i2cbus) | ||
178 | { | ||
179 | /* this will detect the tfp410 chip on the specified i2c bus */ | ||
180 | struct tfp410_priv *tfp; | ||
181 | int id; | ||
182 | |||
183 | tfp = kzalloc(sizeof(struct tfp410_priv), GFP_KERNEL); | ||
184 | if (tfp == NULL) | ||
185 | return false; | ||
186 | |||
187 | dvo->i2c_bus = i2cbus; | ||
188 | dvo->i2c_bus->slave_addr = dvo->slave_addr; | ||
189 | dvo->dev_priv = tfp; | ||
190 | tfp->quiet = true; | ||
191 | |||
192 | if ((id = tfp410_getid(dvo, TFP410_VID_LO)) != TFP410_VID) { | ||
193 | DRM_DEBUG("tfp410 not detected got VID %X: from %s Slave %d.\n", | ||
194 | id, i2cbus->adapter.name, i2cbus->slave_addr); | ||
195 | goto out; | ||
196 | } | ||
197 | |||
198 | if ((id = tfp410_getid(dvo, TFP410_DID_LO)) != TFP410_DID) { | ||
199 | DRM_DEBUG("tfp410 not detected got DID %X: from %s Slave %d.\n", | ||
200 | id, i2cbus->adapter.name, i2cbus->slave_addr); | ||
201 | goto out; | ||
202 | } | ||
203 | tfp->quiet = false; | ||
204 | return true; | ||
205 | out: | ||
206 | kfree(tfp); | ||
207 | return false; | ||
208 | } | ||
209 | |||
210 | static enum drm_connector_status tfp410_detect(struct intel_dvo_device *dvo) | ||
211 | { | ||
212 | enum drm_connector_status ret = connector_status_disconnected; | ||
213 | uint8_t ctl2; | ||
214 | |||
215 | if (tfp410_readb(dvo, TFP410_CTL_2, &ctl2)) { | ||
216 | if (ctl2 & TFP410_CTL_2_HTPLG) | ||
217 | ret = connector_status_connected; | ||
218 | else | ||
219 | ret = connector_status_disconnected; | ||
220 | } | ||
221 | |||
222 | return ret; | ||
223 | } | ||
224 | |||
225 | static enum drm_mode_status tfp410_mode_valid(struct intel_dvo_device *dvo, | ||
226 | struct drm_display_mode *mode) | ||
227 | { | ||
228 | return MODE_OK; | ||
229 | } | ||
230 | |||
231 | static void tfp410_mode_set(struct intel_dvo_device *dvo, | ||
232 | struct drm_display_mode *mode, | ||
233 | struct drm_display_mode *adjusted_mode) | ||
234 | { | ||
235 | /* As long as the basics are set up, since we don't have clock dependencies | ||
236 | * in the mode setup, we can just leave the registers alone and everything | ||
237 | * will work fine. | ||
238 | */ | ||
239 | /* don't do much */ | ||
240 | return; | ||
241 | } | ||
242 | |||
243 | /* set the tfp410 power state */ | ||
244 | static void tfp410_dpms(struct intel_dvo_device *dvo, int mode) | ||
245 | { | ||
246 | uint8_t ctl1; | ||
247 | |||
248 | if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1)) | ||
249 | return; | ||
250 | |||
251 | if (mode == DRM_MODE_DPMS_ON) | ||
252 | ctl1 |= TFP410_CTL_1_PD; | ||
253 | else | ||
254 | ctl1 &= ~TFP410_CTL_1_PD; | ||
255 | |||
256 | tfp410_writeb(dvo, TFP410_CTL_1, ctl1); | ||
257 | } | ||
258 | |||
259 | static void tfp410_dump_regs(struct intel_dvo_device *dvo) | ||
260 | { | ||
261 | uint8_t val, val2; | ||
262 | |||
263 | tfp410_readb(dvo, TFP410_REV, &val); | ||
264 | DRM_DEBUG("TFP410_REV: 0x%02X\n", val); | ||
265 | tfp410_readb(dvo, TFP410_CTL_1, &val); | ||
266 | DRM_DEBUG("TFP410_CTL1: 0x%02X\n", val); | ||
267 | tfp410_readb(dvo, TFP410_CTL_2, &val); | ||
268 | DRM_DEBUG("TFP410_CTL2: 0x%02X\n", val); | ||
269 | tfp410_readb(dvo, TFP410_CTL_3, &val); | ||
270 | DRM_DEBUG("TFP410_CTL3: 0x%02X\n", val); | ||
271 | tfp410_readb(dvo, TFP410_USERCFG, &val); | ||
272 | DRM_DEBUG("TFP410_USERCFG: 0x%02X\n", val); | ||
273 | tfp410_readb(dvo, TFP410_DE_DLY, &val); | ||
274 | DRM_DEBUG("TFP410_DE_DLY: 0x%02X\n", val); | ||
275 | tfp410_readb(dvo, TFP410_DE_CTL, &val); | ||
276 | DRM_DEBUG("TFP410_DE_CTL: 0x%02X\n", val); | ||
277 | tfp410_readb(dvo, TFP410_DE_TOP, &val); | ||
278 | DRM_DEBUG("TFP410_DE_TOP: 0x%02X\n", val); | ||
279 | tfp410_readb(dvo, TFP410_DE_CNT_LO, &val); | ||
280 | tfp410_readb(dvo, TFP410_DE_CNT_HI, &val2); | ||
281 | DRM_DEBUG("TFP410_DE_CNT: 0x%02X%02X\n", val2, val); | ||
282 | tfp410_readb(dvo, TFP410_DE_LIN_LO, &val); | ||
283 | tfp410_readb(dvo, TFP410_DE_LIN_HI, &val2); | ||
284 | DRM_DEBUG("TFP410_DE_LIN: 0x%02X%02X\n", val2, val); | ||
285 | tfp410_readb(dvo, TFP410_H_RES_LO, &val); | ||
286 | tfp410_readb(dvo, TFP410_H_RES_HI, &val2); | ||
287 | DRM_DEBUG("TFP410_H_RES: 0x%02X%02X\n", val2, val); | ||
288 | tfp410_readb(dvo, TFP410_V_RES_LO, &val); | ||
289 | tfp410_readb(dvo, TFP410_V_RES_HI, &val2); | ||
290 | DRM_DEBUG("TFP410_V_RES: 0x%02X%02X\n", val2, val); | ||
291 | } | ||
292 | |||
293 | static void tfp410_save(struct intel_dvo_device *dvo) | ||
294 | { | ||
295 | struct tfp410_priv *tfp = dvo->dev_priv; | ||
296 | |||
297 | if (!tfp410_readb(dvo, TFP410_CTL_1, &tfp->saved_reg.ctl1)) | ||
298 | return; | ||
299 | |||
300 | if (!tfp410_readb(dvo, TFP410_CTL_2, &tfp->saved_reg.ctl2)) | ||
301 | return; | ||
302 | } | ||
303 | |||
304 | static void tfp410_restore(struct intel_dvo_device *dvo) | ||
305 | { | ||
306 | struct tfp410_priv *tfp = dvo->dev_priv; | ||
307 | |||
308 | /* Restore it powered down initially */ | ||
309 | tfp410_writeb(dvo, TFP410_CTL_1, tfp->saved_reg.ctl1 & ~0x1); | ||
310 | |||
311 | tfp410_writeb(dvo, TFP410_CTL_2, tfp->saved_reg.ctl2); | ||
312 | tfp410_writeb(dvo, TFP410_CTL_1, tfp->saved_reg.ctl1); | ||
313 | } | ||
314 | |||
315 | static void tfp410_destroy(struct intel_dvo_device *dvo) | ||
316 | { | ||
317 | struct tfp410_priv *tfp = dvo->dev_priv; | ||
318 | |||
319 | if (tfp) { | ||
320 | kfree(tfp); | ||
321 | dvo->dev_priv = NULL; | ||
322 | } | ||
323 | } | ||
324 | |||
325 | struct intel_dvo_dev_ops tfp410_ops = { | ||
326 | .init = tfp410_init, | ||
327 | .detect = tfp410_detect, | ||
328 | .mode_valid = tfp410_mode_valid, | ||
329 | .mode_set = tfp410_mode_set, | ||
330 | .dpms = tfp410_dpms, | ||
331 | .dump_regs = tfp410_dump_regs, | ||
332 | .save = tfp410_save, | ||
333 | .restore = tfp410_restore, | ||
334 | .destroy = tfp410_destroy, | ||
335 | }; | ||
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 1b81b6a6d81b..b5d0809eecb1 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c | |||
@@ -28,6 +28,8 @@ | |||
28 | 28 | ||
29 | #include "drmP.h" | 29 | #include "drmP.h" |
30 | #include "drm.h" | 30 | #include "drm.h" |
31 | #include "drm_crtc_helper.h" | ||
32 | #include "intel_drv.h" | ||
31 | #include "i915_drm.h" | 33 | #include "i915_drm.h" |
32 | #include "i915_drv.h" | 34 | #include "i915_drv.h" |
33 | 35 | ||
@@ -125,6 +127,13 @@ void i915_kernel_lost_context(struct drm_device * dev) | |||
125 | struct drm_i915_master_private *master_priv; | 127 | struct drm_i915_master_private *master_priv; |
126 | drm_i915_ring_buffer_t *ring = &(dev_priv->ring); | 128 | drm_i915_ring_buffer_t *ring = &(dev_priv->ring); |
127 | 129 | ||
130 | /* | ||
131 | * We should never lose context on the ring with modesetting | ||
132 | * as we don't expose it to userspace | ||
133 | */ | ||
134 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
135 | return; | ||
136 | |||
128 | ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; | 137 | ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; |
129 | ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; | 138 | ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; |
130 | ring->space = ring->head - (ring->tail + 8); | 139 | ring->space = ring->head - (ring->tail + 8); |
@@ -769,6 +778,11 @@ static int i915_set_status_page(struct drm_device *dev, void *data, | |||
769 | return -EINVAL; | 778 | return -EINVAL; |
770 | } | 779 | } |
771 | 780 | ||
781 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
782 | WARN(1, "tried to set status page when mode setting active\n"); | ||
783 | return 0; | ||
784 | } | ||
785 | |||
772 | printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws->addr); | 786 | printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws->addr); |
773 | 787 | ||
774 | dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12); | 788 | dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12); |
@@ -797,6 +811,173 @@ static int i915_set_status_page(struct drm_device *dev, void *data, | |||
797 | return 0; | 811 | return 0; |
798 | } | 812 | } |
799 | 813 | ||
814 | /** | ||
815 | * i915_probe_agp - get AGP bootup configuration | ||
816 | * @pdev: PCI device | ||
817 | * @aperture_size: returns AGP aperture configured size | ||
818 | * @preallocated_size: returns size of BIOS preallocated AGP space | ||
819 | * | ||
820 | * Since Intel integrated graphics are UMA, the BIOS has to set aside | ||
821 | * some RAM for the framebuffer at early boot. This code figures out | ||
822 | * how much was set aside so we can use it for our own purposes. | ||
823 | */ | ||
824 | int i915_probe_agp(struct pci_dev *pdev, unsigned long *aperture_size, | ||
825 | unsigned long *preallocated_size) | ||
826 | { | ||
827 | struct pci_dev *bridge_dev; | ||
828 | u16 tmp = 0; | ||
829 | unsigned long overhead; | ||
830 | |||
831 | bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); | ||
832 | if (!bridge_dev) { | ||
833 | DRM_ERROR("bridge device not found\n"); | ||
834 | return -1; | ||
835 | } | ||
836 | |||
837 | /* Get the fb aperture size and "stolen" memory amount. */ | ||
838 | pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp); | ||
839 | pci_dev_put(bridge_dev); | ||
840 | |||
841 | *aperture_size = 1024 * 1024; | ||
842 | *preallocated_size = 1024 * 1024; | ||
843 | |||
844 | switch (pdev->device) { | ||
845 | case PCI_DEVICE_ID_INTEL_82830_CGC: | ||
846 | case PCI_DEVICE_ID_INTEL_82845G_IG: | ||
847 | case PCI_DEVICE_ID_INTEL_82855GM_IG: | ||
848 | case PCI_DEVICE_ID_INTEL_82865_IG: | ||
849 | if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M) | ||
850 | *aperture_size *= 64; | ||
851 | else | ||
852 | *aperture_size *= 128; | ||
853 | break; | ||
854 | default: | ||
855 | /* 9xx supports large sizes, just look at the length */ | ||
856 | *aperture_size = pci_resource_len(pdev, 2); | ||
857 | break; | ||
858 | } | ||
859 | |||
860 | /* | ||
861 | * Some of the preallocated space is taken by the GTT | ||
862 | * and popup. GTT is 1K per MB of aperture size, and popup is 4K. | ||
863 | */ | ||
864 | overhead = (*aperture_size / 1024) + 4096; | ||
865 | switch (tmp & INTEL_855_GMCH_GMS_MASK) { | ||
866 | case INTEL_855_GMCH_GMS_STOLEN_1M: | ||
867 | break; /* 1M already */ | ||
868 | case INTEL_855_GMCH_GMS_STOLEN_4M: | ||
869 | *preallocated_size *= 4; | ||
870 | break; | ||
871 | case INTEL_855_GMCH_GMS_STOLEN_8M: | ||
872 | *preallocated_size *= 8; | ||
873 | break; | ||
874 | case INTEL_855_GMCH_GMS_STOLEN_16M: | ||
875 | *preallocated_size *= 16; | ||
876 | break; | ||
877 | case INTEL_855_GMCH_GMS_STOLEN_32M: | ||
878 | *preallocated_size *= 32; | ||
879 | break; | ||
880 | case INTEL_915G_GMCH_GMS_STOLEN_48M: | ||
881 | *preallocated_size *= 48; | ||
882 | break; | ||
883 | case INTEL_915G_GMCH_GMS_STOLEN_64M: | ||
884 | *preallocated_size *= 64; | ||
885 | break; | ||
886 | case INTEL_855_GMCH_GMS_DISABLED: | ||
887 | DRM_ERROR("video memory is disabled\n"); | ||
888 | return -1; | ||
889 | default: | ||
890 | DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n", | ||
891 | tmp & INTEL_855_GMCH_GMS_MASK); | ||
892 | return -1; | ||
893 | } | ||
894 | *preallocated_size -= overhead; | ||
895 | |||
896 | return 0; | ||
897 | } | ||
898 | |||
899 | static int i915_load_modeset_init(struct drm_device *dev) | ||
900 | { | ||
901 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
902 | unsigned long agp_size, prealloc_size; | ||
903 | int fb_bar = IS_I9XX(dev) ? 2 : 0; | ||
904 | int ret = 0; | ||
905 | |||
906 | dev->mode_config.fb_base = drm_get_resource_start(dev, fb_bar) & | ||
907 | 0xff000000; | ||
908 | |||
909 | DRM_DEBUG("*** fb base 0x%08lx\n", dev->mode_config.fb_base); | ||
910 | |||
911 | if (IS_MOBILE(dev) || (IS_I9XX(dev) && !IS_I965G(dev) && !IS_G33(dev))) | ||
912 | dev_priv->cursor_needs_physical = true; | ||
913 | else | ||
914 | dev_priv->cursor_needs_physical = false; | ||
915 | |||
916 | i915_probe_agp(dev->pdev, &agp_size, &prealloc_size); | ||
917 | |||
918 | /* Basic memrange allocator for stolen space (aka vram) */ | ||
919 | drm_mm_init(&dev_priv->vram, 0, prealloc_size); | ||
920 | |||
921 | /* Let GEM Manage from end of prealloc space to end of aperture */ | ||
922 | i915_gem_do_init(dev, prealloc_size, agp_size); | ||
923 | |||
924 | ret = i915_gem_init_ringbuffer(dev); | ||
925 | if (ret) | ||
926 | goto out; | ||
927 | |||
928 | dev_priv->mm.gtt_mapping = | ||
929 | io_mapping_create_wc(dev->agp->base, | ||
930 | dev->agp->agp_info.aper_size * 1024*1024); | ||
931 | |||
932 | /* Allow hardware batchbuffers unless told otherwise. | ||
933 | */ | ||
934 | dev_priv->allow_batchbuffer = 1; | ||
935 | |||
936 | ret = intel_init_bios(dev); | ||
937 | if (ret) | ||
938 | DRM_INFO("failed to find VBIOS tables\n"); | ||
939 | |||
940 | ret = drm_irq_install(dev); | ||
941 | if (ret) | ||
942 | goto destroy_ringbuffer; | ||
943 | |||
944 | /* FIXME: re-add hotplug support */ | ||
945 | #if 0 | ||
946 | ret = drm_hotplug_init(dev); | ||
947 | if (ret) | ||
948 | goto destroy_ringbuffer; | ||
949 | #endif | ||
950 | |||
951 | /* Always safe in the mode setting case. */ | ||
952 | /* FIXME: do pre/post-mode set stuff in core KMS code */ | ||
953 | dev->vblank_disable_allowed = 1; | ||
954 | |||
955 | /* | ||
956 | * Initialize the hardware status page IRQ location. | ||
957 | */ | ||
958 | |||
959 | I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); | ||
960 | |||
961 | intel_modeset_init(dev); | ||
962 | |||
963 | drm_helper_initial_config(dev, false); | ||
964 | |||
965 | dev->devname = kstrdup(DRIVER_NAME, GFP_KERNEL); | ||
966 | if (!dev->devname) { | ||
967 | ret = -ENOMEM; | ||
968 | goto modeset_cleanup; | ||
969 | } | ||
970 | |||
971 | return 0; | ||
972 | |||
973 | modeset_cleanup: | ||
974 | intel_modeset_cleanup(dev); | ||
975 | destroy_ringbuffer: | ||
976 | i915_gem_cleanup_ringbuffer(dev); | ||
977 | out: | ||
978 | return ret; | ||
979 | } | ||
980 | |||
800 | int i915_master_create(struct drm_device *dev, struct drm_master *master) | 981 | int i915_master_create(struct drm_device *dev, struct drm_master *master) |
801 | { | 982 | { |
802 | struct drm_i915_master_private *master_priv; | 983 | struct drm_i915_master_private *master_priv; |
@@ -821,6 +1002,25 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master) | |||
821 | master->driver_priv = NULL; | 1002 | master->driver_priv = NULL; |
822 | } | 1003 | } |
823 | 1004 | ||
1005 | |||
1006 | int i915_driver_firstopen(struct drm_device *dev) | ||
1007 | { | ||
1008 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
1009 | return 0; | ||
1010 | return 0; | ||
1011 | } | ||
1012 | |||
1013 | /** | ||
1014 | * i915_driver_load - setup chip and create an initial config | ||
1015 | * @dev: DRM device | ||
1016 | * @flags: startup flags | ||
1017 | * | ||
1018 | * The driver load routine has to do several things: | ||
1019 | * - drive output discovery via intel_modeset_init() | ||
1020 | * - initialize the memory manager | ||
1021 | * - allocate initial config memory | ||
1022 | * - setup the DRM framebuffer with the allocated memory | ||
1023 | */ | ||
824 | int i915_driver_load(struct drm_device *dev, unsigned long flags) | 1024 | int i915_driver_load(struct drm_device *dev, unsigned long flags) |
825 | { | 1025 | { |
826 | struct drm_i915_private *dev_priv = dev->dev_private; | 1026 | struct drm_i915_private *dev_priv = dev->dev_private; |
@@ -848,6 +1048,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
848 | size = drm_get_resource_len(dev, mmio_bar); | 1048 | size = drm_get_resource_len(dev, mmio_bar); |
849 | 1049 | ||
850 | dev_priv->regs = ioremap(base, size); | 1050 | dev_priv->regs = ioremap(base, size); |
1051 | if (!dev_priv->regs) { | ||
1052 | DRM_ERROR("failed to map registers\n"); | ||
1053 | ret = -EIO; | ||
1054 | goto free_priv; | ||
1055 | } | ||
851 | 1056 | ||
852 | #ifdef CONFIG_HIGHMEM64G | 1057 | #ifdef CONFIG_HIGHMEM64G |
853 | /* don't enable GEM on PAE - needs agp + set_memory_* interface fixes */ | 1058 | /* don't enable GEM on PAE - needs agp + set_memory_* interface fixes */ |
@@ -863,7 +1068,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
863 | if (!I915_NEED_GFX_HWS(dev)) { | 1068 | if (!I915_NEED_GFX_HWS(dev)) { |
864 | ret = i915_init_phys_hws(dev); | 1069 | ret = i915_init_phys_hws(dev); |
865 | if (ret != 0) | 1070 | if (ret != 0) |
866 | return ret; | 1071 | goto out_rmmap; |
867 | } | 1072 | } |
868 | 1073 | ||
869 | /* On the 945G/GM, the chipset reports the MSI capability on the | 1074 | /* On the 945G/GM, the chipset reports the MSI capability on the |
@@ -883,6 +1088,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
883 | intel_opregion_init(dev); | 1088 | intel_opregion_init(dev); |
884 | 1089 | ||
885 | spin_lock_init(&dev_priv->user_irq_lock); | 1090 | spin_lock_init(&dev_priv->user_irq_lock); |
1091 | dev_priv->user_irq_refcount = 0; | ||
886 | 1092 | ||
887 | ret = drm_vblank_init(dev, I915_NUM_PIPE); | 1093 | ret = drm_vblank_init(dev, I915_NUM_PIPE); |
888 | 1094 | ||
@@ -891,6 +1097,20 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
891 | return ret; | 1097 | return ret; |
892 | } | 1098 | } |
893 | 1099 | ||
1100 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
1101 | ret = i915_load_modeset_init(dev); | ||
1102 | if (ret < 0) { | ||
1103 | DRM_ERROR("failed to init modeset\n"); | ||
1104 | goto out_rmmap; | ||
1105 | } | ||
1106 | } | ||
1107 | |||
1108 | return 0; | ||
1109 | |||
1110 | out_rmmap: | ||
1111 | iounmap(dev_priv->regs); | ||
1112 | free_priv: | ||
1113 | drm_free(dev_priv, sizeof(struct drm_i915_private), DRM_MEM_DRIVER); | ||
894 | return ret; | 1114 | return ret; |
895 | } | 1115 | } |
896 | 1116 | ||
@@ -898,16 +1118,29 @@ int i915_driver_unload(struct drm_device *dev) | |||
898 | { | 1118 | { |
899 | struct drm_i915_private *dev_priv = dev->dev_private; | 1119 | struct drm_i915_private *dev_priv = dev->dev_private; |
900 | 1120 | ||
1121 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
1122 | io_mapping_free(dev_priv->mm.gtt_mapping); | ||
1123 | drm_irq_uninstall(dev); | ||
1124 | } | ||
1125 | |||
901 | if (dev->pdev->msi_enabled) | 1126 | if (dev->pdev->msi_enabled) |
902 | pci_disable_msi(dev->pdev); | 1127 | pci_disable_msi(dev->pdev); |
903 | 1128 | ||
904 | i915_free_hws(dev); | ||
905 | |||
906 | if (dev_priv->regs != NULL) | 1129 | if (dev_priv->regs != NULL) |
907 | iounmap(dev_priv->regs); | 1130 | iounmap(dev_priv->regs); |
908 | 1131 | ||
909 | intel_opregion_free(dev); | 1132 | intel_opregion_free(dev); |
910 | 1133 | ||
1134 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
1135 | intel_modeset_cleanup(dev); | ||
1136 | |||
1137 | mutex_lock(&dev->struct_mutex); | ||
1138 | i915_gem_cleanup_ringbuffer(dev); | ||
1139 | mutex_unlock(&dev->struct_mutex); | ||
1140 | drm_mm_takedown(&dev_priv->vram); | ||
1141 | i915_gem_lastclose(dev); | ||
1142 | } | ||
1143 | |||
911 | drm_free(dev->dev_private, sizeof(drm_i915_private_t), | 1144 | drm_free(dev->dev_private, sizeof(drm_i915_private_t), |
912 | DRM_MEM_DRIVER); | 1145 | DRM_MEM_DRIVER); |
913 | 1146 | ||
@@ -933,12 +1166,26 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv) | |||
933 | return 0; | 1166 | return 0; |
934 | } | 1167 | } |
935 | 1168 | ||
1169 | /** | ||
1170 | * i915_driver_lastclose - clean up after all DRM clients have exited | ||
1171 | * @dev: DRM device | ||
1172 | * | ||
1173 | * Take care of cleaning up after all DRM clients have exited. In the | ||
1174 | * mode setting case, we want to restore the kernel's initial mode (just | ||
1175 | * in case the last client left us in a bad state). | ||
1176 | * | ||
1177 | * Additionally, in the non-mode setting case, we'll tear down the AGP | ||
1178 | * and DMA structures, since the kernel won't be using them, and clea | ||
1179 | * up any GEM state. | ||
1180 | */ | ||
936 | void i915_driver_lastclose(struct drm_device * dev) | 1181 | void i915_driver_lastclose(struct drm_device * dev) |
937 | { | 1182 | { |
938 | drm_i915_private_t *dev_priv = dev->dev_private; | 1183 | drm_i915_private_t *dev_priv = dev->dev_private; |
939 | 1184 | ||
940 | if (!dev_priv) | 1185 | if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) { |
1186 | intelfb_restore(); | ||
941 | return; | 1187 | return; |
1188 | } | ||
942 | 1189 | ||
943 | i915_gem_lastclose(dev); | 1190 | i915_gem_lastclose(dev); |
944 | 1191 | ||
@@ -951,7 +1198,8 @@ void i915_driver_lastclose(struct drm_device * dev) | |||
951 | void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) | 1198 | void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) |
952 | { | 1199 | { |
953 | drm_i915_private_t *dev_priv = dev->dev_private; | 1200 | drm_i915_private_t *dev_priv = dev->dev_private; |
954 | i915_mem_release(dev, file_priv, dev_priv->agp_heap); | 1201 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
1202 | i915_mem_release(dev, file_priv, dev_priv->agp_heap); | ||
955 | } | 1203 | } |
956 | 1204 | ||
957 | void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) | 1205 | void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) |
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index e0d996ed9026..cbee41c32417 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
@@ -33,11 +33,22 @@ | |||
33 | #include "i915_drv.h" | 33 | #include "i915_drv.h" |
34 | 34 | ||
35 | #include "drm_pciids.h" | 35 | #include "drm_pciids.h" |
36 | #include <linux/console.h> | ||
37 | |||
38 | unsigned int i915_modeset = -1; | ||
39 | module_param_named(modeset, i915_modeset, int, 0400); | ||
40 | |||
41 | unsigned int i915_fbpercrtc = 0; | ||
42 | module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); | ||
36 | 43 | ||
37 | static struct pci_device_id pciidlist[] = { | 44 | static struct pci_device_id pciidlist[] = { |
38 | i915_PCI_IDS | 45 | i915_PCI_IDS |
39 | }; | 46 | }; |
40 | 47 | ||
48 | #if defined(CONFIG_DRM_I915_KMS) | ||
49 | MODULE_DEVICE_TABLE(pci, pciidlist); | ||
50 | #endif | ||
51 | |||
41 | static int i915_suspend(struct drm_device *dev, pm_message_t state) | 52 | static int i915_suspend(struct drm_device *dev, pm_message_t state) |
42 | { | 53 | { |
43 | struct drm_i915_private *dev_priv = dev->dev_private; | 54 | struct drm_i915_private *dev_priv = dev->dev_private; |
@@ -148,6 +159,28 @@ static struct drm_driver driver = { | |||
148 | static int __init i915_init(void) | 159 | static int __init i915_init(void) |
149 | { | 160 | { |
150 | driver.num_ioctls = i915_max_ioctl; | 161 | driver.num_ioctls = i915_max_ioctl; |
162 | |||
163 | /* | ||
164 | * If CONFIG_DRM_I915_KMS is set, default to KMS unless | ||
165 | * explicitly disabled with the module pararmeter. | ||
166 | * | ||
167 | * Otherwise, just follow the parameter (defaulting to off). | ||
168 | * | ||
169 | * Allow optional vga_text_mode_force boot option to override | ||
170 | * the default behavior. | ||
171 | */ | ||
172 | #if defined(CONFIG_DRM_I915_KMS) | ||
173 | if (i915_modeset != 0) | ||
174 | driver.driver_features |= DRIVER_MODESET; | ||
175 | #endif | ||
176 | if (i915_modeset == 1) | ||
177 | driver.driver_features |= DRIVER_MODESET; | ||
178 | |||
179 | #ifdef CONFIG_VGA_CONSOLE | ||
180 | if (vgacon_text_force() && i915_modeset == -1) | ||
181 | driver.driver_features &= ~DRIVER_MODESET; | ||
182 | #endif | ||
183 | |||
151 | return drm_init(&driver); | 184 | return drm_init(&driver); |
152 | } | 185 | } |
153 | 186 | ||
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 85a072e80637..6f18ee68d06a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -31,6 +31,7 @@ | |||
31 | #define _I915_DRV_H_ | 31 | #define _I915_DRV_H_ |
32 | 32 | ||
33 | #include "i915_reg.h" | 33 | #include "i915_reg.h" |
34 | #include "intel_bios.h" | ||
34 | #include <linux/io-mapping.h> | 35 | #include <linux/io-mapping.h> |
35 | 36 | ||
36 | /* General customization: | 37 | /* General customization: |
@@ -152,8 +153,26 @@ typedef struct drm_i915_private { | |||
152 | unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; | 153 | unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; |
153 | int vblank_pipe; | 154 | int vblank_pipe; |
154 | 155 | ||
156 | bool cursor_needs_physical; | ||
157 | |||
158 | struct drm_mm vram; | ||
159 | |||
160 | int irq_enabled; | ||
161 | |||
155 | struct intel_opregion opregion; | 162 | struct intel_opregion opregion; |
156 | 163 | ||
164 | /* LVDS info */ | ||
165 | int backlight_duty_cycle; /* restore backlight to this value */ | ||
166 | bool panel_wants_dither; | ||
167 | struct drm_display_mode *panel_fixed_mode; | ||
168 | struct drm_display_mode *vbt_mode; /* if any */ | ||
169 | |||
170 | /* Feature bits from the VBIOS */ | ||
171 | int int_tv_support:1; | ||
172 | int lvds_dither:1; | ||
173 | int lvds_vbt:1; | ||
174 | int int_crt_support:1; | ||
175 | |||
157 | struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */ | 176 | struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */ |
158 | int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */ | 177 | int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */ |
159 | int num_fence_regs; /* 8 on pre-965, 16 otherwise */ | 178 | int num_fence_regs; /* 8 on pre-965, 16 otherwise */ |
@@ -413,6 +432,10 @@ struct drm_i915_gem_object { | |||
413 | * flags which individual pages are valid. | 432 | * flags which individual pages are valid. |
414 | */ | 433 | */ |
415 | uint8_t *page_cpu_valid; | 434 | uint8_t *page_cpu_valid; |
435 | |||
436 | /** User space pin count and filp owning the pin */ | ||
437 | uint32_t user_pin_count; | ||
438 | struct drm_file *pin_filp; | ||
416 | }; | 439 | }; |
417 | 440 | ||
418 | /** | 441 | /** |
@@ -442,8 +465,16 @@ struct drm_i915_file_private { | |||
442 | } mm; | 465 | } mm; |
443 | }; | 466 | }; |
444 | 467 | ||
468 | enum intel_chip_family { | ||
469 | CHIP_I8XX = 0x01, | ||
470 | CHIP_I9XX = 0x02, | ||
471 | CHIP_I915 = 0x04, | ||
472 | CHIP_I965 = 0x08, | ||
473 | }; | ||
474 | |||
445 | extern struct drm_ioctl_desc i915_ioctls[]; | 475 | extern struct drm_ioctl_desc i915_ioctls[]; |
446 | extern int i915_max_ioctl; | 476 | extern int i915_max_ioctl; |
477 | extern unsigned int i915_fbpercrtc; | ||
447 | 478 | ||
448 | extern int i915_master_create(struct drm_device *dev, struct drm_master *master); | 479 | extern int i915_master_create(struct drm_device *dev, struct drm_master *master); |
449 | extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master); | 480 | extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master); |
@@ -472,6 +503,7 @@ extern int i915_irq_wait(struct drm_device *dev, void *data, | |||
472 | struct drm_file *file_priv); | 503 | struct drm_file *file_priv); |
473 | void i915_user_irq_get(struct drm_device *dev); | 504 | void i915_user_irq_get(struct drm_device *dev); |
474 | void i915_user_irq_put(struct drm_device *dev); | 505 | void i915_user_irq_put(struct drm_device *dev); |
506 | extern void i915_enable_interrupt (struct drm_device *dev); | ||
475 | 507 | ||
476 | extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); | 508 | extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); |
477 | extern void i915_driver_irq_preinstall(struct drm_device * dev); | 509 | extern void i915_driver_irq_preinstall(struct drm_device * dev); |
@@ -556,7 +588,16 @@ uint32_t i915_get_gem_seqno(struct drm_device *dev); | |||
556 | void i915_gem_retire_requests(struct drm_device *dev); | 588 | void i915_gem_retire_requests(struct drm_device *dev); |
557 | void i915_gem_retire_work_handler(struct work_struct *work); | 589 | void i915_gem_retire_work_handler(struct work_struct *work); |
558 | void i915_gem_clflush_object(struct drm_gem_object *obj); | 590 | void i915_gem_clflush_object(struct drm_gem_object *obj); |
591 | int i915_gem_object_set_domain(struct drm_gem_object *obj, | ||
592 | uint32_t read_domains, | ||
593 | uint32_t write_domain); | ||
594 | int i915_gem_init_ringbuffer(struct drm_device *dev); | ||
595 | void i915_gem_cleanup_ringbuffer(struct drm_device *dev); | ||
596 | int i915_gem_do_init(struct drm_device *dev, unsigned long start, | ||
597 | unsigned long end); | ||
559 | int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); | 598 | int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); |
599 | int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, | ||
600 | int write); | ||
560 | 601 | ||
561 | /* i915_gem_tiling.c */ | 602 | /* i915_gem_tiling.c */ |
562 | void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); | 603 | void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); |
@@ -595,6 +636,10 @@ static inline void opregion_asle_intr(struct drm_device *dev) { return; } | |||
595 | static inline void opregion_enable_asle(struct drm_device *dev) { return; } | 636 | static inline void opregion_enable_asle(struct drm_device *dev) { return; } |
596 | #endif | 637 | #endif |
597 | 638 | ||
639 | /* modesetting */ | ||
640 | extern void intel_modeset_init(struct drm_device *dev); | ||
641 | extern void intel_modeset_cleanup(struct drm_device *dev); | ||
642 | |||
598 | /** | 643 | /** |
599 | * Lock test for when it's just for synchronization of ring access. | 644 | * Lock test for when it's just for synchronization of ring access. |
600 | * | 645 | * |
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0ac977112f72..c4ccaf3b3c7f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include "i915_drm.h" | 30 | #include "i915_drm.h" |
31 | #include "i915_drv.h" | 31 | #include "i915_drv.h" |
32 | #include <linux/swap.h> | 32 | #include <linux/swap.h> |
33 | #include <linux/pci.h> | ||
33 | 34 | ||
34 | #define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) | 35 | #define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) |
35 | 36 | ||
@@ -40,8 +41,6 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj, | |||
40 | static void i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj); | 41 | static void i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj); |
41 | static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj); | 42 | static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj); |
42 | static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj); | 43 | static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj); |
43 | static int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, | ||
44 | int write); | ||
45 | static int i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, | 44 | static int i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, |
46 | int write); | 45 | int write); |
47 | static int i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, | 46 | static int i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, |
@@ -57,33 +56,37 @@ static void i915_gem_object_get_fence_reg(struct drm_gem_object *obj); | |||
57 | static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); | 56 | static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); |
58 | static int i915_gem_evict_something(struct drm_device *dev); | 57 | static int i915_gem_evict_something(struct drm_device *dev); |
59 | 58 | ||
60 | static void | 59 | int i915_gem_do_init(struct drm_device *dev, unsigned long start, |
61 | i915_gem_cleanup_ringbuffer(struct drm_device *dev); | 60 | unsigned long end) |
62 | |||
63 | int | ||
64 | i915_gem_init_ioctl(struct drm_device *dev, void *data, | ||
65 | struct drm_file *file_priv) | ||
66 | { | 61 | { |
67 | drm_i915_private_t *dev_priv = dev->dev_private; | 62 | drm_i915_private_t *dev_priv = dev->dev_private; |
68 | struct drm_i915_gem_init *args = data; | ||
69 | |||
70 | mutex_lock(&dev->struct_mutex); | ||
71 | 63 | ||
72 | if (args->gtt_start >= args->gtt_end || | 64 | if (start >= end || |
73 | (args->gtt_start & (PAGE_SIZE - 1)) != 0 || | 65 | (start & (PAGE_SIZE - 1)) != 0 || |
74 | (args->gtt_end & (PAGE_SIZE - 1)) != 0) { | 66 | (end & (PAGE_SIZE - 1)) != 0) { |
75 | mutex_unlock(&dev->struct_mutex); | ||
76 | return -EINVAL; | 67 | return -EINVAL; |
77 | } | 68 | } |
78 | 69 | ||
79 | drm_mm_init(&dev_priv->mm.gtt_space, args->gtt_start, | 70 | drm_mm_init(&dev_priv->mm.gtt_space, start, |
80 | args->gtt_end - args->gtt_start); | 71 | end - start); |
81 | 72 | ||
82 | dev->gtt_total = (uint32_t) (args->gtt_end - args->gtt_start); | 73 | dev->gtt_total = (uint32_t) (end - start); |
74 | |||
75 | return 0; | ||
76 | } | ||
83 | 77 | ||
78 | int | ||
79 | i915_gem_init_ioctl(struct drm_device *dev, void *data, | ||
80 | struct drm_file *file_priv) | ||
81 | { | ||
82 | struct drm_i915_gem_init *args = data; | ||
83 | int ret; | ||
84 | |||
85 | mutex_lock(&dev->struct_mutex); | ||
86 | ret = i915_gem_do_init(dev, args->gtt_start, args->gtt_end); | ||
84 | mutex_unlock(&dev->struct_mutex); | 87 | mutex_unlock(&dev->struct_mutex); |
85 | 88 | ||
86 | return 0; | 89 | return ret; |
87 | } | 90 | } |
88 | 91 | ||
89 | int | 92 | int |
@@ -1246,7 +1249,8 @@ i915_gem_object_unbind(struct drm_gem_object *obj) | |||
1246 | 1249 | ||
1247 | /* blow away mappings if mapped through GTT */ | 1250 | /* blow away mappings if mapped through GTT */ |
1248 | offset = ((loff_t) obj->map_list.hash.key) << PAGE_SHIFT; | 1251 | offset = ((loff_t) obj->map_list.hash.key) << PAGE_SHIFT; |
1249 | unmap_mapping_range(dev->dev_mapping, offset, obj->size, 1); | 1252 | if (dev->dev_mapping) |
1253 | unmap_mapping_range(dev->dev_mapping, offset, obj->size, 1); | ||
1250 | 1254 | ||
1251 | if (obj_priv->fence_reg != I915_FENCE_REG_NONE) | 1255 | if (obj_priv->fence_reg != I915_FENCE_REG_NONE) |
1252 | i915_gem_clear_fence_reg(obj); | 1256 | i915_gem_clear_fence_reg(obj); |
@@ -1508,7 +1512,7 @@ static void | |||
1508 | i915_gem_object_get_fence_reg(struct drm_gem_object *obj) | 1512 | i915_gem_object_get_fence_reg(struct drm_gem_object *obj) |
1509 | { | 1513 | { |
1510 | struct drm_device *dev = obj->dev; | 1514 | struct drm_device *dev = obj->dev; |
1511 | drm_i915_private_t *dev_priv = dev->dev_private; | 1515 | struct drm_i915_private *dev_priv = dev->dev_private; |
1512 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | 1516 | struct drm_i915_gem_object *obj_priv = obj->driver_private; |
1513 | struct drm_i915_fence_reg *reg = NULL; | 1517 | struct drm_i915_fence_reg *reg = NULL; |
1514 | int i, ret; | 1518 | int i, ret; |
@@ -1567,8 +1571,9 @@ try_again: | |||
1567 | * for this object next time we need it. | 1571 | * for this object next time we need it. |
1568 | */ | 1572 | */ |
1569 | offset = ((loff_t) reg->obj->map_list.hash.key) << PAGE_SHIFT; | 1573 | offset = ((loff_t) reg->obj->map_list.hash.key) << PAGE_SHIFT; |
1570 | unmap_mapping_range(dev->dev_mapping, offset, | 1574 | if (dev->dev_mapping) |
1571 | reg->obj->size, 1); | 1575 | unmap_mapping_range(dev->dev_mapping, offset, |
1576 | reg->obj->size, 1); | ||
1572 | old_obj_priv->fence_reg = I915_FENCE_REG_NONE; | 1577 | old_obj_priv->fence_reg = I915_FENCE_REG_NONE; |
1573 | } | 1578 | } |
1574 | 1579 | ||
@@ -1594,7 +1599,7 @@ static void | |||
1594 | i915_gem_clear_fence_reg(struct drm_gem_object *obj) | 1599 | i915_gem_clear_fence_reg(struct drm_gem_object *obj) |
1595 | { | 1600 | { |
1596 | struct drm_device *dev = obj->dev; | 1601 | struct drm_device *dev = obj->dev; |
1597 | struct drm_i915_private *dev_priv = dev->dev_private; | 1602 | drm_i915_private_t *dev_priv = dev->dev_private; |
1598 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | 1603 | struct drm_i915_gem_object *obj_priv = obj->driver_private; |
1599 | 1604 | ||
1600 | if (IS_I965G(dev)) | 1605 | if (IS_I965G(dev)) |
@@ -1764,7 +1769,7 @@ i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj) | |||
1764 | * This function returns when the move is complete, including waiting on | 1769 | * This function returns when the move is complete, including waiting on |
1765 | * flushes to occur. | 1770 | * flushes to occur. |
1766 | */ | 1771 | */ |
1767 | static int | 1772 | int |
1768 | i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) | 1773 | i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) |
1769 | { | 1774 | { |
1770 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | 1775 | struct drm_i915_gem_object *obj_priv = obj->driver_private; |
@@ -2706,11 +2711,22 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data, | |||
2706 | } | 2711 | } |
2707 | obj_priv = obj->driver_private; | 2712 | obj_priv = obj->driver_private; |
2708 | 2713 | ||
2709 | ret = i915_gem_object_pin(obj, args->alignment); | 2714 | if (obj_priv->pin_filp != NULL && obj_priv->pin_filp != file_priv) { |
2710 | if (ret != 0) { | 2715 | DRM_ERROR("Already pinned in i915_gem_pin_ioctl(): %d\n", |
2711 | drm_gem_object_unreference(obj); | 2716 | args->handle); |
2712 | mutex_unlock(&dev->struct_mutex); | 2717 | mutex_unlock(&dev->struct_mutex); |
2713 | return ret; | 2718 | return -EINVAL; |
2719 | } | ||
2720 | |||
2721 | obj_priv->user_pin_count++; | ||
2722 | obj_priv->pin_filp = file_priv; | ||
2723 | if (obj_priv->user_pin_count == 1) { | ||
2724 | ret = i915_gem_object_pin(obj, args->alignment); | ||
2725 | if (ret != 0) { | ||
2726 | drm_gem_object_unreference(obj); | ||
2727 | mutex_unlock(&dev->struct_mutex); | ||
2728 | return ret; | ||
2729 | } | ||
2714 | } | 2730 | } |
2715 | 2731 | ||
2716 | /* XXX - flush the CPU caches for pinned objects | 2732 | /* XXX - flush the CPU caches for pinned objects |
@@ -2730,6 +2746,7 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data, | |||
2730 | { | 2746 | { |
2731 | struct drm_i915_gem_pin *args = data; | 2747 | struct drm_i915_gem_pin *args = data; |
2732 | struct drm_gem_object *obj; | 2748 | struct drm_gem_object *obj; |
2749 | struct drm_i915_gem_object *obj_priv; | ||
2733 | 2750 | ||
2734 | mutex_lock(&dev->struct_mutex); | 2751 | mutex_lock(&dev->struct_mutex); |
2735 | 2752 | ||
@@ -2741,7 +2758,19 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data, | |||
2741 | return -EBADF; | 2758 | return -EBADF; |
2742 | } | 2759 | } |
2743 | 2760 | ||
2744 | i915_gem_object_unpin(obj); | 2761 | obj_priv = obj->driver_private; |
2762 | if (obj_priv->pin_filp != file_priv) { | ||
2763 | DRM_ERROR("Not pinned by caller in i915_gem_pin_ioctl(): %d\n", | ||
2764 | args->handle); | ||
2765 | drm_gem_object_unreference(obj); | ||
2766 | mutex_unlock(&dev->struct_mutex); | ||
2767 | return -EINVAL; | ||
2768 | } | ||
2769 | obj_priv->user_pin_count--; | ||
2770 | if (obj_priv->user_pin_count == 0) { | ||
2771 | obj_priv->pin_filp = NULL; | ||
2772 | i915_gem_object_unpin(obj); | ||
2773 | } | ||
2745 | 2774 | ||
2746 | drm_gem_object_unreference(obj); | 2775 | drm_gem_object_unreference(obj); |
2747 | mutex_unlock(&dev->struct_mutex); | 2776 | mutex_unlock(&dev->struct_mutex); |
@@ -3036,12 +3065,13 @@ i915_gem_init_hws(struct drm_device *dev) | |||
3036 | return 0; | 3065 | return 0; |
3037 | } | 3066 | } |
3038 | 3067 | ||
3039 | static int | 3068 | int |
3040 | i915_gem_init_ringbuffer(struct drm_device *dev) | 3069 | i915_gem_init_ringbuffer(struct drm_device *dev) |
3041 | { | 3070 | { |
3042 | drm_i915_private_t *dev_priv = dev->dev_private; | 3071 | drm_i915_private_t *dev_priv = dev->dev_private; |
3043 | struct drm_gem_object *obj; | 3072 | struct drm_gem_object *obj; |
3044 | struct drm_i915_gem_object *obj_priv; | 3073 | struct drm_i915_gem_object *obj_priv; |
3074 | drm_i915_ring_buffer_t *ring = &dev_priv->ring; | ||
3045 | int ret; | 3075 | int ret; |
3046 | u32 head; | 3076 | u32 head; |
3047 | 3077 | ||
@@ -3063,24 +3093,24 @@ i915_gem_init_ringbuffer(struct drm_device *dev) | |||
3063 | } | 3093 | } |
3064 | 3094 | ||
3065 | /* Set up the kernel mapping for the ring. */ | 3095 | /* Set up the kernel mapping for the ring. */ |
3066 | dev_priv->ring.Size = obj->size; | 3096 | ring->Size = obj->size; |
3067 | dev_priv->ring.tail_mask = obj->size - 1; | 3097 | ring->tail_mask = obj->size - 1; |
3068 | 3098 | ||
3069 | dev_priv->ring.map.offset = dev->agp->base + obj_priv->gtt_offset; | 3099 | ring->map.offset = dev->agp->base + obj_priv->gtt_offset; |
3070 | dev_priv->ring.map.size = obj->size; | 3100 | ring->map.size = obj->size; |
3071 | dev_priv->ring.map.type = 0; | 3101 | ring->map.type = 0; |
3072 | dev_priv->ring.map.flags = 0; | 3102 | ring->map.flags = 0; |
3073 | dev_priv->ring.map.mtrr = 0; | 3103 | ring->map.mtrr = 0; |
3074 | 3104 | ||
3075 | drm_core_ioremap_wc(&dev_priv->ring.map, dev); | 3105 | drm_core_ioremap_wc(&ring->map, dev); |
3076 | if (dev_priv->ring.map.handle == NULL) { | 3106 | if (ring->map.handle == NULL) { |
3077 | DRM_ERROR("Failed to map ringbuffer.\n"); | 3107 | DRM_ERROR("Failed to map ringbuffer.\n"); |
3078 | memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); | 3108 | memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); |
3079 | drm_gem_object_unreference(obj); | 3109 | drm_gem_object_unreference(obj); |
3080 | return -EINVAL; | 3110 | return -EINVAL; |
3081 | } | 3111 | } |
3082 | dev_priv->ring.ring_obj = obj; | 3112 | ring->ring_obj = obj; |
3083 | dev_priv->ring.virtual_start = dev_priv->ring.map.handle; | 3113 | ring->virtual_start = ring->map.handle; |
3084 | 3114 | ||
3085 | /* Stop the ring if it's running. */ | 3115 | /* Stop the ring if it's running. */ |
3086 | I915_WRITE(PRB0_CTL, 0); | 3116 | I915_WRITE(PRB0_CTL, 0); |
@@ -3128,12 +3158,20 @@ i915_gem_init_ringbuffer(struct drm_device *dev) | |||
3128 | } | 3158 | } |
3129 | 3159 | ||
3130 | /* Update our cache of the ring state */ | 3160 | /* Update our cache of the ring state */ |
3131 | i915_kernel_lost_context(dev); | 3161 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
3162 | i915_kernel_lost_context(dev); | ||
3163 | else { | ||
3164 | ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; | ||
3165 | ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; | ||
3166 | ring->space = ring->head - (ring->tail + 8); | ||
3167 | if (ring->space < 0) | ||
3168 | ring->space += ring->Size; | ||
3169 | } | ||
3132 | 3170 | ||
3133 | return 0; | 3171 | return 0; |
3134 | } | 3172 | } |
3135 | 3173 | ||
3136 | static void | 3174 | void |
3137 | i915_gem_cleanup_ringbuffer(struct drm_device *dev) | 3175 | i915_gem_cleanup_ringbuffer(struct drm_device *dev) |
3138 | { | 3176 | { |
3139 | drm_i915_private_t *dev_priv = dev->dev_private; | 3177 | drm_i915_private_t *dev_priv = dev->dev_private; |
@@ -3171,6 +3209,9 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, | |||
3171 | drm_i915_private_t *dev_priv = dev->dev_private; | 3209 | drm_i915_private_t *dev_priv = dev->dev_private; |
3172 | int ret; | 3210 | int ret; |
3173 | 3211 | ||
3212 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
3213 | return 0; | ||
3214 | |||
3174 | if (dev_priv->mm.wedged) { | 3215 | if (dev_priv->mm.wedged) { |
3175 | DRM_ERROR("Reenabling wedged hardware, good luck\n"); | 3216 | DRM_ERROR("Reenabling wedged hardware, good luck\n"); |
3176 | dev_priv->mm.wedged = 0; | 3217 | dev_priv->mm.wedged = 0; |
@@ -3204,6 +3245,9 @@ i915_gem_leavevt_ioctl(struct drm_device *dev, void *data, | |||
3204 | drm_i915_private_t *dev_priv = dev->dev_private; | 3245 | drm_i915_private_t *dev_priv = dev->dev_private; |
3205 | int ret; | 3246 | int ret; |
3206 | 3247 | ||
3248 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
3249 | return 0; | ||
3250 | |||
3207 | ret = i915_gem_idle(dev); | 3251 | ret = i915_gem_idle(dev); |
3208 | drm_irq_uninstall(dev); | 3252 | drm_irq_uninstall(dev); |
3209 | 3253 | ||
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 9b673d2f912b..0cadafbef411 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include "drm.h" | 30 | #include "drm.h" |
31 | #include "i915_drm.h" | 31 | #include "i915_drm.h" |
32 | #include "i915_drv.h" | 32 | #include "i915_drv.h" |
33 | #include "intel_drv.h" | ||
33 | 34 | ||
34 | #define MAX_NOPID ((u32)~0) | 35 | #define MAX_NOPID ((u32)~0) |
35 | 36 | ||
@@ -51,6 +52,15 @@ | |||
51 | #define I915_INTERRUPT_ENABLE_MASK (I915_INTERRUPT_ENABLE_FIX | \ | 52 | #define I915_INTERRUPT_ENABLE_MASK (I915_INTERRUPT_ENABLE_FIX | \ |
52 | I915_INTERRUPT_ENABLE_VAR) | 53 | I915_INTERRUPT_ENABLE_VAR) |
53 | 54 | ||
55 | #define I915_PIPE_VBLANK_STATUS (PIPE_START_VBLANK_INTERRUPT_STATUS |\ | ||
56 | PIPE_VBLANK_INTERRUPT_STATUS) | ||
57 | |||
58 | #define I915_PIPE_VBLANK_ENABLE (PIPE_START_VBLANK_INTERRUPT_ENABLE |\ | ||
59 | PIPE_VBLANK_INTERRUPT_ENABLE) | ||
60 | |||
61 | #define DRM_I915_VBLANK_PIPE_ALL (DRM_I915_VBLANK_PIPE_A | \ | ||
62 | DRM_I915_VBLANK_PIPE_B) | ||
63 | |||
54 | void | 64 | void |
55 | i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) | 65 | i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) |
56 | { | 66 | { |
@@ -201,6 +211,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | |||
201 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); | 211 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); |
202 | pipea_stats = I915_READ(PIPEASTAT); | 212 | pipea_stats = I915_READ(PIPEASTAT); |
203 | pipeb_stats = I915_READ(PIPEBSTAT); | 213 | pipeb_stats = I915_READ(PIPEBSTAT); |
214 | |||
204 | /* | 215 | /* |
205 | * Clear the PIPE(A|B)STAT regs before the IIR | 216 | * Clear the PIPE(A|B)STAT regs before the IIR |
206 | */ | 217 | */ |
@@ -427,6 +438,14 @@ void i915_disable_vblank(struct drm_device *dev, int pipe) | |||
427 | spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); | 438 | spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); |
428 | } | 439 | } |
429 | 440 | ||
441 | void i915_enable_interrupt (struct drm_device *dev) | ||
442 | { | ||
443 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
444 | opregion_enable_asle(dev); | ||
445 | dev_priv->irq_enabled = 1; | ||
446 | } | ||
447 | |||
448 | |||
430 | /* Set the vblank monitor pipe | 449 | /* Set the vblank monitor pipe |
431 | */ | 450 | */ |
432 | int i915_vblank_pipe_set(struct drm_device *dev, void *data, | 451 | int i915_vblank_pipe_set(struct drm_device *dev, void *data, |
@@ -487,6 +506,8 @@ void i915_driver_irq_preinstall(struct drm_device * dev) | |||
487 | { | 506 | { |
488 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 507 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
489 | 508 | ||
509 | atomic_set(&dev_priv->irq_received, 0); | ||
510 | |||
490 | I915_WRITE(HWSTAM, 0xeffe); | 511 | I915_WRITE(HWSTAM, 0xeffe); |
491 | I915_WRITE(PIPEASTAT, 0); | 512 | I915_WRITE(PIPEASTAT, 0); |
492 | I915_WRITE(PIPEBSTAT, 0); | 513 | I915_WRITE(PIPEBSTAT, 0); |
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c new file mode 100644 index 000000000000..4ca82a025525 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_bios.c | |||
@@ -0,0 +1,193 @@ | |||
1 | /* | ||
2 | * Copyright © 2006 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
21 | * SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Eric Anholt <eric@anholt.net> | ||
25 | * | ||
26 | */ | ||
27 | #include "drmP.h" | ||
28 | #include "drm.h" | ||
29 | #include "i915_drm.h" | ||
30 | #include "i915_drv.h" | ||
31 | #include "intel_bios.h" | ||
32 | |||
33 | |||
34 | static void * | ||
35 | find_section(struct bdb_header *bdb, int section_id) | ||
36 | { | ||
37 | u8 *base = (u8 *)bdb; | ||
38 | int index = 0; | ||
39 | u16 total, current_size; | ||
40 | u8 current_id; | ||
41 | |||
42 | /* skip to first section */ | ||
43 | index += bdb->header_size; | ||
44 | total = bdb->bdb_size; | ||
45 | |||
46 | /* walk the sections looking for section_id */ | ||
47 | while (index < total) { | ||
48 | current_id = *(base + index); | ||
49 | index++; | ||
50 | current_size = *((u16 *)(base + index)); | ||
51 | index += 2; | ||
52 | if (current_id == section_id) | ||
53 | return base + index; | ||
54 | index += current_size; | ||
55 | } | ||
56 | |||
57 | return NULL; | ||
58 | } | ||
59 | |||
60 | /* Try to find panel data */ | ||
61 | static void | ||
62 | parse_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb) | ||
63 | { | ||
64 | struct bdb_lvds_options *lvds_options; | ||
65 | struct bdb_lvds_lfp_data *lvds_lfp_data; | ||
66 | struct bdb_lvds_lfp_data_entry *entry; | ||
67 | struct lvds_dvo_timing *dvo_timing; | ||
68 | struct drm_display_mode *panel_fixed_mode; | ||
69 | |||
70 | /* Defaults if we can't find VBT info */ | ||
71 | dev_priv->lvds_dither = 0; | ||
72 | dev_priv->lvds_vbt = 0; | ||
73 | |||
74 | lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); | ||
75 | if (!lvds_options) | ||
76 | return; | ||
77 | |||
78 | dev_priv->lvds_dither = lvds_options->pixel_dither; | ||
79 | if (lvds_options->panel_type == 0xff) | ||
80 | return; | ||
81 | |||
82 | lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA); | ||
83 | if (!lvds_lfp_data) | ||
84 | return; | ||
85 | |||
86 | dev_priv->lvds_vbt = 1; | ||
87 | |||
88 | entry = &lvds_lfp_data->data[lvds_options->panel_type]; | ||
89 | dvo_timing = &entry->dvo_timing; | ||
90 | |||
91 | panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode), | ||
92 | DRM_MEM_DRIVER); | ||
93 | |||
94 | panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | | ||
95 | dvo_timing->hactive_lo; | ||
96 | panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay + | ||
97 | ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo); | ||
98 | panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start + | ||
99 | dvo_timing->hsync_pulse_width; | ||
100 | panel_fixed_mode->htotal = panel_fixed_mode->hdisplay + | ||
101 | ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo); | ||
102 | |||
103 | panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) | | ||
104 | dvo_timing->vactive_lo; | ||
105 | panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay + | ||
106 | dvo_timing->vsync_off; | ||
107 | panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start + | ||
108 | dvo_timing->vsync_pulse_width; | ||
109 | panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay + | ||
110 | ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo); | ||
111 | panel_fixed_mode->clock = dvo_timing->clock * 10; | ||
112 | panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; | ||
113 | |||
114 | drm_mode_set_name(panel_fixed_mode); | ||
115 | |||
116 | dev_priv->vbt_mode = panel_fixed_mode; | ||
117 | |||
118 | DRM_DEBUG("Found panel mode in BIOS VBT tables:\n"); | ||
119 | drm_mode_debug_printmodeline(panel_fixed_mode); | ||
120 | |||
121 | return; | ||
122 | } | ||
123 | |||
124 | static void | ||
125 | parse_general_features(struct drm_i915_private *dev_priv, | ||
126 | struct bdb_header *bdb) | ||
127 | { | ||
128 | struct bdb_general_features *general; | ||
129 | |||
130 | /* Set sensible defaults in case we can't find the general block */ | ||
131 | dev_priv->int_tv_support = 1; | ||
132 | dev_priv->int_crt_support = 1; | ||
133 | |||
134 | general = find_section(bdb, BDB_GENERAL_FEATURES); | ||
135 | if (general) { | ||
136 | dev_priv->int_tv_support = general->int_tv_support; | ||
137 | dev_priv->int_crt_support = general->int_crt_support; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | /** | ||
142 | * intel_init_bios - initialize VBIOS settings & find VBT | ||
143 | * @dev: DRM device | ||
144 | * | ||
145 | * Loads the Video BIOS and checks that the VBT exists. Sets scratch registers | ||
146 | * to appropriate values. | ||
147 | * | ||
148 | * VBT existence is a sanity check that is relied on by other i830_bios.c code. | ||
149 | * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may | ||
150 | * feed an updated VBT back through that, compared to what we'll fetch using | ||
151 | * this method of groping around in the BIOS data. | ||
152 | * | ||
153 | * Returns 0 on success, nonzero on failure. | ||
154 | */ | ||
155 | bool | ||
156 | intel_init_bios(struct drm_device *dev) | ||
157 | { | ||
158 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
159 | struct pci_dev *pdev = dev->pdev; | ||
160 | struct vbt_header *vbt = NULL; | ||
161 | struct bdb_header *bdb; | ||
162 | u8 __iomem *bios; | ||
163 | size_t size; | ||
164 | int i; | ||
165 | |||
166 | bios = pci_map_rom(pdev, &size); | ||
167 | if (!bios) | ||
168 | return -1; | ||
169 | |||
170 | /* Scour memory looking for the VBT signature */ | ||
171 | for (i = 0; i + 4 < size; i++) { | ||
172 | if (!memcmp(bios + i, "$VBT", 4)) { | ||
173 | vbt = (struct vbt_header *)(bios + i); | ||
174 | break; | ||
175 | } | ||
176 | } | ||
177 | |||
178 | if (!vbt) { | ||
179 | DRM_ERROR("VBT signature missing\n"); | ||
180 | pci_unmap_rom(pdev, bios); | ||
181 | return -1; | ||
182 | } | ||
183 | |||
184 | bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset); | ||
185 | |||
186 | /* Grab useful general definitions */ | ||
187 | parse_general_features(dev_priv, bdb); | ||
188 | parse_panel_data(dev_priv, bdb); | ||
189 | |||
190 | pci_unmap_rom(pdev, bios); | ||
191 | |||
192 | return 0; | ||
193 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h new file mode 100644 index 000000000000..5ea715ace3a0 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_bios.h | |||
@@ -0,0 +1,405 @@ | |||
1 | /* | ||
2 | * Copyright © 2006 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
21 | * SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Eric Anholt <eric@anholt.net> | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #ifndef _I830_BIOS_H_ | ||
29 | #define _I830_BIOS_H_ | ||
30 | |||
31 | #include "drmP.h" | ||
32 | |||
33 | struct vbt_header { | ||
34 | u8 signature[20]; /**< Always starts with 'VBT$' */ | ||
35 | u16 version; /**< decimal */ | ||
36 | u16 header_size; /**< in bytes */ | ||
37 | u16 vbt_size; /**< in bytes */ | ||
38 | u8 vbt_checksum; | ||
39 | u8 reserved0; | ||
40 | u32 bdb_offset; /**< from beginning of VBT */ | ||
41 | u32 aim_offset[4]; /**< from beginning of VBT */ | ||
42 | } __attribute__((packed)); | ||
43 | |||
44 | struct bdb_header { | ||
45 | u8 signature[16]; /**< Always 'BIOS_DATA_BLOCK' */ | ||
46 | u16 version; /**< decimal */ | ||
47 | u16 header_size; /**< in bytes */ | ||
48 | u16 bdb_size; /**< in bytes */ | ||
49 | }; | ||
50 | |||
51 | /* strictly speaking, this is a "skip" block, but it has interesting info */ | ||
52 | struct vbios_data { | ||
53 | u8 type; /* 0 == desktop, 1 == mobile */ | ||
54 | u8 relstage; | ||
55 | u8 chipset; | ||
56 | u8 lvds_present:1; | ||
57 | u8 tv_present:1; | ||
58 | u8 rsvd2:6; /* finish byte */ | ||
59 | u8 rsvd3[4]; | ||
60 | u8 signon[155]; | ||
61 | u8 copyright[61]; | ||
62 | u16 code_segment; | ||
63 | u8 dos_boot_mode; | ||
64 | u8 bandwidth_percent; | ||
65 | u8 rsvd4; /* popup memory size */ | ||
66 | u8 resize_pci_bios; | ||
67 | u8 rsvd5; /* is crt already on ddc2 */ | ||
68 | } __attribute__((packed)); | ||
69 | |||
70 | /* | ||
71 | * There are several types of BIOS data blocks (BDBs), each block has | ||
72 | * an ID and size in the first 3 bytes (ID in first, size in next 2). | ||
73 | * Known types are listed below. | ||
74 | */ | ||
75 | #define BDB_GENERAL_FEATURES 1 | ||
76 | #define BDB_GENERAL_DEFINITIONS 2 | ||
77 | #define BDB_OLD_TOGGLE_LIST 3 | ||
78 | #define BDB_MODE_SUPPORT_LIST 4 | ||
79 | #define BDB_GENERIC_MODE_TABLE 5 | ||
80 | #define BDB_EXT_MMIO_REGS 6 | ||
81 | #define BDB_SWF_IO 7 | ||
82 | #define BDB_SWF_MMIO 8 | ||
83 | #define BDB_DOT_CLOCK_TABLE 9 | ||
84 | #define BDB_MODE_REMOVAL_TABLE 10 | ||
85 | #define BDB_CHILD_DEVICE_TABLE 11 | ||
86 | #define BDB_DRIVER_FEATURES 12 | ||
87 | #define BDB_DRIVER_PERSISTENCE 13 | ||
88 | #define BDB_EXT_TABLE_PTRS 14 | ||
89 | #define BDB_DOT_CLOCK_OVERRIDE 15 | ||
90 | #define BDB_DISPLAY_SELECT 16 | ||
91 | /* 17 rsvd */ | ||
92 | #define BDB_DRIVER_ROTATION 18 | ||
93 | #define BDB_DISPLAY_REMOVE 19 | ||
94 | #define BDB_OEM_CUSTOM 20 | ||
95 | #define BDB_EFP_LIST 21 /* workarounds for VGA hsync/vsync */ | ||
96 | #define BDB_SDVO_LVDS_OPTIONS 22 | ||
97 | #define BDB_SDVO_PANEL_DTDS 23 | ||
98 | #define BDB_SDVO_LVDS_PNP_IDS 24 | ||
99 | #define BDB_SDVO_LVDS_POWER_SEQ 25 | ||
100 | #define BDB_TV_OPTIONS 26 | ||
101 | #define BDB_LVDS_OPTIONS 40 | ||
102 | #define BDB_LVDS_LFP_DATA_PTRS 41 | ||
103 | #define BDB_LVDS_LFP_DATA 42 | ||
104 | #define BDB_LVDS_BACKLIGHT 43 | ||
105 | #define BDB_LVDS_POWER 44 | ||
106 | #define BDB_SKIP 254 /* VBIOS private block, ignore */ | ||
107 | |||
108 | struct bdb_general_features { | ||
109 | /* bits 1 */ | ||
110 | u8 panel_fitting:2; | ||
111 | u8 flexaim:1; | ||
112 | u8 msg_enable:1; | ||
113 | u8 clear_screen:3; | ||
114 | u8 color_flip:1; | ||
115 | |||
116 | /* bits 2 */ | ||
117 | u8 download_ext_vbt:1; | ||
118 | u8 enable_ssc:1; | ||
119 | u8 ssc_freq:1; | ||
120 | u8 enable_lfp_on_override:1; | ||
121 | u8 disable_ssc_ddt:1; | ||
122 | u8 rsvd8:3; /* finish byte */ | ||
123 | |||
124 | /* bits 3 */ | ||
125 | u8 disable_smooth_vision:1; | ||
126 | u8 single_dvi:1; | ||
127 | u8 rsvd9:6; /* finish byte */ | ||
128 | |||
129 | /* bits 4 */ | ||
130 | u8 legacy_monitor_detect; | ||
131 | |||
132 | /* bits 5 */ | ||
133 | u8 int_crt_support:1; | ||
134 | u8 int_tv_support:1; | ||
135 | u8 rsvd11:6; /* finish byte */ | ||
136 | } __attribute__((packed)); | ||
137 | |||
138 | struct bdb_general_definitions { | ||
139 | /* DDC GPIO */ | ||
140 | u8 crt_ddc_gmbus_pin; | ||
141 | |||
142 | /* DPMS bits */ | ||
143 | u8 dpms_acpi:1; | ||
144 | u8 skip_boot_crt_detect:1; | ||
145 | u8 dpms_aim:1; | ||
146 | u8 rsvd1:5; /* finish byte */ | ||
147 | |||
148 | /* boot device bits */ | ||
149 | u8 boot_display[2]; | ||
150 | u8 child_dev_size; | ||
151 | |||
152 | /* device info */ | ||
153 | u8 tv_or_lvds_info[33]; | ||
154 | u8 dev1[33]; | ||
155 | u8 dev2[33]; | ||
156 | u8 dev3[33]; | ||
157 | u8 dev4[33]; | ||
158 | /* may be another device block here on some platforms */ | ||
159 | }; | ||
160 | |||
161 | struct bdb_lvds_options { | ||
162 | u8 panel_type; | ||
163 | u8 rsvd1; | ||
164 | /* LVDS capabilities, stored in a dword */ | ||
165 | u8 rsvd2:1; | ||
166 | u8 lvds_edid:1; | ||
167 | u8 pixel_dither:1; | ||
168 | u8 pfit_ratio_auto:1; | ||
169 | u8 pfit_gfx_mode_enhanced:1; | ||
170 | u8 pfit_text_mode_enhanced:1; | ||
171 | u8 pfit_mode:2; | ||
172 | u8 rsvd4; | ||
173 | } __attribute__((packed)); | ||
174 | |||
175 | /* LFP pointer table contains entries to the struct below */ | ||
176 | struct bdb_lvds_lfp_data_ptr { | ||
177 | u16 fp_timing_offset; /* offsets are from start of bdb */ | ||
178 | u8 fp_table_size; | ||
179 | u16 dvo_timing_offset; | ||
180 | u8 dvo_table_size; | ||
181 | u16 panel_pnp_id_offset; | ||
182 | u8 pnp_table_size; | ||
183 | } __attribute__((packed)); | ||
184 | |||
185 | struct bdb_lvds_lfp_data_ptrs { | ||
186 | u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */ | ||
187 | struct bdb_lvds_lfp_data_ptr ptr[16]; | ||
188 | } __attribute__((packed)); | ||
189 | |||
190 | /* LFP data has 3 blocks per entry */ | ||
191 | struct lvds_fp_timing { | ||
192 | u16 x_res; | ||
193 | u16 y_res; | ||
194 | u32 lvds_reg; | ||
195 | u32 lvds_reg_val; | ||
196 | u32 pp_on_reg; | ||
197 | u32 pp_on_reg_val; | ||
198 | u32 pp_off_reg; | ||
199 | u32 pp_off_reg_val; | ||
200 | u32 pp_cycle_reg; | ||
201 | u32 pp_cycle_reg_val; | ||
202 | u32 pfit_reg; | ||
203 | u32 pfit_reg_val; | ||
204 | u16 terminator; | ||
205 | } __attribute__((packed)); | ||
206 | |||
207 | struct lvds_dvo_timing { | ||
208 | u16 clock; /**< In 10khz */ | ||
209 | u8 hactive_lo; | ||
210 | u8 hblank_lo; | ||
211 | u8 hblank_hi:4; | ||
212 | u8 hactive_hi:4; | ||
213 | u8 vactive_lo; | ||
214 | u8 vblank_lo; | ||
215 | u8 vblank_hi:4; | ||
216 | u8 vactive_hi:4; | ||
217 | u8 hsync_off_lo; | ||
218 | u8 hsync_pulse_width; | ||
219 | u8 vsync_pulse_width:4; | ||
220 | u8 vsync_off:4; | ||
221 | u8 rsvd0:6; | ||
222 | u8 hsync_off_hi:2; | ||
223 | u8 h_image; | ||
224 | u8 v_image; | ||
225 | u8 max_hv; | ||
226 | u8 h_border; | ||
227 | u8 v_border; | ||
228 | u8 rsvd1:3; | ||
229 | u8 digital:2; | ||
230 | u8 vsync_positive:1; | ||
231 | u8 hsync_positive:1; | ||
232 | u8 rsvd2:1; | ||
233 | } __attribute__((packed)); | ||
234 | |||
235 | struct lvds_pnp_id { | ||
236 | u16 mfg_name; | ||
237 | u16 product_code; | ||
238 | u32 serial; | ||
239 | u8 mfg_week; | ||
240 | u8 mfg_year; | ||
241 | } __attribute__((packed)); | ||
242 | |||
243 | struct bdb_lvds_lfp_data_entry { | ||
244 | struct lvds_fp_timing fp_timing; | ||
245 | struct lvds_dvo_timing dvo_timing; | ||
246 | struct lvds_pnp_id pnp_id; | ||
247 | } __attribute__((packed)); | ||
248 | |||
249 | struct bdb_lvds_lfp_data { | ||
250 | struct bdb_lvds_lfp_data_entry data[16]; | ||
251 | } __attribute__((packed)); | ||
252 | |||
253 | struct aimdb_header { | ||
254 | char signature[16]; | ||
255 | char oem_device[20]; | ||
256 | u16 aimdb_version; | ||
257 | u16 aimdb_header_size; | ||
258 | u16 aimdb_size; | ||
259 | } __attribute__((packed)); | ||
260 | |||
261 | struct aimdb_block { | ||
262 | u8 aimdb_id; | ||
263 | u16 aimdb_size; | ||
264 | } __attribute__((packed)); | ||
265 | |||
266 | struct vch_panel_data { | ||
267 | u16 fp_timing_offset; | ||
268 | u8 fp_timing_size; | ||
269 | u16 dvo_timing_offset; | ||
270 | u8 dvo_timing_size; | ||
271 | u16 text_fitting_offset; | ||
272 | u8 text_fitting_size; | ||
273 | u16 graphics_fitting_offset; | ||
274 | u8 graphics_fitting_size; | ||
275 | } __attribute__((packed)); | ||
276 | |||
277 | struct vch_bdb_22 { | ||
278 | struct aimdb_block aimdb_block; | ||
279 | struct vch_panel_data panels[16]; | ||
280 | } __attribute__((packed)); | ||
281 | |||
282 | bool intel_init_bios(struct drm_device *dev); | ||
283 | |||
284 | /* | ||
285 | * Driver<->VBIOS interaction occurs through scratch bits in | ||
286 | * GR18 & SWF*. | ||
287 | */ | ||
288 | |||
289 | /* GR18 bits are set on display switch and hotkey events */ | ||
290 | #define GR18_DRIVER_SWITCH_EN (1<<7) /* 0: VBIOS control, 1: driver control */ | ||
291 | #define GR18_HOTKEY_MASK 0x78 /* See also SWF4 15:0 */ | ||
292 | #define GR18_HK_NONE (0x0<<3) | ||
293 | #define GR18_HK_LFP_STRETCH (0x1<<3) | ||
294 | #define GR18_HK_TOGGLE_DISP (0x2<<3) | ||
295 | #define GR18_HK_DISP_SWITCH (0x4<<3) /* see SWF14 15:0 for what to enable */ | ||
296 | #define GR18_HK_POPUP_DISABLED (0x6<<3) | ||
297 | #define GR18_HK_POPUP_ENABLED (0x7<<3) | ||
298 | #define GR18_HK_PFIT (0x8<<3) | ||
299 | #define GR18_HK_APM_CHANGE (0xa<<3) | ||
300 | #define GR18_HK_MULTIPLE (0xc<<3) | ||
301 | #define GR18_USER_INT_EN (1<<2) | ||
302 | #define GR18_A0000_FLUSH_EN (1<<1) | ||
303 | #define GR18_SMM_EN (1<<0) | ||
304 | |||
305 | /* Set by driver, cleared by VBIOS */ | ||
306 | #define SWF00_YRES_SHIFT 16 | ||
307 | #define SWF00_XRES_SHIFT 0 | ||
308 | #define SWF00_RES_MASK 0xffff | ||
309 | |||
310 | /* Set by VBIOS at boot time and driver at runtime */ | ||
311 | #define SWF01_TV2_FORMAT_SHIFT 8 | ||
312 | #define SWF01_TV1_FORMAT_SHIFT 0 | ||
313 | #define SWF01_TV_FORMAT_MASK 0xffff | ||
314 | |||
315 | #define SWF10_VBIOS_BLC_I2C_EN (1<<29) | ||
316 | #define SWF10_GTT_OVERRIDE_EN (1<<28) | ||
317 | #define SWF10_LFP_DPMS_OVR (1<<27) /* override DPMS on display switch */ | ||
318 | #define SWF10_ACTIVE_TOGGLE_LIST_MASK (7<<24) | ||
319 | #define SWF10_OLD_TOGGLE 0x0 | ||
320 | #define SWF10_TOGGLE_LIST_1 0x1 | ||
321 | #define SWF10_TOGGLE_LIST_2 0x2 | ||
322 | #define SWF10_TOGGLE_LIST_3 0x3 | ||
323 | #define SWF10_TOGGLE_LIST_4 0x4 | ||
324 | #define SWF10_PANNING_EN (1<<23) | ||
325 | #define SWF10_DRIVER_LOADED (1<<22) | ||
326 | #define SWF10_EXTENDED_DESKTOP (1<<21) | ||
327 | #define SWF10_EXCLUSIVE_MODE (1<<20) | ||
328 | #define SWF10_OVERLAY_EN (1<<19) | ||
329 | #define SWF10_PLANEB_HOLDOFF (1<<18) | ||
330 | #define SWF10_PLANEA_HOLDOFF (1<<17) | ||
331 | #define SWF10_VGA_HOLDOFF (1<<16) | ||
332 | #define SWF10_ACTIVE_DISP_MASK 0xffff | ||
333 | #define SWF10_PIPEB_LFP2 (1<<15) | ||
334 | #define SWF10_PIPEB_EFP2 (1<<14) | ||
335 | #define SWF10_PIPEB_TV2 (1<<13) | ||
336 | #define SWF10_PIPEB_CRT2 (1<<12) | ||
337 | #define SWF10_PIPEB_LFP (1<<11) | ||
338 | #define SWF10_PIPEB_EFP (1<<10) | ||
339 | #define SWF10_PIPEB_TV (1<<9) | ||
340 | #define SWF10_PIPEB_CRT (1<<8) | ||
341 | #define SWF10_PIPEA_LFP2 (1<<7) | ||
342 | #define SWF10_PIPEA_EFP2 (1<<6) | ||
343 | #define SWF10_PIPEA_TV2 (1<<5) | ||
344 | #define SWF10_PIPEA_CRT2 (1<<4) | ||
345 | #define SWF10_PIPEA_LFP (1<<3) | ||
346 | #define SWF10_PIPEA_EFP (1<<2) | ||
347 | #define SWF10_PIPEA_TV (1<<1) | ||
348 | #define SWF10_PIPEA_CRT (1<<0) | ||
349 | |||
350 | #define SWF11_MEMORY_SIZE_SHIFT 16 | ||
351 | #define SWF11_SV_TEST_EN (1<<15) | ||
352 | #define SWF11_IS_AGP (1<<14) | ||
353 | #define SWF11_DISPLAY_HOLDOFF (1<<13) | ||
354 | #define SWF11_DPMS_REDUCED (1<<12) | ||
355 | #define SWF11_IS_VBE_MODE (1<<11) | ||
356 | #define SWF11_PIPEB_ACCESS (1<<10) /* 0 here means pipe a */ | ||
357 | #define SWF11_DPMS_MASK 0x07 | ||
358 | #define SWF11_DPMS_OFF (1<<2) | ||
359 | #define SWF11_DPMS_SUSPEND (1<<1) | ||
360 | #define SWF11_DPMS_STANDBY (1<<0) | ||
361 | #define SWF11_DPMS_ON 0 | ||
362 | |||
363 | #define SWF14_GFX_PFIT_EN (1<<31) | ||
364 | #define SWF14_TEXT_PFIT_EN (1<<30) | ||
365 | #define SWF14_LID_STATUS_CLOSED (1<<29) /* 0 here means open */ | ||
366 | #define SWF14_POPUP_EN (1<<28) | ||
367 | #define SWF14_DISPLAY_HOLDOFF (1<<27) | ||
368 | #define SWF14_DISP_DETECT_EN (1<<26) | ||
369 | #define SWF14_DOCKING_STATUS_DOCKED (1<<25) /* 0 here means undocked */ | ||
370 | #define SWF14_DRIVER_STATUS (1<<24) | ||
371 | #define SWF14_OS_TYPE_WIN9X (1<<23) | ||
372 | #define SWF14_OS_TYPE_WINNT (1<<22) | ||
373 | /* 21:19 rsvd */ | ||
374 | #define SWF14_PM_TYPE_MASK 0x00070000 | ||
375 | #define SWF14_PM_ACPI_VIDEO (0x4 << 16) | ||
376 | #define SWF14_PM_ACPI (0x3 << 16) | ||
377 | #define SWF14_PM_APM_12 (0x2 << 16) | ||
378 | #define SWF14_PM_APM_11 (0x1 << 16) | ||
379 | #define SWF14_HK_REQUEST_MASK 0x0000ffff /* see GR18 6:3 for event type */ | ||
380 | /* if GR18 indicates a display switch */ | ||
381 | #define SWF14_DS_PIPEB_LFP2_EN (1<<15) | ||
382 | #define SWF14_DS_PIPEB_EFP2_EN (1<<14) | ||
383 | #define SWF14_DS_PIPEB_TV2_EN (1<<13) | ||
384 | #define SWF14_DS_PIPEB_CRT2_EN (1<<12) | ||
385 | #define SWF14_DS_PIPEB_LFP_EN (1<<11) | ||
386 | #define SWF14_DS_PIPEB_EFP_EN (1<<10) | ||
387 | #define SWF14_DS_PIPEB_TV_EN (1<<9) | ||
388 | #define SWF14_DS_PIPEB_CRT_EN (1<<8) | ||
389 | #define SWF14_DS_PIPEA_LFP2_EN (1<<7) | ||
390 | #define SWF14_DS_PIPEA_EFP2_EN (1<<6) | ||
391 | #define SWF14_DS_PIPEA_TV2_EN (1<<5) | ||
392 | #define SWF14_DS_PIPEA_CRT2_EN (1<<4) | ||
393 | #define SWF14_DS_PIPEA_LFP_EN (1<<3) | ||
394 | #define SWF14_DS_PIPEA_EFP_EN (1<<2) | ||
395 | #define SWF14_DS_PIPEA_TV_EN (1<<1) | ||
396 | #define SWF14_DS_PIPEA_CRT_EN (1<<0) | ||
397 | /* if GR18 indicates a panel fitting request */ | ||
398 | #define SWF14_PFIT_EN (1<<0) /* 0 means disable */ | ||
399 | /* if GR18 indicates an APM change request */ | ||
400 | #define SWF14_APM_HIBERNATE 0x4 | ||
401 | #define SWF14_APM_SUSPEND 0x3 | ||
402 | #define SWF14_APM_STANDBY 0x1 | ||
403 | #define SWF14_APM_RESTORE 0x0 | ||
404 | |||
405 | #endif /* _I830_BIOS_H_ */ | ||
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c new file mode 100644 index 000000000000..5d9c94eb7055 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_crt.c | |||
@@ -0,0 +1,284 @@ | |||
1 | /* | ||
2 | * Copyright © 2006-2007 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Eric Anholt <eric@anholt.net> | ||
25 | */ | ||
26 | |||
27 | #include <linux/i2c.h> | ||
28 | #include "drmP.h" | ||
29 | #include "drm.h" | ||
30 | #include "drm_crtc.h" | ||
31 | #include "drm_crtc_helper.h" | ||
32 | #include "intel_drv.h" | ||
33 | #include "i915_drm.h" | ||
34 | #include "i915_drv.h" | ||
35 | |||
36 | static void intel_crt_dpms(struct drm_encoder *encoder, int mode) | ||
37 | { | ||
38 | struct drm_device *dev = encoder->dev; | ||
39 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
40 | u32 temp; | ||
41 | |||
42 | temp = I915_READ(ADPA); | ||
43 | temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); | ||
44 | temp &= ~ADPA_DAC_ENABLE; | ||
45 | |||
46 | switch(mode) { | ||
47 | case DRM_MODE_DPMS_ON: | ||
48 | temp |= ADPA_DAC_ENABLE; | ||
49 | break; | ||
50 | case DRM_MODE_DPMS_STANDBY: | ||
51 | temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; | ||
52 | break; | ||
53 | case DRM_MODE_DPMS_SUSPEND: | ||
54 | temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; | ||
55 | break; | ||
56 | case DRM_MODE_DPMS_OFF: | ||
57 | temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; | ||
58 | break; | ||
59 | } | ||
60 | |||
61 | I915_WRITE(ADPA, temp); | ||
62 | } | ||
63 | |||
64 | static int intel_crt_mode_valid(struct drm_connector *connector, | ||
65 | struct drm_display_mode *mode) | ||
66 | { | ||
67 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
68 | return MODE_NO_DBLESCAN; | ||
69 | |||
70 | if (mode->clock > 400000 || mode->clock < 25000) | ||
71 | return MODE_CLOCK_RANGE; | ||
72 | |||
73 | return MODE_OK; | ||
74 | } | ||
75 | |||
76 | static bool intel_crt_mode_fixup(struct drm_encoder *encoder, | ||
77 | struct drm_display_mode *mode, | ||
78 | struct drm_display_mode *adjusted_mode) | ||
79 | { | ||
80 | return true; | ||
81 | } | ||
82 | |||
83 | static void intel_crt_mode_set(struct drm_encoder *encoder, | ||
84 | struct drm_display_mode *mode, | ||
85 | struct drm_display_mode *adjusted_mode) | ||
86 | { | ||
87 | |||
88 | struct drm_device *dev = encoder->dev; | ||
89 | struct drm_crtc *crtc = encoder->crtc; | ||
90 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
91 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
92 | int dpll_md_reg; | ||
93 | u32 adpa, dpll_md; | ||
94 | |||
95 | if (intel_crtc->pipe == 0) | ||
96 | dpll_md_reg = DPLL_A_MD; | ||
97 | else | ||
98 | dpll_md_reg = DPLL_B_MD; | ||
99 | |||
100 | /* | ||
101 | * Disable separate mode multiplier used when cloning SDVO to CRT | ||
102 | * XXX this needs to be adjusted when we really are cloning | ||
103 | */ | ||
104 | if (IS_I965G(dev)) { | ||
105 | dpll_md = I915_READ(dpll_md_reg); | ||
106 | I915_WRITE(dpll_md_reg, | ||
107 | dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK); | ||
108 | } | ||
109 | |||
110 | adpa = 0; | ||
111 | if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
112 | adpa |= ADPA_HSYNC_ACTIVE_HIGH; | ||
113 | if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
114 | adpa |= ADPA_VSYNC_ACTIVE_HIGH; | ||
115 | |||
116 | if (intel_crtc->pipe == 0) | ||
117 | adpa |= ADPA_PIPE_A_SELECT; | ||
118 | else | ||
119 | adpa |= ADPA_PIPE_B_SELECT; | ||
120 | |||
121 | I915_WRITE(ADPA, adpa); | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence. | ||
126 | * | ||
127 | * Not for i915G/i915GM | ||
128 | * | ||
129 | * \return true if CRT is connected. | ||
130 | * \return false if CRT is disconnected. | ||
131 | */ | ||
132 | static bool intel_crt_detect_hotplug(struct drm_connector *connector) | ||
133 | { | ||
134 | struct drm_device *dev = connector->dev; | ||
135 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
136 | u32 temp; | ||
137 | |||
138 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); | ||
139 | |||
140 | temp = I915_READ(PORT_HOTPLUG_EN); | ||
141 | |||
142 | I915_WRITE(PORT_HOTPLUG_EN, | ||
143 | temp | CRT_HOTPLUG_FORCE_DETECT | (1 << 5)); | ||
144 | |||
145 | do { | ||
146 | if (!(I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT)) | ||
147 | break; | ||
148 | msleep(1); | ||
149 | } while (time_after(timeout, jiffies)); | ||
150 | |||
151 | if ((I915_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) == | ||
152 | CRT_HOTPLUG_MONITOR_COLOR) | ||
153 | return true; | ||
154 | |||
155 | return false; | ||
156 | } | ||
157 | |||
158 | static bool intel_crt_detect_ddc(struct drm_connector *connector) | ||
159 | { | ||
160 | struct intel_output *intel_output = to_intel_output(connector); | ||
161 | |||
162 | /* CRT should always be at 0, but check anyway */ | ||
163 | if (intel_output->type != INTEL_OUTPUT_ANALOG) | ||
164 | return false; | ||
165 | |||
166 | return intel_ddc_probe(intel_output); | ||
167 | } | ||
168 | |||
169 | static enum drm_connector_status intel_crt_detect(struct drm_connector *connector) | ||
170 | { | ||
171 | struct drm_device *dev = connector->dev; | ||
172 | |||
173 | if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { | ||
174 | if (intel_crt_detect_hotplug(connector)) | ||
175 | return connector_status_connected; | ||
176 | else | ||
177 | return connector_status_disconnected; | ||
178 | } | ||
179 | |||
180 | if (intel_crt_detect_ddc(connector)) | ||
181 | return connector_status_connected; | ||
182 | |||
183 | /* TODO use load detect */ | ||
184 | return connector_status_unknown; | ||
185 | } | ||
186 | |||
187 | static void intel_crt_destroy(struct drm_connector *connector) | ||
188 | { | ||
189 | struct intel_output *intel_output = to_intel_output(connector); | ||
190 | |||
191 | intel_i2c_destroy(intel_output->ddc_bus); | ||
192 | drm_sysfs_connector_remove(connector); | ||
193 | drm_connector_cleanup(connector); | ||
194 | kfree(connector); | ||
195 | } | ||
196 | |||
197 | static int intel_crt_get_modes(struct drm_connector *connector) | ||
198 | { | ||
199 | struct intel_output *intel_output = to_intel_output(connector); | ||
200 | return intel_ddc_get_modes(intel_output); | ||
201 | } | ||
202 | |||
203 | static int intel_crt_set_property(struct drm_connector *connector, | ||
204 | struct drm_property *property, | ||
205 | uint64_t value) | ||
206 | { | ||
207 | struct drm_device *dev = connector->dev; | ||
208 | |||
209 | if (property == dev->mode_config.dpms_property && connector->encoder) | ||
210 | intel_crt_dpms(connector->encoder, (uint32_t)(value & 0xf)); | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | /* | ||
216 | * Routines for controlling stuff on the analog port | ||
217 | */ | ||
218 | |||
219 | static const struct drm_encoder_helper_funcs intel_crt_helper_funcs = { | ||
220 | .dpms = intel_crt_dpms, | ||
221 | .mode_fixup = intel_crt_mode_fixup, | ||
222 | .prepare = intel_encoder_prepare, | ||
223 | .commit = intel_encoder_commit, | ||
224 | .mode_set = intel_crt_mode_set, | ||
225 | }; | ||
226 | |||
227 | static const struct drm_connector_funcs intel_crt_connector_funcs = { | ||
228 | .detect = intel_crt_detect, | ||
229 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
230 | .destroy = intel_crt_destroy, | ||
231 | .set_property = intel_crt_set_property, | ||
232 | }; | ||
233 | |||
234 | static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = { | ||
235 | .mode_valid = intel_crt_mode_valid, | ||
236 | .get_modes = intel_crt_get_modes, | ||
237 | .best_encoder = intel_best_encoder, | ||
238 | }; | ||
239 | |||
240 | void intel_crt_enc_destroy(struct drm_encoder *encoder) | ||
241 | { | ||
242 | drm_encoder_cleanup(encoder); | ||
243 | } | ||
244 | |||
245 | static const struct drm_encoder_funcs intel_crt_enc_funcs = { | ||
246 | .destroy = intel_crt_enc_destroy, | ||
247 | }; | ||
248 | |||
249 | void intel_crt_init(struct drm_device *dev) | ||
250 | { | ||
251 | struct drm_connector *connector; | ||
252 | struct intel_output *intel_output; | ||
253 | |||
254 | intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL); | ||
255 | if (!intel_output) | ||
256 | return; | ||
257 | |||
258 | connector = &intel_output->base; | ||
259 | drm_connector_init(dev, &intel_output->base, | ||
260 | &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA); | ||
261 | |||
262 | drm_encoder_init(dev, &intel_output->enc, &intel_crt_enc_funcs, | ||
263 | DRM_MODE_ENCODER_DAC); | ||
264 | |||
265 | drm_mode_connector_attach_encoder(&intel_output->base, | ||
266 | &intel_output->enc); | ||
267 | |||
268 | /* Set up the DDC bus. */ | ||
269 | intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A"); | ||
270 | if (!intel_output->ddc_bus) { | ||
271 | dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " | ||
272 | "failed.\n"); | ||
273 | return; | ||
274 | } | ||
275 | |||
276 | intel_output->type = INTEL_OUTPUT_ANALOG; | ||
277 | connector->interlace_allowed = 0; | ||
278 | connector->doublescan_allowed = 0; | ||
279 | |||
280 | drm_encoder_helper_add(&intel_output->enc, &intel_crt_helper_funcs); | ||
281 | drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); | ||
282 | |||
283 | drm_sysfs_connector_add(connector); | ||
284 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c new file mode 100644 index 000000000000..96c2da5b74e3 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -0,0 +1,1621 @@ | |||
1 | /* | ||
2 | * Copyright © 2006-2007 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Eric Anholt <eric@anholt.net> | ||
25 | */ | ||
26 | |||
27 | #include <linux/i2c.h> | ||
28 | #include "drmP.h" | ||
29 | #include "intel_drv.h" | ||
30 | #include "i915_drm.h" | ||
31 | #include "i915_drv.h" | ||
32 | |||
33 | #include "drm_crtc_helper.h" | ||
34 | |||
35 | bool intel_pipe_has_type (struct drm_crtc *crtc, int type); | ||
36 | |||
37 | typedef struct { | ||
38 | /* given values */ | ||
39 | int n; | ||
40 | int m1, m2; | ||
41 | int p1, p2; | ||
42 | /* derived values */ | ||
43 | int dot; | ||
44 | int vco; | ||
45 | int m; | ||
46 | int p; | ||
47 | } intel_clock_t; | ||
48 | |||
49 | typedef struct { | ||
50 | int min, max; | ||
51 | } intel_range_t; | ||
52 | |||
53 | typedef struct { | ||
54 | int dot_limit; | ||
55 | int p2_slow, p2_fast; | ||
56 | } intel_p2_t; | ||
57 | |||
58 | #define INTEL_P2_NUM 2 | ||
59 | |||
60 | typedef struct { | ||
61 | intel_range_t dot, vco, n, m, m1, m2, p, p1; | ||
62 | intel_p2_t p2; | ||
63 | } intel_limit_t; | ||
64 | |||
65 | #define I8XX_DOT_MIN 25000 | ||
66 | #define I8XX_DOT_MAX 350000 | ||
67 | #define I8XX_VCO_MIN 930000 | ||
68 | #define I8XX_VCO_MAX 1400000 | ||
69 | #define I8XX_N_MIN 3 | ||
70 | #define I8XX_N_MAX 16 | ||
71 | #define I8XX_M_MIN 96 | ||
72 | #define I8XX_M_MAX 140 | ||
73 | #define I8XX_M1_MIN 18 | ||
74 | #define I8XX_M1_MAX 26 | ||
75 | #define I8XX_M2_MIN 6 | ||
76 | #define I8XX_M2_MAX 16 | ||
77 | #define I8XX_P_MIN 4 | ||
78 | #define I8XX_P_MAX 128 | ||
79 | #define I8XX_P1_MIN 2 | ||
80 | #define I8XX_P1_MAX 33 | ||
81 | #define I8XX_P1_LVDS_MIN 1 | ||
82 | #define I8XX_P1_LVDS_MAX 6 | ||
83 | #define I8XX_P2_SLOW 4 | ||
84 | #define I8XX_P2_FAST 2 | ||
85 | #define I8XX_P2_LVDS_SLOW 14 | ||
86 | #define I8XX_P2_LVDS_FAST 14 /* No fast option */ | ||
87 | #define I8XX_P2_SLOW_LIMIT 165000 | ||
88 | |||
89 | #define I9XX_DOT_MIN 20000 | ||
90 | #define I9XX_DOT_MAX 400000 | ||
91 | #define I9XX_VCO_MIN 1400000 | ||
92 | #define I9XX_VCO_MAX 2800000 | ||
93 | #define I9XX_N_MIN 3 | ||
94 | #define I9XX_N_MAX 8 | ||
95 | #define I9XX_M_MIN 70 | ||
96 | #define I9XX_M_MAX 120 | ||
97 | #define I9XX_M1_MIN 10 | ||
98 | #define I9XX_M1_MAX 20 | ||
99 | #define I9XX_M2_MIN 5 | ||
100 | #define I9XX_M2_MAX 9 | ||
101 | #define I9XX_P_SDVO_DAC_MIN 5 | ||
102 | #define I9XX_P_SDVO_DAC_MAX 80 | ||
103 | #define I9XX_P_LVDS_MIN 7 | ||
104 | #define I9XX_P_LVDS_MAX 98 | ||
105 | #define I9XX_P1_MIN 1 | ||
106 | #define I9XX_P1_MAX 8 | ||
107 | #define I9XX_P2_SDVO_DAC_SLOW 10 | ||
108 | #define I9XX_P2_SDVO_DAC_FAST 5 | ||
109 | #define I9XX_P2_SDVO_DAC_SLOW_LIMIT 200000 | ||
110 | #define I9XX_P2_LVDS_SLOW 14 | ||
111 | #define I9XX_P2_LVDS_FAST 7 | ||
112 | #define I9XX_P2_LVDS_SLOW_LIMIT 112000 | ||
113 | |||
114 | #define INTEL_LIMIT_I8XX_DVO_DAC 0 | ||
115 | #define INTEL_LIMIT_I8XX_LVDS 1 | ||
116 | #define INTEL_LIMIT_I9XX_SDVO_DAC 2 | ||
117 | #define INTEL_LIMIT_I9XX_LVDS 3 | ||
118 | |||
119 | static const intel_limit_t intel_limits[] = { | ||
120 | { /* INTEL_LIMIT_I8XX_DVO_DAC */ | ||
121 | .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, | ||
122 | .vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX }, | ||
123 | .n = { .min = I8XX_N_MIN, .max = I8XX_N_MAX }, | ||
124 | .m = { .min = I8XX_M_MIN, .max = I8XX_M_MAX }, | ||
125 | .m1 = { .min = I8XX_M1_MIN, .max = I8XX_M1_MAX }, | ||
126 | .m2 = { .min = I8XX_M2_MIN, .max = I8XX_M2_MAX }, | ||
127 | .p = { .min = I8XX_P_MIN, .max = I8XX_P_MAX }, | ||
128 | .p1 = { .min = I8XX_P1_MIN, .max = I8XX_P1_MAX }, | ||
129 | .p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT, | ||
130 | .p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST }, | ||
131 | }, | ||
132 | { /* INTEL_LIMIT_I8XX_LVDS */ | ||
133 | .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX }, | ||
134 | .vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX }, | ||
135 | .n = { .min = I8XX_N_MIN, .max = I8XX_N_MAX }, | ||
136 | .m = { .min = I8XX_M_MIN, .max = I8XX_M_MAX }, | ||
137 | .m1 = { .min = I8XX_M1_MIN, .max = I8XX_M1_MAX }, | ||
138 | .m2 = { .min = I8XX_M2_MIN, .max = I8XX_M2_MAX }, | ||
139 | .p = { .min = I8XX_P_MIN, .max = I8XX_P_MAX }, | ||
140 | .p1 = { .min = I8XX_P1_LVDS_MIN, .max = I8XX_P1_LVDS_MAX }, | ||
141 | .p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT, | ||
142 | .p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST }, | ||
143 | }, | ||
144 | { /* INTEL_LIMIT_I9XX_SDVO_DAC */ | ||
145 | .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, | ||
146 | .vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX }, | ||
147 | .n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX }, | ||
148 | .m = { .min = I9XX_M_MIN, .max = I9XX_M_MAX }, | ||
149 | .m1 = { .min = I9XX_M1_MIN, .max = I9XX_M1_MAX }, | ||
150 | .m2 = { .min = I9XX_M2_MIN, .max = I9XX_M2_MAX }, | ||
151 | .p = { .min = I9XX_P_SDVO_DAC_MIN, .max = I9XX_P_SDVO_DAC_MAX }, | ||
152 | .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX }, | ||
153 | .p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT, | ||
154 | .p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST }, | ||
155 | }, | ||
156 | { /* INTEL_LIMIT_I9XX_LVDS */ | ||
157 | .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX }, | ||
158 | .vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX }, | ||
159 | .n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX }, | ||
160 | .m = { .min = I9XX_M_MIN, .max = I9XX_M_MAX }, | ||
161 | .m1 = { .min = I9XX_M1_MIN, .max = I9XX_M1_MAX }, | ||
162 | .m2 = { .min = I9XX_M2_MIN, .max = I9XX_M2_MAX }, | ||
163 | .p = { .min = I9XX_P_LVDS_MIN, .max = I9XX_P_LVDS_MAX }, | ||
164 | .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX }, | ||
165 | /* The single-channel range is 25-112Mhz, and dual-channel | ||
166 | * is 80-224Mhz. Prefer single channel as much as possible. | ||
167 | */ | ||
168 | .p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT, | ||
169 | .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST }, | ||
170 | }, | ||
171 | }; | ||
172 | |||
173 | static const intel_limit_t *intel_limit(struct drm_crtc *crtc) | ||
174 | { | ||
175 | struct drm_device *dev = crtc->dev; | ||
176 | const intel_limit_t *limit; | ||
177 | |||
178 | if (IS_I9XX(dev)) { | ||
179 | if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) | ||
180 | limit = &intel_limits[INTEL_LIMIT_I9XX_LVDS]; | ||
181 | else | ||
182 | limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC]; | ||
183 | } else { | ||
184 | if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) | ||
185 | limit = &intel_limits[INTEL_LIMIT_I8XX_LVDS]; | ||
186 | else | ||
187 | limit = &intel_limits[INTEL_LIMIT_I8XX_DVO_DAC]; | ||
188 | } | ||
189 | return limit; | ||
190 | } | ||
191 | |||
192 | /** Derive the pixel clock for the given refclk and divisors for 8xx chips. */ | ||
193 | |||
194 | static void i8xx_clock(int refclk, intel_clock_t *clock) | ||
195 | { | ||
196 | clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); | ||
197 | clock->p = clock->p1 * clock->p2; | ||
198 | clock->vco = refclk * clock->m / (clock->n + 2); | ||
199 | clock->dot = clock->vco / clock->p; | ||
200 | } | ||
201 | |||
202 | /** Derive the pixel clock for the given refclk and divisors for 9xx chips. */ | ||
203 | |||
204 | static void i9xx_clock(int refclk, intel_clock_t *clock) | ||
205 | { | ||
206 | clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2); | ||
207 | clock->p = clock->p1 * clock->p2; | ||
208 | clock->vco = refclk * clock->m / (clock->n + 2); | ||
209 | clock->dot = clock->vco / clock->p; | ||
210 | } | ||
211 | |||
212 | static void intel_clock(struct drm_device *dev, int refclk, | ||
213 | intel_clock_t *clock) | ||
214 | { | ||
215 | if (IS_I9XX(dev)) | ||
216 | return i9xx_clock (refclk, clock); | ||
217 | else | ||
218 | return i8xx_clock (refclk, clock); | ||
219 | } | ||
220 | |||
221 | /** | ||
222 | * Returns whether any output on the specified pipe is of the specified type | ||
223 | */ | ||
224 | bool intel_pipe_has_type (struct drm_crtc *crtc, int type) | ||
225 | { | ||
226 | struct drm_device *dev = crtc->dev; | ||
227 | struct drm_mode_config *mode_config = &dev->mode_config; | ||
228 | struct drm_connector *l_entry; | ||
229 | |||
230 | list_for_each_entry(l_entry, &mode_config->connector_list, head) { | ||
231 | if (l_entry->encoder && | ||
232 | l_entry->encoder->crtc == crtc) { | ||
233 | struct intel_output *intel_output = to_intel_output(l_entry); | ||
234 | if (intel_output->type == type) | ||
235 | return true; | ||
236 | } | ||
237 | } | ||
238 | return false; | ||
239 | } | ||
240 | |||
241 | #define INTELPllInvalid(s) { /* ErrorF (s) */; return false; } | ||
242 | /** | ||
243 | * Returns whether the given set of divisors are valid for a given refclk with | ||
244 | * the given connectors. | ||
245 | */ | ||
246 | |||
247 | static bool intel_PLL_is_valid(struct drm_crtc *crtc, intel_clock_t *clock) | ||
248 | { | ||
249 | const intel_limit_t *limit = intel_limit (crtc); | ||
250 | |||
251 | if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1) | ||
252 | INTELPllInvalid ("p1 out of range\n"); | ||
253 | if (clock->p < limit->p.min || limit->p.max < clock->p) | ||
254 | INTELPllInvalid ("p out of range\n"); | ||
255 | if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2) | ||
256 | INTELPllInvalid ("m2 out of range\n"); | ||
257 | if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1) | ||
258 | INTELPllInvalid ("m1 out of range\n"); | ||
259 | if (clock->m1 <= clock->m2) | ||
260 | INTELPllInvalid ("m1 <= m2\n"); | ||
261 | if (clock->m < limit->m.min || limit->m.max < clock->m) | ||
262 | INTELPllInvalid ("m out of range\n"); | ||
263 | if (clock->n < limit->n.min || limit->n.max < clock->n) | ||
264 | INTELPllInvalid ("n out of range\n"); | ||
265 | if (clock->vco < limit->vco.min || limit->vco.max < clock->vco) | ||
266 | INTELPllInvalid ("vco out of range\n"); | ||
267 | /* XXX: We may need to be checking "Dot clock" depending on the multiplier, | ||
268 | * connector, etc., rather than just a single range. | ||
269 | */ | ||
270 | if (clock->dot < limit->dot.min || limit->dot.max < clock->dot) | ||
271 | INTELPllInvalid ("dot out of range\n"); | ||
272 | |||
273 | return true; | ||
274 | } | ||
275 | |||
276 | /** | ||
277 | * Returns a set of divisors for the desired target clock with the given | ||
278 | * refclk, or FALSE. The returned values represent the clock equation: | ||
279 | * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2. | ||
280 | */ | ||
281 | static bool intel_find_best_PLL(struct drm_crtc *crtc, int target, | ||
282 | int refclk, intel_clock_t *best_clock) | ||
283 | { | ||
284 | struct drm_device *dev = crtc->dev; | ||
285 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
286 | intel_clock_t clock; | ||
287 | const intel_limit_t *limit = intel_limit(crtc); | ||
288 | int err = target; | ||
289 | |||
290 | if (IS_I9XX(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && | ||
291 | (I915_READ(LVDS) & LVDS_PORT_EN) != 0) { | ||
292 | /* | ||
293 | * For LVDS, if the panel is on, just rely on its current | ||
294 | * settings for dual-channel. We haven't figured out how to | ||
295 | * reliably set up different single/dual channel state, if we | ||
296 | * even can. | ||
297 | */ | ||
298 | if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) == | ||
299 | LVDS_CLKB_POWER_UP) | ||
300 | clock.p2 = limit->p2.p2_fast; | ||
301 | else | ||
302 | clock.p2 = limit->p2.p2_slow; | ||
303 | } else { | ||
304 | if (target < limit->p2.dot_limit) | ||
305 | clock.p2 = limit->p2.p2_slow; | ||
306 | else | ||
307 | clock.p2 = limit->p2.p2_fast; | ||
308 | } | ||
309 | |||
310 | memset (best_clock, 0, sizeof (*best_clock)); | ||
311 | |||
312 | for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) { | ||
313 | for (clock.m2 = limit->m2.min; clock.m2 < clock.m1 && | ||
314 | clock.m2 <= limit->m2.max; clock.m2++) { | ||
315 | for (clock.n = limit->n.min; clock.n <= limit->n.max; | ||
316 | clock.n++) { | ||
317 | for (clock.p1 = limit->p1.min; | ||
318 | clock.p1 <= limit->p1.max; clock.p1++) { | ||
319 | int this_err; | ||
320 | |||
321 | intel_clock(dev, refclk, &clock); | ||
322 | |||
323 | if (!intel_PLL_is_valid(crtc, &clock)) | ||
324 | continue; | ||
325 | |||
326 | this_err = abs(clock.dot - target); | ||
327 | if (this_err < err) { | ||
328 | *best_clock = clock; | ||
329 | err = this_err; | ||
330 | } | ||
331 | } | ||
332 | } | ||
333 | } | ||
334 | } | ||
335 | |||
336 | return (err != target); | ||
337 | } | ||
338 | |||
339 | void | ||
340 | intel_wait_for_vblank(struct drm_device *dev) | ||
341 | { | ||
342 | /* Wait for 20ms, i.e. one cycle at 50hz. */ | ||
343 | udelay(20000); | ||
344 | } | ||
345 | |||
346 | void | ||
347 | intel_pipe_set_base(struct drm_crtc *crtc, int x, int y) | ||
348 | { | ||
349 | struct drm_device *dev = crtc->dev; | ||
350 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
351 | struct drm_i915_master_private *master_priv; | ||
352 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
353 | struct intel_framebuffer *intel_fb; | ||
354 | struct drm_i915_gem_object *obj_priv; | ||
355 | struct drm_gem_object *obj; | ||
356 | int pipe = intel_crtc->pipe; | ||
357 | unsigned long Start, Offset; | ||
358 | int dspbase = (pipe == 0 ? DSPAADDR : DSPBADDR); | ||
359 | int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF); | ||
360 | int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE; | ||
361 | int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; | ||
362 | u32 dspcntr; | ||
363 | |||
364 | /* no fb bound */ | ||
365 | if (!crtc->fb) { | ||
366 | DRM_DEBUG("No FB bound\n"); | ||
367 | return; | ||
368 | } | ||
369 | |||
370 | intel_fb = to_intel_framebuffer(crtc->fb); | ||
371 | |||
372 | obj = intel_fb->obj; | ||
373 | obj_priv = obj->driver_private; | ||
374 | |||
375 | Start = obj_priv->gtt_offset; | ||
376 | Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8); | ||
377 | |||
378 | I915_WRITE(dspstride, crtc->fb->pitch); | ||
379 | |||
380 | dspcntr = I915_READ(dspcntr_reg); | ||
381 | switch (crtc->fb->bits_per_pixel) { | ||
382 | case 8: | ||
383 | dspcntr |= DISPPLANE_8BPP; | ||
384 | break; | ||
385 | case 16: | ||
386 | if (crtc->fb->depth == 15) | ||
387 | dspcntr |= DISPPLANE_15_16BPP; | ||
388 | else | ||
389 | dspcntr |= DISPPLANE_16BPP; | ||
390 | break; | ||
391 | case 24: | ||
392 | case 32: | ||
393 | dspcntr |= DISPPLANE_32BPP_NO_ALPHA; | ||
394 | break; | ||
395 | default: | ||
396 | DRM_ERROR("Unknown color depth\n"); | ||
397 | return; | ||
398 | } | ||
399 | I915_WRITE(dspcntr_reg, dspcntr); | ||
400 | |||
401 | DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y); | ||
402 | if (IS_I965G(dev)) { | ||
403 | I915_WRITE(dspbase, Offset); | ||
404 | I915_READ(dspbase); | ||
405 | I915_WRITE(dspsurf, Start); | ||
406 | I915_READ(dspsurf); | ||
407 | } else { | ||
408 | I915_WRITE(dspbase, Start + Offset); | ||
409 | I915_READ(dspbase); | ||
410 | } | ||
411 | |||
412 | |||
413 | if (!dev->primary->master) | ||
414 | return; | ||
415 | |||
416 | master_priv = dev->primary->master->driver_priv; | ||
417 | if (!master_priv->sarea_priv) | ||
418 | return; | ||
419 | |||
420 | switch (pipe) { | ||
421 | case 0: | ||
422 | master_priv->sarea_priv->pipeA_x = x; | ||
423 | master_priv->sarea_priv->pipeA_y = y; | ||
424 | break; | ||
425 | case 1: | ||
426 | master_priv->sarea_priv->pipeB_x = x; | ||
427 | master_priv->sarea_priv->pipeB_y = y; | ||
428 | break; | ||
429 | default: | ||
430 | DRM_ERROR("Can't update pipe %d in SAREA\n", pipe); | ||
431 | break; | ||
432 | } | ||
433 | } | ||
434 | |||
435 | |||
436 | |||
437 | /** | ||
438 | * Sets the power management mode of the pipe and plane. | ||
439 | * | ||
440 | * This code should probably grow support for turning the cursor off and back | ||
441 | * on appropriately at the same time as we're turning the pipe off/on. | ||
442 | */ | ||
443 | static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) | ||
444 | { | ||
445 | struct drm_device *dev = crtc->dev; | ||
446 | struct drm_i915_master_private *master_priv; | ||
447 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
448 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
449 | int pipe = intel_crtc->pipe; | ||
450 | int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; | ||
451 | int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; | ||
452 | int dspbase_reg = (pipe == 0) ? DSPAADDR : DSPBADDR; | ||
453 | int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; | ||
454 | u32 temp; | ||
455 | bool enabled; | ||
456 | |||
457 | /* XXX: When our outputs are all unaware of DPMS modes other than off | ||
458 | * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. | ||
459 | */ | ||
460 | switch (mode) { | ||
461 | case DRM_MODE_DPMS_ON: | ||
462 | case DRM_MODE_DPMS_STANDBY: | ||
463 | case DRM_MODE_DPMS_SUSPEND: | ||
464 | /* Enable the DPLL */ | ||
465 | temp = I915_READ(dpll_reg); | ||
466 | if ((temp & DPLL_VCO_ENABLE) == 0) { | ||
467 | I915_WRITE(dpll_reg, temp); | ||
468 | I915_READ(dpll_reg); | ||
469 | /* Wait for the clocks to stabilize. */ | ||
470 | udelay(150); | ||
471 | I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); | ||
472 | I915_READ(dpll_reg); | ||
473 | /* Wait for the clocks to stabilize. */ | ||
474 | udelay(150); | ||
475 | I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); | ||
476 | I915_READ(dpll_reg); | ||
477 | /* Wait for the clocks to stabilize. */ | ||
478 | udelay(150); | ||
479 | } | ||
480 | |||
481 | /* Enable the pipe */ | ||
482 | temp = I915_READ(pipeconf_reg); | ||
483 | if ((temp & PIPEACONF_ENABLE) == 0) | ||
484 | I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE); | ||
485 | |||
486 | /* Enable the plane */ | ||
487 | temp = I915_READ(dspcntr_reg); | ||
488 | if ((temp & DISPLAY_PLANE_ENABLE) == 0) { | ||
489 | I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE); | ||
490 | /* Flush the plane changes */ | ||
491 | I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); | ||
492 | } | ||
493 | |||
494 | intel_crtc_load_lut(crtc); | ||
495 | |||
496 | /* Give the overlay scaler a chance to enable if it's on this pipe */ | ||
497 | //intel_crtc_dpms_video(crtc, true); TODO | ||
498 | break; | ||
499 | case DRM_MODE_DPMS_OFF: | ||
500 | /* Give the overlay scaler a chance to disable if it's on this pipe */ | ||
501 | //intel_crtc_dpms_video(crtc, FALSE); TODO | ||
502 | |||
503 | /* Disable the VGA plane that we never use */ | ||
504 | I915_WRITE(VGACNTRL, VGA_DISP_DISABLE); | ||
505 | |||
506 | /* Disable display plane */ | ||
507 | temp = I915_READ(dspcntr_reg); | ||
508 | if ((temp & DISPLAY_PLANE_ENABLE) != 0) { | ||
509 | I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); | ||
510 | /* Flush the plane changes */ | ||
511 | I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); | ||
512 | I915_READ(dspbase_reg); | ||
513 | } | ||
514 | |||
515 | if (!IS_I9XX(dev)) { | ||
516 | /* Wait for vblank for the disable to take effect */ | ||
517 | intel_wait_for_vblank(dev); | ||
518 | } | ||
519 | |||
520 | /* Next, disable display pipes */ | ||
521 | temp = I915_READ(pipeconf_reg); | ||
522 | if ((temp & PIPEACONF_ENABLE) != 0) { | ||
523 | I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); | ||
524 | I915_READ(pipeconf_reg); | ||
525 | } | ||
526 | |||
527 | /* Wait for vblank for the disable to take effect. */ | ||
528 | intel_wait_for_vblank(dev); | ||
529 | |||
530 | temp = I915_READ(dpll_reg); | ||
531 | if ((temp & DPLL_VCO_ENABLE) != 0) { | ||
532 | I915_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE); | ||
533 | I915_READ(dpll_reg); | ||
534 | } | ||
535 | |||
536 | /* Wait for the clocks to turn off. */ | ||
537 | udelay(150); | ||
538 | break; | ||
539 | } | ||
540 | |||
541 | if (!dev->primary->master) | ||
542 | return; | ||
543 | |||
544 | master_priv = dev->primary->master->driver_priv; | ||
545 | if (!master_priv->sarea_priv) | ||
546 | return; | ||
547 | |||
548 | enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF; | ||
549 | |||
550 | switch (pipe) { | ||
551 | case 0: | ||
552 | master_priv->sarea_priv->pipeA_w = enabled ? crtc->mode.hdisplay : 0; | ||
553 | master_priv->sarea_priv->pipeA_h = enabled ? crtc->mode.vdisplay : 0; | ||
554 | break; | ||
555 | case 1: | ||
556 | master_priv->sarea_priv->pipeB_w = enabled ? crtc->mode.hdisplay : 0; | ||
557 | master_priv->sarea_priv->pipeB_h = enabled ? crtc->mode.vdisplay : 0; | ||
558 | break; | ||
559 | default: | ||
560 | DRM_ERROR("Can't update pipe %d in SAREA\n", pipe); | ||
561 | break; | ||
562 | } | ||
563 | |||
564 | intel_crtc->dpms_mode = mode; | ||
565 | } | ||
566 | |||
567 | static void intel_crtc_prepare (struct drm_crtc *crtc) | ||
568 | { | ||
569 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
570 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); | ||
571 | } | ||
572 | |||
573 | static void intel_crtc_commit (struct drm_crtc *crtc) | ||
574 | { | ||
575 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
576 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); | ||
577 | } | ||
578 | |||
579 | void intel_encoder_prepare (struct drm_encoder *encoder) | ||
580 | { | ||
581 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; | ||
582 | /* lvds has its own version of prepare see intel_lvds_prepare */ | ||
583 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF); | ||
584 | } | ||
585 | |||
586 | void intel_encoder_commit (struct drm_encoder *encoder) | ||
587 | { | ||
588 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; | ||
589 | /* lvds has its own version of commit see intel_lvds_commit */ | ||
590 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); | ||
591 | } | ||
592 | |||
593 | static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, | ||
594 | struct drm_display_mode *mode, | ||
595 | struct drm_display_mode *adjusted_mode) | ||
596 | { | ||
597 | return true; | ||
598 | } | ||
599 | |||
600 | |||
601 | /** Returns the core display clock speed for i830 - i945 */ | ||
602 | static int intel_get_core_clock_speed(struct drm_device *dev) | ||
603 | { | ||
604 | |||
605 | /* Core clock values taken from the published datasheets. | ||
606 | * The 830 may go up to 166 Mhz, which we should check. | ||
607 | */ | ||
608 | if (IS_I945G(dev)) | ||
609 | return 400000; | ||
610 | else if (IS_I915G(dev)) | ||
611 | return 333000; | ||
612 | else if (IS_I945GM(dev) || IS_845G(dev)) | ||
613 | return 200000; | ||
614 | else if (IS_I915GM(dev)) { | ||
615 | u16 gcfgc = 0; | ||
616 | |||
617 | pci_read_config_word(dev->pdev, GCFGC, &gcfgc); | ||
618 | |||
619 | if (gcfgc & GC_LOW_FREQUENCY_ENABLE) | ||
620 | return 133000; | ||
621 | else { | ||
622 | switch (gcfgc & GC_DISPLAY_CLOCK_MASK) { | ||
623 | case GC_DISPLAY_CLOCK_333_MHZ: | ||
624 | return 333000; | ||
625 | default: | ||
626 | case GC_DISPLAY_CLOCK_190_200_MHZ: | ||
627 | return 190000; | ||
628 | } | ||
629 | } | ||
630 | } else if (IS_I865G(dev)) | ||
631 | return 266000; | ||
632 | else if (IS_I855(dev)) { | ||
633 | u16 hpllcc = 0; | ||
634 | /* Assume that the hardware is in the high speed state. This | ||
635 | * should be the default. | ||
636 | */ | ||
637 | switch (hpllcc & GC_CLOCK_CONTROL_MASK) { | ||
638 | case GC_CLOCK_133_200: | ||
639 | case GC_CLOCK_100_200: | ||
640 | return 200000; | ||
641 | case GC_CLOCK_166_250: | ||
642 | return 250000; | ||
643 | case GC_CLOCK_100_133: | ||
644 | return 133000; | ||
645 | } | ||
646 | } else /* 852, 830 */ | ||
647 | return 133000; | ||
648 | |||
649 | return 0; /* Silence gcc warning */ | ||
650 | } | ||
651 | |||
652 | |||
653 | /** | ||
654 | * Return the pipe currently connected to the panel fitter, | ||
655 | * or -1 if the panel fitter is not present or not in use | ||
656 | */ | ||
657 | static int intel_panel_fitter_pipe (struct drm_device *dev) | ||
658 | { | ||
659 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
660 | u32 pfit_control; | ||
661 | |||
662 | /* i830 doesn't have a panel fitter */ | ||
663 | if (IS_I830(dev)) | ||
664 | return -1; | ||
665 | |||
666 | pfit_control = I915_READ(PFIT_CONTROL); | ||
667 | |||
668 | /* See if the panel fitter is in use */ | ||
669 | if ((pfit_control & PFIT_ENABLE) == 0) | ||
670 | return -1; | ||
671 | |||
672 | /* 965 can place panel fitter on either pipe */ | ||
673 | if (IS_I965G(dev)) | ||
674 | return (pfit_control >> 29) & 0x3; | ||
675 | |||
676 | /* older chips can only use pipe 1 */ | ||
677 | return 1; | ||
678 | } | ||
679 | |||
680 | static void intel_crtc_mode_set(struct drm_crtc *crtc, | ||
681 | struct drm_display_mode *mode, | ||
682 | struct drm_display_mode *adjusted_mode, | ||
683 | int x, int y) | ||
684 | { | ||
685 | struct drm_device *dev = crtc->dev; | ||
686 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
687 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
688 | int pipe = intel_crtc->pipe; | ||
689 | int fp_reg = (pipe == 0) ? FPA0 : FPB0; | ||
690 | int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; | ||
691 | int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD; | ||
692 | int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; | ||
693 | int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; | ||
694 | int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; | ||
695 | int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; | ||
696 | int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; | ||
697 | int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; | ||
698 | int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; | ||
699 | int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; | ||
700 | int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE; | ||
701 | int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS; | ||
702 | int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC; | ||
703 | int refclk; | ||
704 | intel_clock_t clock; | ||
705 | u32 dpll = 0, fp = 0, dspcntr, pipeconf; | ||
706 | bool ok, is_sdvo = false, is_dvo = false; | ||
707 | bool is_crt = false, is_lvds = false, is_tv = false; | ||
708 | struct drm_mode_config *mode_config = &dev->mode_config; | ||
709 | struct drm_connector *connector; | ||
710 | |||
711 | drm_vblank_pre_modeset(dev, pipe); | ||
712 | |||
713 | list_for_each_entry(connector, &mode_config->connector_list, head) { | ||
714 | struct intel_output *intel_output = to_intel_output(connector); | ||
715 | |||
716 | if (!connector->encoder || connector->encoder->crtc != crtc) | ||
717 | continue; | ||
718 | |||
719 | switch (intel_output->type) { | ||
720 | case INTEL_OUTPUT_LVDS: | ||
721 | is_lvds = true; | ||
722 | break; | ||
723 | case INTEL_OUTPUT_SDVO: | ||
724 | is_sdvo = true; | ||
725 | break; | ||
726 | case INTEL_OUTPUT_DVO: | ||
727 | is_dvo = true; | ||
728 | break; | ||
729 | case INTEL_OUTPUT_TVOUT: | ||
730 | is_tv = true; | ||
731 | break; | ||
732 | case INTEL_OUTPUT_ANALOG: | ||
733 | is_crt = true; | ||
734 | break; | ||
735 | } | ||
736 | } | ||
737 | |||
738 | if (IS_I9XX(dev)) { | ||
739 | refclk = 96000; | ||
740 | } else { | ||
741 | refclk = 48000; | ||
742 | } | ||
743 | |||
744 | ok = intel_find_best_PLL(crtc, adjusted_mode->clock, refclk, &clock); | ||
745 | if (!ok) { | ||
746 | DRM_ERROR("Couldn't find PLL settings for mode!\n"); | ||
747 | return; | ||
748 | } | ||
749 | |||
750 | fp = clock.n << 16 | clock.m1 << 8 | clock.m2; | ||
751 | |||
752 | dpll = DPLL_VGA_MODE_DIS; | ||
753 | if (IS_I9XX(dev)) { | ||
754 | if (is_lvds) | ||
755 | dpll |= DPLLB_MODE_LVDS; | ||
756 | else | ||
757 | dpll |= DPLLB_MODE_DAC_SERIAL; | ||
758 | if (is_sdvo) { | ||
759 | dpll |= DPLL_DVO_HIGH_SPEED; | ||
760 | if (IS_I945G(dev) || IS_I945GM(dev)) { | ||
761 | int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; | ||
762 | dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; | ||
763 | } | ||
764 | } | ||
765 | |||
766 | /* compute bitmask from p1 value */ | ||
767 | dpll |= (1 << (clock.p1 - 1)) << 16; | ||
768 | switch (clock.p2) { | ||
769 | case 5: | ||
770 | dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; | ||
771 | break; | ||
772 | case 7: | ||
773 | dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7; | ||
774 | break; | ||
775 | case 10: | ||
776 | dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10; | ||
777 | break; | ||
778 | case 14: | ||
779 | dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; | ||
780 | break; | ||
781 | } | ||
782 | if (IS_I965G(dev)) | ||
783 | dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); | ||
784 | } else { | ||
785 | if (is_lvds) { | ||
786 | dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; | ||
787 | } else { | ||
788 | if (clock.p1 == 2) | ||
789 | dpll |= PLL_P1_DIVIDE_BY_TWO; | ||
790 | else | ||
791 | dpll |= (clock.p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT; | ||
792 | if (clock.p2 == 4) | ||
793 | dpll |= PLL_P2_DIVIDE_BY_4; | ||
794 | } | ||
795 | } | ||
796 | |||
797 | if (is_tv) { | ||
798 | /* XXX: just matching BIOS for now */ | ||
799 | /* dpll |= PLL_REF_INPUT_TVCLKINBC; */ | ||
800 | dpll |= 3; | ||
801 | } | ||
802 | else | ||
803 | dpll |= PLL_REF_INPUT_DREFCLK; | ||
804 | |||
805 | /* setup pipeconf */ | ||
806 | pipeconf = I915_READ(pipeconf_reg); | ||
807 | |||
808 | /* Set up the display plane register */ | ||
809 | dspcntr = DISPPLANE_GAMMA_ENABLE; | ||
810 | |||
811 | if (pipe == 0) | ||
812 | dspcntr |= DISPPLANE_SEL_PIPE_A; | ||
813 | else | ||
814 | dspcntr |= DISPPLANE_SEL_PIPE_B; | ||
815 | |||
816 | if (pipe == 0 && !IS_I965G(dev)) { | ||
817 | /* Enable pixel doubling when the dot clock is > 90% of the (display) | ||
818 | * core speed. | ||
819 | * | ||
820 | * XXX: No double-wide on 915GM pipe B. Is that the only reason for the | ||
821 | * pipe == 0 check? | ||
822 | */ | ||
823 | if (mode->clock > intel_get_core_clock_speed(dev) * 9 / 10) | ||
824 | pipeconf |= PIPEACONF_DOUBLE_WIDE; | ||
825 | else | ||
826 | pipeconf &= ~PIPEACONF_DOUBLE_WIDE; | ||
827 | } | ||
828 | |||
829 | dspcntr |= DISPLAY_PLANE_ENABLE; | ||
830 | pipeconf |= PIPEACONF_ENABLE; | ||
831 | dpll |= DPLL_VCO_ENABLE; | ||
832 | |||
833 | |||
834 | /* Disable the panel fitter if it was on our pipe */ | ||
835 | if (intel_panel_fitter_pipe(dev) == pipe) | ||
836 | I915_WRITE(PFIT_CONTROL, 0); | ||
837 | |||
838 | DRM_DEBUG("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); | ||
839 | drm_mode_debug_printmodeline(mode); | ||
840 | |||
841 | |||
842 | if (dpll & DPLL_VCO_ENABLE) { | ||
843 | I915_WRITE(fp_reg, fp); | ||
844 | I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE); | ||
845 | I915_READ(dpll_reg); | ||
846 | udelay(150); | ||
847 | } | ||
848 | |||
849 | /* The LVDS pin pair needs to be on before the DPLLs are enabled. | ||
850 | * This is an exception to the general rule that mode_set doesn't turn | ||
851 | * things on. | ||
852 | */ | ||
853 | if (is_lvds) { | ||
854 | u32 lvds = I915_READ(LVDS); | ||
855 | |||
856 | lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT; | ||
857 | /* Set the B0-B3 data pairs corresponding to whether we're going to | ||
858 | * set the DPLLs for dual-channel mode or not. | ||
859 | */ | ||
860 | if (clock.p2 == 7) | ||
861 | lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; | ||
862 | else | ||
863 | lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); | ||
864 | |||
865 | /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) | ||
866 | * appropriately here, but we need to look more thoroughly into how | ||
867 | * panels behave in the two modes. | ||
868 | */ | ||
869 | |||
870 | I915_WRITE(LVDS, lvds); | ||
871 | I915_READ(LVDS); | ||
872 | } | ||
873 | |||
874 | I915_WRITE(fp_reg, fp); | ||
875 | I915_WRITE(dpll_reg, dpll); | ||
876 | I915_READ(dpll_reg); | ||
877 | /* Wait for the clocks to stabilize. */ | ||
878 | udelay(150); | ||
879 | |||
880 | if (IS_I965G(dev)) { | ||
881 | int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; | ||
882 | I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | | ||
883 | ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); | ||
884 | } else { | ||
885 | /* write it again -- the BIOS does, after all */ | ||
886 | I915_WRITE(dpll_reg, dpll); | ||
887 | } | ||
888 | I915_READ(dpll_reg); | ||
889 | /* Wait for the clocks to stabilize. */ | ||
890 | udelay(150); | ||
891 | |||
892 | I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) | | ||
893 | ((adjusted_mode->crtc_htotal - 1) << 16)); | ||
894 | I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | | ||
895 | ((adjusted_mode->crtc_hblank_end - 1) << 16)); | ||
896 | I915_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | | ||
897 | ((adjusted_mode->crtc_hsync_end - 1) << 16)); | ||
898 | I915_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | | ||
899 | ((adjusted_mode->crtc_vtotal - 1) << 16)); | ||
900 | I915_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | | ||
901 | ((adjusted_mode->crtc_vblank_end - 1) << 16)); | ||
902 | I915_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | | ||
903 | ((adjusted_mode->crtc_vsync_end - 1) << 16)); | ||
904 | /* pipesrc and dspsize control the size that is scaled from, which should | ||
905 | * always be the user's requested size. | ||
906 | */ | ||
907 | I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); | ||
908 | I915_WRITE(dsppos_reg, 0); | ||
909 | I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); | ||
910 | I915_WRITE(pipeconf_reg, pipeconf); | ||
911 | I915_READ(pipeconf_reg); | ||
912 | |||
913 | intel_wait_for_vblank(dev); | ||
914 | |||
915 | I915_WRITE(dspcntr_reg, dspcntr); | ||
916 | |||
917 | /* Flush the plane changes */ | ||
918 | intel_pipe_set_base(crtc, x, y); | ||
919 | |||
920 | intel_wait_for_vblank(dev); | ||
921 | |||
922 | drm_vblank_post_modeset(dev, pipe); | ||
923 | } | ||
924 | |||
925 | /** Loads the palette/gamma unit for the CRTC with the prepared values */ | ||
926 | void intel_crtc_load_lut(struct drm_crtc *crtc) | ||
927 | { | ||
928 | struct drm_device *dev = crtc->dev; | ||
929 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
930 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
931 | int palreg = (intel_crtc->pipe == 0) ? PALETTE_A : PALETTE_B; | ||
932 | int i; | ||
933 | |||
934 | /* The clocks have to be on to load the palette. */ | ||
935 | if (!crtc->enabled) | ||
936 | return; | ||
937 | |||
938 | for (i = 0; i < 256; i++) { | ||
939 | I915_WRITE(palreg + 4 * i, | ||
940 | (intel_crtc->lut_r[i] << 16) | | ||
941 | (intel_crtc->lut_g[i] << 8) | | ||
942 | intel_crtc->lut_b[i]); | ||
943 | } | ||
944 | } | ||
945 | |||
946 | static int intel_crtc_cursor_set(struct drm_crtc *crtc, | ||
947 | struct drm_file *file_priv, | ||
948 | uint32_t handle, | ||
949 | uint32_t width, uint32_t height) | ||
950 | { | ||
951 | struct drm_device *dev = crtc->dev; | ||
952 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
953 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
954 | struct drm_gem_object *bo; | ||
955 | struct drm_i915_gem_object *obj_priv; | ||
956 | int pipe = intel_crtc->pipe; | ||
957 | uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR; | ||
958 | uint32_t base = (pipe == 0) ? CURABASE : CURBBASE; | ||
959 | uint32_t temp; | ||
960 | size_t addr; | ||
961 | |||
962 | DRM_DEBUG("\n"); | ||
963 | |||
964 | /* if we want to turn off the cursor ignore width and height */ | ||
965 | if (!handle) { | ||
966 | DRM_DEBUG("cursor off\n"); | ||
967 | /* turn of the cursor */ | ||
968 | temp = 0; | ||
969 | temp |= CURSOR_MODE_DISABLE; | ||
970 | |||
971 | I915_WRITE(control, temp); | ||
972 | I915_WRITE(base, 0); | ||
973 | return 0; | ||
974 | } | ||
975 | |||
976 | /* Currently we only support 64x64 cursors */ | ||
977 | if (width != 64 || height != 64) { | ||
978 | DRM_ERROR("we currently only support 64x64 cursors\n"); | ||
979 | return -EINVAL; | ||
980 | } | ||
981 | |||
982 | bo = drm_gem_object_lookup(dev, file_priv, handle); | ||
983 | if (!bo) | ||
984 | return -ENOENT; | ||
985 | |||
986 | obj_priv = bo->driver_private; | ||
987 | |||
988 | if (bo->size < width * height * 4) { | ||
989 | DRM_ERROR("buffer is to small\n"); | ||
990 | drm_gem_object_unreference(bo); | ||
991 | return -ENOMEM; | ||
992 | } | ||
993 | |||
994 | if (dev_priv->cursor_needs_physical) { | ||
995 | addr = dev->agp->base + obj_priv->gtt_offset; | ||
996 | } else { | ||
997 | addr = obj_priv->gtt_offset; | ||
998 | } | ||
999 | |||
1000 | intel_crtc->cursor_addr = addr; | ||
1001 | temp = 0; | ||
1002 | /* set the pipe for the cursor */ | ||
1003 | temp |= (pipe << 28); | ||
1004 | temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; | ||
1005 | |||
1006 | I915_WRITE(control, temp); | ||
1007 | I915_WRITE(base, addr); | ||
1008 | |||
1009 | return 0; | ||
1010 | } | ||
1011 | |||
1012 | static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) | ||
1013 | { | ||
1014 | struct drm_device *dev = crtc->dev; | ||
1015 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
1016 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
1017 | int pipe = intel_crtc->pipe; | ||
1018 | uint32_t temp = 0; | ||
1019 | uint32_t adder; | ||
1020 | |||
1021 | if (x < 0) { | ||
1022 | temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT); | ||
1023 | x = -x; | ||
1024 | } | ||
1025 | if (y < 0) { | ||
1026 | temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT); | ||
1027 | y = -y; | ||
1028 | } | ||
1029 | |||
1030 | temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT); | ||
1031 | temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); | ||
1032 | |||
1033 | adder = intel_crtc->cursor_addr; | ||
1034 | I915_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp); | ||
1035 | I915_WRITE((pipe == 0) ? CURABASE : CURBBASE, adder); | ||
1036 | |||
1037 | return 0; | ||
1038 | } | ||
1039 | |||
1040 | /** Sets the color ramps on behalf of RandR */ | ||
1041 | void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, | ||
1042 | u16 blue, int regno) | ||
1043 | { | ||
1044 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
1045 | |||
1046 | intel_crtc->lut_r[regno] = red >> 8; | ||
1047 | intel_crtc->lut_g[regno] = green >> 8; | ||
1048 | intel_crtc->lut_b[regno] = blue >> 8; | ||
1049 | } | ||
1050 | |||
1051 | static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, | ||
1052 | u16 *blue, uint32_t size) | ||
1053 | { | ||
1054 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
1055 | int i; | ||
1056 | |||
1057 | if (size != 256) | ||
1058 | return; | ||
1059 | |||
1060 | for (i = 0; i < 256; i++) { | ||
1061 | intel_crtc->lut_r[i] = red[i] >> 8; | ||
1062 | intel_crtc->lut_g[i] = green[i] >> 8; | ||
1063 | intel_crtc->lut_b[i] = blue[i] >> 8; | ||
1064 | } | ||
1065 | |||
1066 | intel_crtc_load_lut(crtc); | ||
1067 | } | ||
1068 | |||
1069 | /** | ||
1070 | * Get a pipe with a simple mode set on it for doing load-based monitor | ||
1071 | * detection. | ||
1072 | * | ||
1073 | * It will be up to the load-detect code to adjust the pipe as appropriate for | ||
1074 | * its requirements. The pipe will be connected to no other outputs. | ||
1075 | * | ||
1076 | * Currently this code will only succeed if there is a pipe with no outputs | ||
1077 | * configured for it. In the future, it could choose to temporarily disable | ||
1078 | * some outputs to free up a pipe for its use. | ||
1079 | * | ||
1080 | * \return crtc, or NULL if no pipes are available. | ||
1081 | */ | ||
1082 | |||
1083 | /* VESA 640x480x72Hz mode to set on the pipe */ | ||
1084 | static struct drm_display_mode load_detect_mode = { | ||
1085 | DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664, | ||
1086 | 704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
1087 | }; | ||
1088 | |||
1089 | struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output, | ||
1090 | struct drm_display_mode *mode, | ||
1091 | int *dpms_mode) | ||
1092 | { | ||
1093 | struct intel_crtc *intel_crtc; | ||
1094 | struct drm_crtc *possible_crtc; | ||
1095 | struct drm_crtc *supported_crtc =NULL; | ||
1096 | struct drm_encoder *encoder = &intel_output->enc; | ||
1097 | struct drm_crtc *crtc = NULL; | ||
1098 | struct drm_device *dev = encoder->dev; | ||
1099 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; | ||
1100 | struct drm_crtc_helper_funcs *crtc_funcs; | ||
1101 | int i = -1; | ||
1102 | |||
1103 | /* | ||
1104 | * Algorithm gets a little messy: | ||
1105 | * - if the connector already has an assigned crtc, use it (but make | ||
1106 | * sure it's on first) | ||
1107 | * - try to find the first unused crtc that can drive this connector, | ||
1108 | * and use that if we find one | ||
1109 | * - if there are no unused crtcs available, try to use the first | ||
1110 | * one we found that supports the connector | ||
1111 | */ | ||
1112 | |||
1113 | /* See if we already have a CRTC for this connector */ | ||
1114 | if (encoder->crtc) { | ||
1115 | crtc = encoder->crtc; | ||
1116 | /* Make sure the crtc and connector are running */ | ||
1117 | intel_crtc = to_intel_crtc(crtc); | ||
1118 | *dpms_mode = intel_crtc->dpms_mode; | ||
1119 | if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) { | ||
1120 | crtc_funcs = crtc->helper_private; | ||
1121 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); | ||
1122 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); | ||
1123 | } | ||
1124 | return crtc; | ||
1125 | } | ||
1126 | |||
1127 | /* Find an unused one (if possible) */ | ||
1128 | list_for_each_entry(possible_crtc, &dev->mode_config.crtc_list, head) { | ||
1129 | i++; | ||
1130 | if (!(encoder->possible_crtcs & (1 << i))) | ||
1131 | continue; | ||
1132 | if (!possible_crtc->enabled) { | ||
1133 | crtc = possible_crtc; | ||
1134 | break; | ||
1135 | } | ||
1136 | if (!supported_crtc) | ||
1137 | supported_crtc = possible_crtc; | ||
1138 | } | ||
1139 | |||
1140 | /* | ||
1141 | * If we didn't find an unused CRTC, don't use any. | ||
1142 | */ | ||
1143 | if (!crtc) { | ||
1144 | return NULL; | ||
1145 | } | ||
1146 | |||
1147 | encoder->crtc = crtc; | ||
1148 | intel_output->load_detect_temp = true; | ||
1149 | |||
1150 | intel_crtc = to_intel_crtc(crtc); | ||
1151 | *dpms_mode = intel_crtc->dpms_mode; | ||
1152 | |||
1153 | if (!crtc->enabled) { | ||
1154 | if (!mode) | ||
1155 | mode = &load_detect_mode; | ||
1156 | drm_crtc_helper_set_mode(crtc, mode, 0, 0); | ||
1157 | } else { | ||
1158 | if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) { | ||
1159 | crtc_funcs = crtc->helper_private; | ||
1160 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); | ||
1161 | } | ||
1162 | |||
1163 | /* Add this connector to the crtc */ | ||
1164 | encoder_funcs->mode_set(encoder, &crtc->mode, &crtc->mode); | ||
1165 | encoder_funcs->commit(encoder); | ||
1166 | } | ||
1167 | /* let the connector get through one full cycle before testing */ | ||
1168 | intel_wait_for_vblank(dev); | ||
1169 | |||
1170 | return crtc; | ||
1171 | } | ||
1172 | |||
1173 | void intel_release_load_detect_pipe(struct intel_output *intel_output, int dpms_mode) | ||
1174 | { | ||
1175 | struct drm_encoder *encoder = &intel_output->enc; | ||
1176 | struct drm_device *dev = encoder->dev; | ||
1177 | struct drm_crtc *crtc = encoder->crtc; | ||
1178 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; | ||
1179 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
1180 | |||
1181 | if (intel_output->load_detect_temp) { | ||
1182 | encoder->crtc = NULL; | ||
1183 | intel_output->load_detect_temp = false; | ||
1184 | crtc->enabled = drm_helper_crtc_in_use(crtc); | ||
1185 | drm_helper_disable_unused_functions(dev); | ||
1186 | } | ||
1187 | |||
1188 | /* Switch crtc and output back off if necessary */ | ||
1189 | if (crtc->enabled && dpms_mode != DRM_MODE_DPMS_ON) { | ||
1190 | if (encoder->crtc == crtc) | ||
1191 | encoder_funcs->dpms(encoder, dpms_mode); | ||
1192 | crtc_funcs->dpms(crtc, dpms_mode); | ||
1193 | } | ||
1194 | } | ||
1195 | |||
1196 | /* Returns the clock of the currently programmed mode of the given pipe. */ | ||
1197 | static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) | ||
1198 | { | ||
1199 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
1200 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
1201 | int pipe = intel_crtc->pipe; | ||
1202 | u32 dpll = I915_READ((pipe == 0) ? DPLL_A : DPLL_B); | ||
1203 | u32 fp; | ||
1204 | intel_clock_t clock; | ||
1205 | |||
1206 | if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) | ||
1207 | fp = I915_READ((pipe == 0) ? FPA0 : FPB0); | ||
1208 | else | ||
1209 | fp = I915_READ((pipe == 0) ? FPA1 : FPB1); | ||
1210 | |||
1211 | clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; | ||
1212 | clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; | ||
1213 | clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT; | ||
1214 | if (IS_I9XX(dev)) { | ||
1215 | clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >> | ||
1216 | DPLL_FPA01_P1_POST_DIV_SHIFT); | ||
1217 | |||
1218 | switch (dpll & DPLL_MODE_MASK) { | ||
1219 | case DPLLB_MODE_DAC_SERIAL: | ||
1220 | clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? | ||
1221 | 5 : 10; | ||
1222 | break; | ||
1223 | case DPLLB_MODE_LVDS: | ||
1224 | clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ? | ||
1225 | 7 : 14; | ||
1226 | break; | ||
1227 | default: | ||
1228 | DRM_DEBUG("Unknown DPLL mode %08x in programmed " | ||
1229 | "mode\n", (int)(dpll & DPLL_MODE_MASK)); | ||
1230 | return 0; | ||
1231 | } | ||
1232 | |||
1233 | /* XXX: Handle the 100Mhz refclk */ | ||
1234 | i9xx_clock(96000, &clock); | ||
1235 | } else { | ||
1236 | bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN); | ||
1237 | |||
1238 | if (is_lvds) { | ||
1239 | clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> | ||
1240 | DPLL_FPA01_P1_POST_DIV_SHIFT); | ||
1241 | clock.p2 = 14; | ||
1242 | |||
1243 | if ((dpll & PLL_REF_INPUT_MASK) == | ||
1244 | PLLB_REF_INPUT_SPREADSPECTRUMIN) { | ||
1245 | /* XXX: might not be 66MHz */ | ||
1246 | i8xx_clock(66000, &clock); | ||
1247 | } else | ||
1248 | i8xx_clock(48000, &clock); | ||
1249 | } else { | ||
1250 | if (dpll & PLL_P1_DIVIDE_BY_TWO) | ||
1251 | clock.p1 = 2; | ||
1252 | else { | ||
1253 | clock.p1 = ((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830) >> | ||
1254 | DPLL_FPA01_P1_POST_DIV_SHIFT) + 2; | ||
1255 | } | ||
1256 | if (dpll & PLL_P2_DIVIDE_BY_4) | ||
1257 | clock.p2 = 4; | ||
1258 | else | ||
1259 | clock.p2 = 2; | ||
1260 | |||
1261 | i8xx_clock(48000, &clock); | ||
1262 | } | ||
1263 | } | ||
1264 | |||
1265 | /* XXX: It would be nice to validate the clocks, but we can't reuse | ||
1266 | * i830PllIsValid() because it relies on the xf86_config connector | ||
1267 | * configuration being accurate, which it isn't necessarily. | ||
1268 | */ | ||
1269 | |||
1270 | return clock.dot; | ||
1271 | } | ||
1272 | |||
1273 | /** Returns the currently programmed mode of the given pipe. */ | ||
1274 | struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, | ||
1275 | struct drm_crtc *crtc) | ||
1276 | { | ||
1277 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
1278 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
1279 | int pipe = intel_crtc->pipe; | ||
1280 | struct drm_display_mode *mode; | ||
1281 | int htot = I915_READ((pipe == 0) ? HTOTAL_A : HTOTAL_B); | ||
1282 | int hsync = I915_READ((pipe == 0) ? HSYNC_A : HSYNC_B); | ||
1283 | int vtot = I915_READ((pipe == 0) ? VTOTAL_A : VTOTAL_B); | ||
1284 | int vsync = I915_READ((pipe == 0) ? VSYNC_A : VSYNC_B); | ||
1285 | |||
1286 | mode = kzalloc(sizeof(*mode), GFP_KERNEL); | ||
1287 | if (!mode) | ||
1288 | return NULL; | ||
1289 | |||
1290 | mode->clock = intel_crtc_clock_get(dev, crtc); | ||
1291 | mode->hdisplay = (htot & 0xffff) + 1; | ||
1292 | mode->htotal = ((htot & 0xffff0000) >> 16) + 1; | ||
1293 | mode->hsync_start = (hsync & 0xffff) + 1; | ||
1294 | mode->hsync_end = ((hsync & 0xffff0000) >> 16) + 1; | ||
1295 | mode->vdisplay = (vtot & 0xffff) + 1; | ||
1296 | mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1; | ||
1297 | mode->vsync_start = (vsync & 0xffff) + 1; | ||
1298 | mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1; | ||
1299 | |||
1300 | drm_mode_set_name(mode); | ||
1301 | drm_mode_set_crtcinfo(mode, 0); | ||
1302 | |||
1303 | return mode; | ||
1304 | } | ||
1305 | |||
1306 | static void intel_crtc_destroy(struct drm_crtc *crtc) | ||
1307 | { | ||
1308 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
1309 | |||
1310 | drm_crtc_cleanup(crtc); | ||
1311 | kfree(intel_crtc); | ||
1312 | } | ||
1313 | |||
1314 | static const struct drm_crtc_helper_funcs intel_helper_funcs = { | ||
1315 | .dpms = intel_crtc_dpms, | ||
1316 | .mode_fixup = intel_crtc_mode_fixup, | ||
1317 | .mode_set = intel_crtc_mode_set, | ||
1318 | .mode_set_base = intel_pipe_set_base, | ||
1319 | .prepare = intel_crtc_prepare, | ||
1320 | .commit = intel_crtc_commit, | ||
1321 | }; | ||
1322 | |||
1323 | static const struct drm_crtc_funcs intel_crtc_funcs = { | ||
1324 | .cursor_set = intel_crtc_cursor_set, | ||
1325 | .cursor_move = intel_crtc_cursor_move, | ||
1326 | .gamma_set = intel_crtc_gamma_set, | ||
1327 | .set_config = drm_crtc_helper_set_config, | ||
1328 | .destroy = intel_crtc_destroy, | ||
1329 | }; | ||
1330 | |||
1331 | |||
1332 | void intel_crtc_init(struct drm_device *dev, int pipe) | ||
1333 | { | ||
1334 | struct intel_crtc *intel_crtc; | ||
1335 | int i; | ||
1336 | |||
1337 | intel_crtc = kzalloc(sizeof(struct intel_crtc) + (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL); | ||
1338 | if (intel_crtc == NULL) | ||
1339 | return; | ||
1340 | |||
1341 | drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs); | ||
1342 | |||
1343 | drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256); | ||
1344 | intel_crtc->pipe = pipe; | ||
1345 | for (i = 0; i < 256; i++) { | ||
1346 | intel_crtc->lut_r[i] = i; | ||
1347 | intel_crtc->lut_g[i] = i; | ||
1348 | intel_crtc->lut_b[i] = i; | ||
1349 | } | ||
1350 | |||
1351 | intel_crtc->cursor_addr = 0; | ||
1352 | intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF; | ||
1353 | drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); | ||
1354 | |||
1355 | intel_crtc->mode_set.crtc = &intel_crtc->base; | ||
1356 | intel_crtc->mode_set.connectors = (struct drm_connector **)(intel_crtc + 1); | ||
1357 | intel_crtc->mode_set.num_connectors = 0; | ||
1358 | |||
1359 | if (i915_fbpercrtc) { | ||
1360 | |||
1361 | |||
1362 | |||
1363 | } | ||
1364 | } | ||
1365 | |||
1366 | struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe) | ||
1367 | { | ||
1368 | struct drm_crtc *crtc = NULL; | ||
1369 | |||
1370 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
1371 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
1372 | if (intel_crtc->pipe == pipe) | ||
1373 | break; | ||
1374 | } | ||
1375 | return crtc; | ||
1376 | } | ||
1377 | |||
1378 | int intel_connector_clones(struct drm_device *dev, int type_mask) | ||
1379 | { | ||
1380 | int index_mask = 0; | ||
1381 | struct drm_connector *connector; | ||
1382 | int entry = 0; | ||
1383 | |||
1384 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
1385 | struct intel_output *intel_output = to_intel_output(connector); | ||
1386 | if (type_mask & (1 << intel_output->type)) | ||
1387 | index_mask |= (1 << entry); | ||
1388 | entry++; | ||
1389 | } | ||
1390 | return index_mask; | ||
1391 | } | ||
1392 | |||
1393 | |||
1394 | static void intel_setup_outputs(struct drm_device *dev) | ||
1395 | { | ||
1396 | struct drm_connector *connector; | ||
1397 | |||
1398 | intel_crt_init(dev); | ||
1399 | |||
1400 | /* Set up integrated LVDS */ | ||
1401 | if (IS_MOBILE(dev) && !IS_I830(dev)) | ||
1402 | intel_lvds_init(dev); | ||
1403 | |||
1404 | if (IS_I9XX(dev)) { | ||
1405 | intel_sdvo_init(dev, SDVOB); | ||
1406 | intel_sdvo_init(dev, SDVOC); | ||
1407 | } else | ||
1408 | intel_dvo_init(dev); | ||
1409 | |||
1410 | if (IS_I9XX(dev) && !IS_I915G(dev)) | ||
1411 | intel_tv_init(dev); | ||
1412 | |||
1413 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
1414 | struct intel_output *intel_output = to_intel_output(connector); | ||
1415 | struct drm_encoder *encoder = &intel_output->enc; | ||
1416 | int crtc_mask = 0, clone_mask = 0; | ||
1417 | |||
1418 | /* valid crtcs */ | ||
1419 | switch(intel_output->type) { | ||
1420 | case INTEL_OUTPUT_DVO: | ||
1421 | case INTEL_OUTPUT_SDVO: | ||
1422 | crtc_mask = ((1 << 0)| | ||
1423 | (1 << 1)); | ||
1424 | clone_mask = ((1 << INTEL_OUTPUT_ANALOG) | | ||
1425 | (1 << INTEL_OUTPUT_DVO) | | ||
1426 | (1 << INTEL_OUTPUT_SDVO)); | ||
1427 | break; | ||
1428 | case INTEL_OUTPUT_ANALOG: | ||
1429 | crtc_mask = ((1 << 0)| | ||
1430 | (1 << 1)); | ||
1431 | clone_mask = ((1 << INTEL_OUTPUT_ANALOG) | | ||
1432 | (1 << INTEL_OUTPUT_DVO) | | ||
1433 | (1 << INTEL_OUTPUT_SDVO)); | ||
1434 | break; | ||
1435 | case INTEL_OUTPUT_LVDS: | ||
1436 | crtc_mask = (1 << 1); | ||
1437 | clone_mask = (1 << INTEL_OUTPUT_LVDS); | ||
1438 | break; | ||
1439 | case INTEL_OUTPUT_TVOUT: | ||
1440 | crtc_mask = ((1 << 0) | | ||
1441 | (1 << 1)); | ||
1442 | clone_mask = (1 << INTEL_OUTPUT_TVOUT); | ||
1443 | break; | ||
1444 | } | ||
1445 | encoder->possible_crtcs = crtc_mask; | ||
1446 | encoder->possible_clones = intel_connector_clones(dev, clone_mask); | ||
1447 | } | ||
1448 | } | ||
1449 | |||
1450 | static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) | ||
1451 | { | ||
1452 | struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); | ||
1453 | struct drm_device *dev = fb->dev; | ||
1454 | |||
1455 | if (fb->fbdev) | ||
1456 | intelfb_remove(dev, fb); | ||
1457 | |||
1458 | drm_framebuffer_cleanup(fb); | ||
1459 | mutex_lock(&dev->struct_mutex); | ||
1460 | drm_gem_object_unreference(intel_fb->obj); | ||
1461 | mutex_unlock(&dev->struct_mutex); | ||
1462 | |||
1463 | kfree(intel_fb); | ||
1464 | } | ||
1465 | |||
1466 | static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb, | ||
1467 | struct drm_file *file_priv, | ||
1468 | unsigned int *handle) | ||
1469 | { | ||
1470 | struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); | ||
1471 | struct drm_gem_object *object = intel_fb->obj; | ||
1472 | |||
1473 | return drm_gem_handle_create(file_priv, object, handle); | ||
1474 | } | ||
1475 | |||
1476 | static const struct drm_framebuffer_funcs intel_fb_funcs = { | ||
1477 | .destroy = intel_user_framebuffer_destroy, | ||
1478 | .create_handle = intel_user_framebuffer_create_handle, | ||
1479 | }; | ||
1480 | |||
1481 | int intel_framebuffer_create(struct drm_device *dev, | ||
1482 | struct drm_mode_fb_cmd *mode_cmd, | ||
1483 | struct drm_framebuffer **fb, | ||
1484 | struct drm_gem_object *obj) | ||
1485 | { | ||
1486 | struct intel_framebuffer *intel_fb; | ||
1487 | int ret; | ||
1488 | |||
1489 | intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); | ||
1490 | if (!intel_fb) | ||
1491 | return -ENOMEM; | ||
1492 | |||
1493 | ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs); | ||
1494 | if (ret) { | ||
1495 | DRM_ERROR("framebuffer init failed %d\n", ret); | ||
1496 | return ret; | ||
1497 | } | ||
1498 | |||
1499 | drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); | ||
1500 | |||
1501 | intel_fb->obj = obj; | ||
1502 | |||
1503 | *fb = &intel_fb->base; | ||
1504 | |||
1505 | return 0; | ||
1506 | } | ||
1507 | |||
1508 | |||
1509 | static struct drm_framebuffer * | ||
1510 | intel_user_framebuffer_create(struct drm_device *dev, | ||
1511 | struct drm_file *filp, | ||
1512 | struct drm_mode_fb_cmd *mode_cmd) | ||
1513 | { | ||
1514 | struct drm_gem_object *obj; | ||
1515 | struct drm_framebuffer *fb; | ||
1516 | int ret; | ||
1517 | |||
1518 | obj = drm_gem_object_lookup(dev, filp, mode_cmd->handle); | ||
1519 | if (!obj) | ||
1520 | return NULL; | ||
1521 | |||
1522 | ret = intel_framebuffer_create(dev, mode_cmd, &fb, obj); | ||
1523 | if (ret) { | ||
1524 | drm_gem_object_unreference(obj); | ||
1525 | return NULL; | ||
1526 | } | ||
1527 | |||
1528 | return fb; | ||
1529 | } | ||
1530 | |||
1531 | static int intel_insert_new_fb(struct drm_device *dev, | ||
1532 | struct drm_file *file_priv, | ||
1533 | struct drm_framebuffer *fb, | ||
1534 | struct drm_mode_fb_cmd *mode_cmd) | ||
1535 | { | ||
1536 | struct intel_framebuffer *intel_fb; | ||
1537 | struct drm_gem_object *obj; | ||
1538 | struct drm_crtc *crtc; | ||
1539 | |||
1540 | intel_fb = to_intel_framebuffer(fb); | ||
1541 | |||
1542 | obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); | ||
1543 | |||
1544 | if (!obj) | ||
1545 | return -EINVAL; | ||
1546 | |||
1547 | intel_fb->obj = obj; | ||
1548 | drm_gem_object_unreference(intel_fb->obj); | ||
1549 | drm_helper_mode_fill_fb_struct(fb, mode_cmd); | ||
1550 | mutex_unlock(&dev->struct_mutex); | ||
1551 | |||
1552 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
1553 | if (crtc->fb == fb) { | ||
1554 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
1555 | crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y); | ||
1556 | } | ||
1557 | } | ||
1558 | return 0; | ||
1559 | } | ||
1560 | |||
1561 | static const struct drm_mode_config_funcs intel_mode_funcs = { | ||
1562 | .resize_fb = intel_insert_new_fb, | ||
1563 | .fb_create = intel_user_framebuffer_create, | ||
1564 | .fb_changed = intelfb_probe, | ||
1565 | }; | ||
1566 | |||
1567 | void intel_modeset_init(struct drm_device *dev) | ||
1568 | { | ||
1569 | int num_pipe; | ||
1570 | int i; | ||
1571 | |||
1572 | drm_mode_config_init(dev); | ||
1573 | |||
1574 | dev->mode_config.min_width = 0; | ||
1575 | dev->mode_config.min_height = 0; | ||
1576 | |||
1577 | dev->mode_config.funcs = (void *)&intel_mode_funcs; | ||
1578 | |||
1579 | if (IS_I965G(dev)) { | ||
1580 | dev->mode_config.max_width = 8192; | ||
1581 | dev->mode_config.max_height = 8192; | ||
1582 | } else { | ||
1583 | dev->mode_config.max_width = 2048; | ||
1584 | dev->mode_config.max_height = 2048; | ||
1585 | } | ||
1586 | |||
1587 | /* set memory base */ | ||
1588 | if (IS_I9XX(dev)) | ||
1589 | dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2); | ||
1590 | else | ||
1591 | dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0); | ||
1592 | |||
1593 | if (IS_MOBILE(dev) || IS_I9XX(dev)) | ||
1594 | num_pipe = 2; | ||
1595 | else | ||
1596 | num_pipe = 1; | ||
1597 | DRM_DEBUG("%d display pipe%s available.\n", | ||
1598 | num_pipe, num_pipe > 1 ? "s" : ""); | ||
1599 | |||
1600 | for (i = 0; i < num_pipe; i++) { | ||
1601 | intel_crtc_init(dev, i); | ||
1602 | } | ||
1603 | |||
1604 | intel_setup_outputs(dev); | ||
1605 | } | ||
1606 | |||
1607 | void intel_modeset_cleanup(struct drm_device *dev) | ||
1608 | { | ||
1609 | drm_mode_config_cleanup(dev); | ||
1610 | } | ||
1611 | |||
1612 | |||
1613 | /* current intel driver doesn't take advantage of encoders | ||
1614 | always give back the encoder for the connector | ||
1615 | */ | ||
1616 | struct drm_encoder *intel_best_encoder(struct drm_connector *connector) | ||
1617 | { | ||
1618 | struct intel_output *intel_output = to_intel_output(connector); | ||
1619 | |||
1620 | return &intel_output->enc; | ||
1621 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h new file mode 100644 index 000000000000..407edd5bf582 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_drv.h | |||
@@ -0,0 +1,146 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2006 Dave Airlie <airlied@linux.ie> | ||
3 | * Copyright (c) 2007-2008 Intel Corporation | ||
4 | * Jesse Barnes <jesse.barnes@intel.com> | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the "Software"), | ||
8 | * to deal in the Software without restriction, including without limitation | ||
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
10 | * and/or sell copies of the Software, and to permit persons to whom the | ||
11 | * Software is furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice (including the next | ||
14 | * paragraph) shall be included in all copies or substantial portions of the | ||
15 | * Software. | ||
16 | * | ||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
23 | * IN THE SOFTWARE. | ||
24 | */ | ||
25 | #ifndef __INTEL_DRV_H__ | ||
26 | #define __INTEL_DRV_H__ | ||
27 | |||
28 | #include <linux/i2c.h> | ||
29 | #include <linux/i2c-id.h> | ||
30 | #include <linux/i2c-algo-bit.h> | ||
31 | #include "drm_crtc.h" | ||
32 | |||
33 | #include "drm_crtc_helper.h" | ||
34 | /* | ||
35 | * Display related stuff | ||
36 | */ | ||
37 | |||
38 | /* store information about an Ixxx DVO */ | ||
39 | /* The i830->i865 use multiple DVOs with multiple i2cs */ | ||
40 | /* the i915, i945 have a single sDVO i2c bus - which is different */ | ||
41 | #define MAX_OUTPUTS 6 | ||
42 | /* maximum connectors per crtcs in the mode set */ | ||
43 | #define INTELFB_CONN_LIMIT 4 | ||
44 | |||
45 | #define INTEL_I2C_BUS_DVO 1 | ||
46 | #define INTEL_I2C_BUS_SDVO 2 | ||
47 | |||
48 | /* these are outputs from the chip - integrated only | ||
49 | external chips are via DVO or SDVO output */ | ||
50 | #define INTEL_OUTPUT_UNUSED 0 | ||
51 | #define INTEL_OUTPUT_ANALOG 1 | ||
52 | #define INTEL_OUTPUT_DVO 2 | ||
53 | #define INTEL_OUTPUT_SDVO 3 | ||
54 | #define INTEL_OUTPUT_LVDS 4 | ||
55 | #define INTEL_OUTPUT_TVOUT 5 | ||
56 | |||
57 | #define INTEL_DVO_CHIP_NONE 0 | ||
58 | #define INTEL_DVO_CHIP_LVDS 1 | ||
59 | #define INTEL_DVO_CHIP_TMDS 2 | ||
60 | #define INTEL_DVO_CHIP_TVOUT 4 | ||
61 | |||
62 | struct intel_i2c_chan { | ||
63 | struct drm_device *drm_dev; /* for getting at dev. private (mmio etc.) */ | ||
64 | u32 reg; /* GPIO reg */ | ||
65 | struct i2c_adapter adapter; | ||
66 | struct i2c_algo_bit_data algo; | ||
67 | u8 slave_addr; | ||
68 | }; | ||
69 | |||
70 | struct intel_framebuffer { | ||
71 | struct drm_framebuffer base; | ||
72 | struct drm_gem_object *obj; | ||
73 | }; | ||
74 | |||
75 | |||
76 | struct intel_output { | ||
77 | struct drm_connector base; | ||
78 | |||
79 | struct drm_encoder enc; | ||
80 | int type; | ||
81 | struct intel_i2c_chan *i2c_bus; /* for control functions */ | ||
82 | struct intel_i2c_chan *ddc_bus; /* for DDC only stuff */ | ||
83 | bool load_detect_temp; | ||
84 | void *dev_priv; | ||
85 | }; | ||
86 | |||
87 | struct intel_crtc { | ||
88 | struct drm_crtc base; | ||
89 | int pipe; | ||
90 | int plane; | ||
91 | uint32_t cursor_addr; | ||
92 | u8 lut_r[256], lut_g[256], lut_b[256]; | ||
93 | int dpms_mode; | ||
94 | struct intel_framebuffer *fbdev_fb; | ||
95 | /* a mode_set for fbdev users on this crtc */ | ||
96 | struct drm_mode_set mode_set; | ||
97 | }; | ||
98 | |||
99 | #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) | ||
100 | #define to_intel_output(x) container_of(x, struct intel_output, base) | ||
101 | #define enc_to_intel_output(x) container_of(x, struct intel_output, enc) | ||
102 | #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) | ||
103 | |||
104 | struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, | ||
105 | const char *name); | ||
106 | void intel_i2c_destroy(struct intel_i2c_chan *chan); | ||
107 | int intel_ddc_get_modes(struct intel_output *intel_output); | ||
108 | extern bool intel_ddc_probe(struct intel_output *intel_output); | ||
109 | |||
110 | extern void intel_crt_init(struct drm_device *dev); | ||
111 | extern void intel_sdvo_init(struct drm_device *dev, int output_device); | ||
112 | extern void intel_dvo_init(struct drm_device *dev); | ||
113 | extern void intel_tv_init(struct drm_device *dev); | ||
114 | extern void intel_lvds_init(struct drm_device *dev); | ||
115 | |||
116 | extern void intel_crtc_load_lut(struct drm_crtc *crtc); | ||
117 | extern void intel_encoder_prepare (struct drm_encoder *encoder); | ||
118 | extern void intel_encoder_commit (struct drm_encoder *encoder); | ||
119 | |||
120 | extern struct drm_encoder *intel_best_encoder(struct drm_connector *connector); | ||
121 | |||
122 | extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, | ||
123 | struct drm_crtc *crtc); | ||
124 | extern void intel_wait_for_vblank(struct drm_device *dev); | ||
125 | extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); | ||
126 | extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output, | ||
127 | struct drm_display_mode *mode, | ||
128 | int *dpms_mode); | ||
129 | extern void intel_release_load_detect_pipe(struct intel_output *intel_output, | ||
130 | int dpms_mode); | ||
131 | |||
132 | extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB); | ||
133 | extern int intel_sdvo_supports_hotplug(struct drm_connector *connector); | ||
134 | extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable); | ||
135 | extern int intelfb_probe(struct drm_device *dev); | ||
136 | extern int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); | ||
137 | extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc); | ||
138 | extern void intelfb_restore(void); | ||
139 | extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, | ||
140 | u16 blue, int regno); | ||
141 | |||
142 | extern int intel_framebuffer_create(struct drm_device *dev, | ||
143 | struct drm_mode_fb_cmd *mode_cmd, | ||
144 | struct drm_framebuffer **fb, | ||
145 | struct drm_gem_object *obj); | ||
146 | #endif /* __INTEL_DRV_H__ */ | ||
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c new file mode 100644 index 000000000000..008bfaed4614 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_dvo.c | |||
@@ -0,0 +1,501 @@ | |||
1 | /* | ||
2 | * Copyright 2006 Dave Airlie <airlied@linux.ie> | ||
3 | * Copyright © 2006-2007 Intel Corporation | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
6 | * copy of this software and associated documentation files (the "Software"), | ||
7 | * to deal in the Software without restriction, including without limitation | ||
8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
9 | * and/or sell copies of the Software, and to permit persons to whom the | ||
10 | * Software is furnished to do so, subject to the following conditions: | ||
11 | * | ||
12 | * The above copyright notice and this permission notice (including the next | ||
13 | * paragraph) shall be included in all copies or substantial portions of the | ||
14 | * Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
22 | * DEALINGS IN THE SOFTWARE. | ||
23 | * | ||
24 | * Authors: | ||
25 | * Eric Anholt <eric@anholt.net> | ||
26 | */ | ||
27 | #include <linux/i2c.h> | ||
28 | #include "drmP.h" | ||
29 | #include "drm.h" | ||
30 | #include "drm_crtc.h" | ||
31 | #include "intel_drv.h" | ||
32 | #include "i915_drm.h" | ||
33 | #include "i915_drv.h" | ||
34 | #include "dvo.h" | ||
35 | |||
36 | #define SIL164_ADDR 0x38 | ||
37 | #define CH7xxx_ADDR 0x76 | ||
38 | #define TFP410_ADDR 0x38 | ||
39 | |||
40 | extern struct intel_dvo_dev_ops sil164_ops; | ||
41 | extern struct intel_dvo_dev_ops ch7xxx_ops; | ||
42 | extern struct intel_dvo_dev_ops ivch_ops; | ||
43 | extern struct intel_dvo_dev_ops tfp410_ops; | ||
44 | extern struct intel_dvo_dev_ops ch7017_ops; | ||
45 | |||
46 | struct intel_dvo_device intel_dvo_devices[] = { | ||
47 | { | ||
48 | .type = INTEL_DVO_CHIP_TMDS, | ||
49 | .name = "sil164", | ||
50 | .dvo_reg = DVOC, | ||
51 | .slave_addr = SIL164_ADDR, | ||
52 | .dev_ops = &sil164_ops, | ||
53 | }, | ||
54 | { | ||
55 | .type = INTEL_DVO_CHIP_TMDS, | ||
56 | .name = "ch7xxx", | ||
57 | .dvo_reg = DVOC, | ||
58 | .slave_addr = CH7xxx_ADDR, | ||
59 | .dev_ops = &ch7xxx_ops, | ||
60 | }, | ||
61 | { | ||
62 | .type = INTEL_DVO_CHIP_LVDS, | ||
63 | .name = "ivch", | ||
64 | .dvo_reg = DVOA, | ||
65 | .slave_addr = 0x02, /* Might also be 0x44, 0x84, 0xc4 */ | ||
66 | .dev_ops = &ivch_ops, | ||
67 | }, | ||
68 | { | ||
69 | .type = INTEL_DVO_CHIP_TMDS, | ||
70 | .name = "tfp410", | ||
71 | .dvo_reg = DVOC, | ||
72 | .slave_addr = TFP410_ADDR, | ||
73 | .dev_ops = &tfp410_ops, | ||
74 | }, | ||
75 | { | ||
76 | .type = INTEL_DVO_CHIP_LVDS, | ||
77 | .name = "ch7017", | ||
78 | .dvo_reg = DVOC, | ||
79 | .slave_addr = 0x75, | ||
80 | .gpio = GPIOE, | ||
81 | .dev_ops = &ch7017_ops, | ||
82 | } | ||
83 | }; | ||
84 | |||
85 | static void intel_dvo_dpms(struct drm_encoder *encoder, int mode) | ||
86 | { | ||
87 | struct drm_i915_private *dev_priv = encoder->dev->dev_private; | ||
88 | struct intel_output *intel_output = enc_to_intel_output(encoder); | ||
89 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
90 | u32 dvo_reg = dvo->dvo_reg; | ||
91 | u32 temp = I915_READ(dvo_reg); | ||
92 | |||
93 | if (mode == DRM_MODE_DPMS_ON) { | ||
94 | I915_WRITE(dvo_reg, temp | DVO_ENABLE); | ||
95 | I915_READ(dvo_reg); | ||
96 | dvo->dev_ops->dpms(dvo, mode); | ||
97 | } else { | ||
98 | dvo->dev_ops->dpms(dvo, mode); | ||
99 | I915_WRITE(dvo_reg, temp & ~DVO_ENABLE); | ||
100 | I915_READ(dvo_reg); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | static void intel_dvo_save(struct drm_connector *connector) | ||
105 | { | ||
106 | struct drm_i915_private *dev_priv = connector->dev->dev_private; | ||
107 | struct intel_output *intel_output = to_intel_output(connector); | ||
108 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
109 | |||
110 | /* Each output should probably just save the registers it touches, | ||
111 | * but for now, use more overkill. | ||
112 | */ | ||
113 | dev_priv->saveDVOA = I915_READ(DVOA); | ||
114 | dev_priv->saveDVOB = I915_READ(DVOB); | ||
115 | dev_priv->saveDVOC = I915_READ(DVOC); | ||
116 | |||
117 | dvo->dev_ops->save(dvo); | ||
118 | } | ||
119 | |||
120 | static void intel_dvo_restore(struct drm_connector *connector) | ||
121 | { | ||
122 | struct drm_i915_private *dev_priv = connector->dev->dev_private; | ||
123 | struct intel_output *intel_output = to_intel_output(connector); | ||
124 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
125 | |||
126 | dvo->dev_ops->restore(dvo); | ||
127 | |||
128 | I915_WRITE(DVOA, dev_priv->saveDVOA); | ||
129 | I915_WRITE(DVOB, dev_priv->saveDVOB); | ||
130 | I915_WRITE(DVOC, dev_priv->saveDVOC); | ||
131 | } | ||
132 | |||
133 | static int intel_dvo_mode_valid(struct drm_connector *connector, | ||
134 | struct drm_display_mode *mode) | ||
135 | { | ||
136 | struct intel_output *intel_output = to_intel_output(connector); | ||
137 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
138 | |||
139 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
140 | return MODE_NO_DBLESCAN; | ||
141 | |||
142 | /* XXX: Validate clock range */ | ||
143 | |||
144 | if (dvo->panel_fixed_mode) { | ||
145 | if (mode->hdisplay > dvo->panel_fixed_mode->hdisplay) | ||
146 | return MODE_PANEL; | ||
147 | if (mode->vdisplay > dvo->panel_fixed_mode->vdisplay) | ||
148 | return MODE_PANEL; | ||
149 | } | ||
150 | |||
151 | return dvo->dev_ops->mode_valid(dvo, mode); | ||
152 | } | ||
153 | |||
154 | static bool intel_dvo_mode_fixup(struct drm_encoder *encoder, | ||
155 | struct drm_display_mode *mode, | ||
156 | struct drm_display_mode *adjusted_mode) | ||
157 | { | ||
158 | struct intel_output *intel_output = enc_to_intel_output(encoder); | ||
159 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
160 | |||
161 | /* If we have timings from the BIOS for the panel, put them in | ||
162 | * to the adjusted mode. The CRTC will be set up for this mode, | ||
163 | * with the panel scaling set up to source from the H/VDisplay | ||
164 | * of the original mode. | ||
165 | */ | ||
166 | if (dvo->panel_fixed_mode != NULL) { | ||
167 | #define C(x) adjusted_mode->x = dvo->panel_fixed_mode->x | ||
168 | C(hdisplay); | ||
169 | C(hsync_start); | ||
170 | C(hsync_end); | ||
171 | C(htotal); | ||
172 | C(vdisplay); | ||
173 | C(vsync_start); | ||
174 | C(vsync_end); | ||
175 | C(vtotal); | ||
176 | C(clock); | ||
177 | drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); | ||
178 | #undef C | ||
179 | } | ||
180 | |||
181 | if (dvo->dev_ops->mode_fixup) | ||
182 | return dvo->dev_ops->mode_fixup(dvo, mode, adjusted_mode); | ||
183 | |||
184 | return true; | ||
185 | } | ||
186 | |||
187 | static void intel_dvo_mode_set(struct drm_encoder *encoder, | ||
188 | struct drm_display_mode *mode, | ||
189 | struct drm_display_mode *adjusted_mode) | ||
190 | { | ||
191 | struct drm_device *dev = encoder->dev; | ||
192 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
193 | struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); | ||
194 | struct intel_output *intel_output = enc_to_intel_output(encoder); | ||
195 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
196 | int pipe = intel_crtc->pipe; | ||
197 | u32 dvo_val; | ||
198 | u32 dvo_reg = dvo->dvo_reg, dvo_srcdim_reg; | ||
199 | int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; | ||
200 | |||
201 | switch (dvo_reg) { | ||
202 | case DVOA: | ||
203 | default: | ||
204 | dvo_srcdim_reg = DVOA_SRCDIM; | ||
205 | break; | ||
206 | case DVOB: | ||
207 | dvo_srcdim_reg = DVOB_SRCDIM; | ||
208 | break; | ||
209 | case DVOC: | ||
210 | dvo_srcdim_reg = DVOC_SRCDIM; | ||
211 | break; | ||
212 | } | ||
213 | |||
214 | dvo->dev_ops->mode_set(dvo, mode, adjusted_mode); | ||
215 | |||
216 | /* Save the data order, since I don't know what it should be set to. */ | ||
217 | dvo_val = I915_READ(dvo_reg) & | ||
218 | (DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG); | ||
219 | dvo_val |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE | | ||
220 | DVO_BLANK_ACTIVE_HIGH; | ||
221 | |||
222 | if (pipe == 1) | ||
223 | dvo_val |= DVO_PIPE_B_SELECT; | ||
224 | dvo_val |= DVO_PIPE_STALL; | ||
225 | if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
226 | dvo_val |= DVO_HSYNC_ACTIVE_HIGH; | ||
227 | if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
228 | dvo_val |= DVO_VSYNC_ACTIVE_HIGH; | ||
229 | |||
230 | I915_WRITE(dpll_reg, I915_READ(dpll_reg) | DPLL_DVO_HIGH_SPEED); | ||
231 | |||
232 | /*I915_WRITE(DVOB_SRCDIM, | ||
233 | (adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | | ||
234 | (adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/ | ||
235 | I915_WRITE(dvo_srcdim_reg, | ||
236 | (adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | | ||
237 | (adjusted_mode->vdisplay << DVO_SRCDIM_VERTICAL_SHIFT)); | ||
238 | /*I915_WRITE(DVOB, dvo_val);*/ | ||
239 | I915_WRITE(dvo_reg, dvo_val); | ||
240 | } | ||
241 | |||
242 | /** | ||
243 | * Detect the output connection on our DVO device. | ||
244 | * | ||
245 | * Unimplemented. | ||
246 | */ | ||
247 | static enum drm_connector_status intel_dvo_detect(struct drm_connector *connector) | ||
248 | { | ||
249 | struct intel_output *intel_output = to_intel_output(connector); | ||
250 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
251 | |||
252 | return dvo->dev_ops->detect(dvo); | ||
253 | } | ||
254 | |||
255 | static int intel_dvo_get_modes(struct drm_connector *connector) | ||
256 | { | ||
257 | struct intel_output *intel_output = to_intel_output(connector); | ||
258 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
259 | |||
260 | /* We should probably have an i2c driver get_modes function for those | ||
261 | * devices which will have a fixed set of modes determined by the chip | ||
262 | * (TV-out, for example), but for now with just TMDS and LVDS, | ||
263 | * that's not the case. | ||
264 | */ | ||
265 | intel_ddc_get_modes(intel_output); | ||
266 | if (!list_empty(&connector->probed_modes)) | ||
267 | return 1; | ||
268 | |||
269 | |||
270 | if (dvo->panel_fixed_mode != NULL) { | ||
271 | struct drm_display_mode *mode; | ||
272 | mode = drm_mode_duplicate(connector->dev, dvo->panel_fixed_mode); | ||
273 | if (mode) { | ||
274 | drm_mode_probed_add(connector, mode); | ||
275 | return 1; | ||
276 | } | ||
277 | } | ||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | static void intel_dvo_destroy (struct drm_connector *connector) | ||
282 | { | ||
283 | struct intel_output *intel_output = to_intel_output(connector); | ||
284 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
285 | |||
286 | if (dvo) { | ||
287 | if (dvo->dev_ops->destroy) | ||
288 | dvo->dev_ops->destroy(dvo); | ||
289 | if (dvo->panel_fixed_mode) | ||
290 | kfree(dvo->panel_fixed_mode); | ||
291 | /* no need, in i830_dvoices[] now */ | ||
292 | //kfree(dvo); | ||
293 | } | ||
294 | if (intel_output->i2c_bus) | ||
295 | intel_i2c_destroy(intel_output->i2c_bus); | ||
296 | if (intel_output->ddc_bus) | ||
297 | intel_i2c_destroy(intel_output->ddc_bus); | ||
298 | drm_sysfs_connector_remove(connector); | ||
299 | drm_connector_cleanup(connector); | ||
300 | kfree(intel_output); | ||
301 | } | ||
302 | |||
303 | #ifdef RANDR_GET_CRTC_INTERFACE | ||
304 | static struct drm_crtc *intel_dvo_get_crtc(struct drm_connector *connector) | ||
305 | { | ||
306 | struct drm_device *dev = connector->dev; | ||
307 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
308 | struct intel_output *intel_output = to_intel_output(connector); | ||
309 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
310 | int pipe = !!(I915_READ(dvo->dvo_reg) & SDVO_PIPE_B_SELECT); | ||
311 | |||
312 | return intel_pipe_to_crtc(pScrn, pipe); | ||
313 | } | ||
314 | #endif | ||
315 | |||
316 | static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = { | ||
317 | .dpms = intel_dvo_dpms, | ||
318 | .mode_fixup = intel_dvo_mode_fixup, | ||
319 | .prepare = intel_encoder_prepare, | ||
320 | .mode_set = intel_dvo_mode_set, | ||
321 | .commit = intel_encoder_commit, | ||
322 | }; | ||
323 | |||
324 | static const struct drm_connector_funcs intel_dvo_connector_funcs = { | ||
325 | .save = intel_dvo_save, | ||
326 | .restore = intel_dvo_restore, | ||
327 | .detect = intel_dvo_detect, | ||
328 | .destroy = intel_dvo_destroy, | ||
329 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
330 | }; | ||
331 | |||
332 | static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = { | ||
333 | .mode_valid = intel_dvo_mode_valid, | ||
334 | .get_modes = intel_dvo_get_modes, | ||
335 | .best_encoder = intel_best_encoder, | ||
336 | }; | ||
337 | |||
338 | void intel_dvo_enc_destroy(struct drm_encoder *encoder) | ||
339 | { | ||
340 | drm_encoder_cleanup(encoder); | ||
341 | } | ||
342 | |||
343 | static const struct drm_encoder_funcs intel_dvo_enc_funcs = { | ||
344 | .destroy = intel_dvo_enc_destroy, | ||
345 | }; | ||
346 | |||
347 | |||
348 | /** | ||
349 | * Attempts to get a fixed panel timing for LVDS (currently only the i830). | ||
350 | * | ||
351 | * Other chips with DVO LVDS will need to extend this to deal with the LVDS | ||
352 | * chip being on DVOB/C and having multiple pipes. | ||
353 | */ | ||
354 | static struct drm_display_mode * | ||
355 | intel_dvo_get_current_mode (struct drm_connector *connector) | ||
356 | { | ||
357 | struct drm_device *dev = connector->dev; | ||
358 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
359 | struct intel_output *intel_output = to_intel_output(connector); | ||
360 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
361 | uint32_t dvo_reg = dvo->dvo_reg; | ||
362 | uint32_t dvo_val = I915_READ(dvo_reg); | ||
363 | struct drm_display_mode *mode = NULL; | ||
364 | |||
365 | /* If the DVO port is active, that'll be the LVDS, so we can pull out | ||
366 | * its timings to get how the BIOS set up the panel. | ||
367 | */ | ||
368 | if (dvo_val & DVO_ENABLE) { | ||
369 | struct drm_crtc *crtc; | ||
370 | int pipe = (dvo_val & DVO_PIPE_B_SELECT) ? 1 : 0; | ||
371 | |||
372 | crtc = intel_get_crtc_from_pipe(dev, pipe); | ||
373 | if (crtc) { | ||
374 | mode = intel_crtc_mode_get(dev, crtc); | ||
375 | |||
376 | if (mode) { | ||
377 | mode->type |= DRM_MODE_TYPE_PREFERRED; | ||
378 | if (dvo_val & DVO_HSYNC_ACTIVE_HIGH) | ||
379 | mode->flags |= DRM_MODE_FLAG_PHSYNC; | ||
380 | if (dvo_val & DVO_VSYNC_ACTIVE_HIGH) | ||
381 | mode->flags |= DRM_MODE_FLAG_PVSYNC; | ||
382 | } | ||
383 | } | ||
384 | } | ||
385 | return mode; | ||
386 | } | ||
387 | |||
388 | void intel_dvo_init(struct drm_device *dev) | ||
389 | { | ||
390 | struct intel_output *intel_output; | ||
391 | struct intel_dvo_device *dvo; | ||
392 | struct intel_i2c_chan *i2cbus = NULL; | ||
393 | int ret = 0; | ||
394 | int i; | ||
395 | int gpio_inited = 0; | ||
396 | int encoder_type = DRM_MODE_ENCODER_NONE; | ||
397 | intel_output = kzalloc (sizeof(struct intel_output), GFP_KERNEL); | ||
398 | if (!intel_output) | ||
399 | return; | ||
400 | |||
401 | /* Set up the DDC bus */ | ||
402 | intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "DVODDC_D"); | ||
403 | if (!intel_output->ddc_bus) | ||
404 | goto free_intel; | ||
405 | |||
406 | /* Now, try to find a controller */ | ||
407 | for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) { | ||
408 | struct drm_connector *connector = &intel_output->base; | ||
409 | int gpio; | ||
410 | |||
411 | dvo = &intel_dvo_devices[i]; | ||
412 | |||
413 | /* Allow the I2C driver info to specify the GPIO to be used in | ||
414 | * special cases, but otherwise default to what's defined | ||
415 | * in the spec. | ||
416 | */ | ||
417 | if (dvo->gpio != 0) | ||
418 | gpio = dvo->gpio; | ||
419 | else if (dvo->type == INTEL_DVO_CHIP_LVDS) | ||
420 | gpio = GPIOB; | ||
421 | else | ||
422 | gpio = GPIOE; | ||
423 | |||
424 | /* Set up the I2C bus necessary for the chip we're probing. | ||
425 | * It appears that everything is on GPIOE except for panels | ||
426 | * on i830 laptops, which are on GPIOB (DVOA). | ||
427 | */ | ||
428 | if (gpio_inited != gpio) { | ||
429 | if (i2cbus != NULL) | ||
430 | intel_i2c_destroy(i2cbus); | ||
431 | if (!(i2cbus = intel_i2c_create(dev, gpio, | ||
432 | gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) { | ||
433 | continue; | ||
434 | } | ||
435 | gpio_inited = gpio; | ||
436 | } | ||
437 | |||
438 | if (dvo->dev_ops!= NULL) | ||
439 | ret = dvo->dev_ops->init(dvo, i2cbus); | ||
440 | else | ||
441 | ret = false; | ||
442 | |||
443 | if (!ret) | ||
444 | continue; | ||
445 | |||
446 | intel_output->type = INTEL_OUTPUT_DVO; | ||
447 | switch (dvo->type) { | ||
448 | case INTEL_DVO_CHIP_TMDS: | ||
449 | drm_connector_init(dev, connector, | ||
450 | &intel_dvo_connector_funcs, | ||
451 | DRM_MODE_CONNECTOR_DVII); | ||
452 | encoder_type = DRM_MODE_ENCODER_TMDS; | ||
453 | break; | ||
454 | case INTEL_DVO_CHIP_LVDS: | ||
455 | drm_connector_init(dev, connector, | ||
456 | &intel_dvo_connector_funcs, | ||
457 | DRM_MODE_CONNECTOR_LVDS); | ||
458 | encoder_type = DRM_MODE_ENCODER_LVDS; | ||
459 | break; | ||
460 | } | ||
461 | |||
462 | drm_connector_helper_add(connector, | ||
463 | &intel_dvo_connector_helper_funcs); | ||
464 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
465 | connector->interlace_allowed = false; | ||
466 | connector->doublescan_allowed = false; | ||
467 | |||
468 | intel_output->dev_priv = dvo; | ||
469 | intel_output->i2c_bus = i2cbus; | ||
470 | |||
471 | drm_encoder_init(dev, &intel_output->enc, | ||
472 | &intel_dvo_enc_funcs, encoder_type); | ||
473 | drm_encoder_helper_add(&intel_output->enc, | ||
474 | &intel_dvo_helper_funcs); | ||
475 | |||
476 | drm_mode_connector_attach_encoder(&intel_output->base, | ||
477 | &intel_output->enc); | ||
478 | if (dvo->type == INTEL_DVO_CHIP_LVDS) { | ||
479 | /* For our LVDS chipsets, we should hopefully be able | ||
480 | * to dig the fixed panel mode out of the BIOS data. | ||
481 | * However, it's in a different format from the BIOS | ||
482 | * data on chipsets with integrated LVDS (stored in AIM | ||
483 | * headers, likely), so for now, just get the current | ||
484 | * mode being output through DVO. | ||
485 | */ | ||
486 | dvo->panel_fixed_mode = | ||
487 | intel_dvo_get_current_mode(connector); | ||
488 | dvo->panel_wants_dither = true; | ||
489 | } | ||
490 | |||
491 | drm_sysfs_connector_add(connector); | ||
492 | return; | ||
493 | } | ||
494 | |||
495 | intel_i2c_destroy(intel_output->ddc_bus); | ||
496 | /* Didn't find a chip, so tear down. */ | ||
497 | if (i2cbus != NULL) | ||
498 | intel_i2c_destroy(i2cbus); | ||
499 | free_intel: | ||
500 | kfree(intel_output); | ||
501 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c new file mode 100644 index 000000000000..a89ebea7b76d --- /dev/null +++ b/drivers/gpu/drm/i915/intel_fb.c | |||
@@ -0,0 +1,926 @@ | |||
1 | /* | ||
2 | * Copyright © 2007 David Airlie | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * David Airlie | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/errno.h> | ||
30 | #include <linux/string.h> | ||
31 | #include <linux/mm.h> | ||
32 | #include <linux/tty.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/sysrq.h> | ||
35 | #include <linux/delay.h> | ||
36 | #include <linux/fb.h> | ||
37 | #include <linux/init.h> | ||
38 | |||
39 | #include "drmP.h" | ||
40 | #include "drm.h" | ||
41 | #include "drm_crtc.h" | ||
42 | #include "intel_drv.h" | ||
43 | #include "i915_drm.h" | ||
44 | #include "i915_drv.h" | ||
45 | |||
46 | struct intelfb_par { | ||
47 | struct drm_device *dev; | ||
48 | struct drm_display_mode *our_mode; | ||
49 | struct intel_framebuffer *intel_fb; | ||
50 | int crtc_count; | ||
51 | /* crtc currently bound to this */ | ||
52 | uint32_t crtc_ids[2]; | ||
53 | }; | ||
54 | |||
55 | static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green, | ||
56 | unsigned blue, unsigned transp, | ||
57 | struct fb_info *info) | ||
58 | { | ||
59 | struct intelfb_par *par = info->par; | ||
60 | struct drm_device *dev = par->dev; | ||
61 | struct drm_crtc *crtc; | ||
62 | int i; | ||
63 | |||
64 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
65 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
66 | struct drm_mode_set *modeset = &intel_crtc->mode_set; | ||
67 | struct drm_framebuffer *fb = modeset->fb; | ||
68 | |||
69 | for (i = 0; i < par->crtc_count; i++) | ||
70 | if (crtc->base.id == par->crtc_ids[i]) | ||
71 | break; | ||
72 | |||
73 | if (i == par->crtc_count) | ||
74 | continue; | ||
75 | |||
76 | |||
77 | if (regno > 255) | ||
78 | return 1; | ||
79 | |||
80 | if (fb->depth == 8) { | ||
81 | intel_crtc_fb_gamma_set(crtc, red, green, blue, regno); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | if (regno < 16) { | ||
86 | switch (fb->depth) { | ||
87 | case 15: | ||
88 | fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | | ||
89 | ((green & 0xf800) >> 6) | | ||
90 | ((blue & 0xf800) >> 11); | ||
91 | break; | ||
92 | case 16: | ||
93 | fb->pseudo_palette[regno] = (red & 0xf800) | | ||
94 | ((green & 0xfc00) >> 5) | | ||
95 | ((blue & 0xf800) >> 11); | ||
96 | break; | ||
97 | case 24: | ||
98 | case 32: | ||
99 | fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | | ||
100 | (green & 0xff00) | | ||
101 | ((blue & 0xff00) >> 8); | ||
102 | break; | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static int intelfb_check_var(struct fb_var_screeninfo *var, | ||
110 | struct fb_info *info) | ||
111 | { | ||
112 | struct intelfb_par *par = info->par; | ||
113 | struct intel_framebuffer *intel_fb = par->intel_fb; | ||
114 | struct drm_framebuffer *fb = &intel_fb->base; | ||
115 | int depth; | ||
116 | |||
117 | if (var->pixclock == -1 || !var->pixclock) | ||
118 | return -EINVAL; | ||
119 | |||
120 | /* Need to resize the fb object !!! */ | ||
121 | if (var->xres > fb->width || var->yres > fb->height) { | ||
122 | DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height); | ||
123 | DRM_ERROR("Need resizing code.\n"); | ||
124 | return -EINVAL; | ||
125 | } | ||
126 | |||
127 | switch (var->bits_per_pixel) { | ||
128 | case 16: | ||
129 | depth = (var->green.length == 6) ? 16 : 15; | ||
130 | break; | ||
131 | case 32: | ||
132 | depth = (var->transp.length > 0) ? 32 : 24; | ||
133 | break; | ||
134 | default: | ||
135 | depth = var->bits_per_pixel; | ||
136 | break; | ||
137 | } | ||
138 | |||
139 | switch (depth) { | ||
140 | case 8: | ||
141 | var->red.offset = 0; | ||
142 | var->green.offset = 0; | ||
143 | var->blue.offset = 0; | ||
144 | var->red.length = 8; | ||
145 | var->green.length = 8; | ||
146 | var->blue.length = 8; | ||
147 | var->transp.length = 0; | ||
148 | var->transp.offset = 0; | ||
149 | break; | ||
150 | case 15: | ||
151 | var->red.offset = 10; | ||
152 | var->green.offset = 5; | ||
153 | var->blue.offset = 0; | ||
154 | var->red.length = 5; | ||
155 | var->green.length = 5; | ||
156 | var->blue.length = 5; | ||
157 | var->transp.length = 1; | ||
158 | var->transp.offset = 15; | ||
159 | break; | ||
160 | case 16: | ||
161 | var->red.offset = 11; | ||
162 | var->green.offset = 5; | ||
163 | var->blue.offset = 0; | ||
164 | var->red.length = 5; | ||
165 | var->green.length = 6; | ||
166 | var->blue.length = 5; | ||
167 | var->transp.length = 0; | ||
168 | var->transp.offset = 0; | ||
169 | break; | ||
170 | case 24: | ||
171 | var->red.offset = 16; | ||
172 | var->green.offset = 8; | ||
173 | var->blue.offset = 0; | ||
174 | var->red.length = 8; | ||
175 | var->green.length = 8; | ||
176 | var->blue.length = 8; | ||
177 | var->transp.length = 0; | ||
178 | var->transp.offset = 0; | ||
179 | break; | ||
180 | case 32: | ||
181 | var->red.offset = 16; | ||
182 | var->green.offset = 8; | ||
183 | var->blue.offset = 0; | ||
184 | var->red.length = 8; | ||
185 | var->green.length = 8; | ||
186 | var->blue.length = 8; | ||
187 | var->transp.length = 8; | ||
188 | var->transp.offset = 24; | ||
189 | break; | ||
190 | default: | ||
191 | return -EINVAL; | ||
192 | } | ||
193 | |||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | /* this will let fbcon do the mode init */ | ||
198 | /* FIXME: take mode config lock? */ | ||
199 | static int intelfb_set_par(struct fb_info *info) | ||
200 | { | ||
201 | struct intelfb_par *par = info->par; | ||
202 | struct drm_device *dev = par->dev; | ||
203 | struct fb_var_screeninfo *var = &info->var; | ||
204 | int i; | ||
205 | |||
206 | DRM_DEBUG("%d %d\n", var->xres, var->pixclock); | ||
207 | |||
208 | if (var->pixclock != -1) { | ||
209 | |||
210 | DRM_ERROR("PIXEL CLCOK SET\n"); | ||
211 | return -EINVAL; | ||
212 | } else { | ||
213 | struct drm_crtc *crtc; | ||
214 | int ret; | ||
215 | |||
216 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
217 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
218 | |||
219 | for (i = 0; i < par->crtc_count; i++) | ||
220 | if (crtc->base.id == par->crtc_ids[i]) | ||
221 | break; | ||
222 | |||
223 | if (i == par->crtc_count) | ||
224 | continue; | ||
225 | |||
226 | if (crtc->fb == intel_crtc->mode_set.fb) { | ||
227 | mutex_lock(&dev->mode_config.mutex); | ||
228 | ret = crtc->funcs->set_config(&intel_crtc->mode_set); | ||
229 | mutex_unlock(&dev->mode_config.mutex); | ||
230 | if (ret) | ||
231 | return ret; | ||
232 | } | ||
233 | } | ||
234 | return 0; | ||
235 | } | ||
236 | } | ||
237 | |||
238 | static int intelfb_pan_display(struct fb_var_screeninfo *var, | ||
239 | struct fb_info *info) | ||
240 | { | ||
241 | struct intelfb_par *par = info->par; | ||
242 | struct drm_device *dev = par->dev; | ||
243 | struct drm_mode_set *modeset; | ||
244 | struct drm_crtc *crtc; | ||
245 | struct intel_crtc *intel_crtc; | ||
246 | int ret = 0; | ||
247 | int i; | ||
248 | |||
249 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
250 | for (i = 0; i < par->crtc_count; i++) | ||
251 | if (crtc->base.id == par->crtc_ids[i]) | ||
252 | break; | ||
253 | |||
254 | if (i == par->crtc_count) | ||
255 | continue; | ||
256 | |||
257 | intel_crtc = to_intel_crtc(crtc); | ||
258 | modeset = &intel_crtc->mode_set; | ||
259 | |||
260 | modeset->x = var->xoffset; | ||
261 | modeset->y = var->yoffset; | ||
262 | |||
263 | if (modeset->num_connectors) { | ||
264 | mutex_lock(&dev->mode_config.mutex); | ||
265 | ret = crtc->funcs->set_config(modeset); | ||
266 | mutex_unlock(&dev->mode_config.mutex); | ||
267 | if (!ret) { | ||
268 | info->var.xoffset = var->xoffset; | ||
269 | info->var.yoffset = var->yoffset; | ||
270 | } | ||
271 | } | ||
272 | } | ||
273 | |||
274 | return ret; | ||
275 | } | ||
276 | |||
277 | static void intelfb_on(struct fb_info *info) | ||
278 | { | ||
279 | struct intelfb_par *par = info->par; | ||
280 | struct drm_device *dev = par->dev; | ||
281 | struct drm_crtc *crtc; | ||
282 | struct drm_encoder *encoder; | ||
283 | int i; | ||
284 | |||
285 | /* | ||
286 | * For each CRTC in this fb, find all associated encoders | ||
287 | * and turn them off, then turn off the CRTC. | ||
288 | */ | ||
289 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
290 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
291 | |||
292 | for (i = 0; i < par->crtc_count; i++) | ||
293 | if (crtc->base.id == par->crtc_ids[i]) | ||
294 | break; | ||
295 | |||
296 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); | ||
297 | |||
298 | /* Found a CRTC on this fb, now find encoders */ | ||
299 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
300 | if (encoder->crtc == crtc) { | ||
301 | struct drm_encoder_helper_funcs *encoder_funcs; | ||
302 | encoder_funcs = encoder->helper_private; | ||
303 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); | ||
304 | } | ||
305 | } | ||
306 | } | ||
307 | } | ||
308 | |||
309 | static void intelfb_off(struct fb_info *info, int dpms_mode) | ||
310 | { | ||
311 | struct intelfb_par *par = info->par; | ||
312 | struct drm_device *dev = par->dev; | ||
313 | struct drm_crtc *crtc; | ||
314 | struct drm_encoder *encoder; | ||
315 | int i; | ||
316 | |||
317 | /* | ||
318 | * For each CRTC in this fb, find all associated encoders | ||
319 | * and turn them off, then turn off the CRTC. | ||
320 | */ | ||
321 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
322 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
323 | |||
324 | for (i = 0; i < par->crtc_count; i++) | ||
325 | if (crtc->base.id == par->crtc_ids[i]) | ||
326 | break; | ||
327 | |||
328 | /* Found a CRTC on this fb, now find encoders */ | ||
329 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
330 | if (encoder->crtc == crtc) { | ||
331 | struct drm_encoder_helper_funcs *encoder_funcs; | ||
332 | encoder_funcs = encoder->helper_private; | ||
333 | encoder_funcs->dpms(encoder, dpms_mode); | ||
334 | } | ||
335 | } | ||
336 | if (dpms_mode == DRM_MODE_DPMS_OFF) | ||
337 | crtc_funcs->dpms(crtc, dpms_mode); | ||
338 | } | ||
339 | } | ||
340 | |||
341 | int intelfb_blank(int blank, struct fb_info *info) | ||
342 | { | ||
343 | switch (blank) { | ||
344 | case FB_BLANK_UNBLANK: | ||
345 | intelfb_on(info); | ||
346 | break; | ||
347 | case FB_BLANK_NORMAL: | ||
348 | intelfb_off(info, DRM_MODE_DPMS_STANDBY); | ||
349 | break; | ||
350 | case FB_BLANK_HSYNC_SUSPEND: | ||
351 | intelfb_off(info, DRM_MODE_DPMS_STANDBY); | ||
352 | break; | ||
353 | case FB_BLANK_VSYNC_SUSPEND: | ||
354 | intelfb_off(info, DRM_MODE_DPMS_SUSPEND); | ||
355 | break; | ||
356 | case FB_BLANK_POWERDOWN: | ||
357 | intelfb_off(info, DRM_MODE_DPMS_OFF); | ||
358 | break; | ||
359 | } | ||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | static struct fb_ops intelfb_ops = { | ||
364 | .owner = THIS_MODULE, | ||
365 | .fb_check_var = intelfb_check_var, | ||
366 | .fb_set_par = intelfb_set_par, | ||
367 | .fb_setcolreg = intelfb_setcolreg, | ||
368 | .fb_fillrect = cfb_fillrect, | ||
369 | .fb_copyarea = cfb_copyarea, | ||
370 | .fb_imageblit = cfb_imageblit, | ||
371 | .fb_pan_display = intelfb_pan_display, | ||
372 | .fb_blank = intelfb_blank, | ||
373 | }; | ||
374 | |||
375 | /** | ||
376 | * Curretly it is assumed that the old framebuffer is reused. | ||
377 | * | ||
378 | * LOCKING | ||
379 | * caller should hold the mode config lock. | ||
380 | * | ||
381 | */ | ||
382 | int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) | ||
383 | { | ||
384 | struct fb_info *info; | ||
385 | struct drm_framebuffer *fb; | ||
386 | struct drm_display_mode *mode = crtc->desired_mode; | ||
387 | |||
388 | fb = crtc->fb; | ||
389 | if (!fb) | ||
390 | return 1; | ||
391 | |||
392 | info = fb->fbdev; | ||
393 | if (!info) | ||
394 | return 1; | ||
395 | |||
396 | if (!mode) | ||
397 | return 1; | ||
398 | |||
399 | info->var.xres = mode->hdisplay; | ||
400 | info->var.right_margin = mode->hsync_start - mode->hdisplay; | ||
401 | info->var.hsync_len = mode->hsync_end - mode->hsync_start; | ||
402 | info->var.left_margin = mode->htotal - mode->hsync_end; | ||
403 | info->var.yres = mode->vdisplay; | ||
404 | info->var.lower_margin = mode->vsync_start - mode->vdisplay; | ||
405 | info->var.vsync_len = mode->vsync_end - mode->vsync_start; | ||
406 | info->var.upper_margin = mode->vtotal - mode->vsync_end; | ||
407 | info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100; | ||
408 | /* avoid overflow */ | ||
409 | info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | EXPORT_SYMBOL(intelfb_resize); | ||
414 | |||
415 | static struct drm_mode_set kernelfb_mode; | ||
416 | |||
417 | int intelfb_panic(struct notifier_block *n, unsigned long ununsed, | ||
418 | void *panic_str) | ||
419 | { | ||
420 | DRM_ERROR("panic occurred, switching back to text console\n"); | ||
421 | |||
422 | intelfb_restore(); | ||
423 | return 0; | ||
424 | } | ||
425 | EXPORT_SYMBOL(intelfb_panic); | ||
426 | |||
427 | static struct notifier_block paniced = { | ||
428 | .notifier_call = intelfb_panic, | ||
429 | }; | ||
430 | |||
431 | int intelfb_create(struct drm_device *dev, uint32_t fb_width, | ||
432 | uint32_t fb_height, uint32_t surface_width, | ||
433 | uint32_t surface_height, | ||
434 | struct intel_framebuffer **intel_fb_p) | ||
435 | { | ||
436 | struct fb_info *info; | ||
437 | struct intelfb_par *par; | ||
438 | struct drm_framebuffer *fb; | ||
439 | struct intel_framebuffer *intel_fb; | ||
440 | struct drm_mode_fb_cmd mode_cmd; | ||
441 | struct drm_gem_object *fbo = NULL; | ||
442 | struct drm_i915_gem_object *obj_priv; | ||
443 | struct device *device = &dev->pdev->dev; | ||
444 | int size, ret, mmio_bar = IS_I9XX(dev) ? 0 : 1; | ||
445 | |||
446 | mode_cmd.width = surface_width; | ||
447 | mode_cmd.height = surface_height; | ||
448 | |||
449 | mode_cmd.bpp = 32; | ||
450 | mode_cmd.pitch = mode_cmd.width * ((mode_cmd.bpp + 1) / 8); | ||
451 | mode_cmd.depth = 24; | ||
452 | |||
453 | size = mode_cmd.pitch * mode_cmd.height; | ||
454 | size = ALIGN(size, PAGE_SIZE); | ||
455 | fbo = drm_gem_object_alloc(dev, size); | ||
456 | if (!fbo) { | ||
457 | printk(KERN_ERR "failed to allocate framebuffer\n"); | ||
458 | ret = -ENOMEM; | ||
459 | goto out; | ||
460 | } | ||
461 | obj_priv = fbo->driver_private; | ||
462 | |||
463 | mutex_lock(&dev->struct_mutex); | ||
464 | |||
465 | ret = i915_gem_object_pin(fbo, PAGE_SIZE); | ||
466 | if (ret) { | ||
467 | DRM_ERROR("failed to pin fb: %d\n", ret); | ||
468 | goto out_unref; | ||
469 | } | ||
470 | |||
471 | /* Flush everything out, we'll be doing GTT only from now on */ | ||
472 | i915_gem_object_set_to_gtt_domain(fbo, 1); | ||
473 | |||
474 | ret = intel_framebuffer_create(dev, &mode_cmd, &fb, fbo); | ||
475 | if (ret) { | ||
476 | DRM_ERROR("failed to allocate fb.\n"); | ||
477 | goto out_unref; | ||
478 | } | ||
479 | |||
480 | list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list); | ||
481 | |||
482 | intel_fb = to_intel_framebuffer(fb); | ||
483 | *intel_fb_p = intel_fb; | ||
484 | |||
485 | info = framebuffer_alloc(sizeof(struct intelfb_par), device); | ||
486 | if (!info) { | ||
487 | ret = -ENOMEM; | ||
488 | goto out_unref; | ||
489 | } | ||
490 | |||
491 | par = info->par; | ||
492 | |||
493 | strcpy(info->fix.id, "inteldrmfb"); | ||
494 | info->fix.type = FB_TYPE_PACKED_PIXELS; | ||
495 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
496 | info->fix.type_aux = 0; | ||
497 | info->fix.xpanstep = 1; /* doing it in hw */ | ||
498 | info->fix.ypanstep = 1; /* doing it in hw */ | ||
499 | info->fix.ywrapstep = 0; | ||
500 | info->fix.accel = FB_ACCEL_I830; | ||
501 | info->fix.type_aux = 0; | ||
502 | |||
503 | info->flags = FBINFO_DEFAULT; | ||
504 | |||
505 | info->fbops = &intelfb_ops; | ||
506 | |||
507 | info->fix.line_length = fb->pitch; | ||
508 | info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset; | ||
509 | info->fix.smem_len = size; | ||
510 | |||
511 | info->flags = FBINFO_DEFAULT; | ||
512 | |||
513 | info->screen_base = ioremap_wc(dev->agp->base + obj_priv->gtt_offset, | ||
514 | size); | ||
515 | if (!info->screen_base) { | ||
516 | ret = -ENOSPC; | ||
517 | goto out_unref; | ||
518 | } | ||
519 | info->screen_size = size; | ||
520 | |||
521 | // memset(info->screen_base, 0, size); | ||
522 | |||
523 | info->pseudo_palette = fb->pseudo_palette; | ||
524 | info->var.xres_virtual = fb->width; | ||
525 | info->var.yres_virtual = fb->height; | ||
526 | info->var.bits_per_pixel = fb->bits_per_pixel; | ||
527 | info->var.xoffset = 0; | ||
528 | info->var.yoffset = 0; | ||
529 | info->var.activate = FB_ACTIVATE_NOW; | ||
530 | info->var.height = -1; | ||
531 | info->var.width = -1; | ||
532 | |||
533 | info->var.xres = fb_width; | ||
534 | info->var.yres = fb_height; | ||
535 | |||
536 | /* FIXME: we really shouldn't expose mmio space at all */ | ||
537 | info->fix.mmio_start = pci_resource_start(dev->pdev, mmio_bar); | ||
538 | info->fix.mmio_len = pci_resource_len(dev->pdev, mmio_bar); | ||
539 | |||
540 | info->pixmap.size = 64*1024; | ||
541 | info->pixmap.buf_align = 8; | ||
542 | info->pixmap.access_align = 32; | ||
543 | info->pixmap.flags = FB_PIXMAP_SYSTEM; | ||
544 | info->pixmap.scan_align = 1; | ||
545 | |||
546 | switch(fb->depth) { | ||
547 | case 8: | ||
548 | info->var.red.offset = 0; | ||
549 | info->var.green.offset = 0; | ||
550 | info->var.blue.offset = 0; | ||
551 | info->var.red.length = 8; /* 8bit DAC */ | ||
552 | info->var.green.length = 8; | ||
553 | info->var.blue.length = 8; | ||
554 | info->var.transp.offset = 0; | ||
555 | info->var.transp.length = 0; | ||
556 | break; | ||
557 | case 15: | ||
558 | info->var.red.offset = 10; | ||
559 | info->var.green.offset = 5; | ||
560 | info->var.blue.offset = 0; | ||
561 | info->var.red.length = 5; | ||
562 | info->var.green.length = 5; | ||
563 | info->var.blue.length = 5; | ||
564 | info->var.transp.offset = 15; | ||
565 | info->var.transp.length = 1; | ||
566 | break; | ||
567 | case 16: | ||
568 | info->var.red.offset = 11; | ||
569 | info->var.green.offset = 5; | ||
570 | info->var.blue.offset = 0; | ||
571 | info->var.red.length = 5; | ||
572 | info->var.green.length = 6; | ||
573 | info->var.blue.length = 5; | ||
574 | info->var.transp.offset = 0; | ||
575 | break; | ||
576 | case 24: | ||
577 | info->var.red.offset = 16; | ||
578 | info->var.green.offset = 8; | ||
579 | info->var.blue.offset = 0; | ||
580 | info->var.red.length = 8; | ||
581 | info->var.green.length = 8; | ||
582 | info->var.blue.length = 8; | ||
583 | info->var.transp.offset = 0; | ||
584 | info->var.transp.length = 0; | ||
585 | break; | ||
586 | case 32: | ||
587 | info->var.red.offset = 16; | ||
588 | info->var.green.offset = 8; | ||
589 | info->var.blue.offset = 0; | ||
590 | info->var.red.length = 8; | ||
591 | info->var.green.length = 8; | ||
592 | info->var.blue.length = 8; | ||
593 | info->var.transp.offset = 24; | ||
594 | info->var.transp.length = 8; | ||
595 | break; | ||
596 | default: | ||
597 | break; | ||
598 | } | ||
599 | |||
600 | fb->fbdev = info; | ||
601 | |||
602 | par->intel_fb = intel_fb; | ||
603 | par->dev = dev; | ||
604 | |||
605 | /* To allow resizeing without swapping buffers */ | ||
606 | printk("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width, | ||
607 | intel_fb->base.height, obj_priv->gtt_offset, fbo); | ||
608 | |||
609 | mutex_unlock(&dev->struct_mutex); | ||
610 | return 0; | ||
611 | |||
612 | out_unref: | ||
613 | drm_gem_object_unreference(fbo); | ||
614 | mutex_unlock(&dev->struct_mutex); | ||
615 | out: | ||
616 | return ret; | ||
617 | } | ||
618 | |||
619 | static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *crtc) | ||
620 | { | ||
621 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
622 | struct intel_framebuffer *intel_fb; | ||
623 | struct drm_framebuffer *fb; | ||
624 | struct drm_connector *connector; | ||
625 | struct fb_info *info; | ||
626 | struct intelfb_par *par; | ||
627 | struct drm_mode_set *modeset; | ||
628 | unsigned int width, height; | ||
629 | int new_fb = 0; | ||
630 | int ret, i, conn_count; | ||
631 | |||
632 | if (!drm_helper_crtc_in_use(crtc)) | ||
633 | return 0; | ||
634 | |||
635 | if (!crtc->desired_mode) | ||
636 | return 0; | ||
637 | |||
638 | width = crtc->desired_mode->hdisplay; | ||
639 | height = crtc->desired_mode->vdisplay; | ||
640 | |||
641 | /* is there an fb bound to this crtc already */ | ||
642 | if (!intel_crtc->mode_set.fb) { | ||
643 | ret = intelfb_create(dev, width, height, width, height, &intel_fb); | ||
644 | if (ret) | ||
645 | return -EINVAL; | ||
646 | new_fb = 1; | ||
647 | } else { | ||
648 | fb = intel_crtc->mode_set.fb; | ||
649 | intel_fb = to_intel_framebuffer(fb); | ||
650 | if ((intel_fb->base.width < width) || (intel_fb->base.height < height)) | ||
651 | return -EINVAL; | ||
652 | } | ||
653 | |||
654 | info = intel_fb->base.fbdev; | ||
655 | par = info->par; | ||
656 | |||
657 | modeset = &intel_crtc->mode_set; | ||
658 | modeset->fb = &intel_fb->base; | ||
659 | conn_count = 0; | ||
660 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
661 | if (connector->encoder) | ||
662 | if (connector->encoder->crtc == modeset->crtc) { | ||
663 | modeset->connectors[conn_count] = connector; | ||
664 | conn_count++; | ||
665 | if (conn_count > INTELFB_CONN_LIMIT) | ||
666 | BUG(); | ||
667 | } | ||
668 | } | ||
669 | |||
670 | for (i = conn_count; i < INTELFB_CONN_LIMIT; i++) | ||
671 | modeset->connectors[i] = NULL; | ||
672 | |||
673 | par->crtc_ids[0] = crtc->base.id; | ||
674 | |||
675 | modeset->num_connectors = conn_count; | ||
676 | if (modeset->mode != modeset->crtc->desired_mode) | ||
677 | modeset->mode = modeset->crtc->desired_mode; | ||
678 | |||
679 | par->crtc_count = 1; | ||
680 | |||
681 | if (new_fb) { | ||
682 | info->var.pixclock = -1; | ||
683 | if (register_framebuffer(info) < 0) | ||
684 | return -EINVAL; | ||
685 | } else | ||
686 | intelfb_set_par(info); | ||
687 | |||
688 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, | ||
689 | info->fix.id); | ||
690 | |||
691 | /* Switch back to kernel console on panic */ | ||
692 | kernelfb_mode = *modeset; | ||
693 | atomic_notifier_chain_register(&panic_notifier_list, &paniced); | ||
694 | printk(KERN_INFO "registered panic notifier\n"); | ||
695 | |||
696 | return 0; | ||
697 | } | ||
698 | |||
699 | static int intelfb_multi_fb_probe(struct drm_device *dev) | ||
700 | { | ||
701 | |||
702 | struct drm_crtc *crtc; | ||
703 | int ret = 0; | ||
704 | |||
705 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
706 | ret = intelfb_multi_fb_probe_crtc(dev, crtc); | ||
707 | if (ret) | ||
708 | return ret; | ||
709 | } | ||
710 | return ret; | ||
711 | } | ||
712 | |||
713 | static int intelfb_single_fb_probe(struct drm_device *dev) | ||
714 | { | ||
715 | struct drm_crtc *crtc; | ||
716 | struct drm_connector *connector; | ||
717 | unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1; | ||
718 | unsigned int surface_width = 0, surface_height = 0; | ||
719 | int new_fb = 0; | ||
720 | int crtc_count = 0; | ||
721 | int ret, i, conn_count = 0; | ||
722 | struct intel_framebuffer *intel_fb; | ||
723 | struct fb_info *info; | ||
724 | struct intelfb_par *par; | ||
725 | struct drm_mode_set *modeset = NULL; | ||
726 | |||
727 | DRM_DEBUG("\n"); | ||
728 | |||
729 | /* Get a count of crtcs now in use and new min/maxes width/heights */ | ||
730 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
731 | if (!drm_helper_crtc_in_use(crtc)) | ||
732 | continue; | ||
733 | |||
734 | crtc_count++; | ||
735 | if (!crtc->desired_mode) | ||
736 | continue; | ||
737 | |||
738 | /* Smallest mode determines console size... */ | ||
739 | if (crtc->desired_mode->hdisplay < fb_width) | ||
740 | fb_width = crtc->desired_mode->hdisplay; | ||
741 | |||
742 | if (crtc->desired_mode->vdisplay < fb_height) | ||
743 | fb_height = crtc->desired_mode->vdisplay; | ||
744 | |||
745 | /* ... but largest for memory allocation dimensions */ | ||
746 | if (crtc->desired_mode->hdisplay > surface_width) | ||
747 | surface_width = crtc->desired_mode->hdisplay; | ||
748 | |||
749 | if (crtc->desired_mode->vdisplay > surface_height) | ||
750 | surface_height = crtc->desired_mode->vdisplay; | ||
751 | } | ||
752 | |||
753 | if (crtc_count == 0 || fb_width == -1 || fb_height == -1) { | ||
754 | /* hmm everyone went away - assume VGA cable just fell out | ||
755 | and will come back later. */ | ||
756 | DRM_DEBUG("no CRTCs available?\n"); | ||
757 | return 0; | ||
758 | } | ||
759 | |||
760 | //fail | ||
761 | /* Find the fb for our new config */ | ||
762 | if (list_empty(&dev->mode_config.fb_kernel_list)) { | ||
763 | DRM_DEBUG("creating new fb (console size %dx%d, " | ||
764 | "buffer size %dx%d)\n", fb_width, fb_height, | ||
765 | surface_width, surface_height); | ||
766 | ret = intelfb_create(dev, fb_width, fb_height, surface_width, | ||
767 | surface_height, &intel_fb); | ||
768 | if (ret) | ||
769 | return -EINVAL; | ||
770 | new_fb = 1; | ||
771 | } else { | ||
772 | struct drm_framebuffer *fb; | ||
773 | |||
774 | fb = list_first_entry(&dev->mode_config.fb_kernel_list, | ||
775 | struct drm_framebuffer, filp_head); | ||
776 | intel_fb = to_intel_framebuffer(fb); | ||
777 | |||
778 | /* if someone hotplugs something bigger than we have already | ||
779 | * allocated, we are pwned. As really we can't resize an | ||
780 | * fbdev that is in the wild currently due to fbdev not really | ||
781 | * being designed for the lower layers moving stuff around | ||
782 | * under it. | ||
783 | * - so in the grand style of things - punt. | ||
784 | */ | ||
785 | if ((fb->width < surface_width) || | ||
786 | (fb->height < surface_height)) { | ||
787 | DRM_ERROR("fb not large enough for console\n"); | ||
788 | return -EINVAL; | ||
789 | } | ||
790 | } | ||
791 | // fail | ||
792 | |||
793 | info = intel_fb->base.fbdev; | ||
794 | par = info->par; | ||
795 | |||
796 | crtc_count = 0; | ||
797 | /* | ||
798 | * For each CRTC, set up the connector list for the CRTC's mode | ||
799 | * set configuration. | ||
800 | */ | ||
801 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
802 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
803 | |||
804 | modeset = &intel_crtc->mode_set; | ||
805 | modeset->fb = &intel_fb->base; | ||
806 | conn_count = 0; | ||
807 | list_for_each_entry(connector, &dev->mode_config.connector_list, | ||
808 | head) { | ||
809 | if (!connector->encoder) | ||
810 | continue; | ||
811 | |||
812 | if(connector->encoder->crtc == modeset->crtc) { | ||
813 | modeset->connectors[conn_count++] = connector; | ||
814 | if (conn_count > INTELFB_CONN_LIMIT) | ||
815 | BUG(); | ||
816 | } | ||
817 | } | ||
818 | |||
819 | /* Zero out remaining connector pointers */ | ||
820 | for (i = conn_count; i < INTELFB_CONN_LIMIT; i++) | ||
821 | modeset->connectors[i] = NULL; | ||
822 | |||
823 | par->crtc_ids[crtc_count++] = crtc->base.id; | ||
824 | |||
825 | modeset->num_connectors = conn_count; | ||
826 | if (modeset->mode != modeset->crtc->desired_mode) | ||
827 | modeset->mode = modeset->crtc->desired_mode; | ||
828 | } | ||
829 | par->crtc_count = crtc_count; | ||
830 | |||
831 | if (new_fb) { | ||
832 | info->var.pixclock = -1; | ||
833 | if (register_framebuffer(info) < 0) | ||
834 | return -EINVAL; | ||
835 | } else | ||
836 | intelfb_set_par(info); | ||
837 | |||
838 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, | ||
839 | info->fix.id); | ||
840 | |||
841 | /* Switch back to kernel console on panic */ | ||
842 | kernelfb_mode = *modeset; | ||
843 | atomic_notifier_chain_register(&panic_notifier_list, &paniced); | ||
844 | printk(KERN_INFO "registered panic notifier\n"); | ||
845 | |||
846 | return 0; | ||
847 | } | ||
848 | |||
849 | /** | ||
850 | * intelfb_restore - restore the framebuffer console (kernel) config | ||
851 | * | ||
852 | * Restore's the kernel's fbcon mode, used for lastclose & panic paths. | ||
853 | */ | ||
854 | void intelfb_restore(void) | ||
855 | { | ||
856 | drm_crtc_helper_set_config(&kernelfb_mode); | ||
857 | } | ||
858 | |||
859 | static void intelfb_sysrq(int dummy1, struct tty_struct *dummy3) | ||
860 | { | ||
861 | intelfb_restore(); | ||
862 | } | ||
863 | |||
864 | static struct sysrq_key_op sysrq_intelfb_restore_op = { | ||
865 | .handler = intelfb_sysrq, | ||
866 | .help_msg = "force fb", | ||
867 | .action_msg = "force restore of fb console", | ||
868 | }; | ||
869 | |||
870 | int intelfb_probe(struct drm_device *dev) | ||
871 | { | ||
872 | int ret; | ||
873 | |||
874 | DRM_DEBUG("\n"); | ||
875 | |||
876 | /* something has changed in the lower levels of hell - deal with it | ||
877 | here */ | ||
878 | |||
879 | /* two modes : a) 1 fb to rule all crtcs. | ||
880 | b) one fb per crtc. | ||
881 | two actions 1) new connected device | ||
882 | 2) device removed. | ||
883 | case a/1 : if the fb surface isn't big enough - resize the surface fb. | ||
884 | if the fb size isn't big enough - resize fb into surface. | ||
885 | if everything big enough configure the new crtc/etc. | ||
886 | case a/2 : undo the configuration | ||
887 | possibly resize down the fb to fit the new configuration. | ||
888 | case b/1 : see if it is on a new crtc - setup a new fb and add it. | ||
889 | case b/2 : teardown the new fb. | ||
890 | */ | ||
891 | |||
892 | /* mode a first */ | ||
893 | /* search for an fb */ | ||
894 | if (i915_fbpercrtc == 1) { | ||
895 | ret = intelfb_multi_fb_probe(dev); | ||
896 | } else { | ||
897 | ret = intelfb_single_fb_probe(dev); | ||
898 | } | ||
899 | |||
900 | register_sysrq_key('g', &sysrq_intelfb_restore_op); | ||
901 | |||
902 | return ret; | ||
903 | } | ||
904 | EXPORT_SYMBOL(intelfb_probe); | ||
905 | |||
906 | int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) | ||
907 | { | ||
908 | struct fb_info *info; | ||
909 | |||
910 | if (!fb) | ||
911 | return -EINVAL; | ||
912 | |||
913 | info = fb->fbdev; | ||
914 | |||
915 | if (info) { | ||
916 | unregister_framebuffer(info); | ||
917 | iounmap(info->screen_base); | ||
918 | framebuffer_release(info); | ||
919 | } | ||
920 | |||
921 | atomic_notifier_chain_unregister(&panic_notifier_list, &paniced); | ||
922 | memset(&kernelfb_mode, 0, sizeof(struct drm_mode_set)); | ||
923 | return 0; | ||
924 | } | ||
925 | EXPORT_SYMBOL(intelfb_remove); | ||
926 | MODULE_LICENSE("GPL and additional rights"); | ||
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c new file mode 100644 index 000000000000..a5a2f5339e9e --- /dev/null +++ b/drivers/gpu/drm/i915/intel_i2c.c | |||
@@ -0,0 +1,184 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2006 Dave Airlie <airlied@linux.ie> | ||
3 | * Copyright © 2006-2008 Intel Corporation | ||
4 | * Jesse Barnes <jesse.barnes@intel.com> | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the "Software"), | ||
8 | * to deal in the Software without restriction, including without limitation | ||
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
10 | * and/or sell copies of the Software, and to permit persons to whom the | ||
11 | * Software is furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice (including the next | ||
14 | * paragraph) shall be included in all copies or substantial portions of the | ||
15 | * Software. | ||
16 | * | ||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
23 | * DEALINGS IN THE SOFTWARE. | ||
24 | * | ||
25 | * Authors: | ||
26 | * Eric Anholt <eric@anholt.net> | ||
27 | */ | ||
28 | #include <linux/i2c.h> | ||
29 | #include <linux/i2c-id.h> | ||
30 | #include <linux/i2c-algo-bit.h> | ||
31 | #include "drmP.h" | ||
32 | #include "drm.h" | ||
33 | #include "intel_drv.h" | ||
34 | #include "i915_drm.h" | ||
35 | #include "i915_drv.h" | ||
36 | |||
37 | /* | ||
38 | * Intel GPIO access functions | ||
39 | */ | ||
40 | |||
41 | #define I2C_RISEFALL_TIME 20 | ||
42 | |||
43 | static int get_clock(void *data) | ||
44 | { | ||
45 | struct intel_i2c_chan *chan = data; | ||
46 | struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; | ||
47 | u32 val; | ||
48 | |||
49 | val = I915_READ(chan->reg); | ||
50 | return ((val & GPIO_CLOCK_VAL_IN) != 0); | ||
51 | } | ||
52 | |||
53 | static int get_data(void *data) | ||
54 | { | ||
55 | struct intel_i2c_chan *chan = data; | ||
56 | struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; | ||
57 | u32 val; | ||
58 | |||
59 | val = I915_READ(chan->reg); | ||
60 | return ((val & GPIO_DATA_VAL_IN) != 0); | ||
61 | } | ||
62 | |||
63 | static void set_clock(void *data, int state_high) | ||
64 | { | ||
65 | struct intel_i2c_chan *chan = data; | ||
66 | struct drm_device *dev = chan->drm_dev; | ||
67 | struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; | ||
68 | u32 reserved = 0, clock_bits; | ||
69 | |||
70 | /* On most chips, these bits must be preserved in software. */ | ||
71 | if (!IS_I830(dev) && !IS_845G(dev)) | ||
72 | reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | | ||
73 | GPIO_CLOCK_PULLUP_DISABLE); | ||
74 | |||
75 | if (state_high) | ||
76 | clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK; | ||
77 | else | ||
78 | clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK | | ||
79 | GPIO_CLOCK_VAL_MASK; | ||
80 | I915_WRITE(chan->reg, reserved | clock_bits); | ||
81 | udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ | ||
82 | } | ||
83 | |||
84 | static void set_data(void *data, int state_high) | ||
85 | { | ||
86 | struct intel_i2c_chan *chan = data; | ||
87 | struct drm_device *dev = chan->drm_dev; | ||
88 | struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; | ||
89 | u32 reserved = 0, data_bits; | ||
90 | |||
91 | /* On most chips, these bits must be preserved in software. */ | ||
92 | if (!IS_I830(dev) && !IS_845G(dev)) | ||
93 | reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | | ||
94 | GPIO_CLOCK_PULLUP_DISABLE); | ||
95 | |||
96 | if (state_high) | ||
97 | data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK; | ||
98 | else | ||
99 | data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK | | ||
100 | GPIO_DATA_VAL_MASK; | ||
101 | |||
102 | I915_WRITE(chan->reg, reserved | data_bits); | ||
103 | udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ | ||
104 | } | ||
105 | |||
106 | /** | ||
107 | * intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg | ||
108 | * @dev: DRM device | ||
109 | * @output: driver specific output device | ||
110 | * @reg: GPIO reg to use | ||
111 | * @name: name for this bus | ||
112 | * | ||
113 | * Creates and registers a new i2c bus with the Linux i2c layer, for use | ||
114 | * in output probing and control (e.g. DDC or SDVO control functions). | ||
115 | * | ||
116 | * Possible values for @reg include: | ||
117 | * %GPIOA | ||
118 | * %GPIOB | ||
119 | * %GPIOC | ||
120 | * %GPIOD | ||
121 | * %GPIOE | ||
122 | * %GPIOF | ||
123 | * %GPIOG | ||
124 | * %GPIOH | ||
125 | * see PRM for details on how these different busses are used. | ||
126 | */ | ||
127 | struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, | ||
128 | const char *name) | ||
129 | { | ||
130 | struct intel_i2c_chan *chan; | ||
131 | |||
132 | chan = kzalloc(sizeof(struct intel_i2c_chan), GFP_KERNEL); | ||
133 | if (!chan) | ||
134 | goto out_free; | ||
135 | |||
136 | chan->drm_dev = dev; | ||
137 | chan->reg = reg; | ||
138 | snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name); | ||
139 | chan->adapter.owner = THIS_MODULE; | ||
140 | #ifndef I2C_HW_B_INTELFB | ||
141 | #define I2C_HW_B_INTELFB I2C_HW_B_I810 | ||
142 | #endif | ||
143 | chan->adapter.id = I2C_HW_B_INTELFB; | ||
144 | chan->adapter.algo_data = &chan->algo; | ||
145 | chan->adapter.dev.parent = &dev->pdev->dev; | ||
146 | chan->algo.setsda = set_data; | ||
147 | chan->algo.setscl = set_clock; | ||
148 | chan->algo.getsda = get_data; | ||
149 | chan->algo.getscl = get_clock; | ||
150 | chan->algo.udelay = 20; | ||
151 | chan->algo.timeout = usecs_to_jiffies(2200); | ||
152 | chan->algo.data = chan; | ||
153 | |||
154 | i2c_set_adapdata(&chan->adapter, chan); | ||
155 | |||
156 | if(i2c_bit_add_bus(&chan->adapter)) | ||
157 | goto out_free; | ||
158 | |||
159 | /* JJJ: raise SCL and SDA? */ | ||
160 | set_data(chan, 1); | ||
161 | set_clock(chan, 1); | ||
162 | udelay(20); | ||
163 | |||
164 | return chan; | ||
165 | |||
166 | out_free: | ||
167 | kfree(chan); | ||
168 | return NULL; | ||
169 | } | ||
170 | |||
171 | /** | ||
172 | * intel_i2c_destroy - unregister and free i2c bus resources | ||
173 | * @output: channel to free | ||
174 | * | ||
175 | * Unregister the adapter from the i2c layer, then free the structure. | ||
176 | */ | ||
177 | void intel_i2c_destroy(struct intel_i2c_chan *chan) | ||
178 | { | ||
179 | if (!chan) | ||
180 | return; | ||
181 | |||
182 | i2c_del_adapter(&chan->adapter); | ||
183 | kfree(chan); | ||
184 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c new file mode 100644 index 000000000000..ccecfaf6307b --- /dev/null +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
@@ -0,0 +1,525 @@ | |||
1 | /* | ||
2 | * Copyright © 2006-2007 Intel Corporation | ||
3 | * Copyright (c) 2006 Dave Airlie <airlied@linux.ie> | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
6 | * copy of this software and associated documentation files (the "Software"), | ||
7 | * to deal in the Software without restriction, including without limitation | ||
8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
9 | * and/or sell copies of the Software, and to permit persons to whom the | ||
10 | * Software is furnished to do so, subject to the following conditions: | ||
11 | * | ||
12 | * The above copyright notice and this permission notice (including the next | ||
13 | * paragraph) shall be included in all copies or substantial portions of the | ||
14 | * Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
22 | * DEALINGS IN THE SOFTWARE. | ||
23 | * | ||
24 | * Authors: | ||
25 | * Eric Anholt <eric@anholt.net> | ||
26 | * Dave Airlie <airlied@linux.ie> | ||
27 | * Jesse Barnes <jesse.barnes@intel.com> | ||
28 | */ | ||
29 | |||
30 | #include <linux/i2c.h> | ||
31 | #include "drmP.h" | ||
32 | #include "drm.h" | ||
33 | #include "drm_crtc.h" | ||
34 | #include "drm_edid.h" | ||
35 | #include "intel_drv.h" | ||
36 | #include "i915_drm.h" | ||
37 | #include "i915_drv.h" | ||
38 | |||
39 | /** | ||
40 | * Sets the backlight level. | ||
41 | * | ||
42 | * \param level backlight level, from 0 to intel_lvds_get_max_backlight(). | ||
43 | */ | ||
44 | static void intel_lvds_set_backlight(struct drm_device *dev, int level) | ||
45 | { | ||
46 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
47 | u32 blc_pwm_ctl; | ||
48 | |||
49 | blc_pwm_ctl = I915_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK; | ||
50 | I915_WRITE(BLC_PWM_CTL, (blc_pwm_ctl | | ||
51 | (level << BACKLIGHT_DUTY_CYCLE_SHIFT))); | ||
52 | } | ||
53 | |||
54 | /** | ||
55 | * Returns the maximum level of the backlight duty cycle field. | ||
56 | */ | ||
57 | static u32 intel_lvds_get_max_backlight(struct drm_device *dev) | ||
58 | { | ||
59 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
60 | |||
61 | return ((I915_READ(BLC_PWM_CTL) & BACKLIGHT_MODULATION_FREQ_MASK) >> | ||
62 | BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; | ||
63 | } | ||
64 | |||
65 | /** | ||
66 | * Sets the power state for the panel. | ||
67 | */ | ||
68 | static void intel_lvds_set_power(struct drm_device *dev, bool on) | ||
69 | { | ||
70 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
71 | u32 pp_status; | ||
72 | |||
73 | if (on) { | ||
74 | I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | | ||
75 | POWER_TARGET_ON); | ||
76 | do { | ||
77 | pp_status = I915_READ(PP_STATUS); | ||
78 | } while ((pp_status & PP_ON) == 0); | ||
79 | |||
80 | intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle); | ||
81 | } else { | ||
82 | intel_lvds_set_backlight(dev, 0); | ||
83 | |||
84 | I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & | ||
85 | ~POWER_TARGET_ON); | ||
86 | do { | ||
87 | pp_status = I915_READ(PP_STATUS); | ||
88 | } while (pp_status & PP_ON); | ||
89 | } | ||
90 | } | ||
91 | |||
92 | static void intel_lvds_dpms(struct drm_encoder *encoder, int mode) | ||
93 | { | ||
94 | struct drm_device *dev = encoder->dev; | ||
95 | |||
96 | if (mode == DRM_MODE_DPMS_ON) | ||
97 | intel_lvds_set_power(dev, true); | ||
98 | else | ||
99 | intel_lvds_set_power(dev, false); | ||
100 | |||
101 | /* XXX: We never power down the LVDS pairs. */ | ||
102 | } | ||
103 | |||
104 | static void intel_lvds_save(struct drm_connector *connector) | ||
105 | { | ||
106 | struct drm_device *dev = connector->dev; | ||
107 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
108 | |||
109 | dev_priv->savePP_ON = I915_READ(PP_ON_DELAYS); | ||
110 | dev_priv->savePP_OFF = I915_READ(PP_OFF_DELAYS); | ||
111 | dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL); | ||
112 | dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR); | ||
113 | dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); | ||
114 | dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & | ||
115 | BACKLIGHT_DUTY_CYCLE_MASK); | ||
116 | |||
117 | /* | ||
118 | * If the light is off at server startup, just make it full brightness | ||
119 | */ | ||
120 | if (dev_priv->backlight_duty_cycle == 0) | ||
121 | dev_priv->backlight_duty_cycle = | ||
122 | intel_lvds_get_max_backlight(dev); | ||
123 | } | ||
124 | |||
125 | static void intel_lvds_restore(struct drm_connector *connector) | ||
126 | { | ||
127 | struct drm_device *dev = connector->dev; | ||
128 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
129 | |||
130 | I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL); | ||
131 | I915_WRITE(PP_ON_DELAYS, dev_priv->savePP_ON); | ||
132 | I915_WRITE(PP_OFF_DELAYS, dev_priv->savePP_OFF); | ||
133 | I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR); | ||
134 | I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL); | ||
135 | if (dev_priv->savePP_CONTROL & POWER_TARGET_ON) | ||
136 | intel_lvds_set_power(dev, true); | ||
137 | else | ||
138 | intel_lvds_set_power(dev, false); | ||
139 | } | ||
140 | |||
141 | static int intel_lvds_mode_valid(struct drm_connector *connector, | ||
142 | struct drm_display_mode *mode) | ||
143 | { | ||
144 | struct drm_device *dev = connector->dev; | ||
145 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
146 | struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode; | ||
147 | |||
148 | if (fixed_mode) { | ||
149 | if (mode->hdisplay > fixed_mode->hdisplay) | ||
150 | return MODE_PANEL; | ||
151 | if (mode->vdisplay > fixed_mode->vdisplay) | ||
152 | return MODE_PANEL; | ||
153 | } | ||
154 | |||
155 | return MODE_OK; | ||
156 | } | ||
157 | |||
158 | static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, | ||
159 | struct drm_display_mode *mode, | ||
160 | struct drm_display_mode *adjusted_mode) | ||
161 | { | ||
162 | struct drm_device *dev = encoder->dev; | ||
163 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
164 | struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); | ||
165 | struct drm_encoder *tmp_encoder; | ||
166 | |||
167 | /* Should never happen!! */ | ||
168 | if (!IS_I965G(dev) && intel_crtc->pipe == 0) { | ||
169 | printk(KERN_ERR "Can't support LVDS on pipe A\n"); | ||
170 | return false; | ||
171 | } | ||
172 | |||
173 | /* Should never happen!! */ | ||
174 | list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list, head) { | ||
175 | if (tmp_encoder != encoder && tmp_encoder->crtc == encoder->crtc) { | ||
176 | printk(KERN_ERR "Can't enable LVDS and another " | ||
177 | "encoder on the same pipe\n"); | ||
178 | return false; | ||
179 | } | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * If we have timings from the BIOS for the panel, put them in | ||
184 | * to the adjusted mode. The CRTC will be set up for this mode, | ||
185 | * with the panel scaling set up to source from the H/VDisplay | ||
186 | * of the original mode. | ||
187 | */ | ||
188 | if (dev_priv->panel_fixed_mode != NULL) { | ||
189 | adjusted_mode->hdisplay = dev_priv->panel_fixed_mode->hdisplay; | ||
190 | adjusted_mode->hsync_start = | ||
191 | dev_priv->panel_fixed_mode->hsync_start; | ||
192 | adjusted_mode->hsync_end = | ||
193 | dev_priv->panel_fixed_mode->hsync_end; | ||
194 | adjusted_mode->htotal = dev_priv->panel_fixed_mode->htotal; | ||
195 | adjusted_mode->vdisplay = dev_priv->panel_fixed_mode->vdisplay; | ||
196 | adjusted_mode->vsync_start = | ||
197 | dev_priv->panel_fixed_mode->vsync_start; | ||
198 | adjusted_mode->vsync_end = | ||
199 | dev_priv->panel_fixed_mode->vsync_end; | ||
200 | adjusted_mode->vtotal = dev_priv->panel_fixed_mode->vtotal; | ||
201 | adjusted_mode->clock = dev_priv->panel_fixed_mode->clock; | ||
202 | drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * XXX: It would be nice to support lower refresh rates on the | ||
207 | * panels to reduce power consumption, and perhaps match the | ||
208 | * user's requested refresh rate. | ||
209 | */ | ||
210 | |||
211 | return true; | ||
212 | } | ||
213 | |||
214 | static void intel_lvds_prepare(struct drm_encoder *encoder) | ||
215 | { | ||
216 | struct drm_device *dev = encoder->dev; | ||
217 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
218 | |||
219 | dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); | ||
220 | dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL & | ||
221 | BACKLIGHT_DUTY_CYCLE_MASK); | ||
222 | |||
223 | intel_lvds_set_power(dev, false); | ||
224 | } | ||
225 | |||
226 | static void intel_lvds_commit( struct drm_encoder *encoder) | ||
227 | { | ||
228 | struct drm_device *dev = encoder->dev; | ||
229 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
230 | |||
231 | if (dev_priv->backlight_duty_cycle == 0) | ||
232 | dev_priv->backlight_duty_cycle = | ||
233 | intel_lvds_get_max_backlight(dev); | ||
234 | |||
235 | intel_lvds_set_power(dev, true); | ||
236 | } | ||
237 | |||
238 | static void intel_lvds_mode_set(struct drm_encoder *encoder, | ||
239 | struct drm_display_mode *mode, | ||
240 | struct drm_display_mode *adjusted_mode) | ||
241 | { | ||
242 | struct drm_device *dev = encoder->dev; | ||
243 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
244 | struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); | ||
245 | u32 pfit_control; | ||
246 | |||
247 | /* | ||
248 | * The LVDS pin pair will already have been turned on in the | ||
249 | * intel_crtc_mode_set since it has a large impact on the DPLL | ||
250 | * settings. | ||
251 | */ | ||
252 | |||
253 | /* | ||
254 | * Enable automatic panel scaling so that non-native modes fill the | ||
255 | * screen. Should be enabled before the pipe is enabled, according to | ||
256 | * register description and PRM. | ||
257 | */ | ||
258 | if (mode->hdisplay != adjusted_mode->hdisplay || | ||
259 | mode->vdisplay != adjusted_mode->vdisplay) | ||
260 | pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE | | ||
261 | HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR | | ||
262 | HORIZ_INTERP_BILINEAR); | ||
263 | else | ||
264 | pfit_control = 0; | ||
265 | |||
266 | if (!IS_I965G(dev)) { | ||
267 | if (dev_priv->panel_wants_dither) | ||
268 | pfit_control |= PANEL_8TO6_DITHER_ENABLE; | ||
269 | } | ||
270 | else | ||
271 | pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT; | ||
272 | |||
273 | I915_WRITE(PFIT_CONTROL, pfit_control); | ||
274 | } | ||
275 | |||
276 | /** | ||
277 | * Detect the LVDS connection. | ||
278 | * | ||
279 | * This always returns CONNECTOR_STATUS_CONNECTED. This connector should only have | ||
280 | * been set up if the LVDS was actually connected anyway. | ||
281 | */ | ||
282 | static enum drm_connector_status intel_lvds_detect(struct drm_connector *connector) | ||
283 | { | ||
284 | return connector_status_connected; | ||
285 | } | ||
286 | |||
287 | /** | ||
288 | * Return the list of DDC modes if available, or the BIOS fixed mode otherwise. | ||
289 | */ | ||
290 | static int intel_lvds_get_modes(struct drm_connector *connector) | ||
291 | { | ||
292 | struct drm_device *dev = connector->dev; | ||
293 | struct intel_output *intel_output = to_intel_output(connector); | ||
294 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
295 | int ret = 0; | ||
296 | |||
297 | ret = intel_ddc_get_modes(intel_output); | ||
298 | |||
299 | if (ret) | ||
300 | return ret; | ||
301 | |||
302 | /* Didn't get an EDID, so | ||
303 | * Set wide sync ranges so we get all modes | ||
304 | * handed to valid_mode for checking | ||
305 | */ | ||
306 | connector->display_info.min_vfreq = 0; | ||
307 | connector->display_info.max_vfreq = 200; | ||
308 | connector->display_info.min_hfreq = 0; | ||
309 | connector->display_info.max_hfreq = 200; | ||
310 | |||
311 | if (dev_priv->panel_fixed_mode != NULL) { | ||
312 | struct drm_display_mode *mode; | ||
313 | |||
314 | mutex_unlock(&dev->mode_config.mutex); | ||
315 | mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode); | ||
316 | drm_mode_probed_add(connector, mode); | ||
317 | mutex_unlock(&dev->mode_config.mutex); | ||
318 | |||
319 | return 1; | ||
320 | } | ||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | /** | ||
326 | * intel_lvds_destroy - unregister and free LVDS structures | ||
327 | * @connector: connector to free | ||
328 | * | ||
329 | * Unregister the DDC bus for this connector then free the driver private | ||
330 | * structure. | ||
331 | */ | ||
332 | static void intel_lvds_destroy(struct drm_connector *connector) | ||
333 | { | ||
334 | struct intel_output *intel_output = to_intel_output(connector); | ||
335 | |||
336 | if (intel_output->ddc_bus) | ||
337 | intel_i2c_destroy(intel_output->ddc_bus); | ||
338 | drm_sysfs_connector_remove(connector); | ||
339 | drm_connector_cleanup(connector); | ||
340 | kfree(connector); | ||
341 | } | ||
342 | |||
343 | static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = { | ||
344 | .dpms = intel_lvds_dpms, | ||
345 | .mode_fixup = intel_lvds_mode_fixup, | ||
346 | .prepare = intel_lvds_prepare, | ||
347 | .mode_set = intel_lvds_mode_set, | ||
348 | .commit = intel_lvds_commit, | ||
349 | }; | ||
350 | |||
351 | static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = { | ||
352 | .get_modes = intel_lvds_get_modes, | ||
353 | .mode_valid = intel_lvds_mode_valid, | ||
354 | .best_encoder = intel_best_encoder, | ||
355 | }; | ||
356 | |||
357 | static const struct drm_connector_funcs intel_lvds_connector_funcs = { | ||
358 | .save = intel_lvds_save, | ||
359 | .restore = intel_lvds_restore, | ||
360 | .detect = intel_lvds_detect, | ||
361 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
362 | .destroy = intel_lvds_destroy, | ||
363 | }; | ||
364 | |||
365 | |||
366 | static void intel_lvds_enc_destroy(struct drm_encoder *encoder) | ||
367 | { | ||
368 | drm_encoder_cleanup(encoder); | ||
369 | } | ||
370 | |||
371 | static const struct drm_encoder_funcs intel_lvds_enc_funcs = { | ||
372 | .destroy = intel_lvds_enc_destroy, | ||
373 | }; | ||
374 | |||
375 | |||
376 | |||
377 | /** | ||
378 | * intel_lvds_init - setup LVDS connectors on this device | ||
379 | * @dev: drm device | ||
380 | * | ||
381 | * Create the connector, register the LVDS DDC bus, and try to figure out what | ||
382 | * modes we can display on the LVDS panel (if present). | ||
383 | */ | ||
384 | void intel_lvds_init(struct drm_device *dev) | ||
385 | { | ||
386 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
387 | struct intel_output *intel_output; | ||
388 | struct drm_connector *connector; | ||
389 | struct drm_encoder *encoder; | ||
390 | struct drm_display_mode *scan; /* *modes, *bios_mode; */ | ||
391 | struct drm_crtc *crtc; | ||
392 | u32 lvds; | ||
393 | int pipe; | ||
394 | |||
395 | intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL); | ||
396 | if (!intel_output) { | ||
397 | return; | ||
398 | } | ||
399 | |||
400 | connector = &intel_output->base; | ||
401 | encoder = &intel_output->enc; | ||
402 | drm_connector_init(dev, &intel_output->base, &intel_lvds_connector_funcs, | ||
403 | DRM_MODE_CONNECTOR_LVDS); | ||
404 | |||
405 | drm_encoder_init(dev, &intel_output->enc, &intel_lvds_enc_funcs, | ||
406 | DRM_MODE_ENCODER_LVDS); | ||
407 | |||
408 | drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); | ||
409 | intel_output->type = INTEL_OUTPUT_LVDS; | ||
410 | |||
411 | drm_encoder_helper_add(encoder, &intel_lvds_helper_funcs); | ||
412 | drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs); | ||
413 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
414 | connector->interlace_allowed = false; | ||
415 | connector->doublescan_allowed = false; | ||
416 | |||
417 | |||
418 | /* | ||
419 | * LVDS discovery: | ||
420 | * 1) check for EDID on DDC | ||
421 | * 2) check for VBT data | ||
422 | * 3) check to see if LVDS is already on | ||
423 | * if none of the above, no panel | ||
424 | * 4) make sure lid is open | ||
425 | * if closed, act like it's not there for now | ||
426 | */ | ||
427 | |||
428 | /* Set up the DDC bus. */ | ||
429 | intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C"); | ||
430 | if (!intel_output->ddc_bus) { | ||
431 | dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " | ||
432 | "failed.\n"); | ||
433 | goto failed; | ||
434 | } | ||
435 | |||
436 | /* | ||
437 | * Attempt to get the fixed panel mode from DDC. Assume that the | ||
438 | * preferred mode is the right one. | ||
439 | */ | ||
440 | intel_ddc_get_modes(intel_output); | ||
441 | |||
442 | list_for_each_entry(scan, &connector->probed_modes, head) { | ||
443 | mutex_lock(&dev->mode_config.mutex); | ||
444 | if (scan->type & DRM_MODE_TYPE_PREFERRED) { | ||
445 | dev_priv->panel_fixed_mode = | ||
446 | drm_mode_duplicate(dev, scan); | ||
447 | mutex_unlock(&dev->mode_config.mutex); | ||
448 | goto out; /* FIXME: check for quirks */ | ||
449 | } | ||
450 | mutex_unlock(&dev->mode_config.mutex); | ||
451 | } | ||
452 | |||
453 | /* Failed to get EDID, what about VBT? */ | ||
454 | if (dev_priv->vbt_mode) { | ||
455 | mutex_lock(&dev->mode_config.mutex); | ||
456 | dev_priv->panel_fixed_mode = | ||
457 | drm_mode_duplicate(dev, dev_priv->vbt_mode); | ||
458 | mutex_unlock(&dev->mode_config.mutex); | ||
459 | } | ||
460 | |||
461 | /* | ||
462 | * If we didn't get EDID, try checking if the panel is already turned | ||
463 | * on. If so, assume that whatever is currently programmed is the | ||
464 | * correct mode. | ||
465 | */ | ||
466 | lvds = I915_READ(LVDS); | ||
467 | pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0; | ||
468 | crtc = intel_get_crtc_from_pipe(dev, pipe); | ||
469 | |||
470 | if (crtc && (lvds & LVDS_PORT_EN)) { | ||
471 | dev_priv->panel_fixed_mode = intel_crtc_mode_get(dev, crtc); | ||
472 | if (dev_priv->panel_fixed_mode) { | ||
473 | dev_priv->panel_fixed_mode->type |= | ||
474 | DRM_MODE_TYPE_PREFERRED; | ||
475 | goto out; /* FIXME: check for quirks */ | ||
476 | } | ||
477 | } | ||
478 | |||
479 | /* If we still don't have a mode after all that, give up. */ | ||
480 | if (!dev_priv->panel_fixed_mode) | ||
481 | goto failed; | ||
482 | |||
483 | /* FIXME: detect aopen & mac mini type stuff automatically? */ | ||
484 | /* | ||
485 | * Blacklist machines with BIOSes that list an LVDS panel without | ||
486 | * actually having one. | ||
487 | */ | ||
488 | if (IS_I945GM(dev)) { | ||
489 | /* aopen mini pc */ | ||
490 | if (dev->pdev->subsystem_vendor == 0xa0a0) | ||
491 | goto failed; | ||
492 | |||
493 | if ((dev->pdev->subsystem_vendor == 0x8086) && | ||
494 | (dev->pdev->subsystem_device == 0x7270)) { | ||
495 | /* It's a Mac Mini or Macbook Pro. | ||
496 | * | ||
497 | * Apple hardware is out to get us. The macbook pro | ||
498 | * has a real LVDS panel, but the mac mini does not, | ||
499 | * and they have the same device IDs. We'll | ||
500 | * distinguish by panel size, on the assumption | ||
501 | * that Apple isn't about to make any machines with an | ||
502 | * 800x600 display. | ||
503 | */ | ||
504 | |||
505 | if (dev_priv->panel_fixed_mode != NULL && | ||
506 | dev_priv->panel_fixed_mode->hdisplay == 800 && | ||
507 | dev_priv->panel_fixed_mode->vdisplay == 600) { | ||
508 | DRM_DEBUG("Suspected Mac Mini, ignoring the LVDS\n"); | ||
509 | goto failed; | ||
510 | } | ||
511 | } | ||
512 | } | ||
513 | |||
514 | |||
515 | out: | ||
516 | drm_sysfs_connector_add(connector); | ||
517 | return; | ||
518 | |||
519 | failed: | ||
520 | DRM_DEBUG("No LVDS modes found, disabling.\n"); | ||
521 | if (intel_output->ddc_bus) | ||
522 | intel_i2c_destroy(intel_output->ddc_bus); | ||
523 | drm_connector_cleanup(connector); | ||
524 | kfree(connector); | ||
525 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c new file mode 100644 index 000000000000..e42019e5d661 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_modes.c | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> | ||
3 | * Copyright (c) 2007 Intel Corporation | ||
4 | * Jesse Barnes <jesse.barnes@intel.com> | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the "Software"), | ||
8 | * to deal in the Software without restriction, including without limitation | ||
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
10 | * and/or sell copies of the Software, and to permit persons to whom the | ||
11 | * Software is furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice (including the next | ||
14 | * paragraph) shall be included in all copies or substantial portions of the | ||
15 | * Software. | ||
16 | * | ||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
23 | * DEALINGS IN THE SOFTWARE. | ||
24 | */ | ||
25 | |||
26 | #include <linux/i2c.h> | ||
27 | #include <linux/fb.h> | ||
28 | #include "drmP.h" | ||
29 | #include "intel_drv.h" | ||
30 | |||
31 | /** | ||
32 | * intel_ddc_probe | ||
33 | * | ||
34 | */ | ||
35 | bool intel_ddc_probe(struct intel_output *intel_output) | ||
36 | { | ||
37 | u8 out_buf[] = { 0x0, 0x0}; | ||
38 | u8 buf[2]; | ||
39 | int ret; | ||
40 | struct i2c_msg msgs[] = { | ||
41 | { | ||
42 | .addr = 0x50, | ||
43 | .flags = 0, | ||
44 | .len = 1, | ||
45 | .buf = out_buf, | ||
46 | }, | ||
47 | { | ||
48 | .addr = 0x50, | ||
49 | .flags = I2C_M_RD, | ||
50 | .len = 1, | ||
51 | .buf = buf, | ||
52 | } | ||
53 | }; | ||
54 | |||
55 | ret = i2c_transfer(&intel_output->ddc_bus->adapter, msgs, 2); | ||
56 | if (ret == 2) | ||
57 | return true; | ||
58 | |||
59 | return false; | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * intel_ddc_get_modes - get modelist from monitor | ||
64 | * @connector: DRM connector device to use | ||
65 | * | ||
66 | * Fetch the EDID information from @connector using the DDC bus. | ||
67 | */ | ||
68 | int intel_ddc_get_modes(struct intel_output *intel_output) | ||
69 | { | ||
70 | struct edid *edid; | ||
71 | int ret = 0; | ||
72 | |||
73 | edid = drm_get_edid(&intel_output->base, | ||
74 | &intel_output->ddc_bus->adapter); | ||
75 | if (edid) { | ||
76 | drm_mode_connector_update_edid_property(&intel_output->base, | ||
77 | edid); | ||
78 | ret = drm_add_edid_modes(&intel_output->base, edid); | ||
79 | kfree(edid); | ||
80 | } | ||
81 | |||
82 | return ret; | ||
83 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c new file mode 100644 index 000000000000..626258d72c90 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_sdvo.c | |||
@@ -0,0 +1,1127 @@ | |||
1 | /* | ||
2 | * Copyright 2006 Dave Airlie <airlied@linux.ie> | ||
3 | * Copyright © 2006-2007 Intel Corporation | ||
4 | * Jesse Barnes <jesse.barnes@intel.com> | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the "Software"), | ||
8 | * to deal in the Software without restriction, including without limitation | ||
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
10 | * and/or sell copies of the Software, and to permit persons to whom the | ||
11 | * Software is furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice (including the next | ||
14 | * paragraph) shall be included in all copies or substantial portions of the | ||
15 | * Software. | ||
16 | * | ||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
23 | * DEALINGS IN THE SOFTWARE. | ||
24 | * | ||
25 | * Authors: | ||
26 | * Eric Anholt <eric@anholt.net> | ||
27 | */ | ||
28 | #include <linux/i2c.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include "drmP.h" | ||
31 | #include "drm.h" | ||
32 | #include "drm_crtc.h" | ||
33 | #include "intel_drv.h" | ||
34 | #include "i915_drm.h" | ||
35 | #include "i915_drv.h" | ||
36 | #include "intel_sdvo_regs.h" | ||
37 | |||
38 | #undef SDVO_DEBUG | ||
39 | |||
40 | struct intel_sdvo_priv { | ||
41 | struct intel_i2c_chan *i2c_bus; | ||
42 | int slaveaddr; | ||
43 | int output_device; | ||
44 | |||
45 | u16 active_outputs; | ||
46 | |||
47 | struct intel_sdvo_caps caps; | ||
48 | int pixel_clock_min, pixel_clock_max; | ||
49 | |||
50 | int save_sdvo_mult; | ||
51 | u16 save_active_outputs; | ||
52 | struct intel_sdvo_dtd save_input_dtd_1, save_input_dtd_2; | ||
53 | struct intel_sdvo_dtd save_output_dtd[16]; | ||
54 | u32 save_SDVOX; | ||
55 | }; | ||
56 | |||
57 | /** | ||
58 | * Writes the SDVOB or SDVOC with the given value, but always writes both | ||
59 | * SDVOB and SDVOC to work around apparent hardware issues (according to | ||
60 | * comments in the BIOS). | ||
61 | */ | ||
62 | void intel_sdvo_write_sdvox(struct intel_output *intel_output, u32 val) | ||
63 | { | ||
64 | struct drm_device *dev = intel_output->base.dev; | ||
65 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
66 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
67 | u32 bval = val, cval = val; | ||
68 | int i; | ||
69 | |||
70 | if (sdvo_priv->output_device == SDVOB) { | ||
71 | cval = I915_READ(SDVOC); | ||
72 | } else { | ||
73 | bval = I915_READ(SDVOB); | ||
74 | } | ||
75 | /* | ||
76 | * Write the registers twice for luck. Sometimes, | ||
77 | * writing them only once doesn't appear to 'stick'. | ||
78 | * The BIOS does this too. Yay, magic | ||
79 | */ | ||
80 | for (i = 0; i < 2; i++) | ||
81 | { | ||
82 | I915_WRITE(SDVOB, bval); | ||
83 | I915_READ(SDVOB); | ||
84 | I915_WRITE(SDVOC, cval); | ||
85 | I915_READ(SDVOC); | ||
86 | } | ||
87 | } | ||
88 | |||
89 | static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr, | ||
90 | u8 *ch) | ||
91 | { | ||
92 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
93 | u8 out_buf[2]; | ||
94 | u8 buf[2]; | ||
95 | int ret; | ||
96 | |||
97 | struct i2c_msg msgs[] = { | ||
98 | { | ||
99 | .addr = sdvo_priv->i2c_bus->slave_addr, | ||
100 | .flags = 0, | ||
101 | .len = 1, | ||
102 | .buf = out_buf, | ||
103 | }, | ||
104 | { | ||
105 | .addr = sdvo_priv->i2c_bus->slave_addr, | ||
106 | .flags = I2C_M_RD, | ||
107 | .len = 1, | ||
108 | .buf = buf, | ||
109 | } | ||
110 | }; | ||
111 | |||
112 | out_buf[0] = addr; | ||
113 | out_buf[1] = 0; | ||
114 | |||
115 | if ((ret = i2c_transfer(&sdvo_priv->i2c_bus->adapter, msgs, 2)) == 2) | ||
116 | { | ||
117 | *ch = buf[0]; | ||
118 | return true; | ||
119 | } | ||
120 | |||
121 | DRM_DEBUG("i2c transfer returned %d\n", ret); | ||
122 | return false; | ||
123 | } | ||
124 | |||
125 | static bool intel_sdvo_write_byte(struct intel_output *intel_output, int addr, | ||
126 | u8 ch) | ||
127 | { | ||
128 | u8 out_buf[2]; | ||
129 | struct i2c_msg msgs[] = { | ||
130 | { | ||
131 | .addr = intel_output->i2c_bus->slave_addr, | ||
132 | .flags = 0, | ||
133 | .len = 2, | ||
134 | .buf = out_buf, | ||
135 | } | ||
136 | }; | ||
137 | |||
138 | out_buf[0] = addr; | ||
139 | out_buf[1] = ch; | ||
140 | |||
141 | if (i2c_transfer(&intel_output->i2c_bus->adapter, msgs, 1) == 1) | ||
142 | { | ||
143 | return true; | ||
144 | } | ||
145 | return false; | ||
146 | } | ||
147 | |||
148 | #define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd} | ||
149 | /** Mapping of command numbers to names, for debug output */ | ||
150 | const static struct _sdvo_cmd_name { | ||
151 | u8 cmd; | ||
152 | char *name; | ||
153 | } sdvo_cmd_names[] = { | ||
154 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_RESET), | ||
155 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DEVICE_CAPS), | ||
156 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FIRMWARE_REV), | ||
157 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TRAINED_INPUTS), | ||
158 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_OUTPUTS), | ||
159 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_OUTPUTS), | ||
160 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_IN_OUT_MAP), | ||
161 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_IN_OUT_MAP), | ||
162 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ATTACHED_DISPLAYS), | ||
163 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HOT_PLUG_SUPPORT), | ||
164 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_HOT_PLUG), | ||
165 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_HOT_PLUG), | ||
166 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE), | ||
167 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_INPUT), | ||
168 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_OUTPUT), | ||
169 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART1), | ||
170 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART2), | ||
171 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1), | ||
172 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART2), | ||
173 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1), | ||
174 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART1), | ||
175 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART2), | ||
176 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART1), | ||
177 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART2), | ||
178 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING), | ||
179 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1), | ||
180 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2), | ||
181 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE), | ||
182 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE), | ||
183 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS), | ||
184 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CLOCK_RATE_MULT), | ||
185 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CLOCK_RATE_MULT), | ||
186 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_TV_FORMATS), | ||
187 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_FORMAT), | ||
188 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_FORMAT), | ||
189 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_RESOLUTION_SUPPORT), | ||
190 | SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTROL_BUS_SWITCH), | ||
191 | }; | ||
192 | |||
193 | #define SDVO_NAME(dev_priv) ((dev_priv)->output_device == SDVOB ? "SDVOB" : "SDVOC") | ||
194 | #define SDVO_PRIV(output) ((struct intel_sdvo_priv *) (output)->dev_priv) | ||
195 | |||
196 | #ifdef SDVO_DEBUG | ||
197 | static void intel_sdvo_debug_write(struct intel_output *intel_output, u8 cmd, | ||
198 | void *args, int args_len) | ||
199 | { | ||
200 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
201 | int i; | ||
202 | |||
203 | DRM_DEBUG("%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd); | ||
204 | for (i = 0; i < args_len; i++) | ||
205 | printk("%02X ", ((u8 *)args)[i]); | ||
206 | for (; i < 8; i++) | ||
207 | printk(" "); | ||
208 | for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) { | ||
209 | if (cmd == sdvo_cmd_names[i].cmd) { | ||
210 | printk("(%s)", sdvo_cmd_names[i].name); | ||
211 | break; | ||
212 | } | ||
213 | } | ||
214 | if (i == sizeof(sdvo_cmd_names)/ sizeof(sdvo_cmd_names[0])) | ||
215 | printk("(%02X)",cmd); | ||
216 | printk("\n"); | ||
217 | } | ||
218 | #else | ||
219 | #define intel_sdvo_debug_write(o, c, a, l) | ||
220 | #endif | ||
221 | |||
222 | static void intel_sdvo_write_cmd(struct intel_output *intel_output, u8 cmd, | ||
223 | void *args, int args_len) | ||
224 | { | ||
225 | int i; | ||
226 | |||
227 | intel_sdvo_debug_write(intel_output, cmd, args, args_len); | ||
228 | |||
229 | for (i = 0; i < args_len; i++) { | ||
230 | intel_sdvo_write_byte(intel_output, SDVO_I2C_ARG_0 - i, | ||
231 | ((u8*)args)[i]); | ||
232 | } | ||
233 | |||
234 | intel_sdvo_write_byte(intel_output, SDVO_I2C_OPCODE, cmd); | ||
235 | } | ||
236 | |||
237 | #ifdef SDVO_DEBUG | ||
238 | static const char *cmd_status_names[] = { | ||
239 | "Power on", | ||
240 | "Success", | ||
241 | "Not supported", | ||
242 | "Invalid arg", | ||
243 | "Pending", | ||
244 | "Target not specified", | ||
245 | "Scaling not supported" | ||
246 | }; | ||
247 | |||
248 | static void intel_sdvo_debug_response(struct intel_output *intel_output, | ||
249 | void *response, int response_len, | ||
250 | u8 status) | ||
251 | { | ||
252 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
253 | |||
254 | DRM_DEBUG("%s: R: ", SDVO_NAME(sdvo_priv)); | ||
255 | for (i = 0; i < response_len; i++) | ||
256 | printk("%02X ", ((u8 *)response)[i]); | ||
257 | for (; i < 8; i++) | ||
258 | printk(" "); | ||
259 | if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) | ||
260 | printk("(%s)", cmd_status_names[status]); | ||
261 | else | ||
262 | printk("(??? %d)", status); | ||
263 | printk("\n"); | ||
264 | } | ||
265 | #else | ||
266 | #define intel_sdvo_debug_response(o, r, l, s) | ||
267 | #endif | ||
268 | |||
269 | static u8 intel_sdvo_read_response(struct intel_output *intel_output, | ||
270 | void *response, int response_len) | ||
271 | { | ||
272 | int i; | ||
273 | u8 status; | ||
274 | u8 retry = 50; | ||
275 | |||
276 | while (retry--) { | ||
277 | /* Read the command response */ | ||
278 | for (i = 0; i < response_len; i++) { | ||
279 | intel_sdvo_read_byte(intel_output, | ||
280 | SDVO_I2C_RETURN_0 + i, | ||
281 | &((u8 *)response)[i]); | ||
282 | } | ||
283 | |||
284 | /* read the return status */ | ||
285 | intel_sdvo_read_byte(intel_output, SDVO_I2C_CMD_STATUS, | ||
286 | &status); | ||
287 | |||
288 | intel_sdvo_debug_response(intel_output, response, response_len, | ||
289 | status); | ||
290 | if (status != SDVO_CMD_STATUS_PENDING) | ||
291 | return status; | ||
292 | |||
293 | mdelay(50); | ||
294 | } | ||
295 | |||
296 | return status; | ||
297 | } | ||
298 | |||
299 | int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode) | ||
300 | { | ||
301 | if (mode->clock >= 100000) | ||
302 | return 1; | ||
303 | else if (mode->clock >= 50000) | ||
304 | return 2; | ||
305 | else | ||
306 | return 4; | ||
307 | } | ||
308 | |||
309 | /** | ||
310 | * Don't check status code from this as it switches the bus back to the | ||
311 | * SDVO chips which defeats the purpose of doing a bus switch in the first | ||
312 | * place. | ||
313 | */ | ||
314 | void intel_sdvo_set_control_bus_switch(struct intel_output *intel_output, u8 target) | ||
315 | { | ||
316 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1); | ||
317 | } | ||
318 | |||
319 | static bool intel_sdvo_set_target_input(struct intel_output *intel_output, bool target_0, bool target_1) | ||
320 | { | ||
321 | struct intel_sdvo_set_target_input_args targets = {0}; | ||
322 | u8 status; | ||
323 | |||
324 | if (target_0 && target_1) | ||
325 | return SDVO_CMD_STATUS_NOTSUPP; | ||
326 | |||
327 | if (target_1) | ||
328 | targets.target_1 = 1; | ||
329 | |||
330 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_TARGET_INPUT, &targets, | ||
331 | sizeof(targets)); | ||
332 | |||
333 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
334 | |||
335 | return (status == SDVO_CMD_STATUS_SUCCESS); | ||
336 | } | ||
337 | |||
338 | /** | ||
339 | * Return whether each input is trained. | ||
340 | * | ||
341 | * This function is making an assumption about the layout of the response, | ||
342 | * which should be checked against the docs. | ||
343 | */ | ||
344 | static bool intel_sdvo_get_trained_inputs(struct intel_output *intel_output, bool *input_1, bool *input_2) | ||
345 | { | ||
346 | struct intel_sdvo_get_trained_inputs_response response; | ||
347 | u8 status; | ||
348 | |||
349 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0); | ||
350 | status = intel_sdvo_read_response(intel_output, &response, sizeof(response)); | ||
351 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
352 | return false; | ||
353 | |||
354 | *input_1 = response.input0_trained; | ||
355 | *input_2 = response.input1_trained; | ||
356 | return true; | ||
357 | } | ||
358 | |||
359 | static bool intel_sdvo_get_active_outputs(struct intel_output *intel_output, | ||
360 | u16 *outputs) | ||
361 | { | ||
362 | u8 status; | ||
363 | |||
364 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ACTIVE_OUTPUTS, NULL, 0); | ||
365 | status = intel_sdvo_read_response(intel_output, outputs, sizeof(*outputs)); | ||
366 | |||
367 | return (status == SDVO_CMD_STATUS_SUCCESS); | ||
368 | } | ||
369 | |||
370 | static bool intel_sdvo_set_active_outputs(struct intel_output *intel_output, | ||
371 | u16 outputs) | ||
372 | { | ||
373 | u8 status; | ||
374 | |||
375 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs, | ||
376 | sizeof(outputs)); | ||
377 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
378 | return (status == SDVO_CMD_STATUS_SUCCESS); | ||
379 | } | ||
380 | |||
381 | static bool intel_sdvo_set_encoder_power_state(struct intel_output *intel_output, | ||
382 | int mode) | ||
383 | { | ||
384 | u8 status, state = SDVO_ENCODER_STATE_ON; | ||
385 | |||
386 | switch (mode) { | ||
387 | case DRM_MODE_DPMS_ON: | ||
388 | state = SDVO_ENCODER_STATE_ON; | ||
389 | break; | ||
390 | case DRM_MODE_DPMS_STANDBY: | ||
391 | state = SDVO_ENCODER_STATE_STANDBY; | ||
392 | break; | ||
393 | case DRM_MODE_DPMS_SUSPEND: | ||
394 | state = SDVO_ENCODER_STATE_SUSPEND; | ||
395 | break; | ||
396 | case DRM_MODE_DPMS_OFF: | ||
397 | state = SDVO_ENCODER_STATE_OFF; | ||
398 | break; | ||
399 | } | ||
400 | |||
401 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ENCODER_POWER_STATE, &state, | ||
402 | sizeof(state)); | ||
403 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
404 | |||
405 | return (status == SDVO_CMD_STATUS_SUCCESS); | ||
406 | } | ||
407 | |||
408 | static bool intel_sdvo_get_input_pixel_clock_range(struct intel_output *intel_output, | ||
409 | int *clock_min, | ||
410 | int *clock_max) | ||
411 | { | ||
412 | struct intel_sdvo_pixel_clock_range clocks; | ||
413 | u8 status; | ||
414 | |||
415 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, | ||
416 | NULL, 0); | ||
417 | |||
418 | status = intel_sdvo_read_response(intel_output, &clocks, sizeof(clocks)); | ||
419 | |||
420 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
421 | return false; | ||
422 | |||
423 | /* Convert the values from units of 10 kHz to kHz. */ | ||
424 | *clock_min = clocks.min * 10; | ||
425 | *clock_max = clocks.max * 10; | ||
426 | |||
427 | return true; | ||
428 | } | ||
429 | |||
430 | static bool intel_sdvo_set_target_output(struct intel_output *intel_output, | ||
431 | u16 outputs) | ||
432 | { | ||
433 | u8 status; | ||
434 | |||
435 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_TARGET_OUTPUT, &outputs, | ||
436 | sizeof(outputs)); | ||
437 | |||
438 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
439 | return (status == SDVO_CMD_STATUS_SUCCESS); | ||
440 | } | ||
441 | |||
442 | static bool intel_sdvo_get_timing(struct intel_output *intel_output, u8 cmd, | ||
443 | struct intel_sdvo_dtd *dtd) | ||
444 | { | ||
445 | u8 status; | ||
446 | |||
447 | intel_sdvo_write_cmd(intel_output, cmd, NULL, 0); | ||
448 | status = intel_sdvo_read_response(intel_output, &dtd->part1, | ||
449 | sizeof(dtd->part1)); | ||
450 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
451 | return false; | ||
452 | |||
453 | intel_sdvo_write_cmd(intel_output, cmd + 1, NULL, 0); | ||
454 | status = intel_sdvo_read_response(intel_output, &dtd->part2, | ||
455 | sizeof(dtd->part2)); | ||
456 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
457 | return false; | ||
458 | |||
459 | return true; | ||
460 | } | ||
461 | |||
462 | static bool intel_sdvo_get_input_timing(struct intel_output *intel_output, | ||
463 | struct intel_sdvo_dtd *dtd) | ||
464 | { | ||
465 | return intel_sdvo_get_timing(intel_output, | ||
466 | SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd); | ||
467 | } | ||
468 | |||
469 | static bool intel_sdvo_get_output_timing(struct intel_output *intel_output, | ||
470 | struct intel_sdvo_dtd *dtd) | ||
471 | { | ||
472 | return intel_sdvo_get_timing(intel_output, | ||
473 | SDVO_CMD_GET_OUTPUT_TIMINGS_PART1, dtd); | ||
474 | } | ||
475 | |||
476 | static bool intel_sdvo_set_timing(struct intel_output *intel_output, u8 cmd, | ||
477 | struct intel_sdvo_dtd *dtd) | ||
478 | { | ||
479 | u8 status; | ||
480 | |||
481 | intel_sdvo_write_cmd(intel_output, cmd, &dtd->part1, sizeof(dtd->part1)); | ||
482 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
483 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
484 | return false; | ||
485 | |||
486 | intel_sdvo_write_cmd(intel_output, cmd + 1, &dtd->part2, sizeof(dtd->part2)); | ||
487 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
488 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
489 | return false; | ||
490 | |||
491 | return true; | ||
492 | } | ||
493 | |||
494 | static bool intel_sdvo_set_input_timing(struct intel_output *intel_output, | ||
495 | struct intel_sdvo_dtd *dtd) | ||
496 | { | ||
497 | return intel_sdvo_set_timing(intel_output, | ||
498 | SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd); | ||
499 | } | ||
500 | |||
501 | static bool intel_sdvo_set_output_timing(struct intel_output *intel_output, | ||
502 | struct intel_sdvo_dtd *dtd) | ||
503 | { | ||
504 | return intel_sdvo_set_timing(intel_output, | ||
505 | SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd); | ||
506 | } | ||
507 | |||
508 | |||
509 | static int intel_sdvo_get_clock_rate_mult(struct intel_output *intel_output) | ||
510 | { | ||
511 | u8 response, status; | ||
512 | |||
513 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_CLOCK_RATE_MULT, NULL, 0); | ||
514 | status = intel_sdvo_read_response(intel_output, &response, 1); | ||
515 | |||
516 | if (status != SDVO_CMD_STATUS_SUCCESS) { | ||
517 | DRM_DEBUG("Couldn't get SDVO clock rate multiplier\n"); | ||
518 | return SDVO_CLOCK_RATE_MULT_1X; | ||
519 | } else { | ||
520 | DRM_DEBUG("Current clock rate multiplier: %d\n", response); | ||
521 | } | ||
522 | |||
523 | return response; | ||
524 | } | ||
525 | |||
526 | static bool intel_sdvo_set_clock_rate_mult(struct intel_output *intel_output, u8 val) | ||
527 | { | ||
528 | u8 status; | ||
529 | |||
530 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); | ||
531 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
532 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
533 | return false; | ||
534 | |||
535 | return true; | ||
536 | } | ||
537 | |||
538 | static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, | ||
539 | struct drm_display_mode *mode, | ||
540 | struct drm_display_mode *adjusted_mode) | ||
541 | { | ||
542 | /* Make the CRTC code factor in the SDVO pixel multiplier. The SDVO | ||
543 | * device will be told of the multiplier during mode_set. | ||
544 | */ | ||
545 | adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode); | ||
546 | return true; | ||
547 | } | ||
548 | |||
549 | static void intel_sdvo_mode_set(struct drm_encoder *encoder, | ||
550 | struct drm_display_mode *mode, | ||
551 | struct drm_display_mode *adjusted_mode) | ||
552 | { | ||
553 | struct drm_device *dev = encoder->dev; | ||
554 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
555 | struct drm_crtc *crtc = encoder->crtc; | ||
556 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
557 | struct intel_output *intel_output = enc_to_intel_output(encoder); | ||
558 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
559 | u16 width, height; | ||
560 | u16 h_blank_len, h_sync_len, v_blank_len, v_sync_len; | ||
561 | u16 h_sync_offset, v_sync_offset; | ||
562 | u32 sdvox; | ||
563 | struct intel_sdvo_dtd output_dtd; | ||
564 | int sdvo_pixel_multiply; | ||
565 | |||
566 | if (!mode) | ||
567 | return; | ||
568 | |||
569 | width = mode->crtc_hdisplay; | ||
570 | height = mode->crtc_vdisplay; | ||
571 | |||
572 | /* do some mode translations */ | ||
573 | h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start; | ||
574 | h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; | ||
575 | |||
576 | v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start; | ||
577 | v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; | ||
578 | |||
579 | h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start; | ||
580 | v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start; | ||
581 | |||
582 | output_dtd.part1.clock = mode->clock / 10; | ||
583 | output_dtd.part1.h_active = width & 0xff; | ||
584 | output_dtd.part1.h_blank = h_blank_len & 0xff; | ||
585 | output_dtd.part1.h_high = (((width >> 8) & 0xf) << 4) | | ||
586 | ((h_blank_len >> 8) & 0xf); | ||
587 | output_dtd.part1.v_active = height & 0xff; | ||
588 | output_dtd.part1.v_blank = v_blank_len & 0xff; | ||
589 | output_dtd.part1.v_high = (((height >> 8) & 0xf) << 4) | | ||
590 | ((v_blank_len >> 8) & 0xf); | ||
591 | |||
592 | output_dtd.part2.h_sync_off = h_sync_offset; | ||
593 | output_dtd.part2.h_sync_width = h_sync_len & 0xff; | ||
594 | output_dtd.part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 | | ||
595 | (v_sync_len & 0xf); | ||
596 | output_dtd.part2.sync_off_width_high = ((h_sync_offset & 0x300) >> 2) | | ||
597 | ((h_sync_len & 0x300) >> 4) | ((v_sync_offset & 0x30) >> 2) | | ||
598 | ((v_sync_len & 0x30) >> 4); | ||
599 | |||
600 | output_dtd.part2.dtd_flags = 0x18; | ||
601 | if (mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
602 | output_dtd.part2.dtd_flags |= 0x2; | ||
603 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
604 | output_dtd.part2.dtd_flags |= 0x4; | ||
605 | |||
606 | output_dtd.part2.sdvo_flags = 0; | ||
607 | output_dtd.part2.v_sync_off_high = v_sync_offset & 0xc0; | ||
608 | output_dtd.part2.reserved = 0; | ||
609 | |||
610 | /* Set the output timing to the screen */ | ||
611 | intel_sdvo_set_target_output(intel_output, sdvo_priv->active_outputs); | ||
612 | intel_sdvo_set_output_timing(intel_output, &output_dtd); | ||
613 | |||
614 | /* Set the input timing to the screen. Assume always input 0. */ | ||
615 | intel_sdvo_set_target_input(intel_output, true, false); | ||
616 | |||
617 | /* We would like to use i830_sdvo_create_preferred_input_timing() to | ||
618 | * provide the device with a timing it can support, if it supports that | ||
619 | * feature. However, presumably we would need to adjust the CRTC to | ||
620 | * output the preferred timing, and we don't support that currently. | ||
621 | */ | ||
622 | intel_sdvo_set_input_timing(intel_output, &output_dtd); | ||
623 | |||
624 | switch (intel_sdvo_get_pixel_multiplier(mode)) { | ||
625 | case 1: | ||
626 | intel_sdvo_set_clock_rate_mult(intel_output, | ||
627 | SDVO_CLOCK_RATE_MULT_1X); | ||
628 | break; | ||
629 | case 2: | ||
630 | intel_sdvo_set_clock_rate_mult(intel_output, | ||
631 | SDVO_CLOCK_RATE_MULT_2X); | ||
632 | break; | ||
633 | case 4: | ||
634 | intel_sdvo_set_clock_rate_mult(intel_output, | ||
635 | SDVO_CLOCK_RATE_MULT_4X); | ||
636 | break; | ||
637 | } | ||
638 | |||
639 | /* Set the SDVO control regs. */ | ||
640 | if (0/*IS_I965GM(dev)*/) { | ||
641 | sdvox = SDVO_BORDER_ENABLE; | ||
642 | } else { | ||
643 | sdvox = I915_READ(sdvo_priv->output_device); | ||
644 | switch (sdvo_priv->output_device) { | ||
645 | case SDVOB: | ||
646 | sdvox &= SDVOB_PRESERVE_MASK; | ||
647 | break; | ||
648 | case SDVOC: | ||
649 | sdvox &= SDVOC_PRESERVE_MASK; | ||
650 | break; | ||
651 | } | ||
652 | sdvox |= (9 << 19) | SDVO_BORDER_ENABLE; | ||
653 | } | ||
654 | if (intel_crtc->pipe == 1) | ||
655 | sdvox |= SDVO_PIPE_B_SELECT; | ||
656 | |||
657 | sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode); | ||
658 | if (IS_I965G(dev)) { | ||
659 | /* done in crtc_mode_set as the dpll_md reg must be written | ||
660 | early */ | ||
661 | } else if (IS_I945G(dev) || IS_I945GM(dev)) { | ||
662 | /* done in crtc_mode_set as it lives inside the | ||
663 | dpll register */ | ||
664 | } else { | ||
665 | sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; | ||
666 | } | ||
667 | |||
668 | intel_sdvo_write_sdvox(intel_output, sdvox); | ||
669 | } | ||
670 | |||
671 | static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) | ||
672 | { | ||
673 | struct drm_device *dev = encoder->dev; | ||
674 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
675 | struct intel_output *intel_output = enc_to_intel_output(encoder); | ||
676 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
677 | u32 temp; | ||
678 | |||
679 | if (mode != DRM_MODE_DPMS_ON) { | ||
680 | intel_sdvo_set_active_outputs(intel_output, 0); | ||
681 | if (0) | ||
682 | intel_sdvo_set_encoder_power_state(intel_output, mode); | ||
683 | |||
684 | if (mode == DRM_MODE_DPMS_OFF) { | ||
685 | temp = I915_READ(sdvo_priv->output_device); | ||
686 | if ((temp & SDVO_ENABLE) != 0) { | ||
687 | intel_sdvo_write_sdvox(intel_output, temp & ~SDVO_ENABLE); | ||
688 | } | ||
689 | } | ||
690 | } else { | ||
691 | bool input1, input2; | ||
692 | int i; | ||
693 | u8 status; | ||
694 | |||
695 | temp = I915_READ(sdvo_priv->output_device); | ||
696 | if ((temp & SDVO_ENABLE) == 0) | ||
697 | intel_sdvo_write_sdvox(intel_output, temp | SDVO_ENABLE); | ||
698 | for (i = 0; i < 2; i++) | ||
699 | intel_wait_for_vblank(dev); | ||
700 | |||
701 | status = intel_sdvo_get_trained_inputs(intel_output, &input1, | ||
702 | &input2); | ||
703 | |||
704 | |||
705 | /* Warn if the device reported failure to sync. | ||
706 | * A lot of SDVO devices fail to notify of sync, but it's | ||
707 | * a given it the status is a success, we succeeded. | ||
708 | */ | ||
709 | if (status == SDVO_CMD_STATUS_SUCCESS && !input1) { | ||
710 | DRM_DEBUG("First %s output reported failure to sync\n", | ||
711 | SDVO_NAME(sdvo_priv)); | ||
712 | } | ||
713 | |||
714 | if (0) | ||
715 | intel_sdvo_set_encoder_power_state(intel_output, mode); | ||
716 | intel_sdvo_set_active_outputs(intel_output, sdvo_priv->active_outputs); | ||
717 | } | ||
718 | return; | ||
719 | } | ||
720 | |||
721 | static void intel_sdvo_save(struct drm_connector *connector) | ||
722 | { | ||
723 | struct drm_device *dev = connector->dev; | ||
724 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
725 | struct intel_output *intel_output = to_intel_output(connector); | ||
726 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
727 | int o; | ||
728 | |||
729 | sdvo_priv->save_sdvo_mult = intel_sdvo_get_clock_rate_mult(intel_output); | ||
730 | intel_sdvo_get_active_outputs(intel_output, &sdvo_priv->save_active_outputs); | ||
731 | |||
732 | if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) { | ||
733 | intel_sdvo_set_target_input(intel_output, true, false); | ||
734 | intel_sdvo_get_input_timing(intel_output, | ||
735 | &sdvo_priv->save_input_dtd_1); | ||
736 | } | ||
737 | |||
738 | if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) { | ||
739 | intel_sdvo_set_target_input(intel_output, false, true); | ||
740 | intel_sdvo_get_input_timing(intel_output, | ||
741 | &sdvo_priv->save_input_dtd_2); | ||
742 | } | ||
743 | |||
744 | for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++) | ||
745 | { | ||
746 | u16 this_output = (1 << o); | ||
747 | if (sdvo_priv->caps.output_flags & this_output) | ||
748 | { | ||
749 | intel_sdvo_set_target_output(intel_output, this_output); | ||
750 | intel_sdvo_get_output_timing(intel_output, | ||
751 | &sdvo_priv->save_output_dtd[o]); | ||
752 | } | ||
753 | } | ||
754 | |||
755 | sdvo_priv->save_SDVOX = I915_READ(sdvo_priv->output_device); | ||
756 | } | ||
757 | |||
758 | static void intel_sdvo_restore(struct drm_connector *connector) | ||
759 | { | ||
760 | struct drm_device *dev = connector->dev; | ||
761 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
762 | struct intel_output *intel_output = to_intel_output(connector); | ||
763 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
764 | int o; | ||
765 | int i; | ||
766 | bool input1, input2; | ||
767 | u8 status; | ||
768 | |||
769 | intel_sdvo_set_active_outputs(intel_output, 0); | ||
770 | |||
771 | for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++) | ||
772 | { | ||
773 | u16 this_output = (1 << o); | ||
774 | if (sdvo_priv->caps.output_flags & this_output) { | ||
775 | intel_sdvo_set_target_output(intel_output, this_output); | ||
776 | intel_sdvo_set_output_timing(intel_output, &sdvo_priv->save_output_dtd[o]); | ||
777 | } | ||
778 | } | ||
779 | |||
780 | if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) { | ||
781 | intel_sdvo_set_target_input(intel_output, true, false); | ||
782 | intel_sdvo_set_input_timing(intel_output, &sdvo_priv->save_input_dtd_1); | ||
783 | } | ||
784 | |||
785 | if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) { | ||
786 | intel_sdvo_set_target_input(intel_output, false, true); | ||
787 | intel_sdvo_set_input_timing(intel_output, &sdvo_priv->save_input_dtd_2); | ||
788 | } | ||
789 | |||
790 | intel_sdvo_set_clock_rate_mult(intel_output, sdvo_priv->save_sdvo_mult); | ||
791 | |||
792 | I915_WRITE(sdvo_priv->output_device, sdvo_priv->save_SDVOX); | ||
793 | |||
794 | if (sdvo_priv->save_SDVOX & SDVO_ENABLE) | ||
795 | { | ||
796 | for (i = 0; i < 2; i++) | ||
797 | intel_wait_for_vblank(dev); | ||
798 | status = intel_sdvo_get_trained_inputs(intel_output, &input1, &input2); | ||
799 | if (status == SDVO_CMD_STATUS_SUCCESS && !input1) | ||
800 | DRM_DEBUG("First %s output reported failure to sync\n", | ||
801 | SDVO_NAME(sdvo_priv)); | ||
802 | } | ||
803 | |||
804 | intel_sdvo_set_active_outputs(intel_output, sdvo_priv->save_active_outputs); | ||
805 | } | ||
806 | |||
807 | static int intel_sdvo_mode_valid(struct drm_connector *connector, | ||
808 | struct drm_display_mode *mode) | ||
809 | { | ||
810 | struct intel_output *intel_output = to_intel_output(connector); | ||
811 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
812 | |||
813 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
814 | return MODE_NO_DBLESCAN; | ||
815 | |||
816 | if (sdvo_priv->pixel_clock_min > mode->clock) | ||
817 | return MODE_CLOCK_LOW; | ||
818 | |||
819 | if (sdvo_priv->pixel_clock_max < mode->clock) | ||
820 | return MODE_CLOCK_HIGH; | ||
821 | |||
822 | return MODE_OK; | ||
823 | } | ||
824 | |||
825 | static bool intel_sdvo_get_capabilities(struct intel_output *intel_output, struct intel_sdvo_caps *caps) | ||
826 | { | ||
827 | u8 status; | ||
828 | |||
829 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0); | ||
830 | status = intel_sdvo_read_response(intel_output, caps, sizeof(*caps)); | ||
831 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
832 | return false; | ||
833 | |||
834 | return true; | ||
835 | } | ||
836 | |||
837 | struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB) | ||
838 | { | ||
839 | struct drm_connector *connector = NULL; | ||
840 | struct intel_output *iout = NULL; | ||
841 | struct intel_sdvo_priv *sdvo; | ||
842 | |||
843 | /* find the sdvo connector */ | ||
844 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
845 | iout = to_intel_output(connector); | ||
846 | |||
847 | if (iout->type != INTEL_OUTPUT_SDVO) | ||
848 | continue; | ||
849 | |||
850 | sdvo = iout->dev_priv; | ||
851 | |||
852 | if (sdvo->output_device == SDVOB && sdvoB) | ||
853 | return connector; | ||
854 | |||
855 | if (sdvo->output_device == SDVOC && !sdvoB) | ||
856 | return connector; | ||
857 | |||
858 | } | ||
859 | |||
860 | return NULL; | ||
861 | } | ||
862 | |||
863 | int intel_sdvo_supports_hotplug(struct drm_connector *connector) | ||
864 | { | ||
865 | u8 response[2]; | ||
866 | u8 status; | ||
867 | struct intel_output *intel_output; | ||
868 | DRM_DEBUG("\n"); | ||
869 | |||
870 | if (!connector) | ||
871 | return 0; | ||
872 | |||
873 | intel_output = to_intel_output(connector); | ||
874 | |||
875 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); | ||
876 | status = intel_sdvo_read_response(intel_output, &response, 2); | ||
877 | |||
878 | if (response[0] !=0) | ||
879 | return 1; | ||
880 | |||
881 | return 0; | ||
882 | } | ||
883 | |||
884 | void intel_sdvo_set_hotplug(struct drm_connector *connector, int on) | ||
885 | { | ||
886 | u8 response[2]; | ||
887 | u8 status; | ||
888 | struct intel_output *intel_output = to_intel_output(connector); | ||
889 | |||
890 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); | ||
891 | intel_sdvo_read_response(intel_output, &response, 2); | ||
892 | |||
893 | if (on) { | ||
894 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); | ||
895 | status = intel_sdvo_read_response(intel_output, &response, 2); | ||
896 | |||
897 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); | ||
898 | } else { | ||
899 | response[0] = 0; | ||
900 | response[1] = 0; | ||
901 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); | ||
902 | } | ||
903 | |||
904 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); | ||
905 | intel_sdvo_read_response(intel_output, &response, 2); | ||
906 | } | ||
907 | |||
908 | static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector) | ||
909 | { | ||
910 | u8 response[2]; | ||
911 | u8 status; | ||
912 | struct intel_output *intel_output = to_intel_output(connector); | ||
913 | |||
914 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); | ||
915 | status = intel_sdvo_read_response(intel_output, &response, 2); | ||
916 | |||
917 | DRM_DEBUG("SDVO response %d %d\n", response[0], response[1]); | ||
918 | if ((response[0] != 0) || (response[1] != 0)) | ||
919 | return connector_status_connected; | ||
920 | else | ||
921 | return connector_status_disconnected; | ||
922 | } | ||
923 | |||
924 | static int intel_sdvo_get_modes(struct drm_connector *connector) | ||
925 | { | ||
926 | struct intel_output *intel_output = to_intel_output(connector); | ||
927 | |||
928 | /* set the bus switch and get the modes */ | ||
929 | intel_sdvo_set_control_bus_switch(intel_output, SDVO_CONTROL_BUS_DDC2); | ||
930 | intel_ddc_get_modes(intel_output); | ||
931 | |||
932 | if (list_empty(&connector->probed_modes)) | ||
933 | return 0; | ||
934 | return 1; | ||
935 | } | ||
936 | |||
937 | static void intel_sdvo_destroy(struct drm_connector *connector) | ||
938 | { | ||
939 | struct intel_output *intel_output = to_intel_output(connector); | ||
940 | |||
941 | if (intel_output->i2c_bus) | ||
942 | intel_i2c_destroy(intel_output->i2c_bus); | ||
943 | drm_sysfs_connector_remove(connector); | ||
944 | drm_connector_cleanup(connector); | ||
945 | kfree(intel_output); | ||
946 | } | ||
947 | |||
948 | static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { | ||
949 | .dpms = intel_sdvo_dpms, | ||
950 | .mode_fixup = intel_sdvo_mode_fixup, | ||
951 | .prepare = intel_encoder_prepare, | ||
952 | .mode_set = intel_sdvo_mode_set, | ||
953 | .commit = intel_encoder_commit, | ||
954 | }; | ||
955 | |||
956 | static const struct drm_connector_funcs intel_sdvo_connector_funcs = { | ||
957 | .save = intel_sdvo_save, | ||
958 | .restore = intel_sdvo_restore, | ||
959 | .detect = intel_sdvo_detect, | ||
960 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
961 | .destroy = intel_sdvo_destroy, | ||
962 | }; | ||
963 | |||
964 | static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = { | ||
965 | .get_modes = intel_sdvo_get_modes, | ||
966 | .mode_valid = intel_sdvo_mode_valid, | ||
967 | .best_encoder = intel_best_encoder, | ||
968 | }; | ||
969 | |||
970 | void intel_sdvo_enc_destroy(struct drm_encoder *encoder) | ||
971 | { | ||
972 | drm_encoder_cleanup(encoder); | ||
973 | } | ||
974 | |||
975 | static const struct drm_encoder_funcs intel_sdvo_enc_funcs = { | ||
976 | .destroy = intel_sdvo_enc_destroy, | ||
977 | }; | ||
978 | |||
979 | |||
980 | void intel_sdvo_init(struct drm_device *dev, int output_device) | ||
981 | { | ||
982 | struct drm_connector *connector; | ||
983 | struct intel_output *intel_output; | ||
984 | struct intel_sdvo_priv *sdvo_priv; | ||
985 | struct intel_i2c_chan *i2cbus = NULL; | ||
986 | int connector_type; | ||
987 | u8 ch[0x40]; | ||
988 | int i; | ||
989 | int encoder_type, output_id; | ||
990 | |||
991 | intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL); | ||
992 | if (!intel_output) { | ||
993 | return; | ||
994 | } | ||
995 | |||
996 | connector = &intel_output->base; | ||
997 | |||
998 | drm_connector_init(dev, connector, &intel_sdvo_connector_funcs, | ||
999 | DRM_MODE_CONNECTOR_Unknown); | ||
1000 | drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs); | ||
1001 | sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1); | ||
1002 | intel_output->type = INTEL_OUTPUT_SDVO; | ||
1003 | |||
1004 | connector->interlace_allowed = 0; | ||
1005 | connector->doublescan_allowed = 0; | ||
1006 | |||
1007 | /* setup the DDC bus. */ | ||
1008 | if (output_device == SDVOB) | ||
1009 | i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB"); | ||
1010 | else | ||
1011 | i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC"); | ||
1012 | |||
1013 | if (!i2cbus) | ||
1014 | goto err_connector; | ||
1015 | |||
1016 | sdvo_priv->i2c_bus = i2cbus; | ||
1017 | |||
1018 | if (output_device == SDVOB) { | ||
1019 | output_id = 1; | ||
1020 | sdvo_priv->i2c_bus->slave_addr = 0x38; | ||
1021 | } else { | ||
1022 | output_id = 2; | ||
1023 | sdvo_priv->i2c_bus->slave_addr = 0x39; | ||
1024 | } | ||
1025 | |||
1026 | sdvo_priv->output_device = output_device; | ||
1027 | intel_output->i2c_bus = i2cbus; | ||
1028 | intel_output->dev_priv = sdvo_priv; | ||
1029 | |||
1030 | |||
1031 | /* Read the regs to test if we can talk to the device */ | ||
1032 | for (i = 0; i < 0x40; i++) { | ||
1033 | if (!intel_sdvo_read_byte(intel_output, i, &ch[i])) { | ||
1034 | DRM_DEBUG("No SDVO device found on SDVO%c\n", | ||
1035 | output_device == SDVOB ? 'B' : 'C'); | ||
1036 | goto err_i2c; | ||
1037 | } | ||
1038 | } | ||
1039 | |||
1040 | intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps); | ||
1041 | |||
1042 | memset(&sdvo_priv->active_outputs, 0, sizeof(sdvo_priv->active_outputs)); | ||
1043 | |||
1044 | /* TODO, CVBS, SVID, YPRPB & SCART outputs. */ | ||
1045 | if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0) | ||
1046 | { | ||
1047 | sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0; | ||
1048 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
1049 | encoder_type = DRM_MODE_ENCODER_DAC; | ||
1050 | connector_type = DRM_MODE_CONNECTOR_VGA; | ||
1051 | } | ||
1052 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1) | ||
1053 | { | ||
1054 | sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1; | ||
1055 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
1056 | encoder_type = DRM_MODE_ENCODER_DAC; | ||
1057 | connector_type = DRM_MODE_CONNECTOR_VGA; | ||
1058 | } | ||
1059 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) | ||
1060 | { | ||
1061 | sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS0; | ||
1062 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
1063 | encoder_type = DRM_MODE_ENCODER_TMDS; | ||
1064 | connector_type = DRM_MODE_CONNECTOR_DVID; | ||
1065 | } | ||
1066 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS1) | ||
1067 | { | ||
1068 | sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS1; | ||
1069 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
1070 | encoder_type = DRM_MODE_ENCODER_TMDS; | ||
1071 | connector_type = DRM_MODE_CONNECTOR_DVID; | ||
1072 | } | ||
1073 | else | ||
1074 | { | ||
1075 | unsigned char bytes[2]; | ||
1076 | |||
1077 | memcpy (bytes, &sdvo_priv->caps.output_flags, 2); | ||
1078 | DRM_DEBUG("%s: No active RGB or TMDS outputs (0x%02x%02x)\n", | ||
1079 | SDVO_NAME(sdvo_priv), | ||
1080 | bytes[0], bytes[1]); | ||
1081 | goto err_i2c; | ||
1082 | } | ||
1083 | |||
1084 | drm_encoder_init(dev, &intel_output->enc, &intel_sdvo_enc_funcs, encoder_type); | ||
1085 | drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs); | ||
1086 | connector->connector_type = connector_type; | ||
1087 | |||
1088 | drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); | ||
1089 | drm_sysfs_connector_add(connector); | ||
1090 | |||
1091 | /* Set the input timing to the screen. Assume always input 0. */ | ||
1092 | intel_sdvo_set_target_input(intel_output, true, false); | ||
1093 | |||
1094 | intel_sdvo_get_input_pixel_clock_range(intel_output, | ||
1095 | &sdvo_priv->pixel_clock_min, | ||
1096 | &sdvo_priv->pixel_clock_max); | ||
1097 | |||
1098 | |||
1099 | DRM_DEBUG("%s device VID/DID: %02X:%02X.%02X, " | ||
1100 | "clock range %dMHz - %dMHz, " | ||
1101 | "input 1: %c, input 2: %c, " | ||
1102 | "output 1: %c, output 2: %c\n", | ||
1103 | SDVO_NAME(sdvo_priv), | ||
1104 | sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id, | ||
1105 | sdvo_priv->caps.device_rev_id, | ||
1106 | sdvo_priv->pixel_clock_min / 1000, | ||
1107 | sdvo_priv->pixel_clock_max / 1000, | ||
1108 | (sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', | ||
1109 | (sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', | ||
1110 | /* check currently supported outputs */ | ||
1111 | sdvo_priv->caps.output_flags & | ||
1112 | (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N', | ||
1113 | sdvo_priv->caps.output_flags & | ||
1114 | (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); | ||
1115 | |||
1116 | intel_output->ddc_bus = i2cbus; | ||
1117 | |||
1118 | return; | ||
1119 | |||
1120 | err_i2c: | ||
1121 | intel_i2c_destroy(intel_output->i2c_bus); | ||
1122 | err_connector: | ||
1123 | drm_connector_cleanup(connector); | ||
1124 | kfree(intel_output); | ||
1125 | |||
1126 | return; | ||
1127 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h new file mode 100644 index 000000000000..861a43f8693c --- /dev/null +++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h | |||
@@ -0,0 +1,327 @@ | |||
1 | /* | ||
2 | * Copyright © 2006-2007 Intel Corporation | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the next | ||
12 | * paragraph) shall be included in all copies or substantial portions of the | ||
13 | * Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | * | ||
23 | * Authors: | ||
24 | * Eric Anholt <eric@anholt.net> | ||
25 | */ | ||
26 | |||
27 | /** | ||
28 | * @file SDVO command definitions and structures. | ||
29 | */ | ||
30 | |||
31 | #define SDVO_OUTPUT_FIRST (0) | ||
32 | #define SDVO_OUTPUT_TMDS0 (1 << 0) | ||
33 | #define SDVO_OUTPUT_RGB0 (1 << 1) | ||
34 | #define SDVO_OUTPUT_CVBS0 (1 << 2) | ||
35 | #define SDVO_OUTPUT_SVID0 (1 << 3) | ||
36 | #define SDVO_OUTPUT_YPRPB0 (1 << 4) | ||
37 | #define SDVO_OUTPUT_SCART0 (1 << 5) | ||
38 | #define SDVO_OUTPUT_LVDS0 (1 << 6) | ||
39 | #define SDVO_OUTPUT_TMDS1 (1 << 8) | ||
40 | #define SDVO_OUTPUT_RGB1 (1 << 9) | ||
41 | #define SDVO_OUTPUT_CVBS1 (1 << 10) | ||
42 | #define SDVO_OUTPUT_SVID1 (1 << 11) | ||
43 | #define SDVO_OUTPUT_YPRPB1 (1 << 12) | ||
44 | #define SDVO_OUTPUT_SCART1 (1 << 13) | ||
45 | #define SDVO_OUTPUT_LVDS1 (1 << 14) | ||
46 | #define SDVO_OUTPUT_LAST (14) | ||
47 | |||
48 | struct intel_sdvo_caps { | ||
49 | u8 vendor_id; | ||
50 | u8 device_id; | ||
51 | u8 device_rev_id; | ||
52 | u8 sdvo_version_major; | ||
53 | u8 sdvo_version_minor; | ||
54 | unsigned int sdvo_inputs_mask:2; | ||
55 | unsigned int smooth_scaling:1; | ||
56 | unsigned int sharp_scaling:1; | ||
57 | unsigned int up_scaling:1; | ||
58 | unsigned int down_scaling:1; | ||
59 | unsigned int stall_support:1; | ||
60 | unsigned int pad:1; | ||
61 | u16 output_flags; | ||
62 | } __attribute__((packed)); | ||
63 | |||
64 | /** This matches the EDID DTD structure, more or less */ | ||
65 | struct intel_sdvo_dtd { | ||
66 | struct { | ||
67 | u16 clock; /**< pixel clock, in 10kHz units */ | ||
68 | u8 h_active; /**< lower 8 bits (pixels) */ | ||
69 | u8 h_blank; /**< lower 8 bits (pixels) */ | ||
70 | u8 h_high; /**< upper 4 bits each h_active, h_blank */ | ||
71 | u8 v_active; /**< lower 8 bits (lines) */ | ||
72 | u8 v_blank; /**< lower 8 bits (lines) */ | ||
73 | u8 v_high; /**< upper 4 bits each v_active, v_blank */ | ||
74 | } part1; | ||
75 | |||
76 | struct { | ||
77 | u8 h_sync_off; /**< lower 8 bits, from hblank start */ | ||
78 | u8 h_sync_width; /**< lower 8 bits (pixels) */ | ||
79 | /** lower 4 bits each vsync offset, vsync width */ | ||
80 | u8 v_sync_off_width; | ||
81 | /** | ||
82 | * 2 high bits of hsync offset, 2 high bits of hsync width, | ||
83 | * bits 4-5 of vsync offset, and 2 high bits of vsync width. | ||
84 | */ | ||
85 | u8 sync_off_width_high; | ||
86 | u8 dtd_flags; | ||
87 | u8 sdvo_flags; | ||
88 | /** bits 6-7 of vsync offset at bits 6-7 */ | ||
89 | u8 v_sync_off_high; | ||
90 | u8 reserved; | ||
91 | } part2; | ||
92 | } __attribute__((packed)); | ||
93 | |||
94 | struct intel_sdvo_pixel_clock_range { | ||
95 | u16 min; /**< pixel clock, in 10kHz units */ | ||
96 | u16 max; /**< pixel clock, in 10kHz units */ | ||
97 | } __attribute__((packed)); | ||
98 | |||
99 | struct intel_sdvo_preferred_input_timing_args { | ||
100 | u16 clock; | ||
101 | u16 width; | ||
102 | u16 height; | ||
103 | } __attribute__((packed)); | ||
104 | |||
105 | /* I2C registers for SDVO */ | ||
106 | #define SDVO_I2C_ARG_0 0x07 | ||
107 | #define SDVO_I2C_ARG_1 0x06 | ||
108 | #define SDVO_I2C_ARG_2 0x05 | ||
109 | #define SDVO_I2C_ARG_3 0x04 | ||
110 | #define SDVO_I2C_ARG_4 0x03 | ||
111 | #define SDVO_I2C_ARG_5 0x02 | ||
112 | #define SDVO_I2C_ARG_6 0x01 | ||
113 | #define SDVO_I2C_ARG_7 0x00 | ||
114 | #define SDVO_I2C_OPCODE 0x08 | ||
115 | #define SDVO_I2C_CMD_STATUS 0x09 | ||
116 | #define SDVO_I2C_RETURN_0 0x0a | ||
117 | #define SDVO_I2C_RETURN_1 0x0b | ||
118 | #define SDVO_I2C_RETURN_2 0x0c | ||
119 | #define SDVO_I2C_RETURN_3 0x0d | ||
120 | #define SDVO_I2C_RETURN_4 0x0e | ||
121 | #define SDVO_I2C_RETURN_5 0x0f | ||
122 | #define SDVO_I2C_RETURN_6 0x10 | ||
123 | #define SDVO_I2C_RETURN_7 0x11 | ||
124 | #define SDVO_I2C_VENDOR_BEGIN 0x20 | ||
125 | |||
126 | /* Status results */ | ||
127 | #define SDVO_CMD_STATUS_POWER_ON 0x0 | ||
128 | #define SDVO_CMD_STATUS_SUCCESS 0x1 | ||
129 | #define SDVO_CMD_STATUS_NOTSUPP 0x2 | ||
130 | #define SDVO_CMD_STATUS_INVALID_ARG 0x3 | ||
131 | #define SDVO_CMD_STATUS_PENDING 0x4 | ||
132 | #define SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED 0x5 | ||
133 | #define SDVO_CMD_STATUS_SCALING_NOT_SUPP 0x6 | ||
134 | |||
135 | /* SDVO commands, argument/result registers */ | ||
136 | |||
137 | #define SDVO_CMD_RESET 0x01 | ||
138 | |||
139 | /** Returns a struct intel_sdvo_caps */ | ||
140 | #define SDVO_CMD_GET_DEVICE_CAPS 0x02 | ||
141 | |||
142 | #define SDVO_CMD_GET_FIRMWARE_REV 0x86 | ||
143 | # define SDVO_DEVICE_FIRMWARE_MINOR SDVO_I2C_RETURN_0 | ||
144 | # define SDVO_DEVICE_FIRMWARE_MAJOR SDVO_I2C_RETURN_1 | ||
145 | # define SDVO_DEVICE_FIRMWARE_PATCH SDVO_I2C_RETURN_2 | ||
146 | |||
147 | /** | ||
148 | * Reports which inputs are trained (managed to sync). | ||
149 | * | ||
150 | * Devices must have trained within 2 vsyncs of a mode change. | ||
151 | */ | ||
152 | #define SDVO_CMD_GET_TRAINED_INPUTS 0x03 | ||
153 | struct intel_sdvo_get_trained_inputs_response { | ||
154 | unsigned int input0_trained:1; | ||
155 | unsigned int input1_trained:1; | ||
156 | unsigned int pad:6; | ||
157 | } __attribute__((packed)); | ||
158 | |||
159 | /** Returns a struct intel_sdvo_output_flags of active outputs. */ | ||
160 | #define SDVO_CMD_GET_ACTIVE_OUTPUTS 0x04 | ||
161 | |||
162 | /** | ||
163 | * Sets the current set of active outputs. | ||
164 | * | ||
165 | * Takes a struct intel_sdvo_output_flags. Must be preceded by a SET_IN_OUT_MAP | ||
166 | * on multi-output devices. | ||
167 | */ | ||
168 | #define SDVO_CMD_SET_ACTIVE_OUTPUTS 0x05 | ||
169 | |||
170 | /** | ||
171 | * Returns the current mapping of SDVO inputs to outputs on the device. | ||
172 | * | ||
173 | * Returns two struct intel_sdvo_output_flags structures. | ||
174 | */ | ||
175 | #define SDVO_CMD_GET_IN_OUT_MAP 0x06 | ||
176 | |||
177 | /** | ||
178 | * Sets the current mapping of SDVO inputs to outputs on the device. | ||
179 | * | ||
180 | * Takes two struct i380_sdvo_output_flags structures. | ||
181 | */ | ||
182 | #define SDVO_CMD_SET_IN_OUT_MAP 0x07 | ||
183 | |||
184 | /** | ||
185 | * Returns a struct intel_sdvo_output_flags of attached displays. | ||
186 | */ | ||
187 | #define SDVO_CMD_GET_ATTACHED_DISPLAYS 0x0b | ||
188 | |||
189 | /** | ||
190 | * Returns a struct intel_sdvo_ouptut_flags of displays supporting hot plugging. | ||
191 | */ | ||
192 | #define SDVO_CMD_GET_HOT_PLUG_SUPPORT 0x0c | ||
193 | |||
194 | /** | ||
195 | * Takes a struct intel_sdvo_output_flags. | ||
196 | */ | ||
197 | #define SDVO_CMD_SET_ACTIVE_HOT_PLUG 0x0d | ||
198 | |||
199 | /** | ||
200 | * Returns a struct intel_sdvo_output_flags of displays with hot plug | ||
201 | * interrupts enabled. | ||
202 | */ | ||
203 | #define SDVO_CMD_GET_ACTIVE_HOT_PLUG 0x0e | ||
204 | |||
205 | #define SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE 0x0f | ||
206 | struct intel_sdvo_get_interrupt_event_source_response { | ||
207 | u16 interrupt_status; | ||
208 | unsigned int ambient_light_interrupt:1; | ||
209 | unsigned int pad:7; | ||
210 | } __attribute__((packed)); | ||
211 | |||
212 | /** | ||
213 | * Selects which input is affected by future input commands. | ||
214 | * | ||
215 | * Commands affected include SET_INPUT_TIMINGS_PART[12], | ||
216 | * GET_INPUT_TIMINGS_PART[12], GET_PREFERRED_INPUT_TIMINGS_PART[12], | ||
217 | * GET_INPUT_PIXEL_CLOCK_RANGE, and CREATE_PREFERRED_INPUT_TIMINGS. | ||
218 | */ | ||
219 | #define SDVO_CMD_SET_TARGET_INPUT 0x10 | ||
220 | struct intel_sdvo_set_target_input_args { | ||
221 | unsigned int target_1:1; | ||
222 | unsigned int pad:7; | ||
223 | } __attribute__((packed)); | ||
224 | |||
225 | /** | ||
226 | * Takes a struct intel_sdvo_output_flags of which outputs are targetted by | ||
227 | * future output commands. | ||
228 | * | ||
229 | * Affected commands inclue SET_OUTPUT_TIMINGS_PART[12], | ||
230 | * GET_OUTPUT_TIMINGS_PART[12], and GET_OUTPUT_PIXEL_CLOCK_RANGE. | ||
231 | */ | ||
232 | #define SDVO_CMD_SET_TARGET_OUTPUT 0x11 | ||
233 | |||
234 | #define SDVO_CMD_GET_INPUT_TIMINGS_PART1 0x12 | ||
235 | #define SDVO_CMD_GET_INPUT_TIMINGS_PART2 0x13 | ||
236 | #define SDVO_CMD_SET_INPUT_TIMINGS_PART1 0x14 | ||
237 | #define SDVO_CMD_SET_INPUT_TIMINGS_PART2 0x15 | ||
238 | #define SDVO_CMD_SET_OUTPUT_TIMINGS_PART1 0x16 | ||
239 | #define SDVO_CMD_SET_OUTPUT_TIMINGS_PART2 0x17 | ||
240 | #define SDVO_CMD_GET_OUTPUT_TIMINGS_PART1 0x18 | ||
241 | #define SDVO_CMD_GET_OUTPUT_TIMINGS_PART2 0x19 | ||
242 | /* Part 1 */ | ||
243 | # define SDVO_DTD_CLOCK_LOW SDVO_I2C_ARG_0 | ||
244 | # define SDVO_DTD_CLOCK_HIGH SDVO_I2C_ARG_1 | ||
245 | # define SDVO_DTD_H_ACTIVE SDVO_I2C_ARG_2 | ||
246 | # define SDVO_DTD_H_BLANK SDVO_I2C_ARG_3 | ||
247 | # define SDVO_DTD_H_HIGH SDVO_I2C_ARG_4 | ||
248 | # define SDVO_DTD_V_ACTIVE SDVO_I2C_ARG_5 | ||
249 | # define SDVO_DTD_V_BLANK SDVO_I2C_ARG_6 | ||
250 | # define SDVO_DTD_V_HIGH SDVO_I2C_ARG_7 | ||
251 | /* Part 2 */ | ||
252 | # define SDVO_DTD_HSYNC_OFF SDVO_I2C_ARG_0 | ||
253 | # define SDVO_DTD_HSYNC_WIDTH SDVO_I2C_ARG_1 | ||
254 | # define SDVO_DTD_VSYNC_OFF_WIDTH SDVO_I2C_ARG_2 | ||
255 | # define SDVO_DTD_SYNC_OFF_WIDTH_HIGH SDVO_I2C_ARG_3 | ||
256 | # define SDVO_DTD_DTD_FLAGS SDVO_I2C_ARG_4 | ||
257 | # define SDVO_DTD_DTD_FLAG_INTERLACED (1 << 7) | ||
258 | # define SDVO_DTD_DTD_FLAG_STEREO_MASK (3 << 5) | ||
259 | # define SDVO_DTD_DTD_FLAG_INPUT_MASK (3 << 3) | ||
260 | # define SDVO_DTD_DTD_FLAG_SYNC_MASK (3 << 1) | ||
261 | # define SDVO_DTD_SDVO_FLAS SDVO_I2C_ARG_5 | ||
262 | # define SDVO_DTD_SDVO_FLAG_STALL (1 << 7) | ||
263 | # define SDVO_DTD_SDVO_FLAG_CENTERED (0 << 6) | ||
264 | # define SDVO_DTD_SDVO_FLAG_UPPER_LEFT (1 << 6) | ||
265 | # define SDVO_DTD_SDVO_FLAG_SCALING_MASK (3 << 4) | ||
266 | # define SDVO_DTD_SDVO_FLAG_SCALING_NONE (0 << 4) | ||
267 | # define SDVO_DTD_SDVO_FLAG_SCALING_SHARP (1 << 4) | ||
268 | # define SDVO_DTD_SDVO_FLAG_SCALING_SMOOTH (2 << 4) | ||
269 | # define SDVO_DTD_VSYNC_OFF_HIGH SDVO_I2C_ARG_6 | ||
270 | |||
271 | /** | ||
272 | * Generates a DTD based on the given width, height, and flags. | ||
273 | * | ||
274 | * This will be supported by any device supporting scaling or interlaced | ||
275 | * modes. | ||
276 | */ | ||
277 | #define SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING 0x1a | ||
278 | # define SDVO_PREFERRED_INPUT_TIMING_CLOCK_LOW SDVO_I2C_ARG_0 | ||
279 | # define SDVO_PREFERRED_INPUT_TIMING_CLOCK_HIGH SDVO_I2C_ARG_1 | ||
280 | # define SDVO_PREFERRED_INPUT_TIMING_WIDTH_LOW SDVO_I2C_ARG_2 | ||
281 | # define SDVO_PREFERRED_INPUT_TIMING_WIDTH_HIGH SDVO_I2C_ARG_3 | ||
282 | # define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_LOW SDVO_I2C_ARG_4 | ||
283 | # define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_HIGH SDVO_I2C_ARG_5 | ||
284 | # define SDVO_PREFERRED_INPUT_TIMING_FLAGS SDVO_I2C_ARG_6 | ||
285 | # define SDVO_PREFERRED_INPUT_TIMING_FLAGS_INTERLACED (1 << 0) | ||
286 | # define SDVO_PREFERRED_INPUT_TIMING_FLAGS_SCALED (1 << 1) | ||
287 | |||
288 | #define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1 0x1b | ||
289 | #define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2 0x1c | ||
290 | |||
291 | /** Returns a struct intel_sdvo_pixel_clock_range */ | ||
292 | #define SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE 0x1d | ||
293 | /** Returns a struct intel_sdvo_pixel_clock_range */ | ||
294 | #define SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE 0x1e | ||
295 | |||
296 | /** Returns a byte bitfield containing SDVO_CLOCK_RATE_MULT_* flags */ | ||
297 | #define SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS 0x1f | ||
298 | |||
299 | /** Returns a byte containing a SDVO_CLOCK_RATE_MULT_* flag */ | ||
300 | #define SDVO_CMD_GET_CLOCK_RATE_MULT 0x20 | ||
301 | /** Takes a byte containing a SDVO_CLOCK_RATE_MULT_* flag */ | ||
302 | #define SDVO_CMD_SET_CLOCK_RATE_MULT 0x21 | ||
303 | # define SDVO_CLOCK_RATE_MULT_1X (1 << 0) | ||
304 | # define SDVO_CLOCK_RATE_MULT_2X (1 << 1) | ||
305 | # define SDVO_CLOCK_RATE_MULT_4X (1 << 3) | ||
306 | |||
307 | #define SDVO_CMD_GET_SUPPORTED_TV_FORMATS 0x27 | ||
308 | |||
309 | #define SDVO_CMD_GET_TV_FORMAT 0x28 | ||
310 | |||
311 | #define SDVO_CMD_SET_TV_FORMAT 0x29 | ||
312 | |||
313 | #define SDVO_CMD_GET_SUPPORTED_POWER_STATES 0x2a | ||
314 | #define SDVO_CMD_GET_ENCODER_POWER_STATE 0x2b | ||
315 | #define SDVO_CMD_SET_ENCODER_POWER_STATE 0x2c | ||
316 | # define SDVO_ENCODER_STATE_ON (1 << 0) | ||
317 | # define SDVO_ENCODER_STATE_STANDBY (1 << 1) | ||
318 | # define SDVO_ENCODER_STATE_SUSPEND (1 << 2) | ||
319 | # define SDVO_ENCODER_STATE_OFF (1 << 3) | ||
320 | |||
321 | #define SDVO_CMD_SET_TV_RESOLUTION_SUPPORT 0x93 | ||
322 | |||
323 | #define SDVO_CMD_SET_CONTROL_BUS_SWITCH 0x7a | ||
324 | # define SDVO_CONTROL_BUS_PROM 0x0 | ||
325 | # define SDVO_CONTROL_BUS_DDC1 0x1 | ||
326 | # define SDVO_CONTROL_BUS_DDC2 0x2 | ||
327 | # define SDVO_CONTROL_BUS_DDC3 0x3 | ||
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c new file mode 100644 index 000000000000..d409b8637883 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_tv.c | |||
@@ -0,0 +1,1725 @@ | |||
1 | /* | ||
2 | * Copyright © 2006-2008 Intel Corporation | ||
3 | * Jesse Barnes <jesse.barnes@intel.com> | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
6 | * copy of this software and associated documentation files (the "Software"), | ||
7 | * to deal in the Software without restriction, including without limitation | ||
8 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
9 | * and/or sell copies of the Software, and to permit persons to whom the | ||
10 | * Software is furnished to do so, subject to the following conditions: | ||
11 | * | ||
12 | * The above copyright notice and this permission notice (including the next | ||
13 | * paragraph) shall be included in all copies or substantial portions of the | ||
14 | * Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
22 | * DEALINGS IN THE SOFTWARE. | ||
23 | * | ||
24 | * Authors: | ||
25 | * Eric Anholt <eric@anholt.net> | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | /** @file | ||
30 | * Integrated TV-out support for the 915GM and 945GM. | ||
31 | */ | ||
32 | |||
33 | #include "drmP.h" | ||
34 | #include "drm.h" | ||
35 | #include "drm_crtc.h" | ||
36 | #include "drm_edid.h" | ||
37 | #include "intel_drv.h" | ||
38 | #include "i915_drm.h" | ||
39 | #include "i915_drv.h" | ||
40 | |||
41 | enum tv_margin { | ||
42 | TV_MARGIN_LEFT, TV_MARGIN_TOP, | ||
43 | TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM | ||
44 | }; | ||
45 | |||
46 | /** Private structure for the integrated TV support */ | ||
47 | struct intel_tv_priv { | ||
48 | int type; | ||
49 | char *tv_format; | ||
50 | int margin[4]; | ||
51 | u32 save_TV_H_CTL_1; | ||
52 | u32 save_TV_H_CTL_2; | ||
53 | u32 save_TV_H_CTL_3; | ||
54 | u32 save_TV_V_CTL_1; | ||
55 | u32 save_TV_V_CTL_2; | ||
56 | u32 save_TV_V_CTL_3; | ||
57 | u32 save_TV_V_CTL_4; | ||
58 | u32 save_TV_V_CTL_5; | ||
59 | u32 save_TV_V_CTL_6; | ||
60 | u32 save_TV_V_CTL_7; | ||
61 | u32 save_TV_SC_CTL_1, save_TV_SC_CTL_2, save_TV_SC_CTL_3; | ||
62 | |||
63 | u32 save_TV_CSC_Y; | ||
64 | u32 save_TV_CSC_Y2; | ||
65 | u32 save_TV_CSC_U; | ||
66 | u32 save_TV_CSC_U2; | ||
67 | u32 save_TV_CSC_V; | ||
68 | u32 save_TV_CSC_V2; | ||
69 | u32 save_TV_CLR_KNOBS; | ||
70 | u32 save_TV_CLR_LEVEL; | ||
71 | u32 save_TV_WIN_POS; | ||
72 | u32 save_TV_WIN_SIZE; | ||
73 | u32 save_TV_FILTER_CTL_1; | ||
74 | u32 save_TV_FILTER_CTL_2; | ||
75 | u32 save_TV_FILTER_CTL_3; | ||
76 | |||
77 | u32 save_TV_H_LUMA[60]; | ||
78 | u32 save_TV_H_CHROMA[60]; | ||
79 | u32 save_TV_V_LUMA[43]; | ||
80 | u32 save_TV_V_CHROMA[43]; | ||
81 | |||
82 | u32 save_TV_DAC; | ||
83 | u32 save_TV_CTL; | ||
84 | }; | ||
85 | |||
86 | struct video_levels { | ||
87 | int blank, black, burst; | ||
88 | }; | ||
89 | |||
90 | struct color_conversion { | ||
91 | u16 ry, gy, by, ay; | ||
92 | u16 ru, gu, bu, au; | ||
93 | u16 rv, gv, bv, av; | ||
94 | }; | ||
95 | |||
96 | static const u32 filter_table[] = { | ||
97 | 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140, | ||
98 | 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000, | ||
99 | 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160, | ||
100 | 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780, | ||
101 | 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50, | ||
102 | 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20, | ||
103 | 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0, | ||
104 | 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0, | ||
105 | 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020, | ||
106 | 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140, | ||
107 | 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20, | ||
108 | 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848, | ||
109 | 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900, | ||
110 | 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080, | ||
111 | 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060, | ||
112 | 0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140, | ||
113 | 0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000, | ||
114 | 0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160, | ||
115 | 0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780, | ||
116 | 0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50, | ||
117 | 0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20, | ||
118 | 0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0, | ||
119 | 0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0, | ||
120 | 0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020, | ||
121 | 0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140, | ||
122 | 0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20, | ||
123 | 0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848, | ||
124 | 0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900, | ||
125 | 0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080, | ||
126 | 0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060, | ||
127 | 0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0, | ||
128 | 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540, | ||
129 | 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00, | ||
130 | 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000, | ||
131 | 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00, | ||
132 | 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40, | ||
133 | 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240, | ||
134 | 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00, | ||
135 | 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0, | ||
136 | 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840, | ||
137 | 0x28003100, 0x28002F00, 0x00003100, 0x36403000, | ||
138 | 0x2D002CC0, 0x30003640, 0x2D0036C0, | ||
139 | 0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540, | ||
140 | 0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00, | ||
141 | 0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000, | ||
142 | 0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00, | ||
143 | 0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40, | ||
144 | 0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240, | ||
145 | 0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00, | ||
146 | 0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0, | ||
147 | 0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840, | ||
148 | 0x28003100, 0x28002F00, 0x00003100, | ||
149 | }; | ||
150 | |||
151 | /* | ||
152 | * Color conversion values have 3 separate fixed point formats: | ||
153 | * | ||
154 | * 10 bit fields (ay, au) | ||
155 | * 1.9 fixed point (b.bbbbbbbbb) | ||
156 | * 11 bit fields (ry, by, ru, gu, gv) | ||
157 | * exp.mantissa (ee.mmmmmmmmm) | ||
158 | * ee = 00 = 10^-1 (0.mmmmmmmmm) | ||
159 | * ee = 01 = 10^-2 (0.0mmmmmmmmm) | ||
160 | * ee = 10 = 10^-3 (0.00mmmmmmmmm) | ||
161 | * ee = 11 = 10^-4 (0.000mmmmmmmmm) | ||
162 | * 12 bit fields (gy, rv, bu) | ||
163 | * exp.mantissa (eee.mmmmmmmmm) | ||
164 | * eee = 000 = 10^-1 (0.mmmmmmmmm) | ||
165 | * eee = 001 = 10^-2 (0.0mmmmmmmmm) | ||
166 | * eee = 010 = 10^-3 (0.00mmmmmmmmm) | ||
167 | * eee = 011 = 10^-4 (0.000mmmmmmmmm) | ||
168 | * eee = 100 = reserved | ||
169 | * eee = 101 = reserved | ||
170 | * eee = 110 = reserved | ||
171 | * eee = 111 = 10^0 (m.mmmmmmmm) (only usable for 1.0 representation) | ||
172 | * | ||
173 | * Saturation and contrast are 8 bits, with their own representation: | ||
174 | * 8 bit field (saturation, contrast) | ||
175 | * exp.mantissa (ee.mmmmmm) | ||
176 | * ee = 00 = 10^-1 (0.mmmmmm) | ||
177 | * ee = 01 = 10^0 (m.mmmmm) | ||
178 | * ee = 10 = 10^1 (mm.mmmm) | ||
179 | * ee = 11 = 10^2 (mmm.mmm) | ||
180 | * | ||
181 | * Simple conversion function: | ||
182 | * | ||
183 | * static u32 | ||
184 | * float_to_csc_11(float f) | ||
185 | * { | ||
186 | * u32 exp; | ||
187 | * u32 mant; | ||
188 | * u32 ret; | ||
189 | * | ||
190 | * if (f < 0) | ||
191 | * f = -f; | ||
192 | * | ||
193 | * if (f >= 1) { | ||
194 | * exp = 0x7; | ||
195 | * mant = 1 << 8; | ||
196 | * } else { | ||
197 | * for (exp = 0; exp < 3 && f < 0.5; exp++) | ||
198 | * f *= 2.0; | ||
199 | * mant = (f * (1 << 9) + 0.5); | ||
200 | * if (mant >= (1 << 9)) | ||
201 | * mant = (1 << 9) - 1; | ||
202 | * } | ||
203 | * ret = (exp << 9) | mant; | ||
204 | * return ret; | ||
205 | * } | ||
206 | */ | ||
207 | |||
208 | /* | ||
209 | * Behold, magic numbers! If we plant them they might grow a big | ||
210 | * s-video cable to the sky... or something. | ||
211 | * | ||
212 | * Pre-converted to appropriate hex value. | ||
213 | */ | ||
214 | |||
215 | /* | ||
216 | * PAL & NTSC values for composite & s-video connections | ||
217 | */ | ||
218 | static const struct color_conversion ntsc_m_csc_composite = { | ||
219 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104, | ||
220 | .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00, | ||
221 | .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00, | ||
222 | }; | ||
223 | |||
224 | static const struct video_levels ntsc_m_levels_composite = { | ||
225 | .blank = 225, .black = 267, .burst = 113, | ||
226 | }; | ||
227 | |||
228 | static const struct color_conversion ntsc_m_csc_svideo = { | ||
229 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134, | ||
230 | .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00, | ||
231 | .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00, | ||
232 | }; | ||
233 | |||
234 | static const struct video_levels ntsc_m_levels_svideo = { | ||
235 | .blank = 266, .black = 316, .burst = 133, | ||
236 | }; | ||
237 | |||
238 | static const struct color_conversion ntsc_j_csc_composite = { | ||
239 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119, | ||
240 | .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0f00, | ||
241 | .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0f00, | ||
242 | }; | ||
243 | |||
244 | static const struct video_levels ntsc_j_levels_composite = { | ||
245 | .blank = 225, .black = 225, .burst = 113, | ||
246 | }; | ||
247 | |||
248 | static const struct color_conversion ntsc_j_csc_svideo = { | ||
249 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c, | ||
250 | .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0f00, | ||
251 | .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0f00, | ||
252 | }; | ||
253 | |||
254 | static const struct video_levels ntsc_j_levels_svideo = { | ||
255 | .blank = 266, .black = 266, .burst = 133, | ||
256 | }; | ||
257 | |||
258 | static const struct color_conversion pal_csc_composite = { | ||
259 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113, | ||
260 | .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0f00, | ||
261 | .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0f00, | ||
262 | }; | ||
263 | |||
264 | static const struct video_levels pal_levels_composite = { | ||
265 | .blank = 237, .black = 237, .burst = 118, | ||
266 | }; | ||
267 | |||
268 | static const struct color_conversion pal_csc_svideo = { | ||
269 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145, | ||
270 | .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0f00, | ||
271 | .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0f00, | ||
272 | }; | ||
273 | |||
274 | static const struct video_levels pal_levels_svideo = { | ||
275 | .blank = 280, .black = 280, .burst = 139, | ||
276 | }; | ||
277 | |||
278 | static const struct color_conversion pal_m_csc_composite = { | ||
279 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104, | ||
280 | .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00, | ||
281 | .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00, | ||
282 | }; | ||
283 | |||
284 | static const struct video_levels pal_m_levels_composite = { | ||
285 | .blank = 225, .black = 267, .burst = 113, | ||
286 | }; | ||
287 | |||
288 | static const struct color_conversion pal_m_csc_svideo = { | ||
289 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134, | ||
290 | .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00, | ||
291 | .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00, | ||
292 | }; | ||
293 | |||
294 | static const struct video_levels pal_m_levels_svideo = { | ||
295 | .blank = 266, .black = 316, .burst = 133, | ||
296 | }; | ||
297 | |||
298 | static const struct color_conversion pal_n_csc_composite = { | ||
299 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104, | ||
300 | .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00, | ||
301 | .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00, | ||
302 | }; | ||
303 | |||
304 | static const struct video_levels pal_n_levels_composite = { | ||
305 | .blank = 225, .black = 267, .burst = 118, | ||
306 | }; | ||
307 | |||
308 | static const struct color_conversion pal_n_csc_svideo = { | ||
309 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134, | ||
310 | .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00, | ||
311 | .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00, | ||
312 | }; | ||
313 | |||
314 | static const struct video_levels pal_n_levels_svideo = { | ||
315 | .blank = 266, .black = 316, .burst = 139, | ||
316 | }; | ||
317 | |||
318 | /* | ||
319 | * Component connections | ||
320 | */ | ||
321 | static const struct color_conversion sdtv_csc_yprpb = { | ||
322 | .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0146, | ||
323 | .ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0f00, | ||
324 | .rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0f00, | ||
325 | }; | ||
326 | |||
327 | static const struct color_conversion sdtv_csc_rgb = { | ||
328 | .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166, | ||
329 | .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166, | ||
330 | .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166, | ||
331 | }; | ||
332 | |||
333 | static const struct color_conversion hdtv_csc_yprpb = { | ||
334 | .ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0146, | ||
335 | .ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0f00, | ||
336 | .rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0f00, | ||
337 | }; | ||
338 | |||
339 | static const struct color_conversion hdtv_csc_rgb = { | ||
340 | .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166, | ||
341 | .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166, | ||
342 | .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166, | ||
343 | }; | ||
344 | |||
345 | static const struct video_levels component_levels = { | ||
346 | .blank = 279, .black = 279, .burst = 0, | ||
347 | }; | ||
348 | |||
349 | |||
350 | struct tv_mode { | ||
351 | char *name; | ||
352 | int clock; | ||
353 | int refresh; /* in millihertz (for precision) */ | ||
354 | u32 oversample; | ||
355 | int hsync_end, hblank_start, hblank_end, htotal; | ||
356 | bool progressive, trilevel_sync, component_only; | ||
357 | int vsync_start_f1, vsync_start_f2, vsync_len; | ||
358 | bool veq_ena; | ||
359 | int veq_start_f1, veq_start_f2, veq_len; | ||
360 | int vi_end_f1, vi_end_f2, nbr_end; | ||
361 | bool burst_ena; | ||
362 | int hburst_start, hburst_len; | ||
363 | int vburst_start_f1, vburst_end_f1; | ||
364 | int vburst_start_f2, vburst_end_f2; | ||
365 | int vburst_start_f3, vburst_end_f3; | ||
366 | int vburst_start_f4, vburst_end_f4; | ||
367 | /* | ||
368 | * subcarrier programming | ||
369 | */ | ||
370 | int dda2_size, dda3_size, dda1_inc, dda2_inc, dda3_inc; | ||
371 | u32 sc_reset; | ||
372 | bool pal_burst; | ||
373 | /* | ||
374 | * blank/black levels | ||
375 | */ | ||
376 | const struct video_levels *composite_levels, *svideo_levels; | ||
377 | const struct color_conversion *composite_color, *svideo_color; | ||
378 | const u32 *filter_table; | ||
379 | int max_srcw; | ||
380 | }; | ||
381 | |||
382 | |||
383 | /* | ||
384 | * Sub carrier DDA | ||
385 | * | ||
386 | * I think this works as follows: | ||
387 | * | ||
388 | * subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096 | ||
389 | * | ||
390 | * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value | ||
391 | * | ||
392 | * So, | ||
393 | * dda1_ideal = subcarrier/pixel * 4096 | ||
394 | * dda1_inc = floor (dda1_ideal) | ||
395 | * dda2 = dda1_ideal - dda1_inc | ||
396 | * | ||
397 | * then pick a ratio for dda2 that gives the closest approximation. If | ||
398 | * you can't get close enough, you can play with dda3 as well. This | ||
399 | * seems likely to happen when dda2 is small as the jumps would be larger | ||
400 | * | ||
401 | * To invert this, | ||
402 | * | ||
403 | * pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size) | ||
404 | * | ||
405 | * The constants below were all computed using a 107.520MHz clock | ||
406 | */ | ||
407 | |||
408 | /** | ||
409 | * Register programming values for TV modes. | ||
410 | * | ||
411 | * These values account for -1s required. | ||
412 | */ | ||
413 | |||
414 | const static struct tv_mode tv_modes[] = { | ||
415 | { | ||
416 | .name = "NTSC-M", | ||
417 | .clock = 107520, | ||
418 | .refresh = 29970, | ||
419 | .oversample = TV_OVERSAMPLE_8X, | ||
420 | .component_only = 0, | ||
421 | /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */ | ||
422 | |||
423 | .hsync_end = 64, .hblank_end = 124, | ||
424 | .hblank_start = 836, .htotal = 857, | ||
425 | |||
426 | .progressive = false, .trilevel_sync = false, | ||
427 | |||
428 | .vsync_start_f1 = 6, .vsync_start_f2 = 7, | ||
429 | .vsync_len = 6, | ||
430 | |||
431 | .veq_ena = true, .veq_start_f1 = 0, | ||
432 | .veq_start_f2 = 1, .veq_len = 18, | ||
433 | |||
434 | .vi_end_f1 = 20, .vi_end_f2 = 21, | ||
435 | .nbr_end = 240, | ||
436 | |||
437 | .burst_ena = true, | ||
438 | .hburst_start = 72, .hburst_len = 34, | ||
439 | .vburst_start_f1 = 9, .vburst_end_f1 = 240, | ||
440 | .vburst_start_f2 = 10, .vburst_end_f2 = 240, | ||
441 | .vburst_start_f3 = 9, .vburst_end_f3 = 240, | ||
442 | .vburst_start_f4 = 10, .vburst_end_f4 = 240, | ||
443 | |||
444 | /* desired 3.5800000 actual 3.5800000 clock 107.52 */ | ||
445 | .dda1_inc = 136, | ||
446 | .dda2_inc = 7624, .dda2_size = 20013, | ||
447 | .dda3_inc = 0, .dda3_size = 0, | ||
448 | .sc_reset = TV_SC_RESET_EVERY_4, | ||
449 | .pal_burst = false, | ||
450 | |||
451 | .composite_levels = &ntsc_m_levels_composite, | ||
452 | .composite_color = &ntsc_m_csc_composite, | ||
453 | .svideo_levels = &ntsc_m_levels_svideo, | ||
454 | .svideo_color = &ntsc_m_csc_svideo, | ||
455 | |||
456 | .filter_table = filter_table, | ||
457 | }, | ||
458 | { | ||
459 | .name = "NTSC-443", | ||
460 | .clock = 107520, | ||
461 | .refresh = 29970, | ||
462 | .oversample = TV_OVERSAMPLE_8X, | ||
463 | .component_only = 0, | ||
464 | /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */ | ||
465 | .hsync_end = 64, .hblank_end = 124, | ||
466 | .hblank_start = 836, .htotal = 857, | ||
467 | |||
468 | .progressive = false, .trilevel_sync = false, | ||
469 | |||
470 | .vsync_start_f1 = 6, .vsync_start_f2 = 7, | ||
471 | .vsync_len = 6, | ||
472 | |||
473 | .veq_ena = true, .veq_start_f1 = 0, | ||
474 | .veq_start_f2 = 1, .veq_len = 18, | ||
475 | |||
476 | .vi_end_f1 = 20, .vi_end_f2 = 21, | ||
477 | .nbr_end = 240, | ||
478 | |||
479 | .burst_ena = 8, | ||
480 | .hburst_start = 72, .hburst_len = 34, | ||
481 | .vburst_start_f1 = 9, .vburst_end_f1 = 240, | ||
482 | .vburst_start_f2 = 10, .vburst_end_f2 = 240, | ||
483 | .vburst_start_f3 = 9, .vburst_end_f3 = 240, | ||
484 | .vburst_start_f4 = 10, .vburst_end_f4 = 240, | ||
485 | |||
486 | /* desired 4.4336180 actual 4.4336180 clock 107.52 */ | ||
487 | .dda1_inc = 168, | ||
488 | .dda2_inc = 18557, .dda2_size = 20625, | ||
489 | .dda3_inc = 0, .dda3_size = 0, | ||
490 | .sc_reset = TV_SC_RESET_EVERY_8, | ||
491 | .pal_burst = true, | ||
492 | |||
493 | .composite_levels = &ntsc_m_levels_composite, | ||
494 | .composite_color = &ntsc_m_csc_composite, | ||
495 | .svideo_levels = &ntsc_m_levels_svideo, | ||
496 | .svideo_color = &ntsc_m_csc_svideo, | ||
497 | |||
498 | .filter_table = filter_table, | ||
499 | }, | ||
500 | { | ||
501 | .name = "NTSC-J", | ||
502 | .clock = 107520, | ||
503 | .refresh = 29970, | ||
504 | .oversample = TV_OVERSAMPLE_8X, | ||
505 | .component_only = 0, | ||
506 | |||
507 | /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */ | ||
508 | .hsync_end = 64, .hblank_end = 124, | ||
509 | .hblank_start = 836, .htotal = 857, | ||
510 | |||
511 | .progressive = false, .trilevel_sync = false, | ||
512 | |||
513 | .vsync_start_f1 = 6, .vsync_start_f2 = 7, | ||
514 | .vsync_len = 6, | ||
515 | |||
516 | .veq_ena = true, .veq_start_f1 = 0, | ||
517 | .veq_start_f2 = 1, .veq_len = 18, | ||
518 | |||
519 | .vi_end_f1 = 20, .vi_end_f2 = 21, | ||
520 | .nbr_end = 240, | ||
521 | |||
522 | .burst_ena = true, | ||
523 | .hburst_start = 72, .hburst_len = 34, | ||
524 | .vburst_start_f1 = 9, .vburst_end_f1 = 240, | ||
525 | .vburst_start_f2 = 10, .vburst_end_f2 = 240, | ||
526 | .vburst_start_f3 = 9, .vburst_end_f3 = 240, | ||
527 | .vburst_start_f4 = 10, .vburst_end_f4 = 240, | ||
528 | |||
529 | /* desired 3.5800000 actual 3.5800000 clock 107.52 */ | ||
530 | .dda1_inc = 136, | ||
531 | .dda2_inc = 7624, .dda2_size = 20013, | ||
532 | .dda3_inc = 0, .dda3_size = 0, | ||
533 | .sc_reset = TV_SC_RESET_EVERY_4, | ||
534 | .pal_burst = false, | ||
535 | |||
536 | .composite_levels = &ntsc_j_levels_composite, | ||
537 | .composite_color = &ntsc_j_csc_composite, | ||
538 | .svideo_levels = &ntsc_j_levels_svideo, | ||
539 | .svideo_color = &ntsc_j_csc_svideo, | ||
540 | |||
541 | .filter_table = filter_table, | ||
542 | }, | ||
543 | { | ||
544 | .name = "PAL-M", | ||
545 | .clock = 107520, | ||
546 | .refresh = 29970, | ||
547 | .oversample = TV_OVERSAMPLE_8X, | ||
548 | .component_only = 0, | ||
549 | |||
550 | /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */ | ||
551 | .hsync_end = 64, .hblank_end = 124, | ||
552 | .hblank_start = 836, .htotal = 857, | ||
553 | |||
554 | .progressive = false, .trilevel_sync = false, | ||
555 | |||
556 | .vsync_start_f1 = 6, .vsync_start_f2 = 7, | ||
557 | .vsync_len = 6, | ||
558 | |||
559 | .veq_ena = true, .veq_start_f1 = 0, | ||
560 | .veq_start_f2 = 1, .veq_len = 18, | ||
561 | |||
562 | .vi_end_f1 = 20, .vi_end_f2 = 21, | ||
563 | .nbr_end = 240, | ||
564 | |||
565 | .burst_ena = true, | ||
566 | .hburst_start = 72, .hburst_len = 34, | ||
567 | .vburst_start_f1 = 9, .vburst_end_f1 = 240, | ||
568 | .vburst_start_f2 = 10, .vburst_end_f2 = 240, | ||
569 | .vburst_start_f3 = 9, .vburst_end_f3 = 240, | ||
570 | .vburst_start_f4 = 10, .vburst_end_f4 = 240, | ||
571 | |||
572 | /* desired 3.5800000 actual 3.5800000 clock 107.52 */ | ||
573 | .dda1_inc = 136, | ||
574 | .dda2_inc = 7624, .dda2_size = 20013, | ||
575 | .dda3_inc = 0, .dda3_size = 0, | ||
576 | .sc_reset = TV_SC_RESET_EVERY_4, | ||
577 | .pal_burst = false, | ||
578 | |||
579 | .composite_levels = &pal_m_levels_composite, | ||
580 | .composite_color = &pal_m_csc_composite, | ||
581 | .svideo_levels = &pal_m_levels_svideo, | ||
582 | .svideo_color = &pal_m_csc_svideo, | ||
583 | |||
584 | .filter_table = filter_table, | ||
585 | }, | ||
586 | { | ||
587 | /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */ | ||
588 | .name = "PAL-N", | ||
589 | .clock = 107520, | ||
590 | .refresh = 25000, | ||
591 | .oversample = TV_OVERSAMPLE_8X, | ||
592 | .component_only = 0, | ||
593 | |||
594 | .hsync_end = 64, .hblank_end = 128, | ||
595 | .hblank_start = 844, .htotal = 863, | ||
596 | |||
597 | .progressive = false, .trilevel_sync = false, | ||
598 | |||
599 | |||
600 | .vsync_start_f1 = 6, .vsync_start_f2 = 7, | ||
601 | .vsync_len = 6, | ||
602 | |||
603 | .veq_ena = true, .veq_start_f1 = 0, | ||
604 | .veq_start_f2 = 1, .veq_len = 18, | ||
605 | |||
606 | .vi_end_f1 = 24, .vi_end_f2 = 25, | ||
607 | .nbr_end = 286, | ||
608 | |||
609 | .burst_ena = true, | ||
610 | .hburst_start = 73, .hburst_len = 34, | ||
611 | .vburst_start_f1 = 8, .vburst_end_f1 = 285, | ||
612 | .vburst_start_f2 = 8, .vburst_end_f2 = 286, | ||
613 | .vburst_start_f3 = 9, .vburst_end_f3 = 286, | ||
614 | .vburst_start_f4 = 9, .vburst_end_f4 = 285, | ||
615 | |||
616 | |||
617 | /* desired 4.4336180 actual 4.4336180 clock 107.52 */ | ||
618 | .dda1_inc = 168, | ||
619 | .dda2_inc = 18557, .dda2_size = 20625, | ||
620 | .dda3_inc = 0, .dda3_size = 0, | ||
621 | .sc_reset = TV_SC_RESET_EVERY_8, | ||
622 | .pal_burst = true, | ||
623 | |||
624 | .composite_levels = &pal_n_levels_composite, | ||
625 | .composite_color = &pal_n_csc_composite, | ||
626 | .svideo_levels = &pal_n_levels_svideo, | ||
627 | .svideo_color = &pal_n_csc_svideo, | ||
628 | |||
629 | .filter_table = filter_table, | ||
630 | }, | ||
631 | { | ||
632 | /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */ | ||
633 | .name = "PAL", | ||
634 | .clock = 107520, | ||
635 | .refresh = 25000, | ||
636 | .oversample = TV_OVERSAMPLE_8X, | ||
637 | .component_only = 0, | ||
638 | |||
639 | .hsync_end = 64, .hblank_end = 128, | ||
640 | .hblank_start = 844, .htotal = 863, | ||
641 | |||
642 | .progressive = false, .trilevel_sync = false, | ||
643 | |||
644 | .vsync_start_f1 = 5, .vsync_start_f2 = 6, | ||
645 | .vsync_len = 5, | ||
646 | |||
647 | .veq_ena = true, .veq_start_f1 = 0, | ||
648 | .veq_start_f2 = 1, .veq_len = 15, | ||
649 | |||
650 | .vi_end_f1 = 24, .vi_end_f2 = 25, | ||
651 | .nbr_end = 286, | ||
652 | |||
653 | .burst_ena = true, | ||
654 | .hburst_start = 73, .hburst_len = 32, | ||
655 | .vburst_start_f1 = 8, .vburst_end_f1 = 285, | ||
656 | .vburst_start_f2 = 8, .vburst_end_f2 = 286, | ||
657 | .vburst_start_f3 = 9, .vburst_end_f3 = 286, | ||
658 | .vburst_start_f4 = 9, .vburst_end_f4 = 285, | ||
659 | |||
660 | /* desired 4.4336180 actual 4.4336180 clock 107.52 */ | ||
661 | .dda1_inc = 168, | ||
662 | .dda2_inc = 18557, .dda2_size = 20625, | ||
663 | .dda3_inc = 0, .dda3_size = 0, | ||
664 | .sc_reset = TV_SC_RESET_EVERY_8, | ||
665 | .pal_burst = true, | ||
666 | |||
667 | .composite_levels = &pal_levels_composite, | ||
668 | .composite_color = &pal_csc_composite, | ||
669 | .svideo_levels = &pal_levels_svideo, | ||
670 | .svideo_color = &pal_csc_svideo, | ||
671 | |||
672 | .filter_table = filter_table, | ||
673 | }, | ||
674 | { | ||
675 | .name = "480p@59.94Hz", | ||
676 | .clock = 107520, | ||
677 | .refresh = 59940, | ||
678 | .oversample = TV_OVERSAMPLE_4X, | ||
679 | .component_only = 1, | ||
680 | |||
681 | .hsync_end = 64, .hblank_end = 122, | ||
682 | .hblank_start = 842, .htotal = 857, | ||
683 | |||
684 | .progressive = true,.trilevel_sync = false, | ||
685 | |||
686 | .vsync_start_f1 = 12, .vsync_start_f2 = 12, | ||
687 | .vsync_len = 12, | ||
688 | |||
689 | .veq_ena = false, | ||
690 | |||
691 | .vi_end_f1 = 44, .vi_end_f2 = 44, | ||
692 | .nbr_end = 496, | ||
693 | |||
694 | .burst_ena = false, | ||
695 | |||
696 | .filter_table = filter_table, | ||
697 | }, | ||
698 | { | ||
699 | .name = "480p@60Hz", | ||
700 | .clock = 107520, | ||
701 | .refresh = 60000, | ||
702 | .oversample = TV_OVERSAMPLE_4X, | ||
703 | .component_only = 1, | ||
704 | |||
705 | .hsync_end = 64, .hblank_end = 122, | ||
706 | .hblank_start = 842, .htotal = 856, | ||
707 | |||
708 | .progressive = true,.trilevel_sync = false, | ||
709 | |||
710 | .vsync_start_f1 = 12, .vsync_start_f2 = 12, | ||
711 | .vsync_len = 12, | ||
712 | |||
713 | .veq_ena = false, | ||
714 | |||
715 | .vi_end_f1 = 44, .vi_end_f2 = 44, | ||
716 | .nbr_end = 496, | ||
717 | |||
718 | .burst_ena = false, | ||
719 | |||
720 | .filter_table = filter_table, | ||
721 | }, | ||
722 | { | ||
723 | .name = "576p", | ||
724 | .clock = 107520, | ||
725 | .refresh = 50000, | ||
726 | .oversample = TV_OVERSAMPLE_4X, | ||
727 | .component_only = 1, | ||
728 | |||
729 | .hsync_end = 64, .hblank_end = 139, | ||
730 | .hblank_start = 859, .htotal = 863, | ||
731 | |||
732 | .progressive = true, .trilevel_sync = false, | ||
733 | |||
734 | .vsync_start_f1 = 10, .vsync_start_f2 = 10, | ||
735 | .vsync_len = 10, | ||
736 | |||
737 | .veq_ena = false, | ||
738 | |||
739 | .vi_end_f1 = 48, .vi_end_f2 = 48, | ||
740 | .nbr_end = 575, | ||
741 | |||
742 | .burst_ena = false, | ||
743 | |||
744 | .filter_table = filter_table, | ||
745 | }, | ||
746 | { | ||
747 | .name = "720p@60Hz", | ||
748 | .clock = 148800, | ||
749 | .refresh = 60000, | ||
750 | .oversample = TV_OVERSAMPLE_2X, | ||
751 | .component_only = 1, | ||
752 | |||
753 | .hsync_end = 80, .hblank_end = 300, | ||
754 | .hblank_start = 1580, .htotal = 1649, | ||
755 | |||
756 | .progressive = true, .trilevel_sync = true, | ||
757 | |||
758 | .vsync_start_f1 = 10, .vsync_start_f2 = 10, | ||
759 | .vsync_len = 10, | ||
760 | |||
761 | .veq_ena = false, | ||
762 | |||
763 | .vi_end_f1 = 29, .vi_end_f2 = 29, | ||
764 | .nbr_end = 719, | ||
765 | |||
766 | .burst_ena = false, | ||
767 | |||
768 | .filter_table = filter_table, | ||
769 | }, | ||
770 | { | ||
771 | .name = "720p@59.94Hz", | ||
772 | .clock = 148800, | ||
773 | .refresh = 59940, | ||
774 | .oversample = TV_OVERSAMPLE_2X, | ||
775 | .component_only = 1, | ||
776 | |||
777 | .hsync_end = 80, .hblank_end = 300, | ||
778 | .hblank_start = 1580, .htotal = 1651, | ||
779 | |||
780 | .progressive = true, .trilevel_sync = true, | ||
781 | |||
782 | .vsync_start_f1 = 10, .vsync_start_f2 = 10, | ||
783 | .vsync_len = 10, | ||
784 | |||
785 | .veq_ena = false, | ||
786 | |||
787 | .vi_end_f1 = 29, .vi_end_f2 = 29, | ||
788 | .nbr_end = 719, | ||
789 | |||
790 | .burst_ena = false, | ||
791 | |||
792 | .filter_table = filter_table, | ||
793 | }, | ||
794 | { | ||
795 | .name = "720p@50Hz", | ||
796 | .clock = 148800, | ||
797 | .refresh = 50000, | ||
798 | .oversample = TV_OVERSAMPLE_2X, | ||
799 | .component_only = 1, | ||
800 | |||
801 | .hsync_end = 80, .hblank_end = 300, | ||
802 | .hblank_start = 1580, .htotal = 1979, | ||
803 | |||
804 | .progressive = true, .trilevel_sync = true, | ||
805 | |||
806 | .vsync_start_f1 = 10, .vsync_start_f2 = 10, | ||
807 | .vsync_len = 10, | ||
808 | |||
809 | .veq_ena = false, | ||
810 | |||
811 | .vi_end_f1 = 29, .vi_end_f2 = 29, | ||
812 | .nbr_end = 719, | ||
813 | |||
814 | .burst_ena = false, | ||
815 | |||
816 | .filter_table = filter_table, | ||
817 | .max_srcw = 800 | ||
818 | }, | ||
819 | { | ||
820 | .name = "1080i@50Hz", | ||
821 | .clock = 148800, | ||
822 | .refresh = 25000, | ||
823 | .oversample = TV_OVERSAMPLE_2X, | ||
824 | .component_only = 1, | ||
825 | |||
826 | .hsync_end = 88, .hblank_end = 235, | ||
827 | .hblank_start = 2155, .htotal = 2639, | ||
828 | |||
829 | .progressive = false, .trilevel_sync = true, | ||
830 | |||
831 | .vsync_start_f1 = 4, .vsync_start_f2 = 5, | ||
832 | .vsync_len = 10, | ||
833 | |||
834 | .veq_ena = true, .veq_start_f1 = 4, | ||
835 | .veq_start_f2 = 4, .veq_len = 10, | ||
836 | |||
837 | |||
838 | .vi_end_f1 = 21, .vi_end_f2 = 22, | ||
839 | .nbr_end = 539, | ||
840 | |||
841 | .burst_ena = false, | ||
842 | |||
843 | .filter_table = filter_table, | ||
844 | }, | ||
845 | { | ||
846 | .name = "1080i@60Hz", | ||
847 | .clock = 148800, | ||
848 | .refresh = 30000, | ||
849 | .oversample = TV_OVERSAMPLE_2X, | ||
850 | .component_only = 1, | ||
851 | |||
852 | .hsync_end = 88, .hblank_end = 235, | ||
853 | .hblank_start = 2155, .htotal = 2199, | ||
854 | |||
855 | .progressive = false, .trilevel_sync = true, | ||
856 | |||
857 | .vsync_start_f1 = 4, .vsync_start_f2 = 5, | ||
858 | .vsync_len = 10, | ||
859 | |||
860 | .veq_ena = true, .veq_start_f1 = 4, | ||
861 | .veq_start_f2 = 4, .veq_len = 10, | ||
862 | |||
863 | |||
864 | .vi_end_f1 = 21, .vi_end_f2 = 22, | ||
865 | .nbr_end = 539, | ||
866 | |||
867 | .burst_ena = false, | ||
868 | |||
869 | .filter_table = filter_table, | ||
870 | }, | ||
871 | { | ||
872 | .name = "1080i@59.94Hz", | ||
873 | .clock = 148800, | ||
874 | .refresh = 29970, | ||
875 | .oversample = TV_OVERSAMPLE_2X, | ||
876 | .component_only = 1, | ||
877 | |||
878 | .hsync_end = 88, .hblank_end = 235, | ||
879 | .hblank_start = 2155, .htotal = 2200, | ||
880 | |||
881 | .progressive = false, .trilevel_sync = true, | ||
882 | |||
883 | .vsync_start_f1 = 4, .vsync_start_f2 = 5, | ||
884 | .vsync_len = 10, | ||
885 | |||
886 | .veq_ena = true, .veq_start_f1 = 4, | ||
887 | .veq_start_f2 = 4, .veq_len = 10, | ||
888 | |||
889 | |||
890 | .vi_end_f1 = 21, .vi_end_f2 = 22, | ||
891 | .nbr_end = 539, | ||
892 | |||
893 | .burst_ena = false, | ||
894 | |||
895 | .filter_table = filter_table, | ||
896 | }, | ||
897 | }; | ||
898 | |||
899 | #define NUM_TV_MODES sizeof(tv_modes) / sizeof (tv_modes[0]) | ||
900 | |||
901 | static void | ||
902 | intel_tv_dpms(struct drm_encoder *encoder, int mode) | ||
903 | { | ||
904 | struct drm_device *dev = encoder->dev; | ||
905 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
906 | |||
907 | switch(mode) { | ||
908 | case DRM_MODE_DPMS_ON: | ||
909 | I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE); | ||
910 | break; | ||
911 | case DRM_MODE_DPMS_STANDBY: | ||
912 | case DRM_MODE_DPMS_SUSPEND: | ||
913 | case DRM_MODE_DPMS_OFF: | ||
914 | I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE); | ||
915 | break; | ||
916 | } | ||
917 | } | ||
918 | |||
919 | static void | ||
920 | intel_tv_save(struct drm_connector *connector) | ||
921 | { | ||
922 | struct drm_device *dev = connector->dev; | ||
923 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
924 | struct intel_output *intel_output = to_intel_output(connector); | ||
925 | struct intel_tv_priv *tv_priv = intel_output->dev_priv; | ||
926 | int i; | ||
927 | |||
928 | tv_priv->save_TV_H_CTL_1 = I915_READ(TV_H_CTL_1); | ||
929 | tv_priv->save_TV_H_CTL_2 = I915_READ(TV_H_CTL_2); | ||
930 | tv_priv->save_TV_H_CTL_3 = I915_READ(TV_H_CTL_3); | ||
931 | tv_priv->save_TV_V_CTL_1 = I915_READ(TV_V_CTL_1); | ||
932 | tv_priv->save_TV_V_CTL_2 = I915_READ(TV_V_CTL_2); | ||
933 | tv_priv->save_TV_V_CTL_3 = I915_READ(TV_V_CTL_3); | ||
934 | tv_priv->save_TV_V_CTL_4 = I915_READ(TV_V_CTL_4); | ||
935 | tv_priv->save_TV_V_CTL_5 = I915_READ(TV_V_CTL_5); | ||
936 | tv_priv->save_TV_V_CTL_6 = I915_READ(TV_V_CTL_6); | ||
937 | tv_priv->save_TV_V_CTL_7 = I915_READ(TV_V_CTL_7); | ||
938 | tv_priv->save_TV_SC_CTL_1 = I915_READ(TV_SC_CTL_1); | ||
939 | tv_priv->save_TV_SC_CTL_2 = I915_READ(TV_SC_CTL_2); | ||
940 | tv_priv->save_TV_SC_CTL_3 = I915_READ(TV_SC_CTL_3); | ||
941 | |||
942 | tv_priv->save_TV_CSC_Y = I915_READ(TV_CSC_Y); | ||
943 | tv_priv->save_TV_CSC_Y2 = I915_READ(TV_CSC_Y2); | ||
944 | tv_priv->save_TV_CSC_U = I915_READ(TV_CSC_U); | ||
945 | tv_priv->save_TV_CSC_U2 = I915_READ(TV_CSC_U2); | ||
946 | tv_priv->save_TV_CSC_V = I915_READ(TV_CSC_V); | ||
947 | tv_priv->save_TV_CSC_V2 = I915_READ(TV_CSC_V2); | ||
948 | tv_priv->save_TV_CLR_KNOBS = I915_READ(TV_CLR_KNOBS); | ||
949 | tv_priv->save_TV_CLR_LEVEL = I915_READ(TV_CLR_LEVEL); | ||
950 | tv_priv->save_TV_WIN_POS = I915_READ(TV_WIN_POS); | ||
951 | tv_priv->save_TV_WIN_SIZE = I915_READ(TV_WIN_SIZE); | ||
952 | tv_priv->save_TV_FILTER_CTL_1 = I915_READ(TV_FILTER_CTL_1); | ||
953 | tv_priv->save_TV_FILTER_CTL_2 = I915_READ(TV_FILTER_CTL_2); | ||
954 | tv_priv->save_TV_FILTER_CTL_3 = I915_READ(TV_FILTER_CTL_3); | ||
955 | |||
956 | for (i = 0; i < 60; i++) | ||
957 | tv_priv->save_TV_H_LUMA[i] = I915_READ(TV_H_LUMA_0 + (i <<2)); | ||
958 | for (i = 0; i < 60; i++) | ||
959 | tv_priv->save_TV_H_CHROMA[i] = I915_READ(TV_H_CHROMA_0 + (i <<2)); | ||
960 | for (i = 0; i < 43; i++) | ||
961 | tv_priv->save_TV_V_LUMA[i] = I915_READ(TV_V_LUMA_0 + (i <<2)); | ||
962 | for (i = 0; i < 43; i++) | ||
963 | tv_priv->save_TV_V_CHROMA[i] = I915_READ(TV_V_CHROMA_0 + (i <<2)); | ||
964 | |||
965 | tv_priv->save_TV_DAC = I915_READ(TV_DAC); | ||
966 | tv_priv->save_TV_CTL = I915_READ(TV_CTL); | ||
967 | } | ||
968 | |||
969 | static void | ||
970 | intel_tv_restore(struct drm_connector *connector) | ||
971 | { | ||
972 | struct drm_device *dev = connector->dev; | ||
973 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
974 | struct intel_output *intel_output = to_intel_output(connector); | ||
975 | struct intel_tv_priv *tv_priv = intel_output->dev_priv; | ||
976 | struct drm_crtc *crtc = connector->encoder->crtc; | ||
977 | struct intel_crtc *intel_crtc; | ||
978 | int i; | ||
979 | |||
980 | /* FIXME: No CRTC? */ | ||
981 | if (!crtc) | ||
982 | return; | ||
983 | |||
984 | intel_crtc = to_intel_crtc(crtc); | ||
985 | I915_WRITE(TV_H_CTL_1, tv_priv->save_TV_H_CTL_1); | ||
986 | I915_WRITE(TV_H_CTL_2, tv_priv->save_TV_H_CTL_2); | ||
987 | I915_WRITE(TV_H_CTL_3, tv_priv->save_TV_H_CTL_3); | ||
988 | I915_WRITE(TV_V_CTL_1, tv_priv->save_TV_V_CTL_1); | ||
989 | I915_WRITE(TV_V_CTL_2, tv_priv->save_TV_V_CTL_2); | ||
990 | I915_WRITE(TV_V_CTL_3, tv_priv->save_TV_V_CTL_3); | ||
991 | I915_WRITE(TV_V_CTL_4, tv_priv->save_TV_V_CTL_4); | ||
992 | I915_WRITE(TV_V_CTL_5, tv_priv->save_TV_V_CTL_5); | ||
993 | I915_WRITE(TV_V_CTL_6, tv_priv->save_TV_V_CTL_6); | ||
994 | I915_WRITE(TV_V_CTL_7, tv_priv->save_TV_V_CTL_7); | ||
995 | I915_WRITE(TV_SC_CTL_1, tv_priv->save_TV_SC_CTL_1); | ||
996 | I915_WRITE(TV_SC_CTL_2, tv_priv->save_TV_SC_CTL_2); | ||
997 | I915_WRITE(TV_SC_CTL_3, tv_priv->save_TV_SC_CTL_3); | ||
998 | |||
999 | I915_WRITE(TV_CSC_Y, tv_priv->save_TV_CSC_Y); | ||
1000 | I915_WRITE(TV_CSC_Y2, tv_priv->save_TV_CSC_Y2); | ||
1001 | I915_WRITE(TV_CSC_U, tv_priv->save_TV_CSC_U); | ||
1002 | I915_WRITE(TV_CSC_U2, tv_priv->save_TV_CSC_U2); | ||
1003 | I915_WRITE(TV_CSC_V, tv_priv->save_TV_CSC_V); | ||
1004 | I915_WRITE(TV_CSC_V2, tv_priv->save_TV_CSC_V2); | ||
1005 | I915_WRITE(TV_CLR_KNOBS, tv_priv->save_TV_CLR_KNOBS); | ||
1006 | I915_WRITE(TV_CLR_LEVEL, tv_priv->save_TV_CLR_LEVEL); | ||
1007 | |||
1008 | { | ||
1009 | int pipeconf_reg = (intel_crtc->pipe == 0) ? | ||
1010 | PIPEACONF : PIPEBCONF; | ||
1011 | int dspcntr_reg = (intel_crtc->plane == 0) ? | ||
1012 | DSPACNTR : DSPBCNTR; | ||
1013 | int pipeconf = I915_READ(pipeconf_reg); | ||
1014 | int dspcntr = I915_READ(dspcntr_reg); | ||
1015 | int dspbase_reg = (intel_crtc->plane == 0) ? | ||
1016 | DSPAADDR : DSPBADDR; | ||
1017 | /* Pipe must be off here */ | ||
1018 | I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE); | ||
1019 | /* Flush the plane changes */ | ||
1020 | I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); | ||
1021 | |||
1022 | if (!IS_I9XX(dev)) { | ||
1023 | /* Wait for vblank for the disable to take effect */ | ||
1024 | intel_wait_for_vblank(dev); | ||
1025 | } | ||
1026 | |||
1027 | I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE); | ||
1028 | /* Wait for vblank for the disable to take effect. */ | ||
1029 | intel_wait_for_vblank(dev); | ||
1030 | |||
1031 | /* Filter ctl must be set before TV_WIN_SIZE */ | ||
1032 | I915_WRITE(TV_FILTER_CTL_1, tv_priv->save_TV_FILTER_CTL_1); | ||
1033 | I915_WRITE(TV_FILTER_CTL_2, tv_priv->save_TV_FILTER_CTL_2); | ||
1034 | I915_WRITE(TV_FILTER_CTL_3, tv_priv->save_TV_FILTER_CTL_3); | ||
1035 | I915_WRITE(TV_WIN_POS, tv_priv->save_TV_WIN_POS); | ||
1036 | I915_WRITE(TV_WIN_SIZE, tv_priv->save_TV_WIN_SIZE); | ||
1037 | I915_WRITE(pipeconf_reg, pipeconf); | ||
1038 | I915_WRITE(dspcntr_reg, dspcntr); | ||
1039 | /* Flush the plane changes */ | ||
1040 | I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); | ||
1041 | } | ||
1042 | |||
1043 | for (i = 0; i < 60; i++) | ||
1044 | I915_WRITE(TV_H_LUMA_0 + (i <<2), tv_priv->save_TV_H_LUMA[i]); | ||
1045 | for (i = 0; i < 60; i++) | ||
1046 | I915_WRITE(TV_H_CHROMA_0 + (i <<2), tv_priv->save_TV_H_CHROMA[i]); | ||
1047 | for (i = 0; i < 43; i++) | ||
1048 | I915_WRITE(TV_V_LUMA_0 + (i <<2), tv_priv->save_TV_V_LUMA[i]); | ||
1049 | for (i = 0; i < 43; i++) | ||
1050 | I915_WRITE(TV_V_CHROMA_0 + (i <<2), tv_priv->save_TV_V_CHROMA[i]); | ||
1051 | |||
1052 | I915_WRITE(TV_DAC, tv_priv->save_TV_DAC); | ||
1053 | I915_WRITE(TV_CTL, tv_priv->save_TV_CTL); | ||
1054 | } | ||
1055 | |||
1056 | static const struct tv_mode * | ||
1057 | intel_tv_mode_lookup (char *tv_format) | ||
1058 | { | ||
1059 | int i; | ||
1060 | |||
1061 | for (i = 0; i < sizeof(tv_modes) / sizeof (tv_modes[0]); i++) { | ||
1062 | const struct tv_mode *tv_mode = &tv_modes[i]; | ||
1063 | |||
1064 | if (!strcmp(tv_format, tv_mode->name)) | ||
1065 | return tv_mode; | ||
1066 | } | ||
1067 | return NULL; | ||
1068 | } | ||
1069 | |||
1070 | static const struct tv_mode * | ||
1071 | intel_tv_mode_find (struct intel_output *intel_output) | ||
1072 | { | ||
1073 | struct intel_tv_priv *tv_priv = intel_output->dev_priv; | ||
1074 | |||
1075 | return intel_tv_mode_lookup(tv_priv->tv_format); | ||
1076 | } | ||
1077 | |||
1078 | static enum drm_mode_status | ||
1079 | intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) | ||
1080 | { | ||
1081 | struct intel_output *intel_output = to_intel_output(connector); | ||
1082 | const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output); | ||
1083 | |||
1084 | /* Ensure TV refresh is close to desired refresh */ | ||
1085 | if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode)) < 1) | ||
1086 | return MODE_OK; | ||
1087 | return MODE_CLOCK_RANGE; | ||
1088 | } | ||
1089 | |||
1090 | |||
1091 | static bool | ||
1092 | intel_tv_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, | ||
1093 | struct drm_display_mode *adjusted_mode) | ||
1094 | { | ||
1095 | struct drm_device *dev = encoder->dev; | ||
1096 | struct drm_mode_config *drm_config = &dev->mode_config; | ||
1097 | struct intel_output *intel_output = enc_to_intel_output(encoder); | ||
1098 | const struct tv_mode *tv_mode = intel_tv_mode_find (intel_output); | ||
1099 | struct drm_encoder *other_encoder; | ||
1100 | |||
1101 | if (!tv_mode) | ||
1102 | return false; | ||
1103 | |||
1104 | /* FIXME: lock encoder list */ | ||
1105 | list_for_each_entry(other_encoder, &drm_config->encoder_list, head) { | ||
1106 | if (other_encoder != encoder && | ||
1107 | other_encoder->crtc == encoder->crtc) | ||
1108 | return false; | ||
1109 | } | ||
1110 | |||
1111 | adjusted_mode->clock = tv_mode->clock; | ||
1112 | return true; | ||
1113 | } | ||
1114 | |||
1115 | static void | ||
1116 | intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, | ||
1117 | struct drm_display_mode *adjusted_mode) | ||
1118 | { | ||
1119 | struct drm_device *dev = encoder->dev; | ||
1120 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
1121 | struct drm_crtc *crtc = encoder->crtc; | ||
1122 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
1123 | struct intel_output *intel_output = enc_to_intel_output(encoder); | ||
1124 | struct intel_tv_priv *tv_priv = intel_output->dev_priv; | ||
1125 | const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output); | ||
1126 | u32 tv_ctl; | ||
1127 | u32 hctl1, hctl2, hctl3; | ||
1128 | u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7; | ||
1129 | u32 scctl1, scctl2, scctl3; | ||
1130 | int i, j; | ||
1131 | const struct video_levels *video_levels; | ||
1132 | const struct color_conversion *color_conversion; | ||
1133 | bool burst_ena; | ||
1134 | |||
1135 | if (!tv_mode) | ||
1136 | return; /* can't happen (mode_prepare prevents this) */ | ||
1137 | |||
1138 | tv_ctl = 0; | ||
1139 | |||
1140 | switch (tv_priv->type) { | ||
1141 | default: | ||
1142 | case DRM_MODE_CONNECTOR_Unknown: | ||
1143 | case DRM_MODE_CONNECTOR_Composite: | ||
1144 | tv_ctl |= TV_ENC_OUTPUT_COMPOSITE; | ||
1145 | video_levels = tv_mode->composite_levels; | ||
1146 | color_conversion = tv_mode->composite_color; | ||
1147 | burst_ena = tv_mode->burst_ena; | ||
1148 | break; | ||
1149 | case DRM_MODE_CONNECTOR_Component: | ||
1150 | tv_ctl |= TV_ENC_OUTPUT_COMPONENT; | ||
1151 | video_levels = &component_levels; | ||
1152 | if (tv_mode->burst_ena) | ||
1153 | color_conversion = &sdtv_csc_yprpb; | ||
1154 | else | ||
1155 | color_conversion = &hdtv_csc_yprpb; | ||
1156 | burst_ena = false; | ||
1157 | break; | ||
1158 | case DRM_MODE_CONNECTOR_SVIDEO: | ||
1159 | tv_ctl |= TV_ENC_OUTPUT_SVIDEO; | ||
1160 | video_levels = tv_mode->svideo_levels; | ||
1161 | color_conversion = tv_mode->svideo_color; | ||
1162 | burst_ena = tv_mode->burst_ena; | ||
1163 | break; | ||
1164 | } | ||
1165 | hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) | | ||
1166 | (tv_mode->htotal << TV_HTOTAL_SHIFT); | ||
1167 | |||
1168 | hctl2 = (tv_mode->hburst_start << 16) | | ||
1169 | (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT); | ||
1170 | |||
1171 | if (burst_ena) | ||
1172 | hctl2 |= TV_BURST_ENA; | ||
1173 | |||
1174 | hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) | | ||
1175 | (tv_mode->hblank_end << TV_HBLANK_END_SHIFT); | ||
1176 | |||
1177 | vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) | | ||
1178 | (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) | | ||
1179 | (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT); | ||
1180 | |||
1181 | vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) | | ||
1182 | (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) | | ||
1183 | (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT); | ||
1184 | |||
1185 | vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) | | ||
1186 | (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) | | ||
1187 | (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT); | ||
1188 | |||
1189 | if (tv_mode->veq_ena) | ||
1190 | vctl3 |= TV_EQUAL_ENA; | ||
1191 | |||
1192 | vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) | | ||
1193 | (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT); | ||
1194 | |||
1195 | vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) | | ||
1196 | (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT); | ||
1197 | |||
1198 | vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) | | ||
1199 | (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT); | ||
1200 | |||
1201 | vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) | | ||
1202 | (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT); | ||
1203 | |||
1204 | if (intel_crtc->pipe == 1) | ||
1205 | tv_ctl |= TV_ENC_PIPEB_SELECT; | ||
1206 | tv_ctl |= tv_mode->oversample; | ||
1207 | |||
1208 | if (tv_mode->progressive) | ||
1209 | tv_ctl |= TV_PROGRESSIVE; | ||
1210 | if (tv_mode->trilevel_sync) | ||
1211 | tv_ctl |= TV_TRILEVEL_SYNC; | ||
1212 | if (tv_mode->pal_burst) | ||
1213 | tv_ctl |= TV_PAL_BURST; | ||
1214 | scctl1 = 0; | ||
1215 | /* dda1 implies valid video levels */ | ||
1216 | if (tv_mode->dda1_inc) { | ||
1217 | scctl1 |= TV_SC_DDA1_EN; | ||
1218 | scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT; | ||
1219 | } | ||
1220 | |||
1221 | if (tv_mode->dda2_inc) | ||
1222 | scctl1 |= TV_SC_DDA2_EN; | ||
1223 | |||
1224 | if (tv_mode->dda3_inc) | ||
1225 | scctl1 |= TV_SC_DDA3_EN; | ||
1226 | |||
1227 | scctl1 |= tv_mode->sc_reset; | ||
1228 | scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT; | ||
1229 | |||
1230 | scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT | | ||
1231 | tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT; | ||
1232 | |||
1233 | scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT | | ||
1234 | tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT; | ||
1235 | |||
1236 | /* Enable two fixes for the chips that need them. */ | ||
1237 | if (dev->pci_device < 0x2772) | ||
1238 | tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX; | ||
1239 | |||
1240 | I915_WRITE(TV_H_CTL_1, hctl1); | ||
1241 | I915_WRITE(TV_H_CTL_2, hctl2); | ||
1242 | I915_WRITE(TV_H_CTL_3, hctl3); | ||
1243 | I915_WRITE(TV_V_CTL_1, vctl1); | ||
1244 | I915_WRITE(TV_V_CTL_2, vctl2); | ||
1245 | I915_WRITE(TV_V_CTL_3, vctl3); | ||
1246 | I915_WRITE(TV_V_CTL_4, vctl4); | ||
1247 | I915_WRITE(TV_V_CTL_5, vctl5); | ||
1248 | I915_WRITE(TV_V_CTL_6, vctl6); | ||
1249 | I915_WRITE(TV_V_CTL_7, vctl7); | ||
1250 | I915_WRITE(TV_SC_CTL_1, scctl1); | ||
1251 | I915_WRITE(TV_SC_CTL_2, scctl2); | ||
1252 | I915_WRITE(TV_SC_CTL_3, scctl3); | ||
1253 | |||
1254 | if (color_conversion) { | ||
1255 | I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) | | ||
1256 | color_conversion->gy); | ||
1257 | I915_WRITE(TV_CSC_Y2,(color_conversion->by << 16) | | ||
1258 | color_conversion->ay); | ||
1259 | I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) | | ||
1260 | color_conversion->gu); | ||
1261 | I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) | | ||
1262 | color_conversion->au); | ||
1263 | I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) | | ||
1264 | color_conversion->gv); | ||
1265 | I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) | | ||
1266 | color_conversion->av); | ||
1267 | } | ||
1268 | |||
1269 | I915_WRITE(TV_CLR_KNOBS, 0x00606000); | ||
1270 | if (video_levels) | ||
1271 | I915_WRITE(TV_CLR_LEVEL, | ||
1272 | ((video_levels->black << TV_BLACK_LEVEL_SHIFT) | | ||
1273 | (video_levels->blank << TV_BLANK_LEVEL_SHIFT))); | ||
1274 | { | ||
1275 | int pipeconf_reg = (intel_crtc->pipe == 0) ? | ||
1276 | PIPEACONF : PIPEBCONF; | ||
1277 | int dspcntr_reg = (intel_crtc->plane == 0) ? | ||
1278 | DSPACNTR : DSPBCNTR; | ||
1279 | int pipeconf = I915_READ(pipeconf_reg); | ||
1280 | int dspcntr = I915_READ(dspcntr_reg); | ||
1281 | int dspbase_reg = (intel_crtc->plane == 0) ? | ||
1282 | DSPAADDR : DSPBADDR; | ||
1283 | int xpos = 0x0, ypos = 0x0; | ||
1284 | unsigned int xsize, ysize; | ||
1285 | /* Pipe must be off here */ | ||
1286 | I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE); | ||
1287 | /* Flush the plane changes */ | ||
1288 | I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); | ||
1289 | |||
1290 | /* Wait for vblank for the disable to take effect */ | ||
1291 | if (!IS_I9XX(dev)) | ||
1292 | intel_wait_for_vblank(dev); | ||
1293 | |||
1294 | I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE); | ||
1295 | /* Wait for vblank for the disable to take effect. */ | ||
1296 | intel_wait_for_vblank(dev); | ||
1297 | |||
1298 | /* Filter ctl must be set before TV_WIN_SIZE */ | ||
1299 | I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE); | ||
1300 | xsize = tv_mode->hblank_start - tv_mode->hblank_end; | ||
1301 | if (tv_mode->progressive) | ||
1302 | ysize = tv_mode->nbr_end + 1; | ||
1303 | else | ||
1304 | ysize = 2*tv_mode->nbr_end + 1; | ||
1305 | |||
1306 | xpos += tv_priv->margin[TV_MARGIN_LEFT]; | ||
1307 | ypos += tv_priv->margin[TV_MARGIN_TOP]; | ||
1308 | xsize -= (tv_priv->margin[TV_MARGIN_LEFT] + | ||
1309 | tv_priv->margin[TV_MARGIN_RIGHT]); | ||
1310 | ysize -= (tv_priv->margin[TV_MARGIN_TOP] + | ||
1311 | tv_priv->margin[TV_MARGIN_BOTTOM]); | ||
1312 | I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos); | ||
1313 | I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize); | ||
1314 | |||
1315 | I915_WRITE(pipeconf_reg, pipeconf); | ||
1316 | I915_WRITE(dspcntr_reg, dspcntr); | ||
1317 | /* Flush the plane changes */ | ||
1318 | I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); | ||
1319 | } | ||
1320 | |||
1321 | j = 0; | ||
1322 | for (i = 0; i < 60; i++) | ||
1323 | I915_WRITE(TV_H_LUMA_0 + (i<<2), tv_mode->filter_table[j++]); | ||
1324 | for (i = 0; i < 60; i++) | ||
1325 | I915_WRITE(TV_H_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]); | ||
1326 | for (i = 0; i < 43; i++) | ||
1327 | I915_WRITE(TV_V_LUMA_0 + (i<<2), tv_mode->filter_table[j++]); | ||
1328 | for (i = 0; i < 43; i++) | ||
1329 | I915_WRITE(TV_V_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]); | ||
1330 | I915_WRITE(TV_DAC, 0); | ||
1331 | I915_WRITE(TV_CTL, tv_ctl); | ||
1332 | } | ||
1333 | |||
1334 | static const struct drm_display_mode reported_modes[] = { | ||
1335 | { | ||
1336 | .name = "NTSC 480i", | ||
1337 | .clock = 107520, | ||
1338 | .hdisplay = 1280, | ||
1339 | .hsync_start = 1368, | ||
1340 | .hsync_end = 1496, | ||
1341 | .htotal = 1712, | ||
1342 | |||
1343 | .vdisplay = 1024, | ||
1344 | .vsync_start = 1027, | ||
1345 | .vsync_end = 1034, | ||
1346 | .vtotal = 1104, | ||
1347 | .type = DRM_MODE_TYPE_DRIVER, | ||
1348 | }, | ||
1349 | }; | ||
1350 | |||
1351 | /** | ||
1352 | * Detects TV presence by checking for load. | ||
1353 | * | ||
1354 | * Requires that the current pipe's DPLL is active. | ||
1355 | |||
1356 | * \return true if TV is connected. | ||
1357 | * \return false if TV is disconnected. | ||
1358 | */ | ||
1359 | static int | ||
1360 | intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output) | ||
1361 | { | ||
1362 | struct drm_encoder *encoder = &intel_output->enc; | ||
1363 | struct drm_device *dev = encoder->dev; | ||
1364 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
1365 | unsigned long irqflags; | ||
1366 | u32 tv_ctl, save_tv_ctl; | ||
1367 | u32 tv_dac, save_tv_dac; | ||
1368 | int type = DRM_MODE_CONNECTOR_Unknown; | ||
1369 | |||
1370 | tv_dac = I915_READ(TV_DAC); | ||
1371 | |||
1372 | /* Disable TV interrupts around load detect or we'll recurse */ | ||
1373 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); | ||
1374 | i915_disable_pipestat(dev_priv, 0, PIPE_HOTPLUG_INTERRUPT_ENABLE | | ||
1375 | PIPE_HOTPLUG_TV_INTERRUPT_ENABLE); | ||
1376 | spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); | ||
1377 | |||
1378 | /* | ||
1379 | * Detect TV by polling) | ||
1380 | */ | ||
1381 | if (intel_output->load_detect_temp) { | ||
1382 | /* TV not currently running, prod it with destructive detect */ | ||
1383 | save_tv_dac = tv_dac; | ||
1384 | tv_ctl = I915_READ(TV_CTL); | ||
1385 | save_tv_ctl = tv_ctl; | ||
1386 | tv_ctl &= ~TV_ENC_ENABLE; | ||
1387 | tv_ctl &= ~TV_TEST_MODE_MASK; | ||
1388 | tv_ctl |= TV_TEST_MODE_MONITOR_DETECT; | ||
1389 | tv_dac &= ~TVDAC_SENSE_MASK; | ||
1390 | tv_dac |= (TVDAC_STATE_CHG_EN | | ||
1391 | TVDAC_A_SENSE_CTL | | ||
1392 | TVDAC_B_SENSE_CTL | | ||
1393 | TVDAC_C_SENSE_CTL | | ||
1394 | DAC_CTL_OVERRIDE | | ||
1395 | DAC_A_0_7_V | | ||
1396 | DAC_B_0_7_V | | ||
1397 | DAC_C_0_7_V); | ||
1398 | I915_WRITE(TV_CTL, tv_ctl); | ||
1399 | I915_WRITE(TV_DAC, tv_dac); | ||
1400 | intel_wait_for_vblank(dev); | ||
1401 | tv_dac = I915_READ(TV_DAC); | ||
1402 | I915_WRITE(TV_DAC, save_tv_dac); | ||
1403 | I915_WRITE(TV_CTL, save_tv_ctl); | ||
1404 | } | ||
1405 | /* | ||
1406 | * A B C | ||
1407 | * 0 1 1 Composite | ||
1408 | * 1 0 X svideo | ||
1409 | * 0 0 0 Component | ||
1410 | */ | ||
1411 | if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) { | ||
1412 | DRM_DEBUG("Detected Composite TV connection\n"); | ||
1413 | type = DRM_MODE_CONNECTOR_Composite; | ||
1414 | } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) { | ||
1415 | DRM_DEBUG("Detected S-Video TV connection\n"); | ||
1416 | type = DRM_MODE_CONNECTOR_SVIDEO; | ||
1417 | } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) { | ||
1418 | DRM_DEBUG("Detected Component TV connection\n"); | ||
1419 | type = DRM_MODE_CONNECTOR_Component; | ||
1420 | } else { | ||
1421 | DRM_DEBUG("No TV connection detected\n"); | ||
1422 | type = -1; | ||
1423 | } | ||
1424 | |||
1425 | /* Restore interrupt config */ | ||
1426 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); | ||
1427 | i915_enable_pipestat(dev_priv, 0, PIPE_HOTPLUG_INTERRUPT_ENABLE | | ||
1428 | PIPE_HOTPLUG_TV_INTERRUPT_ENABLE); | ||
1429 | spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags); | ||
1430 | |||
1431 | return type; | ||
1432 | } | ||
1433 | |||
1434 | /** | ||
1435 | * Detect the TV connection. | ||
1436 | * | ||
1437 | * Currently this always returns CONNECTOR_STATUS_UNKNOWN, as we need to be sure | ||
1438 | * we have a pipe programmed in order to probe the TV. | ||
1439 | */ | ||
1440 | static enum drm_connector_status | ||
1441 | intel_tv_detect(struct drm_connector *connector) | ||
1442 | { | ||
1443 | struct drm_crtc *crtc; | ||
1444 | struct drm_display_mode mode; | ||
1445 | struct intel_output *intel_output = to_intel_output(connector); | ||
1446 | struct intel_tv_priv *tv_priv = intel_output->dev_priv; | ||
1447 | struct drm_encoder *encoder = &intel_output->enc; | ||
1448 | int dpms_mode; | ||
1449 | int type = tv_priv->type; | ||
1450 | |||
1451 | mode = reported_modes[0]; | ||
1452 | drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V); | ||
1453 | |||
1454 | if (encoder->crtc) { | ||
1455 | type = intel_tv_detect_type(encoder->crtc, intel_output); | ||
1456 | } else { | ||
1457 | crtc = intel_get_load_detect_pipe(intel_output, &mode, &dpms_mode); | ||
1458 | if (crtc) { | ||
1459 | type = intel_tv_detect_type(crtc, intel_output); | ||
1460 | intel_release_load_detect_pipe(intel_output, dpms_mode); | ||
1461 | } else | ||
1462 | type = -1; | ||
1463 | } | ||
1464 | |||
1465 | if (type < 0) | ||
1466 | return connector_status_disconnected; | ||
1467 | |||
1468 | return connector_status_connected; | ||
1469 | } | ||
1470 | |||
1471 | static struct input_res { | ||
1472 | char *name; | ||
1473 | int w, h; | ||
1474 | } input_res_table[] = | ||
1475 | { | ||
1476 | {"640x480", 640, 480}, | ||
1477 | {"800x600", 800, 600}, | ||
1478 | {"1024x768", 1024, 768}, | ||
1479 | {"1280x1024", 1280, 1024}, | ||
1480 | {"848x480", 848, 480}, | ||
1481 | {"1280x720", 1280, 720}, | ||
1482 | {"1920x1080", 1920, 1080}, | ||
1483 | }; | ||
1484 | |||
1485 | /** | ||
1486 | * Stub get_modes function. | ||
1487 | * | ||
1488 | * This should probably return a set of fixed modes, unless we can figure out | ||
1489 | * how to probe modes off of TV connections. | ||
1490 | */ | ||
1491 | |||
1492 | static int | ||
1493 | intel_tv_get_modes(struct drm_connector *connector) | ||
1494 | { | ||
1495 | struct drm_display_mode *mode_ptr; | ||
1496 | struct intel_output *intel_output = to_intel_output(connector); | ||
1497 | const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output); | ||
1498 | int j; | ||
1499 | |||
1500 | for (j = 0; j < sizeof(input_res_table) / sizeof(input_res_table[0]); | ||
1501 | j++) { | ||
1502 | struct input_res *input = &input_res_table[j]; | ||
1503 | unsigned int hactive_s = input->w; | ||
1504 | unsigned int vactive_s = input->h; | ||
1505 | |||
1506 | if (tv_mode->max_srcw && input->w > tv_mode->max_srcw) | ||
1507 | continue; | ||
1508 | |||
1509 | if (input->w > 1024 && (!tv_mode->progressive | ||
1510 | && !tv_mode->component_only)) | ||
1511 | continue; | ||
1512 | |||
1513 | mode_ptr = drm_calloc(1, sizeof(struct drm_display_mode), | ||
1514 | DRM_MEM_DRIVER); | ||
1515 | strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN); | ||
1516 | |||
1517 | mode_ptr->hdisplay = hactive_s; | ||
1518 | mode_ptr->hsync_start = hactive_s + 1; | ||
1519 | mode_ptr->hsync_end = hactive_s + 64; | ||
1520 | if (mode_ptr->hsync_end <= mode_ptr->hsync_start) | ||
1521 | mode_ptr->hsync_end = mode_ptr->hsync_start + 1; | ||
1522 | mode_ptr->htotal = hactive_s + 96; | ||
1523 | |||
1524 | mode_ptr->vdisplay = vactive_s; | ||
1525 | mode_ptr->vsync_start = vactive_s + 1; | ||
1526 | mode_ptr->vsync_end = vactive_s + 32; | ||
1527 | if (mode_ptr->vsync_end <= mode_ptr->vsync_start) | ||
1528 | mode_ptr->vsync_end = mode_ptr->vsync_start + 1; | ||
1529 | mode_ptr->vtotal = vactive_s + 33; | ||
1530 | |||
1531 | mode_ptr->clock = (int) (tv_mode->refresh * | ||
1532 | mode_ptr->vtotal * | ||
1533 | mode_ptr->htotal / 1000) / 1000; | ||
1534 | |||
1535 | mode_ptr->type = DRM_MODE_TYPE_DRIVER; | ||
1536 | drm_mode_probed_add(connector, mode_ptr); | ||
1537 | } | ||
1538 | |||
1539 | return 0; | ||
1540 | } | ||
1541 | |||
1542 | static void | ||
1543 | intel_tv_destroy (struct drm_connector *connector) | ||
1544 | { | ||
1545 | struct intel_output *intel_output = to_intel_output(connector); | ||
1546 | |||
1547 | drm_sysfs_connector_remove(connector); | ||
1548 | drm_connector_cleanup(connector); | ||
1549 | drm_free(intel_output, sizeof(struct intel_output) + sizeof(struct intel_tv_priv), | ||
1550 | DRM_MEM_DRIVER); | ||
1551 | } | ||
1552 | |||
1553 | |||
1554 | static int | ||
1555 | intel_tv_set_property(struct drm_connector *connector, struct drm_property *property, | ||
1556 | uint64_t val) | ||
1557 | { | ||
1558 | struct drm_device *dev = connector->dev; | ||
1559 | struct intel_output *intel_output = to_intel_output(connector); | ||
1560 | struct intel_tv_priv *tv_priv = intel_output->dev_priv; | ||
1561 | int ret = 0; | ||
1562 | |||
1563 | ret = drm_connector_property_set_value(connector, property, val); | ||
1564 | if (ret < 0) | ||
1565 | goto out; | ||
1566 | |||
1567 | if (property == dev->mode_config.tv_left_margin_property) | ||
1568 | tv_priv->margin[TV_MARGIN_LEFT] = val; | ||
1569 | else if (property == dev->mode_config.tv_right_margin_property) | ||
1570 | tv_priv->margin[TV_MARGIN_RIGHT] = val; | ||
1571 | else if (property == dev->mode_config.tv_top_margin_property) | ||
1572 | tv_priv->margin[TV_MARGIN_TOP] = val; | ||
1573 | else if (property == dev->mode_config.tv_bottom_margin_property) | ||
1574 | tv_priv->margin[TV_MARGIN_BOTTOM] = val; | ||
1575 | else if (property == dev->mode_config.tv_mode_property) { | ||
1576 | if (val >= NUM_TV_MODES) { | ||
1577 | ret = -EINVAL; | ||
1578 | goto out; | ||
1579 | } | ||
1580 | tv_priv->tv_format = tv_modes[val].name; | ||
1581 | intel_tv_mode_set(&intel_output->enc, NULL, NULL); | ||
1582 | } else { | ||
1583 | ret = -EINVAL; | ||
1584 | goto out; | ||
1585 | } | ||
1586 | |||
1587 | intel_tv_mode_set(&intel_output->enc, NULL, NULL); | ||
1588 | out: | ||
1589 | return ret; | ||
1590 | } | ||
1591 | |||
1592 | static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = { | ||
1593 | .dpms = intel_tv_dpms, | ||
1594 | .mode_fixup = intel_tv_mode_fixup, | ||
1595 | .prepare = intel_encoder_prepare, | ||
1596 | .mode_set = intel_tv_mode_set, | ||
1597 | .commit = intel_encoder_commit, | ||
1598 | }; | ||
1599 | |||
1600 | static const struct drm_connector_funcs intel_tv_connector_funcs = { | ||
1601 | .save = intel_tv_save, | ||
1602 | .restore = intel_tv_restore, | ||
1603 | .detect = intel_tv_detect, | ||
1604 | .destroy = intel_tv_destroy, | ||
1605 | .set_property = intel_tv_set_property, | ||
1606 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
1607 | }; | ||
1608 | |||
1609 | static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = { | ||
1610 | .mode_valid = intel_tv_mode_valid, | ||
1611 | .get_modes = intel_tv_get_modes, | ||
1612 | .best_encoder = intel_best_encoder, | ||
1613 | }; | ||
1614 | |||
1615 | void intel_tv_enc_destroy(struct drm_encoder *encoder) | ||
1616 | { | ||
1617 | drm_encoder_cleanup(encoder); | ||
1618 | } | ||
1619 | |||
1620 | static const struct drm_encoder_funcs intel_tv_enc_funcs = { | ||
1621 | .destroy = intel_tv_enc_destroy, | ||
1622 | }; | ||
1623 | |||
1624 | |||
1625 | void | ||
1626 | intel_tv_init(struct drm_device *dev) | ||
1627 | { | ||
1628 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
1629 | struct drm_connector *connector; | ||
1630 | struct intel_output *intel_output; | ||
1631 | struct intel_tv_priv *tv_priv; | ||
1632 | u32 tv_dac_on, tv_dac_off, save_tv_dac; | ||
1633 | char **tv_format_names; | ||
1634 | int i, initial_mode = 0; | ||
1635 | |||
1636 | if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED) | ||
1637 | return; | ||
1638 | |||
1639 | /* Even if we have an encoder we may not have a connector */ | ||
1640 | if (!dev_priv->int_tv_support) | ||
1641 | return; | ||
1642 | |||
1643 | /* | ||
1644 | * Sanity check the TV output by checking to see if the | ||
1645 | * DAC register holds a value | ||
1646 | */ | ||
1647 | save_tv_dac = I915_READ(TV_DAC); | ||
1648 | |||
1649 | I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN); | ||
1650 | tv_dac_on = I915_READ(TV_DAC); | ||
1651 | |||
1652 | I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN); | ||
1653 | tv_dac_off = I915_READ(TV_DAC); | ||
1654 | |||
1655 | I915_WRITE(TV_DAC, save_tv_dac); | ||
1656 | |||
1657 | /* | ||
1658 | * If the register does not hold the state change enable | ||
1659 | * bit, (either as a 0 or a 1), assume it doesn't really | ||
1660 | * exist | ||
1661 | */ | ||
1662 | if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 || | ||
1663 | (tv_dac_off & TVDAC_STATE_CHG_EN) != 0) | ||
1664 | return; | ||
1665 | |||
1666 | intel_output = drm_calloc(1, sizeof(struct intel_output) + | ||
1667 | sizeof(struct intel_tv_priv), DRM_MEM_DRIVER); | ||
1668 | if (!intel_output) { | ||
1669 | return; | ||
1670 | } | ||
1671 | connector = &intel_output->base; | ||
1672 | |||
1673 | drm_connector_init(dev, connector, &intel_tv_connector_funcs, | ||
1674 | DRM_MODE_CONNECTOR_SVIDEO); | ||
1675 | |||
1676 | drm_encoder_init(dev, &intel_output->enc, &intel_tv_enc_funcs, | ||
1677 | DRM_MODE_ENCODER_TVDAC); | ||
1678 | |||
1679 | drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); | ||
1680 | tv_priv = (struct intel_tv_priv *)(intel_output + 1); | ||
1681 | intel_output->type = INTEL_OUTPUT_TVOUT; | ||
1682 | intel_output->enc.possible_crtcs = ((1 << 0) | (1 << 1)); | ||
1683 | intel_output->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT); | ||
1684 | intel_output->dev_priv = tv_priv; | ||
1685 | tv_priv->type = DRM_MODE_CONNECTOR_Unknown; | ||
1686 | |||
1687 | /* BIOS margin values */ | ||
1688 | tv_priv->margin[TV_MARGIN_LEFT] = 54; | ||
1689 | tv_priv->margin[TV_MARGIN_TOP] = 36; | ||
1690 | tv_priv->margin[TV_MARGIN_RIGHT] = 46; | ||
1691 | tv_priv->margin[TV_MARGIN_BOTTOM] = 37; | ||
1692 | |||
1693 | tv_priv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL); | ||
1694 | |||
1695 | drm_encoder_helper_add(&intel_output->enc, &intel_tv_helper_funcs); | ||
1696 | drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs); | ||
1697 | connector->interlace_allowed = false; | ||
1698 | connector->doublescan_allowed = false; | ||
1699 | |||
1700 | /* Create TV properties then attach current values */ | ||
1701 | tv_format_names = drm_alloc(sizeof(char *) * NUM_TV_MODES, | ||
1702 | DRM_MEM_DRIVER); | ||
1703 | if (!tv_format_names) | ||
1704 | goto out; | ||
1705 | for (i = 0; i < NUM_TV_MODES; i++) | ||
1706 | tv_format_names[i] = tv_modes[i].name; | ||
1707 | drm_mode_create_tv_properties(dev, NUM_TV_MODES, tv_format_names); | ||
1708 | |||
1709 | drm_connector_attach_property(connector, dev->mode_config.tv_mode_property, | ||
1710 | initial_mode); | ||
1711 | drm_connector_attach_property(connector, | ||
1712 | dev->mode_config.tv_left_margin_property, | ||
1713 | tv_priv->margin[TV_MARGIN_LEFT]); | ||
1714 | drm_connector_attach_property(connector, | ||
1715 | dev->mode_config.tv_top_margin_property, | ||
1716 | tv_priv->margin[TV_MARGIN_TOP]); | ||
1717 | drm_connector_attach_property(connector, | ||
1718 | dev->mode_config.tv_right_margin_property, | ||
1719 | tv_priv->margin[TV_MARGIN_RIGHT]); | ||
1720 | drm_connector_attach_property(connector, | ||
1721 | dev->mode_config.tv_bottom_margin_property, | ||
1722 | tv_priv->margin[TV_MARGIN_BOTTOM]); | ||
1723 | out: | ||
1724 | drm_sysfs_connector_add(connector); | ||
1725 | } | ||