exynos_drm_drv.c 18.7 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 16
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
17

18
#include <linux/component.h>
19

20 21 22 23
#include <drm/exynos_drm.h>

#include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h"
24
#include "exynos_drm_encoder.h"
25 26 27
#include "exynos_drm_fbdev.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_gem.h"
28
#include "exynos_drm_plane.h"
29
#include "exynos_drm_vidi.h"
I
Inki Dae 已提交
30
#include "exynos_drm_dmabuf.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
static struct platform_device *exynos_drm_pdev;

43 44 45 46 47
static DEFINE_MUTEX(drm_component_lock);
static LIST_HEAD(drm_component_list);

struct component_dev {
	struct list_head list;
48 49 50 51
	struct device *crtc_dev;
	struct device *conn_dev;
	enum exynos_drm_output_type out_type;
	unsigned int dev_type_flag;
52 53
};

54 55 56 57 58 59 60
static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
{
	struct exynos_drm_private *private;
	int ret;
	int nr;

	private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL);
61
	if (!private)
62 63 64
		return -ENOMEM;

	INIT_LIST_HEAD(&private->pageflip_event_list);
65
	dev_set_drvdata(dev->dev, dev);
66 67
	dev->dev_private = (void *)private;

68 69 70 71 72 73 74 75 76
	/*
	 * create mapping to manage iommu table and set a pointer to iommu
	 * mapping structure to iommu_mapping of private data.
	 * also this iommu_mapping can be used to check if iommu is supported
	 * or not.
	 */
	ret = drm_create_iommu_mapping(dev);
	if (ret < 0) {
		DRM_ERROR("failed to create iommu mapping.\n");
77
		goto err_free_private;
78 79
	}

80 81 82 83
	drm_mode_config_init(dev);

	exynos_drm_mode_config_init(dev);

84
	for (nr = 0; nr < MAX_PLANE; nr++) {
85
		struct drm_plane *plane;
86
		unsigned long possible_crtcs = (1 << MAX_CRTC) - 1;
87

88 89 90
		plane = exynos_plane_init(dev, possible_crtcs,
					  DRM_PLANE_TYPE_OVERLAY);
		if (IS_ERR(plane))
91
			goto err_mode_config_cleanup;
92 93
	}

94 95 96
	/* init kms poll for handling hpd */
	drm_kms_helper_poll_init(dev);

97 98
	ret = drm_vblank_init(dev, MAX_CRTC);
	if (ret)
99
		goto err_mode_config_cleanup;
100

101 102 103
	/* setup possible_clones. */
	exynos_drm_encoder_setup(dev);

104 105
	platform_set_drvdata(dev->platformdev, dev);

106 107 108 109 110
	/* Try to bind all sub drivers. */
	ret = component_bind_all(dev->dev, dev);
	if (ret)
		goto err_cleanup_vblank;

111
	/* Probe non kms sub drivers and virtual display driver. */
112 113 114 115
	ret = exynos_drm_device_subdrv_probe(dev);
	if (ret)
		goto err_unbind_all;

116 117 118
	/* force connectors detection */
	drm_helper_hpd_irq_event(dev);

119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
	/*
	 * 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;

	/*
	 * with vblank_disable_allowed = true, vblank interrupt will be disabled
	 * by drm timer once a current process gives up ownership of
	 * vblank event.(after drm_vblank_put function is called)
	 */
	dev->vblank_disable_allowed = true;

136 137
	return 0;

138 139 140
err_unbind_all:
	component_unbind_all(dev->dev, dev);
err_cleanup_vblank:
141
	drm_vblank_cleanup(dev);
142 143
err_mode_config_cleanup:
	drm_mode_config_cleanup(dev);
144
	drm_release_iommu_mapping(dev);
145
err_free_private:
146 147 148 149 150 151 152
	kfree(private);

	return ret;
}

static int exynos_drm_unload(struct drm_device *dev)
{
153 154
	exynos_drm_device_subdrv_remove(dev);

155
	exynos_drm_fbdev_fini(dev);
156
	drm_kms_helper_poll_fini(dev);
157

158 159 160
	component_unbind_all(dev->dev, dev);
	drm_vblank_cleanup(dev);
	drm_mode_config_cleanup(dev);
161
	drm_release_iommu_mapping(dev);
162

163
	kfree(dev->dev_private);
164 165 166 167 168
	dev->dev_private = NULL;

	return 0;
}

