Subversion Repositories Kolibri OS

Rev

Rev 1246 | Rev 1313 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1179 serge 1
/*
2
 * Copyright (c) 2006-2009 Red Hat Inc.
3
 * Copyright (c) 2006-2008 Intel Corporation
4
 * Copyright (c) 2007 Dave Airlie 
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 
28
 *      Jesse Barnes 
29
 */
30
//#include 
31
#include 
32
#include "drmP.h"
33
#include "drm_crtc.h"
34
#include "drm_fb_helper.h"
35
#include "drm_crtc_helper.h"
36
 
37
//MODULE_AUTHOR("David Airlie, Jesse Barnes");
38
//MODULE_DESCRIPTION("DRM KMS helper");
39
//MODULE_LICENSE("GPL and additional rights");
40
 
41
static LIST_HEAD(kernel_fb_helper_list);
42
 
1221 serge 43
int drm_fb_helper_add_connector(struct drm_connector *connector)
44
{
45
	connector->fb_helper_private = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL);
46
	if (!connector->fb_helper_private)
47
		return -ENOMEM;
48
 
49
	return 0;
50
}
51
EXPORT_SYMBOL(drm_fb_helper_add_connector);
52
 
1179 serge 53
bool drm_fb_helper_force_kernel_mode(void)
54
{
55
	int i = 0;
56
	bool ret, error = false;
57
	struct drm_fb_helper *helper;
58
 
59
	if (list_empty(&kernel_fb_helper_list))
60
		return false;
61
 
62
	list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
63
		for (i = 0; i < helper->crtc_count; i++) {
64
			struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
65
			ret = drm_crtc_helper_set_config(mode_set);
66
			if (ret)
67
				error = true;
68
		}
69
	}
70
	return error;
71
}
72
 
73
/**
74
 * drm_fb_helper_restore - restore the framebuffer console (kernel) config
75
 *
76
 * Restore's the kernel's fbcon mode, used for lastclose & panic paths.
77
 */
78
void drm_fb_helper_restore(void)
79
{
80
	bool ret;
81
	ret = drm_fb_helper_force_kernel_mode();
82
	if (ret == true)
83
		DRM_ERROR("Failed to restore crtc configuration\n");
84
}
85
EXPORT_SYMBOL(drm_fb_helper_restore);
86
 
87
 
88
static void drm_fb_helper_on(struct fb_info *info)
89
{
90
	struct drm_fb_helper *fb_helper = info->par;
91
	struct drm_device *dev = fb_helper->dev;
92
	struct drm_crtc *crtc;
93
	struct drm_encoder *encoder;
94
	int i;
95
 
96
	/*
97
	 * For each CRTC in this fb, turn the crtc on then,
98
	 * find all associated encoders and turn them on.
99
	 */
100
	for (i = 0; i < fb_helper->crtc_count; i++) {
101
		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
102
			struct drm_crtc_helper_funcs *crtc_funcs =
103
				crtc->helper_private;
104
 
105
			/* Only mess with CRTCs in this fb */
106
			if (crtc->base.id != fb_helper->crtc_info[i].crtc_id ||
107
			    !crtc->enabled)
108
				continue;
109
 
110
			mutex_lock(&dev->mode_config.mutex);
111
			crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
112
			mutex_unlock(&dev->mode_config.mutex);
113
 
114
			/* Found a CRTC on this fb, now find encoders */
115
			list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
116
				if (encoder->crtc == crtc) {
117
					struct drm_encoder_helper_funcs *encoder_funcs;
118
 
119
					encoder_funcs = encoder->helper_private;
120
					mutex_lock(&dev->mode_config.mutex);
121
					encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
122
					mutex_unlock(&dev->mode_config.mutex);
123
				}
124
			}
125
		}
126
	}
127
}
128
 
