Subversion Repositories Kolibri OS

Rev

Rev 1986 | Rev 2160 | 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 */
1179 serge 583
 
1963 serge 584
    DRM_INFO("enter fb probe\n");
1179 serge 585
 
586
 
1963 serge 587
    new_fb = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
588
	if (new_fb < 0)
589
		return new_fb;
1179 serge 590
 
1963 serge 591
	info = fb_helper->fbdev;
1179 serge 592
 
1963 serge 593
	/* set the fb pointer */
594
	for (i = 0; i < fb_helper->crtc_count; i++) {
595
		fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
1179 serge 596
		}
597
 
598
	if (new_fb) {
1313 serge 599
		info->var.pixclock = 0;
1963 serge 600
 
601
		printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
602
		       info->fix.id);
603
 
1179 serge 604
	} else {
605
		drm_fb_helper_set_par(info);
606
	}
607
 
1963 serge 608
 
609
	if (new_fb)
610
        list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
611
 
612
 
613
    LEAVE();
614
 
1179 serge 615
	return 0;
616
}
617
EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
618
 
1221 serge 619
void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
620
			    uint32_t depth)
1179 serge 621
{
622
	info->fix.type = FB_TYPE_PACKED_PIXELS;
1221 serge 623
	info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
1246 serge 624
		FB_VISUAL_TRUECOLOR;
1963 serge 625
	info->fix.mmio_start = 0;
626
	info->fix.mmio_len = 0;
1179 serge 627
	info->fix.type_aux = 0;
628
	info->fix.xpanstep = 1; /* doing it in hw */
629
	info->fix.ypanstep = 1; /* doing it in hw */
630
	info->fix.ywrapstep = 0;
631
	info->fix.accel = FB_ACCEL_NONE;
632
	info->fix.type_aux = 0;
633
 
634
	info->fix.line_length = pitch;
635
	return;
636
}
637
EXPORT_SYMBOL(drm_fb_helper_fill_fix);
638
 
1963 serge 639
void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
1179 serge 640
			    uint32_t fb_width, uint32_t fb_height)
641
{
1963 serge 642
	struct drm_framebuffer *fb = fb_helper->fb;
643
	info->pseudo_palette = fb_helper->pseudo_palette;
1179 serge 644
	info->var.xres_virtual = fb->width;
645
	info->var.yres_virtual = fb->height;
646
	info->var.bits_per_pixel = fb->bits_per_pixel;
1963 serge 647
	info->var.accel_flags = FB_ACCELF_TEXT;
1179 serge 648
	info->var.xoffset = 0;
649
	info->var.yoffset = 0;
650
	info->var.activate = FB_ACTIVATE_NOW;
651
	info->var.height = -1;
652
	info->var.width = -1;
653
 
654
	switch (fb->depth) {
655
	case 8:
656
		info->var.red.offset = 0;
657
		info->var.green.offset = 0;
658
		info->var.blue.offset = 0;
659
		info->var.red.length = 8; /* 8bit DAC */
660
		info->var.green.length = 8;
661
		info->var.blue.length = 8;
662
		info->var.transp.offset = 0;
663
		info->var.transp.length = 0;
664
		break;
665
	case 15:
666
		info->var.red.offset = 10;
667
		info->var.green.offset = 5;
668
		info->var.blue.offset = 0;
669
		info->var.red.length = 5;
670
		info->var.green.length = 5;
671
		info->var.blue.length = 5;
672
		info->var.transp.offset = 15;
673
		info->var.transp.length = 1;
674
		break;
675
	case 16:
676
		info->var.red.offset = 11;
677
		info->var.green.offset = 5;
678
		info->var.blue.offset = 0;
679
		info->var.red.length = 5;
680
		info->var.green.length = 6;
681
		info->var.blue.length = 5;
682
		info->var.transp.offset = 0;
683
		break;
684
	case 24:
685
		info->var.red.offset = 16;
686
		info->var.green.offset = 8;
687
		info->var.blue.offset = 0;
688
		info->var.red.length = 8;
689
		info->var.green.length = 8;
690
		info->var.blue.length = 8;
691
		info->var.transp.offset = 0;
692
		info->var.transp.length = 0;
693
		break;
694
	case 32:
695
		info->var.red.offset = 16;
696
		info->var.green.offset = 8;
697
		info->var.blue.offset = 0;
698
		info->var.red.length = 8;
699
		info->var.green.length = 8;
700
		info->var.blue.length = 8;
701
		info->var.transp.offset = 24;
702
		info->var.transp.length = 8;
703
		break;
704
	default:
705
		break;
706
	}
707
 
708
	info->var.xres = fb_width;
709
	info->var.yres = fb_height;
710
}
711
EXPORT_SYMBOL(drm_fb_helper_fill_var);
1963 serge 712
 
713
static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
714
					       uint32_t maxX,
715
					       uint32_t maxY)
