Subversion Repositories Kolibri OS

Rev

Rev 1404 | Rev 1430 | 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
				mutex_lock(&dev->mode_config.mutex);
1321 serge 163
			    crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
1179 serge 164
				mutex_unlock(&dev->mode_config.mutex);
165
			}
166
		}
167
}
168
 
169
int drm_fb_helper_blank(int blank, struct fb_info *info)
170
{
171
	switch (blank) {
1321 serge 172
	/* Display: On; HSync: On, VSync: On */
1179 serge 173
	case FB_BLANK_UNBLANK:
174
		drm_fb_helper_on(info);
175
		break;
1321 serge 176
	/* Display: Off; HSync: On, VSync: On */
1179 serge 177
	case FB_BLANK_NORMAL:
1404 serge 178
		drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
1179 serge 179
		break;
1321 serge 180
	/* Display: Off; HSync: Off, VSync: On */
1179 serge 181
	case FB_BLANK_HSYNC_SUSPEND:
182
		drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
183
		break;
1321 serge 184
	/* Display: Off; HSync: On, VSync: Off */
1179 serge 185
	case FB_BLANK_VSYNC_SUSPEND:
186
		drm_fb_helper_off(info, DRM_MODE_DPMS_SUSPEND);
187
		break;
1321 serge 188
	/* Display: Off; HSync: Off, VSync: Off */
1179 serge 189
	case FB_BLANK_POWERDOWN:
190
		drm_fb_helper_off(info, DRM_MODE_DPMS_OFF);
191
		break;
192
	}
193
	return 0;
194
}
195
EXPORT_SYMBOL(drm_fb_helper_blank);
196
 
197
static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
198
{
199
	int i;
200
 
201
	for (i = 0; i < helper->crtc_count; i++)
202
		kfree(helper->crtc_info[i].mode_set.connectors);
203
	kfree(helper->crtc_info);
204
}
205
 
206
int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count, int max_conn_count)
207
{
208
	struct drm_device *dev = helper->dev;
209
	struct drm_crtc *crtc;
210
	int ret = 0;
211
	int i;
212
 
213
	helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
214
	if (!helper->crtc_info)
215
		return -ENOMEM;
216
 
217
	helper->crtc_count = crtc_count;
218
 
219
	for (i = 0; i < crtc_count; i++) {
220
		helper->crtc_info[i].mode_set.connectors =
221
			kcalloc(max_conn_count,
222
				sizeof(struct drm_connector *),
223
				GFP_KERNEL);
224
 
225
		if (!helper->crtc_info[i].mode_set.connectors) {
226
			ret = -ENOMEM;
227
			goto out_free;
228
		}
229
		helper->crtc_info[i].mode_set.num_connectors = 0;
230
	}
231
 
232
	i = 0;
233
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
234
		helper->crtc_info[i].crtc_id = crtc->base.id;
235
		helper->crtc_info[i].mode_set.crtc = crtc;
236
		i++;
237
	}
238
	helper->conn_limit = max_conn_count;
239
	return 0;
240
out_free:
241
	drm_fb_helper_crtc_free(helper);
242
	return -ENOMEM;
243
}
244
EXPORT_SYMBOL(drm_fb_helper_init_crtc_count);
245
 
1246 serge 246
static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
1221 serge 247
		     u16 blue, u16 regno, struct fb_info *info)
248
{
249
	struct drm_fb_helper *fb_helper = info->par;
250
	struct drm_framebuffer *fb = fb_helper->fb;
251
	int pindex;
252
 
1246 serge 253
	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
254
		u32 *palette;
255
		u32 value;
256
		/* place color in psuedopalette */
257
		if (regno > 16)
258
			return -EINVAL;
259
		palette = (u32 *)info->pseudo_palette;
260
		red >>= (16 - info->var.red.length);
261
		green >>= (16 - info->var.green.length);
262
		blue >>= (16 - info->var.blue.length);
263
		value = (red << info->var.red.offset) |
264
			(green << info->var.green.offset) |
265
			(blue << info->var.blue.offset);
266
		palette[regno] = value;
267
		return 0;
268
	}
269
 
1221 serge 270
	pindex = regno;
271
 
272
	if (fb->bits_per_pixel == 16) {
273
		pindex = regno << 3;
274
 
275
		if (fb->depth == 16 && regno > 63)
1246 serge 276
			return -EINVAL;
1221 serge 277
		if (fb->depth == 15 && regno > 31)
1246 serge 278
			return -EINVAL;
1221 serge 279
 
280
		if (fb->depth == 16) {
281
			u16 r, g, b;
282
			int i;
283
			if (regno < 32) {
284
				for (i = 0; i < 8; i++)
285
					fb_helper->funcs->gamma_set(crtc, red,
286
						green, blue, pindex + i);
287
			}
288
 
289
			fb_helper->funcs->gamma_get(crtc, &r,
290
						    &g, &b,
291
						    pindex >> 1);
292
 
293
			for (i = 0; i < 4; i++)
294
				fb_helper->funcs->gamma_set(crtc, r,
295
							    green, b,
296
							    (pindex >> 1) + i);
297
		}
298
	}