129
static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
130
{
131
	struct drm_fb_helper *fb_helper = info->par;
132
	struct drm_device *dev = fb_helper->dev;
133
	struct drm_crtc *crtc;
134
	struct drm_encoder *encoder;
135
	int i;
136
 
137
	/*
138
	 * For each CRTC in this fb, find all associated encoders
139
	 * and turn them off, then turn off the CRTC.
140
	 */
141
	for (i = 0; i < fb_helper->crtc_count; i++) {
142
		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
143
			struct drm_crtc_helper_funcs *crtc_funcs =
144
				crtc->helper_private;
145
 
146
			/* Only mess with CRTCs in this fb */
147
			if (crtc->base.id != fb_helper->crtc_info[i].crtc_id ||
148
			    !crtc->enabled)
149
				continue;
150
 
151
			/* Found a CRTC on this fb, now find encoders */
152
			list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
153
				if (encoder->crtc == crtc) {
154
					struct drm_encoder_helper_funcs *encoder_funcs;
155
 
156
					encoder_funcs = encoder->helper_private;
157
					mutex_lock(&dev->mode_config.mutex);
158
					encoder_funcs->dpms(encoder, dpms_mode);
159
					mutex_unlock(&dev->mode_config.mutex);
160
				}
161
			}
162
			if (dpms_mode == DRM_MODE_DPMS_OFF) {
163
				mutex_lock(&dev->mode_config.mutex);
164
				crtc_funcs->dpms(crtc, dpms_mode);
165
				mutex_unlock(&dev->mode_config.mutex);
166
			}
167
		}
168
	}
169
}
170
 
171
int drm_fb_helper_blank(int blank, struct fb_info *info)
172
{
173
	switch (blank) {
174
	case FB_BLANK_UNBLANK:
175
		drm_fb_helper_on(info);
176
		break;
177
	case FB_BLANK_NORMAL:
178
		drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
179
		break;
180
	case FB_BLANK_HSYNC_SUSPEND:
181
		drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
182
		break;
183
	case FB_BLANK_VSYNC_SUSPEND:
184
		drm_fb_helper_off(info, DRM_MODE_DPMS_SUSPEND);
185
		break;
186
	case FB_BLANK_POWERDOWN:
187
		drm_fb_helper_off(info, DRM_MODE_DPMS_OFF);
188
		break;
189
	}
190
	return 0;
191
}
192
EXPORT_SYMBOL(drm_fb_helper_blank);
193
 
194
static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
195
{
196
	int i;
197
 
198
	for (i = 0; i < helper->crtc_count; i++)
199
		kfree(helper->crtc_info[i].mode_set.connectors);
200
	kfree(helper->crtc_info);
201
}
202
 
203
int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count, int max_conn_count)
204
{
205
	struct drm_device *dev = helper->dev;
206
	struct drm_crtc *crtc;
207
	int ret = 0;
208
	int i;
209
 
210
	helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
211
	if (!helper->crtc_info)
212
		return -ENOMEM;
213
 
214
	helper->crtc_count = crtc_count;
215
 
216
	for (i = 0; i < crtc_count; i++) {
217
		helper->crtc_info[i].mode_set.connectors =
218
			kcalloc(max_conn_count,
219
				sizeof(struct drm_connector *),
220
				GFP_KERNEL);
221
 
222
		if (!helper->crtc_info[i].mode_set.connectors) {
223
			ret = -ENOMEM;
224
			goto out_free;
225
		}
226
		helper->crtc_info[i].mode_set.num_connectors = 0;
227
	}
228
 
229
	i = 0;
230
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
231
		helper->crtc_info[i].crtc_id = crtc->base.id;
232
		helper->crtc_info[i].mode_set.crtc = crtc;
233
		i++;
234
	}
235
	helper->conn_limit = max_conn_count;
236
	return 0;
237
out_free:
238
	drm_fb_helper_crtc_free(helper);
239
	return -ENOMEM;
240
}
241
EXPORT_SYMBOL(drm_fb_helper_init_crtc_count);
242
 
