Subversion Repositories Kolibri OS

Rev

Rev 1179 | Rev 1246 | 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
 
1221 serge 243
static void setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
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
 
250
	pindex = regno;
251
 
252
	if (fb->bits_per_pixel == 16) {
253
		pindex = regno << 3;
254
 
255
		if (fb->depth == 16 && regno > 63)
256
			return;
257
		if (fb->depth == 15 && regno > 31)
258
			return;
259
 
260
		if (fb->depth == 16) {
261
			u16 r, g, b;
262
			int i;
263
			if (regno < 32) {
264
				for (i = 0; i < 8; i++)
265
					fb_helper->funcs->gamma_set(crtc, red,
266
						green, blue, pindex + i);
267
			}
268
 
269
			fb_helper->funcs->gamma_get(crtc, &r,
270
						    &g, &b,
271
						    pindex >> 1);
272
 
273
			for (i = 0; i < 4; i++)
274
				fb_helper->funcs->gamma_set(crtc, r,
275
							    green, b,
276
							    (pindex >> 1) + i);
277
		}
278
	}
279
 
280
	if (fb->depth != 16)
281
		fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex);
282
 
283
	if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
284
		((u32 *) fb->pseudo_palette)[regno] =
285
			(regno << info->var.red.offset) |
286
			(regno << info->var.green.offset) |
287
			(regno << info->var.blue.offset);
288
	}
289
}
290
 
291
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
292
{
293
	struct drm_fb_helper *fb_helper = info->par;
294
	struct drm_device *dev = fb_helper->dev;
295
	u16 *red, *green, *blue, *transp;
296
	struct drm_crtc *crtc;
297
	int i, rc = 0;
298
	int start;
299
 
300
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
301
		struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
302
		for (i = 0; i < fb_helper->crtc_count; i++) {
303
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
304
				break;
305
		}
306
		if (i == fb_helper->crtc_count)
307
			continue;
308
 
309
		red = cmap->red;
310
		green = cmap->green;
311
		blue = cmap->blue;
312
		transp = cmap->transp;
313
		start = cmap->start;
314
 
315
		for (i = 0; i < cmap->len; i++) {
316
			u16 hred, hgreen, hblue, htransp = 0xffff;
317
 
318
			hred = *red++;
319
			hgreen = *green++;
320
			hblue = *blue++;
321
 
322
			if (transp)
323
				htransp = *transp++;
324
 
325
			setcolreg(crtc, hred, hgreen, hblue, start++, info);
326
		}
327
		crtc_funcs->load_lut(crtc);
328
	}
329
	return rc;
330
}
331
EXPORT_SYMBOL(drm_fb_helper_setcmap);
332
 
1179 serge 333
int drm_fb_helper_setcolreg(unsigned regno,
334
			    unsigned red,
335
			    unsigned green,
336
			    unsigned blue,
337
			    unsigned transp,
338
			    struct fb_info *info)
339
{
340
	struct drm_fb_helper *fb_helper = info->par;
341
	struct drm_device *dev = fb_helper->dev;
342
	struct drm_crtc *crtc;
343
	int i;
344
 
1221 serge 345
	if (regno > 255)
346
		return 1;
347
 
1179 serge 348
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
1221 serge 349
		struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
1179 serge 350
		for (i = 0; i < fb_helper->crtc_count; i++) {
351
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
352
				break;
353
		}
354
		if (i == fb_helper->crtc_count)
355
			continue;
356
 
357
 
1221 serge 358
		setcolreg(crtc, red, green, blue, regno, info);
359
		crtc_funcs->load_lut(crtc);
1179 serge 360
	}
361
	return 0;
362
}
363
EXPORT_SYMBOL(drm_fb_helper_setcolreg);
364
 
365
int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
366
			    struct fb_info *info)
