Subversion Repositories Kolibri OS

Rev

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