1246 serge 243
static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
1221 serge 244
		     u16 blue, u16 regno, struct fb_info *info)
245
{
246
	struct drm_fb_helper *fb_helper = info->par;
247
	struct drm_framebuffer *fb = fb_helper->fb;
248
	int pindex;
249
 
1246 serge 250
	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
251
		u32 *palette;
252
		u32 value;
253
		/* place color in psuedopalette */
254
		if (regno > 16)
255
			return -EINVAL;
256
		palette = (u32 *)info->pseudo_palette;
257
		red >>= (16 - info->var.red.length);
258
		green >>= (16 - info->var.green.length);
259
		blue >>= (16 - info->var.blue.length);
260
		value = (red << info->var.red.offset) |
261
			(green << info->var.green.offset) |
262
			(blue << info->var.blue.offset);
263
		palette[regno] = value;
264
		return 0;
265
	}
266
 
1221 serge 267
	pindex = regno;
268
 
269
	if (fb->bits_per_pixel == 16) {
270
		pindex = regno << 3;
271
 
272
		if (fb->depth == 16 && regno > 63)
1246 serge 273
			return -EINVAL;
1221 serge 274
		if (fb->depth == 15 && regno > 31)
1246 serge 275
			return -EINVAL;
1221 serge 276
 
277
		if (fb->depth == 16) {
278
			u16 r, g, b;
279
			int i;
280
			if (regno < 32) {
281
				for (i = 0; i < 8; i++)
282
					fb_helper->funcs->gamma_set(crtc, red,
283
						green, blue, pindex + i);
284
			}
285
 
286
			fb_helper->funcs->gamma_get(crtc, &r,
287
						    &g, &b,
288
						    pindex >> 1);
289
 
290
			for (i = 0; i < 4; i++)
291
				fb_helper->funcs->gamma_set(crtc, r,
292
							    green, b,
293
							    (pindex >> 1) + i);
294
		}
295
	}
296
 
297
	if (fb->depth != 16)
298
		fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex);
1246 serge 299
	return 0;
1221 serge 300
}
301
 
302
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
303
{
304
	struct drm_fb_helper *fb_helper = info->par;
305
	struct drm_device *dev = fb_helper->dev;
306
	u16 *red, *green, *blue, *transp;
307
	struct drm_crtc *crtc;
308
	int i, rc = 0;
309
	int start;
310
 
311
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
312
		struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
313
		for (i = 0; i < fb_helper->crtc_count; i++) {
314
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
315
				break;
316
		}
317
		if (i == fb_helper->crtc_count)
318
			continue;
319
 
320
		red = cmap->red;
321
		green = cmap->green;
322
		blue = cmap->blue;
323
		transp = cmap->transp;
324
		start = cmap->start;
325
 
326
		for (i = 0; i < cmap->len; i++) {
327
			u16 hred, hgreen, hblue, htransp = 0xffff;
328
 
329
			hred = *red++;
330
			hgreen = *green++;
331
			hblue = *blue++;
332
 
333
			if (transp)
334
				htransp = *transp++;
335
 
1246 serge 336
			rc = setcolreg(crtc, hred, hgreen, hblue, start++, info);
337
			if (rc)
338
				return rc;
1221 serge 339
		}
340
		crtc_funcs->load_lut(crtc);
341
	}
342
	return rc;
343
}
344
EXPORT_SYMBOL(drm_fb_helper_setcmap);
345
 
1179 serge 346
int drm_fb_helper_setcolreg(unsigned regno,
347
			    unsigned red,
348
			    unsigned green,
349
			    unsigned blue,
350
			    unsigned transp,
351
			    struct fb_info *info)
