Subversion Repositories Kolibri OS

Rev

Rev 5060 | Rev 6084 | 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
 
42
static LIST_HEAD(kernel_fb_helper_list);
43
 
3192 Serge 44
/**
45
 * DOC: fbdev helpers
46
 *
47
 * The fb helper functions are useful to provide an fbdev on top of a drm kernel
5060 serge 48
 * mode setting driver. They can be used mostly independently from the crtc
3192 Serge 49
 * helper functions used by many drivers to implement the kernel mode setting
50
 * interfaces.
3480 Serge 51
 *
5060 serge 52
 * Initialization is done as a four-step process with drm_fb_helper_prepare(),
53
 * drm_fb_helper_init(), drm_fb_helper_single_add_all_connectors() and
54
 * drm_fb_helper_initial_config(). Drivers with fancier requirements than the
55
 * default behaviour can override the third step with their own code.
56
 * Teardown is done with drm_fb_helper_fini().
3480 Serge 57
 *
58
 * At runtime drivers should restore the fbdev console by calling
59
 * drm_fb_helper_restore_fbdev_mode() from their ->lastclose callback. They
60
 * should also notify the fb helper code from updates to the output
61
 * configuration by calling drm_fb_helper_hotplug_event(). For easier
62
 * integration with the output polling code in drm_crtc_helper.c the modeset
5060 serge 63
 * code provides a ->output_poll_changed callback.
3480 Serge 64
 *
65
 * All other functions exported by the fb helper library can be used to
66
 * implement the fbdev driver interface by the driver.
5060 serge 67
 *
68
 * It is possible, though perhaps somewhat tricky, to implement race-free
69
 * hotplug detection using the fbdev helpers. The drm_fb_helper_prepare()
70
 * helper must be called first to initialize the minimum required to make
71
 * hotplug detection work. Drivers also need to make sure to properly set up
72
 * the dev->mode_config.funcs member. After calling drm_kms_helper_poll_init()
73
 * it is safe to enable interrupts and start processing hotplug events. At the
74
 * same time, drivers should initialize all modeset objects such as CRTCs,
75
 * encoders and connectors. To finish up the fbdev helper initialization, the
76
 * drm_fb_helper_init() function is called. To probe for all attached displays
77
 * and set up an initial configuration using the detected hardware, drivers
78
 * should call drm_fb_helper_single_add_all_connectors() followed by
79
 * drm_fb_helper_initial_config().
3192 Serge 80
 */
81
 
3480 Serge 82
/**
83
 * drm_fb_helper_single_add_all_connectors() - add all connectors to fbdev
84
 * 					       emulation helper
85
 * @fb_helper: fbdev initialized with drm_fb_helper_init
86
 *
87
 * This functions adds all the available connectors for use with the given
88
 * fb_helper. This is a separate step to allow drivers to freely assign
89
 * connectors to the fbdev, e.g. if some are reserved for special purposes or
90
 * not adequate to be used for the fbcon.
91
 *
92
 * Since this is part of the initial setup before the fbdev is published, no
93
 * locking is required.
94
 */
1963 serge 95
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
1221 serge 96
{
1963 serge 97
	struct drm_device *dev = fb_helper->dev;
98
	struct drm_connector *connector;
99
	int i;
1221 serge 100
 
1963 serge 101
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
102
		struct drm_fb_helper_connector *fb_helper_connector;
103
 
104
		fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL);
105
		if (!fb_helper_connector)
106
			goto fail;
107
 
108
		fb_helper_connector->connector = connector;
109
		fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector;
110
	}
1221 serge 111
	return 0;
1963 serge 112
fail:
113
	for (i = 0; i < fb_helper->connector_count; i++) {
114
		kfree(fb_helper->connector_info[i]);
115
		fb_helper->connector_info[i] = NULL;
116
	}
117
	fb_helper->connector_count = 0;
118
    return -ENOMEM;
1221 serge 119
}
1963 serge 120
EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
1221 serge 121
 
5060 serge 122
int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector)
123
{
124
	struct drm_fb_helper_connector **temp;
125
	struct drm_fb_helper_connector *fb_helper_connector;
126
 
127
	WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex));
128
	if (fb_helper->connector_count + 1 > fb_helper->connector_info_alloc_count) {
5271 serge 129
		temp = krealloc(fb_helper->connector_info, sizeof(struct drm_fb_helper_connector *) * (fb_helper->connector_count + 1), GFP_KERNEL);
5060 serge 130
		if (!temp)
131
			return -ENOMEM;
132
 
133
		fb_helper->connector_info_alloc_count = fb_helper->connector_count + 1;
134
		fb_helper->connector_info = temp;
135
	}
136
 
137
 
138
	fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL);
139
	if (!fb_helper_connector)
140
		return -ENOMEM;
141
 
142
	fb_helper_connector->connector = connector;
143
	fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector;
144
	return 0;
145
}
146
EXPORT_SYMBOL(drm_fb_helper_add_one_connector);
147
 
148
int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
149
				       struct drm_connector *connector)
150
{
151
	struct drm_fb_helper_connector *fb_helper_connector;
152
	int i, j;
153
 
154
	WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex));
155
 
156
	for (i = 0; i < fb_helper->connector_count; i++) {
157
		if (fb_helper->connector_info[i]->connector == connector)
158
			break;
159
	}
160
 
161
	if (i == fb_helper->connector_count)
162
		return -EINVAL;
163
	fb_helper_connector = fb_helper->connector_info[i];
164
 
165
	for (j = i + 1; j < fb_helper->connector_count; j++) {
166
		fb_helper->connector_info[j - 1] = fb_helper->connector_info[j];
167
	}
168
	fb_helper->connector_count--;
169
	kfree(fb_helper_connector);
170
	return 0;
171
}
172
EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);
5271 serge 173
 
1963 serge 174
static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_helper *helper)
1179 serge 175
{
1963 serge 176
	uint16_t *r_base, *g_base, *b_base;
177
	int i;
1179 serge 178
 
4104 Serge 179
	if (helper->funcs->gamma_get == NULL)
180
		return;
181
 
1963 serge 182
	r_base = crtc->gamma_store;
183
	g_base = r_base + crtc->gamma_size;
184
	b_base = g_base + crtc->gamma_size;
1179 serge 185
 
1963 serge 186
	for (i = 0; i < crtc->gamma_size; i++)
187
		helper->funcs->gamma_get(crtc, &r_base[i], &g_base[i], &b_base[i], i);
1179 serge 188
}
189
 
1963 serge 190
static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
1179 serge 191
{
1963 serge 192
	uint16_t *r_base, *g_base, *b_base;
193
 
3031 serge 194
	if (crtc->funcs->gamma_set == NULL)
195
		return;
196
 
1963 serge 197
	r_base = crtc->gamma_store;
198
	g_base = r_base + crtc->gamma_size;
199
	b_base = g_base + crtc->gamma_size;
200
 
201
	crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
1179 serge 202
}
203
 
204
 
5060 serge 205
static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper)
206
{
207
	struct drm_device *dev = fb_helper->dev;
208
	struct drm_plane *plane;
209
	bool error = false;
210
	int i;
211
 
212
	drm_warn_on_modeset_not_all_locked(dev);
213
 
5271 serge 214
	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
5060 serge 215
		if (plane->type != DRM_PLANE_TYPE_PRIMARY)
216
			drm_plane_force_disable(plane);
217
 
5271 serge 218
		if (dev->mode_config.rotation_property) {
219
			drm_mode_plane_set_obj_prop(plane,
220
						    dev->mode_config.rotation_property,
221
						    BIT(DRM_ROTATE_0));
222
		}
223
	}
224
 
5060 serge 225
	for (i = 0; i < fb_helper->crtc_count; i++) {
226
		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
227
		struct drm_crtc *crtc = mode_set->crtc;
228
		int ret;
229
 
230
		if (crtc->funcs->cursor_set) {
231
			ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0);
232
			if (ret)
233
				error = true;
234
		}
