exynos_drm_drv.c 17.9 KB
Newer Older
1 2 3 4 5 6 7
/*
 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
 * Authors:
 *	Inki Dae <inki.dae@samsung.com>
 *	Joonyoung Shim <jy0922.shim@samsung.com>
 *	Seung-Woo Kim <sw0312.kim@samsung.com>
 *
8 9 10 11
 * 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.
12 13
 */

14
#include <linux/pm_runtime.h>
15
#include <drm/drmP.h>
16 17
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
18
#include <drm/drm_crtc_helper.h>
19

20
#include <linux/component.h>
21

22 23 24 25 26 27 28
#include <drm/exynos_drm.h>

#include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h"
#include "exynos_drm_fbdev.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_gem.h"
29
#include "exynos_drm_plane.h"
30
#include "exynos_drm_vidi.h"
J
Joonyoung Shim 已提交
31
#include "exynos_drm_g2d.h"
E
Eunchul Kim 已提交
32
#include "exynos_drm_ipp.h"
33
#include "exynos_drm_iommu.h"
34

I
Inki Dae 已提交
35
#define DRIVER_NAME	"exynos"
36 37 38 39 40
#define DRIVER_DESC	"Samsung SoC DRM"
#define DRIVER_DATE	"20110530"
#define DRIVER_MAJOR	1
#define DRIVER_MINOR	0

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
struct exynos_atomic_commit {
	struct work_struct	work;
	struct drm_device	*dev;
	struct drm_atomic_state *state;
	u32			crtcs;
};

static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit)
{
	struct drm_device *dev = commit->dev;
	struct exynos_drm_private *priv = dev->dev_private;
	struct drm_atomic_state *state = commit->state;

	drm_atomic_helper_commit_modeset_disables(dev, state);

	drm_atomic_helper_commit_modeset_enables(dev, state);

	/*
	 * Exynos can't update planes with CRTCs and encoders disabled,
	 * its updates routines, specially for FIMD, requires the clocks
	 * to be enabled. So it is necessary to handle the modeset operations
	 * *before* the commit_planes() step, this way it will always
	 * have the relevant clocks enabled to perform the update.
	 */

66
	drm_atomic_helper_commit_planes(dev, state, 0);
67

68
	drm_atomic_helper_wait_for_vblanks(dev, state);
69 70 71

	drm_atomic_helper_cleanup_planes(dev, state);

72
	drm_atomic_state_put(state);
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90

	spin_lock(&priv->lock);
	priv->pending &= ~commit->crtcs;
	spin_unlock(&priv->lock);

	wake_up_all(&priv->wait);

	kfree(commit);
}

static void exynos_drm_atomic_work(struct work_struct *work)
{
	struct exynos_atomic_commit *commit = container_of(work,
				struct exynos_atomic_commit, work);

	exynos_atomic_commit_complete(commit);
}

91 92
static struct device *exynos_drm_get_dma_device(void);

93 94 95
static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
{
	struct exynos_drm_private *private;
96 97 98
	struct drm_encoder *encoder;
	unsigned int clone_mask;
	int cnt, ret;
99 100

	private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL);
101
	if (!private)
102 103
		return -ENOMEM;

104 105 106
	init_waitqueue_head(&private->wait);
	spin_lock_init(&private->lock);

107
	dev_set_drvdata(dev->dev, dev);
108 109
	dev->dev_private = (void *)private;

110 111 112 113 114 115 116 117 118 119
	/* the first real CRTC device is used for all dma mapping operations */
	private->dma_dev = exynos_drm_get_dma_device();
	if (!private->dma_dev) {
		DRM_ERROR("no device found for DMA mapping operations.\n");
		ret = -ENODEV;
		goto err_free_private;
	}
	DRM_INFO("Exynos DRM: using %s device for DMA mapping operations\n",
		 dev_name(private->dma_dev));

120
	/* create common IOMMU mapping for all devices attached to Exynos DRM */
121 122 123
	ret = drm_create_iommu_mapping(dev);
	if (ret < 0) {
		DRM_ERROR("failed to create iommu mapping.\n");
124
		goto err_free_private;
125 126
	}

127 128 129 130
	drm_mode_config_init(dev);

	exynos_drm_mode_config_init(dev);