169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
static int exynos_drm_suspend(struct drm_device *dev, pm_message_t state)
{
	struct drm_connector *connector;

	drm_modeset_lock_all(dev);
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		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(dev);

	return 0;
}

static int exynos_drm_resume(struct drm_device *dev)
{
	struct drm_connector *connector;

	drm_modeset_lock_all(dev);
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		if (connector->funcs->dpms)
			connector->funcs->dpms(connector, connector->dpms);
	}
197
	drm_modeset_unlock_all(dev);
198 199 200 201 202 203

	drm_helper_resume_force_mode(dev);

	return 0;
}

204 205
static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
{
J
Joonyoung Shim 已提交
206
	struct drm_exynos_file_private *file_priv;
207
	int ret;
J
Joonyoung Shim 已提交
208 209 210 211 212 213

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

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

215
	ret = exynos_drm_subdrv_open(dev, file);
216
	if (ret)
217
		goto err_file_priv_free;
218

219
	return ret;
220 221

err_file_priv_free:
222 223
	kfree(file_priv);
	file->driver_priv = NULL;
224
	return ret;
225 226
}

I
Inki Dae 已提交
227
static void exynos_drm_preclose(struct drm_device *dev,
228
					struct drm_file *file)
229 230 231 232 233
{
	exynos_drm_subdrv_close(dev, file);
}

static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
I
Inki Dae 已提交
234
{
235
	struct exynos_drm_private *private = dev->dev_private;
236 237
	struct drm_pending_vblank_event *v, *vt;
	struct drm_pending_event *e, *et;
238 239
	unsigned long flags;

240 241 242 243
	if (!file->driver_priv)
		return;

	/* Release all events not unhandled by page flip handler. */
244
	spin_lock_irqsave(&dev->event_lock, flags);
245
	list_for_each_entry_safe(v, vt, &private->pageflip_event_list,
246
			base.link) {
247 248 249 250
		if (v->base.file_priv == file) {
			list_del(&v->base.link);
			drm_vblank_put(dev, v->pipe);
			v->base.destroy(&v->base);
251 252
		}
	}
253

254 255 256 257 258 259
	/* Release all events handled by page flip handler but not freed. */
	list_for_each_entry_safe(e, et, &file->event_list, link) {
		list_del(&e->link);
		e->destroy(e);
	}
	spin_unlock_irqrestore(&dev->event_lock, flags);
I
Inki Dae 已提交
260

261 262 263 264
	kfree(file->driver_priv);
	file->driver_priv = NULL;
}

265 266 267 268 269
static void exynos_drm_lastclose(struct drm_device *dev)
{
	exynos_drm_fbdev_restore_mode(dev);
}

270
static const struct vm_operations_struct exynos_drm_gem_vm_ops = {
271 272 273 274 275
	.fault = exynos_drm_gem_fault,
	.open = drm_gem_vm_open,
	.close = drm_gem_vm_close,
};

R
Rob Clark 已提交
276
static const struct drm_ioctl_desc exynos_ioctls[] = {
277 278
	DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl,
			DRM_UNLOCKED | DRM_AUTH),
279 280
	DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET,
			exynos_drm_gem_get_ioctl, DRM_UNLOCKED),
281 282
	DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION,
			vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH),
J
Joonyoung Shim 已提交
283 284 285 286 287 288
	DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER,
			exynos_g2d_get_ver_ioctl, DRM_UNLOCKED | DRM_AUTH),
	DRM_IOCTL_DEF_DRV(EXYNOS_G2D_SET_CMDLIST,
			exynos_g2d_set_cmdlist_ioctl, DRM_UNLOCKED | DRM_AUTH),
	DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC,
			exynos_g2d_exec_ioctl, DRM_UNLOCKED | DRM_AUTH),
E
Eunchul Kim 已提交
289 290 291 292 293 294 295 296
	DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_PROPERTY,
			exynos_drm_ipp_get_property, DRM_UNLOCKED | DRM_AUTH),
	DRM_IOCTL_DEF_DRV(EXYNOS_IPP_SET_PROPERTY,
			exynos_drm_ipp_set_property, DRM_UNLOCKED | DRM_AUTH),
	DRM_IOCTL_DEF_DRV(EXYNOS_IPP_QUEUE_BUF,
			exynos_drm_ipp_queue_buf, DRM_UNLOCKED | DRM_AUTH),
	DRM_IOCTL_DEF_DRV(EXYNOS_IPP_CMD_CTRL,
			exynos_drm_ipp_cmd_ctrl, DRM_UNLOCKED | DRM_AUTH),
