Subversion Repositories Kolibri OS

Rev

Rev 5271 | Rev 6088 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 5271 Rev 6084
Line 36... Line 36...
36
#include 
36
#include 
37
#include 
37
#include 
38
#include 
38
#include 
39
#include 
39
#include 
40
#include 
40
#include 
-
 
41
#include 
-
 
42
#include 
-
 
43
 
-
 
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]");
Line 41... Line 48...
41
 
48
 
Line 42... Line 49...
42
static LIST_HEAD(kernel_fb_helper_list);
49
static LIST_HEAD(kernel_fb_helper_list);
43
 
50
 
Line 54... Line 61...
54
 * drm_fb_helper_initial_config(). Drivers with fancier requirements than the
61
 * drm_fb_helper_initial_config(). Drivers with fancier requirements than the
55
 * default behaviour can override the third step with their own code.
62
 * default behaviour can override the third step with their own code.
56
 * Teardown is done with drm_fb_helper_fini().
63
 * Teardown is done with drm_fb_helper_fini().
57
 *
64
 *
58
 * At runtime drivers should restore the fbdev console by calling
65
 * At runtime drivers should restore the fbdev console by calling
59
 * drm_fb_helper_restore_fbdev_mode() from their ->lastclose callback. They
66
 * drm_fb_helper_restore_fbdev_mode_unlocked() from their ->lastclose callback.
60
 * should also notify the fb helper code from updates to the output
67
 * They should also notify the fb helper code from updates to the output
61
 * configuration by calling drm_fb_helper_hotplug_event(). For easier
68
 * configuration by calling drm_fb_helper_hotplug_event(). For easier
62
 * integration with the output polling code in drm_crtc_helper.c the modeset
69
 * integration with the output polling code in drm_crtc_helper.c the modeset
63
 * code provides a ->output_poll_changed callback.
70
 * code provides a ->output_poll_changed callback.
64
 *
71
 *
65
 * All other functions exported by the fb helper library can be used to
72
 * All other functions exported by the fb helper library can be used to
Line 87... Line 94...
87
 * This functions adds all the available connectors for use with the given
94
 * This functions adds all the available connectors for use with the given
88
 * fb_helper. This is a separate step to allow drivers to freely assign
95
 * fb_helper. This is a separate step to allow drivers to freely assign
89
 * connectors to the fbdev, e.g. if some are reserved for special purposes or
96
 * connectors to the fbdev, e.g. if some are reserved for special purposes or
90
 * not adequate to be used for the fbcon.
97
 * not adequate to be used for the fbcon.
91
 *
98
 *
92
 * Since this is part of the initial setup before the fbdev is published, no
99
 * This function is protected against concurrent connector hotadds/removals
-
 
100
 * using drm_fb_helper_add_one_connector() and
93
 * locking is required.
101
 * drm_fb_helper_remove_one_connector().
94
 */
102
 */
95
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
103
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
96
{
104
{
97
	struct drm_device *dev = fb_helper->dev;
105
	struct drm_device *dev = fb_helper->dev;
98
	struct drm_connector *connector;
106
	struct drm_connector *connector;
99
	int i;
107
	int i;
Line -... Line 108...
-
 
108
 
-
 
109
	if (!drm_fbdev_emulation)
-
 
110
		return 0;
-
 
111
 
100
 
112
	mutex_lock(&dev->mode_config.mutex);
101
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
113
	drm_for_each_connector(connector, dev) {
Line 102... Line 114...
102
		struct drm_fb_helper_connector *fb_helper_connector;
114
		struct drm_fb_helper_connector *fb_helper_connector;
103
 
115
 
104
		fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL);
116
		fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL);
Line 105... Line 117...
105
		if (!fb_helper_connector)
117
		if (!fb_helper_connector)
106
			goto fail;
118
			goto fail;
107
 
119
 
-
 
120
		fb_helper_connector->connector = connector;
108
		fb_helper_connector->connector = connector;
121
		fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector;
109
		fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector;
122
	}
110
	}
123
	mutex_unlock(&dev->mode_config.mutex);
111
	return 0;
124
	return 0;