131
	/* setup possible_clones. */
132 133 134 135 136 137 138
	cnt = 0;
	clone_mask = 0;
	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
		clone_mask |= (1 << (cnt++));

	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
		encoder->possible_clones = clone_mask;
139

140 141
	platform_set_drvdata(dev->platformdev, dev);

142 143 144
	/* Try to bind all sub drivers. */
	ret = component_bind_all(dev->dev, dev);
	if (ret)
145 146 147 148 149
		goto err_mode_config_cleanup;

	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
	if (ret)
		goto err_unbind_all;
150

151
	/* Probe non kms sub drivers and virtual display driver. */
152 153
	ret = exynos_drm_device_subdrv_probe(dev);
	if (ret)
154
		goto err_cleanup_vblank;
155

156 157
	drm_mode_config_reset(dev);

158 159 160 161 162 163 164 165 166 167
	/*
	 * 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.
	 */
	dev->irq_enabled = true;

168 169 170 171 172 173
	/* init kms poll for handling hpd */
	drm_kms_helper_poll_init(dev);

	/* force connectors detection */
	drm_helper_hpd_irq_event(dev);

174 175
	return 0;

176
err_cleanup_vblank:
177
	drm_vblank_cleanup(dev);
178 179
err_unbind_all:
	component_unbind_all(dev->dev, dev);
180 181
err_mode_config_cleanup:
	drm_mode_config_cleanup(dev);
182
	drm_release_iommu_mapping(dev);
183
err_free_private:
184 185 186 187 188 189 190
	kfree(private);

	return ret;
}

static int exynos_drm_unload(struct drm_device *dev)
{
191 192
	exynos_drm_device_subdrv_remove(dev);

193
	exynos_drm_fbdev_fini(dev);
194
	drm_kms_helper_poll_fini(dev);
195

196
	drm_vblank_cleanup(dev);
197
	component_unbind_all(dev->dev, dev);
198
	drm_mode_config_cleanup(dev);
199
	drm_release_iommu_mapping(dev);
200

201
	kfree(dev->dev_private);
202 203 204 205 206
	dev->dev_private = NULL;

	return 0;
}

207 208 209 210 211 212 213 214 215 216 217 218
static int commit_is_pending(struct exynos_drm_private *priv, u32 crtcs)
{
	bool pending;

	spin_lock(&priv->lock);
	pending = priv->pending & crtcs;
	spin_unlock(&priv->lock);

	return pending;
}

int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state,
219
			 bool nonblock)
220 221 222
{
	struct exynos_drm_private *priv = dev->dev_private;
	struct exynos_atomic_commit *commit;
223 224
	struct drm_crtc *crtc;
	struct drm_crtc_state *crtc_state;
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
	int i, ret;

	commit = kzalloc(sizeof(*commit), GFP_KERNEL);
	if (!commit)
		return -ENOMEM;

	ret = drm_atomic_helper_prepare_planes(dev, state);
	if (ret) {
		kfree(commit);
		return ret;
	}

	/* This is the point of no return */

	INIT_WORK(&commit->work, exynos_drm_atomic_work);
	commit->dev = dev;
	commit->state = state;

	/* Wait until all affected CRTCs have completed previous commits and
	 * mark them as pending.
	 */
246 247
	for_each_crtc_in_state(state, crtc, crtc_state, i)
		commit->crtcs |= drm_crtc_mask(crtc);
248 249 250 251 252 253 254

	wait_event(priv->wait, !commit_is_pending(priv, commit->crtcs));

	spin_lock(&priv->lock);
	priv->pending |= commit->crtcs;
	spin_unlock(&priv->lock);

255
	drm_atomic_helper_swap_state(state, true);
256

257
	drm_atomic_state_get(state);
258
	if (nonblock)
259 260 261 262 263 264 265
		schedule_work(&commit->work);
	else
		exynos_atomic_commit_complete(commit);

	return 0;
}

266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
int exynos_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_normalize_zpos(dev, state);
	if (ret)
		return ret;

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

	return ret;
}

