imx-drm-core.c 13 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * Freescale i.MX drm driver
 *
 * Copyright (C) 2011 Sascha Hauer, Pengutronix
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */
16
#include <linux/component.h>
17
#include <linux/device.h>
18
#include <linux/dma-buf.h>
19
#include <linux/module.h>
20 21
#include <linux/platform_device.h>
#include <drm/drmP.h>
22 23
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
24 25 26 27
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
28
#include <drm/drm_plane_helper.h>
29
#include <drm/drm_of.h>
30
#include <video/imx-ipu-v3.h>
31 32 33 34 35

#include "imx-drm.h"

#define MAX_CRTC	4

36 37 38 39 40
struct imx_drm_component {
	struct device_node *of_node;
	struct list_head list;
};

41 42
struct imx_drm_device {
	struct drm_device			*drm;
43
	struct imx_drm_crtc			*crtc[MAX_CRTC];
44
	unsigned int				pipes;
45
	struct drm_fbdev_cma			*fbhelper;
46
	struct drm_atomic_state			*state;
47 48 49 50 51 52 53
};

struct imx_drm_crtc {
	struct drm_crtc				*crtc;
	struct imx_drm_crtc_helper_funcs	imx_drm_helper_funcs;
};

54
#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
55 56
static int legacyfb_depth = 16;
module_param(legacyfb_depth, int, 0444);
57
#endif
58

59 60 61 62
static void imx_drm_driver_lastclose(struct drm_device *drm)
{
	struct imx_drm_device *imxdrm = drm->dev_private;

63
	drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
64 65
}

66
static int imx_drm_enable_vblank(struct drm_device *drm, unsigned int pipe)
67 68
{
	struct imx_drm_device *imxdrm = drm->dev_private;
69
	struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[pipe];
70 71 72 73 74 75 76 77 78 79 80 81 82 83
	int ret;

	if (!imx_drm_crtc)
		return -EINVAL;

	if (!imx_drm_crtc->imx_drm_helper_funcs.enable_vblank)
		return -ENOSYS;

	ret = imx_drm_crtc->imx_drm_helper_funcs.enable_vblank(
			imx_drm_crtc->crtc);

	return ret;
}

84
static void imx_drm_disable_vblank(struct drm_device *drm, unsigned int pipe)
85 86
{
	struct imx_drm_device *imxdrm = drm->dev_private;
87
	struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[pipe];
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108

	if (!imx_drm_crtc)
		return;

	if (!imx_drm_crtc->imx_drm_helper_funcs.disable_vblank)
		return;

	imx_drm_crtc->imx_drm_helper_funcs.disable_vblank(imx_drm_crtc->crtc);
}

static const struct file_operations imx_drm_driver_fops = {
	.owner = THIS_MODULE,
	.open = drm_open,
	.release = drm_release,
	.unlocked_ioctl = drm_ioctl,
	.mmap = drm_gem_cma_mmap,
	.poll = drm_poll,
	.read = drm_read,
	.llseek = noop_llseek,
};

109 110
void imx_drm_connector_destroy(struct drm_connector *connector)
{
111
	drm_connector_unregister(connector);
112 113 114 115 116 117 118 119 120 121
	drm_connector_cleanup(connector);
}
EXPORT_SYMBOL_GPL(imx_drm_connector_destroy);

void imx_drm_encoder_destroy(struct drm_encoder *encoder)
{
	drm_encoder_cleanup(encoder);
}
EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);

122 123 124 125 126 127 128
static void imx_drm_output_poll_changed(struct drm_device *drm)
{
	struct imx_drm_device *imxdrm = drm->dev_private;

	drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
}

129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
static int imx_drm_atomic_check(struct drm_device *dev,
				struct drm_atomic_state *state)
{
	int ret;

	ret = drm_atomic_helper_check_modeset(dev, state);
	if (ret)
		return ret;

	ret = drm_atomic_helper_check_planes(dev, state);
	if (ret)
		return ret;

	/*
	 * Check modeset again in case crtc_state->mode_changed is
	 * updated in plane's ->atomic_check callback.
	 */
	ret = drm_atomic_helper_check_modeset(dev, state);
	if (ret)
		return ret;

	return ret;
}

153
static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
Russell King's avatar
Russell King committed
154
	.fb_create = drm_fb_cma_create,