297 298
};

J
Joonyoung Shim 已提交
299 300 301 302 303 304 305
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,
306 307 308
#ifdef CONFIG_COMPAT
	.compat_ioctl = drm_compat_ioctl,
#endif
J
Joonyoung Shim 已提交
309 310 311
	.release	= drm_release,
};

312
static struct drm_driver exynos_drm_driver = {
313
	.driver_features	= DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
314 315
	.load			= exynos_drm_load,
	.unload			= exynos_drm_unload,
316 317
	.suspend		= exynos_drm_suspend,
	.resume			= exynos_drm_resume,
318
	.open			= exynos_drm_open,
I
Inki Dae 已提交
319
	.preclose		= exynos_drm_preclose,
320
	.lastclose		= exynos_drm_lastclose,
321
	.postclose		= exynos_drm_postclose,
322
	.set_busid		= drm_platform_set_busid,
323 324 325 326 327 328 329
	.get_vblank_counter	= drm_vblank_count,
	.enable_vblank		= exynos_drm_crtc_enable_vblank,
	.disable_vblank		= exynos_drm_crtc_disable_vblank,
	.gem_free_object	= exynos_drm_gem_free_object,
	.gem_vm_ops		= &exynos_drm_gem_vm_ops,
	.dumb_create		= exynos_drm_gem_dumb_create,
	.dumb_map_offset	= exynos_drm_gem_dumb_map_offset,
330
	.dumb_destroy		= drm_gem_dumb_destroy,
I
Inki Dae 已提交
331 332 333 334
	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
	.gem_prime_export	= exynos_dmabuf_prime_export,
	.gem_prime_import	= exynos_dmabuf_prime_import,
335
	.ioctls			= exynos_ioctls,
R
Rob Clark 已提交
336
	.num_ioctls		= ARRAY_SIZE(exynos_ioctls),
J
Joonyoung Shim 已提交
337
	.fops			= &exynos_drm_driver_fops,
338 339 340 341 342 343 344
	.name	= DRIVER_NAME,
	.desc	= DRIVER_DESC,
	.date	= DRIVER_DATE,
	.major	= DRIVER_MAJOR,
	.minor	= DRIVER_MINOR,
};

345 346 347 348 349 350
#ifdef CONFIG_PM_SLEEP
static int exynos_drm_sys_suspend(struct device *dev)
{
	struct drm_device *drm_dev = dev_get_drvdata(dev);
	pm_message_t message;

351
	if (pm_runtime_suspended(dev) || !drm_dev)
352 353 354 355 356 357 358 359 360 361
		return 0;

	message.event = PM_EVENT_SUSPEND;
	return exynos_drm_suspend(drm_dev, message);
}

static int exynos_drm_sys_resume(struct device *dev)
{
	struct drm_device *drm_dev = dev_get_drvdata(dev);

362
	if (pm_runtime_suspended(dev) || !drm_dev)
363 364 365 366 367 368 369 370 371 372
		return 0;

	return exynos_drm_resume(drm_dev);
}
#endif

static const struct dev_pm_ops exynos_drm_pm_ops = {
	SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_sys_suspend, exynos_drm_sys_resume)
};

373
int exynos_drm_component_add(struct device *dev,
374 375
				enum exynos_drm_device_type dev_type,
				enum exynos_drm_output_type out_type)