235
 
236
		ret = drm_mode_set_config_internal(mode_set);
237
		if (ret)
238
			error = true;
239
	}
240
	return error;
241
}
242
/**
243
 * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration
244
 * @fb_helper: fbcon to restore
245
 *
246
 * This should be called from driver's drm ->lastclose callback
247
 * when implementing an fbcon on top of kms using this helper. This ensures that
248
 * the user isn't greeted with a black screen when e.g. X dies.
249
 */
250
bool drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
251
{
252
	struct drm_device *dev = fb_helper->dev;
253
	bool ret;
5271 serge 254
	bool do_delayed = false;
255
 
5060 serge 256
	drm_modeset_lock_all(dev);
257
	ret = restore_fbdev_mode(fb_helper);
258
	drm_modeset_unlock_all(dev);
259
	return ret;
260
}
261
EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked);
262
 
3480 Serge 263
static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
264
{
265
	struct drm_device *dev = fb_helper->dev;
266
	struct drm_crtc *crtc;
267
	int bound = 0, crtcs_bound = 0;
1179 serge 268
 
3480 Serge 269
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
5060 serge 270
		if (crtc->primary->fb)
3480 Serge 271
			crtcs_bound++;
5060 serge 272
		if (crtc->primary->fb == fb_helper->fb)
3480 Serge 273
			bound++;
274
	}
275
 
276
	if (bound < crtcs_bound)
277
		return false;
4560 Serge 278
 
3480 Serge 279
	return true;
280
}
281
 
4560 Serge 282
#ifdef CONFIG_MAGIC_SYSRQ
283
static void drm_fb_helper_restore_work_fn(struct work_struct *ignored)
284
{
285
	bool ret;
286
	ret = drm_fb_helper_force_kernel_mode();
287
	if (ret == true)
288
		DRM_ERROR("Failed to restore crtc configuration\n");
289
}
290
static DECLARE_WORK(drm_fb_helper_restore_work, drm_fb_helper_restore_work_fn);
291
 
292
static void drm_fb_helper_sysrq(int dummy1)
293
{
294
	schedule_work(&drm_fb_helper_restore_work);
295
}
296
 
297
static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
298
	.handler = drm_fb_helper_sysrq,
299
	.help_msg = "force-fb(V)",
300
	.action_msg = "Restore framebuffer console",
301
};
302
#else
303
 
304
#endif
305
 
3031 serge 306
static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
1179 serge 307
{
308
	struct drm_fb_helper *fb_helper = info->par;
309
	struct drm_device *dev = fb_helper->dev;
310
	struct drm_crtc *crtc;
1963 serge 311
	struct drm_connector *connector;
312
	int i, j;
1179 serge 313
 
314
	/*
3480 Serge 315
	 * fbdev->blank can be called from irq context in case of a panic.
316
	 * Since we already have our own special panic handler which will
317
	 * restore the fbdev console mode completely, just bail out early.
318
	 */
319
 
320
	/*
3031 serge 321
	 * For each CRTC in this fb, turn the connectors on/off.
1179 serge 322
	 */
3480 Serge 323
	drm_modeset_lock_all(dev);
324
	if (!drm_fb_helper_is_bound(fb_helper)) {
325
		drm_modeset_unlock_all(dev);
326
		return;
327
	}
328
 
1179 serge 329
	for (i = 0; i < fb_helper->crtc_count; i++) {
1963 serge 330
		crtc = fb_helper->crtc_info[i].mode_set.crtc;
1179 serge 331
 
1963 serge 332
		if (!crtc->enabled)
1179 serge 333
				continue;
334
 
3031 serge 335
		/* Walk the connectors & encoders on this fb turning them on/off */
1963 serge 336
		for (j = 0; j < fb_helper->connector_count; j++) {
337
			connector = fb_helper->connector_info[j]->connector;
3031 serge 338
			connector->funcs->dpms(connector, dpms_mode);
3192 Serge 339
			drm_object_property_set_value(&connector->base,
3031 serge 340
				dev->mode_config.dpms_property, dpms_mode);
1963 serge 341
		}
342
	}
3480 Serge 343
	drm_modeset_unlock_all(dev);
1179 serge 344
}
345
 
3480 Serge 346
/**
347
 * drm_fb_helper_blank - implementation for ->fb_blank
348
 * @blank: desired blanking state
349
 * @info: fbdev registered by the helper
350
 */
1179 serge 351
int drm_fb_helper_blank(int blank, struct fb_info *info)
352
{
353
	switch (blank) {
1321 serge 354
	/* Display: On; HSync: On, VSync: On */
1179 serge 355
	case FB_BLANK_UNBLANK:
3031 serge 356
		drm_fb_helper_dpms(info, DRM_MODE_DPMS_ON);
1179 serge 357
		break;
1321 serge 358
	/* Display: Off; HSync: On, VSync: On */
1179 serge 359
	case FB_BLANK_NORMAL:
3031 serge 360
		drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
1179 serge 361
		break;
1321 serge 362
	/* Display: Off; HSync: Off, VSync: On */
1179 serge 363
	case FB_BLANK_HSYNC_SUSPEND:
3031 serge 364
		drm_fb_helper_dpms(info, DRM_MODE_DPMS_STANDBY);
1179 serge 365
		break;
1321 serge 366
	/* Display: Off; HSync: On, VSync: Off */
1179 serge 367
	case FB_BLANK_VSYNC_SUSPEND:
3031 serge 368
		drm_fb_helper_dpms(info, DRM_MODE_DPMS_SUSPEND);
1179 serge 369
		break;
1321 serge 370
	/* Display: Off; HSync: Off, VSync: Off */
1179 serge 371
	case FB_BLANK_POWERDOWN:
3031 serge 372
		drm_fb_helper_dpms(info, DRM_MODE_DPMS_OFF);
1179 serge 373
		break;
374
	}
375
	return 0;
376
}
377
EXPORT_SYMBOL(drm_fb_helper_blank);
378
 
379
static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
380
{
381
	int i;
382
 
1963 serge 383
	for (i = 0; i < helper->connector_count; i++)
384
		kfree(helper->connector_info[i]);
385
	kfree(helper->connector_info);
3031 serge 386
	for (i = 0; i < helper->crtc_count; i++) {
1179 serge 387
		kfree(helper->crtc_info[i].mode_set.connectors);
3031 serge 388
		if (helper->crtc_info[i].mode_set.mode)
389
			drm_mode_destroy(helper->dev, helper->crtc_info[i].mode_set.mode);
390
	}
1179 serge 391
	kfree(helper->crtc_info);
392
}
393
 
3480 Serge 394
/**
5060 serge 395
 * drm_fb_helper_prepare - setup a drm_fb_helper structure
396
 * @dev: DRM device
397
 * @helper: driver-allocated fbdev helper structure to set up
398
 * @funcs: pointer to structure of functions associate with this helper
399
 *
400
 * Sets up the bare minimum to make the framebuffer helper usable. This is
401
 * useful to implement race-free initialization of the polling helpers.
402
 */
403
void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
404
			   const struct drm_fb_helper_funcs *funcs)
405
{
406
	INIT_LIST_HEAD(&helper->kernel_fb_list);
407
	helper->funcs = funcs;
408
	helper->dev = dev;
409
}
410
EXPORT_SYMBOL(drm_fb_helper_prepare);
411
 
