Subversion Repositories Kolibri OS

Rev

Rev 2004 | Rev 3192 | 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 
1963 serge 31
#include 
32
#include 
1179 serge 33
#include 
34
#include "drmP.h"
35
#include "drm_crtc.h"
36
#include "drm_fb_helper.h"
37
#include "drm_crtc_helper.h"
38
 
1430 serge 39
MODULE_AUTHOR("David Airlie, Jesse Barnes");
40
MODULE_DESCRIPTION("DRM KMS helper");
41
MODULE_LICENSE("GPL and additional rights");
1179 serge 42
 
43
static LIST_HEAD(kernel_fb_helper_list);
44
 
1963 serge 45
/* simple single crtc case helper function */
46
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
1221 serge 47
{
1963 serge 48
	struct drm_device *dev = fb_helper->dev;
49
	struct drm_connector *connector;
50
	int i;
1221 serge 51
 
1963 serge 52
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
53
		struct drm_fb_helper_connector *fb_helper_connector;
54
 
55
		fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL);
56
		if (!fb_helper_connector)
57
			goto fail;
58
 
59
		fb_helper_connector->connector = connector;
60
		fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector;
61
	}
1221 serge 62
	return 0;
1963 serge 63
fail:
64
	for (i = 0; i < fb_helper->connector_count; i++) {
65
		kfree(fb_helper->connector_info[i]);
66
		fb_helper->connector_info[i] = NULL;
67
	}
68
	fb_helper->connector_count = 0;
69
    return -ENOMEM;
1221 serge 70
}
1963 serge 71
EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
1221 serge 72
 
1963 serge 73
static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper)
1179 serge 74
{
1963 serge 75
	uint16_t *r_base, *g_base, *b_base;
76
	int i;
1179 serge 77
 
1963 serge 78
	r_base = crtc->gamma_store;
79
	g_base = r_base + crtc->gamma_size;
80
	b_base = g_base + crtc->gamma_size;
1179 serge 81
 
1963 serge 82
	for (i = 0; i < crtc->gamma_size; i++)
83
		helper->funcs->gamma_get(crtc, &r_base[i], &g_base[i], &b_base[i], i);
1179 serge 84
}
85
 
1963 serge 86
static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
1179 serge 87
{
1963 serge 88
	uint16_t *r_base, *g_base, *b_base;
89
 
90
	r_base = crtc->gamma_store;
91
	g_base = r_base + crtc->gamma_size;
92
	b_base = g_base + crtc->gamma_size;
93
 
94
	crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
1179 serge 95
}
96
 
97
 
98
static void drm_fb_helper_on(struct fb_info *info)
99
{
100
	struct drm_fb_helper *fb_helper = info->par;
101
	struct drm_device *dev = fb_helper->dev;
102
	struct drm_crtc *crtc;
1963 serge 103
	struct drm_crtc_helper_funcs *crtc_funcs;
104
	struct drm_connector *connector;
1179 serge 105
	struct drm_encoder *encoder;
1963 serge 106
	int i, j;
1179 serge 107
 
108
	/*
109
	 * For each CRTC in this fb, turn the crtc on then,
110
	 * find all associated encoders and turn them on.
111
	 */
1963 serge 112
	mutex_lock(&dev->mode_config.mutex);
1179 serge 113
	for (i = 0; i < fb_helper->crtc_count; i++) {
1963 serge 114
		crtc = fb_helper->crtc_info[i].mode_set.crtc;
115
		crtc_funcs = crtc->helper_private;
1179 serge 116
 
1963 serge 117
		if (!crtc->enabled)
1179 serge 118
				continue;
119
 
120
			crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
121
 
1963 serge 122
		/* Walk the connectors & encoders on this fb turning them on */
123
		for (j = 0; j < fb_helper->connector_count; j++) {
124
			connector = fb_helper->connector_info[j]->connector;
125
			connector->dpms = DRM_MODE_DPMS_ON;
126
			drm_connector_property_set_value(connector,
127
							 dev->mode_config.dpms_property,
128
							 DRM_MODE_DPMS_ON);
129
		}
1179 serge 130
			/* Found a CRTC on this fb, now find encoders */
131
			list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
132
				if (encoder->crtc == crtc) {
133
					struct drm_encoder_helper_funcs *encoder_funcs;
134
 
135
					encoder_funcs = encoder->helper_private;
136
					encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
137
			}
138
		}
139
	}
1963 serge 140
	mutex_unlock(&dev->mode_config.mutex);
1179 serge 141
}
142
 
