Subversion Repositories Kolibri OS

Rev

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