112
fail:
125
fail:
113
	for (i = 0; i < fb_helper->connector_count; i++) {
126
	for (i = 0; i < fb_helper->connector_count; i++) {
114
		kfree(fb_helper->connector_info[i]);
127
		kfree(fb_helper->connector_info[i]);
-
 
128
		fb_helper->connector_info[i] = NULL;
-
 
129
	}
115
		fb_helper->connector_info[i] = NULL;
130
	fb_helper->connector_count = 0;
116
	}
131
	mutex_unlock(&dev->mode_config.mutex);
117
	fb_helper->connector_count = 0;
132
 
Line 118... Line 133...
118
    return -ENOMEM;
133
	return -ENOMEM;
119
}
134
}
120
EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
135
EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
121
 
136
 
Line -... Line 137...
-
 
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;
122
int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector)
140
	struct drm_fb_helper_connector *fb_helper_connector;
123
{
141
 
124
	struct drm_fb_helper_connector **temp;
142
	if (!drm_fbdev_emulation)
125
	struct drm_fb_helper_connector *fb_helper_connector;
143
		return 0;
126
 
144
 
Line 143... Line 161...
143
	fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector;
161
	fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector;
144
	return 0;
162
	return 0;
145
}
163
}
146
EXPORT_SYMBOL(drm_fb_helper_add_one_connector);
164
EXPORT_SYMBOL(drm_fb_helper_add_one_connector);
Line -... Line 165...
-
 
165
 
-
 
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
}
147
 
193
 
148
int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
194
int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
149
				       struct drm_connector *connector)
195
				       struct drm_connector *connector)
150
{
196
{
151
	struct drm_fb_helper_connector *fb_helper_connector;
197
	struct drm_fb_helper_connector *fb_helper_connector;
Line -... Line 198...
-
 
198
	int i, j;
-
 
199
 
-
 
200
	if (!drm_fbdev_emulation)
152
	int i, j;
201
		return 0;
Line 153... Line 202...
153
 
202
 
154
	WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex));
203
	WARN_ON(!mutex_is_locked(&fb_helper->dev->mode_config.mutex));
155
 
204
 
Line 165... Line 214...
165
	for (j = i + 1; j < fb_helper->connector_count; j++) {
214
	for (j = i + 1; j < fb_helper->connector_count; j++) {
166
		fb_helper->connector_info[j - 1] = fb_helper->connector_info[j];
215
		fb_helper->connector_info[j - 1] = fb_helper->connector_info[j];
167
	}
216
	}
168
	fb_helper->connector_count--;
217
	fb_helper->connector_count--;
169
	kfree(fb_helper_connector);
218
	kfree(fb_helper_connector);
-
 
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
 
170
	return 0;
224
	return 0;
171
}
225
}
172
EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);
226
EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);
Line 173... Line 227...
173
 
227
 
Line 199... Line 253...
199
	b_base = g_base + crtc->gamma_size;
253
	b_base = g_base + crtc->gamma_size;
Line 200... Line 254...
200
 
254
 
201
	crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
255
	crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
Line -... Line 256...
-
 
256
}
-
 
257
 
-
 
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;
-
 
263
 
-
 
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)
-
 
272
{
-
 
273
	struct drm_device *dev = fb_helper->dev;
-
 
274
	struct drm_plane *plane;
-
 
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:
Line -... Line 331...
-
 
331
	drm_atomic_state_clear(state);
-
 
332
	drm_atomic_legacy_backoff(state);
-
 
333
 
202
}
334
	goto retry;
203
 
335
}
204
 
336
 