376 377
{
	struct component_dev *cdev;
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420

	if (dev_type != EXYNOS_DEVICE_TYPE_CRTC &&
			dev_type != EXYNOS_DEVICE_TYPE_CONNECTOR) {
		DRM_ERROR("invalid device type.\n");
		return -EINVAL;
	}

	mutex_lock(&drm_component_lock);

	/*
	 * Make sure to check if there is a component which has two device
	 * objects, for connector and for encoder/connector.
	 * It should make sure that crtc and encoder/connector drivers are
	 * ready before exynos drm core binds them.
	 */
	list_for_each_entry(cdev, &drm_component_list, list) {
		if (cdev->out_type == out_type) {
			/*
			 * If crtc and encoder/connector device objects are
			 * added already just return.
			 */
			if (cdev->dev_type_flag == (EXYNOS_DEVICE_TYPE_CRTC |
						EXYNOS_DEVICE_TYPE_CONNECTOR)) {
				mutex_unlock(&drm_component_lock);
				return 0;
			}

			if (dev_type == EXYNOS_DEVICE_TYPE_CRTC) {
				cdev->crtc_dev = dev;
				cdev->dev_type_flag |= dev_type;
			}

			if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR) {
				cdev->conn_dev = dev;
				cdev->dev_type_flag |= dev_type;
			}

			mutex_unlock(&drm_component_lock);
			return 0;
		}
	}

	mutex_unlock(&drm_component_lock);
421 422 423 424 425

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

426 427 428 429
	if (dev_type == EXYNOS_DEVICE_TYPE_CRTC)
		cdev->crtc_dev = dev;
	if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR)
		cdev->conn_dev = dev;
430

431 432
	cdev->out_type = out_type;
	cdev->dev_type_flag = dev_type;
433 434 435 436 437 438 439 440 441

	mutex_lock(&drm_component_lock);
	list_add_tail(&cdev->list, &drm_component_list);
	mutex_unlock(&drm_component_lock);

	return 0;
}

void exynos_drm_component_del(struct device *dev,
442
				enum exynos_drm_device_type dev_type)
443 444 445 446 447 448
{
	struct component_dev *cdev, *next;

	mutex_lock(&drm_component_lock);

	list_for_each_entry_safe(cdev, next, &drm_component_list, list) {
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
		if (dev_type == EXYNOS_DEVICE_TYPE_CRTC) {
			if (cdev->crtc_dev == dev) {
				cdev->crtc_dev = NULL;
				cdev->dev_type_flag &= ~dev_type;
			}
		}

		if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR) {
			if (cdev->conn_dev == dev) {
				cdev->conn_dev = NULL;
				cdev->dev_type_flag &= ~dev_type;
			}
		}

		/*
		 * Release cdev object only in case that both of crtc and
		 * encoder/connector device objects are NULL.
		 */
		if (!cdev->crtc_dev && !cdev->conn_dev) {
468 469 470
			list_del(&cdev->list);
			kfree(cdev);
		}
471 472

		break;
473 474 475 476 477
	}

	mutex_unlock(&drm_component_lock);
}

478
static int compare_dev(struct device *dev, void *data)
479 480 481 482
{
	return dev == (struct device *)data;
}

483
static struct component_match *exynos_drm_match_add(struct device *dev)
484
{
485
	struct component_match *match = NULL;
486
	struct component_dev *cdev;
487
	unsigned int attach_cnt = 0;
488 489 490 491

	mutex_lock(&drm_component_lock);

	list_for_each_entry(cdev, &drm_component_list, list) {
492 493 494 495 496 497 498 499 500
		/*
		 * Add components to master only in case that crtc and
		 * encoder/connector device objects exist.
		 */
		if (!cdev->crtc_dev || !cdev->conn_dev)
			continue;

		attach_cnt++;

501 502
		mutex_unlock(&drm_component_lock);

503 504 505 506 507
		/*
		 * fimd and dpi modules have same device object so add
		 * only crtc device object in this case.
		 */
		if (cdev->crtc_dev == cdev->conn_dev) {
508 509
			component_match_add(dev, &match, compare_dev,
						cdev->crtc_dev);
510 511
			goto out_lock;
		}
512

513 514 515 516 517 518
		/*
		 * Do not chage below call order.
		 * crtc device first should be added to master because
		 * connector/encoder need pipe number of crtc when they
		 * are created.
		 */
519 520
		component_match_add(dev, &match, compare_dev, cdev->crtc_dev);
		component_match_add(dev, &match, compare_dev, cdev->conn_dev);
521 522

out_lock:
523 524 525 526 527
		mutex_lock(&drm_component_lock);
	}

	mutex_unlock(&drm_component_lock);

528
	return attach_cnt ? match : ERR_PTR(-EPROBE_DEFER);
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
}

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,
544 545
};

546
static int exynos_drm_platform_probe(struct platform_device *pdev)
547
{
548
	struct component_match *match;
549 550
	int ret;

551
	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
552
	exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls);
553 554 555 556 557 558 559