367
{
368
	struct drm_fb_helper *fb_helper = info->par;
369
	struct drm_framebuffer *fb = fb_helper->fb;
370
	int depth;
371
 
372
	if (var->pixclock == -1 || !var->pixclock)
373
		return -EINVAL;
374
 
375
	/* Need to resize the fb object !!! */
376
	if (var->xres > fb->width || var->yres > fb->height) {
377
		DRM_ERROR("Requested width/height is greater than current fb "
378
			   "object %dx%d > %dx%d\n", var->xres, var->yres,
379
			   fb->width, fb->height);
380
		DRM_ERROR("Need resizing code.\n");
381
		return -EINVAL;
382
	}
383
 
384
	switch (var->bits_per_pixel) {
385
	case 16:
386
		depth = (var->green.length == 6) ? 16 : 15;
387
		break;
388
	case 32:
389
		depth = (var->transp.length > 0) ? 32 : 24;
390
		break;
391
	default:
392
		depth = var->bits_per_pixel;
393
		break;
394
	}
395
 
396
	switch (depth) {
397
	case 8:
398
		var->red.offset = 0;
399
		var->green.offset = 0;
400
		var->blue.offset = 0;
401
		var->red.length = 8;
402
		var->green.length = 8;
403
		var->blue.length = 8;
404
		var->transp.length = 0;
405
		var->transp.offset = 0;
406
		break;
407
	case 15:
408
		var->red.offset = 10;
409
		var->green.offset = 5;
410
		var->blue.offset = 0;
411
		var->red.length = 5;
412
		var->green.length = 5;
413
		var->blue.length = 5;
414
		var->transp.length = 1;
415
		var->transp.offset = 15;
416
		break;
417
	case 16:
418
		var->red.offset = 11;
419
		var->green.offset = 5;
420
		var->blue.offset = 0;
421
		var->red.length = 5;
422
		var->green.length = 6;
423
		var->blue.length = 5;
424
		var->transp.length = 0;
425
		var->transp.offset = 0;
426
		break;
427
	case 24:
428
		var->red.offset = 16;
429
		var->green.offset = 8;
430
		var->blue.offset = 0;
431
		var->red.length = 8;
432
		var->green.length = 8;
433
		var->blue.length = 8;
434
		var->transp.length = 0;
435
		var->transp.offset = 0;
436
		break;
437
	case 32:
438
		var->red.offset = 16;
439
		var->green.offset = 8;
440
		var->blue.offset = 0;
441
		var->red.length = 8;
442
		var->green.length = 8;
443
		var->blue.length = 8;
444
		var->transp.length = 8;
445
		var->transp.offset = 24;
446
		break;
447
	default:
448
		return -EINVAL;
449
	}
450
	return 0;
451
}
452
EXPORT_SYMBOL(drm_fb_helper_check_var);
453
 
454
/* this will let fbcon do the mode init */
455
int drm_fb_helper_set_par(struct fb_info *info)
456
{
457
	struct drm_fb_helper *fb_helper = info->par;
458
	struct drm_device *dev = fb_helper->dev;
459
	struct fb_var_screeninfo *var = &info->var;
460
	struct drm_crtc *crtc;
461
	int ret;
462
	int i;
463
 
464
	if (var->pixclock != -1) {
465
		DRM_ERROR("PIXEL CLCOK SET\n");
466
		return -EINVAL;
467
	}
468
 
469
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
470
 
471
		for (i = 0; i < fb_helper->crtc_count; i++) {
472
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
473
				break;
474
		}
475
		if (i == fb_helper->crtc_count)
476
			continue;
477
 
478
		if (crtc->fb == fb_helper->crtc_info[i].mode_set.fb) {
479
			mutex_lock(&dev->mode_config.mutex);
480
			ret = crtc->funcs->set_config(&fb_helper->crtc_info->mode_set);
481
			mutex_unlock(&dev->mode_config.mutex);
482
			if (ret)
483
				return ret;
484
		}
485
	}
486
	return 0;
487
}
488
EXPORT_SYMBOL(drm_fb_helper_set_par);
489
 
490
int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
491
			      struct fb_info *info)
492
{
493
	struct drm_fb_helper *fb_helper = info->par;
494
	struct drm_device *dev = fb_helper->dev;
495
	struct drm_mode_set *modeset;
496
	struct drm_crtc *crtc;
497
	int ret = 0;
498
	int i;
499
 
500
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
501
		for (i = 0; i < fb_helper->crtc_count; i++) {
502
			if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
503
				break;
504
		}
505
 
506
		if (i == fb_helper->crtc_count)
507
			continue;
508
 
509
		modeset = &fb_helper->crtc_info[i].mode_set;
510
 
511
		modeset->x = var->xoffset;
512
		modeset->y = var->yoffset;
513
 
514
		if (modeset->num_connectors) {
515
			mutex_lock(&dev->mode_config.mutex);
516
			ret = crtc->funcs->set_config(modeset);
517
			mutex_unlock(&dev->mode_config.mutex);
518
			if (!ret) {
519
				info->var.xoffset = var->xoffset;
520
				info->var.yoffset = var->yoffset;
521
			}
522
		}
523
	}
524
	return ret;
525
}
526
EXPORT_SYMBOL(drm_fb_helper_pan_display);
527
 
528
int drm_fb_helper_single_fb_probe(struct drm_device *dev,
1221 serge 529
				  int preferred_bpp,
1179 serge 530
				  int (*fb_create)(struct drm_device *dev,
531
						   uint32_t fb_width,
532
						   uint32_t fb_height,
533
						   uint32_t surface_width,
534
						   uint32_t surface_height,
1221 serge 535
						   uint32_t surface_depth,
536
						   uint32_t surface_bpp,
1179 serge 537
						   struct drm_framebuffer **fb_ptr))