143
static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
144
{
145
	struct drm_fb_helper *fb_helper = info->par;
146
	struct drm_device *dev = fb_helper->dev;
147
	struct drm_crtc *crtc;
1963 serge 148
	struct drm_crtc_helper_funcs *crtc_funcs;
149
	struct drm_connector *connector;
1179 serge 150
	struct drm_encoder *encoder;
1963 serge 151
	int i, j;
1179 serge 152
 
153
	/*
154
	 * For each CRTC in this fb, find all associated encoders
155
	 * and turn them off, then turn off the CRTC.
156
	 */
1963 serge 157
	mutex_lock(&dev->mode_config.mutex);
1179 serge 158
	for (i = 0; i < fb_helper->crtc_count; i++) {
1963 serge 159
		crtc = fb_helper->crtc_info[i].mode_set.crtc;
160
		crtc_funcs = crtc->helper_private;
1179 serge 161
 
1963 serge 162
		if (!crtc->enabled)
1179 serge 163
				continue;
164
 
1963 serge 165
		/* Walk the connectors on this fb and mark them off */
166
		for (j = 0; j < fb_helper->connector_count; j++) {
167
			connector = fb_helper->connector_info[j]->connector;
168
			connector->dpms = dpms_mode;
169
			drm_connector_property_set_value(connector,
170
							 dev->mode_config.dpms_property,
171
							 dpms_mode);
172
		}
1179 serge 173
			/* Found a CRTC on this fb, now find encoders */
174
			list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
175
				if (encoder->crtc == crtc) {
176
					struct drm_encoder_helper_funcs *encoder_funcs;
177
 
178
					encoder_funcs = encoder->helper_private;
179
					encoder_funcs->dpms(encoder, dpms_mode);
180
				}
181
			}
1321 serge 182
			    crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
1963 serge 183
	}
1179 serge 184
				mutex_unlock(&dev->mode_config.mutex);
185
}
186
 
187
int drm_fb_helper_blank(int blank, struct fb_info *info)
188
{
189
	switch (blank) {
1321 serge 190
	/* Display: On; HSync: On, VSync: On */
1179 serge 191
	case FB_BLANK_UNBLANK:
192
		drm_fb_helper_on(info);
193
		break;
1321 serge 194
	/* Display: Off; HSync: On, VSync: On */
1179 serge 195
	case FB_BLANK_NORMAL:
1404 serge 196
		drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
1179 serge 197
		break;
1321 serge 198
	/* Display: Off; HSync: Off, VSync: On */
1179 serge 199
	case FB_BLANK_HSYNC_SUSPEND:
200
		drm_fb_helper_off(info, DRM_MODE_DPMS_STANDBY);
201
		break;
1321 serge 202
	/* Display: Off; HSync: On, VSync: Off */
1179 serge 203
	case FB_BLANK_VSYNC_SUSPEND:
204
		drm_fb_helper_off(info, DRM_MODE_DPMS_SUSPEND);
205
		break;
1321 serge 206
	/* Display: Off; HSync: Off, VSync: Off */
1179 serge 207
	case FB_BLANK_POWERDOWN:
208
		drm_fb_helper_off(info, DRM_MODE_DPMS_OFF);
209
		break;
210
	}
211
	return 0;
212
}
213
EXPORT_SYMBOL(drm_fb_helper_blank);
214
 
215
static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
216
{
217
	int i;
218
 
1963 serge 219
	for (i = 0; i < helper->connector_count; i++)
220
		kfree(helper->connector_info[i]);
221
	kfree(helper->connector_info);
1179 serge 222
	for (i = 0; i < helper->crtc_count; i++)
223
		kfree(helper->crtc_info[i].mode_set.connectors);
224
	kfree(helper->crtc_info);
225
}
226
 
1963 serge 227
int drm_fb_helper_init(struct drm_device *dev,
228
		       struct drm_fb_helper *fb_helper,
229
		       int crtc_count, int max_conn_count)