286 287
static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
{
J
Joonyoung Shim 已提交
288
	struct drm_exynos_file_private *file_priv;
289
	int ret;
J
Joonyoung Shim 已提交
290 291 292 293 294 295

	file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
	if (!file_priv)
		return -ENOMEM;

	file->driver_priv = file_priv;
I
Inki Dae 已提交
296

297
	ret = exynos_drm_subdrv_open(dev, file);
298
	if (ret)
299
		goto err_file_priv_free;
300

301
	return ret;
302 303

err_file_priv_free:
304 305
	kfree(file_priv);
	file->driver_priv = NULL;
306
	return ret;
307 308
}

I
Inki Dae 已提交
309
static void exynos_drm_preclose(struct drm_device *dev,
310
					struct drm_file *file)
311
{
312 313
	struct drm_crtc *crtc;

314
	exynos_drm_subdrv_close(dev, file);
315 316 317

	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
		exynos_drm_crtc_cancel_page_flip(crtc, file);
318 319 320
}

static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
I
Inki Dae 已提交
321
{
322 323 324 325
	kfree(file->driver_priv);
	file->driver_priv = NULL;
}

326 327 328 329 330
static void exynos_drm_lastclose(struct drm_device *dev)
{
	exynos_drm_fbdev_restore_mode(dev);
}

331
static const struct vm_operations_struct exynos_drm_gem_vm_ops = {
332 333 334 335 336
	.fault = exynos_drm_gem_fault,
	.open = drm_gem_vm_open,
	.close = drm_gem_vm_close,
};

R
Rob Clark 已提交
337
static const struct drm_ioctl_desc exynos_ioctls[] = {
338
	DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl,
339
			DRM_AUTH | DRM_RENDER_ALLOW),
340 341
	DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MAP, exynos_drm_gem_map_ioctl,
			DRM_AUTH | DRM_RENDER_ALLOW),
342
	DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET, exynos_drm_gem_get_ioctl,
343
			DRM_RENDER_ALLOW),
344
	DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION, vidi_connection_ioctl,
345
			DRM_AUTH),
346
	DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER, exynos_g2d_get_ver_ioctl,
347
			DRM_AUTH | DRM_RENDER_ALLOW),
348
	DRM_IOCTL_DEF_DRV(EXYNOS_G2D_SET_CMDLIST, exynos_g2d_set_cmdlist_ioctl,
349
			DRM_AUTH | DRM_RENDER_ALLOW),
350
	DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC, exynos_g2d_exec_ioctl,
351
			DRM_AUTH | DRM_RENDER_ALLOW),
352
	DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_PROPERTY, exynos_drm_ipp_get_property,
353
			DRM_AUTH | DRM_RENDER_ALLOW),
354
	DRM_IOCTL_DEF_DRV(EXYNOS_IPP_SET_PROPERTY, exynos_drm_ipp_set_property,
355
			DRM_AUTH | DRM_RENDER_ALLOW),
356
	DRM_IOCTL_DEF_DRV(EXYNOS_IPP_QUEUE_BUF, exynos_drm_ipp_queue_buf,
357
			DRM_AUTH | DRM_RENDER_ALLOW),
358
	DRM_IOCTL_DEF_DRV(EXYNOS_IPP_CMD_CTRL, exynos_drm_ipp_cmd_ctrl,
359
			DRM_AUTH | DRM_RENDER_ALLOW),
360 361
};

J
Joonyoung Shim 已提交
362 363 364 365 366 367 368
static const struct file_operations exynos_drm_driver_fops = {
	.owner		= THIS_MODULE,
	.open		= drm_open,
	.mmap		= exynos_drm_gem_mmap,
	.poll		= drm_poll,
	.read		= drm_read,
	.unlocked_ioctl	= drm_ioctl,
369
	.compat_ioctl = drm_compat_ioctl,
J
Joonyoung Shim 已提交
370 371 372
	.release	= drm_release,
};