#ifdef CONFIG_DRM_EXYNOS_FIMD
	ret = platform_driver_register(&fimd_driver);
	if (ret < 0)
		return ret;
#endif

560 561 562
#ifdef CONFIG_DRM_EXYNOS_DP
	ret = platform_driver_register(&dp_driver);
	if (ret < 0)
563
		goto err_unregister_fimd_drv;
564 565
#endif

A
Andrzej Hajda 已提交
566 567 568
#ifdef CONFIG_DRM_EXYNOS_DSI
	ret = platform_driver_register(&dsi_driver);
	if (ret < 0)
569
		goto err_unregister_dp_drv;
A
Andrzej Hajda 已提交
570 571
#endif

572 573 574
#ifdef CONFIG_DRM_EXYNOS_HDMI
	ret = platform_driver_register(&mixer_driver);
	if (ret < 0)
575 576
		goto err_unregister_dsi_drv;
	ret = platform_driver_register(&hdmi_driver);
577
	if (ret < 0)
578
		goto err_unregister_mixer_drv;
579 580
#endif

J
Joonyoung Shim 已提交
581 582 583
#ifdef CONFIG_DRM_EXYNOS_G2D
	ret = platform_driver_register(&g2d_driver);
	if (ret < 0)
584
		goto err_unregister_hdmi_drv;
J
Joonyoung Shim 已提交
585 586
#endif

E
Eunchul Kim 已提交
587 588 589
#ifdef CONFIG_DRM_EXYNOS_FIMC
	ret = platform_driver_register(&fimc_driver);
	if (ret < 0)
590
		goto err_unregister_g2d_drv;
E
Eunchul Kim 已提交
591 592
#endif

E
Eunchul Kim 已提交
593 594 595
#ifdef CONFIG_DRM_EXYNOS_ROTATOR
	ret = platform_driver_register(&rotator_driver);
	if (ret < 0)
596
		goto err_unregister_fimc_drv;
E
Eunchul Kim 已提交
597 598
#endif

E
Eunchul Kim 已提交
599 600 601
#ifdef CONFIG_DRM_EXYNOS_GSC
	ret = platform_driver_register(&gsc_driver);
	if (ret < 0)
602
		goto err_unregister_rotator_drv;
E
Eunchul Kim 已提交
603 604
#endif

E
Eunchul Kim 已提交
605 606 607
#ifdef CONFIG_DRM_EXYNOS_IPP
	ret = platform_driver_register(&ipp_driver);
	if (ret < 0)
608
		goto err_unregister_gsc_drv;
609 610 611

	ret = exynos_platform_device_ipp_register();
	if (ret < 0)
612
		goto err_unregister_ipp_drv;
E
Eunchul Kim 已提交
613 614
#endif

615 616 617 618 619 620 621 622
	match = exynos_drm_match_add(&pdev->dev);
	if (IS_ERR(match)) {
		ret = PTR_ERR(match);
		goto err_unregister_resources;
	}

	ret = component_master_add_with_match(&pdev->dev, &exynos_drm_ops,
						match);
623
	if (ret < 0)
624
		goto err_unregister_resources;
625

626 627 628
	return ret;

err_unregister_resources:
629

E
Eunchul Kim 已提交
630
#ifdef CONFIG_DRM_EXYNOS_IPP
631
	exynos_platform_device_ipp_unregister();
632
err_unregister_ipp_drv:
E
Eunchul Kim 已提交
633
	platform_driver_unregister(&ipp_driver);
634
err_unregister_gsc_drv:
E
Eunchul Kim 已提交
635 636
#endif

E
Eunchul Kim 已提交
637 638
#ifdef CONFIG_DRM_EXYNOS_GSC
	platform_driver_unregister(&gsc_driver);
639
err_unregister_rotator_drv:
E
Eunchul Kim 已提交
640 641
#endif

E
Eunchul Kim 已提交
642 643
#ifdef CONFIG_DRM_EXYNOS_ROTATOR
	platform_driver_unregister(&rotator_driver);
644
err_unregister_fimc_drv:
E
Eunchul Kim 已提交
645 646
#endif

E
Eunchul Kim 已提交
647 648
#ifdef CONFIG_DRM_EXYNOS_FIMC
	platform_driver_unregister(&fimc_driver);