1179 serge 230
{
231
	struct drm_crtc *crtc;
232
	int ret = 0;
233
	int i;
234
 
1963 serge 235
	fb_helper->dev = dev;
236
 
237
	INIT_LIST_HEAD(&fb_helper->kernel_fb_list);
238
 
239
	fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
240
	if (!fb_helper->crtc_info)
1179 serge 241
		return -ENOMEM;
242
 
1963 serge 243
	fb_helper->crtc_count = crtc_count;
244
	fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
245
	if (!fb_helper->connector_info) {
246
		kfree(fb_helper->crtc_info);
247
		return -ENOMEM;
248
	}
249
	fb_helper->connector_count = 0;
1179 serge 250
 
251
	for (i = 0; i < crtc_count; i++) {
1963 serge 252
		fb_helper->crtc_info[i].mode_set.connectors =
1179 serge 253
			kcalloc(max_conn_count,
254
				sizeof(struct drm_connector *),
255
				GFP_KERNEL);
256
 
1963 serge 257
		if (!fb_helper->crtc_info[i].mode_set.connectors) {
1179 serge 258
			ret = -ENOMEM;
259
			goto out_free;
260
		}
1963 serge 261
		fb_helper->crtc_info[i].mode_set.num_connectors = 0;
1179 serge 262
	}
263
 
264
	i = 0;
265
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
1963 serge 266
		fb_helper->crtc_info[i].crtc_id = crtc->base.id;
267
		fb_helper->crtc_info[i].mode_set.crtc = crtc;
1179 serge 268
		i++;
269
	}
1963 serge 270
	fb_helper->conn_limit = max_conn_count;
1179 serge 271
	return 0;
272
out_free:
1963 serge 273
	drm_fb_helper_crtc_free(fb_helper);
1179 serge 274
	return -ENOMEM;
275
}
1963 serge 276
EXPORT_SYMBOL(drm_fb_helper_init);
1179 serge 277
 
1246 serge 278
static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
1221 serge 279
		     u16 blue, u16 regno, struct fb_info *info)
280
{
281
	struct drm_fb_helper *fb_helper = info->par;
282
	struct drm_framebuffer *fb = fb_helper->fb;
283
	int pindex;
284
 
1246 serge 285
	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
286
		u32 *palette;
287
		u32 value;
288
		/* place color in psuedopalette */
289
		if (regno > 16)
290
			return -EINVAL;
291
		palette = (u32 *)info->pseudo_palette;
292
		red >>= (16 - info->var.red.length);
293
		green >>= (16 - info->var.green.length);
294
		blue >>= (16 - info->var.blue.length);
295
		value = (red << info->var.red.offset) |
296
			(green << info->var.green.offset) |
297
			(blue << info->var.blue.offset);
1963 serge 298
		if (info->var.transp.length > 0) {
299
			u32 mask = (1 << info->var.transp.length) - 1;
300
			mask <<= info->var.transp.offset;
301
			value |= mask;
302
		}
1246 serge 303
		palette[regno] = value;
304
		return 0;
305
	}
306
 
1221 serge 307
	pindex = regno;
308
 
309
	if (fb->bits_per_pixel == 16) {
310
		pindex = regno << 3;
311
 
312
		if (fb->depth == 16 && regno > 63)
1246 serge 313
			return -EINVAL;
1221 serge 314
		if (fb->depth == 15 && regno > 31)
1246 serge 315
			return -EINVAL;
1221 serge 316
 
317
		if (fb->depth == 16) {
318
			u16 r, g, b;
319
			int i;
320
			if (regno < 32) {
321
				for (i = 0; i < 8; i++)
322
					fb_helper->funcs->gamma_set(crtc, red,
323
						green, blue, pindex + i);
324
			}
325
 
326
			fb_helper->funcs->gamma_get(crtc, &r,
327
						    &g, &b,
328
						    pindex >> 1);
329
 
330
			for (i = 0; i < 4; i++)
331
				fb_helper->funcs->gamma_set(crtc, r,
332
							    green, b,
333
							    (pindex >> 1) + i);
334
		}
335
	}
336
 
337
	if (fb->depth != 16)
338
		fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex);
1246 serge 339
	return 0;
1221 serge 340
}
341
 
342
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
343
{
344
	struct drm_fb_helper *fb_helper = info->par;
1963 serge 345
	struct drm_crtc_helper_funcs *crtc_funcs;
1221 serge 346
	u16 *red, *green, *blue, *transp;
347
	struct drm_crtc *crtc;
1963 serge 348
	int i, j, rc = 0;
1221 serge 349
	int start;
350
 
351
		for (i = 0; i < fb_helper->crtc_count; i++) {
1963 serge 352
		crtc = fb_helper->crtc_info[i].mode_set.crtc;
353
		crtc_funcs = crtc->helper_private;
1221 serge 354
 
355
		red = cmap->red;
356
		green = cmap->green;
357
		blue = cmap->blue;
358
		transp = cmap->transp;
359
		start = cmap->start;
360
 
1963 serge 361
		for (j = 0; j < cmap->len; j++) {
1221 serge 362
			u16 hred, hgreen, hblue, htransp = 0xffff;
363
 
364
			hred = *red++;
365
			hgreen = *green++;
366
			hblue = *blue++;
367
 
368
			if (transp)
369
				htransp = *transp++;
370
 
1246 serge 371
			rc = setcolreg(crtc, hred, hgreen, hblue, start++, info);
372
			if (rc)
373
				return rc;
1221 serge 374
		}
375
		crtc_funcs->load_lut(crtc);
376
	}
377
	return rc;
378
}
379
EXPORT_SYMBOL(drm_fb_helper_setcmap);
380
 
