aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/Makefile3
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c697
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c3
-rw-r--r--drivers/gpu/drm/i915/intel_display.c12
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h3
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c737
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c670
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h2
9 files changed, 823 insertions, 1309 deletions
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 5f0aec4f082..99071684de2 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -11,7 +11,8 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \
11 drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \ 11 drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
12 drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o \ 12 drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o \
13 drm_crtc.o drm_crtc_helper.o drm_modes.o drm_edid.o \ 13 drm_crtc.o drm_crtc_helper.o drm_modes.o drm_edid.o \
14 drm_info.o drm_debugfs.o drm_encoder_slave.o 14 drm_info.o drm_debugfs.o drm_encoder_slave.o \
15 drm_fb_helper.o
15 16
16drm-$(CONFIG_COMPAT) += drm_ioc32.o 17drm-$(CONFIG_COMPAT) += drm_ioc32.o
17 18
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
new file mode 100644
index 00000000000..d6ffea74a50
--- /dev/null
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -0,0 +1,697 @@
1/*
2 * Copyright (c) 2006-2009 Red Hat Inc.
3 * Copyright (c) 2006-2008 Intel Corporation
4 * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
5 *
6 * DRM framebuffer helper functions
7 *
8 * Permission to use, copy, modify, distribute, and sell this software and its
9 * documentation for any purpose is hereby granted without fee, provided that
10 * the above copyright notice appear in all copies and that both that copyright
11 * notice and this permission notice appear in supporting documentation, and
12 * that the name of the copyright holders not be used in advertising or
13 * publicity pertaining to distribution of the software without specific,
14 * written prior permission. The copyright holders make no representations
15 * about the suitability of this software for any purpose. It is provided "as
16 * is" without express or implied warranty.
17 *
18 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
20 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
21 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
22 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
23 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24 * OF THIS SOFTWARE.
25 *
26 * Authors:
27 * Dave Airlie <airlied@linux.ie>
28 * Jesse Barnes <jesse.barnes@intel.com>
29 */
30#include <linux/sysrq.h>
31#include <linux/fb.h>
32#include "drmP.h"
33#include "drm_crtc.h"
34#include "drm_fb_helper.h"
35#include "drm_crtc_helper.h"
36
37static LIST_HEAD(kernel_fb_helper_list);
38
39bool drm_fb_helper_force_kernel_mode(void)
40{
41 int i = 0;
42 bool ret, error = false;
43 struct drm_fb_helper *helper;
44
45 if (list_empty(&kernel_fb_helper_list))
46 return false;
47
48 list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
49 for (i = 0; i < helper->crtc_count; i++) {
50 struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
51 ret = drm_crtc_helper_set_config(mode_set);
52 if (ret)
53 error = true;
54 }
55 }
56 return error;
57}
58
59int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed,
60 void *panic_str)
61{
62 DRM_ERROR("panic occurred, switching back to text console\n");
63 return drm_fb_helper_force_kernel_mode();
64 return 0;
65}
66EXPORT_SYMBOL(drm_fb_helper_panic);
67
68static struct notifier_block paniced = {
69 .notifier_call = drm_fb_helper_panic,
70};
71
72/**
73 * drm_fb_helper_restore - restore the framebuffer console (kernel) config
74 *
75 * Restore's the kernel's fbcon mode, used for lastclose & panic paths.
76 */
77void drm_fb_helper_restore(void)
78{
79 bool ret;
80 ret = drm_fb_helper_force_kernel_mode();
81 if (ret == true)
82 DRM_ERROR("Failed to restore crtc configuration\n");
83}
84EXPORT_SYMBOL(drm_fb_helper_restore);
85
86static void drm_fb_helper_restore_work_fn(struct work_struct *ignored)
87{
88 drm_fb_helper_restore();
89}
90static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn);
91
92static void drm_fb_helper_sysrq(int dummy1, struct tty_struct *dummy3)
93{
94 schedule_work(&drm_fb_helper_restore_work);
95}
96
97static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
98 .handler = drm_fb_helper_sysrq,
99 .help_msg = "force-fb(V)",
100 .action_msg = "Restore framebuffer console",
101};
102
103static void drm_fb_helper_on(struct fb_info *info)
104{
105 struct drm_fb_helper *fb_helper = info->par;
106 struct drm_device *dev = fb_helper->dev;
107 struct drm_crtc *crtc;
108 struct drm_encoder *encoder;
109 int i;
110
111 /*
112 * For each CRTC in this fb, turn the crtc on then,
113 * find all associated encoders and turn them on.
114 */
115 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
116 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
117
118 for (i = 0; i < fb_helper->crtc_count; i++) {
119 if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
120 break;
121 }
122
123 mutex_lock(&dev->mode_config.mutex);
124 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
125 mutex_unlock(&dev->mode_config.mutex);
126
127 /* Found a CRTC on this fb, now find encoders */
128 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
129 if (encoder->crtc == crtc) {
130 struct drm_encoder_helper_funcs *encoder_funcs;
131
132 encoder_funcs = encoder->helper_private;
133 mutex_lock(&dev->mode_config.mutex);
134 encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
135 mutex_unlock(&dev->mode_config.mutex);
136 }
137 }
138 }
139}
140
141static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
142{
143 struct drm_fb_helper *fb_helper = info->par;
144 struct drm_device *dev = fb_helper->dev;
145 struct drm_crtc *crtc;
146 struct drm_encoder *encoder;
147 int i;
148
149 /*
150 * For each CRTC in this fb, find all associated encoders
151 * and turn them off, then turn off the CRTC.
152 */
153 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
154 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
155
156 for (i = 0; i < fb_helper->crtc_count; i++) {
157 if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
158 break;
159 }
160
161 /* Found a CRTC on this fb, now find encoders */
162 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
163 if (encoder->crtc == crtc) {
164 struct drm_encoder_helper_funcs *encoder_funcs;
165
166 encoder_funcs = encoder->helper_private;
167 mutex_lock(&dev->mode_config.mutex);
168 encoder_funcs->dpms(encoder, dpms_mode);
169 mutex_unlock(&dev->mode_config.mutex);
170 }
171 }
172 if (dpms_mode == DRM_MODE_DPMS_OFF) {
173 mutex_lock(&dev->mode_config.mutex);
174 crtc_funcs->dpms(crtc, dpms_mode);
175 mutex_unlock(&dev->mode_config.mutex);
176 }
177 }
178}
179
180int drm_fb_helper_blank(int blank, struct fb_info *info)
181{
182 switch (blank) {
183 case FB_BLANK_UNBLANK:
184 drm_fb_helper_on(info);
185 break;
186 case FB_BLANK_NORMAL:
187 drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
188 break;
189 case FB_BLANK_HSYNC_SUSPEND:
190 drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
191 break;
192 case FB_BLANK_VSYNC_SUSPEND:
193 drm_fb_helper_off(info, DRM_MODE_DPMS_SUSPEND);
194 break;
195 case FB_BLANK_POWERDOWN:
196 drm_fb_helper_off(info, DRM_MODE_DPMS_OFF);
197 break;
198 }
199 return 0;
200}
201EXPORT_SYMBOL(drm_fb_helper_blank);
202
203static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
204{
205 int i;
206
207 for (i = 0; i < helper->crtc_count; i++)
208 kfree(helper->crtc_info[i].mode_set.connectors);
209 kfree(helper->crtc_info);
210}
211
212int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count, int max_conn_count)
213{
214 struct drm_device *dev = helper->dev;
215 struct drm_crtc *crtc;
216 int ret = 0;
217 int i;
218
219 helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
220 if (!helper->crtc_info)
221 return -ENOMEM;
222
223 helper->crtc_count = crtc_count;
224
225 for (i = 0; i < crtc_count; i++) {
226 helper->crtc_info[i].mode_set.connectors =
227 kcalloc(max_conn_count,
228 sizeof(struct drm_connector *),
229 GFP_KERNEL);
230
231 if (!helper->crtc_info[i].mode_set.connectors) {
232 ret = -ENOMEM;
233 goto out_free;
234 }
235 helper->crtc_info[i].mode_set.num_connectors = 0;
236 }
237
238 i = 0;
239 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
240 helper->crtc_info[i].crtc_id = crtc->base.id;
241 helper->crtc_info[i].mode_set.crtc = crtc;
242 i++;
243 }
244 helper->conn_limit = max_conn_count;
245 return 0;
246out_free:
247 drm_fb_helper_crtc_free(helper);
248 return -ENOMEM;
249}
250EXPORT_SYMBOL(drm_fb_helper_init_crtc_count);
251
252int drm_fb_helper_setcolreg(unsigned regno,
253 unsigned red,
254 unsigned green,
255 unsigned blue,
256 unsigned transp,
257 struct fb_info *info)
258{
259 struct drm_fb_helper *fb_helper = info->par;
260 struct drm_device *dev = fb_helper->dev;
261 struct drm_crtc *crtc;
262 int i;
263
264 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
265 struct drm_framebuffer *fb = fb_helper->fb;
266
267 for (i = 0; i < fb_helper->crtc_count; i++) {
268 if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
269 break;
270 }
271 if (i == fb_helper->crtc_count)
272 continue;
273
274 if (regno > 255)
275 return 1;
276
277 if (fb->depth == 8) {
278 fb_helper->funcs->gamma_set(crtc, red, green, blue, regno);
279 return 0;
280 }
281
282 if (regno < 16) {
283 switch (fb->depth) {
284 case 15:
285 fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
286 ((green & 0xf800) >> 6) |
287 ((blue & 0xf800) >> 11);
288 break;
289 case 16:
290 fb->pseudo_palette[regno] = (red & 0xf800) |
291 ((green & 0xfc00) >> 5) |
292 ((blue & 0xf800) >> 11);
293 break;
294 case 24:
295 case 32:
296 fb->pseudo_palette[regno] =
297 (((red >> 8) & 0xff) << info->var.red.offset) |
298 (((green >> 8) & 0xff) << info->var.green.offset) |
299 (((blue >> 8) & 0xff) << info->var.blue.offset);
300 break;
301 }
302 }
303 }
304 return 0;
305}
306EXPORT_SYMBOL(drm_fb_helper_setcolreg);
307
308int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
309 struct fb_info *info)
310{
311 struct drm_fb_helper *fb_helper = info->par;
312 struct drm_framebuffer *fb = fb_helper->fb;
313 int depth;
314
315 if (var->pixclock == -1 || !var->pixclock)
316 return -EINVAL;
317
318 /* Need to resize the fb object !!! */
319 if (var->xres > fb->width || var->yres > fb->height) {
320 DRM_ERROR("Requested width/height is greater than current fb "
321 "object %dx%d > %dx%d\n", var->xres, var->yres,
322 fb->width, fb->height);
323 DRM_ERROR("Need resizing code.\n");
324 return -EINVAL;
325 }
326
327 switch (var->bits_per_pixel) {
328 case 16:
329 depth = (var->green.length == 6) ? 16 : 15;
330 break;
331 case 32:
332 depth = (var->transp.length > 0) ? 32 : 24;
333 break;
334 default:
335 depth = var->bits_per_pixel;
336 break;
337 }
338
339 switch (depth) {
340 case 8:
341 var->red.offset = 0;
342 var->green.offset = 0;
343 var->blue.offset = 0;
344 var->red.length = 8;
345 var->green.length = 8;
346 var->blue.length = 8;
347 var->transp.length = 0;
348 var->transp.offset = 0;
349 break;
350 case 15:
351 var->red.offset = 10;
352 var->green.offset = 5;
353 var->blue.offset = 0;
354 var->red.length = 5;
355 var->green.length = 5;
356 var->blue.length = 5;
357 var->transp.length = 1;
358 var->transp.offset = 15;
359 break;
360 case 16:
361 var->red.offset = 11;
362 var->green.offset = 5;
363 var->blue.offset = 0;
364 var->red.length = 5;
365 var->green.length = 6;
366 var->blue.length = 5;
367 var->transp.length = 0;
368 var->transp.offset = 0;
369 break;
370 case 24:
371 var->red.offset = 16;
372 var->green.offset = 8;
373 var->blue.offset = 0;
374 var->red.length = 8;
375 var->green.length = 8;
376 var->blue.length = 8;
377 var->transp.length = 0;
378 var->transp.offset = 0;
379 break;
380 case 32:
381 var->red.offset = 16;
382 var->green.offset = 8;
383 var->blue.offset = 0;
384 var->red.length = 8;
385 var->green.length = 8;
386 var->blue.length = 8;
387 var->transp.length = 8;
388 var->transp.offset = 24;
389 break;
390 default:
391 return -EINVAL;
392 }
393 return 0;
394}
395EXPORT_SYMBOL(drm_fb_helper_check_var);
396
397/* this will let fbcon do the mode init */
398int drm_fb_helper_set_par(struct fb_info *info)
399{
400 struct drm_fb_helper *fb_helper = info->par;
401 struct drm_device *dev = fb_helper->dev;
402 struct fb_var_screeninfo *var = &info->var;
403 struct drm_crtc *crtc;
404 int ret;
405 int i;
406
407 if (var->pixclock != -1) {
408 DRM_ERROR("PIXEL CLCOK SET\n");
409 return -EINVAL;
410 }
411
412 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
413
414 for (i = 0; i < fb_helper->crtc_count; i++) {
415 if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
416 break;
417 }
418 if (i == fb_helper->crtc_count)
419 continue;
420
421 if (crtc->fb == fb_helper->crtc_info[i].mode_set.fb) {
422 mutex_lock(&dev->mode_config.mutex);
423 ret = crtc->funcs->set_config(&fb_helper->crtc_info->mode_set);
424 mutex_unlock(&dev->mode_config.mutex);
425 if (ret)
426 return ret;
427 }
428 }
429 return 0;
430}
431EXPORT_SYMBOL(drm_fb_helper_set_par);
432
433int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
434 struct fb_info *info)
435{
436 struct drm_fb_helper *fb_helper = info->par;
437 struct drm_device *dev = fb_helper->dev;
438 struct drm_mode_set *modeset;
439 struct drm_crtc *crtc;
440 int ret = 0;
441 int i;
442
443 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
444 for (i = 0; i < fb_helper->crtc_count; i++) {
445 if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
446 break;
447 }
448
449 if (i == fb_helper->crtc_count)
450 continue;
451
452 modeset = &fb_helper->crtc_info[i].mode_set;
453
454 modeset->x = var->xoffset;
455 modeset->y = var->yoffset;
456
457 if (modeset->num_connectors) {
458 mutex_lock(&dev->mode_config.mutex);
459 ret = crtc->funcs->set_config(modeset);
460 mutex_unlock(&dev->mode_config.mutex);
461 if (!ret) {
462 info->var.xoffset = var->xoffset;
463 info->var.yoffset = var->yoffset;
464 }
465 }
466 }
467 return ret;
468}
469EXPORT_SYMBOL(drm_fb_helper_pan_display);
470
471int drm_fb_helper_single_fb_probe(struct drm_device *dev,
472 int (*fb_create)(struct drm_device *dev,
473 uint32_t fb_width,
474 uint32_t fb_height,
475 uint32_t surface_width,
476 uint32_t surface_height,
477 struct drm_framebuffer **fb_ptr))
478{
479 struct drm_crtc *crtc;
480 struct drm_connector *connector;
481 unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
482 unsigned int surface_width = 0, surface_height = 0;
483 int new_fb = 0;
484 int crtc_count = 0;
485 int ret, i, conn_count = 0;
486 struct fb_info *info;
487 struct drm_framebuffer *fb;
488 struct drm_mode_set *modeset = NULL;
489 struct drm_fb_helper *fb_helper;
490
491 /* first up get a count of crtcs now in use and new min/maxes width/heights */
492 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
493 if (drm_helper_crtc_in_use(crtc)) {
494 if (crtc->desired_mode) {
495 if (crtc->desired_mode->hdisplay < fb_width)
496 fb_width = crtc->desired_mode->hdisplay;
497
498 if (crtc->desired_mode->vdisplay < fb_height)
499 fb_height = crtc->desired_mode->vdisplay;
500
501 if (crtc->desired_mode->hdisplay > surface_width)
502 surface_width = crtc->desired_mode->hdisplay;
503
504 if (crtc->desired_mode->vdisplay > surface_height)
505 surface_height = crtc->desired_mode->vdisplay;
506 }
507 crtc_count++;
508 }
509 }
510
511 if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
512 /* hmm everyone went away - assume VGA cable just fell out
513 and will come back later. */
514 return 0;
515 }
516
517 /* do we have an fb already? */
518 if (list_empty(&dev->mode_config.fb_kernel_list)) {
519 ret = (*fb_create)(dev, fb_width, fb_height, surface_width,
520 surface_height, &fb);
521 if (ret)
522 return -EINVAL;
523 new_fb = 1;
524 } else {
525 fb = list_first_entry(&dev->mode_config.fb_kernel_list,
526 struct drm_framebuffer, filp_head);
527
528 /* if someone hotplugs something bigger than we have already allocated, we are pwned.
529 As really we can't resize an fbdev that is in the wild currently due to fbdev
530 not really being designed for the lower layers moving stuff around under it.
531 - so in the grand style of things - punt. */
532 if ((fb->width < surface_width) ||
533 (fb->height < surface_height)) {
534 DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
535 return -EINVAL;
536 }
537 }
538
539 info = fb->fbdev;
540 fb_helper = info->par;
541
542 crtc_count = 0;
543 /* okay we need to setup new connector sets in the crtcs */
544 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
545 modeset = &fb_helper->crtc_info[crtc_count].mode_set;
546 modeset->fb = fb;
547 conn_count = 0;
548 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
549 if (connector->encoder)
550 if (connector->encoder->crtc == modeset->crtc) {
551 modeset->connectors[conn_count] = connector;
552 conn_count++;
553 if (conn_count > fb_helper->conn_limit)
554 BUG();
555 }
556 }
557
558 for (i = conn_count; i < fb_helper->conn_limit; i++)
559 modeset->connectors[i] = NULL;
560
561 modeset->crtc = crtc;
562 crtc_count++;
563
564 modeset->num_connectors = conn_count;
565 if (modeset->crtc->desired_mode) {
566 if (modeset->mode)
567 drm_mode_destroy(dev, modeset->mode);
568 modeset->mode = drm_mode_duplicate(dev,
569 modeset->crtc->desired_mode);
570 }
571 }
572 fb_helper->crtc_count = crtc_count;
573 fb_helper->fb = fb;
574
575 if (new_fb) {
576 info->var.pixclock = -1;
577 if (register_framebuffer(info) < 0)
578 return -EINVAL;
579 } else {
580 drm_fb_helper_set_par(info);
581 }
582 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
583 info->fix.id);
584
585 /* Switch back to kernel console on panic */
586 /* multi card linked list maybe */
587 if (list_empty(&kernel_fb_helper_list)) {
588 printk(KERN_INFO "registered panic notifier\n");
589 atomic_notifier_chain_register(&panic_notifier_list,
590 &paniced);
591 register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
592 }
593 list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
594 return 0;
595}
596EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
597
598void drm_fb_helper_free(struct drm_fb_helper *helper)
599{
600 list_del(&helper->kernel_fb_list);
601 if (list_empty(&kernel_fb_helper_list)) {
602 printk(KERN_INFO "unregistered panic notifier\n");
603 atomic_notifier_chain_unregister(&panic_notifier_list,
604 &paniced);
605 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
606 }
607 drm_fb_helper_crtc_free(helper);
608}
609EXPORT_SYMBOL(drm_fb_helper_free);
610
611void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch)
612{
613 info->fix.type = FB_TYPE_PACKED_PIXELS;
614 info->fix.visual = FB_VISUAL_TRUECOLOR;
615 info->fix.type_aux = 0;
616 info->fix.xpanstep = 1; /* doing it in hw */
617 info->fix.ypanstep = 1; /* doing it in hw */
618 info->fix.ywrapstep = 0;
619 info->fix.accel = FB_ACCEL_I830;
620 info->fix.type_aux = 0;
621
622 info->fix.line_length = pitch;
623 return;
624}
625EXPORT_SYMBOL(drm_fb_helper_fill_fix);
626
627void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb,
628 uint32_t fb_width, uint32_t fb_height)
629{
630 info->pseudo_palette = fb->pseudo_palette;
631 info->var.xres_virtual = fb->width;
632 info->var.yres_virtual = fb->height;
633 info->var.bits_per_pixel = fb->bits_per_pixel;
634 info->var.xoffset = 0;
635 info->var.yoffset = 0;
636 info->var.activate = FB_ACTIVATE_NOW;
637 info->var.height = -1;
638 info->var.width = -1;
639
640 switch (fb->depth) {
641 case 8:
642 info->var.red.offset = 0;
643 info->var.green.offset = 0;
644 info->var.blue.offset = 0;
645 info->var.red.length = 8; /* 8bit DAC */
646 info->var.green.length = 8;
647 info->var.blue.length = 8;
648 info->var.transp.offset = 0;
649 info->var.transp.length = 0;
650 break;
651 case 15:
652 info->var.red.offset = 10;
653 info->var.green.offset = 5;
654 info->var.blue.offset = 0;
655 info->var.red.length = 5;
656 info->var.green.length = 5;
657 info->var.blue.length = 5;
658 info->var.transp.offset = 15;
659 info->var.transp.length = 1;
660 break;
661 case 16:
662 info->var.red.offset = 11;
663 info->var.green.offset = 5;
664 info->var.blue.offset = 0;
665 info->var.red.length = 5;
666 info->var.green.length = 6;
667 info->var.blue.length = 5;
668 info->var.transp.offset = 0;
669 break;
670 case 24:
671 info->var.red.offset = 16;
672 info->var.green.offset = 8;
673 info->var.blue.offset = 0;
674 info->var.red.length = 8;
675 info->var.green.length = 8;
676 info->var.blue.length = 8;
677 info->var.transp.offset = 0;
678 info->var.transp.length = 0;
679 break;
680 case 32:
681 info->var.red.offset = 16;
682 info->var.green.offset = 8;
683 info->var.blue.offset = 0;
684 info->var.red.length = 8;
685 info->var.green.length = 8;
686 info->var.blue.length = 8;
687 info->var.transp.offset = 24;
688 info->var.transp.length = 8;
689 break;
690 default:
691 break;
692 }
693
694 info->var.xres = fb_width;
695 info->var.yres = fb_height;
696}
697EXPORT_SYMBOL(drm_fb_helper_fill_var);
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 544d889b9b1..c628c367139 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -29,6 +29,7 @@
29#include "drmP.h" 29#include "drmP.h"
30#include "drm.h" 30#include "drm.h"
31#include "drm_crtc_helper.h" 31#include "drm_crtc_helper.h"
32#include "drm_fb_helper.h"
32#include "intel_drv.h" 33#include "intel_drv.h"
33#include "i915_drm.h" 34#include "i915_drm.h"
34#include "i915_drv.h" 35#include "i915_drv.h"
@@ -1347,7 +1348,7 @@ void i915_driver_lastclose(struct drm_device * dev)
1347 drm_i915_private_t *dev_priv = dev->dev_private; 1348 drm_i915_private_t *dev_priv = dev->dev_private;
1348 1349
1349 if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) { 1350 if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) {
1350 intelfb_restore(); 1351 drm_fb_helper_restore();
1351 return; 1352 return;
1352 } 1353 }
1353 1354
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index d6fce213341..5fb7a4f4a42 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3060,8 +3060,6 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
3060{ 3060{
3061 struct intel_crtc *intel_crtc = to_intel_crtc(crtc); 3061 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
3062 3062
3063 if (intel_crtc->mode_set.mode)
3064 drm_mode_destroy(crtc->dev, intel_crtc->mode_set.mode);
3065 drm_crtc_cleanup(crtc); 3063 drm_crtc_cleanup(crtc);
3066 kfree(intel_crtc); 3064 kfree(intel_crtc);
3067} 3065}
@@ -3107,16 +3105,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
3107 intel_crtc->cursor_addr = 0; 3105 intel_crtc->cursor_addr = 0;
3108 intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF; 3106 intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF;
3109 drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); 3107 drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
3110
3111 intel_crtc->mode_set.crtc = &intel_crtc->base;
3112 intel_crtc->mode_set.connectors = (struct drm_connector **)(intel_crtc + 1);
3113 intel_crtc->mode_set.num_connectors = 0;
3114
3115 if (i915_fbpercrtc) {
3116
3117
3118
3119 }
3120} 3108}
3121 3109
3122int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, 3110int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d6f92ea1b55..38910f8f30e 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -96,9 +96,6 @@ struct intel_crtc {
96 uint32_t cursor_addr; 96 uint32_t cursor_addr;
97 u8 lut_r[256], lut_g[256], lut_b[256]; 97 u8 lut_r[256], lut_g[256], lut_b[256];
98 int dpms_mode; 98 int dpms_mode;
99 struct intel_framebuffer *fbdev_fb;
100 /* a mode_set for fbdev users on this crtc */
101 struct drm_mode_set mode_set;
102}; 99};
103 100
104#define to_intel_crtc(x) container_of(x, struct intel_crtc, base) 101#define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 1d30802e773..3041530c367 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -39,339 +39,34 @@
39#include "drmP.h" 39#include "drmP.h"
40#include "drm.h" 40#include "drm.h"
41#include "drm_crtc.h" 41#include "drm_crtc.h"
42#include "drm_fb_helper.h"
42#include "intel_drv.h" 43#include "intel_drv.h"
43#include "i915_drm.h" 44#include "i915_drm.h"
44#include "i915_drv.h" 45#include "i915_drv.h"
45 46
46struct intelfb_par { 47struct intelfb_par {
47 struct drm_device *dev; 48 struct drm_fb_helper helper;
48 struct drm_display_mode *our_mode;
49 struct intel_framebuffer *intel_fb; 49 struct intel_framebuffer *intel_fb;
50 int crtc_count; 50 struct drm_display_mode *our_mode;
51 /* crtc currently bound to this */
52 uint32_t crtc_ids[2];
53}; 51};
54 52
55static 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
109static 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? */
199static 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 CLOCK 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
238static 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
277static 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
309static 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
341static 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
363static struct fb_ops intelfb_ops = { 53static struct fb_ops intelfb_ops = {
364 .owner = THIS_MODULE, 54 .owner = THIS_MODULE,
365 .fb_check_var = intelfb_check_var, 55 .fb_check_var = drm_fb_helper_check_var,
366 .fb_set_par = intelfb_set_par, 56 .fb_set_par = drm_fb_helper_set_par,
367 .fb_setcolreg = intelfb_setcolreg, 57 .fb_setcolreg = drm_fb_helper_setcolreg,
368 .fb_fillrect = cfb_fillrect, 58 .fb_fillrect = cfb_fillrect,
369 .fb_copyarea = cfb_copyarea, 59 .fb_copyarea = cfb_copyarea,
370 .fb_imageblit = cfb_imageblit, 60 .fb_imageblit = cfb_imageblit,
371 .fb_pan_display = intelfb_pan_display, 61 .fb_pan_display = drm_fb_helper_pan_display,
372 .fb_blank = intelfb_blank, 62 .fb_blank = drm_fb_helper_blank,
373}; 63};
374 64
65static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
66 .gamma_set = intel_crtc_fb_gamma_set,
67};
68
69
375/** 70/**
376 * Curretly it is assumed that the old framebuffer is reused. 71 * Curretly it is assumed that the old framebuffer is reused.
377 * 72 *
@@ -412,25 +107,10 @@ int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc)
412} 107}
413EXPORT_SYMBOL(intelfb_resize); 108EXPORT_SYMBOL(intelfb_resize);
414 109
415static struct drm_mode_set kernelfb_mode;
416
417static 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
426static struct notifier_block paniced = {
427 .notifier_call = intelfb_panic,
428};
429
430static int intelfb_create(struct drm_device *dev, uint32_t fb_width, 110static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
431 uint32_t fb_height, uint32_t surface_width, 111 uint32_t fb_height, uint32_t surface_width,
432 uint32_t surface_height, 112 uint32_t surface_height,
433 struct intel_framebuffer **intel_fb_p) 113 struct drm_framebuffer **fb_p)
434{ 114{
435 struct fb_info *info; 115 struct fb_info *info;
436 struct intelfb_par *par; 116 struct intelfb_par *par;
@@ -479,7 +159,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
479 list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list); 159 list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list);
480 160
481 intel_fb = to_intel_framebuffer(fb); 161 intel_fb = to_intel_framebuffer(fb);
482 *intel_fb_p = intel_fb; 162 *fb_p = fb;
483 163
484 info = framebuffer_alloc(sizeof(struct intelfb_par), device); 164 info = framebuffer_alloc(sizeof(struct intelfb_par), device);
485 if (!info) { 165 if (!info) {
@@ -489,21 +169,19 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
489 169
490 par = info->par; 170 par = info->par;
491 171
172 par->helper.funcs = &intel_fb_helper_funcs;
173 par->helper.dev = dev;
174 ret = drm_fb_helper_init_crtc_count(&par->helper, 2,
175 INTELFB_CONN_LIMIT);
176 if (ret)
177 goto out_unref;
178
492 strcpy(info->fix.id, "inteldrmfb"); 179 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 180
502 info->flags = FBINFO_DEFAULT; 181 info->flags = FBINFO_DEFAULT;
503 182
504 info->fbops = &intelfb_ops; 183 info->fbops = &intelfb_ops;
505 184
506 info->fix.line_length = fb->pitch;
507 185
508 /* setup aperture base/size for vesafb takeover */ 186 /* setup aperture base/size for vesafb takeover */
509 info->aperture_base = dev->mode_config.fb_base; 187 info->aperture_base = dev->mode_config.fb_base;
@@ -527,18 +205,8 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
527 205
528// memset(info->screen_base, 0, size); 206// memset(info->screen_base, 0, size);
529 207
530 info->pseudo_palette = fb->pseudo_palette; 208 drm_fb_helper_fill_fix(info, fb->depth);
531 info->var.xres_virtual = fb->width; 209 drm_fb_helper_fill_var(info, fb, fb_width, fb_height);
532 info->var.yres_virtual = fb->height;
533 info->var.bits_per_pixel = fb->bits_per_pixel;
534 info->var.xoffset = 0;
535 info->var.yoffset = 0;
536 info->var.activate = FB_ACTIVATE_NOW;
537 info->var.height = -1;
538 info->var.width = -1;
539
540 info->var.xres = fb_width;
541 info->var.yres = fb_height;
542 210
543 /* FIXME: we really shouldn't expose mmio space at all */ 211 /* FIXME: we really shouldn't expose mmio space at all */
544 info->fix.mmio_start = pci_resource_start(dev->pdev, mmio_bar); 212 info->fix.mmio_start = pci_resource_start(dev->pdev, mmio_bar);
@@ -550,64 +218,9 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
550 info->pixmap.flags = FB_PIXMAP_SYSTEM; 218 info->pixmap.flags = FB_PIXMAP_SYSTEM;
551 info->pixmap.scan_align = 1; 219 info->pixmap.scan_align = 1;
552 220
553 switch(fb->depth) {
554 case 8:
555 info->var.red.offset = 0;
556 info->var.green.offset = 0;
557 info->var.blue.offset = 0;
558 info->var.red.length = 8; /* 8bit DAC */
559 info->var.green.length = 8;
560 info->var.blue.length = 8;
561 info->var.transp.offset = 0;
562 info->var.transp.length = 0;
563 break;
564 case 15:
565 info->var.red.offset = 10;
566 info->var.green.offset = 5;
567 info->var.blue.offset = 0;
568 info->var.red.length = 5;
569 info->var.green.length = 5;
570 info->var.blue.length = 5;
571 info->var.transp.offset = 15;
572 info->var.transp.length = 1;
573 break;
574 case 16:
575 info->var.red.offset = 11;
576 info->var.green.offset = 5;
577 info->var.blue.offset = 0;
578 info->var.red.length = 5;
579 info->var.green.length = 6;
580 info->var.blue.length = 5;
581 info->var.transp.offset = 0;
582 break;
583 case 24:
584 info->var.red.offset = 16;
585 info->var.green.offset = 8;
586 info->var.blue.offset = 0;
587 info->var.red.length = 8;
588 info->var.green.length = 8;
589 info->var.blue.length = 8;
590 info->var.transp.offset = 0;
591 info->var.transp.length = 0;
592 break;
593 case 32:
594 info->var.red.offset = 16;
595 info->var.green.offset = 8;
596 info->var.blue.offset = 0;
597 info->var.red.length = 8;
598 info->var.green.length = 8;
599 info->var.blue.length = 8;
600 info->var.transp.offset = 24;
601 info->var.transp.length = 8;
602 break;
603 default:
604 break;
605 }
606
607 fb->fbdev = info; 221 fb->fbdev = info;
608 222
609 par->intel_fb = intel_fb; 223 par->intel_fb = intel_fb;
610 par->dev = dev;
611 224
612 /* To allow resizeing without swapping buffers */ 225 /* To allow resizeing without swapping buffers */
613 DRM_DEBUG("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width, 226 DRM_DEBUG("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width,
@@ -625,307 +238,12 @@ out:
625 return ret; 238 return ret;
626} 239}
627 240
628static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *crtc)
629{
630 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
631 struct intel_framebuffer *intel_fb;
632 struct drm_framebuffer *fb;
633 struct drm_connector *connector;
634 struct fb_info *info;
635 struct intelfb_par *par;
636 struct drm_mode_set *modeset;
637 unsigned int width, height;
638 int new_fb = 0;
639 int ret, i, conn_count;
640
641 if (!drm_helper_crtc_in_use(crtc))
642 return 0;
643
644 if (!crtc->desired_mode)
645 return 0;
646
647 width = crtc->desired_mode->hdisplay;
648 height = crtc->desired_mode->vdisplay;
649
650 /* is there an fb bound to this crtc already */
651 if (!intel_crtc->mode_set.fb) {
652 ret = intelfb_create(dev, width, height, width, height, &intel_fb);
653 if (ret)
654 return -EINVAL;
655 new_fb = 1;
656 } else {
657 fb = intel_crtc->mode_set.fb;
658 intel_fb = to_intel_framebuffer(fb);
659 if ((intel_fb->base.width < width) || (intel_fb->base.height < height))
660 return -EINVAL;
661 }
662
663 info = intel_fb->base.fbdev;
664 par = info->par;
665
666 modeset = &intel_crtc->mode_set;
667 modeset->fb = &intel_fb->base;
668 conn_count = 0;
669 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
670 if (connector->encoder)
671 if (connector->encoder->crtc == modeset->crtc) {
672 modeset->connectors[conn_count] = connector;
673 conn_count++;
674 if (conn_count > INTELFB_CONN_LIMIT)
675 BUG();
676 }
677 }
678
679 for (i = conn_count; i < INTELFB_CONN_LIMIT; i++)
680 modeset->connectors[i] = NULL;
681
682 par->crtc_ids[0] = crtc->base.id;
683
684 modeset->num_connectors = conn_count;
685 if (modeset->crtc->desired_mode) {
686 if (modeset->mode)
687 drm_mode_destroy(dev, modeset->mode);
688 modeset->mode = drm_mode_duplicate(dev,
689 modeset->crtc->desired_mode);
690 }
691
692 par->crtc_count = 1;
693
694 if (new_fb) {
695 info->var.pixclock = -1;
696 if (register_framebuffer(info) < 0)
697 return -EINVAL;
698 } else
699 intelfb_set_par(info);
700
701 DRM_INFO("fb%d: %s frame buffer device\n", info->node,
702 info->fix.id);
703
704 /* Switch back to kernel console on panic */
705 kernelfb_mode = *modeset;
706 atomic_notifier_chain_register(&panic_notifier_list, &paniced);
707 DRM_DEBUG("registered panic notifier\n");
708
709 return 0;
710}
711
712static int intelfb_multi_fb_probe(struct drm_device *dev)
713{
714
715 struct drm_crtc *crtc;
716 int ret = 0;
717
718 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
719 ret = intelfb_multi_fb_probe_crtc(dev, crtc);
720 if (ret)
721 return ret;
722 }
723 return ret;
724}
725
726static int intelfb_single_fb_probe(struct drm_device *dev)
727{
728 struct drm_crtc *crtc;
729 struct drm_connector *connector;
730 unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
731 unsigned int surface_width = 0, surface_height = 0;
732 int new_fb = 0;
733 int crtc_count = 0;
734 int ret, i, conn_count = 0;
735 struct intel_framebuffer *intel_fb;
736 struct fb_info *info;
737 struct intelfb_par *par;
738 struct drm_mode_set *modeset = NULL;
739
740 DRM_DEBUG("\n");
741
742 /* Get a count of crtcs now in use and new min/maxes width/heights */
743 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
744 if (!drm_helper_crtc_in_use(crtc))
745 continue;
746
747 crtc_count++;
748 if (!crtc->desired_mode)
749 continue;
750
751 /* Smallest mode determines console size... */
752 if (crtc->desired_mode->hdisplay < fb_width)
753 fb_width = crtc->desired_mode->hdisplay;
754
755 if (crtc->desired_mode->vdisplay < fb_height)
756 fb_height = crtc->desired_mode->vdisplay;
757
758 /* ... but largest for memory allocation dimensions */
759 if (crtc->desired_mode->hdisplay > surface_width)
760 surface_width = crtc->desired_mode->hdisplay;
761
762 if (crtc->desired_mode->vdisplay > surface_height)
763 surface_height = crtc->desired_mode->vdisplay;
764 }
765
766 if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
767 /* hmm everyone went away - assume VGA cable just fell out
768 and will come back later. */
769 DRM_DEBUG("no CRTCs available?\n");
770 return 0;
771 }
772
773//fail
774 /* Find the fb for our new config */
775 if (list_empty(&dev->mode_config.fb_kernel_list)) {
776 DRM_DEBUG("creating new fb (console size %dx%d, "
777 "buffer size %dx%d)\n", fb_width, fb_height,
778 surface_width, surface_height);
779 ret = intelfb_create(dev, fb_width, fb_height, surface_width,
780 surface_height, &intel_fb);
781 if (ret)
782 return -EINVAL;
783 new_fb = 1;
784 } else {
785 struct drm_framebuffer *fb;
786
787 fb = list_first_entry(&dev->mode_config.fb_kernel_list,
788 struct drm_framebuffer, filp_head);
789 intel_fb = to_intel_framebuffer(fb);
790
791 /* if someone hotplugs something bigger than we have already
792 * allocated, we are pwned. As really we can't resize an
793 * fbdev that is in the wild currently due to fbdev not really
794 * being designed for the lower layers moving stuff around
795 * under it.
796 * - so in the grand style of things - punt.
797 */
798 if ((fb->width < surface_width) ||
799 (fb->height < surface_height)) {
800 DRM_ERROR("fb not large enough for console\n");
801 return -EINVAL;
802 }
803 }
804// fail
805
806 info = intel_fb->base.fbdev;
807 par = info->par;
808
809 crtc_count = 0;
810 /*
811 * For each CRTC, set up the connector list for the CRTC's mode
812 * set configuration.
813 */
814 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
815 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
816
817 modeset = &intel_crtc->mode_set;
818 modeset->fb = &intel_fb->base;
819 conn_count = 0;
820 list_for_each_entry(connector, &dev->mode_config.connector_list,
821 head) {
822 if (!connector->encoder)
823 continue;
824
825 if(connector->encoder->crtc == modeset->crtc) {
826 modeset->connectors[conn_count++] = connector;
827 if (conn_count > INTELFB_CONN_LIMIT)
828 BUG();
829 }
830 }
831
832 /* Zero out remaining connector pointers */
833 for (i = conn_count; i < INTELFB_CONN_LIMIT; i++)
834 modeset->connectors[i] = NULL;
835
836 par->crtc_ids[crtc_count++] = crtc->base.id;
837
838 modeset->num_connectors = conn_count;
839 if (modeset->crtc->desired_mode) {
840 if (modeset->mode)
841 drm_mode_destroy(dev, modeset->mode);
842 modeset->mode = drm_mode_duplicate(dev,
843 modeset->crtc->desired_mode);
844 }
845 }
846 par->crtc_count = crtc_count;
847
848 if (new_fb) {
849 info->var.pixclock = -1;
850 if (register_framebuffer(info) < 0)
851 return -EINVAL;
852 } else
853 intelfb_set_par(info);
854
855 DRM_INFO("fb%d: %s frame buffer device\n", info->node,
856 info->fix.id);
857
858 /* Switch back to kernel console on panic */
859 kernelfb_mode = *modeset;
860 atomic_notifier_chain_register(&panic_notifier_list, &paniced);
861 DRM_DEBUG("registered panic notifier\n");
862
863 return 0;
864}
865
866/**
867 * intelfb_restore - restore the framebuffer console (kernel) config
868 *
869 * Restore's the kernel's fbcon mode, used for lastclose & panic paths.
870 */
871void intelfb_restore(void)
872{
873 int ret;
874 if ((ret = drm_crtc_helper_set_config(&kernelfb_mode)) != 0) {
875 DRM_ERROR("Failed to restore crtc configuration: %d\n",
876 ret);
877 }
878}
879
880static void intelfb_restore_work_fn(struct work_struct *ignored)
881{
882 intelfb_restore();
883}
884static DECLARE_WORK(intelfb_restore_work, intelfb_restore_work_fn);
885
886static void intelfb_sysrq(int dummy1, struct tty_struct *dummy3)
887{
888 schedule_work(&intelfb_restore_work);
889}
890
891static struct sysrq_key_op sysrq_intelfb_restore_op = {
892 .handler = intelfb_sysrq,
893 .help_msg = "force-fb(V)",
894 .action_msg = "Restore framebuffer console",
895};
896
897int intelfb_probe(struct drm_device *dev) 241int intelfb_probe(struct drm_device *dev)
898{ 242{
899 int ret; 243 int ret;
900 244
901 DRM_DEBUG("\n"); 245 DRM_DEBUG("\n");
902 246 ret = drm_fb_helper_single_fb_probe(dev, intelfb_create);
903 /* something has changed in the lower levels of hell - deal with it
904 here */
905
906 /* two modes : a) 1 fb to rule all crtcs.
907 b) one fb per crtc.
908 two actions 1) new connected device
909 2) device removed.
910 case a/1 : if the fb surface isn't big enough - resize the surface fb.
911 if the fb size isn't big enough - resize fb into surface.
912 if everything big enough configure the new crtc/etc.
913 case a/2 : undo the configuration
914 possibly resize down the fb to fit the new configuration.
915 case b/1 : see if it is on a new crtc - setup a new fb and add it.
916 case b/2 : teardown the new fb.
917 */
918
919 /* mode a first */
920 /* search for an fb */
921 if (i915_fbpercrtc == 1) {
922 ret = intelfb_multi_fb_probe(dev);
923 } else {
924 ret = intelfb_single_fb_probe(dev);
925 }
926
927 register_sysrq_key('v', &sysrq_intelfb_restore_op);
928
929 return ret; 247 return ret;
930} 248}
931EXPORT_SYMBOL(intelfb_probe); 249EXPORT_SYMBOL(intelfb_probe);
@@ -940,13 +258,14 @@ int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
940 info = fb->fbdev; 258 info = fb->fbdev;
941 259
942 if (info) { 260 if (info) {
261 struct intelfb_par *par = info->par;
943 unregister_framebuffer(info); 262 unregister_framebuffer(info);
944 iounmap(info->screen_base); 263 iounmap(info->screen_base);
264 if (info->par)
265 drm_fb_helper_free(&par->helper);
945 framebuffer_release(info); 266 framebuffer_release(info);
946 } 267 }
947 268
948 atomic_notifier_chain_unregister(&panic_notifier_list, &paniced);
949 memset(&kernelfb_mode, 0, sizeof(struct drm_mode_set));
950 return 0; 269 return 0;
951} 270}
952EXPORT_SYMBOL(intelfb_remove); 271EXPORT_SYMBOL(intelfb_remove);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index a8fa1bb84cf..af035605d14 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -158,9 +158,6 @@ static void radeon_crtc_destroy(struct drm_crtc *crtc)
158{ 158{
159 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 159 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
160 160
161 if (radeon_crtc->mode_set.mode) {
162 drm_mode_destroy(crtc->dev, radeon_crtc->mode_set.mode);
163 }
164 drm_crtc_cleanup(crtc); 161 drm_crtc_cleanup(crtc);
165 kfree(radeon_crtc); 162 kfree(radeon_crtc);
166} 163}
@@ -189,9 +186,11 @@ static void radeon_crtc_init(struct drm_device *dev, int index)
189 radeon_crtc->crtc_id = index; 186 radeon_crtc->crtc_id = index;
190 rdev->mode_info.crtcs[index] = radeon_crtc; 187 rdev->mode_info.crtcs[index] = radeon_crtc;
191 188
189#if 0
192 radeon_crtc->mode_set.crtc = &radeon_crtc->base; 190 radeon_crtc->mode_set.crtc = &radeon_crtc->base;
193 radeon_crtc->mode_set.connectors = (struct drm_connector **)(radeon_crtc + 1); 191 radeon_crtc->mode_set.connectors = (struct drm_connector **)(radeon_crtc + 1);
194 radeon_crtc->mode_set.num_connectors = 0; 192 radeon_crtc->mode_set.num_connectors = 0;
193#endif
195 194
196 for (i = 0; i < 256; i++) { 195 for (i = 0; i < 256; i++) {
197 radeon_crtc->lut_r[i] = i << 2; 196 radeon_crtc->lut_r[i] = i << 2;
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index ec383edf5f3..ebb58959f41 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -28,15 +28,7 @@
28 */ 28 */
29 29
30#include <linux/module.h> 30#include <linux/module.h>
31#include <linux/kernel.h>
32#include <linux/errno.h>
33#include <linux/string.h>
34#include <linux/mm.h>
35#include <linux/tty.h>
36#include <linux/slab.h>
37#include <linux/delay.h>
38#include <linux/fb.h> 31#include <linux/fb.h>
39#include <linux/init.h>
40 32
41#include "drmP.h" 33#include "drmP.h"
42#include "drm.h" 34#include "drm.h"
@@ -45,375 +37,86 @@
45#include "radeon_drm.h" 37#include "radeon_drm.h"
46#include "radeon.h" 38#include "radeon.h"
47 39
40#include "drm_fb_helper.h"
41
48struct radeon_fb_device { 42struct radeon_fb_device {
49 struct radeon_device *rdev; 43 struct drm_fb_helper helper;
50 struct drm_display_mode *mode;
51 struct radeon_framebuffer *rfb; 44 struct radeon_framebuffer *rfb;
52 int crtc_count; 45 struct radeon_device *rdev;
53 /* crtc currently bound to this */
54 uint32_t crtc_ids[2];
55}; 46};
56 47
57static int radeonfb_setcolreg(unsigned regno, 48static int radeon_fb_check_var(struct fb_var_screeninfo *var,
58 unsigned red, 49 struct fb_info *info)
59 unsigned green,
60 unsigned blue,
61 unsigned transp,
62 struct fb_info *info)
63{
64 struct radeon_fb_device *rfbdev = info->par;
65 struct drm_device *dev = rfbdev->rdev->ddev;
66 struct drm_crtc *crtc;
67 int i;
68
69 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
70 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
71 struct drm_mode_set *modeset = &radeon_crtc->mode_set;
72 struct drm_framebuffer *fb = modeset->fb;
73
74 for (i = 0; i < rfbdev->crtc_count; i++) {
75 if (crtc->base.id == rfbdev->crtc_ids[i]) {
76 break;
77 }
78 }
79 if (i == rfbdev->crtc_count) {
80 continue;
81 }
82 if (regno > 255) {
83 return 1;
84 }
85 if (fb->depth == 8) {
86 radeon_crtc_fb_gamma_set(crtc, red, green, blue, regno);
87 return 0;
88 }
89
90 if (regno < 16) {
91 switch (fb->depth) {
92 case 15:
93 fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
94 ((green & 0xf800) >> 6) |
95 ((blue & 0xf800) >> 11);
96 break;
97 case 16:
98 fb->pseudo_palette[regno] = (red & 0xf800) |
99 ((green & 0xfc00) >> 5) |
100 ((blue & 0xf800) >> 11);
101 break;
102 case 24:
103 case 32:
104 fb->pseudo_palette[regno] =
105 (((red >> 8) & 0xff) << info->var.red.offset) |
106 (((green >> 8) & 0xff) << info->var.green.offset) |
107 (((blue >> 8) & 0xff) << info->var.blue.offset);
108 break;
109 }
110 }
111 }
112 return 0;
113}
114
115static int radeonfb_check_var(struct fb_var_screeninfo *var,
116 struct fb_info *info)
117{ 50{
118 struct radeon_fb_device *rfbdev = info->par;
119 struct radeon_framebuffer *rfb = rfbdev->rfb;
120 struct drm_framebuffer *fb = &rfb->base;
121 int depth;
122
123 if (var->pixclock == -1 || !var->pixclock) {
124 return -EINVAL;
125 }
126 /* Need to resize the fb object !!! */
127 if (var->xres > fb->width || var->yres > fb->height) {
128 DRM_ERROR("Requested width/height is greater than current fb "
129 "object %dx%d > %dx%d\n", var->xres, var->yres,
130 fb->width, fb->height);
131 DRM_ERROR("Need resizing code.\n");
132 return -EINVAL;
133 }
134
135 switch (var->bits_per_pixel) {
136 case 16:
137 depth = (var->green.length == 6) ? 16 : 15;
138 break;
139 case 32:
140 depth = (var->transp.length > 0) ? 32 : 24;
141 break;
142 default:
143 depth = var->bits_per_pixel;
144 break;
145 }
146
147 switch (depth) {
148 case 8:
149 var->red.offset = 0;
150 var->green.offset = 0;
151 var->blue.offset = 0;
152 var->red.length = 8;
153 var->green.length = 8;
154 var->blue.length = 8;
155 var->transp.length = 0;
156 var->transp.offset = 0;
157 break;
158#ifdef __LITTLE_ENDIAN
159 case 15:
160 var->red.offset = 10;
161 var->green.offset = 5;
162 var->blue.offset = 0;
163 var->red.length = 5;
164 var->green.length = 5;
165 var->blue.length = 5;
166 var->transp.length = 1;
167 var->transp.offset = 15;
168 break;
169 case 16:
170 var->red.offset = 11;
171 var->green.offset = 5;
172 var->blue.offset = 0;
173 var->red.length = 5;
174 var->green.length = 6;
175 var->blue.length = 5;
176 var->transp.length = 0;
177 var->transp.offset = 0;
178 break;
179 case 24:
180 var->red.offset = 16;
181 var->green.offset = 8;
182 var->blue.offset = 0;
183 var->red.length = 8;
184 var->green.length = 8;
185 var->blue.length = 8;
186 var->transp.length = 0;
187 var->transp.offset = 0;
188 break;
189 case 32:
190 var->red.offset = 16;
191 var->green.offset = 8;
192 var->blue.offset = 0;
193 var->red.length = 8;
194 var->green.length = 8;
195 var->blue.length = 8;
196 var->transp.length = 8;
197 var->transp.offset = 24;
198 break;
199#else
200 case 24:
201 var->red.offset = 8;
202 var->green.offset = 16;
203 var->blue.offset = 24;
204 var->red.length = 8;
205 var->green.length = 8;
206 var->blue.length = 8;
207 var->transp.length = 0;
208 var->transp.offset = 0;
209 break;
210 case 32:
211 var->red.offset = 8;
212 var->green.offset = 16;
213 var->blue.offset = 24;
214 var->red.length = 8;
215 var->green.length = 8;
216 var->blue.length = 8;
217 var->transp.length = 8;
218 var->transp.offset = 0;
219 break;
220#endif
221 default:
222 return -EINVAL;
223 }
224 return 0;
225}
226
227/* this will let fbcon do the mode init */
228static int radeonfb_set_par(struct fb_info *info)
229{
230 struct radeon_fb_device *rfbdev = info->par;
231 struct drm_device *dev = rfbdev->rdev->ddev;
232 struct fb_var_screeninfo *var = &info->var;
233 struct drm_crtc *crtc;
234 int ret; 51 int ret;
235 int i; 52 ret = drm_fb_helper_check_var(var, info);
236 53 if (ret)
237 if (var->pixclock != -1) { 54 return ret;
238 DRM_ERROR("PIXEL CLCOK SET\n"); 55
239 return -EINVAL; 56 /* big endian override for radeon endian workaround */
240 } 57#ifdef __BIG_ENDIAN
241 58 {
242 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 59 int depth;
243 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); 60 switch (var->bits_per_pixel) {
244 61 case 16:
245 for (i = 0; i < rfbdev->crtc_count; i++) { 62 depth = (var->green.length == 6) ? 16 : 15;
246 if (crtc->base.id == rfbdev->crtc_ids[i]) { 63 break;
247 break; 64 case 32:
248 } 65 depth = (var->transp.length > 0) ? 32 : 24;
249 } 66 break;
250 if (i == rfbdev->crtc_count) { 67 default:
251 continue; 68 depth = var->bits_per_pixel;
252 } 69 break;
253 if (crtc->fb == radeon_crtc->mode_set.fb) {
254 mutex_lock(&dev->mode_config.mutex);
255 ret = crtc->funcs->set_config(&radeon_crtc->mode_set);
256 mutex_unlock(&dev->mode_config.mutex);
257 if (ret) {
258 return ret;
259 }
260 }
261 }
262 return 0;
263}
264
265static int radeonfb_pan_display(struct fb_var_screeninfo *var,
266 struct fb_info *info)
267{
268 struct radeon_fb_device *rfbdev = info->par;
269 struct drm_device *dev = rfbdev->rdev->ddev;
270 struct drm_mode_set *modeset;
271 struct drm_crtc *crtc;
272 struct radeon_crtc *radeon_crtc;
273 int ret = 0;
274 int i;
275
276 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
277 for (i = 0; i < rfbdev->crtc_count; i++) {
278 if (crtc->base.id == rfbdev->crtc_ids[i]) {
279 break;
280 }
281 }
282
283 if (i == rfbdev->crtc_count) {
284 continue;
285 }
286
287 radeon_crtc = to_radeon_crtc(crtc);
288 modeset = &radeon_crtc->mode_set;
289
290 modeset->x = var->xoffset;
291 modeset->y = var->yoffset;
292
293 if (modeset->num_connectors) {
294 mutex_lock(&dev->mode_config.mutex);
295 ret = crtc->funcs->set_config(modeset);
296 mutex_unlock(&dev->mode_config.mutex);
297 if (!ret) {
298 info->var.xoffset = var->xoffset;
299 info->var.yoffset = var->yoffset;
300 }
301 } 70 }
302 } 71 switch (depth) {
303 return ret; 72 case 8:
304} 73 var->red.offset = 0;
305 74 var->green.offset = 0;
306static void radeonfb_on(struct fb_info *info) 75 var->blue.offset = 0;
307{ 76 var->red.length = 8;
308 struct radeon_fb_device *rfbdev = info->par; 77 var->green.length = 8;
309 struct drm_device *dev = rfbdev->rdev->ddev; 78 var->blue.length = 8;
310 struct drm_crtc *crtc; 79 var->transp.length = 0;
311 struct drm_encoder *encoder; 80 var->transp.offset = 0;
312 int i; 81 break;
313 82 case 24:
314 /* 83 var->red.offset = 8;
315 * For each CRTC in this fb, find all associated encoders 84 var->green.offset = 16;
316 * and turn them off, then turn off the CRTC. 85 var->blue.offset = 24;
317 */ 86 var->red.length = 8;
318 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 87 var->green.length = 8;
319 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; 88 var->blue.length = 8;
320 89 var->transp.length = 0;
321 for (i = 0; i < rfbdev->crtc_count; i++) { 90 var->transp.offset = 0;
322 if (crtc->base.id == rfbdev->crtc_ids[i]) { 91 break;
323 break; 92 case 32:
324 } 93 var->red.offset = 8;
325 } 94 var->green.offset = 16;
326 95 var->blue.offset = 24;
327 mutex_lock(&dev->mode_config.mutex); 96 var->red.length = 8;
328 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); 97 var->green.length = 8;
329 mutex_unlock(&dev->mode_config.mutex); 98 var->blue.length = 8;
330 99 var->transp.length = 8;
331 /* Found a CRTC on this fb, now find encoders */ 100 var->transp.offset = 0;
332 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 101 break;
333 if (encoder->crtc == crtc) { 102 default:
334 struct drm_encoder_helper_funcs *encoder_funcs; 103 return -EINVAL;
335
336 encoder_funcs = encoder->helper_private;
337 mutex_lock(&dev->mode_config.mutex);
338 encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
339 mutex_unlock(&dev->mode_config.mutex);
340 }
341 }
342 }
343}
344
345static void radeonfb_off(struct fb_info *info, int dpms_mode)
346{
347 struct radeon_fb_device *rfbdev = info->par;
348 struct drm_device *dev = rfbdev->rdev->ddev;
349 struct drm_crtc *crtc;
350 struct drm_encoder *encoder;
351 int i;
352
353 /*
354 * For each CRTC in this fb, find all associated encoders
355 * and turn them off, then turn off the CRTC.
356 */
357 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
358 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
359
360 for (i = 0; i < rfbdev->crtc_count; i++) {
361 if (crtc->base.id == rfbdev->crtc_ids[i]) {
362 break;
363 }
364 }
365
366 /* Found a CRTC on this fb, now find encoders */
367 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
368 if (encoder->crtc == crtc) {
369 struct drm_encoder_helper_funcs *encoder_funcs;
370
371 encoder_funcs = encoder->helper_private;
372 mutex_lock(&dev->mode_config.mutex);
373 encoder_funcs->dpms(encoder, dpms_mode);
374 mutex_unlock(&dev->mode_config.mutex);
375 }
376 }
377 if (dpms_mode == DRM_MODE_DPMS_OFF) {
378 mutex_lock(&dev->mode_config.mutex);
379 crtc_funcs->dpms(crtc, dpms_mode);
380 mutex_unlock(&dev->mode_config.mutex);
381 } 104 }
382 } 105 }
383} 106#endif
384
385int radeonfb_blank(int blank, struct fb_info *info)
386{
387 switch (blank) {
388 case FB_BLANK_UNBLANK:
389 radeonfb_on(info);
390 break;
391 case FB_BLANK_NORMAL:
392 radeonfb_off(info, DRM_MODE_DPMS_STANDBY);
393 break;
394 case FB_BLANK_HSYNC_SUSPEND:
395 radeonfb_off(info, DRM_MODE_DPMS_STANDBY);
396 break;
397 case FB_BLANK_VSYNC_SUSPEND:
398 radeonfb_off(info, DRM_MODE_DPMS_SUSPEND);
399 break;
400 case FB_BLANK_POWERDOWN:
401 radeonfb_off(info, DRM_MODE_DPMS_OFF);
402 break;
403 }
404 return 0; 107 return 0;
405} 108}
406 109
407static struct fb_ops radeonfb_ops = { 110static struct fb_ops radeonfb_ops = {
408 .owner = THIS_MODULE, 111 .owner = THIS_MODULE,
409 .fb_check_var = radeonfb_check_var, 112 .fb_check_var = radeon_fb_check_var,
410 .fb_set_par = radeonfb_set_par, 113 .fb_set_par = drm_fb_helper_set_par,
411 .fb_setcolreg = radeonfb_setcolreg, 114 .fb_setcolreg = drm_fb_helper_setcolreg,
412 .fb_fillrect = cfb_fillrect, 115 .fb_fillrect = cfb_fillrect,
413 .fb_copyarea = cfb_copyarea, 116 .fb_copyarea = cfb_copyarea,
414 .fb_imageblit = cfb_imageblit, 117 .fb_imageblit = cfb_imageblit,
415 .fb_pan_display = radeonfb_pan_display, 118 .fb_pan_display = drm_fb_helper_pan_display,
416 .fb_blank = radeonfb_blank, 119 .fb_blank = drm_fb_helper_blank,
417}; 120};
418 121
419/** 122/**
@@ -456,21 +159,6 @@ int radeonfb_resize(struct drm_device *dev, struct drm_crtc *crtc)
456} 159}
457EXPORT_SYMBOL(radeonfb_resize); 160EXPORT_SYMBOL(radeonfb_resize);
458 161
459static struct drm_mode_set panic_mode;
460
461int radeonfb_panic(struct notifier_block *n, unsigned long ununsed,
462 void *panic_str)
463{
464 DRM_ERROR("panic occurred, switching back to text console\n");
465 drm_crtc_helper_set_config(&panic_mode);
466 return 0;
467}
468EXPORT_SYMBOL(radeonfb_panic);
469
470static struct notifier_block paniced = {
471 .notifier_call = radeonfb_panic,
472};
473
474static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled) 162static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled)
475{ 163{
476 int aligned = width; 164 int aligned = width;
@@ -495,11 +183,16 @@ static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bo
495 return aligned; 183 return aligned;
496} 184}
497 185
498int radeonfb_create(struct radeon_device *rdev, 186static struct drm_fb_helper_funcs radeon_fb_helper_funcs = {
187 .gamma_set = radeon_crtc_fb_gamma_set,
188};
189
190int radeonfb_create(struct drm_device *dev,
499 uint32_t fb_width, uint32_t fb_height, 191 uint32_t fb_width, uint32_t fb_height,
500 uint32_t surface_width, uint32_t surface_height, 192 uint32_t surface_width, uint32_t surface_height,
501 struct radeon_framebuffer **rfb_p) 193 struct drm_framebuffer **fb_p)
502{ 194{
195 struct radeon_device *rdev = dev->dev_private;
503 struct fb_info *info; 196 struct fb_info *info;
504 struct radeon_fb_device *rfbdev; 197 struct radeon_fb_device *rfbdev;
505 struct drm_framebuffer *fb = NULL; 198 struct drm_framebuffer *fb = NULL;
@@ -554,8 +247,8 @@ int radeonfb_create(struct radeon_device *rdev,
554 247
555 list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list); 248 list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list);
556 249
250 *fb_p = fb;
557 rfb = to_radeon_framebuffer(fb); 251 rfb = to_radeon_framebuffer(fb);
558 *rfb_p = rfb;
559 rdev->fbdev_rfb = rfb; 252 rdev->fbdev_rfb = rfb;
560 rdev->fbdev_robj = robj; 253 rdev->fbdev_robj = robj;
561 254
@@ -564,7 +257,14 @@ int radeonfb_create(struct radeon_device *rdev,
564 ret = -ENOMEM; 257 ret = -ENOMEM;
565 goto out_unref; 258 goto out_unref;
566 } 259 }
260
567 rfbdev = info->par; 261 rfbdev = info->par;
262 rfbdev->helper.funcs = &radeon_fb_helper_funcs;
263 rfbdev->helper.dev = dev;
264 ret = drm_fb_helper_init_crtc_count(&rfbdev->helper, 2,
265 RADEONFB_CONN_LIMIT);
266 if (ret)
267 goto out_unref;
568 268
569 if (fb_tiled) 269 if (fb_tiled)
570 radeon_object_check_tiling(robj, 0, 0); 270 radeon_object_check_tiling(robj, 0, 0);
@@ -577,33 +277,19 @@ int radeonfb_create(struct radeon_device *rdev,
577 memset_io(fbptr, 0, aligned_size); 277 memset_io(fbptr, 0, aligned_size);
578 278
579 strcpy(info->fix.id, "radeondrmfb"); 279 strcpy(info->fix.id, "radeondrmfb");
580 info->fix.type = FB_TYPE_PACKED_PIXELS; 280
581 info->fix.visual = FB_VISUAL_TRUECOLOR; 281 drm_fb_helper_fill_fix(info, fb->pitch);
582 info->fix.type_aux = 0; 282
583 info->fix.xpanstep = 1; /* doing it in hw */
584 info->fix.ypanstep = 1; /* doing it in hw */
585 info->fix.ywrapstep = 0;
586 info->fix.accel = FB_ACCEL_NONE;
587 info->fix.type_aux = 0;
588 info->flags = FBINFO_DEFAULT; 283 info->flags = FBINFO_DEFAULT;
589 info->fbops = &radeonfb_ops; 284 info->fbops = &radeonfb_ops;
590 info->fix.line_length = fb->pitch; 285
591 tmp = fb_gpuaddr - rdev->mc.vram_location; 286 tmp = fb_gpuaddr - rdev->mc.vram_location;
592 info->fix.smem_start = rdev->mc.aper_base + tmp; 287 info->fix.smem_start = rdev->mc.aper_base + tmp;
593 info->fix.smem_len = size; 288 info->fix.smem_len = size;
594 info->screen_base = fbptr; 289 info->screen_base = fbptr;
595 info->screen_size = size; 290 info->screen_size = size;
596 info->pseudo_palette = fb->pseudo_palette; 291
597 info->var.xres_virtual = fb->width; 292 drm_fb_helper_fill_var(info, fb, fb_width, fb_height);
598 info->var.yres_virtual = fb->height;
599 info->var.bits_per_pixel = fb->bits_per_pixel;
600 info->var.xoffset = 0;
601 info->var.yoffset = 0;
602 info->var.activate = FB_ACTIVATE_NOW;
603 info->var.height = -1;
604 info->var.width = -1;
605 info->var.xres = fb_width;
606 info->var.yres = fb_height;
607 293
608 /* setup aperture base/size for vesafb takeover */ 294 /* setup aperture base/size for vesafb takeover */
609 info->aperture_base = rdev->ddev->mode_config.fb_base; 295 info->aperture_base = rdev->ddev->mode_config.fb_base;
@@ -626,6 +312,9 @@ int radeonfb_create(struct radeon_device *rdev,
626 DRM_INFO("fb depth is %d\n", fb->depth); 312 DRM_INFO("fb depth is %d\n", fb->depth);
627 DRM_INFO(" pitch is %d\n", fb->pitch); 313 DRM_INFO(" pitch is %d\n", fb->pitch);
628 314
315#ifdef __BIG_ENDIAN
316 /* fill var sets defaults for this stuff - override
317 on big endian */
629 switch (fb->depth) { 318 switch (fb->depth) {
630 case 8: 319 case 8:
631 info->var.red.offset = 0; 320 info->var.red.offset = 0;
@@ -637,47 +326,6 @@ int radeonfb_create(struct radeon_device *rdev,
637 info->var.transp.offset = 0; 326 info->var.transp.offset = 0;
638 info->var.transp.length = 0; 327 info->var.transp.length = 0;
639 break; 328 break;
640#ifdef __LITTLE_ENDIAN
641 case 15:
642 info->var.red.offset = 10;
643 info->var.green.offset = 5;
644 info->var.blue.offset = 0;
645 info->var.red.length = 5;
646 info->var.green.length = 5;
647 info->var.blue.length = 5;
648 info->var.transp.offset = 15;
649 info->var.transp.length = 1;
650 break;
651 case 16:
652 info->var.red.offset = 11;
653 info->var.green.offset = 5;
654 info->var.blue.offset = 0;
655 info->var.red.length = 5;
656 info->var.green.length = 6;
657 info->var.blue.length = 5;
658 info->var.transp.offset = 0;
659 break;
660 case 24:
661 info->var.red.offset = 16;
662 info->var.green.offset = 8;
663 info->var.blue.offset = 0;
664 info->var.red.length = 8;
665 info->var.green.length = 8;
666 info->var.blue.length = 8;
667 info->var.transp.offset = 0;
668 info->var.transp.length = 0;
669 break;
670 case 32:
671 info->var.red.offset = 16;
672 info->var.green.offset = 8;
673 info->var.blue.offset = 0;
674 info->var.red.length = 8;
675 info->var.green.length = 8;
676 info->var.blue.length = 8;
677 info->var.transp.offset = 24;
678 info->var.transp.length = 8;
679 break;
680#else
681 case 24: 329 case 24:
682 info->var.red.offset = 8; 330 info->var.red.offset = 8;
683 info->var.green.offset = 16; 331 info->var.green.offset = 16;
@@ -699,9 +347,9 @@ int radeonfb_create(struct radeon_device *rdev,
699 info->var.transp.length = 8; 347 info->var.transp.length = 8;
700 break; 348 break;
701 default: 349 default:
702#endif
703 break; 350 break;
704 } 351 }
352#endif
705 353
706 fb->fbdev = info; 354 fb->fbdev = info;
707 rfbdev->rfb = rfb; 355 rfbdev->rfb = rfb;
@@ -726,145 +374,10 @@ out:
726 return ret; 374 return ret;
727} 375}
728 376
729static int radeonfb_single_fb_probe(struct radeon_device *rdev)
730{
731 struct drm_crtc *crtc;
732 struct drm_connector *connector;
733 unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
734 unsigned int surface_width = 0, surface_height = 0;
735 int new_fb = 0;
736 int crtc_count = 0;
737 int ret, i, conn_count = 0;
738 struct radeon_framebuffer *rfb;
739 struct fb_info *info;
740 struct radeon_fb_device *rfbdev;
741 struct drm_mode_set *modeset = NULL;
742
743 /* first up get a count of crtcs now in use and new min/maxes width/heights */
744 list_for_each_entry(crtc, &rdev->ddev->mode_config.crtc_list, head) {
745 if (drm_helper_crtc_in_use(crtc)) {
746 if (crtc->desired_mode) {
747 if (crtc->desired_mode->hdisplay < fb_width)
748 fb_width = crtc->desired_mode->hdisplay;
749
750 if (crtc->desired_mode->vdisplay < fb_height)
751 fb_height = crtc->desired_mode->vdisplay;
752
753 if (crtc->desired_mode->hdisplay > surface_width)
754 surface_width = crtc->desired_mode->hdisplay;
755
756 if (crtc->desired_mode->vdisplay > surface_height)
757 surface_height = crtc->desired_mode->vdisplay;
758 }
759 crtc_count++;
760 }
761 }
762
763 if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
764 /* hmm everyone went away - assume VGA cable just fell out
765 and will come back later. */
766 return 0;
767 }
768
769 /* do we have an fb already? */
770 if (list_empty(&rdev->ddev->mode_config.fb_kernel_list)) {
771 /* create an fb if we don't have one */
772 ret = radeonfb_create(rdev, fb_width, fb_height, surface_width, surface_height, &rfb);
773 if (ret) {
774 return -EINVAL;
775 }
776 new_fb = 1;
777 } else {
778 struct drm_framebuffer *fb;
779 fb = list_first_entry(&rdev->ddev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head);
780 rfb = to_radeon_framebuffer(fb);
781
782 /* if someone hotplugs something bigger than we have already allocated, we are pwned.
783 As really we can't resize an fbdev that is in the wild currently due to fbdev
784 not really being designed for the lower layers moving stuff around under it.
785 - so in the grand style of things - punt. */
786 if ((fb->width < surface_width) || (fb->height < surface_height)) {
787 DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
788 return -EINVAL;
789 }
790 }
791
792 info = rfb->base.fbdev;
793 rdev->fbdev_info = info;
794 rfbdev = info->par;
795
796 crtc_count = 0;
797 /* okay we need to setup new connector sets in the crtcs */
798 list_for_each_entry(crtc, &rdev->ddev->mode_config.crtc_list, head) {
799 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
800 modeset = &radeon_crtc->mode_set;
801 modeset->fb = &rfb->base;
802 conn_count = 0;
803 list_for_each_entry(connector, &rdev->ddev->mode_config.connector_list, head) {
804 if (connector->encoder)
805 if (connector->encoder->crtc == modeset->crtc) {
806 modeset->connectors[conn_count] = connector;
807 conn_count++;
808 if (conn_count > RADEONFB_CONN_LIMIT)
809 BUG();
810 }
811 }
812
813 for (i = conn_count; i < RADEONFB_CONN_LIMIT; i++)
814 modeset->connectors[i] = NULL;
815
816
817 rfbdev->crtc_ids[crtc_count++] = crtc->base.id;
818
819 modeset->num_connectors = conn_count;
820 if (modeset->crtc->desired_mode) {
821 if (modeset->mode) {
822 drm_mode_destroy(rdev->ddev, modeset->mode);
823 }
824 modeset->mode = drm_mode_duplicate(rdev->ddev,
825 modeset->crtc->desired_mode);
826 }
827 }
828 rfbdev->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 radeonfb_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 panic_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
848int radeonfb_probe(struct drm_device *dev) 377int radeonfb_probe(struct drm_device *dev)
849{ 378{
850 int ret; 379 int ret;
851 380 ret = drm_fb_helper_single_fb_probe(dev, &radeonfb_create);
852 /* something has changed in the lower levels of hell - deal with it
853 here */
854
855 /* two modes : a) 1 fb to rule all crtcs.
856 b) one fb per crtc.
857 two actions 1) new connected device
858 2) device removed.
859 case a/1 : if the fb surface isn't big enough - resize the surface fb.
860 if the fb size isn't big enough - resize fb into surface.
861 if everything big enough configure the new crtc/etc.
862 case a/2 : undo the configuration
863 possibly resize down the fb to fit the new configuration.
864 case b/1 : see if it is on a new crtc - setup a new fb and add it.
865 case b/2 : teardown the new fb.
866 */
867 ret = radeonfb_single_fb_probe(dev->dev_private);
868 return ret; 381 return ret;
869} 382}
870EXPORT_SYMBOL(radeonfb_probe); 383EXPORT_SYMBOL(radeonfb_probe);
@@ -880,16 +393,17 @@ int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
880 } 393 }
881 info = fb->fbdev; 394 info = fb->fbdev;
882 if (info) { 395 if (info) {
396 struct radeon_fb_device *rfbdev = info->par;
883 robj = rfb->obj->driver_private; 397 robj = rfb->obj->driver_private;
884 unregister_framebuffer(info); 398 unregister_framebuffer(info);
885 radeon_object_kunmap(robj); 399 radeon_object_kunmap(robj);
886 radeon_object_unpin(robj); 400 radeon_object_unpin(robj);
401 drm_fb_helper_free(&rfbdev->helper);
887 framebuffer_release(info); 402 framebuffer_release(info);
888 } 403 }
889 404
890 printk(KERN_INFO "unregistered panic notifier\n"); 405 printk(KERN_INFO "unregistered panic notifier\n");
891 atomic_notifier_chain_unregister(&panic_notifier_list, &paniced); 406
892 memset(&panic_mode, 0, sizeof(struct drm_mode_set));
893 return 0; 407 return 0;
894} 408}
895EXPORT_SYMBOL(radeonfb_remove); 409EXPORT_SYMBOL(radeonfb_remove);
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 3b09a1f2d8f..20e9509a713 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -195,8 +195,6 @@ struct radeon_crtc {
195 bool enabled; 195 bool enabled;
196 bool can_tile; 196 bool can_tile;
197 uint32_t crtc_offset; 197 uint32_t crtc_offset;
198 struct radeon_framebuffer *fbdev_fb;
199 struct drm_mode_set mode_set;
200 struct drm_gem_object *cursor_bo; 198 struct drm_gem_object *cursor_bo;
201 uint64_t cursor_addr; 199 uint64_t cursor_addr;
202 int cursor_width; 200 int cursor_width;