File: | dev/pci/drm/i915/display/intel_fbdev.c |
Warning: | line 175, column 20 Value stored to 'ggtt' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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/async.h> |
28 | #include <linux/console.h> |
29 | #include <linux/delay.h> |
30 | #include <linux/errno.h> |
31 | #include <linux/init.h> |
32 | #include <linux/kernel.h> |
33 | #include <linux/mm.h> |
34 | #include <linux/module.h> |
35 | #include <linux/string.h> |
36 | #include <linux/sysrq.h> |
37 | #include <linux/tty.h> |
38 | #include <linux/vga_switcheroo.h> |
39 | |
40 | #include <drm/drm_crtc.h> |
41 | #include <drm/drm_fb_helper.h> |
42 | #include <drm/drm_fourcc.h> |
43 | |
44 | #include "i915_drv.h" |
45 | #include "intel_display_types.h" |
46 | #include "intel_fbdev.h" |
47 | #include "intel_frontbuffer.h" |
48 | |
49 | static struct intel_frontbuffer *to_frontbuffer(struct intel_fbdev *ifbdev) |
50 | { |
51 | return ifbdev->fb->frontbuffer; |
52 | } |
53 | |
54 | static void intel_fbdev_invalidate(struct intel_fbdev *ifbdev) |
55 | { |
56 | intel_frontbuffer_invalidate(to_frontbuffer(ifbdev), ORIGIN_CPU); |
57 | } |
58 | |
59 | static int intel_fbdev_set_par(struct fb_info *info) |
60 | { |
61 | struct drm_fb_helper *fb_helper = info->par; |
62 | struct intel_fbdev *ifbdev = |
63 | container_of(fb_helper, struct intel_fbdev, helper)({ const __typeof( ((struct intel_fbdev *)0)->helper ) *__mptr = (fb_helper); (struct intel_fbdev *)( (char *)__mptr - __builtin_offsetof (struct intel_fbdev, helper) );}); |
64 | int ret; |
65 | |
66 | ret = drm_fb_helper_set_par(info); |
67 | if (ret == 0) |
68 | intel_fbdev_invalidate(ifbdev); |
69 | |
70 | return ret; |
71 | } |
72 | |
73 | static int intel_fbdev_blank(int blank, struct fb_info *info) |
74 | { |
75 | struct drm_fb_helper *fb_helper = info->par; |
76 | struct intel_fbdev *ifbdev = |
77 | container_of(fb_helper, struct intel_fbdev, helper)({ const __typeof( ((struct intel_fbdev *)0)->helper ) *__mptr = (fb_helper); (struct intel_fbdev *)( (char *)__mptr - __builtin_offsetof (struct intel_fbdev, helper) );}); |
78 | int ret; |
79 | |
80 | ret = drm_fb_helper_blank(blank, info); |
81 | if (ret == 0) |
82 | intel_fbdev_invalidate(ifbdev); |
83 | |
84 | return ret; |
85 | } |
86 | |
87 | static int intel_fbdev_pan_display(struct fb_var_screeninfo *var, |
88 | struct fb_info *info) |
89 | { |
90 | struct drm_fb_helper *fb_helper = info->par; |
91 | struct intel_fbdev *ifbdev = |
92 | container_of(fb_helper, struct intel_fbdev, helper)({ const __typeof( ((struct intel_fbdev *)0)->helper ) *__mptr = (fb_helper); (struct intel_fbdev *)( (char *)__mptr - __builtin_offsetof (struct intel_fbdev, helper) );}); |
93 | int ret; |
94 | |
95 | ret = drm_fb_helper_pan_display(var, info); |
96 | if (ret == 0) |
97 | intel_fbdev_invalidate(ifbdev); |
98 | |
99 | return ret; |
100 | } |
101 | |
102 | static const struct fb_ops intelfb_ops = { |
103 | #ifdef notyet |
104 | .owner = THIS_MODULE((void *)0), |
105 | DRM_FB_HELPER_DEFAULT_OPS.fb_set_par = drm_fb_helper_set_par, |
106 | #endif |
107 | .fb_set_par = intel_fbdev_set_par, |
108 | #ifdef notyet |
109 | .fb_fillrect = drm_fb_helper_cfb_fillrect, |
110 | .fb_copyarea = drm_fb_helper_cfb_copyarea, |
111 | .fb_imageblit = drm_fb_helper_cfb_imageblit, |
112 | .fb_pan_display = intel_fbdev_pan_display, |
113 | .fb_blank = intel_fbdev_blank, |
114 | #endif |
115 | }; |
116 | |
117 | static int intelfb_alloc(struct drm_fb_helper *helper, |
118 | struct drm_fb_helper_surface_size *sizes) |
119 | { |
120 | struct intel_fbdev *ifbdev = |
121 | container_of(helper, struct intel_fbdev, helper)({ const __typeof( ((struct intel_fbdev *)0)->helper ) *__mptr = (helper); (struct intel_fbdev *)( (char *)__mptr - __builtin_offsetof (struct intel_fbdev, helper) );}); |
122 | struct drm_framebuffer *fb; |
123 | struct drm_device *dev = helper->dev; |
124 | struct drm_i915_privateinteldrm_softc *dev_priv = to_i915(dev); |
125 | struct drm_mode_fb_cmd2 mode_cmd = {}; |
126 | struct drm_i915_gem_object *obj; |
127 | int size; |
128 | |
129 | /* we don't do packed 24bpp */ |
130 | if (sizes->surface_bpp == 24) |
131 | sizes->surface_bpp = 32; |
132 | |
133 | mode_cmd.width = sizes->surface_width; |
134 | mode_cmd.height = sizes->surface_height; |
135 | |
136 | mode_cmd.pitches[0] = roundup2(mode_cmd.width *(((mode_cmd.width * (((sizes->surface_bpp) + ((8) - 1)) / ( 8))) + ((64) - 1)) & (~((__typeof(mode_cmd.width * (((sizes ->surface_bpp) + ((8) - 1)) / (8))))(64) - 1))) |
137 | DIV_ROUND_UP(sizes->surface_bpp, 8), 64)(((mode_cmd.width * (((sizes->surface_bpp) + ((8) - 1)) / ( 8))) + ((64) - 1)) & (~((__typeof(mode_cmd.width * (((sizes ->surface_bpp) + ((8) - 1)) / (8))))(64) - 1))); |
138 | mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, |
139 | sizes->surface_depth); |
140 | |
141 | size = mode_cmd.pitches[0] * mode_cmd.height; |
142 | size = PAGE_ALIGN(size)(((size) + ((1 << 12) - 1)) & ~((1 << 12) - 1 )); |
143 | |
144 | /* If the FB is too big, just don't use it since fbdev is not very |
145 | * important and we should probably use that space with FBC or other |
146 | * features. */ |
147 | obj = ERR_PTR(-ENODEV19); |
148 | if (size * 2 < dev_priv->stolen_usable_size) |
149 | obj = i915_gem_object_create_stolen(dev_priv, size); |
150 | if (IS_ERR(obj)) |
151 | obj = i915_gem_object_create_shmem(dev_priv, size); |
152 | if (IS_ERR(obj)) { |
153 | drm_err(&dev_priv->drm, "failed to allocate framebuffer\n")printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "failed to allocate framebuffer\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__); |
154 | return PTR_ERR(obj); |
155 | } |
156 | |
157 | fb = intel_framebuffer_create(obj, &mode_cmd); |
158 | i915_gem_object_put(obj); |
159 | if (IS_ERR(fb)) |
160 | return PTR_ERR(fb); |
161 | |
162 | ifbdev->fb = to_intel_framebuffer(fb)({ const __typeof( ((struct intel_framebuffer *)0)->base ) *__mptr = (fb); (struct intel_framebuffer *)( (char *)__mptr - __builtin_offsetof(struct intel_framebuffer, base) );}); |
163 | return 0; |
164 | } |
165 | |
166 | static int intelfb_create(struct drm_fb_helper *helper, |
167 | struct drm_fb_helper_surface_size *sizes) |
168 | { |
169 | struct intel_fbdev *ifbdev = |
170 | container_of(helper, struct intel_fbdev, helper)({ const __typeof( ((struct intel_fbdev *)0)->helper ) *__mptr = (helper); (struct intel_fbdev *)( (char *)__mptr - __builtin_offsetof (struct intel_fbdev, helper) );}); |
171 | struct intel_framebuffer *intel_fb = ifbdev->fb; |
172 | struct drm_device *dev = helper->dev; |
173 | struct drm_i915_privateinteldrm_softc *dev_priv = to_i915(dev); |
174 | struct pci_dev *pdev = dev_priv->drm.pdev; |
175 | struct i915_ggtt *ggtt = &dev_priv->ggtt; |
Value stored to 'ggtt' during its initialization is never read | |
176 | const struct i915_ggtt_view view = { |
177 | .type = I915_GGTT_VIEW_NORMAL, |
178 | }; |
179 | intel_wakeref_t wakeref; |
180 | struct fb_info *info; |
181 | struct i915_vma *vma; |
182 | unsigned long flags = 0; |
183 | bool_Bool prealloc = false0; |
184 | void __iomem *vaddr; |
185 | int ret; |
186 | |
187 | if (intel_fb && |
188 | (sizes->fb_width > intel_fb->base.width || |
189 | sizes->fb_height > intel_fb->base.height)) { |
190 | drm_dbg_kms(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "BIOS fb too small (%dx%d), we require (%dx%d)," " releasing it\n", intel_fb->base.width, intel_fb->base .height, sizes->fb_width, sizes->fb_height) |
191 | "BIOS fb too small (%dx%d), we require (%dx%d),"drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "BIOS fb too small (%dx%d), we require (%dx%d)," " releasing it\n", intel_fb->base.width, intel_fb->base .height, sizes->fb_width, sizes->fb_height) |
192 | " releasing it\n",drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "BIOS fb too small (%dx%d), we require (%dx%d)," " releasing it\n", intel_fb->base.width, intel_fb->base .height, sizes->fb_width, sizes->fb_height) |
193 | intel_fb->base.width, intel_fb->base.height,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "BIOS fb too small (%dx%d), we require (%dx%d)," " releasing it\n", intel_fb->base.width, intel_fb->base .height, sizes->fb_width, sizes->fb_height) |
194 | sizes->fb_width, sizes->fb_height)drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "BIOS fb too small (%dx%d), we require (%dx%d)," " releasing it\n", intel_fb->base.width, intel_fb->base .height, sizes->fb_width, sizes->fb_height); |
195 | drm_framebuffer_put(&intel_fb->base); |
196 | intel_fb = ifbdev->fb = NULL((void *)0); |
197 | } |
198 | if (!intel_fb || drm_WARN_ON(dev, !intel_fb_obj(&intel_fb->base))({ int __ret = !!((!((&intel_fb->base) ? to_intel_bo(( &intel_fb->base)->obj[0]) : ((void *)0)))); if (__ret ) printf("%s %s: " "%s", dev_driver_string(((dev))->dev), "" , "drm_WARN_ON(" "!((&intel_fb->base) ? to_intel_bo((&intel_fb->base)->obj[0]) : ((void *)0))" ")"); __builtin_expect(!!(__ret), 0); })) { |
199 | drm_dbg_kms(&dev_priv->drm,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "no BIOS fb, allocating a new one\n" ) |
200 | "no BIOS fb, allocating a new one\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "no BIOS fb, allocating a new one\n" ); |
201 | ret = intelfb_alloc(helper, sizes); |
202 | if (ret) |
203 | return ret; |
204 | intel_fb = ifbdev->fb; |
205 | } else { |
206 | drm_dbg_kms(&dev_priv->drm, "re-using BIOS fb\n")drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "re-using BIOS fb\n" ); |
207 | prealloc = true1; |
208 | sizes->fb_width = intel_fb->base.width; |
209 | sizes->fb_height = intel_fb->base.height; |
210 | } |
211 | |
212 | wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); |
213 | |
214 | /* Pin the GGTT vma for our access via info->screen_base. |
215 | * This also validates that any existing fb inherited from the |
216 | * BIOS is suitable for own access. |
217 | */ |
218 | vma = intel_pin_and_fence_fb_obj(&ifbdev->fb->base, |
219 | &view, false0, &flags); |
220 | if (IS_ERR(vma)) { |
221 | ret = PTR_ERR(vma); |
222 | goto out_unlock; |
223 | } |
224 | |
225 | intel_frontbuffer_flush(to_frontbuffer(ifbdev), ORIGIN_DIRTYFB); |
226 | |
227 | info = drm_fb_helper_alloc_fbi(helper); |
228 | if (IS_ERR(info)) { |
229 | drm_err(&dev_priv->drm, "Failed to allocate fb_info\n")printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "Failed to allocate fb_info\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__); |
230 | ret = PTR_ERR(info); |
231 | goto out_unpin; |
232 | } |
233 | |
234 | ifbdev->helper.fb = &ifbdev->fb->base; |
235 | |
236 | info->fbops = &intelfb_ops; |
237 | |
238 | #ifdef __linux__ |
239 | /* setup aperture base/size for vesafb takeover */ |
240 | info->apertures->ranges[0].base = ggtt->gmadr.start; |
241 | info->apertures->ranges[0].size = ggtt->mappable_end; |
242 | |
243 | /* Our framebuffer is the entirety of fbdev's system memory */ |
244 | info->fix.smem_start = |
245 | (unsigned long)(ggtt->gmadr.start + vma->node.start); |
246 | info->fix.smem_len = vma->node.size; |
247 | |
248 | vaddr = i915_vma_pin_iomap(vma); |
249 | if (IS_ERR(vaddr)) { |
250 | drm_err(&dev_priv->drm,printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "Failed to remap framebuffer into virtual memory\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__) |
251 | "Failed to remap framebuffer into virtual memory\n")printf("drm:pid%d:%s *ERROR* " "[drm] " "*ERROR* " "Failed to remap framebuffer into virtual memory\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__); |
252 | ret = PTR_ERR(vaddr); |
253 | goto out_unpin; |
254 | } |
255 | info->screen_base = vaddr; |
256 | info->screen_size = vma->node.size; |
257 | |
258 | drm_fb_helper_fill_info(info, &ifbdev->helper, sizes); |
259 | |
260 | /* If the object is shmemfs backed, it will have given us zeroed pages. |
261 | * If the object is stolen however, it will be full of whatever |
262 | * garbage was left in there. |
263 | */ |
264 | if (vma->obj->stolen && !prealloc) |
265 | memset_io(info->screen_base, 0, info->screen_size)__builtin_memset((info->screen_base), (0), (info->screen_size )); |
266 | |
267 | /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ |
268 | #else |
269 | { |
270 | struct drm_framebuffer *fb = ifbdev->helper.fb; |
271 | struct rasops_info *ri = &dev_priv->ro; |
272 | bus_space_handle_t bsh; |
273 | int err; |
274 | |
275 | vaddr = i915_vma_pin_iomap(vma); |
276 | if (IS_ERR(vaddr)) { |
277 | DRM_ERROR("Failed to remap framebuffer into virtual memory\n")__drm_err("Failed to remap framebuffer into virtual memory\n" ); |
278 | ret = PTR_ERR(vaddr); |
279 | goto out_unpin; |
280 | } |
281 | |
282 | drm_fb_helper_fill_info(info, &ifbdev->helper, sizes); |
283 | |
284 | ri->ri_bits = vaddr; |
285 | ri->ri_depth = fb->format->cpp[0] * 8; |
286 | ri->ri_stride = fb->pitches[0]; |
287 | ri->ri_width = sizes->fb_width; |
288 | ri->ri_height = sizes->fb_height; |
289 | |
290 | switch (fb->format->format) { |
291 | case DRM_FORMAT_XRGB8888((__u32)('X') | ((__u32)('R') << 8) | ((__u32)('2') << 16) | ((__u32)('4') << 24)): |
292 | ri->ri_rnum = 8; |
293 | ri->ri_rpos = 16; |
294 | ri->ri_gnum = 8; |
295 | ri->ri_gpos = 8; |
296 | ri->ri_bnum = 8; |
297 | ri->ri_bpos = 0; |
298 | break; |
299 | case DRM_FORMAT_RGB565((__u32)('R') | ((__u32)('G') << 8) | ((__u32)('1') << 16) | ((__u32)('6') << 24)): |
300 | ri->ri_rnum = 5; |
301 | ri->ri_rpos = 11; |
302 | ri->ri_gnum = 6; |
303 | ri->ri_gpos = 5; |
304 | ri->ri_bnum = 5; |
305 | ri->ri_bpos = 0; |
306 | break; |
307 | } |
308 | |
309 | if (vma->obj->stolen && !prealloc) |
310 | memset(ri->ri_bits, 0, vma->node.size)__builtin_memset((ri->ri_bits), (0), (vma->node.size)); |
311 | } |
312 | #endif |
313 | |
314 | drm_dbg_kms(&dev_priv->drm, "allocated %dx%d fb: 0x%08x\n",drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "allocated %dx%d fb: 0x%08x\n" , ifbdev->fb->base.width, ifbdev->fb->base.height , i915_ggtt_offset(vma)) |
315 | ifbdev->fb->base.width, ifbdev->fb->base.height,drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "allocated %dx%d fb: 0x%08x\n" , ifbdev->fb->base.width, ifbdev->fb->base.height , i915_ggtt_offset(vma)) |
316 | i915_ggtt_offset(vma))drm_dev_dbg((&dev_priv->drm)->dev, DRM_UT_KMS, "allocated %dx%d fb: 0x%08x\n" , ifbdev->fb->base.width, ifbdev->fb->base.height , i915_ggtt_offset(vma)); |
317 | ifbdev->vma = vma; |
318 | ifbdev->vma_flags = flags; |
319 | |
320 | intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); |
321 | vga_switcheroo_client_fb_set(pdev, info); |
322 | return 0; |
323 | |
324 | out_unpin: |
325 | intel_unpin_fb_vma(vma, flags); |
326 | out_unlock: |
327 | intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); |
328 | return ret; |
329 | } |
330 | |
331 | static const struct drm_fb_helper_funcs intel_fb_helper_funcs = { |
332 | .fb_probe = intelfb_create, |
333 | }; |
334 | |
335 | static void intel_fbdev_destroy(struct intel_fbdev *ifbdev) |
336 | { |
337 | /* We rely on the object-free to release the VMA pinning for |
338 | * the info->screen_base mmaping. Leaking the VMA is simpler than |
339 | * trying to rectify all the possible error paths leading here. |
340 | */ |
341 | |
342 | drm_fb_helper_fini(&ifbdev->helper); |
343 | |
344 | if (ifbdev->vma) |
345 | intel_unpin_fb_vma(ifbdev->vma, ifbdev->vma_flags); |
346 | |
347 | if (ifbdev->fb) |
348 | drm_framebuffer_remove(&ifbdev->fb->base); |
349 | |
350 | kfree(ifbdev); |
351 | } |
352 | |
353 | /* |
354 | * Build an intel_fbdev struct using a BIOS allocated framebuffer, if possible. |
355 | * The core display code will have read out the current plane configuration, |
356 | * so we use that to figure out if there's an object for us to use as the |
357 | * fb, and if so, we re-use it for the fbdev configuration. |
358 | * |
359 | * Note we only support a single fb shared across pipes for boot (mostly for |
360 | * fbcon), so we just find the biggest and use that. |
361 | */ |
362 | static bool_Bool intel_fbdev_init_bios(struct drm_device *dev, |
363 | struct intel_fbdev *ifbdev) |
364 | { |
365 | struct drm_i915_privateinteldrm_softc *i915 = to_i915(dev); |
366 | struct intel_framebuffer *fb = NULL((void *)0); |
367 | struct drm_crtc *crtc; |
368 | struct intel_crtc *intel_crtc; |
369 | unsigned int max_size = 0; |
370 | |
371 | /* Find the largest fb */ |
372 | for_each_crtc(dev, crtc)for (crtc = ({ const __typeof( ((__typeof(*crtc) *)0)->head ) *__mptr = ((&(dev)->mode_config.crtc_list)->next ); (__typeof(*crtc) *)( (char *)__mptr - __builtin_offsetof(__typeof (*crtc), head) );}); &crtc->head != (&(dev)->mode_config .crtc_list); crtc = ({ const __typeof( ((__typeof(*crtc) *)0) ->head ) *__mptr = (crtc->head.next); (__typeof(*crtc) * )( (char *)__mptr - __builtin_offsetof(__typeof(*crtc), head) );})) { |
373 | struct drm_i915_gem_object *obj = |
374 | intel_fb_obj(crtc->primary->state->fb)((crtc->primary->state->fb) ? to_intel_bo((crtc-> primary->state->fb)->obj[0]) : ((void *)0)); |
375 | intel_crtc = to_intel_crtc(crtc)({ const __typeof( ((struct intel_crtc *)0)->base ) *__mptr = (crtc); (struct intel_crtc *)( (char *)__mptr - __builtin_offsetof (struct intel_crtc, base) );}); |
376 | |
377 | if (!crtc->state->active || !obj) { |
378 | drm_dbg_kms(&i915->drm,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c not active or no fb, skipping\n" , ((intel_crtc->pipe) + 'A')) |
379 | "pipe %c not active or no fb, skipping\n",drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c not active or no fb, skipping\n" , ((intel_crtc->pipe) + 'A')) |
380 | pipe_name(intel_crtc->pipe))drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c not active or no fb, skipping\n" , ((intel_crtc->pipe) + 'A')); |
381 | continue; |
382 | } |
383 | |
384 | if (obj->base.size > max_size) { |
385 | drm_dbg_kms(&i915->drm,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "found possible fb from plane %c\n" , ((intel_crtc->pipe) + 'A')) |
386 | "found possible fb from plane %c\n",drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "found possible fb from plane %c\n" , ((intel_crtc->pipe) + 'A')) |
387 | pipe_name(intel_crtc->pipe))drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "found possible fb from plane %c\n" , ((intel_crtc->pipe) + 'A')); |
388 | fb = to_intel_framebuffer(crtc->primary->state->fb)({ const __typeof( ((struct intel_framebuffer *)0)->base ) *__mptr = (crtc->primary->state->fb); (struct intel_framebuffer *)( (char *)__mptr - __builtin_offsetof(struct intel_framebuffer , base) );}); |
389 | max_size = obj->base.size; |
390 | } |
391 | } |
392 | |
393 | if (!fb) { |
394 | drm_dbg_kms(&i915->drm,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "no active fbs found, not using BIOS config\n" ) |
395 | "no active fbs found, not using BIOS config\n")drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "no active fbs found, not using BIOS config\n" ); |
396 | goto out; |
397 | } |
398 | |
399 | /* Now make sure all the pipes will fit into it */ |
400 | for_each_crtc(dev, crtc)for (crtc = ({ const __typeof( ((__typeof(*crtc) *)0)->head ) *__mptr = ((&(dev)->mode_config.crtc_list)->next ); (__typeof(*crtc) *)( (char *)__mptr - __builtin_offsetof(__typeof (*crtc), head) );}); &crtc->head != (&(dev)->mode_config .crtc_list); crtc = ({ const __typeof( ((__typeof(*crtc) *)0) ->head ) *__mptr = (crtc->head.next); (__typeof(*crtc) * )( (char *)__mptr - __builtin_offsetof(__typeof(*crtc), head) );})) { |
401 | unsigned int cur_size; |
402 | |
403 | intel_crtc = to_intel_crtc(crtc)({ const __typeof( ((struct intel_crtc *)0)->base ) *__mptr = (crtc); (struct intel_crtc *)( (char *)__mptr - __builtin_offsetof (struct intel_crtc, base) );}); |
404 | |
405 | if (!crtc->state->active) { |
406 | drm_dbg_kms(&i915->drm,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c not active, skipping\n" , ((intel_crtc->pipe) + 'A')) |
407 | "pipe %c not active, skipping\n",drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c not active, skipping\n" , ((intel_crtc->pipe) + 'A')) |
408 | pipe_name(intel_crtc->pipe))drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c not active, skipping\n" , ((intel_crtc->pipe) + 'A')); |
409 | continue; |
410 | } |
411 | |
412 | drm_dbg_kms(&i915->drm, "checking plane %c for BIOS fb\n",drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "checking plane %c for BIOS fb\n" , ((intel_crtc->pipe) + 'A')) |
413 | pipe_name(intel_crtc->pipe))drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "checking plane %c for BIOS fb\n" , ((intel_crtc->pipe) + 'A')); |
414 | |
415 | /* |
416 | * See if the plane fb we found above will fit on this |
417 | * pipe. Note we need to use the selected fb's pitch and bpp |
418 | * rather than the current pipe's, since they differ. |
419 | */ |
420 | cur_size = crtc->state->adjusted_mode.crtc_hdisplay; |
421 | cur_size = cur_size * fb->base.format->cpp[0]; |
422 | if (fb->base.pitches[0] < cur_size) { |
423 | drm_dbg_kms(&i915->drm,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb not wide enough for plane %c (%d vs %d)\n" , ((intel_crtc->pipe) + 'A'), cur_size, fb->base.pitches [0]) |
424 | "fb not wide enough for plane %c (%d vs %d)\n",drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb not wide enough for plane %c (%d vs %d)\n" , ((intel_crtc->pipe) + 'A'), cur_size, fb->base.pitches [0]) |
425 | pipe_name(intel_crtc->pipe),drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb not wide enough for plane %c (%d vs %d)\n" , ((intel_crtc->pipe) + 'A'), cur_size, fb->base.pitches [0]) |
426 | cur_size, fb->base.pitches[0])drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb not wide enough for plane %c (%d vs %d)\n" , ((intel_crtc->pipe) + 'A'), cur_size, fb->base.pitches [0]); |
427 | fb = NULL((void *)0); |
428 | break; |
429 | } |
430 | |
431 | cur_size = crtc->state->adjusted_mode.crtc_vdisplay; |
432 | cur_size = intel_fb_align_height(&fb->base, 0, cur_size); |
433 | cur_size *= fb->base.pitches[0]; |
434 | drm_dbg_kms(&i915->drm,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c area: %dx%d, bpp: %d, size: %d\n" , ((intel_crtc->pipe) + 'A'), crtc->state->adjusted_mode .crtc_hdisplay, crtc->state->adjusted_mode.crtc_vdisplay , fb->base.format->cpp[0] * 8, cur_size) |
435 | "pipe %c area: %dx%d, bpp: %d, size: %d\n",drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c area: %dx%d, bpp: %d, size: %d\n" , ((intel_crtc->pipe) + 'A'), crtc->state->adjusted_mode .crtc_hdisplay, crtc->state->adjusted_mode.crtc_vdisplay , fb->base.format->cpp[0] * 8, cur_size) |
436 | pipe_name(intel_crtc->pipe),drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c area: %dx%d, bpp: %d, size: %d\n" , ((intel_crtc->pipe) + 'A'), crtc->state->adjusted_mode .crtc_hdisplay, crtc->state->adjusted_mode.crtc_vdisplay , fb->base.format->cpp[0] * 8, cur_size) |
437 | crtc->state->adjusted_mode.crtc_hdisplay,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c area: %dx%d, bpp: %d, size: %d\n" , ((intel_crtc->pipe) + 'A'), crtc->state->adjusted_mode .crtc_hdisplay, crtc->state->adjusted_mode.crtc_vdisplay , fb->base.format->cpp[0] * 8, cur_size) |
438 | crtc->state->adjusted_mode.crtc_vdisplay,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c area: %dx%d, bpp: %d, size: %d\n" , ((intel_crtc->pipe) + 'A'), crtc->state->adjusted_mode .crtc_hdisplay, crtc->state->adjusted_mode.crtc_vdisplay , fb->base.format->cpp[0] * 8, cur_size) |
439 | fb->base.format->cpp[0] * 8,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c area: %dx%d, bpp: %d, size: %d\n" , ((intel_crtc->pipe) + 'A'), crtc->state->adjusted_mode .crtc_hdisplay, crtc->state->adjusted_mode.crtc_vdisplay , fb->base.format->cpp[0] * 8, cur_size) |
440 | cur_size)drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "pipe %c area: %dx%d, bpp: %d, size: %d\n" , ((intel_crtc->pipe) + 'A'), crtc->state->adjusted_mode .crtc_hdisplay, crtc->state->adjusted_mode.crtc_vdisplay , fb->base.format->cpp[0] * 8, cur_size); |
441 | |
442 | if (cur_size > max_size) { |
443 | drm_dbg_kms(&i915->drm,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb not big enough for plane %c (%d vs %d)\n" , ((intel_crtc->pipe) + 'A'), cur_size, max_size) |
444 | "fb not big enough for plane %c (%d vs %d)\n",drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb not big enough for plane %c (%d vs %d)\n" , ((intel_crtc->pipe) + 'A'), cur_size, max_size) |
445 | pipe_name(intel_crtc->pipe),drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb not big enough for plane %c (%d vs %d)\n" , ((intel_crtc->pipe) + 'A'), cur_size, max_size) |
446 | cur_size, max_size)drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb not big enough for plane %c (%d vs %d)\n" , ((intel_crtc->pipe) + 'A'), cur_size, max_size); |
447 | fb = NULL((void *)0); |
448 | break; |
449 | } |
450 | |
451 | drm_dbg_kms(&i915->drm,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb big enough for plane %c (%d >= %d)\n" , ((intel_crtc->pipe) + 'A'), max_size, cur_size) |
452 | "fb big enough for plane %c (%d >= %d)\n",drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb big enough for plane %c (%d >= %d)\n" , ((intel_crtc->pipe) + 'A'), max_size, cur_size) |
453 | pipe_name(intel_crtc->pipe),drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb big enough for plane %c (%d >= %d)\n" , ((intel_crtc->pipe) + 'A'), max_size, cur_size) |
454 | max_size, cur_size)drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "fb big enough for plane %c (%d >= %d)\n" , ((intel_crtc->pipe) + 'A'), max_size, cur_size); |
455 | } |
456 | |
457 | if (!fb) { |
458 | drm_dbg_kms(&i915->drm,drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "BIOS fb not suitable for all pipes, not using\n" ) |
459 | "BIOS fb not suitable for all pipes, not using\n")drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "BIOS fb not suitable for all pipes, not using\n" ); |
460 | goto out; |
461 | } |
462 | |
463 | ifbdev->preferred_bpp = fb->base.format->cpp[0] * 8; |
464 | ifbdev->fb = fb; |
465 | |
466 | drm_framebuffer_get(&ifbdev->fb->base); |
467 | |
468 | /* Final pass to check if any active pipes don't have fbs */ |
469 | for_each_crtc(dev, crtc)for (crtc = ({ const __typeof( ((__typeof(*crtc) *)0)->head ) *__mptr = ((&(dev)->mode_config.crtc_list)->next ); (__typeof(*crtc) *)( (char *)__mptr - __builtin_offsetof(__typeof (*crtc), head) );}); &crtc->head != (&(dev)->mode_config .crtc_list); crtc = ({ const __typeof( ((__typeof(*crtc) *)0) ->head ) *__mptr = (crtc->head.next); (__typeof(*crtc) * )( (char *)__mptr - __builtin_offsetof(__typeof(*crtc), head) );})) { |
470 | intel_crtc = to_intel_crtc(crtc)({ const __typeof( ((struct intel_crtc *)0)->base ) *__mptr = (crtc); (struct intel_crtc *)( (char *)__mptr - __builtin_offsetof (struct intel_crtc, base) );}); |
471 | |
472 | if (!crtc->state->active) |
473 | continue; |
474 | |
475 | drm_WARN(dev, !crtc->primary->state->fb,({ int __ret = !!(!crtc->primary->state->fb); if (__ret ) printf("%s %s: " "re-used BIOS config but lost an fb on crtc %d\n" , dev_driver_string((dev)->dev), "", crtc->base.id); __builtin_expect (!!(__ret), 0); }) |
476 | "re-used BIOS config but lost an fb on crtc %d\n",({ int __ret = !!(!crtc->primary->state->fb); if (__ret ) printf("%s %s: " "re-used BIOS config but lost an fb on crtc %d\n" , dev_driver_string((dev)->dev), "", crtc->base.id); __builtin_expect (!!(__ret), 0); }) |
477 | crtc->base.id)({ int __ret = !!(!crtc->primary->state->fb); if (__ret ) printf("%s %s: " "re-used BIOS config but lost an fb on crtc %d\n" , dev_driver_string((dev)->dev), "", crtc->base.id); __builtin_expect (!!(__ret), 0); }); |
478 | } |
479 | |
480 | |
481 | drm_dbg_kms(&i915->drm, "using BIOS fb for initial console\n")drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "using BIOS fb for initial console\n" ); |
482 | return true1; |
483 | |
484 | out: |
485 | |
486 | return false0; |
487 | } |
488 | |
489 | static void intel_fbdev_suspend_worker(struct work_struct *work) |
490 | { |
491 | intel_fbdev_set_suspend(&container_of(work,({ const __typeof( ((struct inteldrm_softc *)0)->fbdev_suspend_work ) *__mptr = (work); (struct inteldrm_softc *)( (char *)__mptr - __builtin_offsetof(struct inteldrm_softc, fbdev_suspend_work ) );}) |
492 | struct drm_i915_private,({ const __typeof( ((struct inteldrm_softc *)0)->fbdev_suspend_work ) *__mptr = (work); (struct inteldrm_softc *)( (char *)__mptr - __builtin_offsetof(struct inteldrm_softc, fbdev_suspend_work ) );}) |
493 | fbdev_suspend_work)({ const __typeof( ((struct inteldrm_softc *)0)->fbdev_suspend_work ) *__mptr = (work); (struct inteldrm_softc *)( (char *)__mptr - __builtin_offsetof(struct inteldrm_softc, fbdev_suspend_work ) );})->drm, |
494 | FBINFO_STATE_RUNNING0, |
495 | true1); |
496 | } |
497 | |
498 | int intel_fbdev_init(struct drm_device *dev) |
499 | { |
500 | struct drm_i915_privateinteldrm_softc *dev_priv = to_i915(dev); |
501 | struct intel_fbdev *ifbdev; |
502 | int ret; |
503 | |
504 | if (drm_WARN_ON(dev, !HAS_DISPLAY(dev_priv))({ int __ret = !!((!((&(dev_priv)->__info)->pipe_mask != 0))); if (__ret) printf("%s %s: " "%s", dev_driver_string (((dev))->dev), "", "drm_WARN_ON(" "!((&(dev_priv)->__info)->pipe_mask != 0)" ")"); __builtin_expect(!!(__ret), 0); })) |
505 | return -ENODEV19; |
506 | |
507 | ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL(0x0001 | 0x0004)); |
508 | if (ifbdev == NULL((void *)0)) |
509 | return -ENOMEM12; |
510 | |
511 | rw_init(&ifbdev->hpd_lock, "hdplk")_rw_init_flags(&ifbdev->hpd_lock, "hdplk", 0, ((void * )0)); |
512 | drm_fb_helper_prepare(dev, &ifbdev->helper, &intel_fb_helper_funcs); |
513 | |
514 | if (!intel_fbdev_init_bios(dev, ifbdev)) |
515 | ifbdev->preferred_bpp = 32; |
516 | |
517 | ret = drm_fb_helper_init(dev, &ifbdev->helper); |
518 | if (ret) { |
519 | kfree(ifbdev); |
520 | return ret; |
521 | } |
522 | |
523 | dev_priv->fbdev = ifbdev; |
524 | INIT_WORK(&dev_priv->fbdev_suspend_work, intel_fbdev_suspend_worker); |
525 | |
526 | return 0; |
527 | } |
528 | |
529 | static void intel_fbdev_initial_config(void *data, async_cookie_t cookie) |
530 | { |
531 | struct intel_fbdev *ifbdev = data; |
532 | |
533 | /* Due to peculiar init order wrt to hpd handling this is separate. */ |
534 | if (drm_fb_helper_initial_config(&ifbdev->helper, |
535 | ifbdev->preferred_bpp)) |
536 | intel_fbdev_unregister(to_i915(ifbdev->helper.dev)); |
537 | } |
538 | |
539 | void intel_fbdev_initial_config_async(struct drm_device *dev) |
540 | { |
541 | struct intel_fbdev *ifbdev = to_i915(dev)->fbdev; |
542 | |
543 | if (!ifbdev) |
544 | return; |
545 | |
546 | ifbdev->cookie = async_schedule(intel_fbdev_initial_config, ifbdev); |
547 | } |
548 | |
549 | static void intel_fbdev_sync(struct intel_fbdev *ifbdev) |
550 | { |
551 | #ifdef __linux__ |
552 | if (!ifbdev->cookie) |
553 | return; |
554 | |
555 | /* Only serialises with all preceding async calls, hence +1 */ |
556 | async_synchronize_cookie(ifbdev->cookie + 1); |
557 | ifbdev->cookie = 0; |
558 | #endif |
559 | } |
560 | |
561 | void intel_fbdev_unregister(struct drm_i915_privateinteldrm_softc *dev_priv) |
562 | { |
563 | struct intel_fbdev *ifbdev = dev_priv->fbdev; |
564 | |
565 | if (!ifbdev) |
566 | return; |
567 | |
568 | cancel_work_sync(&dev_priv->fbdev_suspend_work); |
569 | #ifdef __linux__ |
570 | if (!current_is_async()) |
571 | intel_fbdev_sync(ifbdev); |
572 | #endif |
573 | |
574 | drm_fb_helper_unregister_fbi(&ifbdev->helper); |
575 | } |
576 | |
577 | void intel_fbdev_fini(struct drm_i915_privateinteldrm_softc *dev_priv) |
578 | { |
579 | struct intel_fbdev *ifbdev = fetch_and_zero(&dev_priv->fbdev)({ typeof(*&dev_priv->fbdev) __T = *(&dev_priv-> fbdev); *(&dev_priv->fbdev) = (typeof(*&dev_priv-> fbdev))0; __T; }); |
580 | |
581 | if (!ifbdev) |
582 | return; |
583 | |
584 | intel_fbdev_destroy(ifbdev); |
585 | } |
586 | |
587 | /* Suspends/resumes fbdev processing of incoming HPD events. When resuming HPD |
588 | * processing, fbdev will perform a full connector reprobe if a hotplug event |
589 | * was received while HPD was suspended. |
590 | */ |
591 | static void intel_fbdev_hpd_set_suspend(struct drm_i915_privateinteldrm_softc *i915, int state) |
592 | { |
593 | struct intel_fbdev *ifbdev = i915->fbdev; |
594 | bool_Bool send_hpd = false0; |
595 | |
596 | mutex_lock(&ifbdev->hpd_lock)rw_enter_write(&ifbdev->hpd_lock); |
597 | ifbdev->hpd_suspended = state == FBINFO_STATE_SUSPENDED1; |
598 | send_hpd = !ifbdev->hpd_suspended && ifbdev->hpd_waiting; |
599 | ifbdev->hpd_waiting = false0; |
600 | mutex_unlock(&ifbdev->hpd_lock)rw_exit_write(&ifbdev->hpd_lock); |
601 | |
602 | if (send_hpd) { |
603 | drm_dbg_kms(&i915->drm, "Handling delayed fbcon HPD event\n")drm_dev_dbg((&i915->drm)->dev, DRM_UT_KMS, "Handling delayed fbcon HPD event\n" ); |
604 | drm_fb_helper_hotplug_event(&ifbdev->helper); |
605 | } |
606 | } |
607 | |
608 | void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool_Bool synchronous) |
609 | { |
610 | #ifdef __linux__ |
611 | struct drm_i915_privateinteldrm_softc *dev_priv = to_i915(dev); |
612 | struct intel_fbdev *ifbdev = dev_priv->fbdev; |
613 | struct fb_info *info; |
614 | |
615 | if (!ifbdev || !ifbdev->vma) |
616 | return; |
617 | |
618 | info = ifbdev->helper.fbdev; |
619 | |
620 | if (synchronous) { |
621 | /* Flush any pending work to turn the console on, and then |
622 | * wait to turn it off. It must be synchronous as we are |
623 | * about to suspend or unload the driver. |
624 | * |
625 | * Note that from within the work-handler, we cannot flush |
626 | * ourselves, so only flush outstanding work upon suspend! |
627 | */ |
628 | if (state != FBINFO_STATE_RUNNING0) |
629 | flush_work(&dev_priv->fbdev_suspend_work); |
630 | |
631 | console_lock(); |
632 | } else { |
633 | /* |
634 | * The console lock can be pretty contented on resume due |
635 | * to all the printk activity. Try to keep it out of the hot |
636 | * path of resume if possible. |
637 | */ |
638 | drm_WARN_ON(dev, state != FBINFO_STATE_RUNNING)({ int __ret = !!((state != 0)); if (__ret) printf("%s %s: " "%s" , dev_driver_string(((dev))->dev), "", "drm_WARN_ON(" "state != 0" ")"); __builtin_expect(!!(__ret), 0); }); |
639 | if (!console_trylock()1) { |
640 | /* Don't block our own workqueue as this can |
641 | * be run in parallel with other i915.ko tasks. |
642 | */ |
643 | schedule_work(&dev_priv->fbdev_suspend_work); |
644 | return; |
645 | } |
646 | } |
647 | |
648 | /* On resume from hibernation: If the object is shmemfs backed, it has |
649 | * been restored from swap. If the object is stolen however, it will be |
650 | * full of whatever garbage was left in there. |
651 | */ |
652 | if (state == FBINFO_STATE_RUNNING0 && |
653 | intel_fb_obj(&ifbdev->fb->base)((&ifbdev->fb->base) ? to_intel_bo((&ifbdev-> fb->base)->obj[0]) : ((void *)0))->stolen) |
654 | memset_io(info->screen_base, 0, info->screen_size)__builtin_memset((info->screen_base), (0), (info->screen_size )); |
655 | |
656 | drm_fb_helper_set_suspend(&ifbdev->helper, state); |
657 | console_unlock(); |
658 | |
659 | intel_fbdev_hpd_set_suspend(dev_priv, state); |
660 | #endif |
661 | } |
662 | |
663 | void intel_fbdev_output_poll_changed(struct drm_device *dev) |
664 | { |
665 | struct intel_fbdev *ifbdev = to_i915(dev)->fbdev; |
666 | bool_Bool send_hpd; |
667 | |
668 | if (!ifbdev) |
669 | return; |
670 | |
671 | intel_fbdev_sync(ifbdev); |
672 | |
673 | mutex_lock(&ifbdev->hpd_lock)rw_enter_write(&ifbdev->hpd_lock); |
674 | send_hpd = !ifbdev->hpd_suspended; |
675 | ifbdev->hpd_waiting = true1; |
676 | mutex_unlock(&ifbdev->hpd_lock)rw_exit_write(&ifbdev->hpd_lock); |
677 | |
678 | if (send_hpd && (ifbdev->vma || ifbdev->helper.deferred_setup)) |
679 | drm_fb_helper_hotplug_event(&ifbdev->helper); |
680 | } |
681 | |
682 | void intel_fbdev_restore_mode(struct drm_device *dev) |
683 | { |
684 | struct intel_fbdev *ifbdev = to_i915(dev)->fbdev; |
685 | |
686 | if (!ifbdev) |
687 | return; |
688 | |
689 | intel_fbdev_sync(ifbdev); |
690 | if (!ifbdev->vma) |
691 | return; |
692 | |
693 | if (drm_fb_helper_restore_fbdev_mode_unlocked(&ifbdev->helper) == 0) |
694 | intel_fbdev_invalidate(ifbdev); |
695 | } |