1179 serge 381
int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
382
			    struct fb_info *info)
383
{
384
	struct drm_fb_helper *fb_helper = info->par;
385
	struct drm_framebuffer *fb = fb_helper->fb;
386
	int depth;
387
 
1963 serge 388
	if (var->pixclock != 0 || in_dbg_master())
1179 serge 389
		return -EINVAL;
390
 
391
	/* Need to resize the fb object !!! */
1404 serge 392
	if (var->bits_per_pixel > fb->bits_per_pixel || var->xres > fb->width || var->yres > fb->height) {
393
		DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb "
394
			  "object %dx%d-%d > %dx%d-%d\n", var->xres, var->yres, var->bits_per_pixel,
395
			  fb->width, fb->height, fb->bits_per_pixel);
1179 serge 396
		return -EINVAL;
397
	}
398
 
399
	switch (var->bits_per_pixel) {
400
	case 16:
401
		depth = (var->green.length == 6) ? 16 : 15;
402
		break;
403
	case 32:
404
		depth = (var->transp.length > 0) ? 32 : 24;
405
		break;
406
	default:
407
		depth = var->bits_per_pixel;
408
		break;
409
	}
410
 
411
	switch (depth) {
412
	case 8:
413
		var->red.offset = 0;
414
		var->green.offset = 0;
415
		var->blue.offset = 0;
416
		var->red.length = 8;
417
		var->green.length = 8;
418
		var->blue.length = 8;
419
		var->transp.length = 0;
420
		var->transp.offset = 0;
421
		break;
422
	case 15:
423
		var->red.offset = 10;
424
		var->green.offset = 5;
425
		var->blue.offset = 0;
426
		var->red.length = 5;
427
		var->green.length = 5;
428
		var->blue.length = 5;
429
		var->transp.length = 1;
430
		var->transp.offset = 15;
431
		break;
432
	case 16:
433
		var->red.offset = 11;
434
		var->green.offset = 5;
435
		var->blue.offset = 0;
436
		var->red.length = 5;
437
		var->green.length = 6;
438
		var->blue.length = 5;
439
		var->transp.length = 0;
440
		var->transp.offset = 0;
441
		break;
442
	case 24:
443
		var->red.offset = 16;
444
		var->green.offset = 8;
445
		var->blue.offset = 0;
446
		var->red.length = 8;
447
		var->green.length = 8;
448
		var->blue.length = 8;
449
		var->transp.length = 0;
450
		var->transp.offset = 0;
451
		break;
452
	case 32:
453
		var->red.offset = 16;
454
		var->green.offset = 8;
455
		var->blue.offset = 0;
456
		var->red.length = 8;
457
		var->green.length = 8;
458
		var->blue.length = 8;
459
		var->transp.length = 8;
460
		var->transp.offset = 24;
461
		break;
462
	default:
463
		return -EINVAL;
464
	}
465
	return 0;
466
}
467
EXPORT_SYMBOL(drm_fb_helper_check_var);
468
 
469
/* this will let fbcon do the mode init */
470
int drm_fb_helper_set_par(struct fb_info *info)
471
{
472
	struct drm_fb_helper *fb_helper = info->par;
473
	struct drm_device *dev = fb_helper->dev;
474
	struct fb_var_screeninfo *var = &info->var;
475
	struct drm_crtc *crtc;
476
	int ret;
477
	int i;
478
 
1313 serge 479
	if (var->pixclock != 0) {
1430 serge 480
		DRM_ERROR("PIXEL CLOCK SET\n");
1179 serge 481
		return -EINVAL;
482
	}
483
 
1963 serge 484
	mutex_lock(&dev->mode_config.mutex);
1179 serge 485
		for (i = 0; i < fb_helper->crtc_count; i++) {
1963 serge 486
		crtc = fb_helper->crtc_info[i].mode_set.crtc;
1268 serge 487
			ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set);
1963 serge 488
		if (ret) {
1179 serge 489
			mutex_unlock(&dev->mode_config.mutex);
490
				return ret;
491
		}
492
	}
1963 serge 493
	mutex_unlock(&dev->mode_config.mutex);
494
 