205
static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper)
337
static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
206
{
-
 
207
	struct drm_device *dev = fb_helper->dev;
338
{
Line 208... Line 339...
208
	struct drm_plane *plane;
339
	struct drm_device *dev = fb_helper->dev;
Line -... Line 340...
-
 
340
	struct drm_plane *plane;
-
 
341
	int i;
-
 
342
 
209
	bool error = false;
343
	drm_warn_on_modeset_not_all_locked(dev);
210
	int i;
344
 
211
 
345
	if (fb_helper->atomic)
Line 212... Line 346...
212
	drm_warn_on_modeset_not_all_locked(dev);
346
		return restore_fbdev_mode_atomic(fb_helper);
213
 
347
 
Line 225... Line 359...
225
	for (i = 0; i < fb_helper->crtc_count; i++) {
359
	for (i = 0; i < fb_helper->crtc_count; i++) {
226
		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
360
		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
227
		struct drm_crtc *crtc = mode_set->crtc;
361
		struct drm_crtc *crtc = mode_set->crtc;
228
		int ret;
362
		int ret;
Line 229... Line 363...
229
 
363
 
-
 
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;
230
		if (crtc->funcs->cursor_set) {
368
		} else if (crtc->funcs->cursor_set) {
231
			ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0);
369
			ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0);
232
			if (ret)
370
			if (ret)
233
				error = true;
371
				return ret;
Line 234... Line 372...
234
		}
372
		}
235
 
373
 
236
		ret = drm_mode_set_config_internal(mode_set);
374
		ret = drm_mode_set_config_internal(mode_set);
237
		if (ret)
375
		if (ret)
-
 
376
			return ret;
238
			error = true;
377
	}
239
	}
378
 
-
 
379
	return 0;
240
	return error;
380
}
241
}
381
 
242
/**
382
/**
243
 * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration
383
 * drm_fb_helper_restore_fbdev_mode_unlocked - restore fbdev configuration
244
 * @fb_helper: fbcon to restore
384
 * @fb_helper: fbcon to restore
245
 *
385
 *
246
 * This should be called from driver's drm ->lastclose callback
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.
-
 
389
 *
247
 * when implementing an fbcon on top of kms using this helper. This ensures that
390
 * RETURNS:
248
 * the user isn't greeted with a black screen when e.g. X dies.
391
 * Zero if everything went ok, negative error code otherwise.
249
 */
392
 */
250
bool drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
393
int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper)
-
 
394
{
251
{
395
	struct drm_device *dev = fb_helper->dev;
-
 
396
	bool do_delayed;
252
	struct drm_device *dev = fb_helper->dev;
397
	int ret;
-
 
398
 
Line 253... Line 399...
253
	bool ret;
399
	if (!drm_fbdev_emulation)
254
	bool do_delayed = false;
400
		return -ENODEV;
-
 
401
 
-
 
402
	drm_modeset_lock_all(dev);
-
 
403
	ret = restore_fbdev_mode(fb_helper);
-
 
404
 
255
 
405
	do_delayed = fb_helper->delayed_hotplug;
-
 
406
	if (do_delayed)
-
 
407
		fb_helper->delayed_hotplug = false;
-
 
408
	drm_modeset_unlock_all(dev);
256
	drm_modeset_lock_all(dev);
409
 
257
	ret = restore_fbdev_mode(fb_helper);
410
	if (do_delayed)
258
	drm_modeset_unlock_all(dev);
411
		drm_fb_helper_hotplug_event(fb_helper);
Line 259... Line 412...
259
	return ret;
412
	return ret;
260
}
413
}
261
EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked);
414
EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode_unlocked);
262
 
415
 
263
static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
416
static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
Line -... Line 417...
-
 
