aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon/radeon_fb.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2009-08-28 01:46:53 -0400
committerDave Airlie <airlied@redhat.com>2009-08-30 19:09:31 -0400
commit785b93ef8c309730c2de84ce9c229e40e2d01480 (patch)
treeea1b26781fc49cef92d439fdaffa41af8c165778 /drivers/gpu/drm/radeon/radeon_fb.c
parent7dc482dfeeeefcfd000d4271c4626937406756d7 (diff)
drm/kms: move driver specific fb common code to helper functions (v2)
Initially I always meant this code to be shared, but things ran away from me before I got to it. This refactors the i915 and radeon kms fbdev interaction layers out into generic helpers + driver specific pieces. It moves all the panic/sysrq enhancements to the core file, and stores a linked list of kernel fbs. This could possibly be improved to only store the fb which has fbcon on it for panics etc. radeon retains some specific codes used for a big endian workaround. changes: fix oops in v1 fix freeing path for crtc_info Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_fb.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c670
1 files changed, 92 insertions, 578 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index ec383edf5f38..ebb58959f418 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);