495
	if (fb_helper->delayed_hotplug) {
496
		fb_helper->delayed_hotplug = false;
497
//       drm_fb_helper_hotplug_event(fb_helper);
498
	}
1179 serge 499
	return 0;
500
}
501
EXPORT_SYMBOL(drm_fb_helper_set_par);
502
 
503
int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
504
			      struct fb_info *info)
505
{
506
	struct drm_fb_helper *fb_helper = info->par;
507
	struct drm_device *dev = fb_helper->dev;
508
	struct drm_mode_set *modeset;
509
	struct drm_crtc *crtc;
510
	int ret = 0;
511
	int i;
512
 
1963 serge 513
	mutex_lock(&dev->mode_config.mutex);
1179 serge 514
		for (i = 0; i < fb_helper->crtc_count; i++) {
1963 serge 515
		crtc = fb_helper->crtc_info[i].mode_set.crtc;
1179 serge 516
 
517
		modeset = &fb_helper->crtc_info[i].mode_set;
518
 
519
		modeset->x = var->xoffset;
520
		modeset->y = var->yoffset;
521
 
522
		if (modeset->num_connectors) {
523
			ret = crtc->funcs->set_config(modeset);
524
			if (!ret) {
525
				info->var.xoffset = var->xoffset;
526
				info->var.yoffset = var->yoffset;
527
			}
528
		}
529
	}
1963 serge 530
	mutex_unlock(&dev->mode_config.mutex);
1179 serge 531
	return ret;
532
}
533
EXPORT_SYMBOL(drm_fb_helper_pan_display);
534
 
1963 serge 535
int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
536
				  int preferred_bpp)
1179 serge 537
{
538
	int new_fb = 0;
539
	int crtc_count = 0;
1963 serge 540
	int i;
1179 serge 541
	struct fb_info *info;
1963 serge 542
	struct drm_fb_helper_surface_size sizes;
543
	int gamma_size = 0;
1179 serge 544
 
1963 serge 545
	memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
546
	sizes.surface_depth = 24;
547
	sizes.surface_bpp = 32;
548
	sizes.fb_width = (unsigned)-1;
549
	sizes.fb_height = (unsigned)-1;
1221 serge 550
 
1963 serge 551
    sizes.surface_depth = 24;
552
    sizes.surface_bpp = 32;
1221 serge 553
 
1963 serge 554
	crtc_count = 0;
555
	for (i = 0; i < fb_helper->crtc_count; i++) {
556
		struct drm_display_mode *desired_mode;
557
		desired_mode = fb_helper->crtc_info[i].desired_mode;
1221 serge 558
 
1963 serge 559
		if (desired_mode) {
560
			if (gamma_size == 0)
561
				gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
562
			if (desired_mode->hdisplay < sizes.fb_width)
563
				sizes.fb_width = desired_mode->hdisplay;
564
			if (desired_mode->vdisplay < sizes.fb_height)
565
				sizes.fb_height = desired_mode->vdisplay;
566
			if (desired_mode->hdisplay > sizes.surface_width)
567
				sizes.surface_width = desired_mode->hdisplay;
568
			if (desired_mode->vdisplay > sizes.surface_height)
569
				sizes.surface_height = desired_mode->vdisplay;
1179 serge 570
			crtc_count++;
571
		}
572
	}
573
 
1963 serge 574
	if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
1179 serge 575
		/* hmm everyone went away - assume VGA cable just fell out
576
		   and will come back later. */
1963 serge 577
		DRM_INFO("Cannot find any crtc or sizes - going 1024x768\n");
578
		sizes.fb_width = sizes.surface_width = 1024;
579
		sizes.fb_height = sizes.surface_height = 768;
1179 serge 580
	}
581
 
1963 serge 582
	/* push down into drivers */
583
    new_fb = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
584
	if (new_fb < 0)
585
		return new_fb;
1179 serge 586
 
1963 serge 587
	info = fb_helper->fbdev;
1179 serge 588
 
1963 serge 589
	/* set the fb pointer */
590
	for (i = 0; i < fb_helper->crtc_count; i++) {
591
		fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
1179 serge 592
		}
593
 
594
	if (new_fb) {
1313 serge 595
		info->var.pixclock = 0;
1963 serge 596
 
597
		printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
598
		       info->fix.id);
599
 
1179 serge 600
	} else {
601
		drm_fb_helper_set_par(info);
602
	}
603
 
1963 serge 604
 
605
	if (new_fb)
606
        list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
607
 
1179 serge 608
	return 0;
609
}
610
EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
611
 
1221 serge 612
void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
613
			    uint32_t depth)
