exynos_drm_drv.c 19.4 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
		plane = exynos_plane_init(dev, possible_crtcs,
					  DRM_PLANE_TYPE_OVERLAY);
90 91 92 93 94
		if (!IS_ERR(plane))
			continue;

		ret = PTR_ERR(plane);
		goto err_mode_config_cleanup;
95 96
	}

97 98 99
	/* setup possible_clones. */
	exynos_drm_encoder_setup(dev);

100 101
	platform_set_drvdata(dev->platformdev, dev);

102 103 104
	/* Try to bind all sub drivers. */
	ret = component_bind_all(dev->dev, dev);
	if (ret)
105 106 107 108 109
		goto err_mode_config_cleanup;

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

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

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

133 134 135 136 137 138
	/* init kms poll for handling hpd */
	drm_kms_helper_poll_init(dev);

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

139 140
	return 0;

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

	return ret;
}

static int exynos_drm_unload(struct drm_device *dev)
{
156 157
	exynos_drm_device_subdrv_remove(dev);

158
	exynos_drm_fbdev_fini(dev);
159
	drm_kms_helper_poll_fini(dev);
160

161
	drm_vblank_cleanup(dev);
162
	component_unbind_all(dev->dev, dev);
163
	drm_mode_config_cleanup(dev);
164
	drm_release_iommu_mapping(dev);
165

166
	kfree(dev->dev_private);
167 168 169 170 171
	dev->dev_private = NULL;

	return 0;
}

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) {
197 198 199 200 201 202
		if (connector->funcs->dpms) {
			int dpms = connector->dpms;

			connector->dpms = DRM_MODE_DPMS_OFF;
			connector->funcs->dpms(connector, dpms);
		}
203
	}
204
	drm_modeset_unlock_all(dev);
205 206 207 208 209 210

	drm_helper_resume_force_mode(dev);

	return 0;
}

211 212
static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
{
J
Joonyoung Shim 已提交
213
	struct drm_exynos_file_private *file_priv;
214
	int ret;
J
Joonyoung Shim 已提交
215 216 217 218 219 220

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

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

222
	ret = exynos_drm_subdrv_open(dev, file);
223
	if (ret)
224
		goto err_file_priv_free;
225

226
	return ret;
227 228

err_file_priv_free:
229 230
	kfree(file_priv);
	file->driver_priv = NULL;
231
	return ret;
232 233
}

I
Inki Dae 已提交
234
static void exynos_drm_preclose(struct drm_device *dev,
235
					struct drm_file *file)
236 237 238 239 240
{
	exynos_drm_subdrv_close(dev, file);
}