299
 
300
	if (fb->depth != 16)
301
		fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex);
1246 serge 302
	return 0;
1221 serge 303
}
304
 
305
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
306
{
307
	struct drm_fb_helper *fb_helper = info->par;
308
	struct drm_device *dev = fb_helper->dev;
309
	u16 *red, *green, *blue, *transp;
310
	struct drm_crtc *crtc;
311
	int i, rc = 0;
312
	int start;
313
 
314
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
315
		struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
316
		for (i = 0; i < fb_helper->crtc_count; i++) {
317
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
318
				break;
319
		}
320
		if (i == fb_helper->crtc_count)
321
			continue;
322
 
323
		red = cmap->red;
324
		green = cmap->green;
325
		blue = cmap->blue;
326
		transp = cmap->transp;
327
		start = cmap->start;
328
 
329
		for (i = 0; i < cmap->len; i++) {
330
			u16 hred, hgreen, hblue, htransp = 0xffff;
331
 
332
			hred = *red++;
333
			hgreen = *green++;
334
			hblue = *blue++;
335
 
336
			if (transp)
337
				htransp = *transp++;
338
 
1246 serge 339
			rc = setcolreg(crtc, hred, hgreen, hblue, start++, info);
340
			if (rc)
341
				return rc;
1221 serge 342
		}
343
		crtc_funcs->load_lut(crtc);
344
	}
345
	return rc;
346
}
347
EXPORT_SYMBOL(drm_fb_helper_setcmap);
348
 
1179 serge 349
int drm_fb_helper_setcolreg(unsigned regno,
350
			    unsigned red,
351
			    unsigned green,
352
			    unsigned blue,
353
			    unsigned transp,
354
			    struct fb_info *info)
355
{
356
	struct drm_fb_helper *fb_helper = info->par;
357
	struct drm_device *dev = fb_helper->dev;
358
	struct drm_crtc *crtc;
359
	int i;
1246 serge 360
	int ret;
1179 serge 361
 
1221 serge 362
	if (regno > 255)
363
		return 1;
364
 
1179 serge 365
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
1221 serge 366
		struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
1179 serge 367
		for (i = 0; i < fb_helper->crtc_count; i++) {
368
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
369
				break;
370
		}
371
		if (i == fb_helper->crtc_count)
372
			continue;
373
 
1246 serge 374
		ret = setcolreg(crtc, red, green, blue, regno, info);
375
		if (ret)
376
			return ret;
1179 serge 377
 
1221 serge 378
		crtc_funcs->load_lut(crtc);
1179 serge 379
	}
380
	return 0;
381
}
382
EXPORT_SYMBOL(drm_fb_helper_setcolreg);
383
 
384
int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
385
			    struct fb_info *info)
386
{
387
	struct drm_fb_helper *fb_helper = info->par;
388
	struct drm_framebuffer *fb = fb_helper->fb;
389
	int depth;
390
 
1313 serge 391
	if (var->pixclock != 0)
1179 serge 392
		return -EINVAL;
393
 
394
	/* Need to resize the fb object !!! */
1404 serge 395
	if (var->bits_per_pixel > fb->bits_per_pixel || var->xres > fb->width || var->yres > fb->height) {
396
		DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb "
397
			  "object %dx%d-%d > %dx%d-%d\n", var->xres, var->yres, var->bits_per_pixel,
398
			  fb->width, fb->height, fb->bits_per_pixel);
1179 serge 399
		return -EINVAL;
400
	}
401
 
402
	switch (var->bits_per_pixel) {
403
	case 16:
404
		depth = (var->green.length == 6) ? 16 : 15;
405
		break;
406
	case 32:
407
		depth = (var->transp.length > 0) ? 32 : 24;
408
		break;
409
	default:
410
		depth = var->bits_per_pixel;
411
		break;
412
	}
413
 