538
{
539
	struct drm_crtc *crtc;
540
	struct drm_connector *connector;
541
	unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
542
	unsigned int surface_width = 0, surface_height = 0;
543
	int new_fb = 0;
544
	int crtc_count = 0;
545
	int ret, i, conn_count = 0;
546
	struct fb_info *info;
547
	struct drm_framebuffer *fb;
548
	struct drm_mode_set *modeset = NULL;
549
	struct drm_fb_helper *fb_helper;
1221 serge 550
	uint32_t surface_depth = 24, surface_bpp = 32;
1179 serge 551
 
1221 serge 552
	/* if driver picks 8 or 16 by default use that
553
	   for both depth/bpp */
554
	if (preferred_bpp != surface_bpp) {
555
		surface_depth = surface_bpp = preferred_bpp;
556
	}
1179 serge 557
	/* first up get a count of crtcs now in use and new min/maxes width/heights */
1221 serge 558
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
559
		struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
560
 
561
		struct drm_fb_helper_cmdline_mode *cmdline_mode;
562
 
563
		if (!fb_help_conn)
564
			continue;
565
 
566
		cmdline_mode = &fb_help_conn->cmdline_mode;
567
 
568
		if (cmdline_mode->bpp_specified) {
569
			switch (cmdline_mode->bpp) {
570
			case 8:
571
				surface_depth = surface_bpp = 8;
572
				break;
573
			case 15:
574
				surface_depth = 15;
575
				surface_bpp = 16;
576
				break;
577
			case 16:
578
				surface_depth = surface_bpp = 16;
579
				break;
580
			case 24:
581
				surface_depth = surface_bpp = 24;
582
				break;
583
			case 32:
584
				surface_depth = 24;
585
				surface_bpp = 32;
586
				break;
587
			}
588
			break;
589
		}
590
	}
591
 
1179 serge 592
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
593
		if (drm_helper_crtc_in_use(crtc)) {
594
			if (crtc->desired_mode) {
595
				if (crtc->desired_mode->hdisplay < fb_width)
596
					fb_width = crtc->desired_mode->hdisplay;
597
 
598
				if (crtc->desired_mode->vdisplay < fb_height)
599
					fb_height = crtc->desired_mode->vdisplay;
600
 
601
				if (crtc->desired_mode->hdisplay > surface_width)
602
					surface_width = crtc->desired_mode->hdisplay;
603
 
604
				if (crtc->desired_mode->vdisplay > surface_height)
605
					surface_height = crtc->desired_mode->vdisplay;
606
			}
607
			crtc_count++;
608
		}
609
	}
610
 
611
	if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
612
		/* hmm everyone went away - assume VGA cable just fell out
613
		   and will come back later. */
614
		return 0;
615
	}
616
 
617
	/* do we have an fb already? */
618
	if (list_empty(&dev->mode_config.fb_kernel_list)) {
619
		ret = (*fb_create)(dev, fb_width, fb_height, surface_width,
1221 serge 620
				   surface_height, surface_depth, surface_bpp,
621
				   &fb);
1179 serge 622
		if (ret)
623
			return -EINVAL;
624
		new_fb = 1;
625
	} else {
626
		fb = list_first_entry(&dev->mode_config.fb_kernel_list,
627
				      struct drm_framebuffer, filp_head);
628
 
629
		/* if someone hotplugs something bigger than we have already allocated, we are pwned.
630
		   As really we can't resize an fbdev that is in the wild currently due to fbdev
631
		   not really being designed for the lower layers moving stuff around under it.
632
		   - so in the grand style of things - punt. */
633
		if ((fb->width < surface_width) ||
634
		    (fb->height < surface_height)) {
635
			DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
636
			return -EINVAL;
637
		}
638
	}
639
 
640
	info = fb->fbdev;
641
	fb_helper = info->par;
642
 
643
	crtc_count = 0;
644
	/* okay we need to setup new connector sets in the crtcs */
645
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
646
		modeset = &fb_helper->crtc_info[crtc_count].mode_set;
647
		modeset->fb = fb;
648
		conn_count = 0;
649
		list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
650
			if (connector->encoder)
651
				if (connector->encoder->crtc == modeset->crtc) {
652
					modeset->connectors[conn_count] = connector;
653
					conn_count++;
654
					if (conn_count > fb_helper->conn_limit)
655
						BUG();
656
				}
657
		}
658
 
