Commit | Line | Data |
---|---|---|
1b082ccf AC |
1 | /* |
2 | * Copyright © 2006-2009 Intel Corporation | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms and conditions of the GNU General Public License, | |
6 | * version 2, as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope it will be useful, but WITHOUT | |
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
11 | * more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License along with | |
14 | * this program; if not, write to the Free Software Foundation, Inc., | |
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | |
16 | * | |
17 | * Authors: | |
18 | * Eric Anholt <eric@anholt.net> | |
19 | * Dave Airlie <airlied@linux.ie> | |
20 | * Jesse Barnes <jesse.barnes@intel.com> | |
21 | */ | |
22 | ||
23 | #include <linux/i2c.h> | |
24 | #include <drm/drmP.h> | |
25 | #include <asm/mrst.h> | |
26 | ||
27 | #include "intel_bios.h" | |
28 | #include "psb_drv.h" | |
29 | #include "psb_intel_drv.h" | |
30 | #include "psb_intel_reg.h" | |
31 | #include "power.h" | |
32 | #include <linux/pm_runtime.h> | |
33 | ||
34 | /* The max/min PWM frequency in BPCR[31:17] - */ | |
35 | /* The smallest number is 1 (not 0) that can fit in the | |
36 | * 15-bit field of the and then*/ | |
37 | /* shifts to the left by one bit to get the actual 16-bit | |
38 | * value that the 15-bits correspond to.*/ | |
39 | #define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF | |
40 | #define BRIGHTNESS_MAX_LEVEL 100 | |
41 | ||
42 | /** | |
43 | * Sets the power state for the panel. | |
44 | */ | |
45 | static void oaktrail_lvds_set_power(struct drm_device *dev, | |
9bd81acd PJ |
46 | struct psb_intel_encoder *psb_intel_encoder, |
47 | bool on) | |
1b082ccf AC |
48 | { |
49 | u32 pp_status; | |
50 | struct drm_psb_private *dev_priv = dev->dev_private; | |
51 | ||
52 | if (!gma_power_begin(dev, true)) | |
53 | return; | |
54 | ||
55 | if (on) { | |
56 | REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) | | |
57 | POWER_TARGET_ON); | |
58 | do { | |
59 | pp_status = REG_READ(PP_STATUS); | |
60 | } while ((pp_status & (PP_ON | PP_READY)) == PP_READY); | |
61 | dev_priv->is_lvds_on = true; | |
62 | if (dev_priv->ops->lvds_bl_power) | |
63 | dev_priv->ops->lvds_bl_power(dev, true); | |
64 | } else { | |
65 | if (dev_priv->ops->lvds_bl_power) | |
66 | dev_priv->ops->lvds_bl_power(dev, false); | |
67 | REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) & | |
68 | ~POWER_TARGET_ON); | |
69 | do { | |
70 | pp_status = REG_READ(PP_STATUS); | |
71 | } while (pp_status & PP_ON); | |
72 | dev_priv->is_lvds_on = false; | |
73 | pm_request_idle(&dev->pdev->dev); | |
74 | } | |
75 | gma_power_end(dev); | |
76 | } | |
77 | ||
78 | static void oaktrail_lvds_dpms(struct drm_encoder *encoder, int mode) | |
79 | { | |
80 | struct drm_device *dev = encoder->dev; | |
9bd81acd PJ |
81 | struct psb_intel_encoder *psb_intel_encoder = |
82 | to_psb_intel_encoder(encoder); | |
1b082ccf AC |
83 | |
84 | if (mode == DRM_MODE_DPMS_ON) | |
9bd81acd | 85 | oaktrail_lvds_set_power(dev, psb_intel_encoder, true); |
1b082ccf | 86 | else |
9bd81acd | 87 | oaktrail_lvds_set_power(dev, psb_intel_encoder, false); |
1b082ccf AC |
88 | |
89 | /* XXX: We never power down the LVDS pairs. */ | |
90 | } | |
91 | ||
92 | static void oaktrail_lvds_mode_set(struct drm_encoder *encoder, | |
93 | struct drm_display_mode *mode, | |
94 | struct drm_display_mode *adjusted_mode) | |
95 | { | |
1b082ccf AC |
96 | struct drm_device *dev = encoder->dev; |
97 | struct drm_psb_private *dev_priv = dev->dev_private; | |
9bd81acd PJ |
98 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; |
99 | struct drm_mode_config *mode_config = &dev->mode_config; | |
100 | struct drm_connector *connector = NULL; | |
101 | struct drm_crtc *crtc = encoder->crtc; | |
1b082ccf AC |
102 | u32 lvds_port; |
103 | uint64_t v = DRM_MODE_SCALE_FULLSCREEN; | |
104 | ||
105 | if (!gma_power_begin(dev, true)) | |
106 | return; | |
107 | ||
108 | /* | |
109 | * The LVDS pin pair will already have been turned on in the | |
110 | * psb_intel_crtc_mode_set since it has a large impact on the DPLL | |
111 | * settings. | |
112 | */ | |
113 | lvds_port = (REG_READ(LVDS) & | |
114 | (~LVDS_PIPEB_SELECT)) | | |
115 | LVDS_PORT_EN | | |
116 | LVDS_BORDER_EN; | |
117 | ||
118 | /* If the firmware says dither on Moorestown, or the BIOS does | |
119 | on Oaktrail then enable dithering */ | |
120 | if (mode_dev->panel_wants_dither || dev_priv->lvds_dither) | |
121 | lvds_port |= MRST_PANEL_8TO6_DITHER_ENABLE; | |
122 | ||
123 | REG_WRITE(LVDS, lvds_port); | |
124 | ||
9bd81acd PJ |
125 | /* Find the connector we're trying to set up */ |
126 | list_for_each_entry(connector, &mode_config->connector_list, head) { | |
127 | if (!connector->encoder || connector->encoder->crtc != crtc) | |
128 | continue; | |
129 | } | |
130 | ||
131 | if (!connector) { | |
132 | DRM_ERROR("Couldn't find connector when setting mode"); | |
133 | return; | |
134 | } | |
135 | ||
a69ac9ea RC |
136 | drm_object_property_get_value( |
137 | &connector->base, | |
1b082ccf AC |
138 | dev->mode_config.scaling_mode_property, |
139 | &v); | |
140 | ||
141 | if (v == DRM_MODE_SCALE_NO_SCALE) | |
142 | REG_WRITE(PFIT_CONTROL, 0); | |
143 | else if (v == DRM_MODE_SCALE_ASPECT) { | |
144 | if ((mode->vdisplay != adjusted_mode->crtc_vdisplay) || | |
145 | (mode->hdisplay != adjusted_mode->crtc_hdisplay)) { | |
146 | if ((adjusted_mode->crtc_hdisplay * mode->vdisplay) == | |
147 | (mode->hdisplay * adjusted_mode->crtc_vdisplay)) | |
148 | REG_WRITE(PFIT_CONTROL, PFIT_ENABLE); | |
149 | else if ((adjusted_mode->crtc_hdisplay * | |
150 | mode->vdisplay) > (mode->hdisplay * | |
151 | adjusted_mode->crtc_vdisplay)) | |
152 | REG_WRITE(PFIT_CONTROL, PFIT_ENABLE | | |
153 | PFIT_SCALING_MODE_PILLARBOX); | |
154 | else | |
155 | REG_WRITE(PFIT_CONTROL, PFIT_ENABLE | | |
156 | PFIT_SCALING_MODE_LETTERBOX); | |
157 | } else | |
158 | REG_WRITE(PFIT_CONTROL, PFIT_ENABLE); | |
159 | } else /*(v == DRM_MODE_SCALE_FULLSCREEN)*/ | |
160 | REG_WRITE(PFIT_CONTROL, PFIT_ENABLE); | |
161 | ||
162 | gma_power_end(dev); | |
163 | } | |
164 | ||
165 | static void oaktrail_lvds_prepare(struct drm_encoder *encoder) | |
166 | { | |
167 | struct drm_device *dev = encoder->dev; | |
9bd81acd PJ |
168 | struct drm_psb_private *dev_priv = dev->dev_private; |
169 | struct psb_intel_encoder *psb_intel_encoder = | |
170 | to_psb_intel_encoder(encoder); | |
171 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; | |
1b082ccf AC |
172 | |
173 | if (!gma_power_begin(dev, true)) | |
174 | return; | |
175 | ||
176 | mode_dev->saveBLC_PWM_CTL = REG_READ(BLC_PWM_CTL); | |
177 | mode_dev->backlight_duty_cycle = (mode_dev->saveBLC_PWM_CTL & | |
178 | BACKLIGHT_DUTY_CYCLE_MASK); | |
9bd81acd | 179 | oaktrail_lvds_set_power(dev, psb_intel_encoder, false); |
1b082ccf AC |
180 | gma_power_end(dev); |
181 | } | |
182 | ||
183 | static u32 oaktrail_lvds_get_max_backlight(struct drm_device *dev) | |
184 | { | |
185 | struct drm_psb_private *dev_priv = dev->dev_private; | |
186 | u32 ret; | |
187 | ||
188 | if (gma_power_begin(dev, false)) { | |
189 | ret = ((REG_READ(BLC_PWM_CTL) & | |
190 | BACKLIGHT_MODULATION_FREQ_MASK) >> | |
191 | BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; | |
192 | ||
193 | gma_power_end(dev); | |
194 | } else | |
648a8e34 | 195 | ret = ((dev_priv->regs.saveBLC_PWM_CTL & |
1b082ccf AC |
196 | BACKLIGHT_MODULATION_FREQ_MASK) >> |
197 | BACKLIGHT_MODULATION_FREQ_SHIFT) * 2; | |
198 | ||
199 | return ret; | |
200 | } | |
201 | ||
202 | static void oaktrail_lvds_commit(struct drm_encoder *encoder) | |
203 | { | |
204 | struct drm_device *dev = encoder->dev; | |
9bd81acd PJ |
205 | struct drm_psb_private *dev_priv = dev->dev_private; |
206 | struct psb_intel_encoder *psb_intel_encoder = | |
207 | to_psb_intel_encoder(encoder); | |
208 | struct psb_intel_mode_device *mode_dev = &dev_priv->mode_dev; | |
1b082ccf AC |
209 | |
210 | if (mode_dev->backlight_duty_cycle == 0) | |
211 | mode_dev->backlight_duty_cycle = | |
212 | oaktrail_lvds_get_max_backlight(dev); | |
9bd81acd | 213 | oaktrail_lvds_set_power(dev, psb_intel_encoder, true); |
1b082ccf AC |
214 | } |
215 | ||
216 | static const struct drm_encoder_helper_funcs oaktrail_lvds_helper_funcs = { | |
217 | .dpms = oaktrail_lvds_dpms, | |
218 | .mode_fixup = psb_intel_lvds_mode_fixup, | |
219 | .prepare = oaktrail_lvds_prepare, | |
220 | .mode_set = oaktrail_lvds_mode_set, | |
221 | .commit = oaktrail_lvds_commit, | |
222 | }; | |
223 | ||
224 | static struct drm_display_mode lvds_configuration_modes[] = { | |
225 | /* hard coded fixed mode for TPO LTPS LPJ040K001A */ | |
226 | { DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER, 33264, 800, 836, | |
227 | 846, 1056, 0, 480, 489, 491, 525, 0, 0) }, | |
228 | /* hard coded fixed mode for LVDS 800x480 */ | |
229 | { DRM_MODE("800x480", DRM_MODE_TYPE_DRIVER, 30994, 800, 801, | |
230 | 802, 1024, 0, 480, 481, 482, 525, 0, 0) }, | |
231 | /* hard coded fixed mode for Samsung 480wsvga LVDS 1024x600@75 */ | |
232 | { DRM_MODE("1024x600", DRM_MODE_TYPE_DRIVER, 53990, 1024, 1072, | |
233 | 1104, 1184, 0, 600, 603, 604, 608, 0, 0) }, | |
234 | /* hard coded fixed mode for Samsung 480wsvga LVDS 1024x600@75 */ | |
235 | { DRM_MODE("1024x600", DRM_MODE_TYPE_DRIVER, 53990, 1024, 1104, | |
236 | 1136, 1184, 0, 600, 603, 604, 608, 0, 0) }, | |
237 | /* hard coded fixed mode for Sharp wsvga LVDS 1024x600 */ | |
238 | { DRM_MODE("1024x600", DRM_MODE_TYPE_DRIVER, 48885, 1024, 1124, | |
239 | 1204, 1312, 0, 600, 607, 610, 621, 0, 0) }, | |
240 | /* hard coded fixed mode for LVDS 1024x768 */ | |
241 | { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048, | |
242 | 1184, 1344, 0, 768, 771, 777, 806, 0, 0) }, | |
243 | /* hard coded fixed mode for LVDS 1366x768 */ | |
244 | { DRM_MODE("1366x768", DRM_MODE_TYPE_DRIVER, 77500, 1366, 1430, | |
245 | 1558, 1664, 0, 768, 769, 770, 776, 0, 0) }, | |
246 | }; | |
247 | ||
248 | /* Returns the panel fixed mode from configuration. */ | |
249 | ||
1b22edfd AC |
250 | static void oaktrail_lvds_get_configuration_mode(struct drm_device *dev, |
251 | struct psb_intel_mode_device *mode_dev) | |
1b082ccf AC |
252 | { |
253 | struct drm_display_mode *mode = NULL; | |
254 | struct drm_psb_private *dev_priv = dev->dev_private; | |
255 | struct oaktrail_timing_info *ti = &dev_priv->gct_data.DTD; | |
256 | ||
1b22edfd AC |
257 | mode_dev->panel_fixed_mode = NULL; |
258 | ||
259 | /* Use the firmware provided data on Moorestown */ | |
4086b1e2 | 260 | if (dev_priv->has_gct) { |
1b082ccf AC |
261 | mode = kzalloc(sizeof(*mode), GFP_KERNEL); |
262 | if (!mode) | |
1b22edfd | 263 | return; |
1b082ccf AC |
264 | |
265 | mode->hdisplay = (ti->hactive_hi << 8) | ti->hactive_lo; | |
266 | mode->vdisplay = (ti->vactive_hi << 8) | ti->vactive_lo; | |
267 | mode->hsync_start = mode->hdisplay + \ | |
268 | ((ti->hsync_offset_hi << 8) | \ | |
269 | ti->hsync_offset_lo); | |
270 | mode->hsync_end = mode->hsync_start + \ | |
271 | ((ti->hsync_pulse_width_hi << 8) | \ | |
272 | ti->hsync_pulse_width_lo); | |
273 | mode->htotal = mode->hdisplay + ((ti->hblank_hi << 8) | \ | |
274 | ti->hblank_lo); | |
275 | mode->vsync_start = \ | |
276 | mode->vdisplay + ((ti->vsync_offset_hi << 4) | \ | |
277 | ti->vsync_offset_lo); | |
278 | mode->vsync_end = \ | |
279 | mode->vsync_start + ((ti->vsync_pulse_width_hi << 4) | \ | |
280 | ti->vsync_pulse_width_lo); | |
281 | mode->vtotal = mode->vdisplay + \ | |
282 | ((ti->vblank_hi << 8) | ti->vblank_lo); | |
283 | mode->clock = ti->pixel_clock * 10; | |
284 | #if 0 | |
285 | printk(KERN_INFO "hdisplay is %d\n", mode->hdisplay); | |
286 | printk(KERN_INFO "vdisplay is %d\n", mode->vdisplay); | |
287 | printk(KERN_INFO "HSS is %d\n", mode->hsync_start); | |
288 | printk(KERN_INFO "HSE is %d\n", mode->hsync_end); | |
289 | printk(KERN_INFO "htotal is %d\n", mode->htotal); | |
290 | printk(KERN_INFO "VSS is %d\n", mode->vsync_start); | |
291 | printk(KERN_INFO "VSE is %d\n", mode->vsync_end); | |
292 | printk(KERN_INFO "vtotal is %d\n", mode->vtotal); | |
293 | printk(KERN_INFO "clock is %d\n", mode->clock); | |
294 | #endif | |
1b22edfd AC |
295 | mode_dev->panel_fixed_mode = mode; |
296 | } | |
1b082ccf | 297 | |
1b22edfd AC |
298 | /* Use the BIOS VBT mode if available */ |
299 | if (mode_dev->panel_fixed_mode == NULL && mode_dev->vbt_mode) | |
300 | mode_dev->panel_fixed_mode = drm_mode_duplicate(dev, | |
301 | mode_dev->vbt_mode); | |
302 | ||
303 | /* Then try the LVDS VBT mode */ | |
304 | if (mode_dev->panel_fixed_mode == NULL) | |
305 | if (dev_priv->lfp_lvds_vbt_mode) | |
306 | mode_dev->panel_fixed_mode = | |
307 | drm_mode_duplicate(dev, | |
308 | dev_priv->lfp_lvds_vbt_mode); | |
309 | /* Then guess */ | |
310 | if (mode_dev->panel_fixed_mode == NULL) | |
311 | mode_dev->panel_fixed_mode | |
312 | = drm_mode_duplicate(dev, &lvds_configuration_modes[2]); | |
313 | ||
314 | drm_mode_set_name(mode_dev->panel_fixed_mode); | |
315 | drm_mode_set_crtcinfo(mode_dev->panel_fixed_mode, 0); | |
1b082ccf AC |
316 | } |
317 | ||
318 | /** | |
319 | * oaktrail_lvds_init - setup LVDS connectors on this device | |
320 | * @dev: drm device | |
321 | * | |
322 | * Create the connector, register the LVDS DDC bus, and try to figure out what | |
323 | * modes we can display on the LVDS panel (if present). | |
324 | */ | |
325 | void oaktrail_lvds_init(struct drm_device *dev, | |
326 | struct psb_intel_mode_device *mode_dev) | |
327 | { | |
9bd81acd PJ |
328 | struct psb_intel_encoder *psb_intel_encoder; |
329 | struct psb_intel_connector *psb_intel_connector; | |
1b082ccf AC |
330 | struct drm_connector *connector; |
331 | struct drm_encoder *encoder; | |
5d3852dc | 332 | struct drm_psb_private *dev_priv = dev->dev_private; |
1b082ccf | 333 | struct edid *edid; |
1b082ccf AC |
334 | struct i2c_adapter *i2c_adap; |
335 | struct drm_display_mode *scan; /* *modes, *bios_mode; */ | |
336 | ||
9bd81acd PJ |
337 | psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder), GFP_KERNEL); |
338 | if (!psb_intel_encoder) | |
1b082ccf AC |
339 | return; |
340 | ||
5d3852dc | 341 | psb_intel_connector = kzalloc(sizeof(struct psb_intel_connector), GFP_KERNEL); |
9bd81acd PJ |
342 | if (!psb_intel_connector) |
343 | goto failed_connector; | |
344 | ||
345 | connector = &psb_intel_connector->base; | |
346 | encoder = &psb_intel_encoder->base; | |
1b082ccf | 347 | dev_priv->is_lvds_on = true; |
9bd81acd | 348 | drm_connector_init(dev, connector, |
1b082ccf AC |
349 | &psb_intel_lvds_connector_funcs, |
350 | DRM_MODE_CONNECTOR_LVDS); | |
351 | ||
9bd81acd | 352 | drm_encoder_init(dev, encoder, &psb_intel_lvds_enc_funcs, |
1b082ccf AC |
353 | DRM_MODE_ENCODER_LVDS); |
354 | ||
9bd81acd PJ |
355 | psb_intel_connector_attach_encoder(psb_intel_connector, |
356 | psb_intel_encoder); | |
357 | psb_intel_encoder->type = INTEL_OUTPUT_LVDS; | |
1b082ccf AC |
358 | |
359 | drm_encoder_helper_add(encoder, &oaktrail_lvds_helper_funcs); | |
360 | drm_connector_helper_add(connector, | |
361 | &psb_intel_lvds_connector_helper_funcs); | |
362 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | |
363 | connector->interlace_allowed = false; | |
364 | connector->doublescan_allowed = false; | |
365 | ||
a69ac9ea | 366 | drm_object_attach_property(&connector->base, |
1b082ccf AC |
367 | dev->mode_config.scaling_mode_property, |
368 | DRM_MODE_SCALE_FULLSCREEN); | |
a69ac9ea | 369 | drm_object_attach_property(&connector->base, |
1b082ccf AC |
370 | dev_priv->backlight_property, |
371 | BRIGHTNESS_MAX_LEVEL); | |
372 | ||
373 | mode_dev->panel_wants_dither = false; | |
4086b1e2 | 374 | if (dev_priv->has_gct) |
1b082ccf AC |
375 | mode_dev->panel_wants_dither = (dev_priv->gct_data. |
376 | Panel_Port_Control & MRST_PANEL_8TO6_DITHER_ENABLE); | |
e2e022ec AC |
377 | if (dev_priv->lvds_dither) |
378 | mode_dev->panel_wants_dither = 1; | |
1b082ccf AC |
379 | |
380 | /* | |
381 | * LVDS discovery: | |
382 | * 1) check for EDID on DDC | |
383 | * 2) check for VBT data | |
384 | * 3) check to see if LVDS is already on | |
385 | * if none of the above, no panel | |
386 | * 4) make sure lid is open | |
387 | * if closed, act like it's not there for now | |
388 | */ | |
389 | ||
390 | i2c_adap = i2c_get_adapter(dev_priv->ops->i2c_bus); | |
391 | if (i2c_adap == NULL) | |
392 | dev_err(dev->dev, "No ddc adapter available!\n"); | |
393 | /* | |
394 | * Attempt to get the fixed panel mode from DDC. Assume that the | |
395 | * preferred mode is the right one. | |
396 | */ | |
397 | if (i2c_adap) { | |
398 | edid = drm_get_edid(connector, i2c_adap); | |
399 | if (edid) { | |
400 | drm_mode_connector_update_edid_property(connector, | |
401 | edid); | |
cc2e991c | 402 | drm_add_edid_modes(connector, edid); |
1b082ccf AC |
403 | kfree(edid); |
404 | } | |
405 | ||
406 | list_for_each_entry(scan, &connector->probed_modes, head) { | |
407 | if (scan->type & DRM_MODE_TYPE_PREFERRED) { | |
408 | mode_dev->panel_fixed_mode = | |
409 | drm_mode_duplicate(dev, scan); | |
410 | goto out; /* FIXME: check for quirks */ | |
411 | } | |
412 | } | |
413 | } | |
414 | /* | |
415 | * If we didn't get EDID, try geting panel timing | |
416 | * from configuration data | |
417 | */ | |
1b22edfd | 418 | oaktrail_lvds_get_configuration_mode(dev, mode_dev); |
1b082ccf AC |
419 | |
420 | if (mode_dev->panel_fixed_mode) { | |
421 | mode_dev->panel_fixed_mode->type |= DRM_MODE_TYPE_PREFERRED; | |
422 | goto out; /* FIXME: check for quirks */ | |
423 | } | |
424 | ||
425 | /* If we still don't have a mode after all that, give up. */ | |
426 | if (!mode_dev->panel_fixed_mode) { | |
427 | dev_err(dev->dev, "Found no modes on the lvds, ignoring the LVDS\n"); | |
428 | goto failed_find; | |
429 | } | |
430 | ||
431 | out: | |
432 | drm_sysfs_connector_add(connector); | |
433 | return; | |
434 | ||
435 | failed_find: | |
436 | dev_dbg(dev->dev, "No LVDS modes found, disabling.\n"); | |
9bd81acd PJ |
437 | if (psb_intel_encoder->ddc_bus) |
438 | psb_intel_i2c_destroy(psb_intel_encoder->ddc_bus); | |
1b082ccf AC |
439 | |
440 | /* failed_ddc: */ | |
441 | ||
442 | drm_encoder_cleanup(encoder); | |
443 | drm_connector_cleanup(connector); | |
9bd81acd PJ |
444 | kfree(psb_intel_connector); |
445 | failed_connector: | |
446 | kfree(psb_intel_encoder); | |
1b082ccf AC |
447 | } |
448 |