1179 serge 614
{
615
	info->fix.type = FB_TYPE_PACKED_PIXELS;
1221 serge 616
	info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
1246 serge 617
		FB_VISUAL_TRUECOLOR;
1963 serge 618
	info->fix.mmio_start = 0;
619
	info->fix.mmio_len = 0;
1179 serge 620
	info->fix.type_aux = 0;
621
	info->fix.xpanstep = 1; /* doing it in hw */
622
	info->fix.ypanstep = 1; /* doing it in hw */
623
	info->fix.ywrapstep = 0;
624
	info->fix.accel = FB_ACCEL_NONE;
625
	info->fix.type_aux = 0;
626
 
627
	info->fix.line_length = pitch;
628
	return;
629
}
630
EXPORT_SYMBOL(drm_fb_helper_fill_fix);
631
 
1963 serge 632
void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
1179 serge 633
			    uint32_t fb_width, uint32_t fb_height)
634
{
1963 serge 635
	struct drm_framebuffer *fb = fb_helper->fb;
636
	info->pseudo_palette = fb_helper->pseudo_palette;
1179 serge 637
	info->var.xres_virtual = fb->width;
638
	info->var.yres_virtual = fb->height;
639
	info->var.bits_per_pixel = fb->bits_per_pixel;
1963 serge 640
	info->var.accel_flags = FB_ACCELF_TEXT;
1179 serge 641
	info->var.xoffset = 0;
642
	info->var.yoffset = 0;
643
	info->var.activate = FB_ACTIVATE_NOW;
644
	info->var.height = -1;
645
	info->var.width = -1;
646
 
647
	switch (fb->depth) {
648
	case 8:
649
		info->var.red.offset = 0;
650
		info->var.green.offset = 0;
651
		info->var.blue.offset = 0;
652
		info->var.red.length = 8; /* 8bit DAC */
653
		info->var.green.length = 8;
654
		info->var.blue.length = 8;
655
		info->var.transp.offset = 0;
656
		info->var.transp.length = 0;
657
		break;
658
	case 15:
659
		info->var.red.offset = 10;
660
		info->var.green.offset = 5;
661
		info->var.blue.offset = 0;
662
		info->var.red.length = 5;
663
		info->var.green.length = 5;
664
		info->var.blue.length = 5;
665
		info->var.transp.offset = 15;
666
		info->var.transp.length = 1;
667
		break;
668
	case 16:
669
		info->var.red.offset = 11;
670
		info->var.green.offset = 5;
671
		info->var.blue.offset = 0;
672
		info->var.red.length = 5;
673
		info->var.green.length = 6;
674
		info->var.blue.length = 5;
675
		info->var.transp.offset = 0;
676
		break;
677
	case 24:
678
		info->var.red.offset = 16;
679
		info->var.green.offset = 8;
680
		info->var.blue.offset = 0;
681
		info->var.red.length = 8;
682
		info->var.green.length = 8;
683
		info->var.blue.length = 8;
684
		info->var.transp.offset = 0;
685
		info->var.transp.length = 0;
686
		break;
687
	case 32:
688
		info->var.red.offset = 16;
689
		info->var.green.offset = 8;
690
		info->var.blue.offset = 0;
691
		info->var.red.length = 8;
692
		info->var.green.length = 8;
693
		info->var.blue.length = 8;
694
		info->var.transp.offset = 24;
695
		info->var.transp.length = 8;
696
		break;
697
	default:
698
		break;
699
	}
700
 
701
	info->var.xres = fb_width;
702
	info->var.yres = fb_height;
703
}
704
EXPORT_SYMBOL(drm_fb_helper_fill_var);
1963 serge 705
 
706
static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
707
					       uint32_t maxX,
708
					       uint32_t maxY)
709
{
710
	struct drm_connector *connector;
711
	int count = 0;
712
	int i;
713
 
714
	for (i = 0; i < fb_helper->connector_count; i++) {
715
		connector = fb_helper->connector_info[i]->connector;
716
		count += connector->funcs->fill_modes(connector, maxX, maxY);
717
	}
718
 
719
	return count;
720
}
721
 
722
static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height)
723
{
724
	struct drm_display_mode *mode;
725
 
726
	list_for_each_entry(mode, &fb_connector->connector->modes, head) {
727
		if (drm_mode_width(mode) > width ||
728
		    drm_mode_height(mode) > height)
729
			continue;
730
		if (mode->type & DRM_MODE_TYPE_PREFERRED)
731
			return mode;
732
	}
733
	return NULL;
734
}
735
 