352
{
353
	struct drm_fb_helper *fb_helper = info->par;
354
	struct drm_device *dev = fb_helper->dev;
355
	struct drm_crtc *crtc;
356
	int i;
1246 serge 357
	int ret;
1179 serge 358
 
1221 serge 359
	if (regno > 255)
360
		return 1;
361
 
1179 serge 362
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
1221 serge 363
		struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
1179 serge 364
		for (i = 0; i < fb_helper->crtc_count; i++) {
365
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
366
				break;
367
		}
368
		if (i == fb_helper->crtc_count)
369
			continue;
370
 
1246 serge 371
		ret = setcolreg(crtc, red, green, blue, regno, info);
372
		if (ret)
373
			return ret;
1179 serge 374
 
1221 serge 375
		crtc_funcs->load_lut(crtc);
1179 serge 376
	}
377
	return 0;
378
}
379
EXPORT_SYMBOL(drm_fb_helper_setcolreg);
380
 
381
int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
382
			    struct fb_info *info)
383
{
384
	struct drm_fb_helper *fb_helper = info->par;
385
	struct drm_framebuffer *fb = fb_helper->fb;
386
	int depth;
387
 
388
	if (var->pixclock == -1 || !var->pixclock)
389
		return -EINVAL;
390
 
391
	/* Need to resize the fb object !!! */
392
	if (var->xres > fb->width || var->yres > fb->height) {
393
		DRM_ERROR("Requested width/height is greater than current fb "
394
			   "object %dx%d > %dx%d\n", var->xres, var->yres,
395
			   fb->width, fb->height);
396
		DRM_ERROR("Need resizing code.\n");
397
		return -EINVAL;
398
	}
399
 
400
	switch (var->bits_per_pixel) {
401
	case 16:
402
		depth = (var->green.length == 6) ? 16 : 15;
403
		break;
404
	case 32:
405
		depth = (var->transp.length > 0) ? 32 : 24;
406
		break;
407
	default:
408
		depth = var->bits_per_pixel;
409
		break;
410
	}
411
 
412
	switch (depth) {
413
	case 8:
414
		var->red.offset = 0;
415
		var->green.offset = 0;
416
		var->blue.offset = 0;
417
		var->red.length = 8;
418
		var->green.length = 8;
419
		var->blue.length = 8;
420
		var->transp.length = 0;
421
		var->transp.offset = 0;
422
		break;
423
	case 15:
424
		var->red.offset = 10;
425
		var->green.offset = 5;
426
		var->blue.offset = 0;
427
		var->red.length = 5;
428
		var->green.length = 5;
429
		var->blue.length = 5;
430
		var->transp.length = 1;
431
		var->transp.offset = 15;
432
		break;
433
	case 16:
434
		var->red.offset = 11;
435
		var->green.offset = 5;
436
		var->blue.offset = 0;
437
		var->red.length = 5;
438
		var->green.length = 6;
439
		var->blue.length = 5;
440
		var->transp.length = 0;
441
		var->transp.offset = 0;
442
		break;
443
	case 24:
444
		var->red.offset = 16;
445
		var->green.offset = 8;
446
		var->blue.offset = 0;
447
		var->red.length = 8;
448
		var->green.length = 8;
449
		var->blue.length = 8;
450
		var->transp.length = 0;
451
		var->transp.offset = 0;
452
		break;
453
	case 32:
454
		var->red.offset = 16;
455
		var->green.offset = 8;
456
		var->blue.offset = 0;
457
		var->red.length = 8;
458
		var->green.length = 8;
459
		var->blue.length = 8;
460
		var->transp.length = 8;
461
		var->transp.offset = 24;
462
		break;
463
	default:
464
		return -EINVAL;
465
	}
466
	return 0;
467
}
468
EXPORT_SYMBOL(drm_fb_helper_check_var);
469
 
