Subversion Repositories Kolibri OS

Rev

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