412
/**
3480 Serge 413
 * drm_fb_helper_init - initialize a drm_fb_helper structure
414
 * @dev: drm device
415
 * @fb_helper: driver-allocated fbdev helper structure to initialize
416
 * @crtc_count: maximum number of crtcs to support in this fbdev emulation
417
 * @max_conn_count: max connector count
418
 *
419
 * This allocates the structures for the fbdev helper with the given limits.
420
 * Note that this won't yet touch the hardware (through the driver interfaces)
421
 * nor register the fbdev. This is only done in drm_fb_helper_initial_config()
422
 * to allow driver writes more control over the exact init sequence.
423
 *
5060 serge 424
 * Drivers must call drm_fb_helper_prepare() before calling this function.
3480 Serge 425
 *
426
 * RETURNS:
427
 * Zero if everything went ok, nonzero otherwise.
428
 */
1963 serge 429
int drm_fb_helper_init(struct drm_device *dev,
430
		       struct drm_fb_helper *fb_helper,
431
		       int crtc_count, int max_conn_count)
1179 serge 432
{
433
	struct drm_crtc *crtc;
434
	int i;
435
 
5060 serge 436
	if (!max_conn_count)
437
		return -EINVAL;
1963 serge 438
 
439
	fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
440
	if (!fb_helper->crtc_info)
1179 serge 441
		return -ENOMEM;
442
 
1963 serge 443
	fb_helper->crtc_count = crtc_count;
444
	fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
445
	if (!fb_helper->connector_info) {
446
		kfree(fb_helper->crtc_info);
447
		return -ENOMEM;
448
	}
5060 serge 449
	fb_helper->connector_info_alloc_count = dev->mode_config.num_connector;
1963 serge 450
	fb_helper->connector_count = 0;
1179 serge 451
 
452
	for (i = 0; i < crtc_count; i++) {
1963 serge 453
		fb_helper->crtc_info[i].mode_set.connectors =
1179 serge 454
			kcalloc(max_conn_count,
455
				sizeof(struct drm_connector *),
456
				GFP_KERNEL);
457
 
3031 serge 458
		if (!fb_helper->crtc_info[i].mode_set.connectors)
1179 serge 459
			goto out_free;
1963 serge 460
		fb_helper->crtc_info[i].mode_set.num_connectors = 0;
1179 serge 461
	}
462
 
463
	i = 0;
464
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
1963 serge 465
		fb_helper->crtc_info[i].mode_set.crtc = crtc;
1179 serge 466
		i++;
467
	}
3031 serge 468
 
1179 serge 469
	return 0;
470
out_free:
1963 serge 471
	drm_fb_helper_crtc_free(fb_helper);
1179 serge 472
	return -ENOMEM;
473
}
1963 serge 474
EXPORT_SYMBOL(drm_fb_helper_init);
1179 serge 475
 
1246 serge 476
static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
1221 serge 477
		     u16 blue, u16 regno, struct fb_info *info)
478
{
479
	struct drm_fb_helper *fb_helper = info->par;
480
	struct drm_framebuffer *fb = fb_helper->fb;
481
	int pindex;
482
 
1246 serge 483
	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
484
		u32 *palette;
485
		u32 value;
486
		/* place color in psuedopalette */
487
		if (regno > 16)
488
			return -EINVAL;
489
		palette = (u32 *)info->pseudo_palette;
490
		red >>= (16 - info->var.red.length);
491
		green >>= (16 - info->var.green.length);
492
		blue >>= (16 - info->var.blue.length);
493
		value = (red << info->var.red.offset) |
494
			(green << info->var.green.offset) |
495
			(blue << info->var.blue.offset);
1963 serge 496
		if (info->var.transp.length > 0) {
497
			u32 mask = (1 << info->var.transp.length) - 1;
498
			mask <<= info->var.transp.offset;
499
			value |= mask;
500
		}
1246 serge 501
		palette[regno] = value;
502
		return 0;
503
	}
504
 
4104 Serge 505
	/*
506
	 * The driver really shouldn't advertise pseudo/directcolor
507
	 * visuals if it can't deal with the palette.
508
	 */
509
	if (WARN_ON(!fb_helper->funcs->gamma_set ||
510
		    !fb_helper->funcs->gamma_get))
511
		return -EINVAL;
512
 
1221 serge 513
	pindex = regno;
514
 
515
	if (fb->bits_per_pixel == 16) {
516
		pindex = regno << 3;
517
 
518
		if (fb->depth == 16 && regno > 63)
1246 serge 519
			return -EINVAL;
1221 serge 520
		if (fb->depth == 15 && regno > 31)
1246 serge 521
			return -EINVAL;
1221 serge 522
 
523
		if (fb->depth == 16) {
524
			u16 r, g, b;
525
			int i;
526
			if (regno < 32) {
527
				for (i = 0; i < 8; i++)
528
					fb_helper->funcs->gamma_set(crtc, red,
529
						green, blue, pindex + i);
530
			}
531
 
532
			fb_helper->funcs->gamma_get(crtc, &r,
533
						    &g, &b,
534
						    pindex >> 1);
535
 
536
			for (i = 0; i < 4; i++)
537
				fb_helper->funcs->gamma_set(crtc, r,
538
							    green, b,
539
							    (pindex >> 1) + i);
540
		}
541
	}
542
 
543
	if (fb->depth != 16)
544
		fb_helper->funcs->gamma_set(crtc, red, green, blue, pindex);
1246 serge 545
	return 0;
1221 serge 546
}
547
 
3480 Serge 548
/**
549
 * drm_fb_helper_setcmap - implementation for ->fb_setcmap
550
 * @cmap: cmap to set
551
 * @info: fbdev registered by the helper
552
 */
1221 serge 553
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
554
{
555
	struct drm_fb_helper *fb_helper = info->par;
4104 Serge 556
	struct drm_device *dev = fb_helper->dev;
1963 serge 557
	struct drm_crtc_helper_funcs *crtc_funcs;
1221 serge 558
	u16 *red, *green, *blue, *transp;
559
	struct drm_crtc *crtc;
1963 serge 560
	int i, j, rc = 0;
1221 serge 561
	int start;
562
 
4104 Serge 563
	drm_modeset_lock_all(dev);
564
	if (!drm_fb_helper_is_bound(fb_helper)) {
565
		drm_modeset_unlock_all(dev);
566
		return -EBUSY;
567
	}
568
 
1221 serge 569
		for (i = 0; i < fb_helper->crtc_count; i++) {
1963 serge 570
		crtc = fb_helper->crtc_info[i].mode_set.crtc;
571
		crtc_funcs = crtc->helper_private;
1221 serge 572
 
573
		red = cmap->red;
574
		green = cmap->green;
575
		blue = cmap->blue;
576
		transp = cmap->transp;
577
		start = cmap->start;
578
 
1963 serge 579
		for (j = 0; j < cmap->len; j++) {
1221 serge 580
			u16 hred, hgreen, hblue, htransp = 0xffff;
581
 
582
			hred = *red++;
583
			hgreen = *green++;
584
			hblue = *blue++;
585
 
586
			if (transp)
587
				htransp = *transp++;
588
 
1246 serge 589
			rc = setcolreg(crtc, hred, hgreen, hblue, start++, info);
590
			if (rc)
4104 Serge 591
				goto out;
1221 serge 592
		}
4104 Serge 593
		if (crtc_funcs->load_lut)
1221 serge 594
		crtc_funcs->load_lut(crtc);
595
	}
4104 Serge 596
 out:
597
	drm_modeset_unlock_all(dev);
1221 serge 598
	return rc;
599
}
600
EXPORT_SYMBOL(drm_fb_helper_setcmap);
601
 
3480 Serge 602
/**
603
 * drm_fb_helper_check_var - implementation for ->fb_check_var
604
 * @var: screeninfo to check
605
 * @info: fbdev registered by the helper
606
 */
1179 serge 607
int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
608
			    struct fb_info *info)