373
static struct drm_driver exynos_drm_driver = {
374
	.driver_features	= DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME
375
				  | DRIVER_ATOMIC | DRIVER_RENDER,
376 377
	.load			= exynos_drm_load,
	.unload			= exynos_drm_unload,
378
	.open			= exynos_drm_open,
I
Inki Dae 已提交
379
	.preclose		= exynos_drm_preclose,
380
	.lastclose		= exynos_drm_lastclose,
381
	.postclose		= exynos_drm_postclose,
382
	.get_vblank_counter	= drm_vblank_no_hw_counter,
383 384
	.enable_vblank		= exynos_drm_crtc_enable_vblank,
	.disable_vblank		= exynos_drm_crtc_disable_vblank,
385
	.gem_free_object_unlocked = exynos_drm_gem_free_object,
386 387 388
	.gem_vm_ops		= &exynos_drm_gem_vm_ops,
	.dumb_create		= exynos_drm_gem_dumb_create,
	.dumb_map_offset	= exynos_drm_gem_dumb_map_offset,
389
	.dumb_destroy		= drm_gem_dumb_destroy,
I
Inki Dae 已提交
390 391
	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
J
Joonyoung Shim 已提交
392 393 394 395 396 397
	.gem_prime_export	= drm_gem_prime_export,
	.gem_prime_import	= drm_gem_prime_import,
	.gem_prime_get_sg_table	= exynos_drm_gem_prime_get_sg_table,
	.gem_prime_import_sg_table	= exynos_drm_gem_prime_import_sg_table,
	.gem_prime_vmap		= exynos_drm_gem_prime_vmap,
	.gem_prime_vunmap	= exynos_drm_gem_prime_vunmap,
398
	.gem_prime_mmap		= exynos_drm_gem_prime_mmap,
399
	.ioctls			= exynos_ioctls,
R
Rob Clark 已提交
400
	.num_ioctls		= ARRAY_SIZE(exynos_ioctls),
J
Joonyoung Shim 已提交
401
	.fops			= &exynos_drm_driver_fops,
402 403 404 405 406 407 408
	.name	= DRIVER_NAME,
	.desc	= DRIVER_DESC,
	.date	= DRIVER_DATE,
	.major	= DRIVER_MAJOR,
	.minor	= DRIVER_MINOR,
};

409
#ifdef CONFIG_PM_SLEEP
A
Andrzej Hajda 已提交
410
static int exynos_drm_suspend(struct device *dev)
411 412
{
	struct drm_device *drm_dev = dev_get_drvdata(dev);
A
Andrzej Hajda 已提交
413
	struct drm_connector *connector;
414

415
	if (pm_runtime_suspended(dev) || !drm_dev)
416 417
		return 0;

A
Andrzej Hajda 已提交
418 419 420 421 422 423 424 425 426 427 428 429 430
	drm_modeset_lock_all(drm_dev);
	drm_for_each_connector(connector, drm_dev) {
		int old_dpms = connector->dpms;

		if (connector->funcs->dpms)
			connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);

		/* Set the old mode back to the connector for resume */
		connector->dpms = old_dpms;
	}
	drm_modeset_unlock_all(drm_dev);

	return 0;
431 432
}

A
Andrzej Hajda 已提交
433
static int exynos_drm_resume(struct device *dev)
434 435
{
	struct drm_device *drm_dev = dev_get_drvdata(dev);
A
Andrzej Hajda 已提交
436
	struct drm_connector *connector;
437

438
	if (pm_runtime_suspended(dev) || !drm_dev)
439 440
		return 0;

A
Andrzej Hajda 已提交
441 442 443 444 445 446 447 448 449 450 451 452
	drm_modeset_lock_all(drm_dev);
	drm_for_each_connector(connector, drm_dev) {
		if (connector->funcs->dpms) {
			int dpms = connector->dpms;

			connector->dpms = DRM_MODE_DPMS_OFF;
			connector->funcs->dpms(connector, dpms);
		}
	}
	drm_modeset_unlock_all(drm_dev);

	return 0;
453 454 455 456
}
#endif

static const struct dev_pm_ops exynos_drm_pm_ops = {
A
Andrzej Hajda 已提交
457
	SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_suspend, exynos_drm_resume)
458 459
};

460 461
/* forward declaration */
static struct platform_driver exynos_drm_platform_driver;
462

463 464 465 466 467 468 469
struct exynos_drm_driver_info {
	struct platform_driver *driver;
	unsigned int flags;
};

#define DRM_COMPONENT_DRIVER	BIT(0)	/* supports component framework */
#define DRM_VIRTUAL_DEVICE	BIT(1)	/* create virtual platform device */
470
#define DRM_DMA_DEVICE		BIT(2)	/* can be used for dma allocations */
471 472 473