470
/* this will let fbcon do the mode init */
471
int drm_fb_helper_set_par(struct fb_info *info)
472
{
473
	struct drm_fb_helper *fb_helper = info->par;
474
	struct drm_device *dev = fb_helper->dev;
475
	struct fb_var_screeninfo *var = &info->var;
476
	struct drm_crtc *crtc;
477
	int ret;
478
	int i;
479
 
480
	if (var->pixclock != -1) {
481
		DRM_ERROR("PIXEL CLCOK SET\n");
482
		return -EINVAL;
483
	}
484
 
485
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
486
 
487
		for (i = 0; i < fb_helper->crtc_count; i++) {
488
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
489
				break;
490
		}
491
		if (i == fb_helper->crtc_count)
492
			continue;
493
 
494
		if (crtc->fb == fb_helper->crtc_info[i].mode_set.fb) {
495
			mutex_lock(&dev->mode_config.mutex);
1268 serge 496
			ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set);
1179 serge 497
			mutex_unlock(&dev->mode_config.mutex);
498
			if (ret)
499
				return ret;
500
		}
501
	}
502
	return 0;
503
}
504
EXPORT_SYMBOL(drm_fb_helper_set_par);
505
 
506
int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
507
			      struct fb_info *info)
508
{
509
	struct drm_fb_helper *fb_helper = info->par;
510
	struct drm_device *dev = fb_helper->dev;
511
	struct drm_mode_set *modeset;
512
	struct drm_crtc *crtc;
513
	int ret = 0;
514
	int i;
515
 
516
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
517
		for (i = 0; i < fb_helper->crtc_count; i++) {
518
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
519
				break;
520
		}
521
 
522
		if (i == fb_helper->crtc_count)
523
			continue;
524
 
525
		modeset = &fb_helper->crtc_info[i].mode_set;
526
 
527
		modeset->x = var->xoffset;
528
		modeset->y = var->yoffset;
529
 
530
		if (modeset->num_connectors) {
531
			mutex_lock(&dev->mode_config.mutex);
532
			ret = crtc->funcs->set_config(modeset);
533
			mutex_unlock(&dev->mode_config.mutex);
534
			if (!ret) {
535
				info->var.xoffset = var->xoffset;
536
				info->var.yoffset = var->yoffset;
537
			}
538
		}
539
	}
540
	return ret;
541
}
542
EXPORT_SYMBOL(drm_fb_helper_pan_display);
543
 
544
int drm_fb_helper_single_fb_probe(struct drm_device *dev,
1221 serge 545
				  int preferred_bpp,
1179 serge 546
				  int (*fb_create)(struct drm_device *dev,
547
						   uint32_t fb_width,
548
						   uint32_t fb_height,
549
						   uint32_t surface_width,
550
						   uint32_t surface_height,
1221 serge 551
						   uint32_t surface_depth,
552
						   uint32_t surface_bpp,
1179 serge 553
						   struct drm_framebuffer **fb_ptr))
554
{
555
	struct drm_crtc *crtc;
556
	struct drm_connector *connector;
557
	unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
558
	unsigned int surface_width = 0, surface_height = 0;
559
	int new_fb = 0;
560
	int crtc_count = 0;
561
	int ret, i, conn_count = 0;
562
	struct fb_info *info;
563
	struct drm_framebuffer *fb;
564
	struct drm_mode_set *modeset = NULL;
565
	struct drm_fb_helper *fb_helper;
1221 serge 566
	uint32_t surface_depth = 24, surface_bpp = 32;
1179 serge 567
 
1221 serge 568
	/* if driver picks 8 or 16 by default use that
569
	   for both depth/bpp */
570
	if (preferred_bpp != surface_bpp) {
571
		surface_depth = surface_bpp = preferred_bpp;
572
	}
1179 serge 573
	/* first up get a count of crtcs now in use and new min/maxes width/heights */
1221 serge 574
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
575
		struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
576
 
577
		struct drm_fb_helper_cmdline_mode *cmdline_mode;
578
 
579
		if (!fb_help_conn)
580
			continue;
581
 
582
		cmdline_mode = &fb_help_conn->cmdline_mode;
583
 
584
		if (cmdline_mode->bpp_specified) {
585
			switch (cmdline_mode->bpp) {
586
			case 8:
587
				surface_depth = surface_bpp = 8;
588
				break;
589
			case 15:
590
				surface_depth = 15;
591
				surface_bpp = 16;
592
				break;
593
			case 16:
594
				surface_depth = surface_bpp = 16;
595
				break;
596
			case 24:
597
				surface_depth = surface_bpp = 24;
598
				break;
599
			case 32:
600
				surface_depth = 24;
601
				surface_bpp = 32;
602
				break;
603
			}
604
			break;
605
		}
606
	}