static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
I
Inki Dae 已提交
241
{
242
	struct exynos_drm_private *private = dev->dev_private;
243 244
	struct drm_pending_vblank_event *v, *vt;
	struct drm_pending_event *e, *et;
245 246
	unsigned long flags;

247 248 249 250
	if (!file->driver_priv)
		return;

	/* Release all events not unhandled by page flip handler. */
251
	spin_lock_irqsave(&dev->event_lock, flags);
252
	list_for_each_entry_safe(v, vt, &private->pageflip_event_list,
253
			base.link) {
254 255 256 257
		if (v->base.file_priv == file) {
			list_del(&v->base.link);
			drm_vblank_put(dev, v->pipe);
			v->base.destroy(&v->base);
258 259
		}
	}
260

261 262 263 264 265 266
	/* 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 已提交
267

268 269 270 271
	kfree(file->driver_priv);
	file->driver_priv = NULL;
}

272 273 274 275 276
static void exynos_drm_lastclose(struct drm_device *dev)
{
	exynos_drm_fbdev_restore_mode(dev);
}

277
static const struct vm_operations_struct exynos_drm_gem_vm_ops = {
278 279 280 281 282
	.fault = exynos_drm_gem_fault,
	.open = drm_gem_vm_open,
	.close = drm_gem_vm_close,
};

R
Rob Clark 已提交
283
static const struct drm_ioctl_desc exynos_ioctls[] = {
284 285
	DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl,
			DRM_UNLOCKED | DRM_AUTH),
286 287
	DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET,
			exynos_drm_gem_get_ioctl, DRM_UNLOCKED),
288 289
	DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION,
			vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH),
J
Joonyoung Shim 已提交
290 291 292 293 294 295
	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 已提交
296 297 298 299 300 301 302 303
	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),
304 305
};

J
Joonyoung Shim 已提交
306 307 308 309 310 311 312
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,
313 314 315
#ifdef CONFIG_COMPAT
	.compat_ioctl = drm_compat_ioctl,
#endif
J
Joonyoung Shim 已提交
316 317 318
	.release	= drm_release,
};

319
static struct drm_driver exynos_drm_driver = {
320
	.driver_features	= DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
321 322
	.load			= exynos_drm_load,
	.unload			= exynos_drm_unload,
323 324
	.suspend		= exynos_drm_suspend,
	.resume			= exynos_drm_resume,
325
	.open			= exynos_drm_open,
I
Inki Dae 已提交
326
	.preclose		= exynos_drm_preclose,
327
	.lastclose		= exynos_drm_lastclose,
328
	.postclose		= exynos_drm_postclose,
329
	.set_busid		= drm_platform_set_busid,
330 331 332 333 334 335 336
	.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,
337
	.dumb_destroy		= drm_gem_dumb_destroy,
I
Inki Dae 已提交
338 339 340 341
	.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,
342
	.ioctls			= exynos_ioctls,
R
Rob Clark 已提交
343
	.num_ioctls		= ARRAY_SIZE(exynos_ioctls),
J
Joonyoung Shim 已提交
344
	.fops			= &exynos_drm_driver_fops,
345 346 347 348 349 350 351
	.name	= DRIVER_NAME,
	.desc	= DRIVER_DESC,
	.date	= DRIVER_DATE,
	.major	= DRIVER_MAJOR,
	.minor	= DRIVER_MINOR,
};

352 353 354 355 356 357
#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;

358
	if (pm_runtime_suspended(dev) || !drm_dev)
359 360 361 362 363 364 365 366 367 368
		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);

369
	if (pm_runtime_suspended(dev) || !drm_dev)
370 371 372 373 374 375 376 377 378 379
		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)
};

380
int exynos_drm_component_add(struct device *dev,
381 382
				enum exynos_drm_device_type dev_type,
				enum exynos_drm_output_type out_type)
383 384
{
	struct component_dev *cdev;
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 421 422 423 424 425 426 427

	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);
428 429 430 431 432

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

433 434 435 436
	if (dev_type == EXYNOS_DEVICE_TYPE_CRTC)
		cdev->crtc_dev = dev;
	if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR)
		cdev->conn_dev = dev;
437

438 439
	cdev->out_type = out_type;
	cdev->dev_type_flag = dev_type;
440 441 442 443 444 445 446 447 448

	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,
449
				enum exynos_drm_device_type dev_type)
450 451 452 453 454 455
{
	struct component_dev *cdev, *next;

	mutex_lock(&drm_component_lock);

	list_for_each_entry_safe(cdev, next, &drm_component_list, list) {
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
		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) {
475 476 477
			list_del(&cdev->list);
			kfree(cdev);
		}
478 479

		break;
480 481 482 483 484
	}

	mutex_unlock(&drm_component_lock);
}

485
static int compare_dev(struct device *dev, void *data)
486 487 488 489
{
	return dev == (struct device *)data;
}

490
static struct component_match *exynos_drm_match_add(struct device *dev)
491
{
492
	struct component_match *match = NULL;
493
	struct component_dev *cdev;
494
	unsigned int attach_cnt = 0;
495 496 497

	mutex_lock(&drm_component_lock);

498 499 500 501 502 503
	/* Do not retry to probe if there is no any kms driver regitered. */
	if (list_empty(&drm_component_list)) {
		mutex_unlock(&drm_component_lock);
		return ERR_PTR(-ENODEV);
	}

504
	list_for_each_entry(cdev, &drm_component_list, list) {
505 506 507 508 509 510 511 512 513
		/*
		 * 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++;

514 515
		mutex_unlock(&drm_component_lock);

516 517 518 519 520
		/*
		 * fimd and dpi modules have same device object so add
		 * only crtc device object in this case.
		 */
		if (cdev->crtc_dev == cdev->conn_dev) {
521 522
			component_match_add(dev, &match, compare_dev,
						cdev->crtc_dev);
523 524
			goto out_lock;
		}
525

526 527 528 529 530 531
		/*
		 * 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.
		 */
532 533
		component_match_add(dev, &match, compare_dev, cdev->crtc_dev);
		component_match_add(dev, &match, compare_dev, cdev->conn_dev);
534 535

out_lock:
536 537 538 539 540
		mutex_lock(&drm_component_lock);
	}

	mutex_unlock(&drm_component_lock);

541
	return attach_cnt ? match : ERR_PTR(-EPROBE_DEFER);
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
}

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,
557 558
};

