exynos_drm_drv.c 17.8 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
	kfree(private);

	return ret;
}

189
static void exynos_drm_unload(struct drm_device *dev)
190
{
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
	dev->dev_private = NULL;
}

205 206 207 208 209 210 211 212 213 214 215 216
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,
217
			 bool nonblock)
218 219 220
{
	struct exynos_drm_private *priv = dev->dev_private;
	struct exynos_atomic_commit *commit;
221 222
	struct drm_crtc *crtc;
	struct drm_crtc_state *crtc_state;
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
	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.
	 */
244 245
	for_each_crtc_in_state(state, crtc, crtc_state, i)
		commit->crtcs |= drm_crtc_mask(crtc);
246 247 248 249 250 251 252

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

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

253
	drm_atomic_helper_swap_state(state, true);
254

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

	return 0;
}

264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
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;
}

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

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

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

295
	ret = exynos_drm_subdrv_open(dev, file);
296
	if (ret)
297
		goto err_file_priv_free;
298

299
	return ret;
300 301

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

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

static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
I
Inki Dae 已提交
314
{
315 316 317 318
	kfree(file->driver_priv);
	file->driver_priv = NULL;
}

319 320 321 322 323
static void exynos_drm_lastclose(struct drm_device *dev)
{
	exynos_drm_fbdev_restore_mode(dev);
}

324
static const struct vm_operations_struct exynos_drm_gem_vm_ops = {
325 326 327 328 329
	.fault = exynos_drm_gem_fault,
	.open = drm_gem_vm_open,
	.close = drm_gem_vm_close,
};

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

J
Joonyoung Shim 已提交
355 356 357 358 359 360 361
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,
362
	.compat_ioctl = drm_compat_ioctl,
J
Joonyoung Shim 已提交
363 364 365
	.release	= drm_release,
};

366
static struct drm_driver exynos_drm_driver = {
367
	.driver_features	= DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME
368
				  | DRIVER_ATOMIC | DRIVER_RENDER,
369 370
	.load			= exynos_drm_load,
	.unload			= exynos_drm_unload,
371
	.open			= exynos_drm_open,
I
Inki Dae 已提交
372
	.preclose		= exynos_drm_preclose,
373
	.lastclose		= exynos_drm_lastclose,
374
	.postclose		= exynos_drm_postclose,
375
	.get_vblank_counter	= drm_vblank_no_hw_counter,
376 377
	.enable_vblank		= exynos_drm_crtc_enable_vblank,
	.disable_vblank		= exynos_drm_crtc_disable_vblank,
378
	.gem_free_object_unlocked = exynos_drm_gem_free_object,
379 380 381
	.gem_vm_ops		= &exynos_drm_gem_vm_ops,
	.dumb_create		= exynos_drm_gem_dumb_create,
	.dumb_map_offset	= exynos_drm_gem_dumb_map_offset,
382
	.dumb_destroy		= drm_gem_dumb_destroy,
I
Inki Dae 已提交
383 384
	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
J
Joonyoung Shim 已提交
385 386 387 388 389 390
	.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,
391
	.gem_prime_mmap		= exynos_drm_gem_prime_mmap,
392
	.ioctls			= exynos_ioctls,
R
Rob Clark 已提交
393
	.num_ioctls		= ARRAY_SIZE(exynos_ioctls),
J
Joonyoung Shim 已提交
394
	.fops			= &exynos_drm_driver_fops,
395 396 397 398 399 400 401
	.name	= DRIVER_NAME,
	.desc	= DRIVER_DESC,
	.date	= DRIVER_DATE,
	.major	= DRIVER_MAJOR,
	.minor	= DRIVER_MINOR,
};

402
#ifdef CONFIG_PM_SLEEP
A
Andrzej Hajda 已提交
403
static int exynos_drm_suspend(struct device *dev)
404 405
{
	struct drm_device *drm_dev = dev_get_drvdata(dev);
A
Andrzej Hajda 已提交
406
	struct drm_connector *connector;
407

408
	if (pm_runtime_suspended(dev) || !drm_dev)
409 410
		return 0;

A
Andrzej Hajda 已提交
411 412 413 414 415 416 417 418 419 420 421 422 423
	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;
424 425
}

A
Andrzej Hajda 已提交
426
static int exynos_drm_resume(struct device *dev)
427 428
{
	struct drm_device *drm_dev = dev_get_drvdata(dev);
A
Andrzej Hajda 已提交
429
	struct drm_connector *connector;
430

431
	if (pm_runtime_suspended(dev) || !drm_dev)
432 433
		return 0;

A
Andrzej Hajda 已提交
434 435 436 437 438 439 440 441 442 443 444 445
	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;
446 447 448 449
}
#endif

static const struct dev_pm_ops exynos_drm_pm_ops = {
A
Andrzej Hajda 已提交
450
	SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_suspend, exynos_drm_resume)