736
static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
737
{
738
	struct drm_cmdline_mode *cmdline_mode;
739
	cmdline_mode = &fb_connector->cmdline_mode;
740
	return cmdline_mode->specified;
741
}
742
 
743
 
744
static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
745
{
746
	bool enable;
747
 
748
	if (strict) {
749
		enable = connector->status == connector_status_connected;
750
	} else {
751
		enable = connector->status != connector_status_disconnected;
752
	}
753
	return enable;
754
}
755
 
756
static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
757
				  bool *enabled)
758
{
759
	bool any_enabled = false;
760
	struct drm_connector *connector;
761
	int i = 0;
762
 
763
	for (i = 0; i < fb_helper->connector_count; i++) {
764
		connector = fb_helper->connector_info[i]->connector;
765
		enabled[i] = drm_connector_enabled(connector, true);
766
		DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
767
			  enabled[i] ? "yes" : "no");
768
		any_enabled |= enabled[i];
769
	}
770
 
771
	if (any_enabled)
772
		return;
773
 
774
	for (i = 0; i < fb_helper->connector_count; i++) {
775
		connector = fb_helper->connector_info[i]->connector;
776
		enabled[i] = drm_connector_enabled(connector, false);
777
	}
778
}
779
 
780
 
781
static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
782
				 struct drm_display_mode **modes,
783
				 bool *enabled, int width, int height)
784
{
785
	struct drm_fb_helper_connector *fb_helper_conn;
786
	int i;
787
 
788
	for (i = 0; i < fb_helper->connector_count; i++) {
789
		fb_helper_conn = fb_helper->connector_info[i];
790
 
791
		if (enabled[i] == false)
792
			continue;
793
 
794
		DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
795
			      fb_helper_conn->connector->base.id);
796
 
797
		/* got for command line mode first */
798
//       modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
799
 
800
        modes[i] = NULL;
801
 
802
		if (!modes[i]) {
803
			DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
804
				      fb_helper_conn->connector->base.id);
805
			modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height);
806
		}
807
		/* No preferred modes, pick one off the list */
808
		if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) {
809
			list_for_each_entry(modes[i], &fb_helper_conn->connector->modes, head)
810
				break;
811
		}
812
		DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
813
			  "none");
814
	}
815
	return true;
816
}
817
 
818
static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
819
			  struct drm_fb_helper_crtc **best_crtcs,
820
			  struct drm_display_mode **modes,
821
			  int n, int width, int height)
822
{
823
	int c, o;
824
	struct drm_device *dev = fb_helper->dev;
825
	struct drm_connector *connector;
826
	struct drm_connector_helper_funcs *connector_funcs;
827
	struct drm_encoder *encoder;
828
	struct drm_fb_helper_crtc *best_crtc;
829
	int my_score, best_score, score;
830
	struct drm_fb_helper_crtc **crtcs, *crtc;
831
	struct drm_fb_helper_connector *fb_helper_conn;
832
 
833
	if (n == fb_helper->connector_count)
834
		return 0;
835
 
836
	fb_helper_conn = fb_helper->connector_info[n];
837
	connector = fb_helper_conn->connector;
838
 
839
	best_crtcs[n] = NULL;
840
	best_crtc = NULL;
841
	best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height);
842
	if (modes[n] == NULL)
843
		return best_score;
844
 
845
	crtcs = kzalloc(dev->mode_config.num_connector *
846
			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
847
	if (!crtcs)
848
		return best_score;
849
 
850
	my_score = 1;
851
	if (connector->status == connector_status_connected)
852
		my_score++;
853
	if (drm_has_cmdline_mode(fb_helper_conn))
854
		my_score++;
855
	if (drm_has_preferred_mode(fb_helper_conn, width, height))
856
		my_score++;
857
 
858
	connector_funcs = connector->helper_private;
859
	encoder = connector_funcs->best_encoder(connector);
860
	if (!encoder)
861
		goto out;
862
 
863
	/* select a crtc for this connector and then attempt to configure
864
	   remaining connectors */
865
	for (c = 0; c < fb_helper->crtc_count; c++) {
866
		crtc = &fb_helper->crtc_info[c];
867
 
868
		if ((encoder->possible_crtcs & (1 << c)) == 0) {
869
			continue;
870
		}
871
 
872
		for (o = 0; o < n; o++)
873
			if (best_crtcs[o] == crtc)
874
				break;
875
 
876
		if (o < n) {
877
			/* ignore cloning unless only a single crtc */
878
			if (fb_helper->crtc_count > 1)
879
				continue;
880
 
881
			if (!drm_mode_equal(modes[o], modes[n]))
882
				continue;
883
		}
884
 
885
		crtcs[n] = crtc;
886
		memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *));