609
{
610
	struct drm_fb_helper *fb_helper = info->par;
611
	struct drm_framebuffer *fb = fb_helper->fb;
612
	int depth;
613
 
1963 serge 614
	if (var->pixclock != 0 || in_dbg_master())
1179 serge 615
		return -EINVAL;
616
 
617
	/* Need to resize the fb object !!! */
3031 serge 618
	if (var->bits_per_pixel > fb->bits_per_pixel ||
619
	    var->xres > fb->width || var->yres > fb->height ||
620
	    var->xres_virtual > fb->width || var->yres_virtual > fb->height) {
1404 serge 621
		DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb "
3031 serge 622
			  "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n",
623
			  var->xres, var->yres, var->bits_per_pixel,
624
			  var->xres_virtual, var->yres_virtual,
1404 serge 625
			  fb->width, fb->height, fb->bits_per_pixel);
1179 serge 626
		return -EINVAL;
627
	}
628
 
629
	switch (var->bits_per_pixel) {
630
	case 16:
631
		depth = (var->green.length == 6) ? 16 : 15;
632
		break;
633
	case 32:
634
		depth = (var->transp.length > 0) ? 32 : 24;
635
		break;
636
	default:
637
		depth = var->bits_per_pixel;
638
		break;
639
	}
640
 
641
	switch (depth) {
642
	case 8:
643
		var->red.offset = 0;
644
		var->green.offset = 0;
645
		var->blue.offset = 0;
646
		var->red.length = 8;
647
		var->green.length = 8;
648
		var->blue.length = 8;
649
		var->transp.length = 0;
650
		var->transp.offset = 0;
651
		break;
652
	case 15:
653
		var->red.offset = 10;
654
		var->green.offset = 5;
655
		var->blue.offset = 0;
656
		var->red.length = 5;
657
		var->green.length = 5;
658
		var->blue.length = 5;
659
		var->transp.length = 1;
660
		var->transp.offset = 15;
661
		break;
662
	case 16:
663
		var->red.offset = 11;
664
		var->green.offset = 5;
665
		var->blue.offset = 0;
666
		var->red.length = 5;
667
		var->green.length = 6;
668
		var->blue.length = 5;
669
		var->transp.length = 0;
670
		var->transp.offset = 0;
671
		break;
672
	case 24:
673
		var->red.offset = 16;
674
		var->green.offset = 8;
675
		var->blue.offset = 0;
676
		var->red.length = 8;
677
		var->green.length = 8;
678
		var->blue.length = 8;
679
		var->transp.length = 0;
680
		var->transp.offset = 0;
681
		break;
682
	case 32:
683
		var->red.offset = 16;
684
		var->green.offset = 8;
685
		var->blue.offset = 0;
686
		var->red.length = 8;
687
		var->green.length = 8;
688
		var->blue.length = 8;
689
		var->transp.length = 8;
690
		var->transp.offset = 24;
691
		break;
692
	default:
693
		return -EINVAL;
694
	}
695
	return 0;
696
}
697
EXPORT_SYMBOL(drm_fb_helper_check_var);
698
 
3480 Serge 699
/**
700
 * drm_fb_helper_set_par - implementation for ->fb_set_par
701
 * @info: fbdev registered by the helper
702
 *
703
 * This will let fbcon do the mode init and is called at initialization time by
704
 * the fbdev core when registering the driver, and later on through the hotplug
705
 * callback.
706
 */
1179 serge 707
int drm_fb_helper_set_par(struct fb_info *info)
708
{
709
	struct drm_fb_helper *fb_helper = info->par;
710
	struct fb_var_screeninfo *var = &info->var;
711
 
1313 serge 712
	if (var->pixclock != 0) {
1430 serge 713
		DRM_ERROR("PIXEL CLOCK SET\n");
1179 serge 714
		return -EINVAL;
715
	}
716
 
5060 serge 717
	drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
1963 serge 718
 
1179 serge 719
	return 0;
720
}
721
EXPORT_SYMBOL(drm_fb_helper_set_par);
722
 
3480 Serge 723
/**
724
 * drm_fb_helper_pan_display - implementation for ->fb_pan_display
725
 * @var: updated screen information
726
 * @info: fbdev registered by the helper
727
 */
1179 serge 728
int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
729
			      struct fb_info *info)
730
{
731
	struct drm_fb_helper *fb_helper = info->par;
732
	struct drm_device *dev = fb_helper->dev;
733
	struct drm_mode_set *modeset;
734
	int ret = 0;
735
	int i;
736
 
3480 Serge 737
	drm_modeset_lock_all(dev);
738
	if (!drm_fb_helper_is_bound(fb_helper)) {
739
		drm_modeset_unlock_all(dev);
740
		return -EBUSY;
741
	}
742
 
1179 serge 743
		for (i = 0; i < fb_helper->crtc_count; i++) {
744
		modeset = &fb_helper->crtc_info[i].mode_set;
745
 
746
		modeset->x = var->xoffset;
747
		modeset->y = var->yoffset;
748
 
749
		if (modeset->num_connectors) {
3480 Serge 750
			ret = drm_mode_set_config_internal(modeset);
1179 serge 751
			if (!ret) {
752
				info->var.xoffset = var->xoffset;
753
				info->var.yoffset = var->yoffset;
754
			}
755
		}
756
	}
3480 Serge 757
	drm_modeset_unlock_all(dev);
1179 serge 758
	return ret;
759
}
760
EXPORT_SYMBOL(drm_fb_helper_pan_display);
761
 
3480 Serge 762
/*
763
 * Allocates the backing storage and sets up the fbdev info structure through
764
 * the ->fb_probe callback and then registers the fbdev and sets up the panic
765
 * notifier.
766
 */
767
static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
1963 serge 768
				  int preferred_bpp)
1179 serge 769
{
3480 Serge 770
	int ret = 0;
1179 serge 771
	int crtc_count = 0;
1963 serge 772
	int i;
1179 serge 773
	struct fb_info *info;
1963 serge 774
	struct drm_fb_helper_surface_size sizes;
775
	int gamma_size = 0;
1179 serge 776
 
1963 serge 777
	memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
778
	sizes.surface_depth = 24;
779
	sizes.surface_bpp = 32;
780
	sizes.fb_width = (unsigned)-1;
781
	sizes.fb_height = (unsigned)-1;
1221 serge 782
 
3031 serge 783
	/* if driver picks 8 or 16 by default use that
784
	   for both depth/bpp */
3192 Serge 785
	if (preferred_bpp != sizes.surface_bpp)
3031 serge 786
		sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
3192 Serge 787
 
3031 serge 788
	/* first up get a count of crtcs now in use and new min/maxes width/heights */
789
	for (i = 0; i < fb_helper->connector_count; i++) {
790
		struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
791
		struct drm_cmdline_mode *cmdline_mode;
792
 
5271 serge 793
		cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
3031 serge 794
 
795
		if (cmdline_mode->bpp_specified) {
796
			switch (cmdline_mode->bpp) {
797
			case 8:
798
				sizes.surface_depth = sizes.surface_bpp = 8;
799
				break;
800
			case 15:
801
				sizes.surface_depth = 15;
802
				sizes.surface_bpp = 16;
803
				break;
804
			case 16:
805
				sizes.surface_depth = sizes.surface_bpp = 16;
806
				break;
807
			case 24:
808
				sizes.surface_depth = sizes.surface_bpp = 24;
809
				break;
810
			case 32:
1963 serge 811
    sizes.surface_depth = 24;
812
    sizes.surface_bpp = 32;
3031 serge 813
				break;
814
			}
815
			break;
816
		}
817
	}
1221 serge 818
 
1963 serge 819
	crtc_count = 0;
820
	for (i = 0; i < fb_helper->crtc_count; i++) {
821
		struct drm_display_mode *desired_mode;
5271 serge 822
		int x, y;
1963 serge 823
		desired_mode = fb_helper->crtc_info[i].desired_mode;
5271 serge 824
		x = fb_helper->crtc_info[i].x;
825
		y = fb_helper->crtc_info[i].y;
1963 serge 826
		if (desired_mode) {
827
			if (gamma_size == 0)
828
				gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
5271 serge 829
			if (desired_mode->hdisplay + x < sizes.fb_width)
830
				sizes.fb_width = desired_mode->hdisplay + x;
831
			if (desired_mode->vdisplay + y < sizes.fb_height)
832
				sizes.fb_height = desired_mode->vdisplay + y;
833
			if (desired_mode->hdisplay + x > sizes.surface_width)
834
				sizes.surface_width = desired_mode->hdisplay + x;
835
			if (desired_mode->vdisplay + y > sizes.surface_height)
836
				sizes.surface_height = desired_mode->vdisplay + y;
1179 serge 837
			crtc_count++;
4539 Serge 838
       }
1179 serge 839
	}
840
 
1963 serge 841
	if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
1179 serge 842
		/* hmm everyone went away - assume VGA cable just fell out
843
		   and will come back later. */
1963 serge 844
		DRM_INFO("Cannot find any crtc or sizes - going 1024x768\n");
845
		sizes.fb_width = sizes.surface_width = 1024;
846
		sizes.fb_height = sizes.surface_height = 768;
1179 serge 847
	}