716
{
717
	struct drm_connector *connector;
718
	int count = 0;
719
	int i;
720
 
721
	for (i = 0; i < fb_helper->connector_count; i++) {
722
		connector = fb_helper->connector_info[i]->connector;
723
		count += connector->funcs->fill_modes(connector, maxX, maxY);
724
	}
725
 
726
	return count;
727
}
728
 
729
static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height)
730
{
731
	struct drm_display_mode *mode;
732
 
733
	list_for_each_entry(mode, &fb_connector->connector->modes, head) {
734
		if (drm_mode_width(mode) > width ||
735
		    drm_mode_height(mode) > height)
736
			continue;
737
		if (mode->type & DRM_MODE_TYPE_PREFERRED)
738
			return mode;
739
	}
740
	return NULL;
741
}
742
 
743
static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
744
{
745
	struct drm_cmdline_mode *cmdline_mode;
746
	cmdline_mode = &fb_connector->cmdline_mode;
747
	return cmdline_mode->specified;
748
}
749
 
750
 
751
static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
752
{
753
	bool enable;
754
 
755
	if (strict) {
756
		enable = connector->status == connector_status_connected;
757
	} else {
758
		enable = connector->status != connector_status_disconnected;
759
	}
760
	return enable;
761
}
762
 
763
static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
764
				  bool *enabled)
765
{
766
	bool any_enabled = false;
767
	struct drm_connector *connector;
768
	int i = 0;
769
 
770
	for (i = 0; i < fb_helper->connector_count; i++) {
771
		connector = fb_helper->connector_info[i]->connector;
772
		enabled[i] = drm_connector_enabled(connector, true);
773
		DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
774
			  enabled[i] ? "yes" : "no");
775
		any_enabled |= enabled[i];
776
	}
777
 
778
	if (any_enabled)
779
		return;
780
 
781
	for (i = 0; i < fb_helper->connector_count; i++) {
782
		connector = fb_helper->connector_info[i]->connector;
783
		enabled[i] = drm_connector_enabled(connector, false);
784
	}
785
}
786
 
787
 
788
static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
789
				 struct drm_display_mode **modes,
790
				 bool *enabled, int width, int height)
791
{
792
	struct drm_fb_helper_connector *fb_helper_conn;
793
	int i;
794
 
795
	for (i = 0; i < fb_helper->connector_count; i++) {
796
		fb_helper_conn = fb_helper->connector_info[i];
797
 
798
		if (enabled[i] == false)
799
			continue;
800
 
801
		DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
802
			      fb_helper_conn->connector->base.id);
803
 
804
		/* got for command line mode first */
805
//       modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
806
 
807
        modes[i] = NULL;
808
 
809
		if (!modes[i]) {
810
			DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
811
				      fb_helper_conn->connector->base.id);
812
			modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height);
813
		}
814
		/* No preferred modes, pick one off the list */
815
		if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) {
816
			list_for_each_entry(modes[i], &fb_helper_conn->connector->modes, head)
817
				break;
818
		}
819
		DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
820
			  "none");
821
	}
822
	return true;
823
}
824
 
825
static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
826
			  struct drm_fb_helper_crtc **best_crtcs,
827
			  struct drm_display_mode **modes,
828
			  int n, int width, int height)
829
{
830
	int c, o;
831
	struct drm_device *dev = fb_helper->dev;
832
	struct drm_connector *connector;
833
	struct drm_connector_helper_funcs *connector_funcs;
834
	struct drm_encoder *encoder;
835
	struct drm_fb_helper_crtc *best_crtc;
836
	int my_score, best_score, score;
837
	struct drm_fb_helper_crtc **crtcs, *crtc;
838
	struct drm_fb_helper_connector *fb_helper_conn;
839
 
840
	if (n == fb_helper->connector_count)
841
		return 0;
842
 
843
	fb_helper_conn = fb_helper->connector_info[n];
844
	connector = fb_helper_conn->connector;
845
 
846
	best_crtcs[n] = NULL;
847
	best_crtc = NULL;
848
	best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height);
849
	if (modes[n] == NULL)
850
		return best_score;
851
 
852
	crtcs = kzalloc(dev->mode_config.num_connector *
853
			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
854
	if (!crtcs)
855
		return best_score;
856
 
857
	my_score = 1;
858
	if (connector->status == connector_status_connected)
859
		my_score++;
860
	if (drm_has_cmdline_mode(fb_helper_conn))
861
		my_score++;
862
	if (drm_has_preferred_mode(fb_helper_conn, width, height))
863
		my_score++;
864
 
865
	connector_funcs = connector->helper_private;
866
	encoder = connector_funcs->best_encoder(connector);
867
	if (!encoder)
868
		goto out;
869
 
870
	/* select a crtc for this connector and then attempt to configure
871
	   remaining connectors */
872
	for (c = 0; c < fb_helper->crtc_count; c++) {
873
		crtc = &fb_helper->crtc_info[c];
874
 
875
		if ((encoder->possible_crtcs & (1 << c)) == 0) {
876
			continue;
877
		}
878
 
879
		for (o = 0; o < n; o++)
880
			if (best_crtcs[o] == crtc)
881
				break;
882
 
883
		if (o < n) {
884
			/* ignore cloning unless only a single crtc */
885
			if (fb_helper->crtc_count > 1)
886
				continue;
887
 
888
			if (!drm_mode_equal(modes[o], modes[n]))
889
				continue;
890
		}
891
 
892
		crtcs[n] = crtc;
893
		memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *));