451 452
};

453 454
/* forward declaration */
static struct platform_driver exynos_drm_platform_driver;
455

456 457 458 459 460 461 462
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 */
463
#define DRM_DMA_DEVICE		BIT(2)	/* can be used for dma allocations */
464 465 466

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

467 468 469 470
/*
 * Connector drivers should not be placed before associated crtc drivers,
 * because connector requires pipe number of its crtc during initialization.
 */
471 472 473
static struct exynos_drm_driver_info exynos_drm_drivers[] = {
	{
		DRV_PTR(fimd_driver, CONFIG_DRM_EXYNOS_FIMD),
474
		DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE
475 476
	}, {
		DRV_PTR(exynos5433_decon_driver, CONFIG_DRM_EXYNOS5433_DECON),
477
		DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE
478 479
	}, {
		DRV_PTR(decon_driver, CONFIG_DRM_EXYNOS7_DECON),
480
		DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE
481 482
	}, {
		DRV_PTR(mixer_driver, CONFIG_DRM_EXYNOS_MIXER),
483
		DRM_COMPONENT_DRIVER | DRM_DMA_DEVICE
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
	}, {
		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
	}
514
};
515

516
static int compare_dev(struct device *dev, void *data)
517 518 519 520
{
	return dev == (struct device *)data;
}

521
static struct component_match *exynos_drm_match_add(struct device *dev)
522
{
523
	struct component_match *match = NULL;
524
	int i;
525

526 527
	for (i = 0; i < ARRAY_SIZE(exynos_drm_drivers); ++i) {
		struct exynos_drm_driver_info *info = &exynos_drm_drivers[i];
528
		struct device *p = NULL, *d;
529

530 531 532 533 534
		if (!info->driver || !(info->flags & DRM_COMPONENT_DRIVER))
			continue;

		while ((d = bus_find_device(&platform_bus_type, p,
					    &info->driver->driver,
535 536 537 538
					    (void *)platform_bus_type.match))) {
			put_device(p);
			component_match_add(dev, &match, compare_dev, d);
			p = d;
539
		}
540
		put_device(p);
541 542
	}

543
	return match ?: ERR_PTR(-ENODEV);
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
}

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,
559 560
};

561 562 563 564 565 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
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,
	},
};

591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
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;
}

612
static void exynos_drm_unregister_devices(void)
613
{
614 615 616 617 618
	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;
619

620 621 622 623 624 625 626 627 628
		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));
		}
629 630
	}
}
A
Andrzej Hajda 已提交
631

632 633
static int exynos_drm_register_devices(void)
{
634
	struct platform_device *pdev;
635 636
	int i;

637 638
	for (i = 0; i < ARRAY_SIZE(exynos_drm_drivers); ++i) {
		struct exynos_drm_driver_info *info = &exynos_drm_drivers[i];
639

640
		if (!info->driver || !(info->flags & DRM_VIRTUAL_DEVICE))
641 642
			continue;

643 644 645 646
		pdev = platform_device_register_simple(
					info->driver->driver.name, -1, NULL, 0);
		if (IS_ERR(pdev))
			goto fail;
647
	}
648

649
	return 0;
650 651 652
fail:
	exynos_drm_unregister_devices();
	return PTR_ERR(pdev);
653 654
}

655
static void exynos_drm_unregister_drivers(void)
656
{
657
	int i;
658

659 660
	for (i = ARRAY_SIZE(exynos_drm_drivers) - 1; i >= 0; --i) {
		struct exynos_drm_driver_info *info = &exynos_drm_drivers[i];
661

662
		if (!info->driver)
663 664
			continue;

665
		platform_driver_unregister(info->driver);
666
	}
667 668
}

669
static int exynos_drm_register_drivers(void)
670
{
671
	int i, ret;
672

673 674
	for (i = 0; i < ARRAY_SIZE(exynos_drm_drivers); ++i) {
		struct exynos_drm_driver_info *info = &exynos_drm_drivers[i];
675

676 677
		if (!info->driver)
			continue;
678

679 680 681 682 683 684 685 686
		ret = platform_driver_register(info->driver);
		if (ret)
			goto fail;
	}
	return 0;
fail:
	exynos_drm_unregister_drivers();
	return ret;
687 688
}

689 690
static int exynos_drm_init(void)
{
691
	int ret;
692

693 694 695
	ret = exynos_drm_register_devices();
	if (ret)
		return ret;
696

697
	ret = exynos_drm_register_drivers();
698 699
	if (ret)
		goto err_unregister_pdevs;
700 701 702

	return 0;

703 704
err_unregister_pdevs:
	exynos_drm_unregister_devices();
705 706 707 708 709 710

	return ret;
}

static void exynos_drm_exit(void)
{
711
	exynos_drm_unregister_drivers();
712
	exynos_drm_unregister_devices();
713 714 715 716 717 718 719 720 721 722
}

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");