607
 
1179 serge 608
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
609
		if (drm_helper_crtc_in_use(crtc)) {
610
			if (crtc->desired_mode) {
611
				if (crtc->desired_mode->hdisplay < fb_width)
612
					fb_width = crtc->desired_mode->hdisplay;
613
 
614
				if (crtc->desired_mode->vdisplay < fb_height)
615
					fb_height = crtc->desired_mode->vdisplay;
616
 
617
				if (crtc->desired_mode->hdisplay > surface_width)
618
					surface_width = crtc->desired_mode->hdisplay;
619
 
620
				if (crtc->desired_mode->vdisplay > surface_height)
621
					surface_height = crtc->desired_mode->vdisplay;
622
			}
623
			crtc_count++;
624
		}
625
	}
626
 
627
	if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
628
		/* hmm everyone went away - assume VGA cable just fell out
629
		   and will come back later. */
630
		return 0;
631
	}
632
 
633
	/* do we have an fb already? */
634
	if (list_empty(&dev->mode_config.fb_kernel_list)) {
635
		ret = (*fb_create)(dev, fb_width, fb_height, surface_width,
1221 serge 636
				   surface_height, surface_depth, surface_bpp,
637
				   &fb);
1179 serge 638
		if (ret)
639
			return -EINVAL;
640
		new_fb = 1;
641
	} else {
642
		fb = list_first_entry(&dev->mode_config.fb_kernel_list,
643
				      struct drm_framebuffer, filp_head);
644
 
645
		/* if someone hotplugs something bigger than we have already allocated, we are pwned.
646
		   As really we can't resize an fbdev that is in the wild currently due to fbdev
647
		   not really being designed for the lower layers moving stuff around under it.
648
		   - so in the grand style of things - punt. */
649
		if ((fb->width < surface_width) ||
650
		    (fb->height < surface_height)) {
651
			DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
652
			return -EINVAL;
653
		}
654
	}
655
 
656
	info = fb->fbdev;
657
	fb_helper = info->par;
658
 
659
	crtc_count = 0;
660
	/* okay we need to setup new connector sets in the crtcs */
661
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
662
		modeset = &fb_helper->crtc_info[crtc_count].mode_set;
663
		modeset->fb = fb;
664
		conn_count = 0;
665
		list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
666
			if (connector->encoder)
667
				if (connector->encoder->crtc == modeset->crtc) {
668
					modeset->connectors[conn_count] = connector;
669
					conn_count++;
670
					if (conn_count > fb_helper->conn_limit)
671
						BUG();
672
				}
673
		}
674
 
675
		for (i = conn_count; i < fb_helper->conn_limit; i++)
676
			modeset->connectors[i] = NULL;
677
 
678
		modeset->crtc = crtc;
679
		crtc_count++;
680
 
681
		modeset->num_connectors = conn_count;
682
		if (modeset->crtc->desired_mode) {
683
			if (modeset->mode)
684
				drm_mode_destroy(dev, modeset->mode);
685
			modeset->mode = drm_mode_duplicate(dev,
686
							   modeset->crtc->desired_mode);
687
		}
688
	}
689
	fb_helper->crtc_count = crtc_count;
690
	fb_helper->fb = fb;
691
 
692
	if (new_fb) {
693
		info->var.pixclock = -1;
694
//       if (register_framebuffer(info) < 0)
695
//           return -EINVAL;
696
	} else {
697
		drm_fb_helper_set_par(info);
698
	}