155
	.output_poll_changed = imx_drm_output_poll_changed,
156
	.atomic_check = imx_drm_atomic_check,
157
	.atomic_commit = drm_atomic_helper_commit,
158 159 160 161 162 163 164 165
};

static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state)
{
	struct drm_device *dev = state->dev;

	drm_atomic_helper_commit_modeset_disables(dev, state);

166
	drm_atomic_helper_commit_planes(dev, state,
167 168
				DRM_PLANE_COMMIT_ACTIVE_ONLY |
				DRM_PLANE_COMMIT_NO_DISABLE_AFTER_MODESET);
169 170 171 172 173 174 175 176 177 178 179 180

	drm_atomic_helper_commit_modeset_enables(dev, state);

	drm_atomic_helper_commit_hw_done(state);

	drm_atomic_helper_wait_for_vblanks(dev, state);

	drm_atomic_helper_cleanup_planes(dev, state);
}

static struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = {
	.atomic_commit_tail = imx_drm_atomic_commit_tail,
Russell King's avatar
Russell King committed
181 182
};

183 184 185
/*
 * imx_drm_add_crtc - add a new crtc
 */
186
int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
187
		struct imx_drm_crtc **new_crtc, struct drm_plane *primary_plane,
188
		const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
189
		struct device_node *port)
190
{
191
	struct imx_drm_device *imxdrm = drm->dev_private;
192 193
	struct imx_drm_crtc *imx_drm_crtc;

194 195 196 197
	/*
	 * The vblank arrays are dimensioned by MAX_CRTC - we can't
	 * pass IDs greater than this to those functions.
	 */
198 199
	if (imxdrm->pipes >= MAX_CRTC)
		return -EINVAL;
200

201 202
	if (imxdrm->drm->open_count)
		return -EBUSY;
203 204

	imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL);
205 206
	if (!imx_drm_crtc)
		return -ENOMEM;
207 208 209 210

	imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
	imx_drm_crtc->crtc = crtc;

211 212
	crtc->port = port;

213
	imxdrm->crtc[imxdrm->pipes++] = imx_drm_crtc;
214 215 216

	*new_crtc = imx_drm_crtc;

217 218 219
	drm_crtc_helper_add(crtc,
			imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);

220
	drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL,
221
			imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs, NULL);
222

223 224 225 226 227 228 229 230 231
	return 0;
}
EXPORT_SYMBOL_GPL(imx_drm_add_crtc);

/*
 * imx_drm_remove_crtc - remove a crtc
 */
int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
{
232
	struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private;
233
	unsigned int pipe = drm_crtc_index(imx_drm_crtc->crtc);
234 235 236

	drm_crtc_cleanup(imx_drm_crtc->crtc);

237
	imxdrm->crtc[pipe] = NULL;
238 239 240 241 242 243 244

	kfree(imx_drm_crtc);

	return 0;
}
EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);

245 246
int imx_drm_encoder_parse_of(struct drm_device *drm,
	struct drm_encoder *encoder, struct device_node *np)
247
{
248
	uint32_t crtc_mask = drm_of_find_possible_crtcs(drm, np);
249

250 251 252 253 254 255 256 257
	/*
	 * If we failed to find the CRTC(s) which this encoder is
	 * supposed to be connected to, it's because the CRTC has
	 * not been registered yet.  Defer probing, and hope that
	 * the required CRTC is added later.
	 */
	if (crtc_mask == 0)
		return -EPROBE_DEFER;
258

259
	encoder->possible_crtcs = crtc_mask;
260

261 262
	/* FIXME: this is the mask of outputs which can clone this output. */
	encoder->possible_clones = ~0;
263 264 265

	return 0;
}
266
EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
267

Rob Clark's avatar
Rob Clark committed
268
static const struct drm_ioctl_desc imx_drm_ioctls[] = {
269 270 271 272
	/* none so far */
};