417
{
-
 
418
	struct drm_device *dev = fb_helper->dev;
-
 
419
	struct drm_crtc *crtc;
-
 
420
	int bound = 0, crtcs_bound = 0;
-
 
421
 
264
{
422
	/* Sometimes user space wants everything disabled, so don't steal the
265
	struct drm_device *dev = fb_helper->dev;
423
	 * display if there's a master. */
266
	struct drm_crtc *crtc;
424
	if (dev->primary->master)
267
	int bound = 0, crtcs_bound = 0;
425
		return false;
268
 
426
 
269
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
427
	drm_for_each_crtc(crtc, dev) {
Line 310... Line 468...
310
	struct drm_crtc *crtc;
468
	struct drm_crtc *crtc;
311
	struct drm_connector *connector;
469
	struct drm_connector *connector;
312
	int i, j;
470
	int i, j;
Line 313... Line 471...
313
 
471
 
314
	/*
-
 
315
	 * fbdev->blank can be called from irq context in case of a panic.
-
 
316
	 * Since we already have our own special panic handler which will
-
 
317
	 * restore the fbdev console mode completely, just bail out early.
-
 
318
	 */
-
 
319
 
-
 
320
	/*
472
	/*
321
	 * For each CRTC in this fb, turn the connectors on/off.
473
	 * For each CRTC in this fb, turn the connectors on/off.
322
	 */
474
	 */
323
	drm_modeset_lock_all(dev);
475
	drm_modeset_lock_all(dev);
324
	if (!drm_fb_helper_is_bound(fb_helper)) {
476
	if (!drm_fb_helper_is_bound(fb_helper)) {
Line 348... Line 500...
348
 * @blank: desired blanking state
500
 * @blank: desired blanking state
349
 * @info: fbdev registered by the helper
501
 * @info: fbdev registered by the helper
350
 */
502
 */
351
int drm_fb_helper_blank(int blank, struct fb_info *info)
503
int drm_fb_helper_blank(int blank, struct fb_info *info)
352
{
504
{
-
 
505
	if (oops_in_progress)
-
 
506
		return -EBUSY;
-
 
507
 
353
	switch (blank) {
508
	switch (blank) {
354
	/* Display: On; HSync: On, VSync: On */
509
	/* Display: On; HSync: On, VSync: On */
355
	case FB_BLANK_UNBLANK:
510
	case FB_BLANK_UNBLANK:
356
		drm_fb_helper_dpms(info, DRM_MODE_DPMS_ON);
511
		drm_fb_helper_dpms(info, DRM_MODE_DPMS_ON);
357
		break;
512
		break;
Line 431... Line 586...
431
		       int crtc_count, int max_conn_count)
586
		       int crtc_count, int max_conn_count)
432
{
587
{
433
	struct drm_crtc *crtc;
588
	struct drm_crtc *crtc;
434
	int i;
589
	int i;
Line -... Line 590...
-
 
590
 
-
 
591
	if (!drm_fbdev_emulation)
-
 
592
		return 0;
435
 
593
 
436
	if (!max_conn_count)
594
	if (!max_conn_count)
Line 437... Line 595...
437
		return -EINVAL;
595
		return -EINVAL;
438
 
596
 
Line 459... Line 617...
459
			goto out_free;
617
			goto out_free;
460
		fb_helper->crtc_info[i].mode_set.num_connectors = 0;
618
		fb_helper->crtc_info[i].mode_set.num_connectors = 0;
461
	}
619
	}
Line 462... Line 620...
462
 
620
 
463
	i = 0;
621
	i = 0;
464
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
622
	drm_for_each_crtc(crtc, dev) {
465
		fb_helper->crtc_info[i].mode_set.crtc = crtc;
623
		fb_helper->crtc_info[i].mode_set.crtc = crtc;
466
		i++;
624
		i++;
Line -... Line 625...
-
 
625
	}
-
 
626
 
467
	}
627
	fb_helper->atomic = !!drm_core_check_feature(dev, DRIVER_ATOMIC);
468
 
628
 
469
	return 0;
629
	return 0;
470
out_free:
630
out_free:
471
	drm_fb_helper_crtc_free(fb_helper);
631
	drm_fb_helper_crtc_free(fb_helper);
472
	return -ENOMEM;
632
	return -ENOMEM;
Line -... Line 633...
-
 
633
}
-
 
634
EXPORT_SYMBOL(drm_fb_helper_init);
-
 
635
 
-
 
636
/**
-
 
637
 * drm_fb_helper_alloc_fbi - allocate fb_info and some of its members
-
 
638
 * @fb_helper: driver-allocated fbdev helper
-
 
639
 *
-
 
640
 * A helper to alloc fb_info and the members cmap and apertures. Called
-
 
641
 * by the driver within the fb_probe fb_helper callback function.
-
 
642
 *
-
 
643
 * RETURNS:
-
 
644
 * fb_info pointer if things went okay, pointer containing error code
-
 
645
 * otherwise
-
 
646
 */
-
 
647
struct fb_info *drm_fb_helper_alloc_fbi(struct drm_fb_helper *fb_helper)
-
 
648
{
-
 
649
	struct device *dev = fb_helper->dev->dev;
-
 
650
	struct fb_info *info;
-
 
651
	int ret;
-
 
652
 
-
 
653
	info = framebuffer_alloc(0, dev);
-
 
654
	if (!info)
-
 
655
		return ERR_PTR(-ENOMEM);
-
 
656
 
-
 
657
 
-
 
658
	fb_helper->fbdev = info;
-
 
659
 
-
 
660
	return info;
473
}
661
 
474
EXPORT_SYMBOL(drm_fb_helper_init);
662
}
475
 
663
EXPORT_SYMBOL(drm_fb_helper_alloc_fbi);
476
static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
664
static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
477
		     u16 blue, u16 regno, struct fb_info *info)
665
		     u16 blue, u16 regno, struct fb_info *info)
Line 552... Line 740...
552
 */
740
 */
553
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
741
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
554
{
742
{
555
	struct drm_fb_helper *fb_helper = info->par;
743
	struct drm_fb_helper *fb_helper = info->par;
556
	struct drm_device *dev = fb_helper->dev;
744
	struct drm_device *dev = fb_helper->dev;
557
	struct drm_crtc_helper_funcs *crtc_funcs;
745
	const struct drm_crtc_helper_funcs *crtc_funcs;
558
	u16 *red, *green, *blue, *transp;
746
	u16 *red, *green, *blue, *transp;
559
	struct drm_crtc *crtc;
747
	struct drm_crtc *crtc;
560
	int i, j, rc = 0;
748
	int i, j, rc = 0;
561
	int start;
749
	int start;
Line -... Line 750...
-
 
750
 
-
 
751
	if (oops_in_progress)
-
 
752
		return -EBUSY;
562
 
753
 
563
	drm_modeset_lock_all(dev);
754
	drm_modeset_lock_all(dev);
564
	if (!drm_fb_helper_is_bound(fb_helper)) {
755
	if (!drm_fb_helper_is_bound(fb_helper)) {
565
		drm_modeset_unlock_all(dev);
756
		drm_modeset_unlock_all(dev);
566
		return -EBUSY;
757
		return -EBUSY;
Line 707... Line 898...
707
int drm_fb_helper_set_par(struct fb_info *info)
898
int drm_fb_helper_set_par(struct fb_info *info)
708
{
899
{
709
	struct drm_fb_helper *fb_helper = info->par;
900
	struct drm_fb_helper *fb_helper = info->par;
710
	struct fb_var_screeninfo *var = &info->var;
901
	struct fb_var_screeninfo *var = &info->var;
Line -... Line 902...
-
 
902
 
-
 
903
	if (oops_in_progress)
-
 
904
		return -EBUSY;
711
 
905
 
712
	if (var->pixclock != 0) {
906
	if (var->pixclock != 0) {
713
		DRM_ERROR("PIXEL CLOCK SET\n");
907
		DRM_ERROR("PIXEL CLOCK SET\n");
714
		return -EINVAL;
908
		return -EINVAL;
Line 718... Line 912...
718
 
912
 
719
	return 0;
913
	return 0;
720
}
914
}
Line -... Line 915...
-
 
915
EXPORT_SYMBOL(drm_fb_helper_set_par);
-
 
916
 
-
 
917
static int pan_display_atomic(struct fb_var_screeninfo *var,
-
 
918
			      struct fb_info *info)
-
 
919
{
-
 
920
	struct drm_fb_helper *fb_helper = info->par;
-
 
921
	struct drm_device *dev = fb_helper->dev;
-
 
922
	struct drm_atomic_state *state;
-
 
923
	struct drm_plane *plane;
-
 
924
	int i, ret;
-
 
925
	unsigned plane_mask;
-
 
926
 
-
 
927
	state = drm_atomic_state_alloc(dev);
-
 
928
	if (!state)
-
 
929
		return -ENOMEM;
-
 
930
 
-
 
931
	state->acquire_ctx = dev->mode_config.acquire_ctx;
-
 
932
retry:
-
 
933
	plane_mask = 0;
-
 
934
	for(i = 0; i < fb_helper->crtc_count; i++) {
-
 
935
		struct drm_mode_set *mode_set;
-
 
936
 
-
 
937
		mode_set = &fb_helper->crtc_info[i].mode_set;
-
 
938
 
-
 
939
		mode_set->x = var->xoffset;
-
 
940
		mode_set->y = var->yoffset;
-
 
941
 
-
 
942
		ret = __drm_atomic_helper_set_config(mode_set, state);
-
 
943
		if (ret != 0)
-
 
944
			goto fail;
-
 
945
 
-
 
946
		plane = mode_set->crtc->primary;
-
 
947
		plane_mask |= drm_plane_index(plane);
-
 
948
		plane->old_fb = plane->fb;
-
 
949
	}
-
 
950
 
-
 
951
	ret = drm_atomic_commit(state);
-
 
952
	if (ret != 0)
-
 
953
		goto fail;
-
 
954
 
-
 
955
	info->var.xoffset = var->xoffset;
-
 
956
	info->var.yoffset = var->yoffset;
-
 
957
 
-
 
958
 
-
 
959
fail:
-
 
960
	drm_atomic_clean_old_fb(dev, plane_mask, ret);
-
 
961
 
-
 
962
	if (ret == -EDEADLK)
-
 
963
		goto backoff;
-
 
964
 
-
 
965
	if (ret != 0)
-
 
966
		drm_atomic_state_free(state);
-
 
967
 
-
 
968
	return ret;
-
 
969
 
-
 
970
backoff:
-
 
971
	drm_atomic_state_clear(state);
-
 
972
	drm_atomic_legacy_backoff(state);
-
 
973
 
-
 
974
	goto retry;
721
EXPORT_SYMBOL(drm_fb_helper_set_par);
975
}
722
 
976
 
723
/**
977
/**
724
 * drm_fb_helper_pan_display - implementation for ->fb_pan_display
978
 * drm_fb_helper_pan_display - implementation for ->fb_pan_display
725
 * @var: updated screen information
979
 * @var: updated screen information
Line 732... Line 986...
732
	struct drm_device *dev = fb_helper->dev;
986
	struct drm_device *dev = fb_helper->dev;
733
	struct drm_mode_set *modeset;
987
	struct drm_mode_set *modeset;
734
	int ret = 0;
988
	int ret = 0;
735
	int i;
989
	int i;
Line -... Line 990...
-
 
990
 
-
 
991
	if (oops_in_progress)
-
 
992
		return -EBUSY;
736
 
993
 
737
	drm_modeset_lock_all(dev);
994
	drm_modeset_lock_all(dev);
738
	if (!drm_fb_helper_is_bound(fb_helper)) {
995
	if (!drm_fb_helper_is_bound(fb_helper)) {
739
		drm_modeset_unlock_all(dev);
996
		drm_modeset_unlock_all(dev);
740
		return -EBUSY;
997
		return -EBUSY;
Line -... Line 998...
-
 
998
	}
-
 
999
 
-
 
1000
	if (fb_helper->atomic) {
-
 
1001
		ret = pan_display_atomic(var, info);
-
 
1002
		goto unlock;
741
	}
1003
	}
742
 
1004
 
Line 743... Line 1005...
743
		for (i = 0; i < fb_helper->crtc_count; i++) {
1005
	for (i = 0; i < fb_helper->crtc_count; i++) {
744
		modeset = &fb_helper->crtc_info[i].mode_set;
1006
		modeset = &fb_helper->crtc_info[i].mode_set;
Line 752... Line 1014...
752
				info->var.xoffset = var->xoffset;
1014
				info->var.xoffset = var->xoffset;
753
				info->var.yoffset = var->yoffset;
1015
				info->var.yoffset = var->yoffset;
754
			}
1016
			}
755
		}
1017
		}
756
	}
1018
	}
-
 
1019
unlock:
757
	drm_modeset_unlock_all(dev);
1020
	drm_modeset_unlock_all(dev);
758
	return ret;
1021
	return ret;
759
}
1022
}
760
EXPORT_SYMBOL(drm_fb_helper_pan_display);
1023
EXPORT_SYMBOL(drm_fb_helper_pan_display);
Line 817... Line 1080...
817
	}
1080
	}
Line 818... Line 1081...
818
 
1081
 
819
	crtc_count = 0;
1082
	crtc_count = 0;
820
	for (i = 0; i < fb_helper->crtc_count; i++) {
1083
	for (i = 0; i < fb_helper->crtc_count; i++) {
-
 
1084
		struct drm_display_mode *desired_mode;
821
		struct drm_display_mode *desired_mode;
1085
		struct drm_mode_set *mode_set;
-
 
1086
		int x, y, j;
-
 
1087
		/* in case of tile group, are we the last tile vert or horiz?
-
 
1088
		 * If no tile group you are always the last one both vertically
-
 
1089
		 * and horizontally
-
 
1090
		 */
-
 
1091
		bool lastv = true, lasth = true;
822
		int x, y;
1092
 
-
 
1093
		desired_mode = fb_helper->crtc_info[i].desired_mode;
-
 
1094
		mode_set = &fb_helper->crtc_info[i].mode_set;
-
 
1095
 
-
 
1096
		if (!desired_mode)
-
 
1097
			continue;
-
 
1098
 
-
 
1099
		crtc_count++;
823
		desired_mode = fb_helper->crtc_info[i].desired_mode;
1100
 
824
		x = fb_helper->crtc_info[i].x;
1101
		x = fb_helper->crtc_info[i].x;
825
		y = fb_helper->crtc_info[i].y;
-
 
-
 
1102
		y = fb_helper->crtc_info[i].y;
826
		if (desired_mode) {
1103
 
827
			if (gamma_size == 0)
1104
		if (gamma_size == 0)
-
 
1105
			gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
828
				gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
1106
 
829
			if (desired_mode->hdisplay + x < sizes.fb_width)
1107
		sizes.surface_width  = max_t(u32, desired_mode->hdisplay + x, sizes.surface_width);
-
 
1108
		sizes.surface_height = max_t(u32, desired_mode->vdisplay + y, sizes.surface_height);
830
				sizes.fb_width = desired_mode->hdisplay + x;
1109
 
831
			if (desired_mode->vdisplay + y < sizes.fb_height)
1110
		for (j = 0; j < mode_set->num_connectors; j++) {
832
				sizes.fb_height = desired_mode->vdisplay + y;
1111
			struct drm_connector *connector = mode_set->connectors[j];
833
			if (desired_mode->hdisplay + x > sizes.surface_width)
1112
			if (connector->has_tile) {
834
				sizes.surface_width = desired_mode->hdisplay + x;
1113
				lasth = (connector->tile_h_loc == (connector->num_h_tile - 1));
835
			if (desired_mode->vdisplay + y > sizes.surface_height)
1114
				lastv = (connector->tile_v_loc == (connector->num_v_tile - 1));
836
				sizes.surface_height = desired_mode->vdisplay + y;
1115
				/* cloning to multiple tiles is just crazy-talk, so: */
-
 
1116
				break;
837
			crtc_count++;
1117
			}
-
 
1118
		}
-
 
1119
 
-
 
1120
		if (lasth)
-
 
1121
			sizes.fb_width  = min_t(u32, desired_mode->hdisplay + x, sizes.fb_width);
-
 
1122
		if (lastv)
838
       }
1123
			sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height);
Line 839... Line 1124...
839
	}
1124
	}
840
 
1125
 
841
	if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
1126
	if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
Line 864... Line 1149...
864
		if (fb_helper->crtc_info[i].mode_set.num_connectors)
1149
		if (fb_helper->crtc_info[i].mode_set.num_connectors)
865
		fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
1150
			fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
Line 866... Line 1151...
866
 
1151
 
-
 
1152
 
867
 
1153
	info->var.pixclock = 0;
868
		info->var.pixclock = 0;
1154
 
Line -... Line 1155...
-
 
1155
	dev_info(fb_helper->dev->dev, "fb%d: %s frame buffer device\n",
869
	dev_info(fb_helper->dev->dev, "fb%d: %s frame buffer device\n",
1156
			info->node, info->fix.id);
Line 870... Line 1157...
870
			info->node, info->fix.id);
1157
 
871
 
1158
 
Line 1032... Line 1319...
1032
 
1319
 
1033
struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
1320
struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
1034
						      int width, int height)
1321
						      int width, int height)
1035
{
1322
{
1036
	struct drm_cmdline_mode *cmdline_mode;
1323
	struct drm_cmdline_mode *cmdline_mode;
1037
	struct drm_display_mode *mode = NULL;
1324
	struct drm_display_mode *mode;
Line 1038... Line 1325...
1038
	bool prefer_non_interlace;
1325
	bool prefer_non_interlace;
1039
 
1326
 
-
 
1327
    return NULL;
1040
	return NULL;
1328
#if 0
1041
 
1329
	cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
Line 1042... Line 1330...
1042
	if (cmdline_mode->specified == false)
1330
	if (cmdline_mode->specified == false)
1043
		return mode;
1331
        return NULL;
1044
 
1332
 
1045
	/* attempt to find a matching mode in the list of modes
1333
	/* attempt to find a matching mode in the list of modes
Line 1079... Line 1367...
1079
create_mode:
1367
create_mode:
1080
	mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
1368
	mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
1081
						 cmdline_mode);
1369
						 cmdline_mode);
1082
	list_add(&mode->head, &fb_helper_conn->connector->modes);
1370
	list_add(&mode->head, &fb_helper_conn->connector->modes);
1083
	return mode;
1371
	return mode;
-
 
1372
#endif
1084
}
1373
}
1085
EXPORT_SYMBOL(drm_pick_cmdline_mode);
1374
EXPORT_SYMBOL(drm_pick_cmdline_mode);
Line 1086... Line 1375...
1086
 
1375
 
1087
static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
1376
static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
Line 1301... Line 1590...
1301
			  int n, int width, int height)
1590
			  int n, int width, int height)
1302
{
1591
{
1303
	int c, o;
1592
	int c, o;
1304
	struct drm_device *dev = fb_helper->dev;
1593
	struct drm_device *dev = fb_helper->dev;
1305
	struct drm_connector *connector;
1594
	struct drm_connector *connector;
1306
	struct drm_connector_helper_funcs *connector_funcs;
1595
	const struct drm_connector_helper_funcs *connector_funcs;
1307
	struct drm_encoder *encoder;
1596
	struct drm_encoder *encoder;
1308
	int my_score, best_score, score;
1597
	int my_score, best_score, score;
1309
	struct drm_fb_helper_crtc **crtcs, *crtc;
1598
	struct drm_fb_helper_crtc **crtcs, *crtc;
1310
	struct drm_fb_helper_connector *fb_helper_conn;
1599
	struct drm_fb_helper_connector *fb_helper_conn;
Line 1494... Line 1783...
1494
 * values for the fbdev info structure.
1783
 * values for the fbdev info structure.
1495
 *
1784
 *
1496
 * RETURNS:
1785
 * RETURNS:
1497
 * Zero if everything went ok, nonzero otherwise.
1786
 * Zero if everything went ok, nonzero otherwise.
1498
 */
1787
 */
1499
bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
1788
int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
1500
{
1789
{
1501
	struct drm_device *dev = fb_helper->dev;
1790
	struct drm_device *dev = fb_helper->dev;
1502
	int count = 0;
1791
	int count = 0;
Line -... Line 1792...
-
 
1792
 
-
 
1793
	if (!drm_fbdev_emulation)
-
 
1794
		return 0;
1503
 
1795
 
1504
	mutex_lock(&dev->mode_config.mutex);
1796
	mutex_lock(&dev->mode_config.mutex);
1505
	count = drm_fb_helper_probe_connector_modes(fb_helper,
1797
	count = drm_fb_helper_probe_connector_modes(fb_helper,
1506
						    dev->mode_config.max_width,
1798
						    dev->mode_config.max_width,
1507
						    dev->mode_config.max_height);
1799
						    dev->mode_config.max_height);
Line 1542... Line 1834...
1542
int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
1834
int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
1543
{
1835
{
1544
	struct drm_device *dev = fb_helper->dev;
1836
	struct drm_device *dev = fb_helper->dev;
1545
	u32 max_width, max_height;
1837
	u32 max_width, max_height;
Line -... Line 1838...
-
 
1838
 
-
 
1839
	if (!drm_fbdev_emulation)
-
 
1840
		return 0;
1546
 
1841
 
1547
	mutex_lock(&fb_helper->dev->mode_config.mutex);
1842
	mutex_lock(&fb_helper->dev->mode_config.mutex);
1548
	if (!fb_helper->fb || !drm_fb_helper_is_bound(fb_helper)) {
1843
	if (!fb_helper->fb || !drm_fb_helper_is_bound(fb_helper)) {
1549
		fb_helper->delayed_hotplug = true;
1844
		fb_helper->delayed_hotplug = true;
1550
		mutex_unlock(&fb_helper->dev->mode_config.mutex);
1845
		mutex_unlock(&fb_helper->dev->mode_config.mutex);