887
		score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1,
888
						  width, height);
889
		if (score > best_score) {
890
			best_crtc = crtc;
891
			best_score = score;
892
			memcpy(best_crtcs, crtcs,
893
			       dev->mode_config.num_connector *
894
			       sizeof(struct drm_fb_helper_crtc *));
895
		}
896
	}
897
out:
898
	kfree(crtcs);
899
	return best_score;
900
}
901
 
902
static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
903
{
904
	struct drm_device *dev = fb_helper->dev;
905
	struct drm_fb_helper_crtc **crtcs;
906
	struct drm_display_mode **modes;
907
	struct drm_encoder *encoder;
908
	struct drm_mode_set *modeset;
909
	bool *enabled;
910
	int width, height;
911
	int i, ret;
912
 
913
	DRM_DEBUG_KMS("\n");
914
 
915
	width = dev->mode_config.max_width;
916
	height = dev->mode_config.max_height;
917
 
918
	/* clean out all the encoder/crtc combos */
1986 serge 919
   list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
2004 serge 920
		encoder->crtc = NULL;
1986 serge 921
   }
1963 serge 922
 
923
	crtcs = kcalloc(dev->mode_config.num_connector,
924
			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
925
	modes = kcalloc(dev->mode_config.num_connector,
926
			sizeof(struct drm_display_mode *), GFP_KERNEL);
927
	enabled = kcalloc(dev->mode_config.num_connector,
928
			  sizeof(bool), GFP_KERNEL);
929
 
930
	drm_enable_connectors(fb_helper, enabled);
931
 
932
    //ret = drm_target_cloned(fb_helper, modes, enabled, width, height);
933
 
934
    ret = 0;
935
 
936
	if (!ret) {
937
		ret = drm_target_preferred(fb_helper, modes, enabled, width, height);
938
		if (!ret)
939
			DRM_ERROR("Unable to find initial modes\n");
940
	}
941
 
942
	DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height);
943
 
944
	drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
945
 
946
	/* need to set the modesets up here for use later */
947
	/* fill out the connector<->crtc mappings into the modesets */
948
	for (i = 0; i < fb_helper->crtc_count; i++) {
949
		modeset = &fb_helper->crtc_info[i].mode_set;
950
		modeset->num_connectors = 0;
951
	}
952
 
953
	for (i = 0; i < fb_helper->connector_count; i++) {
954
		struct drm_display_mode *mode = modes[i];
955
		struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
956
		modeset = &fb_crtc->mode_set;
957
 
958
		if (mode && fb_crtc) {
959
			DRM_DEBUG_KMS("desired mode %s set on crtc %d\n",
960
				      mode->name, fb_crtc->mode_set.crtc->base.id);
961
			fb_crtc->desired_mode = mode;
962
			if (modeset->mode)
963
				drm_mode_destroy(dev, modeset->mode);
964
			modeset->mode = drm_mode_duplicate(dev,
965
							   fb_crtc->desired_mode);
966
			modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector;
967
		}
968
	}
969
 
970
	kfree(crtcs);
971
	kfree(modes);
972
	kfree(enabled);
973
}
974
 
975
/**
976
 * drm_helper_initial_config - setup a sane initial connector configuration
977
 * @dev: DRM device
978
 *
979
 * LOCKING:
980
 * Called at init time, must take mode config lock.
981
 *
982
 * Scan the CRTCs and connectors and try to put together an initial setup.
983
 * At the moment, this is a cloned configuration across all heads with
984
 * a new framebuffer object as the backing store.
985
 *
986
 * RETURNS:
987
 * Zero if everything went ok, nonzero otherwise.
988
 */
989
bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
990
{
991
	struct drm_device *dev = fb_helper->dev;
992
	int count = 0;
993
 
994
	/* disable all the possible outputs/crtcs before entering KMS mode */
995
//   drm_helper_disable_unused_functions(fb_helper->dev);
996
 
997
//   drm_fb_helper_parse_command_line(fb_helper);
998
 
999
	count = drm_fb_helper_probe_connector_modes(fb_helper,
1000
						    dev->mode_config.max_width,
1001
						    dev->mode_config.max_height);
1002
	/*
1003
	 * we shouldn't end up with no modes here.
1004
	 */
1005
	if (count == 0) {
1006
		printk(KERN_INFO "No connectors reported connected with modes\n");
1007
	}
1008
	drm_setup_crtcs(fb_helper);
1009
 
1010
	return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
1011
}
1012
EXPORT_SYMBOL(drm_fb_helper_initial_config);