649
err_unregister_g2d_drv:
E
Eunchul Kim 已提交
650 651
#endif

J
Joonyoung Shim 已提交
652 653
#ifdef CONFIG_DRM_EXYNOS_G2D
	platform_driver_unregister(&g2d_driver);
654
err_unregister_hdmi_drv:
655 656
#endif

657 658
#ifdef CONFIG_DRM_EXYNOS_HDMI
	platform_driver_unregister(&hdmi_driver);
659 660
err_unregister_mixer_drv:
	platform_driver_unregister(&mixer_driver);
661
err_unregister_dsi_drv:
662
#endif
663

A
Andrzej Hajda 已提交
664 665
#ifdef CONFIG_DRM_EXYNOS_DSI
	platform_driver_unregister(&dsi_driver);
666
err_unregister_dp_drv:
A
Andrzej Hajda 已提交
667 668
#endif

669 670
#ifdef CONFIG_DRM_EXYNOS_DP
	platform_driver_unregister(&dp_driver);
671 672 673 674 675
err_unregister_fimd_drv:
#endif

#ifdef CONFIG_DRM_EXYNOS_FIMD
	platform_driver_unregister(&fimd_driver);
676 677
#endif
	return ret;
678 679
}

680
static int exynos_drm_platform_remove(struct platform_device *pdev)
681
{
E
Eunchul Kim 已提交
682
#ifdef CONFIG_DRM_EXYNOS_IPP
683
	exynos_platform_device_ipp_unregister();
E
Eunchul Kim 已提交
684 685 686
	platform_driver_unregister(&ipp_driver);
#endif

E
Eunchul Kim 已提交
687 688 689 690
#ifdef CONFIG_DRM_EXYNOS_GSC
	platform_driver_unregister(&gsc_driver);
#endif

E
Eunchul Kim 已提交
691 692 693 694
#ifdef CONFIG_DRM_EXYNOS_ROTATOR
	platform_driver_unregister(&rotator_driver);
#endif

E
Eunchul Kim 已提交
695 696 697 698
#ifdef CONFIG_DRM_EXYNOS_FIMC
	platform_driver_unregister(&fimc_driver);
#endif

J
Joonyoung Shim 已提交
699 700 701 702
#ifdef CONFIG_DRM_EXYNOS_G2D
	platform_driver_unregister(&g2d_driver);
#endif

703 704 705 706 707 708 709 710
#ifdef CONFIG_DRM_EXYNOS_HDMI
	platform_driver_unregister(&mixer_driver);
	platform_driver_unregister(&hdmi_driver);
#endif

#ifdef CONFIG_DRM_EXYNOS_FIMD
	platform_driver_unregister(&fimd_driver);
#endif
711

A
Andrzej Hajda 已提交
712 713 714 715
#ifdef CONFIG_DRM_EXYNOS_DSI
	platform_driver_unregister(&dsi_driver);
#endif

716 717 718
#ifdef CONFIG_DRM_EXYNOS_DP
	platform_driver_unregister(&dp_driver);
#endif
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756
	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	= {
		.owner	= THIS_MODULE,
		.name	= "exynos-drm",
		.pm	= &exynos_drm_pm_ops,
	},
};

static int exynos_drm_init(void)
{
	int ret;

	exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1,
								NULL, 0);
	if (IS_ERR(exynos_drm_pdev))
		return PTR_ERR(exynos_drm_pdev);

#ifdef CONFIG_DRM_EXYNOS_VIDI
	ret = exynos_drm_probe_vidi();
	if (ret < 0)
		goto err_unregister_pd;
#endif

	ret = platform_driver_register(&exynos_drm_platform_driver);
	if (ret)
		goto err_remove_vidi;

	return 0;

err_remove_vidi:
#ifdef CONFIG_DRM_EXYNOS_VIDI
	exynos_drm_remove_vidi();
757 758

err_unregister_pd:
759
#endif
760
	platform_device_unregister(exynos_drm_pdev);
761 762 763 764 765 766

	return ret;
}

static void exynos_drm_exit(void)
{
767
	platform_driver_unregister(&exynos_drm_platform_driver);
768 769 770 771
#ifdef CONFIG_DRM_EXYNOS_VIDI
	exynos_drm_remove_vidi();
#endif
	platform_device_unregister(exynos_drm_pdev);
772 773 774 775 776 777 778 779 780 781
}

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