699
	printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
700
	       info->fix.id);
701
 
702
	/* Switch back to kernel console on panic */
703
	/* multi card linked list maybe */
704
	list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
705
	return 0;
706
}
707
EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
708
 
709
void drm_fb_helper_free(struct drm_fb_helper *helper)
710
{
711
	list_del(&helper->kernel_fb_list);
712
	drm_fb_helper_crtc_free(helper);
713
}
714
EXPORT_SYMBOL(drm_fb_helper_free);
715
 
1221 serge 716
void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
717
			    uint32_t depth)
1179 serge 718
{
719
	info->fix.type = FB_TYPE_PACKED_PIXELS;
1221 serge 720
	info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
1246 serge 721
		FB_VISUAL_TRUECOLOR;
1179 serge 722
	info->fix.type_aux = 0;
723
	info->fix.xpanstep = 1; /* doing it in hw */
724
	info->fix.ypanstep = 1; /* doing it in hw */
725
	info->fix.ywrapstep = 0;
726
	info->fix.accel = FB_ACCEL_NONE;
727
	info->fix.type_aux = 0;
728
 
729
	info->fix.line_length = pitch;
730
	return;
731
}
732
EXPORT_SYMBOL(drm_fb_helper_fill_fix);
733
 
734
void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb,
735
			    uint32_t fb_width, uint32_t fb_height)
736
{
737
	info->pseudo_palette = fb->pseudo_palette;
738
	info->var.xres_virtual = fb->width;
739
	info->var.yres_virtual = fb->height;
740
	info->var.bits_per_pixel = fb->bits_per_pixel;
741
	info->var.xoffset = 0;
742
	info->var.yoffset = 0;
743
	info->var.activate = FB_ACTIVATE_NOW;
744
	info->var.height = -1;
745
	info->var.width = -1;
746
 
747
	switch (fb->depth) {
748
	case 8:
749
		info->var.red.offset = 0;
750
		info->var.green.offset = 0;
751
		info->var.blue.offset = 0;
752
		info->var.red.length = 8; /* 8bit DAC */
753
		info->var.green.length = 8;
754
		info->var.blue.length = 8;
755
		info->var.transp.offset = 0;
756
		info->var.transp.length = 0;
757
		break;
758
	case 15:
759
		info->var.red.offset = 10;
760
		info->var.green.offset = 5;
761
		info->var.blue.offset = 0;
762
		info->var.red.length = 5;
763
		info->var.green.length = 5;
764
		info->var.blue.length = 5;
765
		info->var.transp.offset = 15;
766
		info->var.transp.length = 1;
767
		break;
768
	case 16:
769
		info->var.red.offset = 11;
770
		info->var.green.offset = 5;
771
		info->var.blue.offset = 0;
772
		info->var.red.length = 5;
773
		info->var.green.length = 6;
774
		info->var.blue.length = 5;
775
		info->var.transp.offset = 0;
776
		break;
777
	case 24:
778
		info->var.red.offset = 16;
779
		info->var.green.offset = 8;
780
		info->var.blue.offset = 0;
781
		info->var.red.length = 8;
782
		info->var.green.length = 8;
783
		info->var.blue.length = 8;
784
		info->var.transp.offset = 0;
785
		info->var.transp.length = 0;
786
		break;
787
	case 32:
788
		info->var.red.offset = 16;
789
		info->var.green.offset = 8;
790
		info->var.blue.offset = 0;
791
		info->var.red.length = 8;
792
		info->var.green.length = 8;
793
		info->var.blue.length = 8;
794
		info->var.transp.offset = 24;
795
		info->var.transp.length = 8;
796
		break;
797
	default:
798
		break;
799
	}
800
 
801
	info->var.xres = fb_width;
802
	info->var.yres = fb_height;
803
}
804
EXPORT_SYMBOL(drm_fb_helper_fill_var);