Subversion Repositories Kolibri OS

Rev

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