static struct drm_driver imx_drm_driver = {
273 274
	.driver_features	= DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
				  DRIVER_ATOMIC,
275
	.lastclose		= imx_drm_driver_lastclose,
276
	.gem_free_object_unlocked = drm_gem_cma_free_object,
277 278 279
	.gem_vm_ops		= &drm_gem_cma_vm_ops,
	.dumb_create		= drm_gem_cma_dumb_create,
	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
280
	.dumb_destroy		= drm_gem_dumb_destroy,
281

282 283 284 285 286 287 288 289 290
	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
	.gem_prime_import	= drm_gem_prime_import,
	.gem_prime_export	= drm_gem_prime_export,
	.gem_prime_get_sg_table	= drm_gem_cma_prime_get_sg_table,
	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
	.gem_prime_vmap		= drm_gem_cma_prime_vmap,
	.gem_prime_vunmap	= drm_gem_cma_prime_vunmap,
	.gem_prime_mmap		= drm_gem_cma_prime_mmap,
291
	.get_vblank_counter	= drm_vblank_no_hw_counter,
292 293 294 295 296 297 298 299 300 301 302 303 304
	.enable_vblank		= imx_drm_enable_vblank,
	.disable_vblank		= imx_drm_disable_vblank,
	.ioctls			= imx_drm_ioctls,
	.num_ioctls		= ARRAY_SIZE(imx_drm_ioctls),
	.fops			= &imx_drm_driver_fops,
	.name			= "imx-drm",
	.desc			= "i.MX DRM graphics",
	.date			= "20120507",
	.major			= 1,
	.minor			= 0,
	.patchlevel		= 0,
};

305 306
static int compare_of(struct device *dev, void *data)
{
307
	struct device_node *np = data;
308

309 310 311 312 313 314 315
	/* Special case for DI, dev->of_node may not be set yet */
	if (strcmp(dev->driver->name, "imx-ipuv3-crtc") == 0) {
		struct ipu_client_platformdata *pdata = dev->platform_data;

		return pdata->of_node == np;
	}

316 317 318 319
	/* Special case for LDB, one device for two channels */
	if (of_node_cmp(np->name, "lvds-channel") == 0) {
		np = of_get_parent(np);
		of_node_put(np);
320 321
	}

322 323
	return dev->of_node == np;
}
324 325 326

static int imx_drm_bind(struct device *dev)
{
327 328 329 330 331
	struct drm_device *drm;
	struct imx_drm_device *imxdrm;
	int ret;

	drm = drm_dev_alloc(&imx_drm_driver, dev);
332 333
	if (IS_ERR(drm))
		return PTR_ERR(drm);
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391

	imxdrm = devm_kzalloc(dev, sizeof(*imxdrm), GFP_KERNEL);
	if (!imxdrm) {
		ret = -ENOMEM;
		goto err_unref;
	}

	imxdrm->drm = drm;
	drm->dev_private = imxdrm;

	/*
	 * enable drm irq mode.
	 * - with irq_enabled = true, we can use the vblank feature.
	 *
	 * P.S. note that we wouldn't use drm irq handler but
	 *      just specific driver own one instead because
	 *      drm framework supports only one irq handler and
	 *      drivers can well take care of their interrupts
	 */
	drm->irq_enabled = true;

	/*
	 * set max width and height as default value(4096x4096).
	 * this value would be used to check framebuffer size limitation
	 * at drm_mode_addfb().
	 */
	drm->mode_config.min_width = 64;
	drm->mode_config.min_height = 64;
	drm->mode_config.max_width = 4096;
	drm->mode_config.max_height = 4096;
	drm->mode_config.funcs = &imx_drm_mode_config_funcs;
	drm->mode_config.helper_private = &imx_drm_mode_config_helpers;

	drm_mode_config_init(drm);

	ret = drm_vblank_init(drm, MAX_CRTC);
	if (ret)
		goto err_kms;

	dev_set_drvdata(dev, drm);

	/* Now try and bind all our sub-components */
	ret = component_bind_all(dev, drm);
	if (ret)
		goto err_vblank;

	drm_mode_config_reset(drm);

	/*
	 * All components are now initialised, so setup the fb helper.
	 * The fb helper takes copies of key hardware information, so the
	 * crtcs/connectors/encoders must not change after this point.
	 */
#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
	if (legacyfb_depth != 16 && legacyfb_depth != 32) {
		dev_warn(dev, "Invalid legacyfb_depth.  Defaulting to 16bpp\n");
		legacyfb_depth = 16;
	}
392
	imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth, MAX_CRTC);
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
	if (IS_ERR(imxdrm->fbhelper)) {
		ret = PTR_ERR(imxdrm->fbhelper);
		imxdrm->fbhelper = NULL;
		goto err_unbind;
	}