848
 
1963 serge 849
	/* push down into drivers */
3480 Serge 850
	ret = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
851
	if (ret < 0)
852
		return ret;
1179 serge 853
 
1963 serge 854
	info = fb_helper->fbdev;
1179 serge 855
 
3480 Serge 856
	/*
857
	 * Set the fb pointer - usually drm_setup_crtcs does this for hotplug
858
	 * events, but at init time drm_setup_crtcs needs to be called before
859
	 * the fb is allocated (since we need to figure out the desired size of
860
	 * the fb before we can allocate it ...). Hence we need to fix things up
861
	 * here again.
862
	 */
3192 Serge 863
	for (i = 0; i < fb_helper->crtc_count; i++)
3480 Serge 864
		if (fb_helper->crtc_info[i].mode_set.num_connectors)
1963 serge 865
		fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
1179 serge 866
 
3480 Serge 867
 
1313 serge 868
		info->var.pixclock = 0;
5271 serge 869
	dev_info(fb_helper->dev->dev, "fb%d: %s frame buffer device\n",
870
			info->node, info->fix.id);
1963 serge 871
 
872
        list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
873
 
1179 serge 874
	return 0;
875
}
876
 
3480 Serge 877
/**
878
 * drm_fb_helper_fill_fix - initializes fixed fbdev information
879
 * @info: fbdev registered by the helper
880
 * @pitch: desired pitch
881
 * @depth: desired depth
882
 *
883
 * Helper to fill in the fixed fbdev information useful for a non-accelerated
884
 * fbdev emulations. Drivers which support acceleration methods which impose
885
 * additional constraints need to set up their own limits.
886
 *
887
 * Drivers should call this (or their equivalent setup code) from their
888
 * ->fb_probe callback.
889
 */
1221 serge 890
void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
891
			    uint32_t depth)
1179 serge 892
{
893
	info->fix.type = FB_TYPE_PACKED_PIXELS;
1221 serge 894
	info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
1246 serge 895
		FB_VISUAL_TRUECOLOR;
1963 serge 896
	info->fix.mmio_start = 0;
897
	info->fix.mmio_len = 0;
1179 serge 898
	info->fix.type_aux = 0;
899
	info->fix.xpanstep = 1; /* doing it in hw */
900
	info->fix.ypanstep = 1; /* doing it in hw */
901
	info->fix.ywrapstep = 0;
902
	info->fix.accel = FB_ACCEL_NONE;
903
 
904
	info->fix.line_length = pitch;
905
	return;
906
}
907
EXPORT_SYMBOL(drm_fb_helper_fill_fix);
908
 
3480 Serge 909
/**
910
 * drm_fb_helper_fill_var - initalizes variable fbdev information
911
 * @info: fbdev instance to set up
912
 * @fb_helper: fb helper instance to use as template
913
 * @fb_width: desired fb width
914
 * @fb_height: desired fb height
915
 *
916
 * Sets up the variable fbdev metainformation from the given fb helper instance
917
 * and the drm framebuffer allocated in fb_helper->fb.
918
 *
919
 * Drivers should call this (or their equivalent setup code) from their
920
 * ->fb_probe callback after having allocated the fbdev backing
921
 * storage framebuffer.
922
 */
1963 serge 923
void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
1179 serge 924
			    uint32_t fb_width, uint32_t fb_height)
925
{
1963 serge 926
	struct drm_framebuffer *fb = fb_helper->fb;
927
	info->pseudo_palette = fb_helper->pseudo_palette;
1179 serge 928
	info->var.xres_virtual = fb->width;
929
	info->var.yres_virtual = fb->height;
930
	info->var.bits_per_pixel = fb->bits_per_pixel;
1963 serge 931
	info->var.accel_flags = FB_ACCELF_TEXT;
1179 serge 932
	info->var.xoffset = 0;
933
	info->var.yoffset = 0;
934
	info->var.activate = FB_ACTIVATE_NOW;
935
	info->var.height = -1;
936
	info->var.width = -1;
937
 
938
	switch (fb->depth) {
939
	case 8:
940
		info->var.red.offset = 0;
941
		info->var.green.offset = 0;
942
		info->var.blue.offset = 0;
943
		info->var.red.length = 8; /* 8bit DAC */
944
		info->var.green.length = 8;
945
		info->var.blue.length = 8;
946
		info->var.transp.offset = 0;
947
		info->var.transp.length = 0;
948
		break;
949
	case 15:
950
		info->var.red.offset = 10;
951
		info->var.green.offset = 5;
952
		info->var.blue.offset = 0;
953
		info->var.red.length = 5;
954
		info->var.green.length = 5;
955
		info->var.blue.length = 5;
956
		info->var.transp.offset = 15;
957
		info->var.transp.length = 1;
958
		break;
959
	case 16:
960
		info->var.red.offset = 11;
961
		info->var.green.offset = 5;
962
		info->var.blue.offset = 0;
963
		info->var.red.length = 5;
964
		info->var.green.length = 6;
965
		info->var.blue.length = 5;
966
		info->var.transp.offset = 0;
967
		break;
968
	case 24:
969
		info->var.red.offset = 16;
970
		info->var.green.offset = 8;
971
		info->var.blue.offset = 0;
972
		info->var.red.length = 8;
973
		info->var.green.length = 8;
974
		info->var.blue.length = 8;
975
		info->var.transp.offset = 0;
976
		info->var.transp.length = 0;
977
		break;
978
	case 32:
979
		info->var.red.offset = 16;
980
		info->var.green.offset = 8;
981
		info->var.blue.offset = 0;
982
		info->var.red.length = 8;
983
		info->var.green.length = 8;
984
		info->var.blue.length = 8;
985
		info->var.transp.offset = 24;
986
		info->var.transp.length = 8;
987
		break;
988
	default:
989
		break;
990
	}
991
 
992
	info->var.xres = fb_width;
993
	info->var.yres = fb_height;
994
}
995
EXPORT_SYMBOL(drm_fb_helper_fill_var);
1963 serge 996
 
997
static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
998
					       uint32_t maxX,
999
					       uint32_t maxY)
1000
{
1001
	struct drm_connector *connector;
1002
	int count = 0;
1003
	int i;
1004
 
1005
	for (i = 0; i < fb_helper->connector_count; i++) {
1006
		connector = fb_helper->connector_info[i]->connector;
1007
		count += connector->funcs->fill_modes(connector, maxX, maxY);
1008
	}
1009
 
1010
	return count;
1011
}
1012
 
5060 serge 1013
struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height)
1963 serge 1014
{
1015
	struct drm_display_mode *mode;
1016
 
1017
	list_for_each_entry(mode, &fb_connector->connector->modes, head) {
5060 serge 1018
		if (mode->hdisplay > width ||
1019
		    mode->vdisplay > height)
1963 serge 1020
			continue;
1021
		if (mode->type & DRM_MODE_TYPE_PREFERRED)
1022
			return mode;
1023
	}
1024
	return NULL;
1025
}
5060 serge 1026
EXPORT_SYMBOL(drm_has_preferred_mode);
1963 serge 1027
 
