Subversion Repositories Kolibri OS

Rev

Rev 1313 | Rev 1404 | 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:
1321 serge 178
		drm_fb_helper_off(info, DRM_MODE_DPMS_ON);
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 !!! */
395
	if (var->xres > fb->width || var->yres > fb->height) {
396
		DRM_ERROR("Requested width/height is greater than current fb "
397
			   "object %dx%d > %dx%d\n", var->xres, var->yres,
398
			   fb->width, fb->height);
399
		DRM_ERROR("Need resizing code.\n");
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) {
1179 serge 484
		DRM_ERROR("PIXEL CLCOK SET\n");
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
//       if (register_framebuffer(info) < 0)
698
//           return -EINVAL;
699
	} else {
700
		drm_fb_helper_set_par(info);
701
	}
702
	printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
703
	       info->fix.id);
704
 
705
	/* Switch back to kernel console on panic */
706
	/* multi card linked list maybe */
707
	list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
708
	return 0;
709
}
710
EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
711
 
712
void drm_fb_helper_free(struct drm_fb_helper *helper)
713
{
714
	list_del(&helper->kernel_fb_list);
715
	drm_fb_helper_crtc_free(helper);
716
}
717
EXPORT_SYMBOL(drm_fb_helper_free);
718
 
1221 serge 719
void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
720
			    uint32_t depth)
1179 serge 721
{
722
	info->fix.type = FB_TYPE_PACKED_PIXELS;
1221 serge 723
	info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
1246 serge 724
		FB_VISUAL_TRUECOLOR;
1179 serge 725
	info->fix.type_aux = 0;
726
	info->fix.xpanstep = 1; /* doing it in hw */
727
	info->fix.ypanstep = 1; /* doing it in hw */
728
	info->fix.ywrapstep = 0;
729
	info->fix.accel = FB_ACCEL_NONE;
730
	info->fix.type_aux = 0;
731
 
732
	info->fix.line_length = pitch;
733
	return;
734
}
735
EXPORT_SYMBOL(drm_fb_helper_fill_fix);
736
 
737
void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb,
738
			    uint32_t fb_width, uint32_t fb_height)
739
{
740
	info->pseudo_palette = fb->pseudo_palette;
741
	info->var.xres_virtual = fb->width;
742
	info->var.yres_virtual = fb->height;
743
	info->var.bits_per_pixel = fb->bits_per_pixel;
744
	info->var.xoffset = 0;
745
	info->var.yoffset = 0;
746
	info->var.activate = FB_ACTIVATE_NOW;
747
	info->var.height = -1;
748
	info->var.width = -1;
749
 
750
	switch (fb->depth) {
751
	case 8:
752
		info->var.red.offset = 0;
753
		info->var.green.offset = 0;
754
		info->var.blue.offset = 0;
755
		info->var.red.length = 8; /* 8bit DAC */
756
		info->var.green.length = 8;
757
		info->var.blue.length = 8;
758
		info->var.transp.offset = 0;
759
		info->var.transp.length = 0;
760
		break;
761
	case 15:
762
		info->var.red.offset = 10;
763
		info->var.green.offset = 5;
764
		info->var.blue.offset = 0;
765
		info->var.red.length = 5;
766
		info->var.green.length = 5;
767
		info->var.blue.length = 5;
768
		info->var.transp.offset = 15;
769
		info->var.transp.length = 1;
770
		break;
771
	case 16:
772
		info->var.red.offset = 11;
773
		info->var.green.offset = 5;
774
		info->var.blue.offset = 0;
775
		info->var.red.length = 5;
776
		info->var.green.length = 6;
777
		info->var.blue.length = 5;
778
		info->var.transp.offset = 0;
779
		break;
780
	case 24:
781
		info->var.red.offset = 16;
782
		info->var.green.offset = 8;
783
		info->var.blue.offset = 0;
784
		info->var.red.length = 8;
785
		info->var.green.length = 8;
786
		info->var.blue.length = 8;
787
		info->var.transp.offset = 0;
788
		info->var.transp.length = 0;
789
		break;
790
	case 32:
791
		info->var.red.offset = 16;
792
		info->var.green.offset = 8;
793
		info->var.blue.offset = 0;
794
		info->var.red.length = 8;
795
		info->var.green.length = 8;
796
		info->var.blue.length = 8;
797
		info->var.transp.offset = 24;
798
		info->var.transp.length = 8;
799
		break;
800
	default:
801
		break;
802
	}
803
 
804
	info->var.xres = fb_width;
805
	info->var.yres = fb_height;
806
}
807
EXPORT_SYMBOL(drm_fb_helper_fill_var);