414
	switch (depth) {
415
	case 8:
416
		var->red.offset = 0;
417
		var->green.offset = 0;
418
		var->blue.offset = 0;
419
		var->red.length = 8;
420
		var->green.length = 8;
421
		var->blue.length = 8;
422
		var->transp.length = 0;
423
		var->transp.offset = 0;
424
		break;
425
	case 15:
426
		var->red.offset = 10;
427
		var->green.offset = 5;
428
		var->blue.offset = 0;
429
		var->red.length = 5;
430
		var->green.length = 5;
431
		var->blue.length = 5;
432
		var->transp.length = 1;
433
		var->transp.offset = 15;
434
		break;
435
	case 16:
436
		var->red.offset = 11;
437
		var->green.offset = 5;
438
		var->blue.offset = 0;
439
		var->red.length = 5;
440
		var->green.length = 6;
441
		var->blue.length = 5;
442
		var->transp.length = 0;
443
		var->transp.offset = 0;
444
		break;
445
	case 24:
446
		var->red.offset = 16;
447
		var->green.offset = 8;
448
		var->blue.offset = 0;
449
		var->red.length = 8;
450
		var->green.length = 8;
451
		var->blue.length = 8;
452
		var->transp.length = 0;
453
		var->transp.offset = 0;
454
		break;
455
	case 32:
456
		var->red.offset = 16;
457
		var->green.offset = 8;
458
		var->blue.offset = 0;
459
		var->red.length = 8;
460
		var->green.length = 8;
461
		var->blue.length = 8;
462
		var->transp.length = 8;
463
		var->transp.offset = 24;
464
		break;
465
	default:
466
		return -EINVAL;
467
	}
468
	return 0;
469
}
470
EXPORT_SYMBOL(drm_fb_helper_check_var);
471
 
472
/* this will let fbcon do the mode init */
473
int drm_fb_helper_set_par(struct fb_info *info)
474
{
475
	struct drm_fb_helper *fb_helper = info->par;
476
	struct drm_device *dev = fb_helper->dev;
477
	struct fb_var_screeninfo *var = &info->var;
478
	struct drm_crtc *crtc;
479
	int ret;
480
	int i;
481
 
1313 serge 482
	if (var->pixclock != 0) {
1179 serge 483
		DRM_ERROR("PIXEL CLCOK SET\n");
484
		return -EINVAL;
485
	}
486
 
487
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
488
 
489
		for (i = 0; i < fb_helper->crtc_count; i++) {
490
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
491
				break;
492
		}
493
		if (i == fb_helper->crtc_count)
494
			continue;
495
 
496
		if (crtc->fb == fb_helper->crtc_info[i].mode_set.fb) {
497
			mutex_lock(&dev->mode_config.mutex);
1268 serge 498
			ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set);
1179 serge 499
			mutex_unlock(&dev->mode_config.mutex);
500
			if (ret)
501
				return ret;
502
		}
503
	}
504
	return 0;
505
}
506
EXPORT_SYMBOL(drm_fb_helper_set_par);
507
 
508
int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
509
			      struct fb_info *info)
510
{
511
	struct drm_fb_helper *fb_helper = info->par;
512
	struct drm_device *dev = fb_helper->dev;
513
	struct drm_mode_set *modeset;
514
	struct drm_crtc *crtc;
515
	int ret = 0;
516
	int i;
517
 
518
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
519
		for (i = 0; i < fb_helper->crtc_count; i++) {
520
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
521
				break;
522
		}
523
 
524
		if (i == fb_helper->crtc_count)
525
			continue;
526
 
527
		modeset = &fb_helper->crtc_info[i].mode_set;
528
 
529
		modeset->x = var->xoffset;
530
		modeset->y = var->yoffset;
531
 
532
		if (modeset->num_connectors) {
533
			mutex_lock(&dev->mode_config.mutex);
534
			ret = crtc->funcs->set_config(modeset);
535
			mutex_unlock(&dev->mode_config.mutex);
536
			if (!ret) {
537
				info->var.xoffset = var->xoffset;
538
				info->var.yoffset = var->yoffset;
539
			}
540
		}
541
	}
542
	return ret;
543
}
544
EXPORT_SYMBOL(drm_fb_helper_pan_display);
545
 
546
int drm_fb_helper_single_fb_probe(struct drm_device *dev,
1221 serge 547
				  int preferred_bpp,
1179 serge 548
				  int (*fb_create)(struct drm_device *dev,
549
						   uint32_t fb_width,
550
						   uint32_t fb_height,
551
						   uint32_t surface_width,
552
						   uint32_t surface_height,
1221 serge 553
						   uint32_t surface_depth,
554
						   uint32_t surface_bpp,
1179 serge 555
						   struct drm_framebuffer **fb_ptr))