894
		score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1,
895
						  width, height);
896
		if (score > best_score) {
897
			best_crtc = crtc;
898
			best_score = score;
899
			memcpy(best_crtcs, crtcs,
900
			       dev->mode_config.num_connector *
901
			       sizeof(struct drm_fb_helper_crtc *));
902
		}
903
	}
904
out:
905
	kfree(crtcs);
906
	return best_score;
907
}
908
 
909
static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
910
{
911
	struct drm_device *dev = fb_helper->dev;
912
	struct drm_fb_helper_crtc **crtcs;
913
	struct drm_display_mode **modes;
914
	struct drm_encoder *encoder;
915
	struct drm_mode_set *modeset;
916
	bool *enabled;
917
	int width, height;
918
	int i, ret;
919
 
920
	DRM_DEBUG_KMS("\n");
921
 
922
	width = dev->mode_config.max_width;
923
	height = dev->mode_config.max_height;
924
 
925
	/* clean out all the encoder/crtc combos */
1986 serge 926
   list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
2004 serge 927
		encoder->crtc = NULL;
1986 serge 928
   }
1963 serge 929
 
930
	crtcs = kcalloc(dev->mode_config.num_connector,
931
			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
932
	modes = kcalloc(dev->mode_config.num_connector,
933
			sizeof(struct drm_display_mode *), GFP_KERNEL);
934
	enabled = kcalloc(dev->mode_config.num_connector,
935
			  sizeof(bool), GFP_KERNEL);
936
 
937
	drm_enable_connectors(fb_helper, enabled);
938
 
939
    //ret = drm_target_cloned(fb_helper, modes, enabled, width, height);
940
 
941
    ret = 0;
942
 
943
	if (!ret) {
944
		ret = drm_target_preferred(fb_helper, modes, enabled, width, height);
945
		if (!ret)
946
			DRM_ERROR("Unable to find initial modes\n");
947
	}
948
 
949
	DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height);
950
 
951
	drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
952
 
953
	/* need to set the modesets up here for use later */
954
	/* fill out the connector<->crtc mappings into the modesets */
955
	for (i = 0; i < fb_helper->crtc_count; i++) {
956
		modeset = &fb_helper->crtc_info[i].mode_set;
957
		modeset->num_connectors = 0;
958
	}
959
 
960
	for (i = 0; i < fb_helper->connector_count; i++) {
961
		struct drm_display_mode *mode = modes[i];
962
		struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
963
		modeset = &fb_crtc->mode_set;
964
 
965
		if (mode && fb_crtc) {
966
			DRM_DEBUG_KMS("desired mode %s set on crtc %d\n",
967
				      mode->name, fb_crtc->mode_set.crtc->base.id);
968
			fb_crtc->desired_mode = mode;
969
			if (modeset->mode)
970
				drm_mode_destroy(dev, modeset->mode);
971
			modeset->mode = drm_mode_duplicate(dev,
972
							   fb_crtc->desired_mode);
973
			modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector;
974
		}
975
	}
976
 
977
	kfree(crtcs);
978
	kfree(modes);
979
	kfree(enabled);
980
}
981
 
982
/**
983
 * drm_helper_initial_config - setup a sane initial connector configuration
984
 * @dev: DRM device
985
 *
986
 * LOCKING:
987
 * Called at init time, must take mode config lock.
988
 *
989
 * Scan the CRTCs and connectors and try to put together an initial setup.
990
 * At the moment, this is a cloned configuration across all heads with
991
 * a new framebuffer object as the backing store.
992
 *
993
 * RETURNS:
994
 * Zero if everything went ok, nonzero otherwise.
995
 */
996
bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
997
{
998
	struct drm_device *dev = fb_helper->dev;
999
	int count = 0;
1000
 
1001
	/* disable all the possible outputs/crtcs before entering KMS mode */
1002
//   drm_helper_disable_unused_functions(fb_helper->dev);
1003
 
1004
//   drm_fb_helper_parse_command_line(fb_helper);
1005
 
1006
	count = drm_fb_helper_probe_connector_modes(fb_helper,
1007
						    dev->mode_config.max_width,
1008
						    dev->mode_config.max_height);
1009
	/*
1010
	 * we shouldn't end up with no modes here.
1011
	 */
1012
	if (count == 0) {
1013
		printk(KERN_INFO "No connectors reported connected with modes\n");
1014
	}
1015
	drm_setup_crtcs(fb_helper);
1016
 
1017
	return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
1018
}
1019
EXPORT_SYMBOL(drm_fb_helper_initial_config);