659
		for (i = conn_count; i < fb_helper->conn_limit; i++)
660
			modeset->connectors[i] = NULL;
661
 
662
		modeset->crtc = crtc;
663
		crtc_count++;
664
 
665
		modeset->num_connectors = conn_count;
666
		if (modeset->crtc->desired_mode) {
667
			if (modeset->mode)
668
				drm_mode_destroy(dev, modeset->mode);
669
			modeset->mode = drm_mode_duplicate(dev,
670
							   modeset->crtc->desired_mode);
671
		}
672
	}
673
	fb_helper->crtc_count = crtc_count;
674
	fb_helper->fb = fb;
675
 
676
	if (new_fb) {
677
		info->var.pixclock = -1;
678
//       if (register_framebuffer(info) < 0)
679
//           return -EINVAL;
680
	} else {
681
		drm_fb_helper_set_par(info);
682
	}
683
	printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
684
	       info->fix.id);
685
 
686
	/* Switch back to kernel console on panic */
687
	/* multi card linked list maybe */
688
	list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
689
	return 0;
690
}
691
EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
692
 
693
void drm_fb_helper_free(struct drm_fb_helper *helper)
694
{
695
	list_del(&helper->kernel_fb_list);
696
	drm_fb_helper_crtc_free(helper);
697
}
698
EXPORT_SYMBOL(drm_fb_helper_free);
699
 
1221 serge 700
void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
701
			    uint32_t depth)
1179 serge 702
{
703
	info->fix.type = FB_TYPE_PACKED_PIXELS;
1221 serge 704
	info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
705
		FB_VISUAL_DIRECTCOLOR;
1179 serge 706
	info->fix.type_aux = 0;
707
	info->fix.xpanstep = 1; /* doing it in hw */
708
	info->fix.ypanstep = 1; /* doing it in hw */
709
	info->fix.ywrapstep = 0;
710
	info->fix.accel = FB_ACCEL_NONE;
711
	info->fix.type_aux = 0;
712
 
713
	info->fix.line_length = pitch;
714
	return;
715
}
716
EXPORT_SYMBOL(drm_fb_helper_fill_fix);
717
 
718
void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb,
719
			    uint32_t fb_width, uint32_t fb_height)
720
{
721
	info->pseudo_palette = fb->pseudo_palette;
722
	info->var.xres_virtual = fb->width;
723
	info->var.yres_virtual = fb->height;
724
	info->var.bits_per_pixel = fb->bits_per_pixel;
725
	info->var.xoffset = 0;
726
	info->var.yoffset = 0;
727
	info->var.activate = FB_ACTIVATE_NOW;
728
	info->var.height = -1;
729
	info->var.width = -1;
730
 
731
	switch (fb->depth) {
732
	case 8:
733
		info->var.red.offset = 0;
734
		info->var.green.offset = 0;
735
		info->var.blue.offset = 0;
736
		info->var.red.length = 8; /* 8bit DAC */
737
		info->var.green.length = 8;
738
		info->var.blue.length = 8;
739
		info->var.transp.offset = 0;
740
		info->var.transp.length = 0;
741
		break;
742
	case 15:
743
		info->var.red.offset = 10;
744
		info->var.green.offset = 5;
745
		info->var.blue.offset = 0;
746
		info->var.red.length = 5;
747
		info->var.green.length = 5;
748
		info->var.blue.length = 5;
749
		info->var.transp.offset = 15;
750
		info->var.transp.length = 1;
751
		break;
752
	case 16:
753
		info->var.red.offset = 11;
754
		info->var.green.offset = 5;
755
		info->var.blue.offset = 0;
756
		info->var.red.length = 5;
757
		info->var.green.length = 6;
758
		info->var.blue.length = 5;
759
		info->var.transp.offset = 0;
760
		break;
761
	case 24:
762
		info->var.red.offset = 16;
763
		info->var.green.offset = 8;
764
		info->var.blue.offset = 0;
765
		info->var.red.length = 8;
766
		info->var.green.length = 8;
767
		info->var.blue.length = 8;
768
		info->var.transp.offset = 0;
769
		info->var.transp.length = 0;
770
		break;
771
	case 32:
772
		info->var.red.offset = 16;
773
		info->var.green.offset = 8;
774
		info->var.blue.offset = 0;
775
		info->var.red.length = 8;
776
		info->var.green.length = 8;
777
		info->var.blue.length = 8;
778
		info->var.transp.offset = 24;
779
		info->var.transp.length = 8;
780
		break;
781
	default:
782
		break;
783
	}
784
 
785
	info->var.xres = fb_width;
786
	info->var.yres = fb_height;
787
}
788
EXPORT_SYMBOL(drm_fb_helper_fill_var);