diff options
Diffstat (limited to 'drivers/gpu/drm/i915')
30 files changed, 11218 insertions, 109 deletions
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..e747ac42fe3a --- /dev/null +++ b/drivers/gpu/drm/i915/dvo.h | |||
@@ -0,0 +1,157 @@ | |||
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 | extern struct intel_dvo_dev_ops sil164_ops; | ||
152 | extern struct intel_dvo_dev_ops ch7xxx_ops; | ||
153 | extern struct intel_dvo_dev_ops ivch_ops; | ||
154 | extern struct intel_dvo_dev_ops tfp410_ops; | ||
155 | extern struct intel_dvo_dev_ops ch7017_ops; | ||
156 | |||
157 | #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 afa8a12cd009..3d7082af5b72 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 | ||
@@ -39,6 +41,7 @@ | |||
39 | int i915_wait_ring(struct drm_device * dev, int n, const char *caller) | 41 | int i915_wait_ring(struct drm_device * dev, int n, const char *caller) |
40 | { | 42 | { |
41 | drm_i915_private_t *dev_priv = dev->dev_private; | 43 | drm_i915_private_t *dev_priv = dev->dev_private; |
44 | struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; | ||
42 | drm_i915_ring_buffer_t *ring = &(dev_priv->ring); | 45 | drm_i915_ring_buffer_t *ring = &(dev_priv->ring); |
43 | u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD; | 46 | u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD; |
44 | u32 last_acthd = I915_READ(acthd_reg); | 47 | u32 last_acthd = I915_READ(acthd_reg); |
@@ -55,8 +58,8 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller) | |||
55 | if (ring->space >= n) | 58 | if (ring->space >= n) |
56 | return 0; | 59 | return 0; |
57 | 60 | ||
58 | if (dev_priv->sarea_priv) | 61 | if (master_priv->sarea_priv) |
59 | dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; | 62 | master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; |
60 | 63 | ||
61 | if (ring->head != last_head) | 64 | if (ring->head != last_head) |
62 | i = 0; | 65 | i = 0; |
@@ -121,16 +124,28 @@ static void i915_free_hws(struct drm_device *dev) | |||
121 | void i915_kernel_lost_context(struct drm_device * dev) | 124 | void i915_kernel_lost_context(struct drm_device * dev) |
122 | { | 125 | { |
123 | drm_i915_private_t *dev_priv = dev->dev_private; | 126 | drm_i915_private_t *dev_priv = dev->dev_private; |
127 | struct drm_i915_master_private *master_priv; | ||
124 | drm_i915_ring_buffer_t *ring = &(dev_priv->ring); | 128 | drm_i915_ring_buffer_t *ring = &(dev_priv->ring); |
125 | 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 | |||
126 | ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; | 137 | ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; |
127 | ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; | 138 | ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; |
128 | ring->space = ring->head - (ring->tail + 8); | 139 | ring->space = ring->head - (ring->tail + 8); |
129 | if (ring->space < 0) | 140 | if (ring->space < 0) |
130 | ring->space += ring->Size; | 141 | ring->space += ring->Size; |
131 | 142 | ||
132 | if (ring->head == ring->tail && dev_priv->sarea_priv) | 143 | if (!dev->primary->master) |
133 | dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY; | 144 | return; |
145 | |||
146 | master_priv = dev->primary->master->driver_priv; | ||
147 | if (ring->head == ring->tail && master_priv->sarea_priv) | ||
148 | master_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY; | ||
134 | } | 149 | } |
135 | 150 | ||
136 | static int i915_dma_cleanup(struct drm_device * dev) | 151 | static int i915_dma_cleanup(struct drm_device * dev) |
@@ -154,25 +169,13 @@ static int i915_dma_cleanup(struct drm_device * dev) | |||
154 | if (I915_NEED_GFX_HWS(dev)) | 169 | if (I915_NEED_GFX_HWS(dev)) |
155 | i915_free_hws(dev); | 170 | i915_free_hws(dev); |
156 | 171 | ||
157 | dev_priv->sarea = NULL; | ||
158 | dev_priv->sarea_priv = NULL; | ||
159 | |||
160 | return 0; | 172 | return 0; |
161 | } | 173 | } |
162 | 174 | ||
163 | static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) | 175 | static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) |
164 | { | 176 | { |
165 | drm_i915_private_t *dev_priv = dev->dev_private; | 177 | drm_i915_private_t *dev_priv = dev->dev_private; |
166 | 178 | struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; | |
167 | dev_priv->sarea = drm_getsarea(dev); | ||
168 | if (!dev_priv->sarea) { | ||
169 | DRM_ERROR("can not find sarea!\n"); | ||
170 | i915_dma_cleanup(dev); | ||
171 | return -EINVAL; | ||
172 | } | ||
173 | |||
174 | dev_priv->sarea_priv = (drm_i915_sarea_t *) | ||
175 | ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset); | ||
176 | 179 | ||
177 | if (init->ring_size != 0) { | 180 | if (init->ring_size != 0) { |
178 | if (dev_priv->ring.ring_obj != NULL) { | 181 | if (dev_priv->ring.ring_obj != NULL) { |
@@ -207,7 +210,8 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) | |||
207 | dev_priv->back_offset = init->back_offset; | 210 | dev_priv->back_offset = init->back_offset; |
208 | dev_priv->front_offset = init->front_offset; | 211 | dev_priv->front_offset = init->front_offset; |
209 | dev_priv->current_page = 0; | 212 | dev_priv->current_page = 0; |
210 | dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; | 213 | if (master_priv->sarea_priv) |
214 | master_priv->sarea_priv->pf_current_page = 0; | ||
211 | 215 | ||
212 | /* Allow hardware batchbuffers unless told otherwise. | 216 | /* Allow hardware batchbuffers unless told otherwise. |
213 | */ | 217 | */ |
@@ -222,11 +226,6 @@ static int i915_dma_resume(struct drm_device * dev) | |||
222 | 226 | ||
223 | DRM_DEBUG("%s\n", __func__); | 227 | DRM_DEBUG("%s\n", __func__); |
224 | 228 | ||
225 | if (!dev_priv->sarea) { | ||
226 | DRM_ERROR("can not find sarea!\n"); | ||
227 | return -EINVAL; | ||
228 | } | ||
229 | |||
230 | if (dev_priv->ring.map.handle == NULL) { | 229 | if (dev_priv->ring.map.handle == NULL) { |
231 | DRM_ERROR("can not ioremap virtual address for" | 230 | DRM_ERROR("can not ioremap virtual address for" |
232 | " ring buffer\n"); | 231 | " ring buffer\n"); |
@@ -435,13 +434,14 @@ i915_emit_box(struct drm_device *dev, | |||
435 | static void i915_emit_breadcrumb(struct drm_device *dev) | 434 | static void i915_emit_breadcrumb(struct drm_device *dev) |
436 | { | 435 | { |
437 | drm_i915_private_t *dev_priv = dev->dev_private; | 436 | drm_i915_private_t *dev_priv = dev->dev_private; |
437 | struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; | ||
438 | RING_LOCALS; | 438 | RING_LOCALS; |
439 | 439 | ||
440 | dev_priv->counter++; | 440 | dev_priv->counter++; |
441 | if (dev_priv->counter > 0x7FFFFFFFUL) | 441 | if (dev_priv->counter > 0x7FFFFFFFUL) |
442 | dev_priv->counter = 0; | 442 | dev_priv->counter = 0; |
443 | if (dev_priv->sarea_priv) | 443 | if (master_priv->sarea_priv) |
444 | dev_priv->sarea_priv->last_enqueue = dev_priv->counter; | 444 | master_priv->sarea_priv->last_enqueue = dev_priv->counter; |
445 | 445 | ||
446 | BEGIN_LP_RING(4); | 446 | BEGIN_LP_RING(4); |
447 | OUT_RING(MI_STORE_DWORD_INDEX); | 447 | OUT_RING(MI_STORE_DWORD_INDEX); |
@@ -537,15 +537,17 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev, | |||
537 | static int i915_dispatch_flip(struct drm_device * dev) | 537 | static int i915_dispatch_flip(struct drm_device * dev) |
538 | { | 538 | { |
539 | drm_i915_private_t *dev_priv = dev->dev_private; | 539 | drm_i915_private_t *dev_priv = dev->dev_private; |
540 | struct drm_i915_master_private *master_priv = | ||
541 | dev->primary->master->driver_priv; | ||
540 | RING_LOCALS; | 542 | RING_LOCALS; |
541 | 543 | ||
542 | if (!dev_priv->sarea_priv) | 544 | if (!master_priv->sarea_priv) |
543 | return -EINVAL; | 545 | return -EINVAL; |
544 | 546 | ||
545 | DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", | 547 | DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", |
546 | __func__, | 548 | __func__, |
547 | dev_priv->current_page, | 549 | dev_priv->current_page, |
548 | dev_priv->sarea_priv->pf_current_page); | 550 | master_priv->sarea_priv->pf_current_page); |
549 | 551 | ||
550 | i915_kernel_lost_context(dev); | 552 | i915_kernel_lost_context(dev); |
551 | 553 | ||
@@ -572,7 +574,7 @@ static int i915_dispatch_flip(struct drm_device * dev) | |||
572 | OUT_RING(0); | 574 | OUT_RING(0); |
573 | ADVANCE_LP_RING(); | 575 | ADVANCE_LP_RING(); |
574 | 576 | ||
575 | dev_priv->sarea_priv->last_enqueue = dev_priv->counter++; | 577 | master_priv->sarea_priv->last_enqueue = dev_priv->counter++; |
576 | 578 | ||
577 | BEGIN_LP_RING(4); | 579 | BEGIN_LP_RING(4); |
578 | OUT_RING(MI_STORE_DWORD_INDEX); | 580 | OUT_RING(MI_STORE_DWORD_INDEX); |
@@ -581,7 +583,7 @@ static int i915_dispatch_flip(struct drm_device * dev) | |||
581 | OUT_RING(0); | 583 | OUT_RING(0); |
582 | ADVANCE_LP_RING(); | 584 | ADVANCE_LP_RING(); |
583 | 585 | ||
584 | dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; | 586 | master_priv->sarea_priv->pf_current_page = dev_priv->current_page; |
585 | return 0; | 587 | return 0; |
586 | } | 588 | } |
587 | 589 | ||
@@ -611,8 +613,9 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, | |||
611 | struct drm_file *file_priv) | 613 | struct drm_file *file_priv) |
612 | { | 614 | { |
613 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 615 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
616 | struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; | ||
614 | drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) | 617 | drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) |
615 | dev_priv->sarea_priv; | 618 | master_priv->sarea_priv; |
616 | drm_i915_batchbuffer_t *batch = data; | 619 | drm_i915_batchbuffer_t *batch = data; |
617 | int ret; | 620 | int ret; |
618 | 621 | ||
@@ -644,8 +647,9 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, | |||
644 | struct drm_file *file_priv) | 647 | struct drm_file *file_priv) |
645 | { | 648 | { |
646 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 649 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
650 | struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; | ||
647 | drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) | 651 | drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *) |
648 | dev_priv->sarea_priv; | 652 | master_priv->sarea_priv; |
649 | drm_i915_cmdbuffer_t *cmdbuf = data; | 653 | drm_i915_cmdbuffer_t *cmdbuf = data; |
650 | int ret; | 654 | int ret; |
651 | 655 | ||
@@ -774,6 +778,11 @@ static int i915_set_status_page(struct drm_device *dev, void *data, | |||
774 | return -EINVAL; | 778 | return -EINVAL; |
775 | } | 779 | } |
776 | 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 | |||
777 | 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); |
778 | 787 | ||
779 | dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12); | 788 | dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12); |
@@ -802,6 +811,214 @@ static int i915_set_status_page(struct drm_device *dev, void *data, | |||
802 | return 0; | 811 | return 0; |
803 | } | 812 | } |
804 | 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 | static int i915_probe_agp(struct drm_device *dev, 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 (dev->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(dev->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 | if (IS_G4X(dev)) | ||
865 | overhead = 4096; | ||
866 | else | ||
867 | overhead = (*aperture_size / 1024) + 4096; | ||
868 | |||
869 | switch (tmp & INTEL_855_GMCH_GMS_MASK) { | ||
870 | case INTEL_855_GMCH_GMS_STOLEN_1M: | ||
871 | break; /* 1M already */ | ||
872 | case INTEL_855_GMCH_GMS_STOLEN_4M: | ||
873 | *preallocated_size *= 4; | ||
874 | break; | ||
875 | case INTEL_855_GMCH_GMS_STOLEN_8M: | ||
876 | *preallocated_size *= 8; | ||
877 | break; | ||
878 | case INTEL_855_GMCH_GMS_STOLEN_16M: | ||
879 | *preallocated_size *= 16; | ||
880 | break; | ||
881 | case INTEL_855_GMCH_GMS_STOLEN_32M: | ||
882 | *preallocated_size *= 32; | ||
883 | break; | ||
884 | case INTEL_915G_GMCH_GMS_STOLEN_48M: | ||
885 | *preallocated_size *= 48; | ||
886 | break; | ||
887 | case INTEL_915G_GMCH_GMS_STOLEN_64M: | ||
888 | *preallocated_size *= 64; | ||
889 | break; | ||
890 | case INTEL_855_GMCH_GMS_DISABLED: | ||
891 | DRM_ERROR("video memory is disabled\n"); | ||
892 | return -1; | ||
893 | default: | ||
894 | DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n", | ||
895 | tmp & INTEL_855_GMCH_GMS_MASK); | ||
896 | return -1; | ||
897 | } | ||
898 | *preallocated_size -= overhead; | ||
899 | |||
900 | return 0; | ||
901 | } | ||
902 | |||
903 | static int i915_load_modeset_init(struct drm_device *dev) | ||
904 | { | ||
905 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
906 | unsigned long agp_size, prealloc_size; | ||
907 | int fb_bar = IS_I9XX(dev) ? 2 : 0; | ||
908 | int ret = 0; | ||
909 | |||
910 | dev->devname = kstrdup(DRIVER_NAME, GFP_KERNEL); | ||
911 | if (!dev->devname) { | ||
912 | ret = -ENOMEM; | ||
913 | goto out; | ||
914 | } | ||
915 | |||
916 | dev->mode_config.fb_base = drm_get_resource_start(dev, fb_bar) & | ||
917 | 0xff000000; | ||
918 | |||
919 | DRM_DEBUG("*** fb base 0x%08lx\n", dev->mode_config.fb_base); | ||
920 | |||
921 | if (IS_MOBILE(dev) || (IS_I9XX(dev) && !IS_I965G(dev) && !IS_G33(dev))) | ||
922 | dev_priv->cursor_needs_physical = true; | ||
923 | else | ||
924 | dev_priv->cursor_needs_physical = false; | ||
925 | |||
926 | ret = i915_probe_agp(dev, &agp_size, &prealloc_size); | ||
927 | if (ret) | ||
928 | goto kfree_devname; | ||
929 | |||
930 | /* Basic memrange allocator for stolen space (aka vram) */ | ||
931 | drm_mm_init(&dev_priv->vram, 0, prealloc_size); | ||
932 | |||
933 | /* Let GEM Manage from end of prealloc space to end of aperture */ | ||
934 | i915_gem_do_init(dev, prealloc_size, agp_size); | ||
935 | |||
936 | ret = i915_gem_init_ringbuffer(dev); | ||
937 | if (ret) | ||
938 | goto kfree_devname; | ||
939 | |||
940 | dev_priv->mm.gtt_mapping = | ||
941 | io_mapping_create_wc(dev->agp->base, | ||
942 | dev->agp->agp_info.aper_size * 1024*1024); | ||
943 | |||
944 | /* Allow hardware batchbuffers unless told otherwise. | ||
945 | */ | ||
946 | dev_priv->allow_batchbuffer = 1; | ||
947 | |||
948 | ret = intel_init_bios(dev); | ||
949 | if (ret) | ||
950 | DRM_INFO("failed to find VBIOS tables\n"); | ||
951 | |||
952 | ret = drm_irq_install(dev); | ||
953 | if (ret) | ||
954 | goto destroy_ringbuffer; | ||
955 | |||
956 | /* FIXME: re-add hotplug support */ | ||
957 | #if 0 | ||
958 | ret = drm_hotplug_init(dev); | ||
959 | if (ret) | ||
960 | goto destroy_ringbuffer; | ||
961 | #endif | ||
962 | |||
963 | /* Always safe in the mode setting case. */ | ||
964 | /* FIXME: do pre/post-mode set stuff in core KMS code */ | ||
965 | dev->vblank_disable_allowed = 1; | ||
966 | |||
967 | /* | ||
968 | * Initialize the hardware status page IRQ location. | ||
969 | */ | ||
970 | |||
971 | I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); | ||
972 | |||
973 | intel_modeset_init(dev); | ||
974 | |||
975 | drm_helper_initial_config(dev, false); | ||
976 | |||
977 | return 0; | ||
978 | |||
979 | destroy_ringbuffer: | ||
980 | i915_gem_cleanup_ringbuffer(dev); | ||
981 | kfree_devname: | ||
982 | kfree(dev->devname); | ||
983 | out: | ||
984 | return ret; | ||
985 | } | ||
986 | |||
987 | int i915_master_create(struct drm_device *dev, struct drm_master *master) | ||
988 | { | ||
989 | struct drm_i915_master_private *master_priv; | ||
990 | |||
991 | master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER); | ||
992 | if (!master_priv) | ||
993 | return -ENOMEM; | ||
994 | |||
995 | master->driver_priv = master_priv; | ||
996 | return 0; | ||
997 | } | ||
998 | |||
999 | void i915_master_destroy(struct drm_device *dev, struct drm_master *master) | ||
1000 | { | ||
1001 | struct drm_i915_master_private *master_priv = master->driver_priv; | ||
1002 | |||
1003 | if (!master_priv) | ||
1004 | return; | ||
1005 | |||
1006 | drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER); | ||
1007 | |||
1008 | master->driver_priv = NULL; | ||
1009 | } | ||
1010 | |||
1011 | /** | ||
1012 | * i915_driver_load - setup chip and create an initial config | ||
1013 | * @dev: DRM device | ||
1014 | * @flags: startup flags | ||
1015 | * | ||
1016 | * The driver load routine has to do several things: | ||
1017 | * - drive output discovery via intel_modeset_init() | ||
1018 | * - initialize the memory manager | ||
1019 | * - allocate initial config memory | ||
1020 | * - setup the DRM framebuffer with the allocated memory | ||
1021 | */ | ||
805 | int i915_driver_load(struct drm_device *dev, unsigned long flags) | 1022 | int i915_driver_load(struct drm_device *dev, unsigned long flags) |
806 | { | 1023 | { |
807 | struct drm_i915_private *dev_priv = dev->dev_private; | 1024 | struct drm_i915_private *dev_priv = dev->dev_private; |
@@ -829,6 +1046,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
829 | size = drm_get_resource_len(dev, mmio_bar); | 1046 | size = drm_get_resource_len(dev, mmio_bar); |
830 | 1047 | ||
831 | dev_priv->regs = ioremap(base, size); | 1048 | dev_priv->regs = ioremap(base, size); |
1049 | if (!dev_priv->regs) { | ||
1050 | DRM_ERROR("failed to map registers\n"); | ||
1051 | ret = -EIO; | ||
1052 | goto free_priv; | ||
1053 | } | ||
832 | 1054 | ||
833 | #ifdef CONFIG_HIGHMEM64G | 1055 | #ifdef CONFIG_HIGHMEM64G |
834 | /* don't enable GEM on PAE - needs agp + set_memory_* interface fixes */ | 1056 | /* don't enable GEM on PAE - needs agp + set_memory_* interface fixes */ |
@@ -844,7 +1066,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
844 | if (!I915_NEED_GFX_HWS(dev)) { | 1066 | if (!I915_NEED_GFX_HWS(dev)) { |
845 | ret = i915_init_phys_hws(dev); | 1067 | ret = i915_init_phys_hws(dev); |
846 | if (ret != 0) | 1068 | if (ret != 0) |
847 | return ret; | 1069 | goto out_rmmap; |
848 | } | 1070 | } |
849 | 1071 | ||
850 | /* On the 945G/GM, the chipset reports the MSI capability on the | 1072 | /* On the 945G/GM, the chipset reports the MSI capability on the |
@@ -864,6 +1086,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
864 | intel_opregion_init(dev); | 1086 | intel_opregion_init(dev); |
865 | 1087 | ||
866 | spin_lock_init(&dev_priv->user_irq_lock); | 1088 | spin_lock_init(&dev_priv->user_irq_lock); |
1089 | dev_priv->user_irq_refcount = 0; | ||
867 | 1090 | ||
868 | ret = drm_vblank_init(dev, I915_NUM_PIPE); | 1091 | ret = drm_vblank_init(dev, I915_NUM_PIPE); |
869 | 1092 | ||
@@ -872,6 +1095,20 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) | |||
872 | return ret; | 1095 | return ret; |
873 | } | 1096 | } |
874 | 1097 | ||
1098 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
1099 | ret = i915_load_modeset_init(dev); | ||
1100 | if (ret < 0) { | ||
1101 | DRM_ERROR("failed to init modeset\n"); | ||
1102 | goto out_rmmap; | ||
1103 | } | ||
1104 | } | ||
1105 | |||
1106 | return 0; | ||
1107 | |||
1108 | out_rmmap: | ||
1109 | iounmap(dev_priv->regs); | ||
1110 | free_priv: | ||
1111 | drm_free(dev_priv, sizeof(struct drm_i915_private), DRM_MEM_DRIVER); | ||
875 | return ret; | 1112 | return ret; |
876 | } | 1113 | } |
877 | 1114 | ||
@@ -879,16 +1116,29 @@ int i915_driver_unload(struct drm_device *dev) | |||
879 | { | 1116 | { |
880 | struct drm_i915_private *dev_priv = dev->dev_private; | 1117 | struct drm_i915_private *dev_priv = dev->dev_private; |
881 | 1118 | ||
1119 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
1120 | io_mapping_free(dev_priv->mm.gtt_mapping); | ||
1121 | drm_irq_uninstall(dev); | ||
1122 | } | ||
1123 | |||
882 | if (dev->pdev->msi_enabled) | 1124 | if (dev->pdev->msi_enabled) |
883 | pci_disable_msi(dev->pdev); | 1125 | pci_disable_msi(dev->pdev); |
884 | 1126 | ||
885 | i915_free_hws(dev); | ||
886 | |||
887 | if (dev_priv->regs != NULL) | 1127 | if (dev_priv->regs != NULL) |
888 | iounmap(dev_priv->regs); | 1128 | iounmap(dev_priv->regs); |
889 | 1129 | ||
890 | intel_opregion_free(dev); | 1130 | intel_opregion_free(dev); |
891 | 1131 | ||
1132 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
1133 | intel_modeset_cleanup(dev); | ||
1134 | |||
1135 | mutex_lock(&dev->struct_mutex); | ||
1136 | i915_gem_cleanup_ringbuffer(dev); | ||
1137 | mutex_unlock(&dev->struct_mutex); | ||
1138 | drm_mm_takedown(&dev_priv->vram); | ||
1139 | i915_gem_lastclose(dev); | ||
1140 | } | ||
1141 | |||
892 | drm_free(dev->dev_private, sizeof(drm_i915_private_t), | 1142 | drm_free(dev->dev_private, sizeof(drm_i915_private_t), |
893 | DRM_MEM_DRIVER); | 1143 | DRM_MEM_DRIVER); |
894 | 1144 | ||
@@ -914,12 +1164,26 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv) | |||
914 | return 0; | 1164 | return 0; |
915 | } | 1165 | } |
916 | 1166 | ||
1167 | /** | ||
1168 | * i915_driver_lastclose - clean up after all DRM clients have exited | ||
1169 | * @dev: DRM device | ||
1170 | * | ||
1171 | * Take care of cleaning up after all DRM clients have exited. In the | ||
1172 | * mode setting case, we want to restore the kernel's initial mode (just | ||
1173 | * in case the last client left us in a bad state). | ||
1174 | * | ||
1175 | * Additionally, in the non-mode setting case, we'll tear down the AGP | ||
1176 | * and DMA structures, since the kernel won't be using them, and clea | ||
1177 | * up any GEM state. | ||
1178 | */ | ||
917 | void i915_driver_lastclose(struct drm_device * dev) | 1179 | void i915_driver_lastclose(struct drm_device * dev) |
918 | { | 1180 | { |
919 | drm_i915_private_t *dev_priv = dev->dev_private; | 1181 | drm_i915_private_t *dev_priv = dev->dev_private; |
920 | 1182 | ||
921 | if (!dev_priv) | 1183 | if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) { |
1184 | intelfb_restore(); | ||
922 | return; | 1185 | return; |
1186 | } | ||
923 | 1187 | ||
924 | i915_gem_lastclose(dev); | 1188 | i915_gem_lastclose(dev); |
925 | 1189 | ||
@@ -932,7 +1196,8 @@ void i915_driver_lastclose(struct drm_device * dev) | |||
932 | void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) | 1196 | void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) |
933 | { | 1197 | { |
934 | drm_i915_private_t *dev_priv = dev->dev_private; | 1198 | drm_i915_private_t *dev_priv = dev->dev_private; |
935 | i915_mem_release(dev, file_priv, dev_priv->agp_heap); | 1199 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
1200 | i915_mem_release(dev, file_priv, dev_priv->agp_heap); | ||
936 | } | 1201 | } |
937 | 1202 | ||
938 | void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) | 1203 | void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) |
@@ -972,6 +1237,7 @@ struct drm_ioctl_desc i915_ioctls[] = { | |||
972 | DRM_IOCTL_DEF(DRM_I915_GEM_PREAD, i915_gem_pread_ioctl, 0), | 1237 | DRM_IOCTL_DEF(DRM_I915_GEM_PREAD, i915_gem_pread_ioctl, 0), |
973 | DRM_IOCTL_DEF(DRM_I915_GEM_PWRITE, i915_gem_pwrite_ioctl, 0), | 1238 | DRM_IOCTL_DEF(DRM_I915_GEM_PWRITE, i915_gem_pwrite_ioctl, 0), |
974 | DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, 0), | 1239 | DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, 0), |
1240 | DRM_IOCTL_DEF(DRM_I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, 0), | ||
975 | DRM_IOCTL_DEF(DRM_I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, 0), | 1241 | DRM_IOCTL_DEF(DRM_I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, 0), |
976 | DRM_IOCTL_DEF(DRM_I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, 0), | 1242 | DRM_IOCTL_DEF(DRM_I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, 0), |
977 | DRM_IOCTL_DEF(DRM_I915_GEM_SET_TILING, i915_gem_set_tiling, 0), | 1243 | DRM_IOCTL_DEF(DRM_I915_GEM_SET_TILING, i915_gem_set_tiling, 0), |
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index a80ead215282..f8b3df0926c0 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 | static 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; |
@@ -81,6 +92,10 @@ static int i915_resume(struct drm_device *dev) | |||
81 | return 0; | 92 | return 0; |
82 | } | 93 | } |
83 | 94 | ||
95 | static struct vm_operations_struct i915_gem_vm_ops = { | ||
96 | .fault = i915_gem_fault, | ||
97 | }; | ||
98 | |||
84 | static struct drm_driver driver = { | 99 | static struct drm_driver driver = { |
85 | /* don't use mtrr's here, the Xserver or user space app should | 100 | /* don't use mtrr's here, the Xserver or user space app should |
86 | * deal with them for intel hardware. | 101 | * deal with them for intel hardware. |
@@ -107,17 +122,20 @@ static struct drm_driver driver = { | |||
107 | .reclaim_buffers = drm_core_reclaim_buffers, | 122 | .reclaim_buffers = drm_core_reclaim_buffers, |
108 | .get_map_ofs = drm_core_get_map_ofs, | 123 | .get_map_ofs = drm_core_get_map_ofs, |
109 | .get_reg_ofs = drm_core_get_reg_ofs, | 124 | .get_reg_ofs = drm_core_get_reg_ofs, |
125 | .master_create = i915_master_create, | ||
126 | .master_destroy = i915_master_destroy, | ||
110 | .proc_init = i915_gem_proc_init, | 127 | .proc_init = i915_gem_proc_init, |
111 | .proc_cleanup = i915_gem_proc_cleanup, | 128 | .proc_cleanup = i915_gem_proc_cleanup, |
112 | .gem_init_object = i915_gem_init_object, | 129 | .gem_init_object = i915_gem_init_object, |
113 | .gem_free_object = i915_gem_free_object, | 130 | .gem_free_object = i915_gem_free_object, |
131 | .gem_vm_ops = &i915_gem_vm_ops, | ||
114 | .ioctls = i915_ioctls, | 132 | .ioctls = i915_ioctls, |
115 | .fops = { | 133 | .fops = { |
116 | .owner = THIS_MODULE, | 134 | .owner = THIS_MODULE, |
117 | .open = drm_open, | 135 | .open = drm_open, |
118 | .release = drm_release, | 136 | .release = drm_release, |
119 | .ioctl = drm_ioctl, | 137 | .ioctl = drm_ioctl, |
120 | .mmap = drm_mmap, | 138 | .mmap = drm_gem_mmap, |
121 | .poll = drm_poll, | 139 | .poll = drm_poll, |
122 | .fasync = drm_fasync, | 140 | .fasync = drm_fasync, |
123 | #ifdef CONFIG_COMPAT | 141 | #ifdef CONFIG_COMPAT |
@@ -141,6 +159,28 @@ static struct drm_driver driver = { | |||
141 | static int __init i915_init(void) | 159 | static int __init i915_init(void) |
142 | { | 160 | { |
143 | 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 | |||
144 | return drm_init(&driver); | 184 | return drm_init(&driver); |
145 | } | 185 | } |
146 | 186 | ||
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b3cc4731aa7c..4756e5cd6b5e 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: |
@@ -103,15 +104,23 @@ struct intel_opregion { | |||
103 | int enabled; | 104 | int enabled; |
104 | }; | 105 | }; |
105 | 106 | ||
107 | struct drm_i915_master_private { | ||
108 | drm_local_map_t *sarea; | ||
109 | struct _drm_i915_sarea *sarea_priv; | ||
110 | }; | ||
111 | #define I915_FENCE_REG_NONE -1 | ||
112 | |||
113 | struct drm_i915_fence_reg { | ||
114 | struct drm_gem_object *obj; | ||
115 | }; | ||
116 | |||
106 | typedef struct drm_i915_private { | 117 | typedef struct drm_i915_private { |
107 | struct drm_device *dev; | 118 | struct drm_device *dev; |
108 | 119 | ||
109 | int has_gem; | 120 | int has_gem; |
110 | 121 | ||
111 | void __iomem *regs; | 122 | void __iomem *regs; |
112 | drm_local_map_t *sarea; | ||
113 | 123 | ||
114 | drm_i915_sarea_t *sarea_priv; | ||
115 | drm_i915_ring_buffer_t ring; | 124 | drm_i915_ring_buffer_t ring; |
116 | 125 | ||
117 | drm_dma_handle_t *status_page_dmah; | 126 | drm_dma_handle_t *status_page_dmah; |
@@ -144,8 +153,30 @@ typedef struct drm_i915_private { | |||
144 | unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; | 153 | unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; |
145 | int vblank_pipe; | 154 | int vblank_pipe; |
146 | 155 | ||
156 | bool cursor_needs_physical; | ||
157 | |||
158 | struct drm_mm vram; | ||
159 | |||
160 | int irq_enabled; | ||
161 | |||
147 | struct intel_opregion opregion; | 162 | struct intel_opregion opregion; |
148 | 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 | unsigned int int_tv_support:1; | ||
172 | unsigned int lvds_dither:1; | ||
173 | unsigned int lvds_vbt:1; | ||
174 | unsigned int int_crt_support:1; | ||
175 | |||
176 | struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */ | ||
177 | int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */ | ||
178 | int num_fence_regs; /* 8 on pre-965, 16 otherwise */ | ||
179 | |||
149 | /* Register state */ | 180 | /* Register state */ |
150 | u8 saveLBB; | 181 | u8 saveLBB; |
151 | u32 saveDSPACNTR; | 182 | u32 saveDSPACNTR; |
@@ -364,6 +395,21 @@ struct drm_i915_gem_object { | |||
364 | * This is the same as gtt_space->start | 395 | * This is the same as gtt_space->start |
365 | */ | 396 | */ |
366 | uint32_t gtt_offset; | 397 | uint32_t gtt_offset; |
398 | /** | ||
399 | * Required alignment for the object | ||
400 | */ | ||
401 | uint32_t gtt_alignment; | ||
402 | /** | ||
403 | * Fake offset for use by mmap(2) | ||
404 | */ | ||
405 | uint64_t mmap_offset; | ||
406 | |||
407 | /** | ||
408 | * Fence register bits (if any) for this object. Will be set | ||
409 | * as needed when mapped into the GTT. | ||
410 | * Protected by dev->struct_mutex. | ||
411 | */ | ||
412 | int fence_reg; | ||
367 | 413 | ||
368 | /** Boolean whether this object has a valid gtt offset. */ | 414 | /** Boolean whether this object has a valid gtt offset. */ |
369 | int gtt_bound; | 415 | int gtt_bound; |
@@ -376,6 +422,7 @@ struct drm_i915_gem_object { | |||
376 | 422 | ||
377 | /** Current tiling mode for the object. */ | 423 | /** Current tiling mode for the object. */ |
378 | uint32_t tiling_mode; | 424 | uint32_t tiling_mode; |
425 | uint32_t stride; | ||
379 | 426 | ||
380 | /** AGP mapping type (AGP_USER_MEMORY or AGP_USER_CACHED_MEMORY */ | 427 | /** AGP mapping type (AGP_USER_MEMORY or AGP_USER_CACHED_MEMORY */ |
381 | uint32_t agp_type; | 428 | uint32_t agp_type; |
@@ -385,6 +432,10 @@ struct drm_i915_gem_object { | |||
385 | * flags which individual pages are valid. | 432 | * flags which individual pages are valid. |
386 | */ | 433 | */ |
387 | 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; | ||
388 | }; | 439 | }; |
389 | 440 | ||
390 | /** | 441 | /** |
@@ -414,8 +465,19 @@ struct drm_i915_file_private { | |||
414 | } mm; | 465 | } mm; |
415 | }; | 466 | }; |
416 | 467 | ||
468 | enum intel_chip_family { | ||
469 | CHIP_I8XX = 0x01, | ||
470 | CHIP_I9XX = 0x02, | ||
471 | CHIP_I915 = 0x04, | ||
472 | CHIP_I965 = 0x08, | ||
473 | }; | ||
474 | |||
417 | extern struct drm_ioctl_desc i915_ioctls[]; | 475 | extern struct drm_ioctl_desc i915_ioctls[]; |
418 | extern int i915_max_ioctl; | 476 | extern int i915_max_ioctl; |
477 | extern unsigned int i915_fbpercrtc; | ||
478 | |||
479 | extern int i915_master_create(struct drm_device *dev, struct drm_master *master); | ||
480 | extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master); | ||
419 | 481 | ||
420 | /* i915_dma.c */ | 482 | /* i915_dma.c */ |
421 | extern void i915_kernel_lost_context(struct drm_device * dev); | 483 | extern void i915_kernel_lost_context(struct drm_device * dev); |
@@ -441,6 +503,7 @@ extern int i915_irq_wait(struct drm_device *dev, void *data, | |||
441 | struct drm_file *file_priv); | 503 | struct drm_file *file_priv); |
442 | void i915_user_irq_get(struct drm_device *dev); | 504 | void i915_user_irq_get(struct drm_device *dev); |
443 | 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); | ||
444 | 507 | ||
445 | extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); | 508 | extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); |
446 | extern void i915_driver_irq_preinstall(struct drm_device * dev); | 509 | extern void i915_driver_irq_preinstall(struct drm_device * dev); |
@@ -487,6 +550,8 @@ int i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, | |||
487 | struct drm_file *file_priv); | 550 | struct drm_file *file_priv); |
488 | int i915_gem_mmap_ioctl(struct drm_device *dev, void *data, | 551 | int i915_gem_mmap_ioctl(struct drm_device *dev, void *data, |
489 | struct drm_file *file_priv); | 552 | struct drm_file *file_priv); |
553 | int i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, | ||
554 | struct drm_file *file_priv); | ||
490 | int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, | 555 | int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, |
491 | struct drm_file *file_priv); | 556 | struct drm_file *file_priv); |
492 | int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, | 557 | int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, |
@@ -523,6 +588,16 @@ uint32_t i915_get_gem_seqno(struct drm_device *dev); | |||
523 | void i915_gem_retire_requests(struct drm_device *dev); | 588 | void i915_gem_retire_requests(struct drm_device *dev); |
524 | void i915_gem_retire_work_handler(struct work_struct *work); | 589 | void i915_gem_retire_work_handler(struct work_struct *work); |
525 | 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); | ||
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); | ||
526 | 601 | ||
527 | /* i915_gem_tiling.c */ | 602 | /* i915_gem_tiling.c */ |
528 | void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); | 603 | void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); |
@@ -561,6 +636,10 @@ static inline void opregion_asle_intr(struct drm_device *dev) { return; } | |||
561 | static inline void opregion_enable_asle(struct drm_device *dev) { return; } | 636 | static inline void opregion_enable_asle(struct drm_device *dev) { return; } |
562 | #endif | 637 | #endif |
563 | 638 | ||
639 | /* modesetting */ | ||
640 | extern void intel_modeset_init(struct drm_device *dev); | ||
641 | extern void intel_modeset_cleanup(struct drm_device *dev); | ||
642 | |||
564 | /** | 643 | /** |
565 | * 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. |
566 | * | 645 | * |
@@ -578,6 +657,13 @@ static inline void opregion_enable_asle(struct drm_device *dev) { return; } | |||
578 | #define I915_WRITE16(reg, val) writel(val, dev_priv->regs + (reg)) | 657 | #define I915_WRITE16(reg, val) writel(val, dev_priv->regs + (reg)) |
579 | #define I915_READ8(reg) readb(dev_priv->regs + (reg)) | 658 | #define I915_READ8(reg) readb(dev_priv->regs + (reg)) |
580 | #define I915_WRITE8(reg, val) writeb(val, dev_priv->regs + (reg)) | 659 | #define I915_WRITE8(reg, val) writeb(val, dev_priv->regs + (reg)) |
660 | #ifdef writeq | ||
661 | #define I915_WRITE64(reg, val) writeq(val, dev_priv->regs + (reg)) | ||
662 | #else | ||
663 | #define I915_WRITE64(reg, val) (writel(val, dev_priv->regs + (reg)), \ | ||
664 | writel(upper_32_bits(val), dev_priv->regs + \ | ||
665 | (reg) + 4)) | ||
666 | #endif | ||
581 | 667 | ||
582 | #define I915_VERBOSE 0 | 668 | #define I915_VERBOSE 0 |
583 | 669 | ||
@@ -660,7 +746,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); | |||
660 | 746 | ||
661 | #define IS_G4X(dev) ((dev)->pci_device == 0x2E02 || \ | 747 | #define IS_G4X(dev) ((dev)->pci_device == 0x2E02 || \ |
662 | (dev)->pci_device == 0x2E12 || \ | 748 | (dev)->pci_device == 0x2E12 || \ |
663 | (dev)->pci_device == 0x2E22) | 749 | (dev)->pci_device == 0x2E22 || \ |
750 | IS_GM45(dev)) | ||
664 | 751 | ||
665 | #define IS_G33(dev) ((dev)->pci_device == 0x29C2 || \ | 752 | #define IS_G33(dev) ((dev)->pci_device == 0x29C2 || \ |
666 | (dev)->pci_device == 0x29B2 || \ | 753 | (dev)->pci_device == 0x29B2 || \ |
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 24fe8c10b4b2..cc2ca5561feb 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, |
@@ -51,34 +50,43 @@ static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *o | |||
51 | static int i915_gem_object_get_page_list(struct drm_gem_object *obj); | 50 | static int i915_gem_object_get_page_list(struct drm_gem_object *obj); |
52 | static void i915_gem_object_free_page_list(struct drm_gem_object *obj); | 51 | static void i915_gem_object_free_page_list(struct drm_gem_object *obj); |
53 | static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); | 52 | static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); |
53 | static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, | ||
54 | unsigned alignment); | ||
55 | static void i915_gem_object_get_fence_reg(struct drm_gem_object *obj); | ||
56 | static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); | ||
57 | static int i915_gem_evict_something(struct drm_device *dev); | ||
58 | |||
59 | int i915_gem_do_init(struct drm_device *dev, unsigned long start, | ||
60 | unsigned long end) | ||
61 | { | ||
62 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
54 | 63 | ||
55 | static void | 64 | if (start >= end || |
56 | i915_gem_cleanup_ringbuffer(struct drm_device *dev); | 65 | (start & (PAGE_SIZE - 1)) != 0 || |
66 | (end & (PAGE_SIZE - 1)) != 0) { | ||
67 | return -EINVAL; | ||
68 | } | ||
69 | |||
70 | drm_mm_init(&dev_priv->mm.gtt_space, start, | ||
71 | end - start); | ||
72 | |||
73 | dev->gtt_total = (uint32_t) (end - start); | ||
74 | |||
75 | return 0; | ||
76 | } | ||
57 | 77 | ||
58 | int | 78 | int |
59 | i915_gem_init_ioctl(struct drm_device *dev, void *data, | 79 | i915_gem_init_ioctl(struct drm_device *dev, void *data, |
60 | struct drm_file *file_priv) | 80 | struct drm_file *file_priv) |
61 | { | 81 | { |
62 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
63 | struct drm_i915_gem_init *args = data; | 82 | struct drm_i915_gem_init *args = data; |
83 | int ret; | ||
64 | 84 | ||
65 | mutex_lock(&dev->struct_mutex); | 85 | mutex_lock(&dev->struct_mutex); |
66 | 86 | ret = i915_gem_do_init(dev, args->gtt_start, args->gtt_end); | |
67 | if (args->gtt_start >= args->gtt_end || | ||
68 | (args->gtt_start & (PAGE_SIZE - 1)) != 0 || | ||
69 | (args->gtt_end & (PAGE_SIZE - 1)) != 0) { | ||
70 | mutex_unlock(&dev->struct_mutex); | ||
71 | return -EINVAL; | ||
72 | } | ||
73 | |||
74 | drm_mm_init(&dev_priv->mm.gtt_space, args->gtt_start, | ||
75 | args->gtt_end - args->gtt_start); | ||
76 | |||
77 | dev->gtt_total = (uint32_t) (args->gtt_end - args->gtt_start); | ||
78 | |||
79 | mutex_unlock(&dev->struct_mutex); | 87 | mutex_unlock(&dev->struct_mutex); |
80 | 88 | ||
81 | return 0; | 89 | return ret; |
82 | } | 90 | } |
83 | 91 | ||
84 | int | 92 | int |
@@ -529,6 +537,252 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, | |||
529 | return 0; | 537 | return 0; |
530 | } | 538 | } |
531 | 539 | ||
540 | /** | ||
541 | * i915_gem_fault - fault a page into the GTT | ||
542 | * vma: VMA in question | ||
543 | * vmf: fault info | ||
544 | * | ||
545 | * The fault handler is set up by drm_gem_mmap() when a object is GTT mapped | ||
546 | * from userspace. The fault handler takes care of binding the object to | ||
547 | * the GTT (if needed), allocating and programming a fence register (again, | ||
548 | * only if needed based on whether the old reg is still valid or the object | ||
549 | * is tiled) and inserting a new PTE into the faulting process. | ||
550 | * | ||
551 | * Note that the faulting process may involve evicting existing objects | ||
552 | * from the GTT and/or fence registers to make room. So performance may | ||
553 | * suffer if the GTT working set is large or there are few fence registers | ||
554 | * left. | ||
555 | */ | ||
556 | int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | ||
557 | { | ||
558 | struct drm_gem_object *obj = vma->vm_private_data; | ||
559 | struct drm_device *dev = obj->dev; | ||
560 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
561 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
562 | pgoff_t page_offset; | ||
563 | unsigned long pfn; | ||
564 | int ret = 0; | ||
565 | |||
566 | /* We don't use vmf->pgoff since that has the fake offset */ | ||
567 | page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> | ||
568 | PAGE_SHIFT; | ||
569 | |||
570 | /* Now bind it into the GTT if needed */ | ||
571 | mutex_lock(&dev->struct_mutex); | ||
572 | if (!obj_priv->gtt_space) { | ||
573 | ret = i915_gem_object_bind_to_gtt(obj, obj_priv->gtt_alignment); | ||
574 | if (ret) { | ||
575 | mutex_unlock(&dev->struct_mutex); | ||
576 | return VM_FAULT_SIGBUS; | ||
577 | } | ||
578 | list_add(&obj_priv->list, &dev_priv->mm.inactive_list); | ||
579 | } | ||
580 | |||
581 | /* Need a new fence register? */ | ||
582 | if (obj_priv->fence_reg == I915_FENCE_REG_NONE && | ||
583 | obj_priv->tiling_mode != I915_TILING_NONE) | ||
584 | i915_gem_object_get_fence_reg(obj); | ||
585 | |||
586 | pfn = ((dev->agp->base + obj_priv->gtt_offset) >> PAGE_SHIFT) + | ||
587 | page_offset; | ||
588 | |||
589 | /* Finally, remap it using the new GTT offset */ | ||
590 | ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); | ||
591 | |||
592 | mutex_unlock(&dev->struct_mutex); | ||
593 | |||
594 | switch (ret) { | ||
595 | case -ENOMEM: | ||
596 | case -EAGAIN: | ||
597 | return VM_FAULT_OOM; | ||
598 | case -EFAULT: | ||
599 | case -EBUSY: | ||
600 | DRM_ERROR("can't insert pfn?? fault or busy...\n"); | ||
601 | return VM_FAULT_SIGBUS; | ||
602 | default: | ||
603 | return VM_FAULT_NOPAGE; | ||
604 | } | ||
605 | } | ||
606 | |||
607 | /** | ||
608 | * i915_gem_create_mmap_offset - create a fake mmap offset for an object | ||
609 | * @obj: obj in question | ||
610 | * | ||
611 | * GEM memory mapping works by handing back to userspace a fake mmap offset | ||
612 | * it can use in a subsequent mmap(2) call. The DRM core code then looks | ||
613 | * up the object based on the offset and sets up the various memory mapping | ||
614 | * structures. | ||
615 | * | ||
616 | * This routine allocates and attaches a fake offset for @obj. | ||
617 | */ | ||
618 | static int | ||
619 | i915_gem_create_mmap_offset(struct drm_gem_object *obj) | ||
620 | { | ||
621 | struct drm_device *dev = obj->dev; | ||
622 | struct drm_gem_mm *mm = dev->mm_private; | ||
623 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
624 | struct drm_map_list *list; | ||
625 | struct drm_map *map; | ||
626 | int ret = 0; | ||
627 | |||
628 | /* Set the object up for mmap'ing */ | ||
629 | list = &obj->map_list; | ||
630 | list->map = drm_calloc(1, sizeof(struct drm_map_list), | ||
631 | DRM_MEM_DRIVER); | ||
632 | if (!list->map) | ||
633 | return -ENOMEM; | ||
634 | |||
635 | map = list->map; | ||
636 | map->type = _DRM_GEM; | ||
637 | map->size = obj->size; | ||
638 | map->handle = obj; | ||
639 | |||
640 | /* Get a DRM GEM mmap offset allocated... */ | ||
641 | list->file_offset_node = drm_mm_search_free(&mm->offset_manager, | ||
642 | obj->size / PAGE_SIZE, 0, 0); | ||
643 | if (!list->file_offset_node) { | ||
644 | DRM_ERROR("failed to allocate offset for bo %d\n", obj->name); | ||
645 | ret = -ENOMEM; | ||
646 | goto out_free_list; | ||
647 | } | ||
648 | |||
649 | list->file_offset_node = drm_mm_get_block(list->file_offset_node, | ||
650 | obj->size / PAGE_SIZE, 0); | ||
651 | if (!list->file_offset_node) { | ||
652 | ret = -ENOMEM; | ||
653 | goto out_free_list; | ||
654 | } | ||
655 | |||
656 | list->hash.key = list->file_offset_node->start; | ||
657 | if (drm_ht_insert_item(&mm->offset_hash, &list->hash)) { | ||
658 | DRM_ERROR("failed to add to map hash\n"); | ||
659 | goto out_free_mm; | ||
660 | } | ||
661 | |||
662 | /* By now we should be all set, any drm_mmap request on the offset | ||
663 | * below will get to our mmap & fault handler */ | ||
664 | obj_priv->mmap_offset = ((uint64_t) list->hash.key) << PAGE_SHIFT; | ||
665 | |||
666 | return 0; | ||
667 | |||
668 | out_free_mm: | ||
669 | drm_mm_put_block(list->file_offset_node); | ||
670 | out_free_list: | ||
671 | drm_free(list->map, sizeof(struct drm_map_list), DRM_MEM_DRIVER); | ||
672 | |||
673 | return ret; | ||
674 | } | ||
675 | |||
676 | /** | ||
677 | * i915_gem_get_gtt_alignment - return required GTT alignment for an object | ||
678 | * @obj: object to check | ||
679 | * | ||
680 | * Return the required GTT alignment for an object, taking into account | ||
681 | * potential fence register mapping if needed. | ||
682 | */ | ||
683 | static uint32_t | ||
684 | i915_gem_get_gtt_alignment(struct drm_gem_object *obj) | ||
685 | { | ||
686 | struct drm_device *dev = obj->dev; | ||
687 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
688 | int start, i; | ||
689 | |||
690 | /* | ||
691 | * Minimum alignment is 4k (GTT page size), but might be greater | ||
692 | * if a fence register is needed for the object. | ||
693 | */ | ||
694 | if (IS_I965G(dev) || obj_priv->tiling_mode == I915_TILING_NONE) | ||
695 | return 4096; | ||
696 | |||
697 | /* | ||
698 | * Previous chips need to be aligned to the size of the smallest | ||
699 | * fence register that can contain the object. | ||
700 | */ | ||
701 | if (IS_I9XX(dev)) | ||
702 | start = 1024*1024; | ||
703 | else | ||
704 | start = 512*1024; | ||
705 | |||
706 | for (i = start; i < obj->size; i <<= 1) | ||
707 | ; | ||
708 | |||
709 | return i; | ||
710 | } | ||
711 | |||
712 | /** | ||
713 | * i915_gem_mmap_gtt_ioctl - prepare an object for GTT mmap'ing | ||
714 | * @dev: DRM device | ||
715 | * @data: GTT mapping ioctl data | ||
716 | * @file_priv: GEM object info | ||
717 | * | ||
718 | * Simply returns the fake offset to userspace so it can mmap it. | ||
719 | * The mmap call will end up in drm_gem_mmap(), which will set things | ||
720 | * up so we can get faults in the handler above. | ||
721 | * | ||
722 | * The fault handler will take care of binding the object into the GTT | ||
723 | * (since it may have been evicted to make room for something), allocating | ||
724 | * a fence register, and mapping the appropriate aperture address into | ||
725 | * userspace. | ||
726 | */ | ||
727 | int | ||
728 | i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, | ||
729 | struct drm_file *file_priv) | ||
730 | { | ||
731 | struct drm_i915_gem_mmap_gtt *args = data; | ||
732 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
733 | struct drm_gem_object *obj; | ||
734 | struct drm_i915_gem_object *obj_priv; | ||
735 | int ret; | ||
736 | |||
737 | if (!(dev->driver->driver_features & DRIVER_GEM)) | ||
738 | return -ENODEV; | ||
739 | |||
740 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | ||
741 | if (obj == NULL) | ||
742 | return -EBADF; | ||
743 | |||
744 | mutex_lock(&dev->struct_mutex); | ||
745 | |||
746 | obj_priv = obj->driver_private; | ||
747 | |||
748 | if (!obj_priv->mmap_offset) { | ||
749 | ret = i915_gem_create_mmap_offset(obj); | ||
750 | if (ret) | ||
751 | return ret; | ||
752 | } | ||
753 | |||
754 | args->offset = obj_priv->mmap_offset; | ||
755 | |||
756 | obj_priv->gtt_alignment = i915_gem_get_gtt_alignment(obj); | ||
757 | |||
758 | /* Make sure the alignment is correct for fence regs etc */ | ||
759 | if (obj_priv->agp_mem && | ||
760 | (obj_priv->gtt_offset & (obj_priv->gtt_alignment - 1))) { | ||
761 | drm_gem_object_unreference(obj); | ||
762 | mutex_unlock(&dev->struct_mutex); | ||
763 | return -EINVAL; | ||
764 | } | ||
765 | |||
766 | /* | ||
767 | * Pull it into the GTT so that we have a page list (makes the | ||
768 | * initial fault faster and any subsequent flushing possible). | ||
769 | */ | ||
770 | if (!obj_priv->agp_mem) { | ||
771 | ret = i915_gem_object_bind_to_gtt(obj, obj_priv->gtt_alignment); | ||
772 | if (ret) { | ||
773 | drm_gem_object_unreference(obj); | ||
774 | mutex_unlock(&dev->struct_mutex); | ||
775 | return ret; | ||
776 | } | ||
777 | list_add(&obj_priv->list, &dev_priv->mm.inactive_list); | ||
778 | } | ||
779 | |||
780 | drm_gem_object_unreference(obj); | ||
781 | mutex_unlock(&dev->struct_mutex); | ||
782 | |||
783 | return 0; | ||
784 | } | ||
785 | |||
532 | static void | 786 | static void |
533 | i915_gem_object_free_page_list(struct drm_gem_object *obj) | 787 | i915_gem_object_free_page_list(struct drm_gem_object *obj) |
534 | { | 788 | { |
@@ -726,6 +980,7 @@ i915_gem_retire_request(struct drm_device *dev, | |||
726 | */ | 980 | */ |
727 | if (obj_priv->last_rendering_seqno != request->seqno) | 981 | if (obj_priv->last_rendering_seqno != request->seqno) |
728 | return; | 982 | return; |
983 | |||
729 | #if WATCH_LRU | 984 | #if WATCH_LRU |
730 | DRM_INFO("%s: retire %d moves to inactive list %p\n", | 985 | DRM_INFO("%s: retire %d moves to inactive list %p\n", |
731 | __func__, request->seqno, obj); | 986 | __func__, request->seqno, obj); |
@@ -956,6 +1211,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj) | |||
956 | { | 1211 | { |
957 | struct drm_device *dev = obj->dev; | 1212 | struct drm_device *dev = obj->dev; |
958 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | 1213 | struct drm_i915_gem_object *obj_priv = obj->driver_private; |
1214 | loff_t offset; | ||
959 | int ret = 0; | 1215 | int ret = 0; |
960 | 1216 | ||
961 | #if WATCH_BUF | 1217 | #if WATCH_BUF |
@@ -991,6 +1247,14 @@ i915_gem_object_unbind(struct drm_gem_object *obj) | |||
991 | 1247 | ||
992 | BUG_ON(obj_priv->active); | 1248 | BUG_ON(obj_priv->active); |
993 | 1249 | ||
1250 | /* blow away mappings if mapped through GTT */ | ||
1251 | offset = ((loff_t) obj->map_list.hash.key) << PAGE_SHIFT; | ||
1252 | if (dev->dev_mapping) | ||
1253 | unmap_mapping_range(dev->dev_mapping, offset, obj->size, 1); | ||
1254 | |||
1255 | if (obj_priv->fence_reg != I915_FENCE_REG_NONE) | ||
1256 | i915_gem_clear_fence_reg(obj); | ||
1257 | |||
994 | i915_gem_object_free_page_list(obj); | 1258 | i915_gem_object_free_page_list(obj); |
995 | 1259 | ||
996 | if (obj_priv->gtt_space) { | 1260 | if (obj_priv->gtt_space) { |
@@ -1149,6 +1413,204 @@ i915_gem_object_get_page_list(struct drm_gem_object *obj) | |||
1149 | return 0; | 1413 | return 0; |
1150 | } | 1414 | } |
1151 | 1415 | ||
1416 | static void i965_write_fence_reg(struct drm_i915_fence_reg *reg) | ||
1417 | { | ||
1418 | struct drm_gem_object *obj = reg->obj; | ||
1419 | struct drm_device *dev = obj->dev; | ||
1420 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
1421 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
1422 | int regnum = obj_priv->fence_reg; | ||
1423 | uint64_t val; | ||
1424 | |||
1425 | val = (uint64_t)((obj_priv->gtt_offset + obj->size - 4096) & | ||
1426 | 0xfffff000) << 32; | ||
1427 | val |= obj_priv->gtt_offset & 0xfffff000; | ||
1428 | val |= ((obj_priv->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT; | ||
1429 | if (obj_priv->tiling_mode == I915_TILING_Y) | ||
1430 | val |= 1 << I965_FENCE_TILING_Y_SHIFT; | ||
1431 | val |= I965_FENCE_REG_VALID; | ||
1432 | |||
1433 | I915_WRITE64(FENCE_REG_965_0 + (regnum * 8), val); | ||
1434 | } | ||
1435 | |||
1436 | static void i915_write_fence_reg(struct drm_i915_fence_reg *reg) | ||
1437 | { | ||
1438 | struct drm_gem_object *obj = reg->obj; | ||
1439 | struct drm_device *dev = obj->dev; | ||
1440 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
1441 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
1442 | int regnum = obj_priv->fence_reg; | ||
1443 | uint32_t val; | ||
1444 | uint32_t pitch_val; | ||
1445 | |||
1446 | if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) || | ||
1447 | (obj_priv->gtt_offset & (obj->size - 1))) { | ||
1448 | WARN(1, "%s: object not 1M or size aligned\n", __FUNCTION__); | ||
1449 | return; | ||
1450 | } | ||
1451 | |||
1452 | if (obj_priv->tiling_mode == I915_TILING_Y && (IS_I945G(dev) || | ||
1453 | IS_I945GM(dev) || | ||
1454 | IS_G33(dev))) | ||
1455 | pitch_val = (obj_priv->stride / 128) - 1; | ||
1456 | else | ||
1457 | pitch_val = (obj_priv->stride / 512) - 1; | ||
1458 | |||
1459 | val = obj_priv->gtt_offset; | ||
1460 | if (obj_priv->tiling_mode == I915_TILING_Y) | ||
1461 | val |= 1 << I830_FENCE_TILING_Y_SHIFT; | ||
1462 | val |= I915_FENCE_SIZE_BITS(obj->size); | ||
1463 | val |= pitch_val << I830_FENCE_PITCH_SHIFT; | ||
1464 | val |= I830_FENCE_REG_VALID; | ||
1465 | |||
1466 | I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val); | ||
1467 | } | ||
1468 | |||
1469 | static void i830_write_fence_reg(struct drm_i915_fence_reg *reg) | ||
1470 | { | ||
1471 | struct drm_gem_object *obj = reg->obj; | ||
1472 | struct drm_device *dev = obj->dev; | ||
1473 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
1474 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
1475 | int regnum = obj_priv->fence_reg; | ||
1476 | uint32_t val; | ||
1477 | uint32_t pitch_val; | ||
1478 | |||
1479 | if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) || | ||
1480 | (obj_priv->gtt_offset & (obj->size - 1))) { | ||
1481 | WARN(1, "%s: object not 1M or size aligned\n", __FUNCTION__); | ||
1482 | return; | ||
1483 | } | ||
1484 | |||
1485 | pitch_val = (obj_priv->stride / 128) - 1; | ||
1486 | |||
1487 | val = obj_priv->gtt_offset; | ||
1488 | if (obj_priv->tiling_mode == I915_TILING_Y) | ||
1489 | val |= 1 << I830_FENCE_TILING_Y_SHIFT; | ||
1490 | val |= I830_FENCE_SIZE_BITS(obj->size); | ||
1491 | val |= pitch_val << I830_FENCE_PITCH_SHIFT; | ||
1492 | val |= I830_FENCE_REG_VALID; | ||
1493 | |||
1494 | I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val); | ||
1495 | |||
1496 | } | ||
1497 | |||
1498 | /** | ||
1499 | * i915_gem_object_get_fence_reg - set up a fence reg for an object | ||
1500 | * @obj: object to map through a fence reg | ||
1501 | * | ||
1502 | * When mapping objects through the GTT, userspace wants to be able to write | ||
1503 | * to them without having to worry about swizzling if the object is tiled. | ||
1504 | * | ||
1505 | * This function walks the fence regs looking for a free one for @obj, | ||
1506 | * stealing one if it can't find any. | ||
1507 | * | ||
1508 | * It then sets up the reg based on the object's properties: address, pitch | ||
1509 | * and tiling format. | ||
1510 | */ | ||
1511 | static void | ||
1512 | i915_gem_object_get_fence_reg(struct drm_gem_object *obj) | ||
1513 | { | ||
1514 | struct drm_device *dev = obj->dev; | ||
1515 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
1516 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
1517 | struct drm_i915_fence_reg *reg = NULL; | ||
1518 | int i, ret; | ||
1519 | |||
1520 | switch (obj_priv->tiling_mode) { | ||
1521 | case I915_TILING_NONE: | ||
1522 | WARN(1, "allocating a fence for non-tiled object?\n"); | ||
1523 | break; | ||
1524 | case I915_TILING_X: | ||
1525 | WARN(obj_priv->stride & (512 - 1), | ||
1526 | "object is X tiled but has non-512B pitch\n"); | ||
1527 | break; | ||
1528 | case I915_TILING_Y: | ||
1529 | WARN(obj_priv->stride & (128 - 1), | ||
1530 | "object is Y tiled but has non-128B pitch\n"); | ||
1531 | break; | ||
1532 | } | ||
1533 | |||
1534 | /* First try to find a free reg */ | ||
1535 | for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { | ||
1536 | reg = &dev_priv->fence_regs[i]; | ||
1537 | if (!reg->obj) | ||
1538 | break; | ||
1539 | } | ||
1540 | |||
1541 | /* None available, try to steal one or wait for a user to finish */ | ||
1542 | if (i == dev_priv->num_fence_regs) { | ||
1543 | struct drm_i915_gem_object *old_obj_priv = NULL; | ||
1544 | loff_t offset; | ||
1545 | |||
1546 | try_again: | ||
1547 | /* Could try to use LRU here instead... */ | ||
1548 | for (i = dev_priv->fence_reg_start; | ||
1549 | i < dev_priv->num_fence_regs; i++) { | ||
1550 | reg = &dev_priv->fence_regs[i]; | ||
1551 | old_obj_priv = reg->obj->driver_private; | ||
1552 | if (!old_obj_priv->pin_count) | ||
1553 | break; | ||
1554 | } | ||
1555 | |||
1556 | /* | ||
1557 | * Now things get ugly... we have to wait for one of the | ||
1558 | * objects to finish before trying again. | ||
1559 | */ | ||
1560 | if (i == dev_priv->num_fence_regs) { | ||
1561 | ret = i915_gem_object_wait_rendering(reg->obj); | ||
1562 | if (ret) { | ||
1563 | WARN(ret, "wait_rendering failed: %d\n", ret); | ||
1564 | return; | ||
1565 | } | ||
1566 | goto try_again; | ||
1567 | } | ||
1568 | |||
1569 | /* | ||
1570 | * Zap this virtual mapping so we can set up a fence again | ||
1571 | * for this object next time we need it. | ||
1572 | */ | ||
1573 | offset = ((loff_t) reg->obj->map_list.hash.key) << PAGE_SHIFT; | ||
1574 | if (dev->dev_mapping) | ||
1575 | unmap_mapping_range(dev->dev_mapping, offset, | ||
1576 | reg->obj->size, 1); | ||
1577 | old_obj_priv->fence_reg = I915_FENCE_REG_NONE; | ||
1578 | } | ||
1579 | |||
1580 | obj_priv->fence_reg = i; | ||
1581 | reg->obj = obj; | ||
1582 | |||
1583 | if (IS_I965G(dev)) | ||
1584 | i965_write_fence_reg(reg); | ||
1585 | else if (IS_I9XX(dev)) | ||
1586 | i915_write_fence_reg(reg); | ||
1587 | else | ||
1588 | i830_write_fence_reg(reg); | ||
1589 | } | ||
1590 | |||
1591 | /** | ||
1592 | * i915_gem_clear_fence_reg - clear out fence register info | ||
1593 | * @obj: object to clear | ||
1594 | * | ||
1595 | * Zeroes out the fence register itself and clears out the associated | ||
1596 | * data structures in dev_priv and obj_priv. | ||
1597 | */ | ||
1598 | static void | ||
1599 | i915_gem_clear_fence_reg(struct drm_gem_object *obj) | ||
1600 | { | ||
1601 | struct drm_device *dev = obj->dev; | ||
1602 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
1603 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
1604 | |||
1605 | if (IS_I965G(dev)) | ||
1606 | I915_WRITE64(FENCE_REG_965_0 + (obj_priv->fence_reg * 8), 0); | ||
1607 | else | ||
1608 | I915_WRITE(FENCE_REG_830_0 + (obj_priv->fence_reg * 4), 0); | ||
1609 | |||
1610 | dev_priv->fence_regs[obj_priv->fence_reg].obj = NULL; | ||
1611 | obj_priv->fence_reg = I915_FENCE_REG_NONE; | ||
1612 | } | ||
1613 | |||
1152 | /** | 1614 | /** |
1153 | * Finds free space in the GTT aperture and binds the object there. | 1615 | * Finds free space in the GTT aperture and binds the object there. |
1154 | */ | 1616 | */ |
@@ -1307,7 +1769,7 @@ i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj) | |||
1307 | * This function returns when the move is complete, including waiting on | 1769 | * This function returns when the move is complete, including waiting on |
1308 | * flushes to occur. | 1770 | * flushes to occur. |
1309 | */ | 1771 | */ |
1310 | static int | 1772 | int |
1311 | 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) |
1312 | { | 1774 | { |
1313 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | 1775 | struct drm_i915_gem_object *obj_priv = obj->driver_private; |
@@ -2029,13 +2491,15 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, | |||
2029 | 2491 | ||
2030 | /* error other than GTT full, or we've already tried again */ | 2492 | /* error other than GTT full, or we've already tried again */ |
2031 | if (ret != -ENOMEM || pin_tries >= 1) { | 2493 | if (ret != -ENOMEM || pin_tries >= 1) { |
2032 | DRM_ERROR("Failed to pin buffers %d\n", ret); | 2494 | if (ret != -ERESTARTSYS) |
2495 | DRM_ERROR("Failed to pin buffers %d\n", ret); | ||
2033 | goto err; | 2496 | goto err; |
2034 | } | 2497 | } |
2035 | 2498 | ||
2036 | /* unpin all of our buffers */ | 2499 | /* unpin all of our buffers */ |
2037 | for (i = 0; i < pinned; i++) | 2500 | for (i = 0; i < pinned; i++) |
2038 | i915_gem_object_unpin(object_list[i]); | 2501 | i915_gem_object_unpin(object_list[i]); |
2502 | pinned = 0; | ||
2039 | 2503 | ||
2040 | /* evict everyone we can from the aperture */ | 2504 | /* evict everyone we can from the aperture */ |
2041 | ret = i915_gem_evict_everything(dev); | 2505 | ret = i915_gem_evict_everything(dev); |
@@ -2149,13 +2613,12 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, | |||
2149 | "back to user (%d)\n", | 2613 | "back to user (%d)\n", |
2150 | args->buffer_count, ret); | 2614 | args->buffer_count, ret); |
2151 | err: | 2615 | err: |
2152 | if (object_list != NULL) { | 2616 | for (i = 0; i < pinned; i++) |
2153 | for (i = 0; i < pinned; i++) | 2617 | i915_gem_object_unpin(object_list[i]); |
2154 | i915_gem_object_unpin(object_list[i]); | 2618 | |
2619 | for (i = 0; i < args->buffer_count; i++) | ||
2620 | drm_gem_object_unreference(object_list[i]); | ||
2155 | 2621 | ||
2156 | for (i = 0; i < args->buffer_count; i++) | ||
2157 | drm_gem_object_unreference(object_list[i]); | ||
2158 | } | ||
2159 | mutex_unlock(&dev->struct_mutex); | 2622 | mutex_unlock(&dev->struct_mutex); |
2160 | 2623 | ||
2161 | pre_mutex_err: | 2624 | pre_mutex_err: |
@@ -2178,7 +2641,8 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) | |||
2178 | if (obj_priv->gtt_space == NULL) { | 2641 | if (obj_priv->gtt_space == NULL) { |
2179 | ret = i915_gem_object_bind_to_gtt(obj, alignment); | 2642 | ret = i915_gem_object_bind_to_gtt(obj, alignment); |
2180 | if (ret != 0) { | 2643 | if (ret != 0) { |
2181 | DRM_ERROR("Failure to bind: %d", ret); | 2644 | if (ret != -ERESTARTSYS) |
2645 | DRM_ERROR("Failure to bind: %d", ret); | ||
2182 | return ret; | 2646 | return ret; |
2183 | } | 2647 | } |
2184 | } | 2648 | } |
@@ -2249,11 +2713,22 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data, | |||
2249 | } | 2713 | } |
2250 | obj_priv = obj->driver_private; | 2714 | obj_priv = obj->driver_private; |
2251 | 2715 | ||
2252 | ret = i915_gem_object_pin(obj, args->alignment); | 2716 | if (obj_priv->pin_filp != NULL && obj_priv->pin_filp != file_priv) { |
2253 | if (ret != 0) { | 2717 | DRM_ERROR("Already pinned in i915_gem_pin_ioctl(): %d\n", |
2254 | drm_gem_object_unreference(obj); | 2718 | args->handle); |
2255 | mutex_unlock(&dev->struct_mutex); | 2719 | mutex_unlock(&dev->struct_mutex); |
2256 | return ret; | 2720 | return -EINVAL; |
2721 | } | ||
2722 | |||
2723 | obj_priv->user_pin_count++; | ||
2724 | obj_priv->pin_filp = file_priv; | ||
2725 | if (obj_priv->user_pin_count == 1) { | ||
2726 | ret = i915_gem_object_pin(obj, args->alignment); | ||
2727 | if (ret != 0) { | ||
2728 | drm_gem_object_unreference(obj); | ||
2729 | mutex_unlock(&dev->struct_mutex); | ||
2730 | return ret; | ||
2731 | } | ||
2257 | } | 2732 | } |
2258 | 2733 | ||
2259 | /* XXX - flush the CPU caches for pinned objects | 2734 | /* XXX - flush the CPU caches for pinned objects |
@@ -2273,6 +2748,7 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data, | |||
2273 | { | 2748 | { |
2274 | struct drm_i915_gem_pin *args = data; | 2749 | struct drm_i915_gem_pin *args = data; |
2275 | struct drm_gem_object *obj; | 2750 | struct drm_gem_object *obj; |
2751 | struct drm_i915_gem_object *obj_priv; | ||
2276 | 2752 | ||
2277 | mutex_lock(&dev->struct_mutex); | 2753 | mutex_lock(&dev->struct_mutex); |
2278 | 2754 | ||
@@ -2284,7 +2760,19 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data, | |||
2284 | return -EBADF; | 2760 | return -EBADF; |
2285 | } | 2761 | } |
2286 | 2762 | ||
2287 | i915_gem_object_unpin(obj); | 2763 | obj_priv = obj->driver_private; |
2764 | if (obj_priv->pin_filp != file_priv) { | ||
2765 | DRM_ERROR("Not pinned by caller in i915_gem_pin_ioctl(): %d\n", | ||
2766 | args->handle); | ||
2767 | drm_gem_object_unreference(obj); | ||
2768 | mutex_unlock(&dev->struct_mutex); | ||
2769 | return -EINVAL; | ||
2770 | } | ||
2771 | obj_priv->user_pin_count--; | ||
2772 | if (obj_priv->user_pin_count == 0) { | ||
2773 | obj_priv->pin_filp = NULL; | ||
2774 | i915_gem_object_unpin(obj); | ||
2775 | } | ||
2288 | 2776 | ||
2289 | drm_gem_object_unreference(obj); | 2777 | drm_gem_object_unreference(obj); |
2290 | mutex_unlock(&dev->struct_mutex); | 2778 | mutex_unlock(&dev->struct_mutex); |
@@ -2351,12 +2839,18 @@ int i915_gem_init_object(struct drm_gem_object *obj) | |||
2351 | 2839 | ||
2352 | obj->driver_private = obj_priv; | 2840 | obj->driver_private = obj_priv; |
2353 | obj_priv->obj = obj; | 2841 | obj_priv->obj = obj; |
2842 | obj_priv->fence_reg = I915_FENCE_REG_NONE; | ||
2354 | INIT_LIST_HEAD(&obj_priv->list); | 2843 | INIT_LIST_HEAD(&obj_priv->list); |
2844 | |||
2355 | return 0; | 2845 | return 0; |
2356 | } | 2846 | } |
2357 | 2847 | ||
2358 | void i915_gem_free_object(struct drm_gem_object *obj) | 2848 | void i915_gem_free_object(struct drm_gem_object *obj) |
2359 | { | 2849 | { |
2850 | struct drm_device *dev = obj->dev; | ||
2851 | struct drm_gem_mm *mm = dev->mm_private; | ||
2852 | struct drm_map_list *list; | ||
2853 | struct drm_map *map; | ||
2360 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | 2854 | struct drm_i915_gem_object *obj_priv = obj->driver_private; |
2361 | 2855 | ||
2362 | while (obj_priv->pin_count > 0) | 2856 | while (obj_priv->pin_count > 0) |
@@ -2364,6 +2858,20 @@ void i915_gem_free_object(struct drm_gem_object *obj) | |||
2364 | 2858 | ||
2365 | i915_gem_object_unbind(obj); | 2859 | i915_gem_object_unbind(obj); |
2366 | 2860 | ||
2861 | list = &obj->map_list; | ||
2862 | drm_ht_remove_item(&mm->offset_hash, &list->hash); | ||
2863 | |||
2864 | if (list->file_offset_node) { | ||
2865 | drm_mm_put_block(list->file_offset_node); | ||
2866 | list->file_offset_node = NULL; | ||
2867 | } | ||
2868 | |||
2869 | map = list->map; | ||
2870 | if (map) { | ||
2871 | drm_free(map, sizeof(*map), DRM_MEM_DRIVER); | ||
2872 | list->map = NULL; | ||
2873 | } | ||
2874 | |||
2367 | drm_free(obj_priv->page_cpu_valid, 1, DRM_MEM_DRIVER); | 2875 | drm_free(obj_priv->page_cpu_valid, 1, DRM_MEM_DRIVER); |
2368 | drm_free(obj->driver_private, 1, DRM_MEM_DRIVER); | 2876 | drm_free(obj->driver_private, 1, DRM_MEM_DRIVER); |
2369 | } | 2877 | } |
@@ -2432,8 +2940,7 @@ i915_gem_idle(struct drm_device *dev) | |||
2432 | */ | 2940 | */ |
2433 | i915_gem_flush(dev, ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT), | 2941 | i915_gem_flush(dev, ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT), |
2434 | ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)); | 2942 | ~(I915_GEM_DOMAIN_CPU|I915_GEM_DOMAIN_GTT)); |
2435 | seqno = i915_add_request(dev, ~(I915_GEM_DOMAIN_CPU | | 2943 | seqno = i915_add_request(dev, ~I915_GEM_DOMAIN_CPU); |
2436 | I915_GEM_DOMAIN_GTT)); | ||
2437 | 2944 | ||
2438 | if (seqno == 0) { | 2945 | if (seqno == 0) { |
2439 | mutex_unlock(&dev->struct_mutex); | 2946 | mutex_unlock(&dev->struct_mutex); |
@@ -2560,12 +3067,13 @@ i915_gem_init_hws(struct drm_device *dev) | |||
2560 | return 0; | 3067 | return 0; |
2561 | } | 3068 | } |
2562 | 3069 | ||
2563 | static int | 3070 | int |
2564 | i915_gem_init_ringbuffer(struct drm_device *dev) | 3071 | i915_gem_init_ringbuffer(struct drm_device *dev) |
2565 | { | 3072 | { |
2566 | drm_i915_private_t *dev_priv = dev->dev_private; | 3073 | drm_i915_private_t *dev_priv = dev->dev_private; |
2567 | struct drm_gem_object *obj; | 3074 | struct drm_gem_object *obj; |
2568 | struct drm_i915_gem_object *obj_priv; | 3075 | struct drm_i915_gem_object *obj_priv; |
3076 | drm_i915_ring_buffer_t *ring = &dev_priv->ring; | ||
2569 | int ret; | 3077 | int ret; |
2570 | u32 head; | 3078 | u32 head; |
2571 | 3079 | ||
@@ -2587,24 +3095,24 @@ i915_gem_init_ringbuffer(struct drm_device *dev) | |||
2587 | } | 3095 | } |
2588 | 3096 | ||
2589 | /* Set up the kernel mapping for the ring. */ | 3097 | /* Set up the kernel mapping for the ring. */ |
2590 | dev_priv->ring.Size = obj->size; | 3098 | ring->Size = obj->size; |
2591 | dev_priv->ring.tail_mask = obj->size - 1; | 3099 | ring->tail_mask = obj->size - 1; |
2592 | 3100 | ||
2593 | dev_priv->ring.map.offset = dev->agp->base + obj_priv->gtt_offset; | 3101 | ring->map.offset = dev->agp->base + obj_priv->gtt_offset; |
2594 | dev_priv->ring.map.size = obj->size; | 3102 | ring->map.size = obj->size; |
2595 | dev_priv->ring.map.type = 0; | 3103 | ring->map.type = 0; |
2596 | dev_priv->ring.map.flags = 0; | 3104 | ring->map.flags = 0; |
2597 | dev_priv->ring.map.mtrr = 0; | 3105 | ring->map.mtrr = 0; |
2598 | 3106 | ||
2599 | drm_core_ioremap_wc(&dev_priv->ring.map, dev); | 3107 | drm_core_ioremap_wc(&ring->map, dev); |
2600 | if (dev_priv->ring.map.handle == NULL) { | 3108 | if (ring->map.handle == NULL) { |
2601 | DRM_ERROR("Failed to map ringbuffer.\n"); | 3109 | DRM_ERROR("Failed to map ringbuffer.\n"); |
2602 | memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); | 3110 | memset(&dev_priv->ring, 0, sizeof(dev_priv->ring)); |
2603 | drm_gem_object_unreference(obj); | 3111 | drm_gem_object_unreference(obj); |
2604 | return -EINVAL; | 3112 | return -EINVAL; |
2605 | } | 3113 | } |
2606 | dev_priv->ring.ring_obj = obj; | 3114 | ring->ring_obj = obj; |
2607 | dev_priv->ring.virtual_start = dev_priv->ring.map.handle; | 3115 | ring->virtual_start = ring->map.handle; |
2608 | 3116 | ||
2609 | /* Stop the ring if it's running. */ | 3117 | /* Stop the ring if it's running. */ |
2610 | I915_WRITE(PRB0_CTL, 0); | 3118 | I915_WRITE(PRB0_CTL, 0); |
@@ -2652,12 +3160,20 @@ i915_gem_init_ringbuffer(struct drm_device *dev) | |||
2652 | } | 3160 | } |
2653 | 3161 | ||
2654 | /* Update our cache of the ring state */ | 3162 | /* Update our cache of the ring state */ |
2655 | i915_kernel_lost_context(dev); | 3163 | if (!drm_core_check_feature(dev, DRIVER_MODESET)) |
3164 | i915_kernel_lost_context(dev); | ||
3165 | else { | ||
3166 | ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR; | ||
3167 | ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR; | ||
3168 | ring->space = ring->head - (ring->tail + 8); | ||
3169 | if (ring->space < 0) | ||
3170 | ring->space += ring->Size; | ||
3171 | } | ||
2656 | 3172 | ||
2657 | return 0; | 3173 | return 0; |
2658 | } | 3174 | } |
2659 | 3175 | ||
2660 | static void | 3176 | void |
2661 | i915_gem_cleanup_ringbuffer(struct drm_device *dev) | 3177 | i915_gem_cleanup_ringbuffer(struct drm_device *dev) |
2662 | { | 3178 | { |
2663 | drm_i915_private_t *dev_priv = dev->dev_private; | 3179 | drm_i915_private_t *dev_priv = dev->dev_private; |
@@ -2695,6 +3211,9 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, | |||
2695 | drm_i915_private_t *dev_priv = dev->dev_private; | 3211 | drm_i915_private_t *dev_priv = dev->dev_private; |
2696 | int ret; | 3212 | int ret; |
2697 | 3213 | ||
3214 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
3215 | return 0; | ||
3216 | |||
2698 | if (dev_priv->mm.wedged) { | 3217 | if (dev_priv->mm.wedged) { |
2699 | DRM_ERROR("Reenabling wedged hardware, good luck\n"); | 3218 | DRM_ERROR("Reenabling wedged hardware, good luck\n"); |
2700 | dev_priv->mm.wedged = 0; | 3219 | dev_priv->mm.wedged = 0; |
@@ -2728,6 +3247,9 @@ i915_gem_leavevt_ioctl(struct drm_device *dev, void *data, | |||
2728 | drm_i915_private_t *dev_priv = dev->dev_private; | 3247 | drm_i915_private_t *dev_priv = dev->dev_private; |
2729 | int ret; | 3248 | int ret; |
2730 | 3249 | ||
3250 | if (drm_core_check_feature(dev, DRIVER_MODESET)) | ||
3251 | return 0; | ||
3252 | |||
2731 | ret = i915_gem_idle(dev); | 3253 | ret = i915_gem_idle(dev); |
2732 | drm_irq_uninstall(dev); | 3254 | drm_irq_uninstall(dev); |
2733 | 3255 | ||
@@ -2758,5 +3280,13 @@ i915_gem_load(struct drm_device *dev) | |||
2758 | i915_gem_retire_work_handler); | 3280 | i915_gem_retire_work_handler); |
2759 | dev_priv->mm.next_gem_seqno = 1; | 3281 | dev_priv->mm.next_gem_seqno = 1; |
2760 | 3282 | ||
3283 | /* Old X drivers will take 0-2 for front, back, depth buffers */ | ||
3284 | dev_priv->fence_reg_start = 3; | ||
3285 | |||
3286 | if (IS_I965G(dev)) | ||
3287 | dev_priv->num_fence_regs = 16; | ||
3288 | else | ||
3289 | dev_priv->num_fence_regs = 8; | ||
3290 | |||
2761 | i915_gem_detect_bit_6_swizzle(dev); | 3291 | i915_gem_detect_bit_6_swizzle(dev); |
2762 | } | 3292 | } |
diff --git a/drivers/gpu/drm/i915/i915_gem_proc.c b/drivers/gpu/drm/i915/i915_gem_proc.c index e8d5abe1250e..4d1b9de0cd8b 100644 --- a/drivers/gpu/drm/i915/i915_gem_proc.c +++ b/drivers/gpu/drm/i915/i915_gem_proc.c | |||
@@ -250,6 +250,39 @@ static int i915_interrupt_info(char *buf, char **start, off_t offset, | |||
250 | return len - offset; | 250 | return len - offset; |
251 | } | 251 | } |
252 | 252 | ||
253 | static int i915_hws_info(char *buf, char **start, off_t offset, | ||
254 | int request, int *eof, void *data) | ||
255 | { | ||
256 | struct drm_minor *minor = (struct drm_minor *) data; | ||
257 | struct drm_device *dev = minor->dev; | ||
258 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
259 | int len = 0, i; | ||
260 | volatile u32 *hws; | ||
261 | |||
262 | if (offset > DRM_PROC_LIMIT) { | ||
263 | *eof = 1; | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | hws = (volatile u32 *)dev_priv->hw_status_page; | ||
268 | if (hws == NULL) { | ||
269 | *eof = 1; | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | *start = &buf[offset]; | ||
274 | *eof = 0; | ||
275 | for (i = 0; i < 4096 / sizeof(u32) / 4; i += 4) { | ||
276 | DRM_PROC_PRINT("0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n", | ||
277 | i * 4, | ||
278 | hws[i], hws[i + 1], hws[i + 2], hws[i + 3]); | ||
279 | } | ||
280 | if (len > request + offset) | ||
281 | return request; | ||
282 | *eof = 1; | ||
283 | return len - offset; | ||
284 | } | ||
285 | |||
253 | static struct drm_proc_list { | 286 | static struct drm_proc_list { |
254 | /** file name */ | 287 | /** file name */ |
255 | const char *name; | 288 | const char *name; |
@@ -262,6 +295,7 @@ static struct drm_proc_list { | |||
262 | {"i915_gem_request", i915_gem_request_info}, | 295 | {"i915_gem_request", i915_gem_request_info}, |
263 | {"i915_gem_seqno", i915_gem_seqno_info}, | 296 | {"i915_gem_seqno", i915_gem_seqno_info}, |
264 | {"i915_gem_interrupt", i915_interrupt_info}, | 297 | {"i915_gem_interrupt", i915_interrupt_info}, |
298 | {"i915_gem_hws", i915_hws_info}, | ||
265 | }; | 299 | }; |
266 | 300 | ||
267 | #define I915_GEM_PROC_ENTRIES ARRAY_SIZE(i915_gem_proc_list) | 301 | #define I915_GEM_PROC_ENTRIES ARRAY_SIZE(i915_gem_proc_list) |
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index a8cb69469c64..241f39b7f460 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c | |||
@@ -208,6 +208,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, | |||
208 | } | 208 | } |
209 | } | 209 | } |
210 | obj_priv->tiling_mode = args->tiling_mode; | 210 | obj_priv->tiling_mode = args->tiling_mode; |
211 | obj_priv->stride = args->stride; | ||
211 | 212 | ||
212 | mutex_unlock(&dev->struct_mutex); | 213 | mutex_unlock(&dev->struct_mutex); |
213 | 214 | ||
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 69b9a42da95e..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 | { |
@@ -168,6 +178,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | |||
168 | { | 178 | { |
169 | struct drm_device *dev = (struct drm_device *) arg; | 179 | struct drm_device *dev = (struct drm_device *) arg; |
170 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 180 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
181 | struct drm_i915_master_private *master_priv; | ||
171 | u32 iir, new_iir; | 182 | u32 iir, new_iir; |
172 | u32 pipea_stats, pipeb_stats; | 183 | u32 pipea_stats, pipeb_stats; |
173 | u32 vblank_status; | 184 | u32 vblank_status; |
@@ -200,6 +211,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | |||
200 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); | 211 | spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); |
201 | pipea_stats = I915_READ(PIPEASTAT); | 212 | pipea_stats = I915_READ(PIPEASTAT); |
202 | pipeb_stats = I915_READ(PIPEBSTAT); | 213 | pipeb_stats = I915_READ(PIPEBSTAT); |
214 | |||
203 | /* | 215 | /* |
204 | * Clear the PIPE(A|B)STAT regs before the IIR | 216 | * Clear the PIPE(A|B)STAT regs before the IIR |
205 | */ | 217 | */ |
@@ -222,9 +234,12 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | |||
222 | I915_WRITE(IIR, iir); | 234 | I915_WRITE(IIR, iir); |
223 | new_iir = I915_READ(IIR); /* Flush posted writes */ | 235 | new_iir = I915_READ(IIR); /* Flush posted writes */ |
224 | 236 | ||
225 | if (dev_priv->sarea_priv) | 237 | if (dev->primary->master) { |
226 | dev_priv->sarea_priv->last_dispatch = | 238 | master_priv = dev->primary->master->driver_priv; |
227 | READ_BREADCRUMB(dev_priv); | 239 | if (master_priv->sarea_priv) |
240 | master_priv->sarea_priv->last_dispatch = | ||
241 | READ_BREADCRUMB(dev_priv); | ||
242 | } | ||
228 | 243 | ||
229 | if (iir & I915_USER_INTERRUPT) { | 244 | if (iir & I915_USER_INTERRUPT) { |
230 | dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); | 245 | dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev); |
@@ -269,6 +284,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | |||
269 | static int i915_emit_irq(struct drm_device * dev) | 284 | static int i915_emit_irq(struct drm_device * dev) |
270 | { | 285 | { |
271 | drm_i915_private_t *dev_priv = dev->dev_private; | 286 | drm_i915_private_t *dev_priv = dev->dev_private; |
287 | struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; | ||
272 | RING_LOCALS; | 288 | RING_LOCALS; |
273 | 289 | ||
274 | i915_kernel_lost_context(dev); | 290 | i915_kernel_lost_context(dev); |
@@ -278,8 +294,8 @@ static int i915_emit_irq(struct drm_device * dev) | |||
278 | dev_priv->counter++; | 294 | dev_priv->counter++; |
279 | if (dev_priv->counter > 0x7FFFFFFFUL) | 295 | if (dev_priv->counter > 0x7FFFFFFFUL) |
280 | dev_priv->counter = 1; | 296 | dev_priv->counter = 1; |
281 | if (dev_priv->sarea_priv) | 297 | if (master_priv->sarea_priv) |
282 | dev_priv->sarea_priv->last_enqueue = dev_priv->counter; | 298 | master_priv->sarea_priv->last_enqueue = dev_priv->counter; |
283 | 299 | ||
284 | BEGIN_LP_RING(4); | 300 | BEGIN_LP_RING(4); |
285 | OUT_RING(MI_STORE_DWORD_INDEX); | 301 | OUT_RING(MI_STORE_DWORD_INDEX); |
@@ -317,21 +333,20 @@ void i915_user_irq_put(struct drm_device *dev) | |||
317 | static int i915_wait_irq(struct drm_device * dev, int irq_nr) | 333 | static int i915_wait_irq(struct drm_device * dev, int irq_nr) |
318 | { | 334 | { |
319 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 335 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
336 | struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; | ||
320 | int ret = 0; | 337 | int ret = 0; |
321 | 338 | ||
322 | DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, | 339 | DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr, |
323 | READ_BREADCRUMB(dev_priv)); | 340 | READ_BREADCRUMB(dev_priv)); |
324 | 341 | ||
325 | if (READ_BREADCRUMB(dev_priv) >= irq_nr) { | 342 | if (READ_BREADCRUMB(dev_priv) >= irq_nr) { |
326 | if (dev_priv->sarea_priv) { | 343 | if (master_priv->sarea_priv) |
327 | dev_priv->sarea_priv->last_dispatch = | 344 | master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); |
328 | READ_BREADCRUMB(dev_priv); | ||
329 | } | ||
330 | return 0; | 345 | return 0; |
331 | } | 346 | } |
332 | 347 | ||
333 | if (dev_priv->sarea_priv) | 348 | if (master_priv->sarea_priv) |
334 | dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; | 349 | master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; |
335 | 350 | ||
336 | i915_user_irq_get(dev); | 351 | i915_user_irq_get(dev); |
337 | DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, | 352 | DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, |
@@ -343,10 +358,6 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr) | |||
343 | READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); | 358 | READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); |
344 | } | 359 | } |
345 | 360 | ||
346 | if (dev_priv->sarea_priv) | ||
347 | dev_priv->sarea_priv->last_dispatch = | ||
348 | READ_BREADCRUMB(dev_priv); | ||
349 | |||
350 | return ret; | 361 | return ret; |
351 | } | 362 | } |
352 | 363 | ||
@@ -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/i915_mem.c b/drivers/gpu/drm/i915/i915_mem.c index 6126a60dc9cb..96e271986d2a 100644 --- a/drivers/gpu/drm/i915/i915_mem.c +++ b/drivers/gpu/drm/i915/i915_mem.c | |||
@@ -46,7 +46,8 @@ | |||
46 | static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use) | 46 | static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use) |
47 | { | 47 | { |
48 | drm_i915_private_t *dev_priv = dev->dev_private; | 48 | drm_i915_private_t *dev_priv = dev->dev_private; |
49 | drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv; | 49 | struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; |
50 | drm_i915_sarea_t *sarea_priv = master_priv->sarea_priv; | ||
50 | struct drm_tex_region *list; | 51 | struct drm_tex_region *list; |
51 | unsigned shift, nr; | 52 | unsigned shift, nr; |
52 | unsigned start; | 53 | unsigned start; |
diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c index 13ae731a33db..ff012835a386 100644 --- a/drivers/gpu/drm/i915/i915_opregion.c +++ b/drivers/gpu/drm/i915/i915_opregion.c | |||
@@ -257,8 +257,8 @@ void opregion_enable_asle(struct drm_device *dev) | |||
257 | 257 | ||
258 | static struct intel_opregion *system_opregion; | 258 | static struct intel_opregion *system_opregion; |
259 | 259 | ||
260 | int intel_opregion_video_event(struct notifier_block *nb, unsigned long val, | 260 | static int intel_opregion_video_event(struct notifier_block *nb, |
261 | void *data) | 261 | unsigned long val, void *data) |
262 | { | 262 | { |
263 | /* The only video events relevant to opregion are 0x80. These indicate | 263 | /* The only video events relevant to opregion are 0x80. These indicate |
264 | either a docking event, lid switch or display switch request. In | 264 | either a docking event, lid switch or display switch request. In |
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 9d24aaeb8a45..47e6bafeb743 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h | |||
@@ -175,9 +175,26 @@ | |||
175 | #define DISPLAY_PLANE_B (1<<20) | 175 | #define DISPLAY_PLANE_B (1<<20) |
176 | 176 | ||
177 | /* | 177 | /* |
178 | * Instruction and interrupt control regs | 178 | * Fence registers |
179 | */ | 179 | */ |
180 | #define FENCE_REG_830_0 0x2000 | ||
181 | #define I830_FENCE_START_MASK 0x07f80000 | ||
182 | #define I830_FENCE_TILING_Y_SHIFT 12 | ||
183 | #define I830_FENCE_SIZE_BITS(size) ((get_order(size >> 19) - 1) << 8) | ||
184 | #define I830_FENCE_PITCH_SHIFT 4 | ||
185 | #define I830_FENCE_REG_VALID (1<<0) | ||
186 | |||
187 | #define I915_FENCE_START_MASK 0x0ff00000 | ||
188 | #define I915_FENCE_SIZE_BITS(size) ((get_order(size >> 20) - 1) << 8) | ||
180 | 189 | ||
190 | #define FENCE_REG_965_0 0x03000 | ||
191 | #define I965_FENCE_PITCH_SHIFT 2 | ||
192 | #define I965_FENCE_TILING_Y_SHIFT 1 | ||
193 | #define I965_FENCE_REG_VALID (1<<0) | ||
194 | |||
195 | /* | ||
196 | * Instruction and interrupt control regs | ||
197 | */ | ||
181 | #define PRB0_TAIL 0x02030 | 198 | #define PRB0_TAIL 0x02030 |
182 | #define PRB0_HEAD 0x02034 | 199 | #define PRB0_HEAD 0x02034 |
183 | #define PRB0_START 0x02038 | 200 | #define PRB0_START 0x02038 |
@@ -245,6 +262,7 @@ | |||
245 | #define CM0_RC_OP_FLUSH_DISABLE (1<<0) | 262 | #define CM0_RC_OP_FLUSH_DISABLE (1<<0) |
246 | #define GFX_FLSH_CNTL 0x02170 /* 915+ only */ | 263 | #define GFX_FLSH_CNTL 0x02170 /* 915+ only */ |
247 | 264 | ||
265 | |||
248 | /* | 266 | /* |
249 | * Framebuffer compression (915+ only) | 267 | * Framebuffer compression (915+ only) |
250 | */ | 268 | */ |
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..dcaed3466e83 --- /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 | static 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..e5c1c80d1f90 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -0,0 +1,1618 @@ | |||
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 | i9xx_clock (refclk, clock); | ||
217 | else | ||
218 | 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 | static void | ||
347 | intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, | ||
348 | struct drm_framebuffer *old_fb) | ||
349 | { | ||
350 | struct drm_device *dev = crtc->dev; | ||
351 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
352 | struct drm_i915_master_private *master_priv; | ||
353 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
354 | struct intel_framebuffer *intel_fb; | ||
355 | struct drm_i915_gem_object *obj_priv; | ||
356 | struct drm_gem_object *obj; | ||
357 | int pipe = intel_crtc->pipe; | ||
358 | unsigned long Start, Offset; | ||
359 | int dspbase = (pipe == 0 ? DSPAADDR : DSPBADDR); | ||
360 | int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF); | ||
361 | int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE; | ||
362 | int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; | ||
363 | u32 dspcntr, alignment; | ||
364 | |||
365 | /* no fb bound */ | ||
366 | if (!crtc->fb) { | ||
367 | DRM_DEBUG("No FB bound\n"); | ||
368 | return; | ||
369 | } | ||
370 | |||
371 | intel_fb = to_intel_framebuffer(crtc->fb); | ||
372 | obj = intel_fb->obj; | ||
373 | obj_priv = obj->driver_private; | ||
374 | |||
375 | switch (obj_priv->tiling_mode) { | ||
376 | case I915_TILING_NONE: | ||
377 | alignment = 64 * 1024; | ||
378 | break; | ||
379 | case I915_TILING_X: | ||
380 | if (IS_I9XX(dev)) | ||
381 | alignment = 1024 * 1024; | ||
382 | else | ||
383 | alignment = 512 * 1024; | ||
384 | break; | ||
385 | case I915_TILING_Y: | ||
386 | /* FIXME: Is this true? */ | ||
387 | DRM_ERROR("Y tiled not allowed for scan out buffers\n"); | ||
388 | return; | ||
389 | default: | ||
390 | BUG(); | ||
391 | } | ||
392 | |||
393 | if (i915_gem_object_pin(intel_fb->obj, alignment)) | ||
394 | return; | ||
395 | |||
396 | i915_gem_object_set_to_gtt_domain(intel_fb->obj, 1); | ||
397 | |||
398 | Start = obj_priv->gtt_offset; | ||
399 | Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8); | ||
400 | |||
401 | I915_WRITE(dspstride, crtc->fb->pitch); | ||
402 | |||
403 | dspcntr = I915_READ(dspcntr_reg); | ||
404 | switch (crtc->fb->bits_per_pixel) { | ||
405 | case 8: | ||
406 | dspcntr |= DISPPLANE_8BPP; | ||
407 | break; | ||
408 | case 16: | ||
409 | if (crtc->fb->depth == 15) | ||
410 | dspcntr |= DISPPLANE_15_16BPP; | ||
411 | else | ||
412 | dspcntr |= DISPPLANE_16BPP; | ||
413 | break; | ||
414 | case 24: | ||
415 | case 32: | ||
416 | dspcntr |= DISPPLANE_32BPP_NO_ALPHA; | ||
417 | break; | ||
418 | default: | ||
419 | DRM_ERROR("Unknown color depth\n"); | ||
420 | return; | ||
421 | } | ||
422 | I915_WRITE(dspcntr_reg, dspcntr); | ||
423 | |||
424 | DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y); | ||
425 | if (IS_I965G(dev)) { | ||
426 | I915_WRITE(dspbase, Offset); | ||
427 | I915_READ(dspbase); | ||
428 | I915_WRITE(dspsurf, Start); | ||
429 | I915_READ(dspsurf); | ||
430 | } else { | ||
431 | I915_WRITE(dspbase, Start + Offset); | ||
432 | I915_READ(dspbase); | ||
433 | } | ||
434 | |||
435 | intel_wait_for_vblank(dev); | ||
436 | |||
437 | if (old_fb) { | ||
438 | intel_fb = to_intel_framebuffer(old_fb); | ||
439 | i915_gem_object_unpin(intel_fb->obj); | ||
440 | } | ||
441 | |||
442 | if (!dev->primary->master) | ||
443 | return; | ||
444 | |||
445 | master_priv = dev->primary->master->driver_priv; | ||
446 | if (!master_priv->sarea_priv) | ||
447 | return; | ||
448 | |||
449 | switch (pipe) { | ||
450 | case 0: | ||
451 | master_priv->sarea_priv->pipeA_x = x; | ||
452 | master_priv->sarea_priv->pipeA_y = y; | ||
453 | break; | ||
454 | case 1: | ||
455 | master_priv->sarea_priv->pipeB_x = x; | ||
456 | master_priv->sarea_priv->pipeB_y = y; | ||
457 | break; | ||
458 | default: | ||
459 | DRM_ERROR("Can't update pipe %d in SAREA\n", pipe); | ||
460 | break; | ||
461 | } | ||
462 | } | ||
463 | |||
464 | |||
465 | |||
466 | /** | ||
467 | * Sets the power management mode of the pipe and plane. | ||
468 | * | ||
469 | * This code should probably grow support for turning the cursor off and back | ||
470 | * on appropriately at the same time as we're turning the pipe off/on. | ||
471 | */ | ||
472 | static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) | ||
473 | { | ||
474 | struct drm_device *dev = crtc->dev; | ||
475 | struct drm_i915_master_private *master_priv; | ||
476 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
477 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
478 | int pipe = intel_crtc->pipe; | ||
479 | int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; | ||
480 | int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; | ||
481 | int dspbase_reg = (pipe == 0) ? DSPAADDR : DSPBADDR; | ||
482 | int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; | ||
483 | u32 temp; | ||
484 | bool enabled; | ||
485 | |||
486 | /* XXX: When our outputs are all unaware of DPMS modes other than off | ||
487 | * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. | ||
488 | */ | ||
489 | switch (mode) { | ||
490 | case DRM_MODE_DPMS_ON: | ||
491 | case DRM_MODE_DPMS_STANDBY: | ||
492 | case DRM_MODE_DPMS_SUSPEND: | ||
493 | /* Enable the DPLL */ | ||
494 | temp = I915_READ(dpll_reg); | ||
495 | if ((temp & DPLL_VCO_ENABLE) == 0) { | ||
496 | I915_WRITE(dpll_reg, temp); | ||
497 | I915_READ(dpll_reg); | ||
498 | /* Wait for the clocks to stabilize. */ | ||
499 | udelay(150); | ||
500 | I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); | ||
501 | I915_READ(dpll_reg); | ||
502 | /* Wait for the clocks to stabilize. */ | ||
503 | udelay(150); | ||
504 | I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE); | ||
505 | I915_READ(dpll_reg); | ||
506 | /* Wait for the clocks to stabilize. */ | ||
507 | udelay(150); | ||
508 | } | ||
509 | |||
510 | /* Enable the pipe */ | ||
511 | temp = I915_READ(pipeconf_reg); | ||
512 | if ((temp & PIPEACONF_ENABLE) == 0) | ||
513 | I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE); | ||
514 | |||
515 | /* Enable the plane */ | ||
516 | temp = I915_READ(dspcntr_reg); | ||
517 | if ((temp & DISPLAY_PLANE_ENABLE) == 0) { | ||
518 | I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE); | ||
519 | /* Flush the plane changes */ | ||
520 | I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); | ||
521 | } | ||
522 | |||
523 | intel_crtc_load_lut(crtc); | ||
524 | |||
525 | /* Give the overlay scaler a chance to enable if it's on this pipe */ | ||
526 | //intel_crtc_dpms_video(crtc, true); TODO | ||
527 | break; | ||
528 | case DRM_MODE_DPMS_OFF: | ||
529 | /* Give the overlay scaler a chance to disable if it's on this pipe */ | ||
530 | //intel_crtc_dpms_video(crtc, FALSE); TODO | ||
531 | |||
532 | /* Disable the VGA plane that we never use */ | ||
533 | I915_WRITE(VGACNTRL, VGA_DISP_DISABLE); | ||
534 | |||
535 | /* Disable display plane */ | ||
536 | temp = I915_READ(dspcntr_reg); | ||
537 | if ((temp & DISPLAY_PLANE_ENABLE) != 0) { | ||
538 | I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE); | ||
539 | /* Flush the plane changes */ | ||
540 | I915_WRITE(dspbase_reg, I915_READ(dspbase_reg)); | ||
541 | I915_READ(dspbase_reg); | ||
542 | } | ||
543 | |||
544 | if (!IS_I9XX(dev)) { | ||
545 | /* Wait for vblank for the disable to take effect */ | ||
546 | intel_wait_for_vblank(dev); | ||
547 | } | ||
548 | |||
549 | /* Next, disable display pipes */ | ||
550 | temp = I915_READ(pipeconf_reg); | ||
551 | if ((temp & PIPEACONF_ENABLE) != 0) { | ||
552 | I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE); | ||
553 | I915_READ(pipeconf_reg); | ||
554 | } | ||
555 | |||
556 | /* Wait for vblank for the disable to take effect. */ | ||
557 | intel_wait_for_vblank(dev); | ||
558 | |||
559 | temp = I915_READ(dpll_reg); | ||
560 | if ((temp & DPLL_VCO_ENABLE) != 0) { | ||
561 | I915_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE); | ||
562 | I915_READ(dpll_reg); | ||
563 | } | ||
564 | |||
565 | /* Wait for the clocks to turn off. */ | ||
566 | udelay(150); | ||
567 | break; | ||
568 | } | ||
569 | |||
570 | if (!dev->primary->master) | ||
571 | return; | ||
572 | |||
573 | master_priv = dev->primary->master->driver_priv; | ||
574 | if (!master_priv->sarea_priv) | ||
575 | return; | ||
576 | |||
577 | enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF; | ||
578 | |||
579 | switch (pipe) { | ||
580 | case 0: | ||
581 | master_priv->sarea_priv->pipeA_w = enabled ? crtc->mode.hdisplay : 0; | ||
582 | master_priv->sarea_priv->pipeA_h = enabled ? crtc->mode.vdisplay : 0; | ||
583 | break; | ||
584 | case 1: | ||
585 | master_priv->sarea_priv->pipeB_w = enabled ? crtc->mode.hdisplay : 0; | ||
586 | master_priv->sarea_priv->pipeB_h = enabled ? crtc->mode.vdisplay : 0; | ||
587 | break; | ||
588 | default: | ||
589 | DRM_ERROR("Can't update pipe %d in SAREA\n", pipe); | ||
590 | break; | ||
591 | } | ||
592 | |||
593 | intel_crtc->dpms_mode = mode; | ||
594 | } | ||
595 | |||
596 | static void intel_crtc_prepare (struct drm_crtc *crtc) | ||
597 | { | ||
598 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
599 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); | ||
600 | } | ||
601 | |||
602 | static void intel_crtc_commit (struct drm_crtc *crtc) | ||
603 | { | ||
604 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
605 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); | ||
606 | } | ||
607 | |||
608 | void intel_encoder_prepare (struct drm_encoder *encoder) | ||
609 | { | ||
610 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; | ||
611 | /* lvds has its own version of prepare see intel_lvds_prepare */ | ||
612 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF); | ||
613 | } | ||
614 | |||
615 | void intel_encoder_commit (struct drm_encoder *encoder) | ||
616 | { | ||
617 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; | ||
618 | /* lvds has its own version of commit see intel_lvds_commit */ | ||
619 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); | ||
620 | } | ||
621 | |||
622 | static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, | ||
623 | struct drm_display_mode *mode, | ||
624 | struct drm_display_mode *adjusted_mode) | ||
625 | { | ||
626 | return true; | ||
627 | } | ||
628 | |||
629 | |||
630 | /** Returns the core display clock speed for i830 - i945 */ | ||
631 | static int intel_get_core_clock_speed(struct drm_device *dev) | ||
632 | { | ||
633 | |||
634 | /* Core clock values taken from the published datasheets. | ||
635 | * The 830 may go up to 166 Mhz, which we should check. | ||
636 | */ | ||
637 | if (IS_I945G(dev)) | ||
638 | return 400000; | ||
639 | else if (IS_I915G(dev)) | ||
640 | return 333000; | ||
641 | else if (IS_I945GM(dev) || IS_845G(dev)) | ||
642 | return 200000; | ||
643 | else if (IS_I915GM(dev)) { | ||
644 | u16 gcfgc = 0; | ||
645 | |||
646 | pci_read_config_word(dev->pdev, GCFGC, &gcfgc); | ||
647 | |||
648 | if (gcfgc & GC_LOW_FREQUENCY_ENABLE) | ||
649 | return 133000; | ||
650 | else { | ||
651 | switch (gcfgc & GC_DISPLAY_CLOCK_MASK) { | ||
652 | case GC_DISPLAY_CLOCK_333_MHZ: | ||
653 | return 333000; | ||
654 | default: | ||
655 | case GC_DISPLAY_CLOCK_190_200_MHZ: | ||
656 | return 190000; | ||
657 | } | ||
658 | } | ||
659 | } else if (IS_I865G(dev)) | ||
660 | return 266000; | ||
661 | else if (IS_I855(dev)) { | ||
662 | u16 hpllcc = 0; | ||
663 | /* Assume that the hardware is in the high speed state. This | ||
664 | * should be the default. | ||
665 | */ | ||
666 | switch (hpllcc & GC_CLOCK_CONTROL_MASK) { | ||
667 | case GC_CLOCK_133_200: | ||
668 | case GC_CLOCK_100_200: | ||
669 | return 200000; | ||
670 | case GC_CLOCK_166_250: | ||
671 | return 250000; | ||
672 | case GC_CLOCK_100_133: | ||
673 | return 133000; | ||
674 | } | ||
675 | } else /* 852, 830 */ | ||
676 | return 133000; | ||
677 | |||
678 | return 0; /* Silence gcc warning */ | ||
679 | } | ||
680 | |||
681 | |||
682 | /** | ||
683 | * Return the pipe currently connected to the panel fitter, | ||
684 | * or -1 if the panel fitter is not present or not in use | ||
685 | */ | ||
686 | static int intel_panel_fitter_pipe (struct drm_device *dev) | ||
687 | { | ||
688 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
689 | u32 pfit_control; | ||
690 | |||
691 | /* i830 doesn't have a panel fitter */ | ||
692 | if (IS_I830(dev)) | ||
693 | return -1; | ||
694 | |||
695 | pfit_control = I915_READ(PFIT_CONTROL); | ||
696 | |||
697 | /* See if the panel fitter is in use */ | ||
698 | if ((pfit_control & PFIT_ENABLE) == 0) | ||
699 | return -1; | ||
700 | |||
701 | /* 965 can place panel fitter on either pipe */ | ||
702 | if (IS_I965G(dev)) | ||
703 | return (pfit_control >> 29) & 0x3; | ||
704 | |||
705 | /* older chips can only use pipe 1 */ | ||
706 | return 1; | ||
707 | } | ||
708 | |||
709 | static void intel_crtc_mode_set(struct drm_crtc *crtc, | ||
710 | struct drm_display_mode *mode, | ||
711 | struct drm_display_mode *adjusted_mode, | ||
712 | int x, int y, | ||
713 | struct drm_framebuffer *old_fb) | ||
714 | { | ||
715 | struct drm_device *dev = crtc->dev; | ||
716 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
717 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
718 | int pipe = intel_crtc->pipe; | ||
719 | int fp_reg = (pipe == 0) ? FPA0 : FPB0; | ||
720 | int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; | ||
721 | int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD; | ||
722 | int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR; | ||
723 | int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; | ||
724 | int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B; | ||
725 | int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B; | ||
726 | int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B; | ||
727 | int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B; | ||
728 | int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B; | ||
729 | int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B; | ||
730 | int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE; | ||
731 | int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS; | ||
732 | int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC; | ||
733 | int refclk; | ||
734 | intel_clock_t clock; | ||
735 | u32 dpll = 0, fp = 0, dspcntr, pipeconf; | ||
736 | bool ok, is_sdvo = false, is_dvo = false; | ||
737 | bool is_crt = false, is_lvds = false, is_tv = false; | ||
738 | struct drm_mode_config *mode_config = &dev->mode_config; | ||
739 | struct drm_connector *connector; | ||
740 | |||
741 | drm_vblank_pre_modeset(dev, pipe); | ||
742 | |||
743 | list_for_each_entry(connector, &mode_config->connector_list, head) { | ||
744 | struct intel_output *intel_output = to_intel_output(connector); | ||
745 | |||
746 | if (!connector->encoder || connector->encoder->crtc != crtc) | ||
747 | continue; | ||
748 | |||
749 | switch (intel_output->type) { | ||
750 | case INTEL_OUTPUT_LVDS: | ||
751 | is_lvds = true; | ||
752 | break; | ||
753 | case INTEL_OUTPUT_SDVO: | ||
754 | is_sdvo = true; | ||
755 | break; | ||
756 | case INTEL_OUTPUT_DVO: | ||
757 | is_dvo = true; | ||
758 | break; | ||
759 | case INTEL_OUTPUT_TVOUT: | ||
760 | is_tv = true; | ||
761 | break; | ||
762 | case INTEL_OUTPUT_ANALOG: | ||
763 | is_crt = true; | ||
764 | break; | ||
765 | } | ||
766 | } | ||
767 | |||
768 | if (IS_I9XX(dev)) { | ||
769 | refclk = 96000; | ||
770 | } else { | ||
771 | refclk = 48000; | ||
772 | } | ||
773 | |||
774 | ok = intel_find_best_PLL(crtc, adjusted_mode->clock, refclk, &clock); | ||
775 | if (!ok) { | ||
776 | DRM_ERROR("Couldn't find PLL settings for mode!\n"); | ||
777 | return; | ||
778 | } | ||
779 | |||
780 | fp = clock.n << 16 | clock.m1 << 8 | clock.m2; | ||
781 | |||
782 | dpll = DPLL_VGA_MODE_DIS; | ||
783 | if (IS_I9XX(dev)) { | ||
784 | if (is_lvds) | ||
785 | dpll |= DPLLB_MODE_LVDS; | ||
786 | else | ||
787 | dpll |= DPLLB_MODE_DAC_SERIAL; | ||
788 | if (is_sdvo) { | ||
789 | dpll |= DPLL_DVO_HIGH_SPEED; | ||
790 | if (IS_I945G(dev) || IS_I945GM(dev)) { | ||
791 | int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; | ||
792 | dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES; | ||
793 | } | ||
794 | } | ||
795 | |||
796 | /* compute bitmask from p1 value */ | ||
797 | dpll |= (1 << (clock.p1 - 1)) << 16; | ||
798 | switch (clock.p2) { | ||
799 | case 5: | ||
800 | dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5; | ||
801 | break; | ||
802 | case 7: | ||
803 | dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7; | ||
804 | break; | ||
805 | case 10: | ||
806 | dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10; | ||
807 | break; | ||
808 | case 14: | ||
809 | dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14; | ||
810 | break; | ||
811 | } | ||
812 | if (IS_I965G(dev)) | ||
813 | dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT); | ||
814 | } else { | ||
815 | if (is_lvds) { | ||
816 | dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT; | ||
817 | } else { | ||
818 | if (clock.p1 == 2) | ||
819 | dpll |= PLL_P1_DIVIDE_BY_TWO; | ||
820 | else | ||
821 | dpll |= (clock.p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT; | ||
822 | if (clock.p2 == 4) | ||
823 | dpll |= PLL_P2_DIVIDE_BY_4; | ||
824 | } | ||
825 | } | ||
826 | |||
827 | if (is_tv) { | ||
828 | /* XXX: just matching BIOS for now */ | ||
829 | /* dpll |= PLL_REF_INPUT_TVCLKINBC; */ | ||
830 | dpll |= 3; | ||
831 | } | ||
832 | else | ||
833 | dpll |= PLL_REF_INPUT_DREFCLK; | ||
834 | |||
835 | /* setup pipeconf */ | ||
836 | pipeconf = I915_READ(pipeconf_reg); | ||
837 | |||
838 | /* Set up the display plane register */ | ||
839 | dspcntr = DISPPLANE_GAMMA_ENABLE; | ||
840 | |||
841 | if (pipe == 0) | ||
842 | dspcntr |= DISPPLANE_SEL_PIPE_A; | ||
843 | else | ||
844 | dspcntr |= DISPPLANE_SEL_PIPE_B; | ||
845 | |||
846 | if (pipe == 0 && !IS_I965G(dev)) { | ||
847 | /* Enable pixel doubling when the dot clock is > 90% of the (display) | ||
848 | * core speed. | ||
849 | * | ||
850 | * XXX: No double-wide on 915GM pipe B. Is that the only reason for the | ||
851 | * pipe == 0 check? | ||
852 | */ | ||
853 | if (mode->clock > intel_get_core_clock_speed(dev) * 9 / 10) | ||
854 | pipeconf |= PIPEACONF_DOUBLE_WIDE; | ||
855 | else | ||
856 | pipeconf &= ~PIPEACONF_DOUBLE_WIDE; | ||
857 | } | ||
858 | |||
859 | dspcntr |= DISPLAY_PLANE_ENABLE; | ||
860 | pipeconf |= PIPEACONF_ENABLE; | ||
861 | dpll |= DPLL_VCO_ENABLE; | ||
862 | |||
863 | |||
864 | /* Disable the panel fitter if it was on our pipe */ | ||
865 | if (intel_panel_fitter_pipe(dev) == pipe) | ||
866 | I915_WRITE(PFIT_CONTROL, 0); | ||
867 | |||
868 | DRM_DEBUG("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); | ||
869 | drm_mode_debug_printmodeline(mode); | ||
870 | |||
871 | |||
872 | if (dpll & DPLL_VCO_ENABLE) { | ||
873 | I915_WRITE(fp_reg, fp); | ||
874 | I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE); | ||
875 | I915_READ(dpll_reg); | ||
876 | udelay(150); | ||
877 | } | ||
878 | |||
879 | /* The LVDS pin pair needs to be on before the DPLLs are enabled. | ||
880 | * This is an exception to the general rule that mode_set doesn't turn | ||
881 | * things on. | ||
882 | */ | ||
883 | if (is_lvds) { | ||
884 | u32 lvds = I915_READ(LVDS); | ||
885 | |||
886 | lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT; | ||
887 | /* Set the B0-B3 data pairs corresponding to whether we're going to | ||
888 | * set the DPLLs for dual-channel mode or not. | ||
889 | */ | ||
890 | if (clock.p2 == 7) | ||
891 | lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; | ||
892 | else | ||
893 | lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); | ||
894 | |||
895 | /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) | ||
896 | * appropriately here, but we need to look more thoroughly into how | ||
897 | * panels behave in the two modes. | ||
898 | */ | ||
899 | |||
900 | I915_WRITE(LVDS, lvds); | ||
901 | I915_READ(LVDS); | ||
902 | } | ||
903 | |||
904 | I915_WRITE(fp_reg, fp); | ||
905 | I915_WRITE(dpll_reg, dpll); | ||
906 | I915_READ(dpll_reg); | ||
907 | /* Wait for the clocks to stabilize. */ | ||
908 | udelay(150); | ||
909 | |||
910 | if (IS_I965G(dev)) { | ||
911 | int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; | ||
912 | I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | | ||
913 | ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT)); | ||
914 | } else { | ||
915 | /* write it again -- the BIOS does, after all */ | ||
916 | I915_WRITE(dpll_reg, dpll); | ||
917 | } | ||
918 | I915_READ(dpll_reg); | ||
919 | /* Wait for the clocks to stabilize. */ | ||
920 | udelay(150); | ||
921 | |||
922 | I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) | | ||
923 | ((adjusted_mode->crtc_htotal - 1) << 16)); | ||
924 | I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) | | ||
925 | ((adjusted_mode->crtc_hblank_end - 1) << 16)); | ||
926 | I915_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) | | ||
927 | ((adjusted_mode->crtc_hsync_end - 1) << 16)); | ||
928 | I915_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) | | ||
929 | ((adjusted_mode->crtc_vtotal - 1) << 16)); | ||
930 | I915_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) | | ||
931 | ((adjusted_mode->crtc_vblank_end - 1) << 16)); | ||
932 | I915_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) | | ||
933 | ((adjusted_mode->crtc_vsync_end - 1) << 16)); | ||
934 | /* pipesrc and dspsize control the size that is scaled from, which should | ||
935 | * always be the user's requested size. | ||
936 | */ | ||
937 | I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1)); | ||
938 | I915_WRITE(dsppos_reg, 0); | ||
939 | I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1)); | ||
940 | I915_WRITE(pipeconf_reg, pipeconf); | ||
941 | I915_READ(pipeconf_reg); | ||
942 | |||
943 | intel_wait_for_vblank(dev); | ||
944 | |||
945 | I915_WRITE(dspcntr_reg, dspcntr); | ||
946 | |||
947 | /* Flush the plane changes */ | ||
948 | intel_pipe_set_base(crtc, x, y, old_fb); | ||
949 | |||
950 | drm_vblank_post_modeset(dev, pipe); | ||
951 | } | ||
952 | |||
953 | /** Loads the palette/gamma unit for the CRTC with the prepared values */ | ||
954 | void intel_crtc_load_lut(struct drm_crtc *crtc) | ||
955 | { | ||
956 | struct drm_device *dev = crtc->dev; | ||
957 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
958 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
959 | int palreg = (intel_crtc->pipe == 0) ? PALETTE_A : PALETTE_B; | ||
960 | int i; | ||
961 | |||
962 | /* The clocks have to be on to load the palette. */ | ||
963 | if (!crtc->enabled) | ||
964 | return; | ||
965 | |||
966 | for (i = 0; i < 256; i++) { | ||
967 | I915_WRITE(palreg + 4 * i, | ||
968 | (intel_crtc->lut_r[i] << 16) | | ||
969 | (intel_crtc->lut_g[i] << 8) | | ||
970 | intel_crtc->lut_b[i]); | ||
971 | } | ||
972 | } | ||
973 | |||
974 | static int intel_crtc_cursor_set(struct drm_crtc *crtc, | ||
975 | struct drm_file *file_priv, | ||
976 | uint32_t handle, | ||
977 | uint32_t width, uint32_t height) | ||
978 | { | ||
979 | struct drm_device *dev = crtc->dev; | ||
980 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
981 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
982 | struct drm_gem_object *bo; | ||
983 | struct drm_i915_gem_object *obj_priv; | ||
984 | int pipe = intel_crtc->pipe; | ||
985 | uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR; | ||
986 | uint32_t base = (pipe == 0) ? CURABASE : CURBBASE; | ||
987 | uint32_t temp; | ||
988 | size_t addr; | ||
989 | |||
990 | DRM_DEBUG("\n"); | ||
991 | |||
992 | /* if we want to turn off the cursor ignore width and height */ | ||
993 | if (!handle) { | ||
994 | DRM_DEBUG("cursor off\n"); | ||
995 | /* turn of the cursor */ | ||
996 | temp = 0; | ||
997 | temp |= CURSOR_MODE_DISABLE; | ||
998 | |||
999 | I915_WRITE(control, temp); | ||
1000 | I915_WRITE(base, 0); | ||
1001 | return 0; | ||
1002 | } | ||
1003 | |||
1004 | /* Currently we only support 64x64 cursors */ | ||
1005 | if (width != 64 || height != 64) { | ||
1006 | DRM_ERROR("we currently only support 64x64 cursors\n"); | ||
1007 | return -EINVAL; | ||
1008 | } | ||
1009 | |||
1010 | bo = drm_gem_object_lookup(dev, file_priv, handle); | ||
1011 | if (!bo) | ||
1012 | return -ENOENT; | ||
1013 | |||
1014 | obj_priv = bo->driver_private; | ||
1015 | |||
1016 | if (bo->size < width * height * 4) { | ||
1017 | DRM_ERROR("buffer is to small\n"); | ||
1018 | drm_gem_object_unreference(bo); | ||
1019 | return -ENOMEM; | ||
1020 | } | ||
1021 | |||
1022 | if (dev_priv->cursor_needs_physical) { | ||
1023 | addr = dev->agp->base + obj_priv->gtt_offset; | ||
1024 | } else { | ||
1025 | addr = obj_priv->gtt_offset; | ||
1026 | } | ||
1027 | |||
1028 | intel_crtc->cursor_addr = addr; | ||
1029 | temp = 0; | ||
1030 | /* set the pipe for the cursor */ | ||
1031 | temp |= (pipe << 28); | ||
1032 | temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; | ||
1033 | |||
1034 | I915_WRITE(control, temp); | ||
1035 | I915_WRITE(base, addr); | ||
1036 | |||
1037 | return 0; | ||
1038 | } | ||
1039 | |||
1040 | static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) | ||
1041 | { | ||
1042 | struct drm_device *dev = crtc->dev; | ||
1043 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
1044 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
1045 | int pipe = intel_crtc->pipe; | ||
1046 | uint32_t temp = 0; | ||
1047 | uint32_t adder; | ||
1048 | |||
1049 | if (x < 0) { | ||
1050 | temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT); | ||
1051 | x = -x; | ||
1052 | } | ||
1053 | if (y < 0) { | ||
1054 | temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT); | ||
1055 | y = -y; | ||
1056 | } | ||
1057 | |||
1058 | temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT); | ||
1059 | temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); | ||
1060 | |||
1061 | adder = intel_crtc->cursor_addr; | ||
1062 | I915_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp); | ||
1063 | I915_WRITE((pipe == 0) ? CURABASE : CURBBASE, adder); | ||
1064 | |||
1065 | return 0; | ||
1066 | } | ||
1067 | |||
1068 | /** Sets the color ramps on behalf of RandR */ | ||
1069 | void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, | ||
1070 | u16 blue, int regno) | ||
1071 | { | ||
1072 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
1073 | |||
1074 | intel_crtc->lut_r[regno] = red >> 8; | ||
1075 | intel_crtc->lut_g[regno] = green >> 8; | ||
1076 | intel_crtc->lut_b[regno] = blue >> 8; | ||
1077 | } | ||
1078 | |||
1079 | static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, | ||
1080 | u16 *blue, uint32_t size) | ||
1081 | { | ||
1082 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
1083 | int i; | ||
1084 | |||
1085 | if (size != 256) | ||
1086 | return; | ||
1087 | |||
1088 | for (i = 0; i < 256; i++) { | ||
1089 | intel_crtc->lut_r[i] = red[i] >> 8; | ||
1090 | intel_crtc->lut_g[i] = green[i] >> 8; | ||
1091 | intel_crtc->lut_b[i] = blue[i] >> 8; | ||
1092 | } | ||
1093 | |||
1094 | intel_crtc_load_lut(crtc); | ||
1095 | } | ||
1096 | |||
1097 | /** | ||
1098 | * Get a pipe with a simple mode set on it for doing load-based monitor | ||
1099 | * detection. | ||
1100 | * | ||
1101 | * It will be up to the load-detect code to adjust the pipe as appropriate for | ||
1102 | * its requirements. The pipe will be connected to no other outputs. | ||
1103 | * | ||
1104 | * Currently this code will only succeed if there is a pipe with no outputs | ||
1105 | * configured for it. In the future, it could choose to temporarily disable | ||
1106 | * some outputs to free up a pipe for its use. | ||
1107 | * | ||
1108 | * \return crtc, or NULL if no pipes are available. | ||
1109 | */ | ||
1110 | |||
1111 | /* VESA 640x480x72Hz mode to set on the pipe */ | ||
1112 | static struct drm_display_mode load_detect_mode = { | ||
1113 | DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664, | ||
1114 | 704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), | ||
1115 | }; | ||
1116 | |||
1117 | struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output, | ||
1118 | struct drm_display_mode *mode, | ||
1119 | int *dpms_mode) | ||
1120 | { | ||
1121 | struct intel_crtc *intel_crtc; | ||
1122 | struct drm_crtc *possible_crtc; | ||
1123 | struct drm_crtc *supported_crtc =NULL; | ||
1124 | struct drm_encoder *encoder = &intel_output->enc; | ||
1125 | struct drm_crtc *crtc = NULL; | ||
1126 | struct drm_device *dev = encoder->dev; | ||
1127 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; | ||
1128 | struct drm_crtc_helper_funcs *crtc_funcs; | ||
1129 | int i = -1; | ||
1130 | |||
1131 | /* | ||
1132 | * Algorithm gets a little messy: | ||
1133 | * - if the connector already has an assigned crtc, use it (but make | ||
1134 | * sure it's on first) | ||
1135 | * - try to find the first unused crtc that can drive this connector, | ||
1136 | * and use that if we find one | ||
1137 | * - if there are no unused crtcs available, try to use the first | ||
1138 | * one we found that supports the connector | ||
1139 | */ | ||
1140 | |||
1141 | /* See if we already have a CRTC for this connector */ | ||
1142 | if (encoder->crtc) { | ||
1143 | crtc = encoder->crtc; | ||
1144 | /* Make sure the crtc and connector are running */ | ||
1145 | intel_crtc = to_intel_crtc(crtc); | ||
1146 | *dpms_mode = intel_crtc->dpms_mode; | ||
1147 | if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) { | ||
1148 | crtc_funcs = crtc->helper_private; | ||
1149 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); | ||
1150 | encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); | ||
1151 | } | ||
1152 | return crtc; | ||
1153 | } | ||
1154 | |||
1155 | /* Find an unused one (if possible) */ | ||
1156 | list_for_each_entry(possible_crtc, &dev->mode_config.crtc_list, head) { | ||
1157 | i++; | ||
1158 | if (!(encoder->possible_crtcs & (1 << i))) | ||
1159 | continue; | ||
1160 | if (!possible_crtc->enabled) { | ||
1161 | crtc = possible_crtc; | ||
1162 | break; | ||
1163 | } | ||
1164 | if (!supported_crtc) | ||
1165 | supported_crtc = possible_crtc; | ||
1166 | } | ||
1167 | |||
1168 | /* | ||
1169 | * If we didn't find an unused CRTC, don't use any. | ||
1170 | */ | ||
1171 | if (!crtc) { | ||
1172 | return NULL; | ||
1173 | } | ||
1174 | |||
1175 | encoder->crtc = crtc; | ||
1176 | intel_output->load_detect_temp = true; | ||
1177 | |||
1178 | intel_crtc = to_intel_crtc(crtc); | ||
1179 | *dpms_mode = intel_crtc->dpms_mode; | ||
1180 | |||
1181 | if (!crtc->enabled) { | ||
1182 | if (!mode) | ||
1183 | mode = &load_detect_mode; | ||
1184 | drm_crtc_helper_set_mode(crtc, mode, 0, 0, crtc->fb); | ||
1185 | } else { | ||
1186 | if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) { | ||
1187 | crtc_funcs = crtc->helper_private; | ||
1188 | crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); | ||
1189 | } | ||
1190 | |||
1191 | /* Add this connector to the crtc */ | ||
1192 | encoder_funcs->mode_set(encoder, &crtc->mode, &crtc->mode); | ||
1193 | encoder_funcs->commit(encoder); | ||
1194 | } | ||
1195 | /* let the connector get through one full cycle before testing */ | ||
1196 | intel_wait_for_vblank(dev); | ||
1197 | |||
1198 | return crtc; | ||
1199 | } | ||
1200 | |||
1201 | void intel_release_load_detect_pipe(struct intel_output *intel_output, int dpms_mode) | ||
1202 | { | ||
1203 | struct drm_encoder *encoder = &intel_output->enc; | ||
1204 | struct drm_device *dev = encoder->dev; | ||
1205 | struct drm_crtc *crtc = encoder->crtc; | ||
1206 | struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; | ||
1207 | struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; | ||
1208 | |||
1209 | if (intel_output->load_detect_temp) { | ||
1210 | encoder->crtc = NULL; | ||
1211 | intel_output->load_detect_temp = false; | ||
1212 | crtc->enabled = drm_helper_crtc_in_use(crtc); | ||
1213 | drm_helper_disable_unused_functions(dev); | ||
1214 | } | ||
1215 | |||
1216 | /* Switch crtc and output back off if necessary */ | ||
1217 | if (crtc->enabled && dpms_mode != DRM_MODE_DPMS_ON) { | ||
1218 | if (encoder->crtc == crtc) | ||
1219 | encoder_funcs->dpms(encoder, dpms_mode); | ||
1220 | crtc_funcs->dpms(crtc, dpms_mode); | ||
1221 | } | ||
1222 | } | ||
1223 | |||
1224 | /* Returns the clock of the currently programmed mode of the given pipe. */ | ||
1225 | static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) | ||
1226 | { | ||
1227 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
1228 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
1229 | int pipe = intel_crtc->pipe; | ||
1230 | u32 dpll = I915_READ((pipe == 0) ? DPLL_A : DPLL_B); | ||
1231 | u32 fp; | ||
1232 | intel_clock_t clock; | ||
1233 | |||
1234 | if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) | ||
1235 | fp = I915_READ((pipe == 0) ? FPA0 : FPB0); | ||
1236 | else | ||
1237 | fp = I915_READ((pipe == 0) ? FPA1 : FPB1); | ||
1238 | |||
1239 | clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; | ||
1240 | clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; | ||
1241 | clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT; | ||
1242 | if (IS_I9XX(dev)) { | ||
1243 | clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >> | ||
1244 | DPLL_FPA01_P1_POST_DIV_SHIFT); | ||
1245 | |||
1246 | switch (dpll & DPLL_MODE_MASK) { | ||
1247 | case DPLLB_MODE_DAC_SERIAL: | ||
1248 | clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? | ||
1249 | 5 : 10; | ||
1250 | break; | ||
1251 | case DPLLB_MODE_LVDS: | ||
1252 | clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ? | ||
1253 | 7 : 14; | ||
1254 | break; | ||
1255 | default: | ||
1256 | DRM_DEBUG("Unknown DPLL mode %08x in programmed " | ||
1257 | "mode\n", (int)(dpll & DPLL_MODE_MASK)); | ||
1258 | return 0; | ||
1259 | } | ||
1260 | |||
1261 | /* XXX: Handle the 100Mhz refclk */ | ||
1262 | i9xx_clock(96000, &clock); | ||
1263 | } else { | ||
1264 | bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN); | ||
1265 | |||
1266 | if (is_lvds) { | ||
1267 | clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> | ||
1268 | DPLL_FPA01_P1_POST_DIV_SHIFT); | ||
1269 | clock.p2 = 14; | ||
1270 | |||
1271 | if ((dpll & PLL_REF_INPUT_MASK) == | ||
1272 | PLLB_REF_INPUT_SPREADSPECTRUMIN) { | ||
1273 | /* XXX: might not be 66MHz */ | ||
1274 | i8xx_clock(66000, &clock); | ||
1275 | } else | ||
1276 | i8xx_clock(48000, &clock); | ||
1277 | } else { | ||
1278 | if (dpll & PLL_P1_DIVIDE_BY_TWO) | ||
1279 | clock.p1 = 2; | ||
1280 | else { | ||
1281 | clock.p1 = ((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830) >> | ||
1282 | DPLL_FPA01_P1_POST_DIV_SHIFT) + 2; | ||
1283 | } | ||
1284 | if (dpll & PLL_P2_DIVIDE_BY_4) | ||
1285 | clock.p2 = 4; | ||
1286 | else | ||
1287 | clock.p2 = 2; | ||
1288 | |||
1289 | i8xx_clock(48000, &clock); | ||
1290 | } | ||
1291 | } | ||
1292 | |||
1293 | /* XXX: It would be nice to validate the clocks, but we can't reuse | ||
1294 | * i830PllIsValid() because it relies on the xf86_config connector | ||
1295 | * configuration being accurate, which it isn't necessarily. | ||
1296 | */ | ||
1297 | |||
1298 | return clock.dot; | ||
1299 | } | ||
1300 | |||
1301 | /** Returns the currently programmed mode of the given pipe. */ | ||
1302 | struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, | ||
1303 | struct drm_crtc *crtc) | ||
1304 | { | ||
1305 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
1306 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
1307 | int pipe = intel_crtc->pipe; | ||
1308 | struct drm_display_mode *mode; | ||
1309 | int htot = I915_READ((pipe == 0) ? HTOTAL_A : HTOTAL_B); | ||
1310 | int hsync = I915_READ((pipe == 0) ? HSYNC_A : HSYNC_B); | ||
1311 | int vtot = I915_READ((pipe == 0) ? VTOTAL_A : VTOTAL_B); | ||
1312 | int vsync = I915_READ((pipe == 0) ? VSYNC_A : VSYNC_B); | ||
1313 | |||
1314 | mode = kzalloc(sizeof(*mode), GFP_KERNEL); | ||
1315 | if (!mode) | ||
1316 | return NULL; | ||
1317 | |||
1318 | mode->clock = intel_crtc_clock_get(dev, crtc); | ||
1319 | mode->hdisplay = (htot & 0xffff) + 1; | ||
1320 | mode->htotal = ((htot & 0xffff0000) >> 16) + 1; | ||
1321 | mode->hsync_start = (hsync & 0xffff) + 1; | ||
1322 | mode->hsync_end = ((hsync & 0xffff0000) >> 16) + 1; | ||
1323 | mode->vdisplay = (vtot & 0xffff) + 1; | ||
1324 | mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1; | ||
1325 | mode->vsync_start = (vsync & 0xffff) + 1; | ||
1326 | mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1; | ||
1327 | |||
1328 | drm_mode_set_name(mode); | ||
1329 | drm_mode_set_crtcinfo(mode, 0); | ||
1330 | |||
1331 | return mode; | ||
1332 | } | ||
1333 | |||
1334 | static void intel_crtc_destroy(struct drm_crtc *crtc) | ||
1335 | { | ||
1336 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
1337 | |||
1338 | drm_crtc_cleanup(crtc); | ||
1339 | kfree(intel_crtc); | ||
1340 | } | ||
1341 | |||
1342 | static const struct drm_crtc_helper_funcs intel_helper_funcs = { | ||
1343 | .dpms = intel_crtc_dpms, | ||
1344 | .mode_fixup = intel_crtc_mode_fixup, | ||
1345 | .mode_set = intel_crtc_mode_set, | ||
1346 | .mode_set_base = intel_pipe_set_base, | ||
1347 | .prepare = intel_crtc_prepare, | ||
1348 | .commit = intel_crtc_commit, | ||
1349 | }; | ||
1350 | |||
1351 | static const struct drm_crtc_funcs intel_crtc_funcs = { | ||
1352 | .cursor_set = intel_crtc_cursor_set, | ||
1353 | .cursor_move = intel_crtc_cursor_move, | ||
1354 | .gamma_set = intel_crtc_gamma_set, | ||
1355 | .set_config = drm_crtc_helper_set_config, | ||
1356 | .destroy = intel_crtc_destroy, | ||
1357 | }; | ||
1358 | |||
1359 | |||
1360 | static void intel_crtc_init(struct drm_device *dev, int pipe) | ||
1361 | { | ||
1362 | struct intel_crtc *intel_crtc; | ||
1363 | int i; | ||
1364 | |||
1365 | intel_crtc = kzalloc(sizeof(struct intel_crtc) + (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL); | ||
1366 | if (intel_crtc == NULL) | ||
1367 | return; | ||
1368 | |||
1369 | drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs); | ||
1370 | |||
1371 | drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256); | ||
1372 | intel_crtc->pipe = pipe; | ||
1373 | for (i = 0; i < 256; i++) { | ||
1374 | intel_crtc->lut_r[i] = i; | ||
1375 | intel_crtc->lut_g[i] = i; | ||
1376 | intel_crtc->lut_b[i] = i; | ||
1377 | } | ||
1378 | |||
1379 | intel_crtc->cursor_addr = 0; | ||
1380 | intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF; | ||
1381 | drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); | ||
1382 | |||
1383 | intel_crtc->mode_set.crtc = &intel_crtc->base; | ||
1384 | intel_crtc->mode_set.connectors = (struct drm_connector **)(intel_crtc + 1); | ||
1385 | intel_crtc->mode_set.num_connectors = 0; | ||
1386 | |||
1387 | if (i915_fbpercrtc) { | ||
1388 | |||
1389 | |||
1390 | |||
1391 | } | ||
1392 | } | ||
1393 | |||
1394 | struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe) | ||
1395 | { | ||
1396 | struct drm_crtc *crtc = NULL; | ||
1397 | |||
1398 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
1399 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
1400 | if (intel_crtc->pipe == pipe) | ||
1401 | break; | ||
1402 | } | ||
1403 | return crtc; | ||
1404 | } | ||
1405 | |||
1406 | static int intel_connector_clones(struct drm_device *dev, int type_mask) | ||
1407 | { | ||
1408 | int index_mask = 0; | ||
1409 | struct drm_connector *connector; | ||
1410 | int entry = 0; | ||
1411 | |||
1412 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
1413 | struct intel_output *intel_output = to_intel_output(connector); | ||
1414 | if (type_mask & (1 << intel_output->type)) | ||
1415 | index_mask |= (1 << entry); | ||
1416 | entry++; | ||
1417 | } | ||
1418 | return index_mask; | ||
1419 | } | ||
1420 | |||
1421 | |||
1422 | static void intel_setup_outputs(struct drm_device *dev) | ||
1423 | { | ||
1424 | struct drm_connector *connector; | ||
1425 | |||
1426 | intel_crt_init(dev); | ||
1427 | |||
1428 | /* Set up integrated LVDS */ | ||
1429 | if (IS_MOBILE(dev) && !IS_I830(dev)) | ||
1430 | intel_lvds_init(dev); | ||
1431 | |||
1432 | if (IS_I9XX(dev)) { | ||
1433 | intel_sdvo_init(dev, SDVOB); | ||
1434 | intel_sdvo_init(dev, SDVOC); | ||
1435 | } else | ||
1436 | intel_dvo_init(dev); | ||
1437 | |||
1438 | if (IS_I9XX(dev) && !IS_I915G(dev)) | ||
1439 | intel_tv_init(dev); | ||
1440 | |||
1441 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
1442 | struct intel_output *intel_output = to_intel_output(connector); | ||
1443 | struct drm_encoder *encoder = &intel_output->enc; | ||
1444 | int crtc_mask = 0, clone_mask = 0; | ||
1445 | |||
1446 | /* valid crtcs */ | ||
1447 | switch(intel_output->type) { | ||
1448 | case INTEL_OUTPUT_DVO: | ||
1449 | case INTEL_OUTPUT_SDVO: | ||
1450 | crtc_mask = ((1 << 0)| | ||
1451 | (1 << 1)); | ||
1452 | clone_mask = ((1 << INTEL_OUTPUT_ANALOG) | | ||
1453 | (1 << INTEL_OUTPUT_DVO) | | ||
1454 | (1 << INTEL_OUTPUT_SDVO)); | ||
1455 | break; | ||
1456 | case INTEL_OUTPUT_ANALOG: | ||
1457 | crtc_mask = ((1 << 0)| | ||
1458 | (1 << 1)); | ||
1459 | clone_mask = ((1 << INTEL_OUTPUT_ANALOG) | | ||
1460 | (1 << INTEL_OUTPUT_DVO) | | ||
1461 | (1 << INTEL_OUTPUT_SDVO)); | ||
1462 | break; | ||
1463 | case INTEL_OUTPUT_LVDS: | ||
1464 | crtc_mask = (1 << 1); | ||
1465 | clone_mask = (1 << INTEL_OUTPUT_LVDS); | ||
1466 | break; | ||
1467 | case INTEL_OUTPUT_TVOUT: | ||
1468 | crtc_mask = ((1 << 0) | | ||
1469 | (1 << 1)); | ||
1470 | clone_mask = (1 << INTEL_OUTPUT_TVOUT); | ||
1471 | break; | ||
1472 | } | ||
1473 | encoder->possible_crtcs = crtc_mask; | ||
1474 | encoder->possible_clones = intel_connector_clones(dev, clone_mask); | ||
1475 | } | ||
1476 | } | ||
1477 | |||
1478 | static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) | ||
1479 | { | ||
1480 | struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); | ||
1481 | struct drm_device *dev = fb->dev; | ||
1482 | |||
1483 | if (fb->fbdev) | ||
1484 | intelfb_remove(dev, fb); | ||
1485 | |||
1486 | drm_framebuffer_cleanup(fb); | ||
1487 | mutex_lock(&dev->struct_mutex); | ||
1488 | drm_gem_object_unreference(intel_fb->obj); | ||
1489 | mutex_unlock(&dev->struct_mutex); | ||
1490 | |||
1491 | kfree(intel_fb); | ||
1492 | } | ||
1493 | |||
1494 | static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb, | ||
1495 | struct drm_file *file_priv, | ||
1496 | unsigned int *handle) | ||
1497 | { | ||
1498 | struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); | ||
1499 | struct drm_gem_object *object = intel_fb->obj; | ||
1500 | |||
1501 | return drm_gem_handle_create(file_priv, object, handle); | ||
1502 | } | ||
1503 | |||
1504 | static const struct drm_framebuffer_funcs intel_fb_funcs = { | ||
1505 | .destroy = intel_user_framebuffer_destroy, | ||
1506 | .create_handle = intel_user_framebuffer_create_handle, | ||
1507 | }; | ||
1508 | |||
1509 | int intel_framebuffer_create(struct drm_device *dev, | ||
1510 | struct drm_mode_fb_cmd *mode_cmd, | ||
1511 | struct drm_framebuffer **fb, | ||
1512 | struct drm_gem_object *obj) | ||
1513 | { | ||
1514 | struct intel_framebuffer *intel_fb; | ||
1515 | int ret; | ||
1516 | |||
1517 | intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); | ||
1518 | if (!intel_fb) | ||
1519 | return -ENOMEM; | ||
1520 | |||
1521 | ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs); | ||
1522 | if (ret) { | ||
1523 | DRM_ERROR("framebuffer init failed %d\n", ret); | ||
1524 | return ret; | ||
1525 | } | ||
1526 | |||
1527 | drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); | ||
1528 | |||
1529 | intel_fb->obj = obj; | ||
1530 | |||
1531 | *fb = &intel_fb->base; | ||
1532 | |||
1533 | return 0; | ||
1534 | } | ||
1535 | |||
1536 | |||
1537 | static struct drm_framebuffer * | ||
1538 | intel_user_framebuffer_create(struct drm_device *dev, | ||
1539 | struct drm_file *filp, | ||
1540 | struct drm_mode_fb_cmd *mode_cmd) | ||
1541 | { | ||
1542 | struct drm_gem_object *obj; | ||
1543 | struct drm_framebuffer *fb; | ||
1544 | int ret; | ||
1545 | |||
1546 | obj = drm_gem_object_lookup(dev, filp, mode_cmd->handle); | ||
1547 | if (!obj) | ||
1548 | return NULL; | ||
1549 | |||
1550 | ret = intel_framebuffer_create(dev, mode_cmd, &fb, obj); | ||
1551 | if (ret) { | ||
1552 | drm_gem_object_unreference(obj); | ||
1553 | return NULL; | ||
1554 | } | ||
1555 | |||
1556 | return fb; | ||
1557 | } | ||
1558 | |||
1559 | static const struct drm_mode_config_funcs intel_mode_funcs = { | ||
1560 | .fb_create = intel_user_framebuffer_create, | ||
1561 | .fb_changed = intelfb_probe, | ||
1562 | }; | ||
1563 | |||
1564 | void intel_modeset_init(struct drm_device *dev) | ||
1565 | { | ||
1566 | int num_pipe; | ||
1567 | int i; | ||
1568 | |||
1569 | drm_mode_config_init(dev); | ||
1570 | |||
1571 | dev->mode_config.min_width = 0; | ||
1572 | dev->mode_config.min_height = 0; | ||
1573 | |||
1574 | dev->mode_config.funcs = (void *)&intel_mode_funcs; | ||
1575 | |||
1576 | if (IS_I965G(dev)) { | ||
1577 | dev->mode_config.max_width = 8192; | ||
1578 | dev->mode_config.max_height = 8192; | ||
1579 | } else { | ||
1580 | dev->mode_config.max_width = 2048; | ||
1581 | dev->mode_config.max_height = 2048; | ||
1582 | } | ||
1583 | |||
1584 | /* set memory base */ | ||
1585 | if (IS_I9XX(dev)) | ||
1586 | dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2); | ||
1587 | else | ||
1588 | dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0); | ||
1589 | |||
1590 | if (IS_MOBILE(dev) || IS_I9XX(dev)) | ||
1591 | num_pipe = 2; | ||
1592 | else | ||
1593 | num_pipe = 1; | ||
1594 | DRM_DEBUG("%d display pipe%s available.\n", | ||
1595 | num_pipe, num_pipe > 1 ? "s" : ""); | ||
1596 | |||
1597 | for (i = 0; i < num_pipe; i++) { | ||
1598 | intel_crtc_init(dev, i); | ||
1599 | } | ||
1600 | |||
1601 | intel_setup_outputs(dev); | ||
1602 | } | ||
1603 | |||
1604 | void intel_modeset_cleanup(struct drm_device *dev) | ||
1605 | { | ||
1606 | drm_mode_config_cleanup(dev); | ||
1607 | } | ||
1608 | |||
1609 | |||
1610 | /* current intel driver doesn't take advantage of encoders | ||
1611 | always give back the encoder for the connector | ||
1612 | */ | ||
1613 | struct drm_encoder *intel_best_encoder(struct drm_connector *connector) | ||
1614 | { | ||
1615 | struct intel_output *intel_output = to_intel_output(connector); | ||
1616 | |||
1617 | return &intel_output->enc; | ||
1618 | } | ||
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..8b8d6e65cd3f --- /dev/null +++ b/drivers/gpu/drm/i915/intel_dvo.c | |||
@@ -0,0 +1,495 @@ | |||
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 | static struct intel_dvo_device intel_dvo_devices[] = { | ||
41 | { | ||
42 | .type = INTEL_DVO_CHIP_TMDS, | ||
43 | .name = "sil164", | ||
44 | .dvo_reg = DVOC, | ||
45 | .slave_addr = SIL164_ADDR, | ||
46 | .dev_ops = &sil164_ops, | ||
47 | }, | ||
48 | { | ||
49 | .type = INTEL_DVO_CHIP_TMDS, | ||
50 | .name = "ch7xxx", | ||
51 | .dvo_reg = DVOC, | ||
52 | .slave_addr = CH7xxx_ADDR, | ||
53 | .dev_ops = &ch7xxx_ops, | ||
54 | }, | ||
55 | { | ||
56 | .type = INTEL_DVO_CHIP_LVDS, | ||
57 | .name = "ivch", | ||
58 | .dvo_reg = DVOA, | ||
59 | .slave_addr = 0x02, /* Might also be 0x44, 0x84, 0xc4 */ | ||
60 | .dev_ops = &ivch_ops, | ||
61 | }, | ||
62 | { | ||
63 | .type = INTEL_DVO_CHIP_TMDS, | ||
64 | .name = "tfp410", | ||
65 | .dvo_reg = DVOC, | ||
66 | .slave_addr = TFP410_ADDR, | ||
67 | .dev_ops = &tfp410_ops, | ||
68 | }, | ||
69 | { | ||
70 | .type = INTEL_DVO_CHIP_LVDS, | ||
71 | .name = "ch7017", | ||
72 | .dvo_reg = DVOC, | ||
73 | .slave_addr = 0x75, | ||
74 | .gpio = GPIOE, | ||
75 | .dev_ops = &ch7017_ops, | ||
76 | } | ||
77 | }; | ||
78 | |||
79 | static void intel_dvo_dpms(struct drm_encoder *encoder, int mode) | ||
80 | { | ||
81 | struct drm_i915_private *dev_priv = encoder->dev->dev_private; | ||
82 | struct intel_output *intel_output = enc_to_intel_output(encoder); | ||
83 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
84 | u32 dvo_reg = dvo->dvo_reg; | ||
85 | u32 temp = I915_READ(dvo_reg); | ||
86 | |||
87 | if (mode == DRM_MODE_DPMS_ON) { | ||
88 | I915_WRITE(dvo_reg, temp | DVO_ENABLE); | ||
89 | I915_READ(dvo_reg); | ||
90 | dvo->dev_ops->dpms(dvo, mode); | ||
91 | } else { | ||
92 | dvo->dev_ops->dpms(dvo, mode); | ||
93 | I915_WRITE(dvo_reg, temp & ~DVO_ENABLE); | ||
94 | I915_READ(dvo_reg); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | static void intel_dvo_save(struct drm_connector *connector) | ||
99 | { | ||
100 | struct drm_i915_private *dev_priv = connector->dev->dev_private; | ||
101 | struct intel_output *intel_output = to_intel_output(connector); | ||
102 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
103 | |||
104 | /* Each output should probably just save the registers it touches, | ||
105 | * but for now, use more overkill. | ||
106 | */ | ||
107 | dev_priv->saveDVOA = I915_READ(DVOA); | ||
108 | dev_priv->saveDVOB = I915_READ(DVOB); | ||
109 | dev_priv->saveDVOC = I915_READ(DVOC); | ||
110 | |||
111 | dvo->dev_ops->save(dvo); | ||
112 | } | ||
113 | |||
114 | static void intel_dvo_restore(struct drm_connector *connector) | ||
115 | { | ||
116 | struct drm_i915_private *dev_priv = connector->dev->dev_private; | ||
117 | struct intel_output *intel_output = to_intel_output(connector); | ||
118 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
119 | |||
120 | dvo->dev_ops->restore(dvo); | ||
121 | |||
122 | I915_WRITE(DVOA, dev_priv->saveDVOA); | ||
123 | I915_WRITE(DVOB, dev_priv->saveDVOB); | ||
124 | I915_WRITE(DVOC, dev_priv->saveDVOC); | ||
125 | } | ||
126 | |||
127 | static int intel_dvo_mode_valid(struct drm_connector *connector, | ||
128 | struct drm_display_mode *mode) | ||
129 | { | ||
130 | struct intel_output *intel_output = to_intel_output(connector); | ||
131 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
132 | |||
133 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
134 | return MODE_NO_DBLESCAN; | ||
135 | |||
136 | /* XXX: Validate clock range */ | ||
137 | |||
138 | if (dvo->panel_fixed_mode) { | ||
139 | if (mode->hdisplay > dvo->panel_fixed_mode->hdisplay) | ||
140 | return MODE_PANEL; | ||
141 | if (mode->vdisplay > dvo->panel_fixed_mode->vdisplay) | ||
142 | return MODE_PANEL; | ||
143 | } | ||
144 | |||
145 | return dvo->dev_ops->mode_valid(dvo, mode); | ||
146 | } | ||
147 | |||
148 | static bool intel_dvo_mode_fixup(struct drm_encoder *encoder, | ||
149 | struct drm_display_mode *mode, | ||
150 | struct drm_display_mode *adjusted_mode) | ||
151 | { | ||
152 | struct intel_output *intel_output = enc_to_intel_output(encoder); | ||
153 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
154 | |||
155 | /* If we have timings from the BIOS for the panel, put them in | ||
156 | * to the adjusted mode. The CRTC will be set up for this mode, | ||
157 | * with the panel scaling set up to source from the H/VDisplay | ||
158 | * of the original mode. | ||
159 | */ | ||
160 | if (dvo->panel_fixed_mode != NULL) { | ||
161 | #define C(x) adjusted_mode->x = dvo->panel_fixed_mode->x | ||
162 | C(hdisplay); | ||
163 | C(hsync_start); | ||
164 | C(hsync_end); | ||
165 | C(htotal); | ||
166 | C(vdisplay); | ||
167 | C(vsync_start); | ||
168 | C(vsync_end); | ||
169 | C(vtotal); | ||
170 | C(clock); | ||
171 | drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); | ||
172 | #undef C | ||
173 | } | ||
174 | |||
175 | if (dvo->dev_ops->mode_fixup) | ||
176 | return dvo->dev_ops->mode_fixup(dvo, mode, adjusted_mode); | ||
177 | |||
178 | return true; | ||
179 | } | ||
180 | |||
181 | static void intel_dvo_mode_set(struct drm_encoder *encoder, | ||
182 | struct drm_display_mode *mode, | ||
183 | struct drm_display_mode *adjusted_mode) | ||
184 | { | ||
185 | struct drm_device *dev = encoder->dev; | ||
186 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
187 | struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); | ||
188 | struct intel_output *intel_output = enc_to_intel_output(encoder); | ||
189 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
190 | int pipe = intel_crtc->pipe; | ||
191 | u32 dvo_val; | ||
192 | u32 dvo_reg = dvo->dvo_reg, dvo_srcdim_reg; | ||
193 | int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B; | ||
194 | |||
195 | switch (dvo_reg) { | ||
196 | case DVOA: | ||
197 | default: | ||
198 | dvo_srcdim_reg = DVOA_SRCDIM; | ||
199 | break; | ||
200 | case DVOB: | ||
201 | dvo_srcdim_reg = DVOB_SRCDIM; | ||
202 | break; | ||
203 | case DVOC: | ||
204 | dvo_srcdim_reg = DVOC_SRCDIM; | ||
205 | break; | ||
206 | } | ||
207 | |||
208 | dvo->dev_ops->mode_set(dvo, mode, adjusted_mode); | ||
209 | |||
210 | /* Save the data order, since I don't know what it should be set to. */ | ||
211 | dvo_val = I915_READ(dvo_reg) & | ||
212 | (DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG); | ||
213 | dvo_val |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE | | ||
214 | DVO_BLANK_ACTIVE_HIGH; | ||
215 | |||
216 | if (pipe == 1) | ||
217 | dvo_val |= DVO_PIPE_B_SELECT; | ||
218 | dvo_val |= DVO_PIPE_STALL; | ||
219 | if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
220 | dvo_val |= DVO_HSYNC_ACTIVE_HIGH; | ||
221 | if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
222 | dvo_val |= DVO_VSYNC_ACTIVE_HIGH; | ||
223 | |||
224 | I915_WRITE(dpll_reg, I915_READ(dpll_reg) | DPLL_DVO_HIGH_SPEED); | ||
225 | |||
226 | /*I915_WRITE(DVOB_SRCDIM, | ||
227 | (adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | | ||
228 | (adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/ | ||
229 | I915_WRITE(dvo_srcdim_reg, | ||
230 | (adjusted_mode->hdisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) | | ||
231 | (adjusted_mode->vdisplay << DVO_SRCDIM_VERTICAL_SHIFT)); | ||
232 | /*I915_WRITE(DVOB, dvo_val);*/ | ||
233 | I915_WRITE(dvo_reg, dvo_val); | ||
234 | } | ||
235 | |||
236 | /** | ||
237 | * Detect the output connection on our DVO device. | ||
238 | * | ||
239 | * Unimplemented. | ||
240 | */ | ||
241 | static enum drm_connector_status intel_dvo_detect(struct drm_connector *connector) | ||
242 | { | ||
243 | struct intel_output *intel_output = to_intel_output(connector); | ||
244 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
245 | |||
246 | return dvo->dev_ops->detect(dvo); | ||
247 | } | ||
248 | |||
249 | static int intel_dvo_get_modes(struct drm_connector *connector) | ||
250 | { | ||
251 | struct intel_output *intel_output = to_intel_output(connector); | ||
252 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
253 | |||
254 | /* We should probably have an i2c driver get_modes function for those | ||
255 | * devices which will have a fixed set of modes determined by the chip | ||
256 | * (TV-out, for example), but for now with just TMDS and LVDS, | ||
257 | * that's not the case. | ||
258 | */ | ||
259 | intel_ddc_get_modes(intel_output); | ||
260 | if (!list_empty(&connector->probed_modes)) | ||
261 | return 1; | ||
262 | |||
263 | |||
264 | if (dvo->panel_fixed_mode != NULL) { | ||
265 | struct drm_display_mode *mode; | ||
266 | mode = drm_mode_duplicate(connector->dev, dvo->panel_fixed_mode); | ||
267 | if (mode) { | ||
268 | drm_mode_probed_add(connector, mode); | ||
269 | return 1; | ||
270 | } | ||
271 | } | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static void intel_dvo_destroy (struct drm_connector *connector) | ||
276 | { | ||
277 | struct intel_output *intel_output = to_intel_output(connector); | ||
278 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
279 | |||
280 | if (dvo) { | ||
281 | if (dvo->dev_ops->destroy) | ||
282 | dvo->dev_ops->destroy(dvo); | ||
283 | if (dvo->panel_fixed_mode) | ||
284 | kfree(dvo->panel_fixed_mode); | ||
285 | /* no need, in i830_dvoices[] now */ | ||
286 | //kfree(dvo); | ||
287 | } | ||
288 | if (intel_output->i2c_bus) | ||
289 | intel_i2c_destroy(intel_output->i2c_bus); | ||
290 | if (intel_output->ddc_bus) | ||
291 | intel_i2c_destroy(intel_output->ddc_bus); | ||
292 | drm_sysfs_connector_remove(connector); | ||
293 | drm_connector_cleanup(connector); | ||
294 | kfree(intel_output); | ||
295 | } | ||
296 | |||
297 | #ifdef RANDR_GET_CRTC_INTERFACE | ||
298 | static struct drm_crtc *intel_dvo_get_crtc(struct drm_connector *connector) | ||
299 | { | ||
300 | struct drm_device *dev = connector->dev; | ||
301 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
302 | struct intel_output *intel_output = to_intel_output(connector); | ||
303 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
304 | int pipe = !!(I915_READ(dvo->dvo_reg) & SDVO_PIPE_B_SELECT); | ||
305 | |||
306 | return intel_pipe_to_crtc(pScrn, pipe); | ||
307 | } | ||
308 | #endif | ||
309 | |||
310 | static const struct drm_encoder_helper_funcs intel_dvo_helper_funcs = { | ||
311 | .dpms = intel_dvo_dpms, | ||
312 | .mode_fixup = intel_dvo_mode_fixup, | ||
313 | .prepare = intel_encoder_prepare, | ||
314 | .mode_set = intel_dvo_mode_set, | ||
315 | .commit = intel_encoder_commit, | ||
316 | }; | ||
317 | |||
318 | static const struct drm_connector_funcs intel_dvo_connector_funcs = { | ||
319 | .save = intel_dvo_save, | ||
320 | .restore = intel_dvo_restore, | ||
321 | .detect = intel_dvo_detect, | ||
322 | .destroy = intel_dvo_destroy, | ||
323 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
324 | }; | ||
325 | |||
326 | static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = { | ||
327 | .mode_valid = intel_dvo_mode_valid, | ||
328 | .get_modes = intel_dvo_get_modes, | ||
329 | .best_encoder = intel_best_encoder, | ||
330 | }; | ||
331 | |||
332 | static void intel_dvo_enc_destroy(struct drm_encoder *encoder) | ||
333 | { | ||
334 | drm_encoder_cleanup(encoder); | ||
335 | } | ||
336 | |||
337 | static const struct drm_encoder_funcs intel_dvo_enc_funcs = { | ||
338 | .destroy = intel_dvo_enc_destroy, | ||
339 | }; | ||
340 | |||
341 | |||
342 | /** | ||
343 | * Attempts to get a fixed panel timing for LVDS (currently only the i830). | ||
344 | * | ||
345 | * Other chips with DVO LVDS will need to extend this to deal with the LVDS | ||
346 | * chip being on DVOB/C and having multiple pipes. | ||
347 | */ | ||
348 | static struct drm_display_mode * | ||
349 | intel_dvo_get_current_mode (struct drm_connector *connector) | ||
350 | { | ||
351 | struct drm_device *dev = connector->dev; | ||
352 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
353 | struct intel_output *intel_output = to_intel_output(connector); | ||
354 | struct intel_dvo_device *dvo = intel_output->dev_priv; | ||
355 | uint32_t dvo_reg = dvo->dvo_reg; | ||
356 | uint32_t dvo_val = I915_READ(dvo_reg); | ||
357 | struct drm_display_mode *mode = NULL; | ||
358 | |||
359 | /* If the DVO port is active, that'll be the LVDS, so we can pull out | ||
360 | * its timings to get how the BIOS set up the panel. | ||
361 | */ | ||
362 | if (dvo_val & DVO_ENABLE) { | ||
363 | struct drm_crtc *crtc; | ||
364 | int pipe = (dvo_val & DVO_PIPE_B_SELECT) ? 1 : 0; | ||
365 | |||
366 | crtc = intel_get_crtc_from_pipe(dev, pipe); | ||
367 | if (crtc) { | ||
368 | mode = intel_crtc_mode_get(dev, crtc); | ||
369 | |||
370 | if (mode) { | ||
371 | mode->type |= DRM_MODE_TYPE_PREFERRED; | ||
372 | if (dvo_val & DVO_HSYNC_ACTIVE_HIGH) | ||
373 | mode->flags |= DRM_MODE_FLAG_PHSYNC; | ||
374 | if (dvo_val & DVO_VSYNC_ACTIVE_HIGH) | ||
375 | mode->flags |= DRM_MODE_FLAG_PVSYNC; | ||
376 | } | ||
377 | } | ||
378 | } | ||
379 | return mode; | ||
380 | } | ||
381 | |||
382 | void intel_dvo_init(struct drm_device *dev) | ||
383 | { | ||
384 | struct intel_output *intel_output; | ||
385 | struct intel_dvo_device *dvo; | ||
386 | struct intel_i2c_chan *i2cbus = NULL; | ||
387 | int ret = 0; | ||
388 | int i; | ||
389 | int gpio_inited = 0; | ||
390 | int encoder_type = DRM_MODE_ENCODER_NONE; | ||
391 | intel_output = kzalloc (sizeof(struct intel_output), GFP_KERNEL); | ||
392 | if (!intel_output) | ||
393 | return; | ||
394 | |||
395 | /* Set up the DDC bus */ | ||
396 | intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "DVODDC_D"); | ||
397 | if (!intel_output->ddc_bus) | ||
398 | goto free_intel; | ||
399 | |||
400 | /* Now, try to find a controller */ | ||
401 | for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) { | ||
402 | struct drm_connector *connector = &intel_output->base; | ||
403 | int gpio; | ||
404 | |||
405 | dvo = &intel_dvo_devices[i]; | ||
406 | |||
407 | /* Allow the I2C driver info to specify the GPIO to be used in | ||
408 | * special cases, but otherwise default to what's defined | ||
409 | * in the spec. | ||
410 | */ | ||
411 | if (dvo->gpio != 0) | ||
412 | gpio = dvo->gpio; | ||
413 | else if (dvo->type == INTEL_DVO_CHIP_LVDS) | ||
414 | gpio = GPIOB; | ||
415 | else | ||
416 | gpio = GPIOE; | ||
417 | |||
418 | /* Set up the I2C bus necessary for the chip we're probing. | ||
419 | * It appears that everything is on GPIOE except for panels | ||
420 | * on i830 laptops, which are on GPIOB (DVOA). | ||
421 | */ | ||
422 | if (gpio_inited != gpio) { | ||
423 | if (i2cbus != NULL) | ||
424 | intel_i2c_destroy(i2cbus); | ||
425 | if (!(i2cbus = intel_i2c_create(dev, gpio, | ||
426 | gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) { | ||
427 | continue; | ||
428 | } | ||
429 | gpio_inited = gpio; | ||
430 | } | ||
431 | |||
432 | if (dvo->dev_ops!= NULL) | ||
433 | ret = dvo->dev_ops->init(dvo, i2cbus); | ||
434 | else | ||
435 | ret = false; | ||
436 | |||
437 | if (!ret) | ||
438 | continue; | ||
439 | |||
440 | intel_output->type = INTEL_OUTPUT_DVO; | ||
441 | switch (dvo->type) { | ||
442 | case INTEL_DVO_CHIP_TMDS: | ||
443 | drm_connector_init(dev, connector, | ||
444 | &intel_dvo_connector_funcs, | ||
445 | DRM_MODE_CONNECTOR_DVII); | ||
446 | encoder_type = DRM_MODE_ENCODER_TMDS; | ||
447 | break; | ||
448 | case INTEL_DVO_CHIP_LVDS: | ||
449 | drm_connector_init(dev, connector, | ||
450 | &intel_dvo_connector_funcs, | ||
451 | DRM_MODE_CONNECTOR_LVDS); | ||
452 | encoder_type = DRM_MODE_ENCODER_LVDS; | ||
453 | break; | ||
454 | } | ||
455 | |||
456 | drm_connector_helper_add(connector, | ||
457 | &intel_dvo_connector_helper_funcs); | ||
458 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
459 | connector->interlace_allowed = false; | ||
460 | connector->doublescan_allowed = false; | ||
461 | |||
462 | intel_output->dev_priv = dvo; | ||
463 | intel_output->i2c_bus = i2cbus; | ||
464 | |||
465 | drm_encoder_init(dev, &intel_output->enc, | ||
466 | &intel_dvo_enc_funcs, encoder_type); | ||
467 | drm_encoder_helper_add(&intel_output->enc, | ||
468 | &intel_dvo_helper_funcs); | ||
469 | |||
470 | drm_mode_connector_attach_encoder(&intel_output->base, | ||
471 | &intel_output->enc); | ||
472 | if (dvo->type == INTEL_DVO_CHIP_LVDS) { | ||
473 | /* For our LVDS chipsets, we should hopefully be able | ||
474 | * to dig the fixed panel mode out of the BIOS data. | ||
475 | * However, it's in a different format from the BIOS | ||
476 | * data on chipsets with integrated LVDS (stored in AIM | ||
477 | * headers, likely), so for now, just get the current | ||
478 | * mode being output through DVO. | ||
479 | */ | ||
480 | dvo->panel_fixed_mode = | ||
481 | intel_dvo_get_current_mode(connector); | ||
482 | dvo->panel_wants_dither = true; | ||
483 | } | ||
484 | |||
485 | drm_sysfs_connector_add(connector); | ||
486 | return; | ||
487 | } | ||
488 | |||
489 | intel_i2c_destroy(intel_output->ddc_bus); | ||
490 | /* Didn't find a chip, so tear down. */ | ||
491 | if (i2cbus != NULL) | ||
492 | intel_i2c_destroy(i2cbus); | ||
493 | free_intel: | ||
494 | kfree(intel_output); | ||
495 | } | ||
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c new file mode 100644 index 000000000000..afd1217b8a02 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_fb.c | |||
@@ -0,0 +1,925 @@ | |||
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 | static 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 | static 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 | |||
426 | static struct notifier_block paniced = { | ||
427 | .notifier_call = intelfb_panic, | ||
428 | }; | ||
429 | |||
430 | static int intelfb_create(struct drm_device *dev, uint32_t fb_width, | ||
431 | uint32_t fb_height, uint32_t surface_width, | ||
432 | uint32_t surface_height, | ||
433 | struct intel_framebuffer **intel_fb_p) | ||
434 | { | ||
435 | struct fb_info *info; | ||
436 | struct intelfb_par *par; | ||
437 | struct drm_framebuffer *fb; | ||
438 | struct intel_framebuffer *intel_fb; | ||
439 | struct drm_mode_fb_cmd mode_cmd; | ||
440 | struct drm_gem_object *fbo = NULL; | ||
441 | struct drm_i915_gem_object *obj_priv; | ||
442 | struct device *device = &dev->pdev->dev; | ||
443 | int size, ret, mmio_bar = IS_I9XX(dev) ? 0 : 1; | ||
444 | |||
445 | mode_cmd.width = surface_width; | ||
446 | mode_cmd.height = surface_height; | ||
447 | |||
448 | mode_cmd.bpp = 32; | ||
449 | mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 1) / 8), 64); | ||
450 | mode_cmd.depth = 24; | ||
451 | |||
452 | size = mode_cmd.pitch * mode_cmd.height; | ||
453 | size = ALIGN(size, PAGE_SIZE); | ||
454 | fbo = drm_gem_object_alloc(dev, size); | ||
455 | if (!fbo) { | ||
456 | printk(KERN_ERR "failed to allocate framebuffer\n"); | ||
457 | ret = -ENOMEM; | ||
458 | goto out; | ||
459 | } | ||
460 | obj_priv = fbo->driver_private; | ||
461 | |||
462 | mutex_lock(&dev->struct_mutex); | ||
463 | |||
464 | ret = i915_gem_object_pin(fbo, PAGE_SIZE); | ||
465 | if (ret) { | ||
466 | DRM_ERROR("failed to pin fb: %d\n", ret); | ||
467 | goto out_unref; | ||
468 | } | ||
469 | |||
470 | /* Flush everything out, we'll be doing GTT only from now on */ | ||
471 | i915_gem_object_set_to_gtt_domain(fbo, 1); | ||
472 | |||
473 | ret = intel_framebuffer_create(dev, &mode_cmd, &fb, fbo); | ||
474 | if (ret) { | ||
475 | DRM_ERROR("failed to allocate fb.\n"); | ||
476 | goto out_unref; | ||
477 | } | ||
478 | |||
479 | list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list); | ||
480 | |||
481 | intel_fb = to_intel_framebuffer(fb); | ||
482 | *intel_fb_p = intel_fb; | ||
483 | |||
484 | info = framebuffer_alloc(sizeof(struct intelfb_par), device); | ||
485 | if (!info) { | ||
486 | ret = -ENOMEM; | ||
487 | goto out_unref; | ||
488 | } | ||
489 | |||
490 | par = info->par; | ||
491 | |||
492 | strcpy(info->fix.id, "inteldrmfb"); | ||
493 | info->fix.type = FB_TYPE_PACKED_PIXELS; | ||
494 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
495 | info->fix.type_aux = 0; | ||
496 | info->fix.xpanstep = 1; /* doing it in hw */ | ||
497 | info->fix.ypanstep = 1; /* doing it in hw */ | ||
498 | info->fix.ywrapstep = 0; | ||
499 | info->fix.accel = FB_ACCEL_I830; | ||
500 | info->fix.type_aux = 0; | ||
501 | |||
502 | info->flags = FBINFO_DEFAULT; | ||
503 | |||
504 | info->fbops = &intelfb_ops; | ||
505 | |||
506 | info->fix.line_length = fb->pitch; | ||
507 | info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset; | ||
508 | info->fix.smem_len = size; | ||
509 | |||
510 | info->flags = FBINFO_DEFAULT; | ||
511 | |||
512 | info->screen_base = ioremap_wc(dev->agp->base + obj_priv->gtt_offset, | ||
513 | size); | ||
514 | if (!info->screen_base) { | ||
515 | ret = -ENOSPC; | ||
516 | goto out_unref; | ||
517 | } | ||
518 | info->screen_size = size; | ||
519 | |||
520 | // memset(info->screen_base, 0, size); | ||
521 | |||
522 | info->pseudo_palette = fb->pseudo_palette; | ||
523 | info->var.xres_virtual = fb->width; | ||
524 | info->var.yres_virtual = fb->height; | ||
525 | info->var.bits_per_pixel = fb->bits_per_pixel; | ||
526 | info->var.xoffset = 0; | ||
527 | info->var.yoffset = 0; | ||
528 | info->var.activate = FB_ACTIVATE_NOW; | ||
529 | info->var.height = -1; | ||
530 | info->var.width = -1; | ||
531 | |||
532 | info->var.xres = fb_width; | ||
533 | info->var.yres = fb_height; | ||
534 | |||
535 | /* FIXME: we really shouldn't expose mmio space at all */ | ||
536 | info->fix.mmio_start = pci_resource_start(dev->pdev, mmio_bar); | ||
537 | info->fix.mmio_len = pci_resource_len(dev->pdev, mmio_bar); | ||
538 | |||
539 | info->pixmap.size = 64*1024; | ||
540 | info->pixmap.buf_align = 8; | ||
541 | info->pixmap.access_align = 32; | ||
542 | info->pixmap.flags = FB_PIXMAP_SYSTEM; | ||
543 | info->pixmap.scan_align = 1; | ||
544 | |||
545 | switch(fb->depth) { | ||
546 | case 8: | ||
547 | info->var.red.offset = 0; | ||
548 | info->var.green.offset = 0; | ||
549 | info->var.blue.offset = 0; | ||
550 | info->var.red.length = 8; /* 8bit DAC */ | ||
551 | info->var.green.length = 8; | ||
552 | info->var.blue.length = 8; | ||
553 | info->var.transp.offset = 0; | ||
554 | info->var.transp.length = 0; | ||
555 | break; | ||
556 | case 15: | ||
557 | info->var.red.offset = 10; | ||
558 | info->var.green.offset = 5; | ||
559 | info->var.blue.offset = 0; | ||
560 | info->var.red.length = 5; | ||
561 | info->var.green.length = 5; | ||
562 | info->var.blue.length = 5; | ||
563 | info->var.transp.offset = 15; | ||
564 | info->var.transp.length = 1; | ||
565 | break; | ||
566 | case 16: | ||
567 | info->var.red.offset = 11; | ||
568 | info->var.green.offset = 5; | ||
569 | info->var.blue.offset = 0; | ||
570 | info->var.red.length = 5; | ||
571 | info->var.green.length = 6; | ||
572 | info->var.blue.length = 5; | ||
573 | info->var.transp.offset = 0; | ||
574 | break; | ||
575 | case 24: | ||
576 | info->var.red.offset = 16; | ||
577 | info->var.green.offset = 8; | ||
578 | info->var.blue.offset = 0; | ||
579 | info->var.red.length = 8; | ||
580 | info->var.green.length = 8; | ||
581 | info->var.blue.length = 8; | ||
582 | info->var.transp.offset = 0; | ||
583 | info->var.transp.length = 0; | ||
584 | break; | ||
585 | case 32: | ||
586 | info->var.red.offset = 16; | ||
587 | info->var.green.offset = 8; | ||
588 | info->var.blue.offset = 0; | ||
589 | info->var.red.length = 8; | ||
590 | info->var.green.length = 8; | ||
591 | info->var.blue.length = 8; | ||
592 | info->var.transp.offset = 24; | ||
593 | info->var.transp.length = 8; | ||
594 | break; | ||
595 | default: | ||
596 | break; | ||
597 | } | ||
598 | |||
599 | fb->fbdev = info; | ||
600 | |||
601 | par->intel_fb = intel_fb; | ||
602 | par->dev = dev; | ||
603 | |||
604 | /* To allow resizeing without swapping buffers */ | ||
605 | printk("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width, | ||
606 | intel_fb->base.height, obj_priv->gtt_offset, fbo); | ||
607 | |||
608 | mutex_unlock(&dev->struct_mutex); | ||
609 | return 0; | ||
610 | |||
611 | out_unref: | ||
612 | drm_gem_object_unreference(fbo); | ||
613 | mutex_unlock(&dev->struct_mutex); | ||
614 | out: | ||
615 | return ret; | ||
616 | } | ||
617 | |||
618 | static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *crtc) | ||
619 | { | ||
620 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
621 | struct intel_framebuffer *intel_fb; | ||
622 | struct drm_framebuffer *fb; | ||
623 | struct drm_connector *connector; | ||
624 | struct fb_info *info; | ||
625 | struct intelfb_par *par; | ||
626 | struct drm_mode_set *modeset; | ||
627 | unsigned int width, height; | ||
628 | int new_fb = 0; | ||
629 | int ret, i, conn_count; | ||
630 | |||
631 | if (!drm_helper_crtc_in_use(crtc)) | ||
632 | return 0; | ||
633 | |||
634 | if (!crtc->desired_mode) | ||
635 | return 0; | ||
636 | |||
637 | width = crtc->desired_mode->hdisplay; | ||
638 | height = crtc->desired_mode->vdisplay; | ||
639 | |||
640 | /* is there an fb bound to this crtc already */ | ||
641 | if (!intel_crtc->mode_set.fb) { | ||
642 | ret = intelfb_create(dev, width, height, width, height, &intel_fb); | ||
643 | if (ret) | ||
644 | return -EINVAL; | ||
645 | new_fb = 1; | ||
646 | } else { | ||
647 | fb = intel_crtc->mode_set.fb; | ||
648 | intel_fb = to_intel_framebuffer(fb); | ||
649 | if ((intel_fb->base.width < width) || (intel_fb->base.height < height)) | ||
650 | return -EINVAL; | ||
651 | } | ||
652 | |||
653 | info = intel_fb->base.fbdev; | ||
654 | par = info->par; | ||
655 | |||
656 | modeset = &intel_crtc->mode_set; | ||
657 | modeset->fb = &intel_fb->base; | ||
658 | conn_count = 0; | ||
659 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
660 | if (connector->encoder) | ||
661 | if (connector->encoder->crtc == modeset->crtc) { | ||
662 | modeset->connectors[conn_count] = connector; | ||
663 | conn_count++; | ||
664 | if (conn_count > INTELFB_CONN_LIMIT) | ||
665 | BUG(); | ||
666 | } | ||
667 | } | ||
668 | |||
669 | for (i = conn_count; i < INTELFB_CONN_LIMIT; i++) | ||
670 | modeset->connectors[i] = NULL; | ||
671 | |||
672 | par->crtc_ids[0] = crtc->base.id; | ||
673 | |||
674 | modeset->num_connectors = conn_count; | ||
675 | if (modeset->mode != modeset->crtc->desired_mode) | ||
676 | modeset->mode = modeset->crtc->desired_mode; | ||
677 | |||
678 | par->crtc_count = 1; | ||
679 | |||
680 | if (new_fb) { | ||
681 | info->var.pixclock = -1; | ||
682 | if (register_framebuffer(info) < 0) | ||
683 | return -EINVAL; | ||
684 | } else | ||
685 | intelfb_set_par(info); | ||
686 | |||
687 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, | ||
688 | info->fix.id); | ||
689 | |||
690 | /* Switch back to kernel console on panic */ | ||
691 | kernelfb_mode = *modeset; | ||
692 | atomic_notifier_chain_register(&panic_notifier_list, &paniced); | ||
693 | printk(KERN_INFO "registered panic notifier\n"); | ||
694 | |||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | static int intelfb_multi_fb_probe(struct drm_device *dev) | ||
699 | { | ||
700 | |||
701 | struct drm_crtc *crtc; | ||
702 | int ret = 0; | ||
703 | |||
704 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
705 | ret = intelfb_multi_fb_probe_crtc(dev, crtc); | ||
706 | if (ret) | ||
707 | return ret; | ||
708 | } | ||
709 | return ret; | ||
710 | } | ||
711 | |||
712 | static int intelfb_single_fb_probe(struct drm_device *dev) | ||
713 | { | ||
714 | struct drm_crtc *crtc; | ||
715 | struct drm_connector *connector; | ||
716 | unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1; | ||
717 | unsigned int surface_width = 0, surface_height = 0; | ||
718 | int new_fb = 0; | ||
719 | int crtc_count = 0; | ||
720 | int ret, i, conn_count = 0; | ||
721 | struct intel_framebuffer *intel_fb; | ||
722 | struct fb_info *info; | ||
723 | struct intelfb_par *par; | ||
724 | struct drm_mode_set *modeset = NULL; | ||
725 | |||
726 | DRM_DEBUG("\n"); | ||
727 | |||
728 | /* Get a count of crtcs now in use and new min/maxes width/heights */ | ||
729 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
730 | if (!drm_helper_crtc_in_use(crtc)) | ||
731 | continue; | ||
732 | |||
733 | crtc_count++; | ||
734 | if (!crtc->desired_mode) | ||
735 | continue; | ||
736 | |||
737 | /* Smallest mode determines console size... */ | ||
738 | if (crtc->desired_mode->hdisplay < fb_width) | ||
739 | fb_width = crtc->desired_mode->hdisplay; | ||
740 | |||
741 | if (crtc->desired_mode->vdisplay < fb_height) | ||
742 | fb_height = crtc->desired_mode->vdisplay; | ||
743 | |||
744 | /* ... but largest for memory allocation dimensions */ | ||
745 | if (crtc->desired_mode->hdisplay > surface_width) | ||
746 | surface_width = crtc->desired_mode->hdisplay; | ||
747 | |||
748 | if (crtc->desired_mode->vdisplay > surface_height) | ||
749 | surface_height = crtc->desired_mode->vdisplay; | ||
750 | } | ||
751 | |||
752 | if (crtc_count == 0 || fb_width == -1 || fb_height == -1) { | ||
753 | /* hmm everyone went away - assume VGA cable just fell out | ||
754 | and will come back later. */ | ||
755 | DRM_DEBUG("no CRTCs available?\n"); | ||
756 | return 0; | ||
757 | } | ||
758 | |||
759 | //fail | ||
760 | /* Find the fb for our new config */ | ||
761 | if (list_empty(&dev->mode_config.fb_kernel_list)) { | ||
762 | DRM_DEBUG("creating new fb (console size %dx%d, " | ||
763 | "buffer size %dx%d)\n", fb_width, fb_height, | ||
764 | surface_width, surface_height); | ||
765 | ret = intelfb_create(dev, fb_width, fb_height, surface_width, | ||
766 | surface_height, &intel_fb); | ||
767 | if (ret) | ||
768 | return -EINVAL; | ||
769 | new_fb = 1; | ||
770 | } else { | ||
771 | struct drm_framebuffer *fb; | ||
772 | |||
773 | fb = list_first_entry(&dev->mode_config.fb_kernel_list, | ||
774 | struct drm_framebuffer, filp_head); | ||
775 | intel_fb = to_intel_framebuffer(fb); | ||
776 | |||
777 | /* if someone hotplugs something bigger than we have already | ||
778 | * allocated, we are pwned. As really we can't resize an | ||
779 | * fbdev that is in the wild currently due to fbdev not really | ||
780 | * being designed for the lower layers moving stuff around | ||
781 | * under it. | ||
782 | * - so in the grand style of things - punt. | ||
783 | */ | ||
784 | if ((fb->width < surface_width) || | ||
785 | (fb->height < surface_height)) { | ||
786 | DRM_ERROR("fb not large enough for console\n"); | ||
787 | return -EINVAL; | ||
788 | } | ||
789 | } | ||
790 | // fail | ||
791 | |||
792 | info = intel_fb->base.fbdev; | ||
793 | par = info->par; | ||
794 | |||
795 | crtc_count = 0; | ||
796 | /* | ||
797 | * For each CRTC, set up the connector list for the CRTC's mode | ||
798 | * set configuration. | ||
799 | */ | ||
800 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | ||
801 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
802 | |||
803 | modeset = &intel_crtc->mode_set; | ||
804 | modeset->fb = &intel_fb->base; | ||
805 | conn_count = 0; | ||
806 | list_for_each_entry(connector, &dev->mode_config.connector_list, | ||
807 | head) { | ||
808 | if (!connector->encoder) | ||
809 | continue; | ||
810 | |||
811 | if(connector->encoder->crtc == modeset->crtc) { | ||
812 | modeset->connectors[conn_count++] = connector; | ||
813 | if (conn_count > INTELFB_CONN_LIMIT) | ||
814 | BUG(); | ||
815 | } | ||
816 | } | ||
817 | |||
818 | /* Zero out remaining connector pointers */ | ||
819 | for (i = conn_count; i < INTELFB_CONN_LIMIT; i++) | ||
820 | modeset->connectors[i] = NULL; | ||
821 | |||
822 | par->crtc_ids[crtc_count++] = crtc->base.id; | ||
823 | |||
824 | modeset->num_connectors = conn_count; | ||
825 | if (modeset->mode != modeset->crtc->desired_mode) | ||
826 | modeset->mode = modeset->crtc->desired_mode; | ||
827 | } | ||
828 | par->crtc_count = crtc_count; | ||
829 | |||
830 | if (new_fb) { | ||
831 | info->var.pixclock = -1; | ||
832 | if (register_framebuffer(info) < 0) | ||
833 | return -EINVAL; | ||
834 | } else | ||
835 | intelfb_set_par(info); | ||
836 | |||
837 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, | ||
838 | info->fix.id); | ||
839 | |||
840 | /* Switch back to kernel console on panic */ | ||
841 | kernelfb_mode = *modeset; | ||
842 | atomic_notifier_chain_register(&panic_notifier_list, &paniced); | ||
843 | printk(KERN_INFO "registered panic notifier\n"); | ||
844 | |||
845 | return 0; | ||
846 | } | ||
847 | |||
848 | /** | ||
849 | * intelfb_restore - restore the framebuffer console (kernel) config | ||
850 | * | ||
851 | * Restore's the kernel's fbcon mode, used for lastclose & panic paths. | ||
852 | */ | ||
853 | void intelfb_restore(void) | ||
854 | { | ||
855 | drm_crtc_helper_set_config(&kernelfb_mode); | ||
856 | } | ||
857 | |||
858 | static void intelfb_sysrq(int dummy1, struct tty_struct *dummy3) | ||
859 | { | ||
860 | intelfb_restore(); | ||
861 | } | ||
862 | |||
863 | static struct sysrq_key_op sysrq_intelfb_restore_op = { | ||
864 | .handler = intelfb_sysrq, | ||
865 | .help_msg = "force fb", | ||
866 | .action_msg = "force restore of fb console", | ||
867 | }; | ||
868 | |||
869 | int intelfb_probe(struct drm_device *dev) | ||
870 | { | ||
871 | int ret; | ||
872 | |||
873 | DRM_DEBUG("\n"); | ||
874 | |||
875 | /* something has changed in the lower levels of hell - deal with it | ||
876 | here */ | ||
877 | |||
878 | /* two modes : a) 1 fb to rule all crtcs. | ||
879 | b) one fb per crtc. | ||
880 | two actions 1) new connected device | ||
881 | 2) device removed. | ||
882 | case a/1 : if the fb surface isn't big enough - resize the surface fb. | ||
883 | if the fb size isn't big enough - resize fb into surface. | ||
884 | if everything big enough configure the new crtc/etc. | ||
885 | case a/2 : undo the configuration | ||
886 | possibly resize down the fb to fit the new configuration. | ||
887 | case b/1 : see if it is on a new crtc - setup a new fb and add it. | ||
888 | case b/2 : teardown the new fb. | ||
889 | */ | ||
890 | |||
891 | /* mode a first */ | ||
892 | /* search for an fb */ | ||
893 | if (i915_fbpercrtc == 1) { | ||
894 | ret = intelfb_multi_fb_probe(dev); | ||
895 | } else { | ||
896 | ret = intelfb_single_fb_probe(dev); | ||
897 | } | ||
898 | |||
899 | register_sysrq_key('g', &sysrq_intelfb_restore_op); | ||
900 | |||
901 | return ret; | ||
902 | } | ||
903 | EXPORT_SYMBOL(intelfb_probe); | ||
904 | |||
905 | int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) | ||
906 | { | ||
907 | struct fb_info *info; | ||
908 | |||
909 | if (!fb) | ||
910 | return -EINVAL; | ||
911 | |||
912 | info = fb->fbdev; | ||
913 | |||
914 | if (info) { | ||
915 | unregister_framebuffer(info); | ||
916 | iounmap(info->screen_base); | ||
917 | framebuffer_release(info); | ||
918 | } | ||
919 | |||
920 | atomic_notifier_chain_unregister(&panic_notifier_list, &paniced); | ||
921 | memset(&kernelfb_mode, 0, sizeof(struct drm_mode_set)); | ||
922 | return 0; | ||
923 | } | ||
924 | EXPORT_SYMBOL(intelfb_remove); | ||
925 | 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..fbbaa4f414a0 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_sdvo.c | |||
@@ -0,0 +1,1128 @@ | |||
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 | static 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 | static 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 | static void intel_sdvo_set_control_bus_switch(struct intel_output *intel_output, | ||
315 | u8 target) | ||
316 | { | ||
317 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1); | ||
318 | } | ||
319 | |||
320 | static bool intel_sdvo_set_target_input(struct intel_output *intel_output, bool target_0, bool target_1) | ||
321 | { | ||
322 | struct intel_sdvo_set_target_input_args targets = {0}; | ||
323 | u8 status; | ||
324 | |||
325 | if (target_0 && target_1) | ||
326 | return SDVO_CMD_STATUS_NOTSUPP; | ||
327 | |||
328 | if (target_1) | ||
329 | targets.target_1 = 1; | ||
330 | |||
331 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_TARGET_INPUT, &targets, | ||
332 | sizeof(targets)); | ||
333 | |||
334 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
335 | |||
336 | return (status == SDVO_CMD_STATUS_SUCCESS); | ||
337 | } | ||
338 | |||
339 | /** | ||
340 | * Return whether each input is trained. | ||
341 | * | ||
342 | * This function is making an assumption about the layout of the response, | ||
343 | * which should be checked against the docs. | ||
344 | */ | ||
345 | static bool intel_sdvo_get_trained_inputs(struct intel_output *intel_output, bool *input_1, bool *input_2) | ||
346 | { | ||
347 | struct intel_sdvo_get_trained_inputs_response response; | ||
348 | u8 status; | ||
349 | |||
350 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0); | ||
351 | status = intel_sdvo_read_response(intel_output, &response, sizeof(response)); | ||
352 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
353 | return false; | ||
354 | |||
355 | *input_1 = response.input0_trained; | ||
356 | *input_2 = response.input1_trained; | ||
357 | return true; | ||
358 | } | ||
359 | |||
360 | static bool intel_sdvo_get_active_outputs(struct intel_output *intel_output, | ||
361 | u16 *outputs) | ||
362 | { | ||
363 | u8 status; | ||
364 | |||
365 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ACTIVE_OUTPUTS, NULL, 0); | ||
366 | status = intel_sdvo_read_response(intel_output, outputs, sizeof(*outputs)); | ||
367 | |||
368 | return (status == SDVO_CMD_STATUS_SUCCESS); | ||
369 | } | ||
370 | |||
371 | static bool intel_sdvo_set_active_outputs(struct intel_output *intel_output, | ||
372 | u16 outputs) | ||
373 | { | ||
374 | u8 status; | ||
375 | |||
376 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs, | ||
377 | sizeof(outputs)); | ||
378 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
379 | return (status == SDVO_CMD_STATUS_SUCCESS); | ||
380 | } | ||
381 | |||
382 | static bool intel_sdvo_set_encoder_power_state(struct intel_output *intel_output, | ||
383 | int mode) | ||
384 | { | ||
385 | u8 status, state = SDVO_ENCODER_STATE_ON; | ||
386 | |||
387 | switch (mode) { | ||
388 | case DRM_MODE_DPMS_ON: | ||
389 | state = SDVO_ENCODER_STATE_ON; | ||
390 | break; | ||
391 | case DRM_MODE_DPMS_STANDBY: | ||
392 | state = SDVO_ENCODER_STATE_STANDBY; | ||
393 | break; | ||
394 | case DRM_MODE_DPMS_SUSPEND: | ||
395 | state = SDVO_ENCODER_STATE_SUSPEND; | ||
396 | break; | ||
397 | case DRM_MODE_DPMS_OFF: | ||
398 | state = SDVO_ENCODER_STATE_OFF; | ||
399 | break; | ||
400 | } | ||
401 | |||
402 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ENCODER_POWER_STATE, &state, | ||
403 | sizeof(state)); | ||
404 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
405 | |||
406 | return (status == SDVO_CMD_STATUS_SUCCESS); | ||
407 | } | ||
408 | |||
409 | static bool intel_sdvo_get_input_pixel_clock_range(struct intel_output *intel_output, | ||
410 | int *clock_min, | ||
411 | int *clock_max) | ||
412 | { | ||
413 | struct intel_sdvo_pixel_clock_range clocks; | ||
414 | u8 status; | ||
415 | |||
416 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, | ||
417 | NULL, 0); | ||
418 | |||
419 | status = intel_sdvo_read_response(intel_output, &clocks, sizeof(clocks)); | ||
420 | |||
421 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
422 | return false; | ||
423 | |||
424 | /* Convert the values from units of 10 kHz to kHz. */ | ||
425 | *clock_min = clocks.min * 10; | ||
426 | *clock_max = clocks.max * 10; | ||
427 | |||
428 | return true; | ||
429 | } | ||
430 | |||
431 | static bool intel_sdvo_set_target_output(struct intel_output *intel_output, | ||
432 | u16 outputs) | ||
433 | { | ||
434 | u8 status; | ||
435 | |||
436 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_TARGET_OUTPUT, &outputs, | ||
437 | sizeof(outputs)); | ||
438 | |||
439 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
440 | return (status == SDVO_CMD_STATUS_SUCCESS); | ||
441 | } | ||
442 | |||
443 | static bool intel_sdvo_get_timing(struct intel_output *intel_output, u8 cmd, | ||
444 | struct intel_sdvo_dtd *dtd) | ||
445 | { | ||
446 | u8 status; | ||
447 | |||
448 | intel_sdvo_write_cmd(intel_output, cmd, NULL, 0); | ||
449 | status = intel_sdvo_read_response(intel_output, &dtd->part1, | ||
450 | sizeof(dtd->part1)); | ||
451 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
452 | return false; | ||
453 | |||
454 | intel_sdvo_write_cmd(intel_output, cmd + 1, NULL, 0); | ||
455 | status = intel_sdvo_read_response(intel_output, &dtd->part2, | ||
456 | sizeof(dtd->part2)); | ||
457 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
458 | return false; | ||
459 | |||
460 | return true; | ||
461 | } | ||
462 | |||
463 | static bool intel_sdvo_get_input_timing(struct intel_output *intel_output, | ||
464 | struct intel_sdvo_dtd *dtd) | ||
465 | { | ||
466 | return intel_sdvo_get_timing(intel_output, | ||
467 | SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd); | ||
468 | } | ||
469 | |||
470 | static bool intel_sdvo_get_output_timing(struct intel_output *intel_output, | ||
471 | struct intel_sdvo_dtd *dtd) | ||
472 | { | ||
473 | return intel_sdvo_get_timing(intel_output, | ||
474 | SDVO_CMD_GET_OUTPUT_TIMINGS_PART1, dtd); | ||
475 | } | ||
476 | |||
477 | static bool intel_sdvo_set_timing(struct intel_output *intel_output, u8 cmd, | ||
478 | struct intel_sdvo_dtd *dtd) | ||
479 | { | ||
480 | u8 status; | ||
481 | |||
482 | intel_sdvo_write_cmd(intel_output, cmd, &dtd->part1, sizeof(dtd->part1)); | ||
483 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
484 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
485 | return false; | ||
486 | |||
487 | intel_sdvo_write_cmd(intel_output, cmd + 1, &dtd->part2, sizeof(dtd->part2)); | ||
488 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
489 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
490 | return false; | ||
491 | |||
492 | return true; | ||
493 | } | ||
494 | |||
495 | static bool intel_sdvo_set_input_timing(struct intel_output *intel_output, | ||
496 | struct intel_sdvo_dtd *dtd) | ||
497 | { | ||
498 | return intel_sdvo_set_timing(intel_output, | ||
499 | SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd); | ||
500 | } | ||
501 | |||
502 | static bool intel_sdvo_set_output_timing(struct intel_output *intel_output, | ||
503 | struct intel_sdvo_dtd *dtd) | ||
504 | { | ||
505 | return intel_sdvo_set_timing(intel_output, | ||
506 | SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd); | ||
507 | } | ||
508 | |||
509 | |||
510 | static int intel_sdvo_get_clock_rate_mult(struct intel_output *intel_output) | ||
511 | { | ||
512 | u8 response, status; | ||
513 | |||
514 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_CLOCK_RATE_MULT, NULL, 0); | ||
515 | status = intel_sdvo_read_response(intel_output, &response, 1); | ||
516 | |||
517 | if (status != SDVO_CMD_STATUS_SUCCESS) { | ||
518 | DRM_DEBUG("Couldn't get SDVO clock rate multiplier\n"); | ||
519 | return SDVO_CLOCK_RATE_MULT_1X; | ||
520 | } else { | ||
521 | DRM_DEBUG("Current clock rate multiplier: %d\n", response); | ||
522 | } | ||
523 | |||
524 | return response; | ||
525 | } | ||
526 | |||
527 | static bool intel_sdvo_set_clock_rate_mult(struct intel_output *intel_output, u8 val) | ||
528 | { | ||
529 | u8 status; | ||
530 | |||
531 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1); | ||
532 | status = intel_sdvo_read_response(intel_output, NULL, 0); | ||
533 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
534 | return false; | ||
535 | |||
536 | return true; | ||
537 | } | ||
538 | |||
539 | static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, | ||
540 | struct drm_display_mode *mode, | ||
541 | struct drm_display_mode *adjusted_mode) | ||
542 | { | ||
543 | /* Make the CRTC code factor in the SDVO pixel multiplier. The SDVO | ||
544 | * device will be told of the multiplier during mode_set. | ||
545 | */ | ||
546 | adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode); | ||
547 | return true; | ||
548 | } | ||
549 | |||
550 | static void intel_sdvo_mode_set(struct drm_encoder *encoder, | ||
551 | struct drm_display_mode *mode, | ||
552 | struct drm_display_mode *adjusted_mode) | ||
553 | { | ||
554 | struct drm_device *dev = encoder->dev; | ||
555 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
556 | struct drm_crtc *crtc = encoder->crtc; | ||
557 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
558 | struct intel_output *intel_output = enc_to_intel_output(encoder); | ||
559 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
560 | u16 width, height; | ||
561 | u16 h_blank_len, h_sync_len, v_blank_len, v_sync_len; | ||
562 | u16 h_sync_offset, v_sync_offset; | ||
563 | u32 sdvox; | ||
564 | struct intel_sdvo_dtd output_dtd; | ||
565 | int sdvo_pixel_multiply; | ||
566 | |||
567 | if (!mode) | ||
568 | return; | ||
569 | |||
570 | width = mode->crtc_hdisplay; | ||
571 | height = mode->crtc_vdisplay; | ||
572 | |||
573 | /* do some mode translations */ | ||
574 | h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start; | ||
575 | h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; | ||
576 | |||
577 | v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start; | ||
578 | v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; | ||
579 | |||
580 | h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start; | ||
581 | v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start; | ||
582 | |||
583 | output_dtd.part1.clock = mode->clock / 10; | ||
584 | output_dtd.part1.h_active = width & 0xff; | ||
585 | output_dtd.part1.h_blank = h_blank_len & 0xff; | ||
586 | output_dtd.part1.h_high = (((width >> 8) & 0xf) << 4) | | ||
587 | ((h_blank_len >> 8) & 0xf); | ||
588 | output_dtd.part1.v_active = height & 0xff; | ||
589 | output_dtd.part1.v_blank = v_blank_len & 0xff; | ||
590 | output_dtd.part1.v_high = (((height >> 8) & 0xf) << 4) | | ||
591 | ((v_blank_len >> 8) & 0xf); | ||
592 | |||
593 | output_dtd.part2.h_sync_off = h_sync_offset; | ||
594 | output_dtd.part2.h_sync_width = h_sync_len & 0xff; | ||
595 | output_dtd.part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 | | ||
596 | (v_sync_len & 0xf); | ||
597 | output_dtd.part2.sync_off_width_high = ((h_sync_offset & 0x300) >> 2) | | ||
598 | ((h_sync_len & 0x300) >> 4) | ((v_sync_offset & 0x30) >> 2) | | ||
599 | ((v_sync_len & 0x30) >> 4); | ||
600 | |||
601 | output_dtd.part2.dtd_flags = 0x18; | ||
602 | if (mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
603 | output_dtd.part2.dtd_flags |= 0x2; | ||
604 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
605 | output_dtd.part2.dtd_flags |= 0x4; | ||
606 | |||
607 | output_dtd.part2.sdvo_flags = 0; | ||
608 | output_dtd.part2.v_sync_off_high = v_sync_offset & 0xc0; | ||
609 | output_dtd.part2.reserved = 0; | ||
610 | |||
611 | /* Set the output timing to the screen */ | ||
612 | intel_sdvo_set_target_output(intel_output, sdvo_priv->active_outputs); | ||
613 | intel_sdvo_set_output_timing(intel_output, &output_dtd); | ||
614 | |||
615 | /* Set the input timing to the screen. Assume always input 0. */ | ||
616 | intel_sdvo_set_target_input(intel_output, true, false); | ||
617 | |||
618 | /* We would like to use i830_sdvo_create_preferred_input_timing() to | ||
619 | * provide the device with a timing it can support, if it supports that | ||
620 | * feature. However, presumably we would need to adjust the CRTC to | ||
621 | * output the preferred timing, and we don't support that currently. | ||
622 | */ | ||
623 | intel_sdvo_set_input_timing(intel_output, &output_dtd); | ||
624 | |||
625 | switch (intel_sdvo_get_pixel_multiplier(mode)) { | ||
626 | case 1: | ||
627 | intel_sdvo_set_clock_rate_mult(intel_output, | ||
628 | SDVO_CLOCK_RATE_MULT_1X); | ||
629 | break; | ||
630 | case 2: | ||
631 | intel_sdvo_set_clock_rate_mult(intel_output, | ||
632 | SDVO_CLOCK_RATE_MULT_2X); | ||
633 | break; | ||
634 | case 4: | ||
635 | intel_sdvo_set_clock_rate_mult(intel_output, | ||
636 | SDVO_CLOCK_RATE_MULT_4X); | ||
637 | break; | ||
638 | } | ||
639 | |||
640 | /* Set the SDVO control regs. */ | ||
641 | if (0/*IS_I965GM(dev)*/) { | ||
642 | sdvox = SDVO_BORDER_ENABLE; | ||
643 | } else { | ||
644 | sdvox = I915_READ(sdvo_priv->output_device); | ||
645 | switch (sdvo_priv->output_device) { | ||
646 | case SDVOB: | ||
647 | sdvox &= SDVOB_PRESERVE_MASK; | ||
648 | break; | ||
649 | case SDVOC: | ||
650 | sdvox &= SDVOC_PRESERVE_MASK; | ||
651 | break; | ||
652 | } | ||
653 | sdvox |= (9 << 19) | SDVO_BORDER_ENABLE; | ||
654 | } | ||
655 | if (intel_crtc->pipe == 1) | ||
656 | sdvox |= SDVO_PIPE_B_SELECT; | ||
657 | |||
658 | sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode); | ||
659 | if (IS_I965G(dev)) { | ||
660 | /* done in crtc_mode_set as the dpll_md reg must be written | ||
661 | early */ | ||
662 | } else if (IS_I945G(dev) || IS_I945GM(dev)) { | ||
663 | /* done in crtc_mode_set as it lives inside the | ||
664 | dpll register */ | ||
665 | } else { | ||
666 | sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; | ||
667 | } | ||
668 | |||
669 | intel_sdvo_write_sdvox(intel_output, sdvox); | ||
670 | } | ||
671 | |||
672 | static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) | ||
673 | { | ||
674 | struct drm_device *dev = encoder->dev; | ||
675 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
676 | struct intel_output *intel_output = enc_to_intel_output(encoder); | ||
677 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
678 | u32 temp; | ||
679 | |||
680 | if (mode != DRM_MODE_DPMS_ON) { | ||
681 | intel_sdvo_set_active_outputs(intel_output, 0); | ||
682 | if (0) | ||
683 | intel_sdvo_set_encoder_power_state(intel_output, mode); | ||
684 | |||
685 | if (mode == DRM_MODE_DPMS_OFF) { | ||
686 | temp = I915_READ(sdvo_priv->output_device); | ||
687 | if ((temp & SDVO_ENABLE) != 0) { | ||
688 | intel_sdvo_write_sdvox(intel_output, temp & ~SDVO_ENABLE); | ||
689 | } | ||
690 | } | ||
691 | } else { | ||
692 | bool input1, input2; | ||
693 | int i; | ||
694 | u8 status; | ||
695 | |||
696 | temp = I915_READ(sdvo_priv->output_device); | ||
697 | if ((temp & SDVO_ENABLE) == 0) | ||
698 | intel_sdvo_write_sdvox(intel_output, temp | SDVO_ENABLE); | ||
699 | for (i = 0; i < 2; i++) | ||
700 | intel_wait_for_vblank(dev); | ||
701 | |||
702 | status = intel_sdvo_get_trained_inputs(intel_output, &input1, | ||
703 | &input2); | ||
704 | |||
705 | |||
706 | /* Warn if the device reported failure to sync. | ||
707 | * A lot of SDVO devices fail to notify of sync, but it's | ||
708 | * a given it the status is a success, we succeeded. | ||
709 | */ | ||
710 | if (status == SDVO_CMD_STATUS_SUCCESS && !input1) { | ||
711 | DRM_DEBUG("First %s output reported failure to sync\n", | ||
712 | SDVO_NAME(sdvo_priv)); | ||
713 | } | ||
714 | |||
715 | if (0) | ||
716 | intel_sdvo_set_encoder_power_state(intel_output, mode); | ||
717 | intel_sdvo_set_active_outputs(intel_output, sdvo_priv->active_outputs); | ||
718 | } | ||
719 | return; | ||
720 | } | ||
721 | |||
722 | static void intel_sdvo_save(struct drm_connector *connector) | ||
723 | { | ||
724 | struct drm_device *dev = connector->dev; | ||
725 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
726 | struct intel_output *intel_output = to_intel_output(connector); | ||
727 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
728 | int o; | ||
729 | |||
730 | sdvo_priv->save_sdvo_mult = intel_sdvo_get_clock_rate_mult(intel_output); | ||
731 | intel_sdvo_get_active_outputs(intel_output, &sdvo_priv->save_active_outputs); | ||
732 | |||
733 | if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) { | ||
734 | intel_sdvo_set_target_input(intel_output, true, false); | ||
735 | intel_sdvo_get_input_timing(intel_output, | ||
736 | &sdvo_priv->save_input_dtd_1); | ||
737 | } | ||
738 | |||
739 | if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) { | ||
740 | intel_sdvo_set_target_input(intel_output, false, true); | ||
741 | intel_sdvo_get_input_timing(intel_output, | ||
742 | &sdvo_priv->save_input_dtd_2); | ||
743 | } | ||
744 | |||
745 | for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++) | ||
746 | { | ||
747 | u16 this_output = (1 << o); | ||
748 | if (sdvo_priv->caps.output_flags & this_output) | ||
749 | { | ||
750 | intel_sdvo_set_target_output(intel_output, this_output); | ||
751 | intel_sdvo_get_output_timing(intel_output, | ||
752 | &sdvo_priv->save_output_dtd[o]); | ||
753 | } | ||
754 | } | ||
755 | |||
756 | sdvo_priv->save_SDVOX = I915_READ(sdvo_priv->output_device); | ||
757 | } | ||
758 | |||
759 | static void intel_sdvo_restore(struct drm_connector *connector) | ||
760 | { | ||
761 | struct drm_device *dev = connector->dev; | ||
762 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
763 | struct intel_output *intel_output = to_intel_output(connector); | ||
764 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
765 | int o; | ||
766 | int i; | ||
767 | bool input1, input2; | ||
768 | u8 status; | ||
769 | |||
770 | intel_sdvo_set_active_outputs(intel_output, 0); | ||
771 | |||
772 | for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++) | ||
773 | { | ||
774 | u16 this_output = (1 << o); | ||
775 | if (sdvo_priv->caps.output_flags & this_output) { | ||
776 | intel_sdvo_set_target_output(intel_output, this_output); | ||
777 | intel_sdvo_set_output_timing(intel_output, &sdvo_priv->save_output_dtd[o]); | ||
778 | } | ||
779 | } | ||
780 | |||
781 | if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) { | ||
782 | intel_sdvo_set_target_input(intel_output, true, false); | ||
783 | intel_sdvo_set_input_timing(intel_output, &sdvo_priv->save_input_dtd_1); | ||
784 | } | ||
785 | |||
786 | if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) { | ||
787 | intel_sdvo_set_target_input(intel_output, false, true); | ||
788 | intel_sdvo_set_input_timing(intel_output, &sdvo_priv->save_input_dtd_2); | ||
789 | } | ||
790 | |||
791 | intel_sdvo_set_clock_rate_mult(intel_output, sdvo_priv->save_sdvo_mult); | ||
792 | |||
793 | I915_WRITE(sdvo_priv->output_device, sdvo_priv->save_SDVOX); | ||
794 | |||
795 | if (sdvo_priv->save_SDVOX & SDVO_ENABLE) | ||
796 | { | ||
797 | for (i = 0; i < 2; i++) | ||
798 | intel_wait_for_vblank(dev); | ||
799 | status = intel_sdvo_get_trained_inputs(intel_output, &input1, &input2); | ||
800 | if (status == SDVO_CMD_STATUS_SUCCESS && !input1) | ||
801 | DRM_DEBUG("First %s output reported failure to sync\n", | ||
802 | SDVO_NAME(sdvo_priv)); | ||
803 | } | ||
804 | |||
805 | intel_sdvo_set_active_outputs(intel_output, sdvo_priv->save_active_outputs); | ||
806 | } | ||
807 | |||
808 | static int intel_sdvo_mode_valid(struct drm_connector *connector, | ||
809 | struct drm_display_mode *mode) | ||
810 | { | ||
811 | struct intel_output *intel_output = to_intel_output(connector); | ||
812 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
813 | |||
814 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | ||
815 | return MODE_NO_DBLESCAN; | ||
816 | |||
817 | if (sdvo_priv->pixel_clock_min > mode->clock) | ||
818 | return MODE_CLOCK_LOW; | ||
819 | |||
820 | if (sdvo_priv->pixel_clock_max < mode->clock) | ||
821 | return MODE_CLOCK_HIGH; | ||
822 | |||
823 | return MODE_OK; | ||
824 | } | ||
825 | |||
826 | static bool intel_sdvo_get_capabilities(struct intel_output *intel_output, struct intel_sdvo_caps *caps) | ||
827 | { | ||
828 | u8 status; | ||
829 | |||
830 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0); | ||
831 | status = intel_sdvo_read_response(intel_output, caps, sizeof(*caps)); | ||
832 | if (status != SDVO_CMD_STATUS_SUCCESS) | ||
833 | return false; | ||
834 | |||
835 | return true; | ||
836 | } | ||
837 | |||
838 | struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB) | ||
839 | { | ||
840 | struct drm_connector *connector = NULL; | ||
841 | struct intel_output *iout = NULL; | ||
842 | struct intel_sdvo_priv *sdvo; | ||
843 | |||
844 | /* find the sdvo connector */ | ||
845 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
846 | iout = to_intel_output(connector); | ||
847 | |||
848 | if (iout->type != INTEL_OUTPUT_SDVO) | ||
849 | continue; | ||
850 | |||
851 | sdvo = iout->dev_priv; | ||
852 | |||
853 | if (sdvo->output_device == SDVOB && sdvoB) | ||
854 | return connector; | ||
855 | |||
856 | if (sdvo->output_device == SDVOC && !sdvoB) | ||
857 | return connector; | ||
858 | |||
859 | } | ||
860 | |||
861 | return NULL; | ||
862 | } | ||
863 | |||
864 | int intel_sdvo_supports_hotplug(struct drm_connector *connector) | ||
865 | { | ||
866 | u8 response[2]; | ||
867 | u8 status; | ||
868 | struct intel_output *intel_output; | ||
869 | DRM_DEBUG("\n"); | ||
870 | |||
871 | if (!connector) | ||
872 | return 0; | ||
873 | |||
874 | intel_output = to_intel_output(connector); | ||
875 | |||
876 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); | ||
877 | status = intel_sdvo_read_response(intel_output, &response, 2); | ||
878 | |||
879 | if (response[0] !=0) | ||
880 | return 1; | ||
881 | |||
882 | return 0; | ||
883 | } | ||
884 | |||
885 | void intel_sdvo_set_hotplug(struct drm_connector *connector, int on) | ||
886 | { | ||
887 | u8 response[2]; | ||
888 | u8 status; | ||
889 | struct intel_output *intel_output = to_intel_output(connector); | ||
890 | |||
891 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); | ||
892 | intel_sdvo_read_response(intel_output, &response, 2); | ||
893 | |||
894 | if (on) { | ||
895 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); | ||
896 | status = intel_sdvo_read_response(intel_output, &response, 2); | ||
897 | |||
898 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); | ||
899 | } else { | ||
900 | response[0] = 0; | ||
901 | response[1] = 0; | ||
902 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); | ||
903 | } | ||
904 | |||
905 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); | ||
906 | intel_sdvo_read_response(intel_output, &response, 2); | ||
907 | } | ||
908 | |||
909 | static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector) | ||
910 | { | ||
911 | u8 response[2]; | ||
912 | u8 status; | ||
913 | struct intel_output *intel_output = to_intel_output(connector); | ||
914 | |||
915 | intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); | ||
916 | status = intel_sdvo_read_response(intel_output, &response, 2); | ||
917 | |||
918 | DRM_DEBUG("SDVO response %d %d\n", response[0], response[1]); | ||
919 | if ((response[0] != 0) || (response[1] != 0)) | ||
920 | return connector_status_connected; | ||
921 | else | ||
922 | return connector_status_disconnected; | ||
923 | } | ||
924 | |||
925 | static int intel_sdvo_get_modes(struct drm_connector *connector) | ||
926 | { | ||
927 | struct intel_output *intel_output = to_intel_output(connector); | ||
928 | |||
929 | /* set the bus switch and get the modes */ | ||
930 | intel_sdvo_set_control_bus_switch(intel_output, SDVO_CONTROL_BUS_DDC2); | ||
931 | intel_ddc_get_modes(intel_output); | ||
932 | |||
933 | if (list_empty(&connector->probed_modes)) | ||
934 | return 0; | ||
935 | return 1; | ||
936 | } | ||
937 | |||
938 | static void intel_sdvo_destroy(struct drm_connector *connector) | ||
939 | { | ||
940 | struct intel_output *intel_output = to_intel_output(connector); | ||
941 | |||
942 | if (intel_output->i2c_bus) | ||
943 | intel_i2c_destroy(intel_output->i2c_bus); | ||
944 | drm_sysfs_connector_remove(connector); | ||
945 | drm_connector_cleanup(connector); | ||
946 | kfree(intel_output); | ||
947 | } | ||
948 | |||
949 | static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = { | ||
950 | .dpms = intel_sdvo_dpms, | ||
951 | .mode_fixup = intel_sdvo_mode_fixup, | ||
952 | .prepare = intel_encoder_prepare, | ||
953 | .mode_set = intel_sdvo_mode_set, | ||
954 | .commit = intel_encoder_commit, | ||
955 | }; | ||
956 | |||
957 | static const struct drm_connector_funcs intel_sdvo_connector_funcs = { | ||
958 | .save = intel_sdvo_save, | ||
959 | .restore = intel_sdvo_restore, | ||
960 | .detect = intel_sdvo_detect, | ||
961 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
962 | .destroy = intel_sdvo_destroy, | ||
963 | }; | ||
964 | |||
965 | static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = { | ||
966 | .get_modes = intel_sdvo_get_modes, | ||
967 | .mode_valid = intel_sdvo_mode_valid, | ||
968 | .best_encoder = intel_best_encoder, | ||
969 | }; | ||
970 | |||
971 | static void intel_sdvo_enc_destroy(struct drm_encoder *encoder) | ||
972 | { | ||
973 | drm_encoder_cleanup(encoder); | ||
974 | } | ||
975 | |||
976 | static const struct drm_encoder_funcs intel_sdvo_enc_funcs = { | ||
977 | .destroy = intel_sdvo_enc_destroy, | ||
978 | }; | ||
979 | |||
980 | |||
981 | void intel_sdvo_init(struct drm_device *dev, int output_device) | ||
982 | { | ||
983 | struct drm_connector *connector; | ||
984 | struct intel_output *intel_output; | ||
985 | struct intel_sdvo_priv *sdvo_priv; | ||
986 | struct intel_i2c_chan *i2cbus = NULL; | ||
987 | int connector_type; | ||
988 | u8 ch[0x40]; | ||
989 | int i; | ||
990 | int encoder_type, output_id; | ||
991 | |||
992 | intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL); | ||
993 | if (!intel_output) { | ||
994 | return; | ||
995 | } | ||
996 | |||
997 | connector = &intel_output->base; | ||
998 | |||
999 | drm_connector_init(dev, connector, &intel_sdvo_connector_funcs, | ||
1000 | DRM_MODE_CONNECTOR_Unknown); | ||
1001 | drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs); | ||
1002 | sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1); | ||
1003 | intel_output->type = INTEL_OUTPUT_SDVO; | ||
1004 | |||
1005 | connector->interlace_allowed = 0; | ||
1006 | connector->doublescan_allowed = 0; | ||
1007 | |||
1008 | /* setup the DDC bus. */ | ||
1009 | if (output_device == SDVOB) | ||
1010 | i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB"); | ||
1011 | else | ||
1012 | i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC"); | ||
1013 | |||
1014 | if (!i2cbus) | ||
1015 | goto err_connector; | ||
1016 | |||
1017 | sdvo_priv->i2c_bus = i2cbus; | ||
1018 | |||
1019 | if (output_device == SDVOB) { | ||
1020 | output_id = 1; | ||
1021 | sdvo_priv->i2c_bus->slave_addr = 0x38; | ||
1022 | } else { | ||
1023 | output_id = 2; | ||
1024 | sdvo_priv->i2c_bus->slave_addr = 0x39; | ||
1025 | } | ||
1026 | |||
1027 | sdvo_priv->output_device = output_device; | ||
1028 | intel_output->i2c_bus = i2cbus; | ||
1029 | intel_output->dev_priv = sdvo_priv; | ||
1030 | |||
1031 | |||
1032 | /* Read the regs to test if we can talk to the device */ | ||
1033 | for (i = 0; i < 0x40; i++) { | ||
1034 | if (!intel_sdvo_read_byte(intel_output, i, &ch[i])) { | ||
1035 | DRM_DEBUG("No SDVO device found on SDVO%c\n", | ||
1036 | output_device == SDVOB ? 'B' : 'C'); | ||
1037 | goto err_i2c; | ||
1038 | } | ||
1039 | } | ||
1040 | |||
1041 | intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps); | ||
1042 | |||
1043 | memset(&sdvo_priv->active_outputs, 0, sizeof(sdvo_priv->active_outputs)); | ||
1044 | |||
1045 | /* TODO, CVBS, SVID, YPRPB & SCART outputs. */ | ||
1046 | if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0) | ||
1047 | { | ||
1048 | sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0; | ||
1049 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
1050 | encoder_type = DRM_MODE_ENCODER_DAC; | ||
1051 | connector_type = DRM_MODE_CONNECTOR_VGA; | ||
1052 | } | ||
1053 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1) | ||
1054 | { | ||
1055 | sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1; | ||
1056 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
1057 | encoder_type = DRM_MODE_ENCODER_DAC; | ||
1058 | connector_type = DRM_MODE_CONNECTOR_VGA; | ||
1059 | } | ||
1060 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0) | ||
1061 | { | ||
1062 | sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS0; | ||
1063 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
1064 | encoder_type = DRM_MODE_ENCODER_TMDS; | ||
1065 | connector_type = DRM_MODE_CONNECTOR_DVID; | ||
1066 | } | ||
1067 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS1) | ||
1068 | { | ||
1069 | sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS1; | ||
1070 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
1071 | encoder_type = DRM_MODE_ENCODER_TMDS; | ||
1072 | connector_type = DRM_MODE_CONNECTOR_DVID; | ||
1073 | } | ||
1074 | else | ||
1075 | { | ||
1076 | unsigned char bytes[2]; | ||
1077 | |||
1078 | memcpy (bytes, &sdvo_priv->caps.output_flags, 2); | ||
1079 | DRM_DEBUG("%s: No active RGB or TMDS outputs (0x%02x%02x)\n", | ||
1080 | SDVO_NAME(sdvo_priv), | ||
1081 | bytes[0], bytes[1]); | ||
1082 | goto err_i2c; | ||
1083 | } | ||
1084 | |||
1085 | drm_encoder_init(dev, &intel_output->enc, &intel_sdvo_enc_funcs, encoder_type); | ||
1086 | drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs); | ||
1087 | connector->connector_type = connector_type; | ||
1088 | |||
1089 | drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); | ||
1090 | drm_sysfs_connector_add(connector); | ||
1091 | |||
1092 | /* Set the input timing to the screen. Assume always input 0. */ | ||
1093 | intel_sdvo_set_target_input(intel_output, true, false); | ||
1094 | |||
1095 | intel_sdvo_get_input_pixel_clock_range(intel_output, | ||
1096 | &sdvo_priv->pixel_clock_min, | ||
1097 | &sdvo_priv->pixel_clock_max); | ||
1098 | |||
1099 | |||
1100 | DRM_DEBUG("%s device VID/DID: %02X:%02X.%02X, " | ||
1101 | "clock range %dMHz - %dMHz, " | ||
1102 | "input 1: %c, input 2: %c, " | ||
1103 | "output 1: %c, output 2: %c\n", | ||
1104 | SDVO_NAME(sdvo_priv), | ||
1105 | sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id, | ||
1106 | sdvo_priv->caps.device_rev_id, | ||
1107 | sdvo_priv->pixel_clock_min / 1000, | ||
1108 | sdvo_priv->pixel_clock_max / 1000, | ||
1109 | (sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N', | ||
1110 | (sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N', | ||
1111 | /* check currently supported outputs */ | ||
1112 | sdvo_priv->caps.output_flags & | ||
1113 | (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N', | ||
1114 | sdvo_priv->caps.output_flags & | ||
1115 | (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); | ||
1116 | |||
1117 | intel_output->ddc_bus = i2cbus; | ||
1118 | |||
1119 | return; | ||
1120 | |||
1121 | err_i2c: | ||
1122 | intel_i2c_destroy(intel_output->i2c_bus); | ||
1123 | err_connector: | ||
1124 | drm_connector_cleanup(connector); | ||
1125 | kfree(intel_output); | ||
1126 | |||
1127 | return; | ||
1128 | } | ||
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..fbb35dc56f5c --- /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 | static 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 | } | ||