1028
static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
1029
{
5271 serge 1030
	return fb_connector->connector->cmdline_mode.specified;
1963 serge 1031
}
1032
 
5060 serge 1033
struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
3746 Serge 1034
						      int width, int height)
1035
{
1036
	struct drm_cmdline_mode *cmdline_mode;
1037
	struct drm_display_mode *mode = NULL;
5060 serge 1038
	bool prefer_non_interlace;
1963 serge 1039
 
3746 Serge 1040
	return NULL;
1041
 
1042
	if (cmdline_mode->specified == false)
1043
		return mode;
1044
 
1045
	/* attempt to find a matching mode in the list of modes
1046
	 *  we have gotten so far, if not add a CVT mode that conforms
1047
	 */
1048
	if (cmdline_mode->rb || cmdline_mode->margins)
1049
		goto create_mode;
1050
 
5060 serge 1051
	prefer_non_interlace = !cmdline_mode->interlace;
1052
 again:
3746 Serge 1053
	list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
1054
		/* check width/height */
1055
		if (mode->hdisplay != cmdline_mode->xres ||
1056
		    mode->vdisplay != cmdline_mode->yres)
1057
			continue;
1058
 
1059
		if (cmdline_mode->refresh_specified) {
1060
			if (mode->vrefresh != cmdline_mode->refresh)
1061
				continue;
1062
		}
1063
 
1064
		if (cmdline_mode->interlace) {
1065
			if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
1066
				continue;
5060 serge 1067
		} else if (prefer_non_interlace) {
1068
			if (mode->flags & DRM_MODE_FLAG_INTERLACE)
1069
				continue;
3746 Serge 1070
		}
1071
		return mode;
1072
	}
1073
 
5060 serge 1074
	if (prefer_non_interlace) {
1075
		prefer_non_interlace = false;
1076
		goto again;
1077
	}
1078
 
3746 Serge 1079
create_mode:
1080
	mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
1081
						 cmdline_mode);
1082
	list_add(&mode->head, &fb_helper_conn->connector->modes);
1083
	return mode;
1084
}
5060 serge 1085
EXPORT_SYMBOL(drm_pick_cmdline_mode);
3746 Serge 1086
 
1963 serge 1087
static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
1088
{
1089
	bool enable;
1090
 
3192 Serge 1091
	if (strict)
1963 serge 1092
		enable = connector->status == connector_status_connected;
3192 Serge 1093
	else
1963 serge 1094
		enable = connector->status != connector_status_disconnected;
3192 Serge 1095
 
1963 serge 1096
	return enable;
1097
}
1098
 
1099
static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
1100
				  bool *enabled)
1101
{
1102
	bool any_enabled = false;
1103
	struct drm_connector *connector;
1104
	int i = 0;
1105
 
1106
	for (i = 0; i < fb_helper->connector_count; i++) {
1107
		connector = fb_helper->connector_info[i]->connector;
1108
		enabled[i] = drm_connector_enabled(connector, true);
1109
		DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
1110
			  enabled[i] ? "yes" : "no");
1111
		any_enabled |= enabled[i];
1112
	}
1113
 
1114
	if (any_enabled)
1115
		return;
1116
 
1117
	for (i = 0; i < fb_helper->connector_count; i++) {
1118
		connector = fb_helper->connector_info[i]->connector;
1119
		enabled[i] = drm_connector_enabled(connector, false);
1120
	}
1121
}
1122
 
3746 Serge 1123
static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
1124
			      struct drm_display_mode **modes,
5271 serge 1125
			      struct drm_fb_offset *offsets,
3746 Serge 1126
			      bool *enabled, int width, int height)
1127
{
1128
	int count, i, j;
1129
	bool can_clone = false;
1130
	struct drm_fb_helper_connector *fb_helper_conn;
1131
	struct drm_display_mode *dmt_mode, *mode;
1963 serge 1132
 
3746 Serge 1133
	/* only contemplate cloning in the single crtc case */
1134
	if (fb_helper->crtc_count > 1)
1135
		return false;
1136
 
1137
	count = 0;
1138
	for (i = 0; i < fb_helper->connector_count; i++) {
1139
		if (enabled[i])
1140
			count++;
1141
	}
1142
 
1143
	/* only contemplate cloning if more than one connector is enabled */
1144
	if (count <= 1)
1145
		return false;
1146
 
1147
	/* check the command line or if nothing common pick 1024x768 */
1148
	can_clone = true;
1149
	for (i = 0; i < fb_helper->connector_count; i++) {
1150
		if (!enabled[i])
1151
			continue;
1152
		fb_helper_conn = fb_helper->connector_info[i];
1153
		modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
1154
		if (!modes[i]) {
1155
			can_clone = false;
1156
			break;
1157
		}
1158
		for (j = 0; j < i; j++) {
1159
			if (!enabled[j])
1160
				continue;
1161
			if (!drm_mode_equal(modes[j], modes[i]))
1162
				can_clone = false;
1163
		}
1164
	}
1165
 
1166
	if (can_clone) {
1167
		DRM_DEBUG_KMS("can clone using command line\n");
1168
		return true;
1169
	}
1170
 
1171
	/* try and find a 1024x768 mode on each connector */
1172
	can_clone = true;
1173
	dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60, false);
1174
 
1175
	for (i = 0; i < fb_helper->connector_count; i++) {
1176
 
1177
		if (!enabled[i])
1178
			continue;
1179
 
1180
		fb_helper_conn = fb_helper->connector_info[i];
1181
		list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
1182
			if (drm_mode_equal(mode, dmt_mode))
1183
				modes[i] = mode;
1184
		}
1185
		if (!modes[i])
1186
			can_clone = false;
1187
	}
1188
 
1189
	if (can_clone) {
1190
		DRM_DEBUG_KMS("can clone using 1024x768\n");
1191
		return true;
1192
	}
1193
	DRM_INFO("kms: can't enable cloning when we probably wanted to.\n");
1194
	return false;
1195
}
1196
 
5271 serge 1197
static int drm_get_tile_offsets(struct drm_fb_helper *fb_helper,
1198
				struct drm_display_mode **modes,
1199
				struct drm_fb_offset *offsets,
1200
				int idx,
1201
				int h_idx, int v_idx)
1202
{
1203
	struct drm_fb_helper_connector *fb_helper_conn;
1204
	int i;
1205
	int hoffset = 0, voffset = 0;
1206
 
1207
	for (i = 0; i < fb_helper->connector_count; i++) {
1208
		fb_helper_conn = fb_helper->connector_info[i];
1209
		if (!fb_helper_conn->connector->has_tile)
1210
			continue;
1211
 
1212
		if (!modes[i] && (h_idx || v_idx)) {
1213
			DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i,
1214
				      fb_helper_conn->connector->base.id);
1215
			continue;
1216
		}
1217
		if (fb_helper_conn->connector->tile_h_loc < h_idx)
1218
			hoffset += modes[i]->hdisplay;
1219
 
1220
		if (fb_helper_conn->connector->tile_v_loc < v_idx)
1221
			voffset += modes[i]->vdisplay;
1222
	}
1223
	offsets[idx].x = hoffset;
1224
	offsets[idx].y = voffset;
1225
	DRM_DEBUG_KMS("returned %d %d for %d %d\n", hoffset, voffset, h_idx, v_idx);
1226
	return 0;
1227
}
1228
 
1963 serge 1229
static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
1230
				 struct drm_display_mode **modes,
5271 serge 1231
				 struct drm_fb_offset *offsets,
1963 serge 1232
				 bool *enabled, int width, int height)