559
static int exynos_drm_platform_probe(struct platform_device *pdev)
560
{
561
	struct component_match *match;
562 563
	int ret;

564
	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
565
	exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls);
566 567 568 569 570 571 572

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

573 574 575
#ifdef CONFIG_DRM_EXYNOS_DP
	ret = platform_driver_register(&dp_driver);
	if (ret < 0)
576
		goto err_unregister_fimd_drv;
577 578
#endif

A
Andrzej Hajda 已提交
579 580 581
#ifdef CONFIG_DRM_EXYNOS_DSI
	ret = platform_driver_register(&dsi_driver);
	if (ret < 0)
582
		goto err_unregister_dp_drv;
A
Andrzej Hajda 已提交
583 584
#endif

585 586 587
#ifdef CONFIG_DRM_EXYNOS_HDMI
	ret = platform_driver_register(&mixer_driver);
	if (ret < 0)
588 589
		goto err_unregister_dsi_drv;
	ret = platform_driver_register(&hdmi_driver);
590
	if (ret < 0)
591
		goto err_unregister_mixer_drv;
592 593
#endif

J
Joonyoung Shim 已提交
594 595 596
#ifdef CONFIG_DRM_EXYNOS_G2D
	ret = platform_driver_register(&g2d_driver);
	if (ret < 0)
597
		goto err_unregister_hdmi_drv;
J
Joonyoung Shim 已提交
598 599
#endif

E
Eunchul Kim 已提交
600 601 602
#ifdef CONFIG_DRM_EXYNOS_FIMC
	ret = platform_driver_register(&fimc_driver);
	if (ret < 0)
603
		goto err_unregister_g2d_drv;
E
Eunchul Kim 已提交
604 605
#endif

E
Eunchul Kim 已提交
606 607 608
#ifdef CONFIG_DRM_EXYNOS_ROTATOR
	ret = platform_driver_register(&rotator_driver);
	if (ret < 0)
609
		goto err_unregister_fimc_drv;
E
Eunchul Kim 已提交
610 611
#endif

E
Eunchul Kim 已提交
612 613 614
#ifdef CONFIG_DRM_EXYNOS_GSC
	ret = platform_driver_register(&gsc_driver);
	if (ret < 0)
615
		goto err_unregister_rotator_drv;
E
Eunchul Kim 已提交
616 617
#endif

E
Eunchul Kim 已提交
618 619 620
#ifdef CONFIG_DRM_EXYNOS_IPP
	ret = platform_driver_register(&ipp_driver);
	if (ret < 0)
621
		goto err_unregister_gsc_drv;
622 623 624

	ret = exynos_platform_device_ipp_register();
	if (ret < 0)
625
		goto err_unregister_ipp_drv;
E
Eunchul Kim 已提交
626 627
#endif

628 629 630 631 632 633 634 635
	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);
636
	if (ret < 0)
637
		goto err_unregister_resources;
638

639 640 641
	return ret;

err_unregister_resources:
642

E
Eunchul Kim 已提交
643
#ifdef CONFIG_DRM_EXYNOS_IPP
644
	exynos_platform_device_ipp_unregister();
645
err_unregister_ipp_drv:
E
Eunchul Kim 已提交
646
	platform_driver_unregister(&ipp_driver);
647
err_unregister_gsc_drv:
E
Eunchul Kim 已提交
648 649
#endif

E
Eunchul Kim 已提交
650 651
#ifdef CONFIG_DRM_EXYNOS_GSC
	platform_driver_unregister(&gsc_driver);
652
err_unregister_rotator_drv:
E
Eunchul Kim 已提交
653 654
#endif