556
{
557
	struct drm_crtc *crtc;
558
	struct drm_connector *connector;
559
	unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
560
	unsigned int surface_width = 0, surface_height = 0;
561
	int new_fb = 0;
562
	int crtc_count = 0;
563
	int ret, i, conn_count = 0;
564
	struct fb_info *info;
565
	struct drm_framebuffer *fb;
566
	struct drm_mode_set *modeset = NULL;
567
	struct drm_fb_helper *fb_helper;
1221 serge 568
	uint32_t surface_depth = 24, surface_bpp = 32;
1179 serge 569
 
1221 serge 570
	/* if driver picks 8 or 16 by default use that
571
	   for both depth/bpp */
572
	if (preferred_bpp != surface_bpp) {
573
		surface_depth = surface_bpp = preferred_bpp;
574
	}
1179 serge 575
	/* first up get a count of crtcs now in use and new min/maxes width/heights */
1221 serge 576
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
577
		struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
578
 
579
		struct drm_fb_helper_cmdline_mode *cmdline_mode;
580
 
581
		if (!fb_help_conn)
582
			continue;
583
 
584
		cmdline_mode = &fb_help_conn->cmdline_mode;
585
 
586
		if (cmdline_mode->bpp_specified) {
587
			switch (cmdline_mode->bpp) {
588
			case 8:
589
				surface_depth = surface_bpp = 8;
590
				break;
591
			case 15:
592
				surface_depth = 15;
593
				surface_bpp = 16;
594
				break;
595
			case 16:
596
				surface_depth = surface_bpp = 16;
597
				break;
598
			case 24:
599
				surface_depth = surface_bpp = 24;
600
				break;
601
			case 32:
602
				surface_depth = 24;
603
				surface_bpp = 32;
604
				break;
605
			}
606
			break;
607
		}
608
	}
609
 
1179 serge 610
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
611
		if (drm_helper_crtc_in_use(crtc)) {
612
			if (crtc->desired_mode) {
613
				if (crtc->desired_mode->hdisplay < fb_width)
614
					fb_width = crtc->desired_mode->hdisplay;
615
 
616
				if (crtc->desired_mode->vdisplay < fb_height)
617
					fb_height = crtc->desired_mode->vdisplay;
618
 
619
				if (crtc->desired_mode->hdisplay > surface_width)
620
					surface_width = crtc->desired_mode->hdisplay;
621
 
622
				if (crtc->desired_mode->vdisplay > surface_height)
623
					surface_height = crtc->desired_mode->vdisplay;
624
			}
625
			crtc_count++;
626
		}
627
	}
628
 
629
	if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
630
		/* hmm everyone went away - assume VGA cable just fell out
631
		   and will come back later. */
632
		return 0;
633
	}
634
 
635
	/* do we have an fb already? */
636
	if (list_empty(&dev->mode_config.fb_kernel_list)) {
637
		ret = (*fb_create)(dev, fb_width, fb_height, surface_width,
1221 serge 638
				   surface_height, surface_depth, surface_bpp,
639
				   &fb);
1179 serge 640
		if (ret)
641
			return -EINVAL;
642
		new_fb = 1;
643
	} else {
644
		fb = list_first_entry(&dev->mode_config.fb_kernel_list,
645
				      struct drm_framebuffer, filp_head);
646
 
647
		/* if someone hotplugs something bigger than we have already allocated, we are pwned.
648
		   As really we can't resize an fbdev that is in the wild currently due to fbdev
649
		   not really being designed for the lower layers moving stuff around under it.
650
		   - so in the grand style of things - punt. */
651
		if ((fb->width < surface_width) ||
652
		    (fb->height < surface_height)) {
653
			DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
654
			return -EINVAL;
655
		}
656
	}
657
 
658
	info = fb->fbdev;
659
	fb_helper = info->par;
660
 
661
	crtc_count = 0;
662
	/* okay we need to setup new connector sets in the crtcs */
663
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
664
		modeset = &fb_helper->crtc_info[crtc_count].mode_set;
665
		modeset->fb = fb;
666
		conn_count = 0;
667
		list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
668
			if (connector->encoder)
669
				if (connector->encoder->crtc == modeset->crtc) {
670
					modeset->connectors[conn_count] = connector;
671
					conn_count++;
672
					if (conn_count > fb_helper->conn_limit)
673
						BUG();
674
				}
675
		}
676
 
677
		for (i = conn_count; i < fb_helper->conn_limit; i++)
678
			modeset->connectors[i] = NULL;
679
 
680
		modeset->crtc = crtc;
681
		crtc_count++;
682
 
683
		modeset->num_connectors = conn_count;
684
		if (modeset->crtc->desired_mode) {
685
			if (modeset->mode)
686
				drm_mode_destroy(dev, modeset->mode);
687
			modeset->mode = drm_mode_duplicate(dev,
688
							   modeset->crtc->desired_mode);
689
		}
690
	}
691
	fb_helper->crtc_count = crtc_count;
692
	fb_helper->fb = fb;
693
 
694
	if (new_fb) {
1313 serge 695
		info->var.pixclock = 0;
1179 serge 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);