#define DRV_PTR(drv, cond) (IS_ENABLED(cond) ? &drv : NULL)

474 475 476 477
/*
 * Connector drivers should not be placed before associated crtc drivers,
 * because connector requires pipe number of its crtc during initialization.
 */
478 479 480
static struct exynos_drm_driver_info exynos_drm_drivers[] = {
	{
		DRV_PTR(fimd_driver, CONFIG_DRM_EXYNOS_FIMD),
481
		DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE
482 483
	}, {
		DRV_PTR(exynos5433_decon_driver, CONFIG_DRM_EXYNOS5433_DECON),
484
		DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE
485 486
	}, {
		DRV_PTR(decon_driver, CONFIG_DRM_EXYNOS7_DECON),
487
		DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE
488 489
	}, {
		DRV_PTR(mixer_driver, CONFIG_DRM_EXYNOS_MIXER),
490
		DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
	}, {
		DRV_PTR(mic_driver, CONFIG_DRM_EXYNOS_MIC),
		DRM_COMPONENT_DRIVER
	}, {
		DRV_PTR(dp_driver, CONFIG_DRM_EXYNOS_DP),
		DRM_COMPONENT_DRIVER
	}, {
		DRV_PTR(dsi_driver, CONFIG_DRM_EXYNOS_DSI),
		DRM_COMPONENT_DRIVER
	}, {
		DRV_PTR(hdmi_driver, CONFIG_DRM_EXYNOS_HDMI),
		DRM_COMPONENT_DRIVER
	}, {
		DRV_PTR(vidi_driver, CONFIG_DRM_EXYNOS_VIDI),
		DRM_COMPONENT_DRIVER | DRM_VIRTUAL_DEVICE
	}, {
		DRV_PTR(g2d_driver, CONFIG_DRM_EXYNOS_G2D),
	}, {
		DRV_PTR(fimc_driver, CONFIG_DRM_EXYNOS_FIMC),
	}, {
		DRV_PTR(rotator_driver, CONFIG_DRM_EXYNOS_ROTATOR),
	}, {
		DRV_PTR(gsc_driver, CONFIG_DRM_EXYNOS_GSC),
	}, {
		DRV_PTR(ipp_driver, CONFIG_DRM_EXYNOS_IPP),
		DRM_VIRTUAL_DEVICE
	}, {
		&exynos_drm_platform_driver,
		DRM_VIRTUAL_DEVICE
	}
521
};
522

523
static int compare_dev(struct device *dev, void *data)
524 525 526 527
{
	return dev == (struct device *)data;
}

528
static struct component_match *exynos_drm_match_add(struct device *dev)
529
{
530
	struct component_match *match = NULL;
531
	int i;
532

533 534
	for (i = 0; i < ARRAY_SIZE(exynos_drm_drivers); ++i) {
		struct exynos_drm_driver_info *info = &exynos_drm_drivers[i];
535
		struct device *p = NULL, *d;
536

537 538 539 540 541
		if (!info->driver || !(info->flags & DRM_COMPONENT_DRIVER))
			continue;

		while ((d = bus_find_device(&platform_bus_type, p,
					    &info->driver->driver,
542 543 544 545
					    (void *)platform_bus_type.match))) {
			put_device(p);
			component_match_add(dev, &match, compare_dev, d);
			p = d;
546
		}
547
		put_device(p);
548 549
	}

550
	return match ?: ERR_PTR(-ENODEV);
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
}

static int exynos_drm_bind(struct device *dev)
{
	return drm_platform_init(&exynos_drm_driver, to_platform_device(dev));
}

static void exynos_drm_unbind(struct device *dev)
{
	drm_put_dev(dev_get_drvdata(dev));
}

static const struct component_master_ops exynos_drm_ops = {
	.bind		= exynos_drm_bind,
	.unbind		= exynos_drm_unbind,
566 567
};

568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597
static int exynos_drm_platform_probe(struct platform_device *pdev)
{
	struct component_match *match;

	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
	exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls);

	match = exynos_drm_match_add(&pdev->dev);
	if (IS_ERR(match))
		return PTR_ERR(match);

	return component_master_add_with_match(&pdev->dev, &exynos_drm_ops,
					       match);
}