E
Eunchul Kim 已提交
655 656
#ifdef CONFIG_DRM_EXYNOS_ROTATOR
	platform_driver_unregister(&rotator_driver);
657
err_unregister_fimc_drv:
E
Eunchul Kim 已提交
658 659
#endif

E
Eunchul Kim 已提交
660 661
#ifdef CONFIG_DRM_EXYNOS_FIMC
	platform_driver_unregister(&fimc_driver);
662
err_unregister_g2d_drv:
E
Eunchul Kim 已提交
663 664
#endif

J
Joonyoung Shim 已提交
665 666
#ifdef CONFIG_DRM_EXYNOS_G2D
	platform_driver_unregister(&g2d_driver);
667
err_unregister_hdmi_drv:
668 669
#endif

670 671
#ifdef CONFIG_DRM_EXYNOS_HDMI
	platform_driver_unregister(&hdmi_driver);
672 673
err_unregister_mixer_drv:
	platform_driver_unregister(&mixer_driver);
674
err_unregister_dsi_drv:
675
#endif
676

A
Andrzej Hajda 已提交
677 678
#ifdef CONFIG_DRM_EXYNOS_DSI
	platform_driver_unregister(&dsi_driver);
679
err_unregister_dp_drv:
A
Andrzej Hajda 已提交
680 681
#endif

682 683
#ifdef CONFIG_DRM_EXYNOS_DP
	platform_driver_unregister(&dp_driver);
684 685 686 687 688
err_unregister_fimd_drv:
#endif

#ifdef CONFIG_DRM_EXYNOS_FIMD
	platform_driver_unregister(&fimd_driver);
689 690
#endif
	return ret;
691 692
}

693
static int exynos_drm_platform_remove(struct platform_device *pdev)
694
{
E
Eunchul Kim 已提交
695
#ifdef CONFIG_DRM_EXYNOS_IPP
696
	exynos_platform_device_ipp_unregister();
E
Eunchul Kim 已提交
697 698 699
	platform_driver_unregister(&ipp_driver);
#endif

E
Eunchul Kim 已提交
700 701 702 703
#ifdef CONFIG_DRM_EXYNOS_GSC
	platform_driver_unregister(&gsc_driver);
#endif

E
Eunchul Kim 已提交
704 705 706 707
#ifdef CONFIG_DRM_EXYNOS_ROTATOR
	platform_driver_unregister(&rotator_driver);
#endif

E
Eunchul Kim 已提交
708 709 710 711
#ifdef CONFIG_DRM_EXYNOS_FIMC
	platform_driver_unregister(&fimc_driver);
#endif

J
Joonyoung Shim 已提交
712 713 714 715
#ifdef CONFIG_DRM_EXYNOS_G2D
	platform_driver_unregister(&g2d_driver);
#endif

716 717 718 719 720 721 722 723
#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
724

A
Andrzej Hajda 已提交
725 726 727 728
#ifdef CONFIG_DRM_EXYNOS_DSI
	platform_driver_unregister(&dsi_driver);
#endif

729 730 731
#ifdef CONFIG_DRM_EXYNOS_DP
	platform_driver_unregister(&dp_driver);
#endif
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749
	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;

750 751 752 753 754 755 756 757 758 759 760 761
	/*
	 * Register device object only in case of Exynos SoC.
	 *
	 * Below codes resolves temporarily infinite loop issue incurred
	 * by Exynos drm driver when using multi-platform kernel.
	 * So these codes will be replaced with more generic way later.
	 */
	if (!of_machine_is_compatible("samsung,exynos3") &&
			!of_machine_is_compatible("samsung,exynos4") &&
			!of_machine_is_compatible("samsung,exynos5"))
		return -ENODEV;

762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781
	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();
782 783

err_unregister_pd:
784
#endif
785
	platform_device_unregister(exynos_drm_pdev);
786 787 788 789 790 791

	return ret;
}

static void exynos_drm_exit(void)
{
792
	platform_driver_unregister(&exynos_drm_platform_driver);
793 794 795 796
#ifdef CONFIG_DRM_EXYNOS_VIDI
	exynos_drm_remove_vidi();
#endif
	platform_device_unregister(exynos_drm_pdev);
797 798 799 800 801 802 803 804 805 806
}

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