Rev 3031 | Rev 6084 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3031 | Rev 5060 | ||
---|---|---|---|
1 | /* |
1 | /* |
2 | * Copyright © 2006 Intel Corporation |
2 | * Copyright © 2006 Intel Corporation |
3 | * |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), |
5 | * copy of this software and associated documentation files (the "Software"), |
6 | * to deal in the Software without restriction, including without limitation |
6 | * to deal in the Software without restriction, including without limitation |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
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 |
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: |
9 | * Software is furnished to do so, subject to the following conditions: |
10 | * |
10 | * |
11 | * The above copyright notice and this permission notice (including the next |
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 |
12 | * paragraph) shall be included in all copies or substantial portions of the |
13 | * Software. |
13 | * Software. |
14 | * |
14 | * |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
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, |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
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 |
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 |
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 |
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
21 | * DEALINGS IN THE SOFTWARE. |
21 | * DEALINGS IN THE SOFTWARE. |
22 | * |
22 | * |
23 | * Authors: |
23 | * Authors: |
24 | * Eric Anholt |
24 | * Eric Anholt |
25 | * |
25 | * |
26 | */ |
26 | */ |
27 | 27 | ||
28 | #include "dvo.h" |
28 | #include "dvo.h" |
29 | 29 | ||
30 | /* |
30 | /* |
31 | * register definitions for the i82807aa. |
31 | * register definitions for the i82807aa. |
32 | * |
32 | * |
33 | * Documentation on this chipset can be found in datasheet #29069001 at |
33 | * Documentation on this chipset can be found in datasheet #29069001 at |
34 | * intel.com. |
34 | * intel.com. |
35 | */ |
35 | */ |
36 | 36 | ||
37 | /* |
37 | /* |
38 | * VCH Revision & GMBus Base Addr |
38 | * VCH Revision & GMBus Base Addr |
39 | */ |
39 | */ |
40 | #define VR00 0x00 |
40 | #define VR00 0x00 |
41 | # define VR00_BASE_ADDRESS_MASK 0x007f |
41 | # define VR00_BASE_ADDRESS_MASK 0x007f |
42 | 42 | ||
43 | /* |
43 | /* |
44 | * Functionality Enable |
44 | * Functionality Enable |
45 | */ |
45 | */ |
46 | #define VR01 0x01 |
46 | #define VR01 0x01 |
47 | 47 | ||
48 | /* |
48 | /* |
49 | * Enable the panel fitter |
49 | * Enable the panel fitter |
50 | */ |
50 | */ |
51 | # define VR01_PANEL_FIT_ENABLE (1 << 3) |
51 | # define VR01_PANEL_FIT_ENABLE (1 << 3) |
52 | /* |
52 | /* |
53 | * Enables the LCD display. |
53 | * Enables the LCD display. |
54 | * |
54 | * |
55 | * This must not be set while VR01_DVO_BYPASS_ENABLE is set. |
55 | * This must not be set while VR01_DVO_BYPASS_ENABLE is set. |
56 | */ |
56 | */ |
57 | # define VR01_LCD_ENABLE (1 << 2) |
57 | # define VR01_LCD_ENABLE (1 << 2) |
58 | /** Enables the DVO repeater. */ |
58 | /** Enables the DVO repeater. */ |
59 | # define VR01_DVO_BYPASS_ENABLE (1 << 1) |
59 | # define VR01_DVO_BYPASS_ENABLE (1 << 1) |
60 | /** Enables the DVO clock */ |
60 | /** Enables the DVO clock */ |
61 | # define VR01_DVO_ENABLE (1 << 0) |
61 | # define VR01_DVO_ENABLE (1 << 0) |
62 | 62 | ||
63 | /* |
63 | /* |
64 | * LCD Interface Format |
64 | * LCD Interface Format |
65 | */ |
65 | */ |
66 | #define VR10 0x10 |
66 | #define VR10 0x10 |
67 | /** Enables LVDS output instead of CMOS */ |
67 | /** Enables LVDS output instead of CMOS */ |
68 | # define VR10_LVDS_ENABLE (1 << 4) |
68 | # define VR10_LVDS_ENABLE (1 << 4) |
69 | /** Enables 18-bit LVDS output. */ |
69 | /** Enables 18-bit LVDS output. */ |
70 | # define VR10_INTERFACE_1X18 (0 << 2) |
70 | # define VR10_INTERFACE_1X18 (0 << 2) |
71 | /** Enables 24-bit LVDS or CMOS output */ |
71 | /** Enables 24-bit LVDS or CMOS output */ |
72 | # define VR10_INTERFACE_1X24 (1 << 2) |
72 | # define VR10_INTERFACE_1X24 (1 << 2) |
73 | /** Enables 2x18-bit LVDS or CMOS output. */ |
73 | /** Enables 2x18-bit LVDS or CMOS output. */ |
74 | # define VR10_INTERFACE_2X18 (2 << 2) |
74 | # define VR10_INTERFACE_2X18 (2 << 2) |
75 | /** Enables 2x24-bit LVDS output */ |
75 | /** Enables 2x24-bit LVDS output */ |
76 | # define VR10_INTERFACE_2X24 (3 << 2) |
76 | # define VR10_INTERFACE_2X24 (3 << 2) |
77 | 77 | ||
78 | /* |
78 | /* |
79 | * VR20 LCD Horizontal Display Size |
79 | * VR20 LCD Horizontal Display Size |
80 | */ |
80 | */ |
81 | #define VR20 0x20 |
81 | #define VR20 0x20 |
82 | 82 | ||
83 | /* |
83 | /* |
84 | * LCD Vertical Display Size |
84 | * LCD Vertical Display Size |
85 | */ |
85 | */ |
86 | #define VR21 0x20 |
86 | #define VR21 0x20 |
87 | 87 | ||
88 | /* |
88 | /* |
89 | * Panel power down status |
89 | * Panel power down status |
90 | */ |
90 | */ |
91 | #define VR30 0x30 |
91 | #define VR30 0x30 |
92 | /** Read only bit indicating that the panel is not in a safe poweroff state. */ |
92 | /** Read only bit indicating that the panel is not in a safe poweroff state. */ |
93 | # define VR30_PANEL_ON (1 << 15) |
93 | # define VR30_PANEL_ON (1 << 15) |
94 | 94 | ||
95 | #define VR40 0x40 |
95 | #define VR40 0x40 |
96 | # define VR40_STALL_ENABLE (1 << 13) |
96 | # define VR40_STALL_ENABLE (1 << 13) |
97 | # define VR40_VERTICAL_INTERP_ENABLE (1 << 12) |
97 | # define VR40_VERTICAL_INTERP_ENABLE (1 << 12) |
98 | # define VR40_ENHANCED_PANEL_FITTING (1 << 11) |
98 | # define VR40_ENHANCED_PANEL_FITTING (1 << 11) |
99 | # define VR40_HORIZONTAL_INTERP_ENABLE (1 << 10) |
99 | # define VR40_HORIZONTAL_INTERP_ENABLE (1 << 10) |
100 | # define VR40_AUTO_RATIO_ENABLE (1 << 9) |
100 | # define VR40_AUTO_RATIO_ENABLE (1 << 9) |
101 | # define VR40_CLOCK_GATING_ENABLE (1 << 8) |
101 | # define VR40_CLOCK_GATING_ENABLE (1 << 8) |
102 | 102 | ||
103 | /* |
103 | /* |
104 | * Panel Fitting Vertical Ratio |
104 | * Panel Fitting Vertical Ratio |
105 | * (((image_height - 1) << 16) / ((panel_height - 1))) >> 2 |
105 | * (((image_height - 1) << 16) / ((panel_height - 1))) >> 2 |
106 | */ |
106 | */ |
107 | #define VR41 0x41 |
107 | #define VR41 0x41 |
108 | 108 | ||
109 | /* |
109 | /* |
110 | * Panel Fitting Horizontal Ratio |
110 | * Panel Fitting Horizontal Ratio |
111 | * (((image_width - 1) << 16) / ((panel_width - 1))) >> 2 |
111 | * (((image_width - 1) << 16) / ((panel_width - 1))) >> 2 |
112 | */ |
112 | */ |
113 | #define VR42 0x42 |
113 | #define VR42 0x42 |
114 | 114 | ||
115 | /* |
115 | /* |
116 | * Horizontal Image Size |
116 | * Horizontal Image Size |
117 | */ |
117 | */ |
118 | #define VR43 0x43 |
118 | #define VR43 0x43 |
119 | 119 | ||
120 | /* VR80 GPIO 0 |
120 | /* VR80 GPIO 0 |
121 | */ |
121 | */ |
122 | #define VR80 0x80 |
122 | #define VR80 0x80 |
123 | #define VR81 0x81 |
123 | #define VR81 0x81 |
124 | #define VR82 0x82 |
124 | #define VR82 0x82 |
125 | #define VR83 0x83 |
125 | #define VR83 0x83 |
126 | #define VR84 0x84 |
126 | #define VR84 0x84 |
127 | #define VR85 0x85 |
127 | #define VR85 0x85 |
128 | #define VR86 0x86 |
128 | #define VR86 0x86 |
129 | #define VR87 0x87 |
129 | #define VR87 0x87 |
130 | 130 | ||
131 | /* VR88 GPIO 8 |
131 | /* VR88 GPIO 8 |
132 | */ |
132 | */ |
133 | #define VR88 0x88 |
133 | #define VR88 0x88 |
134 | 134 | ||
135 | /* Graphics BIOS scratch 0 |
135 | /* Graphics BIOS scratch 0 |
136 | */ |
136 | */ |
137 | #define VR8E 0x8E |
137 | #define VR8E 0x8E |
138 | # define VR8E_PANEL_TYPE_MASK (0xf << 0) |
138 | # define VR8E_PANEL_TYPE_MASK (0xf << 0) |
139 | # define VR8E_PANEL_INTERFACE_CMOS (0 << 4) |
139 | # define VR8E_PANEL_INTERFACE_CMOS (0 << 4) |
140 | # define VR8E_PANEL_INTERFACE_LVDS (1 << 4) |
140 | # define VR8E_PANEL_INTERFACE_LVDS (1 << 4) |
141 | # define VR8E_FORCE_DEFAULT_PANEL (1 << 5) |
141 | # define VR8E_FORCE_DEFAULT_PANEL (1 << 5) |
142 | 142 | ||
143 | /* Graphics BIOS scratch 1 |
143 | /* Graphics BIOS scratch 1 |
144 | */ |
144 | */ |
145 | #define VR8F 0x8F |
145 | #define VR8F 0x8F |
146 | # define VR8F_VCH_PRESENT (1 << 0) |
146 | # define VR8F_VCH_PRESENT (1 << 0) |
147 | # define VR8F_DISPLAY_CONN (1 << 1) |
147 | # define VR8F_DISPLAY_CONN (1 << 1) |
148 | # define VR8F_POWER_MASK (0x3c) |
148 | # define VR8F_POWER_MASK (0x3c) |
149 | # define VR8F_POWER_POS (2) |
149 | # define VR8F_POWER_POS (2) |
150 | 150 | ||
151 | 151 | ||
152 | struct ivch_priv { |
152 | struct ivch_priv { |
153 | bool quiet; |
153 | bool quiet; |
154 | 154 | ||
155 | uint16_t width, height; |
155 | uint16_t width, height; |
156 | }; |
156 | }; |
157 | 157 | ||
158 | 158 | ||
159 | static void ivch_dump_regs(struct intel_dvo_device *dvo); |
159 | static void ivch_dump_regs(struct intel_dvo_device *dvo); |
160 | 160 | ||
161 | /** |
161 | /** |
162 | * Reads a register on the ivch. |
162 | * Reads a register on the ivch. |
163 | * |
163 | * |
164 | * Each of the 256 registers are 16 bits long. |
164 | * Each of the 256 registers are 16 bits long. |
165 | */ |
165 | */ |
166 | static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data) |
166 | static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data) |
167 | { |
167 | { |
168 | struct ivch_priv *priv = dvo->dev_priv; |
168 | struct ivch_priv *priv = dvo->dev_priv; |
169 | struct i2c_adapter *adapter = dvo->i2c_bus; |
169 | struct i2c_adapter *adapter = dvo->i2c_bus; |
170 | u8 out_buf[1]; |
170 | u8 out_buf[1]; |
171 | u8 in_buf[2]; |
171 | u8 in_buf[2]; |
172 | 172 | ||
173 | struct i2c_msg msgs[] = { |
173 | struct i2c_msg msgs[] = { |
174 | { |
174 | { |
175 | .addr = dvo->slave_addr, |
175 | .addr = dvo->slave_addr, |
176 | .flags = I2C_M_RD, |
176 | .flags = I2C_M_RD, |
177 | .len = 0, |
177 | .len = 0, |
178 | }, |
178 | }, |
179 | { |
179 | { |
180 | .addr = 0, |
180 | .addr = 0, |
181 | .flags = I2C_M_NOSTART, |
181 | .flags = I2C_M_NOSTART, |
182 | .len = 1, |
182 | .len = 1, |
183 | .buf = out_buf, |
183 | .buf = out_buf, |
184 | }, |
184 | }, |
185 | { |
185 | { |
186 | .addr = dvo->slave_addr, |
186 | .addr = dvo->slave_addr, |
187 | .flags = I2C_M_RD | I2C_M_NOSTART, |
187 | .flags = I2C_M_RD | I2C_M_NOSTART, |
188 | .len = 2, |
188 | .len = 2, |
189 | .buf = in_buf, |
189 | .buf = in_buf, |
190 | } |
190 | } |
191 | }; |
191 | }; |
192 | 192 | ||
193 | out_buf[0] = addr; |
193 | out_buf[0] = addr; |
194 | 194 | ||
195 | if (i2c_transfer(adapter, msgs, 3) == 3) { |
195 | if (i2c_transfer(adapter, msgs, 3) == 3) { |
196 | *data = (in_buf[1] << 8) | in_buf[0]; |
196 | *data = (in_buf[1] << 8) | in_buf[0]; |
197 | return true; |
197 | return true; |
198 | }; |
198 | } |
199 | 199 | ||
200 | if (!priv->quiet) { |
200 | if (!priv->quiet) { |
201 | DRM_DEBUG_KMS("Unable to read register 0x%02x from " |
201 | DRM_DEBUG_KMS("Unable to read register 0x%02x from " |
202 | "%s:%02x.\n", |
202 | "%s:%02x.\n", |
203 | addr, adapter->name, dvo->slave_addr); |
203 | addr, adapter->name, dvo->slave_addr); |
204 | } |
204 | } |
205 | return false; |
205 | return false; |
206 | } |
206 | } |
207 | 207 | ||
208 | /** Writes a 16-bit register on the ivch */ |
208 | /** Writes a 16-bit register on the ivch */ |
209 | static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data) |
209 | static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data) |
210 | { |
210 | { |
211 | struct ivch_priv *priv = dvo->dev_priv; |
211 | struct ivch_priv *priv = dvo->dev_priv; |
212 | struct i2c_adapter *adapter = dvo->i2c_bus; |
212 | struct i2c_adapter *adapter = dvo->i2c_bus; |
213 | u8 out_buf[3]; |
213 | u8 out_buf[3]; |
214 | struct i2c_msg msg = { |
214 | struct i2c_msg msg = { |
215 | .addr = dvo->slave_addr, |
215 | .addr = dvo->slave_addr, |
216 | .flags = 0, |
216 | .flags = 0, |
217 | .len = 3, |
217 | .len = 3, |
218 | .buf = out_buf, |
218 | .buf = out_buf, |
219 | }; |
219 | }; |
220 | 220 | ||
221 | out_buf[0] = addr; |
221 | out_buf[0] = addr; |
222 | out_buf[1] = data & 0xff; |
222 | out_buf[1] = data & 0xff; |
223 | out_buf[2] = data >> 8; |
223 | out_buf[2] = data >> 8; |
224 | 224 | ||
225 | if (i2c_transfer(adapter, &msg, 1) == 1) |
225 | if (i2c_transfer(adapter, &msg, 1) == 1) |
226 | return true; |
226 | return true; |
227 | 227 | ||
228 | if (!priv->quiet) { |
228 | if (!priv->quiet) { |
229 | DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n", |
229 | DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n", |
230 | addr, adapter->name, dvo->slave_addr); |
230 | addr, adapter->name, dvo->slave_addr); |
231 | } |
231 | } |
232 | 232 | ||
233 | return false; |
233 | return false; |
234 | } |
234 | } |
235 | 235 | ||
236 | /** Probes the given bus and slave address for an ivch */ |
236 | /** Probes the given bus and slave address for an ivch */ |
237 | static bool ivch_init(struct intel_dvo_device *dvo, |
237 | static bool ivch_init(struct intel_dvo_device *dvo, |
238 | struct i2c_adapter *adapter) |
238 | struct i2c_adapter *adapter) |
239 | { |
239 | { |
240 | struct ivch_priv *priv; |
240 | struct ivch_priv *priv; |
241 | uint16_t temp; |
241 | uint16_t temp; |
242 | 242 | ||
243 | priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL); |
243 | priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL); |
244 | if (priv == NULL) |
244 | if (priv == NULL) |
245 | return false; |
245 | return false; |
246 | 246 | ||
247 | dvo->i2c_bus = adapter; |
247 | dvo->i2c_bus = adapter; |
248 | dvo->dev_priv = priv; |
248 | dvo->dev_priv = priv; |
249 | priv->quiet = true; |
249 | priv->quiet = true; |
250 | 250 | ||
251 | if (!ivch_read(dvo, VR00, &temp)) |
251 | if (!ivch_read(dvo, VR00, &temp)) |
252 | goto out; |
252 | goto out; |
253 | priv->quiet = false; |
253 | priv->quiet = false; |
254 | 254 | ||
255 | /* Since the identification bits are probably zeroes, which doesn't seem |
255 | /* Since the identification bits are probably zeroes, which doesn't seem |
256 | * very unique, check that the value in the base address field matches |
256 | * very unique, check that the value in the base address field matches |
257 | * the address it's responding on. |
257 | * the address it's responding on. |
258 | */ |
258 | */ |
259 | if ((temp & VR00_BASE_ADDRESS_MASK) != dvo->slave_addr) { |
259 | if ((temp & VR00_BASE_ADDRESS_MASK) != dvo->slave_addr) { |
260 | DRM_DEBUG_KMS("ivch detect failed due to address mismatch " |
260 | DRM_DEBUG_KMS("ivch detect failed due to address mismatch " |
261 | "(%d vs %d)\n", |
261 | "(%d vs %d)\n", |
262 | (temp & VR00_BASE_ADDRESS_MASK), dvo->slave_addr); |
262 | (temp & VR00_BASE_ADDRESS_MASK), dvo->slave_addr); |
263 | goto out; |
263 | goto out; |
264 | } |
264 | } |
265 | 265 | ||
266 | ivch_read(dvo, VR20, &priv->width); |
266 | ivch_read(dvo, VR20, &priv->width); |
267 | ivch_read(dvo, VR21, &priv->height); |
267 | ivch_read(dvo, VR21, &priv->height); |
268 | 268 | ||
269 | return true; |
269 | return true; |
270 | 270 | ||
271 | out: |
271 | out: |
272 | kfree(priv); |
272 | kfree(priv); |
273 | return false; |
273 | return false; |
274 | } |
274 | } |
275 | 275 | ||
276 | static enum drm_connector_status ivch_detect(struct intel_dvo_device *dvo) |
276 | static enum drm_connector_status ivch_detect(struct intel_dvo_device *dvo) |
277 | { |
277 | { |
278 | return connector_status_connected; |
278 | return connector_status_connected; |
279 | } |
279 | } |
280 | 280 | ||
281 | static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo, |
281 | static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo, |
282 | struct drm_display_mode *mode) |
282 | struct drm_display_mode *mode) |
283 | { |
283 | { |
284 | if (mode->clock > 112000) |
284 | if (mode->clock > 112000) |
285 | return MODE_CLOCK_HIGH; |
285 | return MODE_CLOCK_HIGH; |
286 | 286 | ||
287 | return MODE_OK; |
287 | return MODE_OK; |
288 | } |
288 | } |
289 | 289 | ||
290 | /** Sets the power state of the panel connected to the ivch */ |
290 | /** Sets the power state of the panel connected to the ivch */ |
291 | static void ivch_dpms(struct intel_dvo_device *dvo, bool enable) |
291 | static void ivch_dpms(struct intel_dvo_device *dvo, bool enable) |
292 | { |
292 | { |
293 | int i; |
293 | int i; |
294 | uint16_t vr01, vr30, backlight; |
294 | uint16_t vr01, vr30, backlight; |
295 | 295 | ||
296 | /* Set the new power state of the panel. */ |
296 | /* Set the new power state of the panel. */ |
297 | if (!ivch_read(dvo, VR01, &vr01)) |
297 | if (!ivch_read(dvo, VR01, &vr01)) |
298 | return; |
298 | return; |
299 | 299 | ||
300 | if (enable) |
300 | if (enable) |
301 | backlight = 1; |
301 | backlight = 1; |
302 | else |
302 | else |
303 | backlight = 0; |
303 | backlight = 0; |
304 | ivch_write(dvo, VR80, backlight); |
304 | ivch_write(dvo, VR80, backlight); |
305 | 305 | ||
306 | if (enable) |
306 | if (enable) |
307 | vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE; |
307 | vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE; |
308 | else |
308 | else |
309 | vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE); |
309 | vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE); |
310 | 310 | ||
311 | ivch_write(dvo, VR01, vr01); |
311 | ivch_write(dvo, VR01, vr01); |
312 | 312 | ||
313 | /* Wait for the panel to make its state transition */ |
313 | /* Wait for the panel to make its state transition */ |
314 | for (i = 0; i < 100; i++) { |
314 | for (i = 0; i < 100; i++) { |
315 | if (!ivch_read(dvo, VR30, &vr30)) |
315 | if (!ivch_read(dvo, VR30, &vr30)) |
316 | break; |
316 | break; |
317 | 317 | ||
318 | if (((vr30 & VR30_PANEL_ON) != 0) == enable) |
318 | if (((vr30 & VR30_PANEL_ON) != 0) == enable) |
319 | break; |
319 | break; |
320 | udelay(1000); |
320 | udelay(1000); |
321 | } |
321 | } |
322 | /* wait some more; vch may fail to resync sometimes without this */ |
322 | /* wait some more; vch may fail to resync sometimes without this */ |
323 | udelay(16 * 1000); |
323 | udelay(16 * 1000); |
324 | } |
324 | } |
325 | 325 | ||
326 | static bool ivch_get_hw_state(struct intel_dvo_device *dvo) |
326 | static bool ivch_get_hw_state(struct intel_dvo_device *dvo) |
327 | { |
327 | { |
328 | uint16_t vr01; |
328 | uint16_t vr01; |
329 | 329 | ||
330 | /* Set the new power state of the panel. */ |
330 | /* Set the new power state of the panel. */ |
331 | if (!ivch_read(dvo, VR01, &vr01)) |
331 | if (!ivch_read(dvo, VR01, &vr01)) |
332 | return false; |
332 | return false; |
333 | 333 | ||
334 | if (vr01 & VR01_LCD_ENABLE) |
334 | if (vr01 & VR01_LCD_ENABLE) |
335 | return true; |
335 | return true; |
336 | else |
336 | else |
337 | return false; |
337 | return false; |
338 | } |
338 | } |
339 | 339 | ||
340 | static void ivch_mode_set(struct intel_dvo_device *dvo, |
340 | static void ivch_mode_set(struct intel_dvo_device *dvo, |
341 | struct drm_display_mode *mode, |
341 | struct drm_display_mode *mode, |
342 | struct drm_display_mode *adjusted_mode) |
342 | struct drm_display_mode *adjusted_mode) |
343 | { |
343 | { |
344 | uint16_t vr40 = 0; |
344 | uint16_t vr40 = 0; |
345 | uint16_t vr01; |
345 | uint16_t vr01; |
346 | 346 | ||
347 | vr01 = 0; |
347 | vr01 = 0; |
348 | vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE | |
348 | vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE | |
349 | VR40_HORIZONTAL_INTERP_ENABLE); |
349 | VR40_HORIZONTAL_INTERP_ENABLE); |
350 | 350 | ||
351 | if (mode->hdisplay != adjusted_mode->hdisplay || |
351 | if (mode->hdisplay != adjusted_mode->hdisplay || |
352 | mode->vdisplay != adjusted_mode->vdisplay) { |
352 | mode->vdisplay != adjusted_mode->vdisplay) { |
353 | uint16_t x_ratio, y_ratio; |
353 | uint16_t x_ratio, y_ratio; |
354 | 354 | ||
355 | vr01 |= VR01_PANEL_FIT_ENABLE; |
355 | vr01 |= VR01_PANEL_FIT_ENABLE; |
356 | vr40 |= VR40_CLOCK_GATING_ENABLE; |
356 | vr40 |= VR40_CLOCK_GATING_ENABLE; |
357 | x_ratio = (((mode->hdisplay - 1) << 16) / |
357 | x_ratio = (((mode->hdisplay - 1) << 16) / |
358 | (adjusted_mode->hdisplay - 1)) >> 2; |
358 | (adjusted_mode->hdisplay - 1)) >> 2; |
359 | y_ratio = (((mode->vdisplay - 1) << 16) / |
359 | y_ratio = (((mode->vdisplay - 1) << 16) / |
360 | (adjusted_mode->vdisplay - 1)) >> 2; |
360 | (adjusted_mode->vdisplay - 1)) >> 2; |
361 | ivch_write(dvo, VR42, x_ratio); |
361 | ivch_write(dvo, VR42, x_ratio); |
362 | ivch_write(dvo, VR41, y_ratio); |
362 | ivch_write(dvo, VR41, y_ratio); |
363 | } else { |
363 | } else { |
364 | vr01 &= ~VR01_PANEL_FIT_ENABLE; |
364 | vr01 &= ~VR01_PANEL_FIT_ENABLE; |
365 | vr40 &= ~VR40_CLOCK_GATING_ENABLE; |
365 | vr40 &= ~VR40_CLOCK_GATING_ENABLE; |
366 | } |
366 | } |
367 | vr40 &= ~VR40_AUTO_RATIO_ENABLE; |
367 | vr40 &= ~VR40_AUTO_RATIO_ENABLE; |
368 | 368 | ||
369 | ivch_write(dvo, VR01, vr01); |
369 | ivch_write(dvo, VR01, vr01); |
370 | ivch_write(dvo, VR40, vr40); |
370 | ivch_write(dvo, VR40, vr40); |
371 | 371 | ||
372 | ivch_dump_regs(dvo); |
372 | ivch_dump_regs(dvo); |
373 | } |
373 | } |
374 | 374 | ||
375 | static void ivch_dump_regs(struct intel_dvo_device *dvo) |
375 | static void ivch_dump_regs(struct intel_dvo_device *dvo) |
376 | { |
376 | { |
377 | uint16_t val; |
377 | uint16_t val; |
378 | 378 | ||
379 | ivch_read(dvo, VR00, &val); |
379 | ivch_read(dvo, VR00, &val); |
380 | DRM_LOG_KMS("VR00: 0x%04x\n", val); |
380 | DRM_DEBUG_KMS("VR00: 0x%04x\n", val); |
381 | ivch_read(dvo, VR01, &val); |
381 | ivch_read(dvo, VR01, &val); |
382 | DRM_LOG_KMS("VR01: 0x%04x\n", val); |
382 | DRM_DEBUG_KMS("VR01: 0x%04x\n", val); |
383 | ivch_read(dvo, VR30, &val); |
383 | ivch_read(dvo, VR30, &val); |
384 | DRM_LOG_KMS("VR30: 0x%04x\n", val); |
384 | DRM_DEBUG_KMS("VR30: 0x%04x\n", val); |
385 | ivch_read(dvo, VR40, &val); |
385 | ivch_read(dvo, VR40, &val); |
386 | DRM_LOG_KMS("VR40: 0x%04x\n", val); |
386 | DRM_DEBUG_KMS("VR40: 0x%04x\n", val); |
387 | 387 | ||
388 | /* GPIO registers */ |
388 | /* GPIO registers */ |
389 | ivch_read(dvo, VR80, &val); |
389 | ivch_read(dvo, VR80, &val); |
390 | DRM_LOG_KMS("VR80: 0x%04x\n", val); |
390 | DRM_DEBUG_KMS("VR80: 0x%04x\n", val); |
391 | ivch_read(dvo, VR81, &val); |
391 | ivch_read(dvo, VR81, &val); |
392 | DRM_LOG_KMS("VR81: 0x%04x\n", val); |
392 | DRM_DEBUG_KMS("VR81: 0x%04x\n", val); |
393 | ivch_read(dvo, VR82, &val); |
393 | ivch_read(dvo, VR82, &val); |
394 | DRM_LOG_KMS("VR82: 0x%04x\n", val); |
394 | DRM_DEBUG_KMS("VR82: 0x%04x\n", val); |
395 | ivch_read(dvo, VR83, &val); |
395 | ivch_read(dvo, VR83, &val); |
396 | DRM_LOG_KMS("VR83: 0x%04x\n", val); |
396 | DRM_DEBUG_KMS("VR83: 0x%04x\n", val); |
397 | ivch_read(dvo, VR84, &val); |
397 | ivch_read(dvo, VR84, &val); |
398 | DRM_LOG_KMS("VR84: 0x%04x\n", val); |
398 | DRM_DEBUG_KMS("VR84: 0x%04x\n", val); |
399 | ivch_read(dvo, VR85, &val); |
399 | ivch_read(dvo, VR85, &val); |
400 | DRM_LOG_KMS("VR85: 0x%04x\n", val); |
400 | DRM_DEBUG_KMS("VR85: 0x%04x\n", val); |
401 | ivch_read(dvo, VR86, &val); |
401 | ivch_read(dvo, VR86, &val); |
402 | DRM_LOG_KMS("VR86: 0x%04x\n", val); |
402 | DRM_DEBUG_KMS("VR86: 0x%04x\n", val); |
403 | ivch_read(dvo, VR87, &val); |
403 | ivch_read(dvo, VR87, &val); |
404 | DRM_LOG_KMS("VR87: 0x%04x\n", val); |
404 | DRM_DEBUG_KMS("VR87: 0x%04x\n", val); |
405 | ivch_read(dvo, VR88, &val); |
405 | ivch_read(dvo, VR88, &val); |
406 | DRM_LOG_KMS("VR88: 0x%04x\n", val); |
406 | DRM_DEBUG_KMS("VR88: 0x%04x\n", val); |
407 | 407 | ||
408 | /* Scratch register 0 - AIM Panel type */ |
408 | /* Scratch register 0 - AIM Panel type */ |
409 | ivch_read(dvo, VR8E, &val); |
409 | ivch_read(dvo, VR8E, &val); |
410 | DRM_LOG_KMS("VR8E: 0x%04x\n", val); |
410 | DRM_DEBUG_KMS("VR8E: 0x%04x\n", val); |
411 | 411 | ||
412 | /* Scratch register 1 - Status register */ |
412 | /* Scratch register 1 - Status register */ |
413 | ivch_read(dvo, VR8F, &val); |
413 | ivch_read(dvo, VR8F, &val); |
414 | DRM_LOG_KMS("VR8F: 0x%04x\n", val); |
414 | DRM_DEBUG_KMS("VR8F: 0x%04x\n", val); |
415 | } |
415 | } |
416 | 416 | ||
417 | static void ivch_destroy(struct intel_dvo_device *dvo) |
417 | static void ivch_destroy(struct intel_dvo_device *dvo) |
418 | { |
418 | { |
419 | struct ivch_priv *priv = dvo->dev_priv; |
419 | struct ivch_priv *priv = dvo->dev_priv; |
420 | 420 | ||
421 | if (priv) { |
421 | if (priv) { |
422 | kfree(priv); |
422 | kfree(priv); |
423 | dvo->dev_priv = NULL; |
423 | dvo->dev_priv = NULL; |
424 | } |
424 | } |
425 | } |
425 | } |
426 | 426 | ||
427 | struct intel_dvo_dev_ops ivch_ops = { |
427 | struct intel_dvo_dev_ops ivch_ops = { |
428 | .init = ivch_init, |
428 | .init = ivch_init, |
429 | .dpms = ivch_dpms, |
429 | .dpms = ivch_dpms, |
430 | .get_hw_state = ivch_get_hw_state, |
430 | .get_hw_state = ivch_get_hw_state, |
431 | .mode_valid = ivch_mode_valid, |
431 | .mode_valid = ivch_mode_valid, |
432 | .mode_set = ivch_mode_set, |
432 | .mode_set = ivch_mode_set, |
433 | .detect = ivch_detect, |
433 | .detect = ivch_detect, |
434 | .dump_regs = ivch_dump_regs, |
434 | .dump_regs = ivch_dump_regs, |
435 | .destroy = ivch_destroy, |
435 | .destroy = ivch_destroy, |
436 | };><>><>>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><> |
436 | };><>><>>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><> |