static int exynos_drm_platform_remove(struct platform_device *pdev)
{
	component_master_del(&pdev->dev, &exynos_drm_ops);
	return 0;
}

static struct platform_driver exynos_drm_platform_driver = {
	.probe	= exynos_drm_platform_probe,
	.remove	= exynos_drm_platform_remove,
	.driver	= {
		.name	= "exynos-drm",
		.pm	= &exynos_drm_pm_ops,
	},
};

598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618
static struct device *exynos_drm_get_dma_device(void)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(exynos_drm_drivers); ++i) {
		struct exynos_drm_driver_info *info = &exynos_drm_drivers[i];
		struct device *dev;

		if (!info->driver || !(info->flags & DRM_DMA_DEVICE))
			continue;

		while ((dev = bus_find_device(&platform_bus_type, NULL,
					    &info->driver->driver,
					    (void *)platform_bus_type.match))) {
			put_device(dev);
			return dev;
		}
	}
	return NULL;
}

619
static void exynos_drm_unregister_devices(void)
620
{
621 622 623 624 625
	int i;

	for (i = ARRAY_SIZE(exynos_drm_drivers) - 1; i >= 0; --i) {
		struct exynos_drm_driver_info *info = &exynos_drm_drivers[i];
		struct device *dev;
626

627 628 629 630 631 632 633 634 635
		if (!info->driver || !(info->flags & DRM_VIRTUAL_DEVICE))
			continue;

		while ((dev = bus_find_device(&platform_bus_type, NULL,
					    &info->driver->driver,
					    (void *)platform_bus_type.match))) {
			put_device(dev);
			platform_device_unregister(to_platform_device(dev));
		}
636 637
	}
}
A
Andrzej Hajda 已提交
638

639 640
static int exynos_drm_register_devices(void)
{
641
	struct platform_device *pdev;
642 643
	int i;

644 645
	for (i = 0; i < ARRAY_SIZE(exynos_drm_drivers); ++i) {
		struct exynos_drm_driver_info *info = &exynos_drm_drivers[i];
646

647
		if (!info->driver || !(info->flags & DRM_VIRTUAL_DEVICE))
648 649
			continue;

650 651 652 653
		pdev = platform_device_register_simple(
					info->driver->driver.name, -1, NULL, 0);
		if (IS_ERR(pdev))
			goto fail;
654
	}
655

656
	return 0;
657 658 659
fail:
	exynos_drm_unregister_devices();
	return PTR_ERR(pdev);
660 661
}

662
static void exynos_drm_unregister_drivers(void)
663
{
664
	int i;
665

666 667
	for (i = ARRAY_SIZE(exynos_drm_drivers) - 1; i >= 0; --i) {
		struct exynos_drm_driver_info *info = &exynos_drm_drivers[i];
668

669
		if (!info->driver)
670 671
			continue;

672
		platform_driver_unregister(info->driver);
673
	}
674 675
}

676
static int exynos_drm_register_drivers(void)
677
{
678
	int i, ret;
679

680 681
	for (i = 0; i < ARRAY_SIZE(exynos_drm_drivers); ++i) {
		struct exynos_drm_driver_info *info = &exynos_drm_drivers[i];
682

683 684
		if (!info->driver)
			continue;
685

686 687 688 689 690 691 692 693
		ret = platform_driver_register(info->driver);
		if (ret)
			goto fail;
	}
	return 0;
fail:
	exynos_drm_unregister_drivers();
	return ret;
694 695
}

696 697
static int exynos_drm_init(void)
{
698
	int ret;
699

700 701 702
	ret = exynos_drm_register_devices();
	if (ret)
		return ret;
703

704
	ret = exynos_drm_register_drivers();
705 706
	if (ret)
		goto err_unregister_pdevs;
707 708 709

	return 0;

710 711
err_unregister_pdevs:
	exynos_drm_unregister_devices();
712 713 714 715 716 717

	return ret;
}

static void exynos_drm_exit(void)
{
718
	exynos_drm_unregister_drivers();
719
	exynos_drm_unregister_devices();
720 721 722 723 724 725 726 727 728 729
}

module_init(exynos_drm_init);
module_exit(exynos_drm_exit);

MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
MODULE_DESCRIPTION("Samsung SoC DRM Driver");
MODULE_LICENSE("GPL");