#endif

	drm_kms_helper_poll_init(drm);

	ret = drm_dev_register(drm, 0);
	if (ret)
		goto err_fbhelper;

	return 0;

err_fbhelper:
	drm_kms_helper_poll_fini(drm);
410
#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
411 412 413
	if (imxdrm->fbhelper)
		drm_fbdev_cma_fini(imxdrm->fbhelper);
err_unbind:
414
#endif
415 416 417 418 419 420 421 422 423
	component_unbind_all(drm->dev, drm);
err_vblank:
	drm_vblank_cleanup(drm);
err_kms:
	drm_mode_config_cleanup(drm);
err_unref:
	drm_dev_unref(drm);

	return ret;
424 425 426 427
}

static void imx_drm_unbind(struct device *dev)
{
428 429 430 431 432 433 434 435 436 437
	struct drm_device *drm = dev_get_drvdata(dev);
	struct imx_drm_device *imxdrm = drm->dev_private;

	drm_dev_unregister(drm);

	drm_kms_helper_poll_fini(drm);

	if (imxdrm->fbhelper)
		drm_fbdev_cma_fini(imxdrm->fbhelper);

438 439
	drm_mode_config_cleanup(drm);

440 441 442 443
	component_unbind_all(drm->dev, drm);
	dev_set_drvdata(dev, NULL);

	drm_dev_unref(drm);
444 445 446 447 448 449 450
}

static const struct component_master_ops imx_drm_ops = {
	.bind = imx_drm_bind,
	.unbind = imx_drm_unbind,
};

451 452
static int imx_drm_platform_probe(struct platform_device *pdev)
{
453
	int ret = drm_of_component_probe(&pdev->dev, compare_of, &imx_drm_ops);
454

455 456
	if (!ret)
		ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
457

458
	return ret;
459 460 461 462
}

static int imx_drm_platform_remove(struct platform_device *pdev)
{
463
	component_master_del(&pdev->dev, &imx_drm_ops);
464 465 466
	return 0;
}

467 468 469 470
#ifdef CONFIG_PM_SLEEP
static int imx_drm_suspend(struct device *dev)
{
	struct drm_device *drm_dev = dev_get_drvdata(dev);
471
	struct imx_drm_device *imxdrm;
472 473 474 475 476 477 478

	/* The drm_dev is NULL before .load hook is called */
	if (drm_dev == NULL)
		return 0;

	drm_kms_helper_poll_disable(drm_dev);

479 480 481 482 483 484 485
	imxdrm = drm_dev->dev_private;
	imxdrm->state = drm_atomic_helper_suspend(drm_dev);
	if (IS_ERR(imxdrm->state)) {
		drm_kms_helper_poll_enable(drm_dev);
		return PTR_ERR(imxdrm->state);
	}

486 487 488 489 490 491
	return 0;
}

static int imx_drm_resume(struct device *dev)
{
	struct drm_device *drm_dev = dev_get_drvdata(dev);
492
	struct imx_drm_device *imx_drm;
493 494 495 496

	if (drm_dev == NULL)
		return 0;

497 498
	imx_drm = drm_dev->dev_private;
	drm_atomic_helper_resume(drm_dev, imx_drm->state);
499 500 501 502 503 504 505 506
	drm_kms_helper_poll_enable(drm_dev);

	return 0;
}
#endif

static SIMPLE_DEV_PM_OPS(imx_drm_pm_ops, imx_drm_suspend, imx_drm_resume);

507
static const struct of_device_id imx_drm_dt_ids[] = {
508
	{ .compatible = "fsl,imx-display-subsystem", },
509 510 511 512
	{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, imx_drm_dt_ids);

513 514
static struct platform_driver imx_drm_pdrv = {
	.probe		= imx_drm_platform_probe,
515
	.remove		= imx_drm_platform_remove,
516 517
	.driver		= {
		.name	= "imx-drm",
518
		.pm	= &imx_drm_pm_ops,
519
		.of_match_table = imx_drm_dt_ids,
520 521
	},
};
522
module_platform_driver(imx_drm_pdrv);
523 524 525 526

MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
MODULE_DESCRIPTION("i.MX drm driver core");
MODULE_LICENSE("GPL");