1233
{
1234
	struct drm_fb_helper_connector *fb_helper_conn;
1235
	int i;
5271 serge 1236
	uint64_t conn_configured = 0, mask;
1237
	int tile_pass = 0;
1238
	mask = (1 << fb_helper->connector_count) - 1;
1239
retry:
1963 serge 1240
	for (i = 0; i < fb_helper->connector_count; i++) {
1241
		fb_helper_conn = fb_helper->connector_info[i];
1242
 
5271 serge 1243
		if (conn_configured & (1 << i))
1963 serge 1244
			continue;
1245
 
5271 serge 1246
		if (enabled[i] == false) {
1247
			conn_configured |= (1 << i);
1248
			continue;
1249
		}
1250
 
1251
		/* first pass over all the untiled connectors */
1252
		if (tile_pass == 0 && fb_helper_conn->connector->has_tile)
1253
			continue;
1254
 
1255
		if (tile_pass == 1) {
1256
			if (fb_helper_conn->connector->tile_h_loc != 0 ||
1257
			    fb_helper_conn->connector->tile_v_loc != 0)
1258
			continue;
1259
 
1260
		} else {
1261
			if (fb_helper_conn->connector->tile_h_loc != tile_pass -1 &&
1262
			    fb_helper_conn->connector->tile_v_loc != tile_pass - 1)
1263
			/* if this tile_pass doesn't cover any of the tiles - keep going */
1264
				continue;
1265
 
1266
			/* find the tile offsets for this pass - need
1267
			   to find all tiles left and above */
1268
			drm_get_tile_offsets(fb_helper, modes, offsets,
1269
					     i, fb_helper_conn->connector->tile_h_loc, fb_helper_conn->connector->tile_v_loc);
1270
		}
1963 serge 1271
		DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
1272
			      fb_helper_conn->connector->base.id);
1273
 
1274
		/* got for command line mode first */
3746 Serge 1275
		modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
1963 serge 1276
		if (!modes[i]) {
5271 serge 1277
			DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n",
1278
				      fb_helper_conn->connector->base.id, fb_helper_conn->connector->tile_group ? fb_helper_conn->connector->tile_group->id : 0);
1963 serge 1279
			modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height);
1280
		}
1281
		/* No preferred modes, pick one off the list */
1282
		if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) {
1283
			list_for_each_entry(modes[i], &fb_helper_conn->connector->modes, head)
1284
				break;
1285
		}
1286
		DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
1287
			  "none");
5271 serge 1288
		conn_configured |= (1 << i);
1963 serge 1289
	}
5271 serge 1290
 
1291
	if ((conn_configured & mask) != mask) {
1292
		tile_pass++;
1293
		goto retry;
1294
	}
1963 serge 1295
	return true;
1296
}
1297
 
1298
static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
1299
			  struct drm_fb_helper_crtc **best_crtcs,
1300
			  struct drm_display_mode **modes,
1301
			  int n, int width, int height)
1302
{
1303
	int c, o;
1304
	struct drm_device *dev = fb_helper->dev;
1305
	struct drm_connector *connector;
1306
	struct drm_connector_helper_funcs *connector_funcs;
1307
	struct drm_encoder *encoder;
1308
	int my_score, best_score, score;
1309
	struct drm_fb_helper_crtc **crtcs, *crtc;
1310
	struct drm_fb_helper_connector *fb_helper_conn;
1311
 
1312
	if (n == fb_helper->connector_count)
1313
		return 0;
1314
 
1315
	fb_helper_conn = fb_helper->connector_info[n];
1316
	connector = fb_helper_conn->connector;
1317
 
1318
	best_crtcs[n] = NULL;
1319
	best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height);
1320
	if (modes[n] == NULL)
1321
		return best_score;
1322
 
1323
	crtcs = kzalloc(dev->mode_config.num_connector *
1324
			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
1325
	if (!crtcs)
1326
		return best_score;
1327
 
1328
	my_score = 1;
1329
	if (connector->status == connector_status_connected)
1330
		my_score++;
1331
	if (drm_has_cmdline_mode(fb_helper_conn))
1332
		my_score++;
1333
	if (drm_has_preferred_mode(fb_helper_conn, width, height))
1334
		my_score++;
1335
 
1336
	connector_funcs = connector->helper_private;
1337
	encoder = connector_funcs->best_encoder(connector);
1338
	if (!encoder)
1339
		goto out;
1340
 
1341
	/* select a crtc for this connector and then attempt to configure
1342
	   remaining connectors */
1343
	for (c = 0; c < fb_helper->crtc_count; c++) {
1344
		crtc = &fb_helper->crtc_info[c];
1345
 
3192 Serge 1346
		if ((encoder->possible_crtcs & (1 << c)) == 0)
1963 serge 1347
			continue;
1348
 
1349
		for (o = 0; o < n; o++)
1350
			if (best_crtcs[o] == crtc)
1351
				break;
1352
 
1353
		if (o < n) {
1354
			/* ignore cloning unless only a single crtc */
1355
			if (fb_helper->crtc_count > 1)
1356
				continue;
1357
 
1358
			if (!drm_mode_equal(modes[o], modes[n]))
1359
				continue;
1360
		}
1361
 
1362
		crtcs[n] = crtc;
1363
		memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *));
1364
		score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1,
1365
						  width, height);
1366
		if (score > best_score) {
1367
			best_score = score;
1368
			memcpy(best_crtcs, crtcs,
1369
			       dev->mode_config.num_connector *
1370
			       sizeof(struct drm_fb_helper_crtc *));
1371
		}
1372
	}
1373
out:
1374
	kfree(crtcs);
1375
	return best_score;
1376
}
1377
 
1378
static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
1379
{
1380
	struct drm_device *dev = fb_helper->dev;
1381
	struct drm_fb_helper_crtc **crtcs;
1382
	struct drm_display_mode **modes;
5271 serge 1383
	struct drm_fb_offset *offsets;
1963 serge 1384
	struct drm_mode_set *modeset;
1385
	bool *enabled;
1386
	int width, height;
3746 Serge 1387
	int i;
1963 serge 1388
 
1389
	DRM_DEBUG_KMS("\n");
1390
 
1391
	width = dev->mode_config.max_width;
1392
	height = dev->mode_config.max_height;
1393
 
1394
	crtcs = kcalloc(dev->mode_config.num_connector,
1395
			sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
1396
	modes = kcalloc(dev->mode_config.num_connector,
1397
			sizeof(struct drm_display_mode *), GFP_KERNEL);
5271 serge 1398
	offsets = kcalloc(dev->mode_config.num_connector,
1399
			  sizeof(struct drm_fb_offset), GFP_KERNEL);
1963 serge 1400
	enabled = kcalloc(dev->mode_config.num_connector,
1401
			  sizeof(bool), GFP_KERNEL);
5271 serge 1402
	if (!crtcs || !modes || !enabled || !offsets) {
3192 Serge 1403
		DRM_ERROR("Memory allocation failed\n");
1404
		goto out;
1405
	}
1963 serge 1406
 
3192 Serge 1407
 
1963 serge 1408
	drm_enable_connectors(fb_helper, enabled);
1409
 
3746 Serge 1410
	if (!(fb_helper->funcs->initial_config &&
1411
	      fb_helper->funcs->initial_config(fb_helper, crtcs, modes,
5271 serge 1412
					       offsets,
3746 Serge 1413
					       enabled, width, height))) {
1414
		memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0]));
1415
		memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0]));
5271 serge 1416
		memset(offsets, 0, dev->mode_config.num_connector*sizeof(offsets[0]));
1963 serge 1417
 
5271 serge 1418
		if (!drm_target_cloned(fb_helper, modes, offsets,
1419
				       enabled, width, height) &&
1420
		    !drm_target_preferred(fb_helper, modes, offsets,
1421
					  enabled, width, height))
1963 serge 1422
			DRM_ERROR("Unable to find initial modes\n");
