Subversion Repositories Kolibri OS

Rev

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