1423
 
3746 Serge 1424
		DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n",
1425
			      width, height);
1963 serge 1426
 
1427
	drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
3746 Serge 1428
	}
1963 serge 1429
 
1430
	/* need to set the modesets up here for use later */
1431
	/* fill out the connector<->crtc mappings into the modesets */
1432
	for (i = 0; i < fb_helper->crtc_count; i++) {
1433
		modeset = &fb_helper->crtc_info[i].mode_set;
1434
		modeset->num_connectors = 0;
3480 Serge 1435
		modeset->fb = NULL;
1963 serge 1436
	}
1437
 
1438
	for (i = 0; i < fb_helper->connector_count; i++) {
1439
		struct drm_display_mode *mode = modes[i];
1440
		struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
5271 serge 1441
		struct drm_fb_offset *offset = &offsets[i];
1963 serge 1442
		modeset = &fb_crtc->mode_set;
1443
 
1444
		if (mode && fb_crtc) {
5271 serge 1445
			DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
1446
				      mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y);
1963 serge 1447
			fb_crtc->desired_mode = mode;
5271 serge 1448
			fb_crtc->x = offset->x;
1449
			fb_crtc->y = offset->y;
1963 serge 1450
			if (modeset->mode)
1451
				drm_mode_destroy(dev, modeset->mode);
1452
			modeset->mode = drm_mode_duplicate(dev,
1453
							   fb_crtc->desired_mode);
1454
			modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector;
3480 Serge 1455
			modeset->fb = fb_helper->fb;
5271 serge 1456
			modeset->x = offset->x;
1457
			modeset->y = offset->y;
1963 serge 1458
		}
1459
	}
1460
 
3480 Serge 1461
	/* Clear out any old modes if there are no more connected outputs. */
1462
	for (i = 0; i < fb_helper->crtc_count; i++) {
1463
		modeset = &fb_helper->crtc_info[i].mode_set;
1464
		if (modeset->num_connectors == 0) {
1465
			BUG_ON(modeset->fb);
1466
			if (modeset->mode)
1467
				drm_mode_destroy(dev, modeset->mode);
1468
			modeset->mode = NULL;
1469
		}
1470
	}
3192 Serge 1471
out:
1963 serge 1472
	kfree(crtcs);
1473
	kfree(modes);
5271 serge 1474
	kfree(offsets);
1963 serge 1475
	kfree(enabled);
1476
}
1477
 
1478
/**
3480 Serge 1479
 * drm_fb_helper_initial_config - setup a sane initial connector configuration
3192 Serge 1480
 * @fb_helper: fb_helper device struct
1481
 * @bpp_sel: bpp value to use for the framebuffer configuration
1963 serge 1482
 *
3192 Serge 1483
 * Scans the CRTCs and connectors and tries to put together an initial setup.
1963 serge 1484
 * At the moment, this is a cloned configuration across all heads with
1485
 * a new framebuffer object as the backing store.
1486
 *
3480 Serge 1487
 * Note that this also registers the fbdev and so allows userspace to call into
1488
 * the driver through the fbdev interfaces.
1489
 *
1490
 * This function will call down into the ->fb_probe callback to let
1491
 * the driver allocate and initialize the fbdev info structure and the drm
1492
 * framebuffer used to back the fbdev. drm_fb_helper_fill_var() and
1493
 * drm_fb_helper_fill_fix() are provided as helpers to setup simple default
1494
 * values for the fbdev info structure.
1495
 *
1963 serge 1496
 * RETURNS:
1497
 * Zero if everything went ok, nonzero otherwise.
1498
 */
1499
bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
1500
{
1501
	struct drm_device *dev = fb_helper->dev;
1502
	int count = 0;
1503
 
5060 serge 1504
	mutex_lock(&dev->mode_config.mutex);
1963 serge 1505
	count = drm_fb_helper_probe_connector_modes(fb_helper,
1506
						    dev->mode_config.max_width,
1507
						    dev->mode_config.max_height);
5060 serge 1508
	mutex_unlock(&dev->mode_config.mutex);
1963 serge 1509
	/*
1510
	 * we shouldn't end up with no modes here.
1511
	 */
3192 Serge 1512
	if (count == 0)
1513
		dev_info(fb_helper->dev->dev, "No connectors reported connected with modes\n");
1514
 
1515
	drm_setup_crtcs(fb_helper);
1516
 
3243 Serge 1517
	return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
3192 Serge 1518
}
1519
EXPORT_SYMBOL(drm_fb_helper_initial_config);
1520
 
1521
/**
1522
 * drm_fb_helper_hotplug_event - respond to a hotplug notification by
1523
 *                               probing all the outputs attached to the fb
1524
 * @fb_helper: the drm_fb_helper
1525
 *
1526
 * Scan the connectors attached to the fb_helper and try to put together a
1527
 * setup after *notification of a change in output configuration.
1528
 *
3480 Serge 1529
 * Called at runtime, takes the mode config locks to be able to check/change the
1530
 * modeset configuration. Must be run from process context (which usually means
1531
 * either the output polling work or a work item launched from the driver's
1532
 * hotplug interrupt).
1533
 *
5060 serge 1534
 * Note that drivers may call this even before calling
1535
 * drm_fb_helper_initial_config but only aftert drm_fb_helper_init. This allows
1536
 * for a race-free fbcon setup and will make sure that the fbdev emulation will
1537
 * not miss any hotplug events.
3480 Serge 1538
 *
3192 Serge 1539
 * RETURNS:
1540
 * 0 on success and a non-zero error code otherwise.
1541
 */
1542
int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
1543
{
1544
	struct drm_device *dev = fb_helper->dev;
4560 Serge 1545
	u32 max_width, max_height;
3192 Serge 1546
 
3480 Serge 1547
	mutex_lock(&fb_helper->dev->mode_config.mutex);
5060 serge 1548
	if (!fb_helper->fb || !drm_fb_helper_is_bound(fb_helper)) {
3192 Serge 1549
		fb_helper->delayed_hotplug = true;
3480 Serge 1550
		mutex_unlock(&fb_helper->dev->mode_config.mutex);
3192 Serge 1551
		return 0;
1552
	}
1553
	DRM_DEBUG_KMS("\n");
1554
 
1555
	max_width = fb_helper->fb->width;
1556
	max_height = fb_helper->fb->height;
1557
 
4560 Serge 1558
	drm_fb_helper_probe_connector_modes(fb_helper, max_width, max_height);
3480 Serge 1559
	mutex_unlock(&fb_helper->dev->mode_config.mutex);
1560
 
1561
	drm_modeset_lock_all(dev);
1963 serge 1562
	drm_setup_crtcs(fb_helper);
3480 Serge 1563
	drm_modeset_unlock_all(dev);
1564
	drm_fb_helper_set_par(fb_helper->fbdev);
1963 serge 1565
 
3480 Serge 1566
	return 0;
1963 serge 1567
}
3192 Serge 1568
EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
1569
 
4560 Serge 1570
/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
1571
 * but the module doesn't depend on any fb console symbols.  At least
1572
 * attempt to load fbcon to avoid leaving the system without a usable console.
1573
 */
1574
#if defined(CONFIG_FRAMEBUFFER_CONSOLE_MODULE) && !defined(CONFIG_EXPERT)
1575
static int __init drm_fb_helper_modinit(void)
1576
{
1577
	const char *name = "fbcon";
1578
	struct module *fbcon;
3192 Serge 1579
 
4560 Serge 1580
	mutex_lock(&module_mutex);
1581
	fbcon = find_module(name);
1582
	mutex_unlock(&module_mutex);
3192 Serge 1583
 
4560 Serge 1584
	if (!fbcon)
1585
		request_module_nowait(name);
1586
	return 0;
1587
}
1588
 
1589
module_init(drm_fb_helper_modinit);
1590
#endif