blob: ab7d182063c3aef8699e0d3322cd9af5dbeeaacd [file] [log] [blame]
Inki Dae1c248b72011-10-04 19:19:01 +09001/*
2 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
3 * Authors:
4 * Inki Dae <inki.dae@samsung.com>
5 * Joonyoung Shim <jy0922.shim@samsung.com>
6 * Seung-Woo Kim <sw0312.kim@samsung.com>
7 *
Inki Daed81aecb2012-12-18 02:30:17 +09008 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
Inki Dae1c248b72011-10-04 19:19:01 +090012 */
13
Sean Paulaf65c802014-01-30 16:19:27 -050014#include <linux/pm_runtime.h>
David Howells760285e2012-10-02 18:01:07 +010015#include <drm/drmP.h>
16#include <drm/drm_crtc_helper.h>
Inki Dae1c248b72011-10-04 19:19:01 +090017
Inki Dae96f54212013-12-20 19:16:24 +090018#include <linux/anon_inodes.h>
Inki Daef37cd5e2014-05-09 14:25:20 +090019#include <linux/component.h>
Inki Dae96f54212013-12-20 19:16:24 +090020
Inki Dae1c248b72011-10-04 19:19:01 +090021#include <drm/exynos_drm.h>
22
23#include "exynos_drm_drv.h"
24#include "exynos_drm_crtc.h"
Inki Daed081f562012-02-15 11:25:19 +090025#include "exynos_drm_encoder.h"
Inki Dae1c248b72011-10-04 19:19:01 +090026#include "exynos_drm_fbdev.h"
27#include "exynos_drm_fb.h"
28#include "exynos_drm_gem.h"
Joonyoung Shim864ee9e2011-12-08 17:54:07 +090029#include "exynos_drm_plane.h"
Inki Daeb73d1232012-03-21 10:55:26 +090030#include "exynos_drm_vidi.h"
Inki Daeb2df26c2012-04-23 21:01:28 +090031#include "exynos_drm_dmabuf.h"
Joonyoung Shimd7f16422012-05-17 20:06:32 +090032#include "exynos_drm_g2d.h"
Eunchul Kimcb471f12012-12-14 18:10:31 +090033#include "exynos_drm_ipp.h"
Inki Dae0519f9a2012-10-20 07:53:42 -070034#include "exynos_drm_iommu.h"
Inki Dae1c248b72011-10-04 19:19:01 +090035
Inki Dae0edf9932011-12-15 17:31:24 +090036#define DRIVER_NAME "exynos"
Inki Dae1c248b72011-10-04 19:19:01 +090037#define DRIVER_DESC "Samsung SoC DRM"
38#define DRIVER_DATE "20110530"
39#define DRIVER_MAJOR 1
40#define DRIVER_MINOR 0
41
Inki Dae52c68812011-12-16 21:31:12 +090042#define VBLANK_OFF_DELAY 50000
43
Rahul Sharma422bd002012-10-16 05:50:12 +053044static struct platform_device *exynos_drm_pdev;
45
Inki Daef37cd5e2014-05-09 14:25:20 +090046static DEFINE_MUTEX(drm_component_lock);
47static LIST_HEAD(drm_component_list);
48
49struct component_dev {
50 struct list_head list;
Inki Daedf5225b2014-05-29 18:28:02 +090051 struct device *crtc_dev;
52 struct device *conn_dev;
53 enum exynos_drm_output_type out_type;
54 unsigned int dev_type_flag;
Inki Daef37cd5e2014-05-09 14:25:20 +090055};
56
Inki Dae1c248b72011-10-04 19:19:01 +090057static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
58{
59 struct exynos_drm_private *private;
60 int ret;
61 int nr;
62
Inki Dae1c248b72011-10-04 19:19:01 +090063 private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +090064 if (!private)
Inki Dae1c248b72011-10-04 19:19:01 +090065 return -ENOMEM;
Inki Dae1c248b72011-10-04 19:19:01 +090066
67 INIT_LIST_HEAD(&private->pageflip_event_list);
Sean Paulaf65c802014-01-30 16:19:27 -050068 dev_set_drvdata(dev->dev, dev);
Inki Dae1c248b72011-10-04 19:19:01 +090069 dev->dev_private = (void *)private;
70
Inki Dae0519f9a2012-10-20 07:53:42 -070071 /*
72 * create mapping to manage iommu table and set a pointer to iommu
73 * mapping structure to iommu_mapping of private data.
74 * also this iommu_mapping can be used to check if iommu is supported
75 * or not.
76 */
77 ret = drm_create_iommu_mapping(dev);
78 if (ret < 0) {
79 DRM_ERROR("failed to create iommu mapping.\n");
Inki Daed2ba65f2014-02-28 18:37:02 +090080 goto err_free_private;
Inki Dae0519f9a2012-10-20 07:53:42 -070081 }
82
Inki Dae1c248b72011-10-04 19:19:01 +090083 drm_mode_config_init(dev);
84
85 exynos_drm_mode_config_init(dev);
86
Joonyoung Shim864ee9e2011-12-08 17:54:07 +090087 for (nr = 0; nr < MAX_PLANE; nr++) {
Joonyoung Shimb5d2eb32012-06-27 14:27:04 +090088 struct drm_plane *plane;
Sean Paul3f283d92014-01-30 16:19:11 -050089 unsigned long possible_crtcs = (1 << MAX_CRTC) - 1;
Joonyoung Shimb5d2eb32012-06-27 14:27:04 +090090
91 plane = exynos_plane_init(dev, possible_crtcs, false);
92 if (!plane)
Inki Daef37cd5e2014-05-09 14:25:20 +090093 goto err_mode_config_cleanup;
Joonyoung Shim864ee9e2011-12-08 17:54:07 +090094 }
95
Andrzej Hajda8e527f02014-03-17 11:27:18 +010096 /* init kms poll for handling hpd */
97 drm_kms_helper_poll_init(dev);
98
Inki Dae1c248b72011-10-04 19:19:01 +090099 ret = drm_vblank_init(dev, MAX_CRTC);
100 if (ret)
Inki Daef37cd5e2014-05-09 14:25:20 +0900101 goto err_mode_config_cleanup;
Inki Dae1c248b72011-10-04 19:19:01 +0900102
Inki Daed081f562012-02-15 11:25:19 +0900103 /* setup possible_clones. */
104 exynos_drm_encoder_setup(dev);
105
Inki Dae52c68812011-12-16 21:31:12 +0900106 drm_vblank_offdelay = VBLANK_OFF_DELAY;
107
Daniel Vettera9a346d2013-12-11 11:34:23 +0100108 platform_set_drvdata(dev->platformdev, dev);
109
Inki Daef37cd5e2014-05-09 14:25:20 +0900110 /* Try to bind all sub drivers. */
111 ret = component_bind_all(dev->dev, dev);
112 if (ret)
113 goto err_cleanup_vblank;
114
Inki Daed1afe7d2014-04-14 12:55:55 +0900115 /* Probe non kms sub drivers and virtual display driver. */
Inki Daef37cd5e2014-05-09 14:25:20 +0900116 ret = exynos_drm_device_subdrv_probe(dev);
117 if (ret)
118 goto err_unbind_all;
119
Andrzej Hajda25928a32014-03-17 11:27:17 +0100120 /* force connectors detection */
121 drm_helper_hpd_irq_event(dev);
122
Inki Dae1c248b72011-10-04 19:19:01 +0900123 return 0;
124
Inki Daef37cd5e2014-05-09 14:25:20 +0900125err_unbind_all:
126 component_unbind_all(dev->dev, dev);
127err_cleanup_vblank:
Inki Dae1c248b72011-10-04 19:19:01 +0900128 drm_vblank_cleanup(dev);
Sean Paul080be03d2014-02-19 21:02:55 +0900129err_mode_config_cleanup:
130 drm_mode_config_cleanup(dev);
Inki Dae0519f9a2012-10-20 07:53:42 -0700131 drm_release_iommu_mapping(dev);
Inki Daed2ba65f2014-02-28 18:37:02 +0900132err_free_private:
Inki Dae1c248b72011-10-04 19:19:01 +0900133 kfree(private);
134
135 return ret;
136}
137
138static int exynos_drm_unload(struct drm_device *dev)
139{
Inki Daef37cd5e2014-05-09 14:25:20 +0900140 exynos_drm_device_subdrv_remove(dev);
141
Inki Dae1c248b72011-10-04 19:19:01 +0900142 exynos_drm_fbdev_fini(dev);
Inki Dae1c248b72011-10-04 19:19:01 +0900143 drm_vblank_cleanup(dev);
Seung-Woo Kim7db3eba2011-10-18 16:58:05 +0900144 drm_kms_helper_poll_fini(dev);
Inki Dae1c248b72011-10-04 19:19:01 +0900145 drm_mode_config_cleanup(dev);
Inki Dae0519f9a2012-10-20 07:53:42 -0700146
147 drm_release_iommu_mapping(dev);
Inki Dae1c248b72011-10-04 19:19:01 +0900148 kfree(dev->dev_private);
149
Inki Daef37cd5e2014-05-09 14:25:20 +0900150 component_unbind_all(dev->dev, dev);
Inki Dae1c248b72011-10-04 19:19:01 +0900151 dev->dev_private = NULL;
152
153 return 0;
154}
155
Inki Dae96f54212013-12-20 19:16:24 +0900156static const struct file_operations exynos_drm_gem_fops = {
157 .mmap = exynos_drm_gem_mmap_buffer,
158};
159
Sean Paulaf65c802014-01-30 16:19:27 -0500160static int exynos_drm_suspend(struct drm_device *dev, pm_message_t state)
161{
162 struct drm_connector *connector;
163
164 drm_modeset_lock_all(dev);
165 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
166 int old_dpms = connector->dpms;
167
168 if (connector->funcs->dpms)
169 connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
170
171 /* Set the old mode back to the connector for resume */
172 connector->dpms = old_dpms;
173 }
174 drm_modeset_unlock_all(dev);
175
176 return 0;
177}
178
179static int exynos_drm_resume(struct drm_device *dev)
180{
181 struct drm_connector *connector;
182
183 drm_modeset_lock_all(dev);
184 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
185 if (connector->funcs->dpms)
186 connector->funcs->dpms(connector, connector->dpms);
187 }
Takashi Iwaia16f2232014-05-09 08:14:15 +0200188 drm_modeset_unlock_all(dev);
Sean Paulaf65c802014-01-30 16:19:27 -0500189
190 drm_helper_resume_force_mode(dev);
Sean Paulaf65c802014-01-30 16:19:27 -0500191
192 return 0;
193}
194
Joonyoung Shim9084f7b2012-03-16 18:47:09 +0900195static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
Inki Daeccf4d882011-10-14 13:29:51 +0900196{
Joonyoung Shimd7f16422012-05-17 20:06:32 +0900197 struct drm_exynos_file_private *file_priv;
Inki Dae96f54212013-12-20 19:16:24 +0900198 struct file *anon_filp;
YoungJun Choba3706c2013-07-01 17:00:47 +0900199 int ret;
Joonyoung Shimd7f16422012-05-17 20:06:32 +0900200
Joonyoung Shimd7f16422012-05-17 20:06:32 +0900201 file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
202 if (!file_priv)
203 return -ENOMEM;
204
Joonyoung Shimd7f16422012-05-17 20:06:32 +0900205 file->driver_priv = file_priv;
Inki Daeb2df26c2012-04-23 21:01:28 +0900206
YoungJun Choba3706c2013-07-01 17:00:47 +0900207 ret = exynos_drm_subdrv_open(dev, file);
Sachin Kamat6ca605f2014-01-16 11:31:26 +0530208 if (ret)
Daniel Kurtz307ceaf2014-03-17 11:28:06 +0800209 goto err_file_priv_free;
YoungJun Choba3706c2013-07-01 17:00:47 +0900210
Inki Dae96f54212013-12-20 19:16:24 +0900211 anon_filp = anon_inode_getfile("exynos_gem", &exynos_drm_gem_fops,
212 NULL, 0);
213 if (IS_ERR(anon_filp)) {
Sachin Kamat6ca605f2014-01-16 11:31:26 +0530214 ret = PTR_ERR(anon_filp);
Daniel Kurtz307ceaf2014-03-17 11:28:06 +0800215 goto err_subdrv_close;
Inki Dae96f54212013-12-20 19:16:24 +0900216 }
217
218 anon_filp->f_mode = FMODE_READ | FMODE_WRITE;
219 file_priv->anon_filp = anon_filp;
220
YoungJun Choba3706c2013-07-01 17:00:47 +0900221 return ret;
Daniel Kurtz307ceaf2014-03-17 11:28:06 +0800222
223err_subdrv_close:
224 exynos_drm_subdrv_close(dev, file);
225
226err_file_priv_free:
Sachin Kamat6ca605f2014-01-16 11:31:26 +0530227 kfree(file_priv);
228 file->driver_priv = NULL;
229 return ret;
Joonyoung Shim9084f7b2012-03-16 18:47:09 +0900230}
231
Inki Daeccf4d882011-10-14 13:29:51 +0900232static void exynos_drm_preclose(struct drm_device *dev,
233 struct drm_file *file)
234{
Joonyoung Shim9084f7b2012-03-16 18:47:09 +0900235 exynos_drm_subdrv_close(dev, file);
Inki Daeccf4d882011-10-14 13:29:51 +0900236}
237
Inki Dae53ef2992012-02-15 11:25:22 +0900238static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
239{
Inki Dae0cbc3302013-10-01 14:51:37 +0900240 struct exynos_drm_private *private = dev->dev_private;
Inki Dae96f54212013-12-20 19:16:24 +0900241 struct drm_exynos_file_private *file_priv;
Inki Dae0cbc3302013-10-01 14:51:37 +0900242 struct drm_pending_vblank_event *v, *vt;
243 struct drm_pending_event *e, *et;
244 unsigned long flags;
245
Inki Dae53ef2992012-02-15 11:25:22 +0900246 if (!file->driver_priv)
247 return;
248
Inki Dae0cbc3302013-10-01 14:51:37 +0900249 /* Release all events not unhandled by page flip handler. */
250 spin_lock_irqsave(&dev->event_lock, flags);
251 list_for_each_entry_safe(v, vt, &private->pageflip_event_list,
252 base.link) {
253 if (v->base.file_priv == file) {
254 list_del(&v->base.link);
255 drm_vblank_put(dev, v->pipe);
256 v->base.destroy(&v->base);
257 }
258 }
259
260 /* Release all events handled by page flip handler but not freed. */
261 list_for_each_entry_safe(e, et, &file->event_list, link) {
262 list_del(&e->link);
263 e->destroy(e);
264 }
265 spin_unlock_irqrestore(&dev->event_lock, flags);
266
Inki Dae96f54212013-12-20 19:16:24 +0900267 file_priv = file->driver_priv;
268 if (file_priv->anon_filp)
269 fput(file_priv->anon_filp);
Inki Dae0cbc3302013-10-01 14:51:37 +0900270
Inki Dae53ef2992012-02-15 11:25:22 +0900271 kfree(file->driver_priv);
272 file->driver_priv = NULL;
273}
274
Inki Dae1c248b72011-10-04 19:19:01 +0900275static void exynos_drm_lastclose(struct drm_device *dev)
276{
Inki Dae1c248b72011-10-04 19:19:01 +0900277 exynos_drm_fbdev_restore_mode(dev);
278}
279
Laurent Pinchart78b68552012-05-17 13:27:22 +0200280static const struct vm_operations_struct exynos_drm_gem_vm_ops = {
Inki Dae1c248b72011-10-04 19:19:01 +0900281 .fault = exynos_drm_gem_fault,
282 .open = drm_gem_vm_open,
283 .close = drm_gem_vm_close,
284};
285
Rob Clarkbaa70942013-08-02 13:27:49 -0400286static const struct drm_ioctl_desc exynos_ioctls[] = {
Inki Dae1c248b72011-10-04 19:19:01 +0900287 DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl,
288 DRM_UNLOCKED | DRM_AUTH),
289 DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MAP_OFFSET,
290 exynos_drm_gem_map_offset_ioctl, DRM_UNLOCKED |
291 DRM_AUTH),
292 DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MMAP,
293 exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
Inki Dae40cd7e02012-05-04 15:51:17 +0900294 DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET,
295 exynos_drm_gem_get_ioctl, DRM_UNLOCKED),
Inki Daeb73d1232012-03-21 10:55:26 +0900296 DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION,
297 vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH),
Joonyoung Shimd7f16422012-05-17 20:06:32 +0900298 DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER,
299 exynos_g2d_get_ver_ioctl, DRM_UNLOCKED | DRM_AUTH),
300 DRM_IOCTL_DEF_DRV(EXYNOS_G2D_SET_CMDLIST,
301 exynos_g2d_set_cmdlist_ioctl, DRM_UNLOCKED | DRM_AUTH),
302 DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC,
303 exynos_g2d_exec_ioctl, DRM_UNLOCKED | DRM_AUTH),
Eunchul Kimcb471f12012-12-14 18:10:31 +0900304 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_PROPERTY,
305 exynos_drm_ipp_get_property, DRM_UNLOCKED | DRM_AUTH),
306 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_SET_PROPERTY,
307 exynos_drm_ipp_set_property, DRM_UNLOCKED | DRM_AUTH),
308 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_QUEUE_BUF,
309 exynos_drm_ipp_queue_buf, DRM_UNLOCKED | DRM_AUTH),
310 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_CMD_CTRL,
311 exynos_drm_ipp_cmd_ctrl, DRM_UNLOCKED | DRM_AUTH),
Inki Dae1c248b72011-10-04 19:19:01 +0900312};
313
Joonyoung Shimac2bdf72011-12-08 15:00:20 +0900314static const struct file_operations exynos_drm_driver_fops = {
315 .owner = THIS_MODULE,
316 .open = drm_open,
317 .mmap = exynos_drm_gem_mmap,
318 .poll = drm_poll,
319 .read = drm_read,
320 .unlocked_ioctl = drm_ioctl,
Keith Packard804d74a2012-07-09 15:40:07 -0700321#ifdef CONFIG_COMPAT
322 .compat_ioctl = drm_compat_ioctl,
323#endif
Joonyoung Shimac2bdf72011-12-08 15:00:20 +0900324 .release = drm_release,
325};
326
Inki Dae1c248b72011-10-04 19:19:01 +0900327static struct drm_driver exynos_drm_driver = {
Joonyoung Shimbe9b64a2014-04-12 09:39:52 +0900328 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
Inki Dae1c248b72011-10-04 19:19:01 +0900329 .load = exynos_drm_load,
330 .unload = exynos_drm_unload,
Sean Paulaf65c802014-01-30 16:19:27 -0500331 .suspend = exynos_drm_suspend,
332 .resume = exynos_drm_resume,
Joonyoung Shim9084f7b2012-03-16 18:47:09 +0900333 .open = exynos_drm_open,
Inki Daeccf4d882011-10-14 13:29:51 +0900334 .preclose = exynos_drm_preclose,
Inki Dae1c248b72011-10-04 19:19:01 +0900335 .lastclose = exynos_drm_lastclose,
Inki Dae53ef2992012-02-15 11:25:22 +0900336 .postclose = exynos_drm_postclose,
Inki Dae1c248b72011-10-04 19:19:01 +0900337 .get_vblank_counter = drm_vblank_count,
338 .enable_vblank = exynos_drm_crtc_enable_vblank,
339 .disable_vblank = exynos_drm_crtc_disable_vblank,
Inki Dae1c248b72011-10-04 19:19:01 +0900340 .gem_free_object = exynos_drm_gem_free_object,
341 .gem_vm_ops = &exynos_drm_gem_vm_ops,
342 .dumb_create = exynos_drm_gem_dumb_create,
343 .dumb_map_offset = exynos_drm_gem_dumb_map_offset,
Daniel Vetter43387b32013-07-16 09:12:04 +0200344 .dumb_destroy = drm_gem_dumb_destroy,
Inki Daeb2df26c2012-04-23 21:01:28 +0900345 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
346 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
347 .gem_prime_export = exynos_dmabuf_prime_export,
348 .gem_prime_import = exynos_dmabuf_prime_import,
Inki Dae1c248b72011-10-04 19:19:01 +0900349 .ioctls = exynos_ioctls,
Rob Clarkbaa70942013-08-02 13:27:49 -0400350 .num_ioctls = ARRAY_SIZE(exynos_ioctls),
Joonyoung Shimac2bdf72011-12-08 15:00:20 +0900351 .fops = &exynos_drm_driver_fops,
Inki Dae1c248b72011-10-04 19:19:01 +0900352 .name = DRIVER_NAME,
353 .desc = DRIVER_DESC,
354 .date = DRIVER_DATE,
355 .major = DRIVER_MAJOR,
356 .minor = DRIVER_MINOR,
357};
358
Sean Paulaf65c802014-01-30 16:19:27 -0500359#ifdef CONFIG_PM_SLEEP
360static int exynos_drm_sys_suspend(struct device *dev)
361{
362 struct drm_device *drm_dev = dev_get_drvdata(dev);
363 pm_message_t message;
364
365 if (pm_runtime_suspended(dev))
366 return 0;
367
368 message.event = PM_EVENT_SUSPEND;
369 return exynos_drm_suspend(drm_dev, message);
370}
371
372static int exynos_drm_sys_resume(struct device *dev)
373{
374 struct drm_device *drm_dev = dev_get_drvdata(dev);
375
376 if (pm_runtime_suspended(dev))
377 return 0;
378
379 return exynos_drm_resume(drm_dev);
380}
381#endif
382
Sean Paulaf65c802014-01-30 16:19:27 -0500383static const struct dev_pm_ops exynos_drm_pm_ops = {
384 SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_sys_suspend, exynos_drm_sys_resume)
Sean Paulaf65c802014-01-30 16:19:27 -0500385};
386
Inki Daef37cd5e2014-05-09 14:25:20 +0900387int exynos_drm_component_add(struct device *dev,
Inki Daedf5225b2014-05-29 18:28:02 +0900388 enum exynos_drm_device_type dev_type,
389 enum exynos_drm_output_type out_type)
Inki Daef37cd5e2014-05-09 14:25:20 +0900390{
391 struct component_dev *cdev;
Inki Daedf5225b2014-05-29 18:28:02 +0900392
393 if (dev_type != EXYNOS_DEVICE_TYPE_CRTC &&
394 dev_type != EXYNOS_DEVICE_TYPE_CONNECTOR) {
395 DRM_ERROR("invalid device type.\n");
396 return -EINVAL;
397 }
398
399 mutex_lock(&drm_component_lock);
400
401 /*
402 * Make sure to check if there is a component which has two device
403 * objects, for connector and for encoder/connector.
404 * It should make sure that crtc and encoder/connector drivers are
405 * ready before exynos drm core binds them.
406 */
407 list_for_each_entry(cdev, &drm_component_list, list) {
408 if (cdev->out_type == out_type) {
409 /*
410 * If crtc and encoder/connector device objects are
411 * added already just return.
412 */
413 if (cdev->dev_type_flag == (EXYNOS_DEVICE_TYPE_CRTC |
414 EXYNOS_DEVICE_TYPE_CONNECTOR)) {
415 mutex_unlock(&drm_component_lock);
416 return 0;
417 }
418
419 if (dev_type == EXYNOS_DEVICE_TYPE_CRTC) {
420 cdev->crtc_dev = dev;
421 cdev->dev_type_flag |= dev_type;
422 }
423
424 if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR) {
425 cdev->conn_dev = dev;
426 cdev->dev_type_flag |= dev_type;
427 }
428
429 mutex_unlock(&drm_component_lock);
430 return 0;
431 }
432 }
433
434 mutex_unlock(&drm_component_lock);
Inki Daef37cd5e2014-05-09 14:25:20 +0900435
436 cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
437 if (!cdev)
438 return -ENOMEM;
439
Inki Daedf5225b2014-05-29 18:28:02 +0900440 if (dev_type == EXYNOS_DEVICE_TYPE_CRTC)
441 cdev->crtc_dev = dev;
442 if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR)
443 cdev->conn_dev = dev;
Inki Daef37cd5e2014-05-09 14:25:20 +0900444
Inki Daedf5225b2014-05-29 18:28:02 +0900445 cdev->out_type = out_type;
446 cdev->dev_type_flag = dev_type;
Inki Daef37cd5e2014-05-09 14:25:20 +0900447
448 mutex_lock(&drm_component_lock);
449 list_add_tail(&cdev->list, &drm_component_list);
450 mutex_unlock(&drm_component_lock);
451
452 return 0;
453}
454
455void exynos_drm_component_del(struct device *dev,
Inki Daedf5225b2014-05-29 18:28:02 +0900456 enum exynos_drm_device_type dev_type)
Inki Daef37cd5e2014-05-09 14:25:20 +0900457{
458 struct component_dev *cdev, *next;
459
460 mutex_lock(&drm_component_lock);
461
462 list_for_each_entry_safe(cdev, next, &drm_component_list, list) {
Inki Daedf5225b2014-05-29 18:28:02 +0900463 if (dev_type == EXYNOS_DEVICE_TYPE_CRTC) {
464 if (cdev->crtc_dev == dev) {
465 cdev->crtc_dev = NULL;
466 cdev->dev_type_flag &= ~dev_type;
467 }
468 }
469
470 if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR) {
471 if (cdev->conn_dev == dev) {
472 cdev->conn_dev = NULL;
473 cdev->dev_type_flag &= ~dev_type;
474 }
475 }
476
477 /*
478 * Release cdev object only in case that both of crtc and
479 * encoder/connector device objects are NULL.
480 */
481 if (!cdev->crtc_dev && !cdev->conn_dev) {
Inki Daef37cd5e2014-05-09 14:25:20 +0900482 list_del(&cdev->list);
483 kfree(cdev);
Inki Daef37cd5e2014-05-09 14:25:20 +0900484 }
Inki Daedf5225b2014-05-29 18:28:02 +0900485
486 break;
Inki Daef37cd5e2014-05-09 14:25:20 +0900487 }
488
489 mutex_unlock(&drm_component_lock);
Inki Daef37cd5e2014-05-09 14:25:20 +0900490}
491
492static int compare_of(struct device *dev, void *data)
493{
494 return dev == (struct device *)data;
495}
496
497static int exynos_drm_add_components(struct device *dev, struct master *m)
498{
Inki Daef37cd5e2014-05-09 14:25:20 +0900499 struct component_dev *cdev;
Inki Daedf5225b2014-05-29 18:28:02 +0900500 unsigned int attach_cnt = 0;
Inki Daef37cd5e2014-05-09 14:25:20 +0900501
502 mutex_lock(&drm_component_lock);
503
504 list_for_each_entry(cdev, &drm_component_list, list) {
505 int ret;
506
Inki Daedf5225b2014-05-29 18:28:02 +0900507 /*
508 * Add components to master only in case that crtc and
509 * encoder/connector device objects exist.
510 */
511 if (!cdev->crtc_dev || !cdev->conn_dev)
512 continue;
513
514 attach_cnt++;
515
Inki Daef37cd5e2014-05-09 14:25:20 +0900516 mutex_unlock(&drm_component_lock);
517
Inki Daedf5225b2014-05-29 18:28:02 +0900518 /*
519 * fimd and dpi modules have same device object so add
520 * only crtc device object in this case.
521 *
522 * TODO. if dpi module follows driver-model driver then
523 * below codes can be removed.
524 */
525 if (cdev->crtc_dev == cdev->conn_dev) {
526 ret = component_master_add_child(m, compare_of,
527 cdev->crtc_dev);
528 if (ret < 0)
529 return ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900530
Inki Daedf5225b2014-05-29 18:28:02 +0900531 goto out_lock;
532 }
533
534 /*
535 * Do not chage below call order.
536 * crtc device first should be added to master because
537 * connector/encoder need pipe number of crtc when they
538 * are created.
539 */
540 ret = component_master_add_child(m, compare_of, cdev->crtc_dev);
541 ret |= component_master_add_child(m, compare_of,
542 cdev->conn_dev);
543 if (ret < 0)
544 return ret;
545
546out_lock:
Inki Daef37cd5e2014-05-09 14:25:20 +0900547 mutex_lock(&drm_component_lock);
548 }
549
550 mutex_unlock(&drm_component_lock);
551
Inki Daedf5225b2014-05-29 18:28:02 +0900552 return attach_cnt ? 0 : -ENODEV;
Inki Daef37cd5e2014-05-09 14:25:20 +0900553}
554
555static int exynos_drm_bind(struct device *dev)
556{
Inki Daef37cd5e2014-05-09 14:25:20 +0900557 return drm_platform_init(&exynos_drm_driver, to_platform_device(dev));
558}
559
560static void exynos_drm_unbind(struct device *dev)
561{
562 drm_put_dev(dev_get_drvdata(dev));
563}
564
565static const struct component_master_ops exynos_drm_ops = {
566 .add_components = exynos_drm_add_components,
567 .bind = exynos_drm_bind,
568 .unbind = exynos_drm_unbind,
Inki Dae1c248b72011-10-04 19:19:01 +0900569};
570
Inki Daef37cd5e2014-05-09 14:25:20 +0900571static int exynos_drm_platform_probe(struct platform_device *pdev)
Inki Dae1c248b72011-10-04 19:19:01 +0900572{
Joonyoung Shim132a5b92012-03-16 18:47:08 +0900573 int ret;
574
Inki Daef37cd5e2014-05-09 14:25:20 +0900575 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
Damien Lespiauf95aeb12014-06-09 14:39:49 +0100576 exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls);
Inki Daef37cd5e2014-05-09 14:25:20 +0900577
578#ifdef CONFIG_DRM_EXYNOS_FIMD
579 ret = platform_driver_register(&fimd_driver);
580 if (ret < 0)
581 return ret;
582#endif
583
Sean Paul1417f102014-01-30 16:19:23 -0500584#ifdef CONFIG_DRM_EXYNOS_DP
585 ret = platform_driver_register(&dp_driver);
586 if (ret < 0)
Inki Daef37cd5e2014-05-09 14:25:20 +0900587 goto err_unregister_fimd_drv;
Sean Paul1417f102014-01-30 16:19:23 -0500588#endif
589
Andrzej Hajda7eb8f062014-04-04 01:19:56 +0900590#ifdef CONFIG_DRM_EXYNOS_DSI
591 ret = platform_driver_register(&dsi_driver);
592 if (ret < 0)
Inki Dae121692e2014-04-17 13:49:35 +0900593 goto err_unregister_dp_drv;
Andrzej Hajda7eb8f062014-04-04 01:19:56 +0900594#endif
595
Joonyoung Shim132a5b92012-03-16 18:47:08 +0900596#ifdef CONFIG_DRM_EXYNOS_HDMI
Joonyoung Shim132a5b92012-03-16 18:47:08 +0900597 ret = platform_driver_register(&mixer_driver);
598 if (ret < 0)
Inki Daef37cd5e2014-05-09 14:25:20 +0900599 goto err_unregister_dsi_drv;
600 ret = platform_driver_register(&hdmi_driver);
Inki Daeb73d1232012-03-21 10:55:26 +0900601 if (ret < 0)
Inki Dae121692e2014-04-17 13:49:35 +0900602 goto err_unregister_mixer_drv;
Inki Daeb73d1232012-03-21 10:55:26 +0900603#endif
604
Joonyoung Shimd7f16422012-05-17 20:06:32 +0900605#ifdef CONFIG_DRM_EXYNOS_G2D
606 ret = platform_driver_register(&g2d_driver);
607 if (ret < 0)
Inki Daef37cd5e2014-05-09 14:25:20 +0900608 goto err_unregister_hdmi_drv;
Joonyoung Shimd7f16422012-05-17 20:06:32 +0900609#endif
610
Eunchul Kim16102ed2012-12-14 17:58:55 +0900611#ifdef CONFIG_DRM_EXYNOS_FIMC
612 ret = platform_driver_register(&fimc_driver);
613 if (ret < 0)
Inki Dae121692e2014-04-17 13:49:35 +0900614 goto err_unregister_g2d_drv;
Eunchul Kim16102ed2012-12-14 17:58:55 +0900615#endif
616
Eunchul Kimbea8a422012-12-14 17:58:56 +0900617#ifdef CONFIG_DRM_EXYNOS_ROTATOR
618 ret = platform_driver_register(&rotator_driver);
619 if (ret < 0)
Inki Dae121692e2014-04-17 13:49:35 +0900620 goto err_unregister_fimc_drv;
Eunchul Kimbea8a422012-12-14 17:58:56 +0900621#endif
622
Eunchul Kimf2646382012-12-14 17:58:57 +0900623#ifdef CONFIG_DRM_EXYNOS_GSC
624 ret = platform_driver_register(&gsc_driver);
625 if (ret < 0)
Inki Dae121692e2014-04-17 13:49:35 +0900626 goto err_unregister_rotator_drv;
Eunchul Kimf2646382012-12-14 17:58:57 +0900627#endif
628
Eunchul Kimcb471f12012-12-14 18:10:31 +0900629#ifdef CONFIG_DRM_EXYNOS_IPP
630 ret = platform_driver_register(&ipp_driver);
631 if (ret < 0)
Inki Dae121692e2014-04-17 13:49:35 +0900632 goto err_unregister_gsc_drv;
Seung-Woo Kim43f41902013-04-23 14:02:53 +0900633
634 ret = exynos_platform_device_ipp_register();
635 if (ret < 0)
Inki Dae121692e2014-04-17 13:49:35 +0900636 goto err_unregister_ipp_drv;
Eunchul Kimcb471f12012-12-14 18:10:31 +0900637#endif
638
Inki Daef37cd5e2014-05-09 14:25:20 +0900639 ret = component_master_add(&pdev->dev, &exynos_drm_ops);
Joonyoung Shim132a5b92012-03-16 18:47:08 +0900640 if (ret < 0)
Inki Daef37cd5e2014-05-09 14:25:20 +0900641 DRM_DEBUG_KMS("re-tried by last sub driver probed later.\n");
Joonyoung Shim132a5b92012-03-16 18:47:08 +0900642
643 return 0;
644
Eunchul Kimcb471f12012-12-14 18:10:31 +0900645#ifdef CONFIG_DRM_EXYNOS_IPP
Inki Dae121692e2014-04-17 13:49:35 +0900646err_unregister_ipp_drv:
Eunchul Kimcb471f12012-12-14 18:10:31 +0900647 platform_driver_unregister(&ipp_driver);
Inki Dae121692e2014-04-17 13:49:35 +0900648err_unregister_gsc_drv:
Eunchul Kimcb471f12012-12-14 18:10:31 +0900649#endif
650
Eunchul Kimf2646382012-12-14 17:58:57 +0900651#ifdef CONFIG_DRM_EXYNOS_GSC
652 platform_driver_unregister(&gsc_driver);
Inki Dae121692e2014-04-17 13:49:35 +0900653err_unregister_rotator_drv:
Eunchul Kimf2646382012-12-14 17:58:57 +0900654#endif
655
Eunchul Kimbea8a422012-12-14 17:58:56 +0900656#ifdef CONFIG_DRM_EXYNOS_ROTATOR
657 platform_driver_unregister(&rotator_driver);
Inki Dae121692e2014-04-17 13:49:35 +0900658err_unregister_fimc_drv:
Eunchul Kimbea8a422012-12-14 17:58:56 +0900659#endif
660
Eunchul Kim16102ed2012-12-14 17:58:55 +0900661#ifdef CONFIG_DRM_EXYNOS_FIMC
662 platform_driver_unregister(&fimc_driver);
Inki Dae121692e2014-04-17 13:49:35 +0900663err_unregister_g2d_drv:
Eunchul Kim16102ed2012-12-14 17:58:55 +0900664#endif
665
Joonyoung Shimd7f16422012-05-17 20:06:32 +0900666#ifdef CONFIG_DRM_EXYNOS_G2D
667 platform_driver_unregister(&g2d_driver);
Inki Daef37cd5e2014-05-09 14:25:20 +0900668err_unregister_hdmi_drv:
Inki Daeb73d1232012-03-21 10:55:26 +0900669#endif
670
Joonyoung Shim132a5b92012-03-16 18:47:08 +0900671#ifdef CONFIG_DRM_EXYNOS_HDMI
Joonyoung Shim132a5b92012-03-16 18:47:08 +0900672 platform_driver_unregister(&hdmi_driver);
Inki Daef37cd5e2014-05-09 14:25:20 +0900673err_unregister_mixer_drv:
674 platform_driver_unregister(&mixer_driver);
Inki Dae121692e2014-04-17 13:49:35 +0900675err_unregister_dsi_drv:
Joonyoung Shim132a5b92012-03-16 18:47:08 +0900676#endif
Andrzej Hajda25928a32014-03-17 11:27:17 +0100677
Andrzej Hajda7eb8f062014-04-04 01:19:56 +0900678#ifdef CONFIG_DRM_EXYNOS_DSI
679 platform_driver_unregister(&dsi_driver);
Inki Dae121692e2014-04-17 13:49:35 +0900680err_unregister_dp_drv:
Andrzej Hajda7eb8f062014-04-04 01:19:56 +0900681#endif
682
Sean Paul1417f102014-01-30 16:19:23 -0500683#ifdef CONFIG_DRM_EXYNOS_DP
684 platform_driver_unregister(&dp_driver);
Inki Daef37cd5e2014-05-09 14:25:20 +0900685err_unregister_fimd_drv:
686#endif
687
688#ifdef CONFIG_DRM_EXYNOS_FIMD
689 platform_driver_unregister(&fimd_driver);
Sean Paul1417f102014-01-30 16:19:23 -0500690#endif
Joonyoung Shim132a5b92012-03-16 18:47:08 +0900691 return ret;
Inki Dae1c248b72011-10-04 19:19:01 +0900692}
693
Inki Daef37cd5e2014-05-09 14:25:20 +0900694static int exynos_drm_platform_remove(struct platform_device *pdev)
Inki Dae1c248b72011-10-04 19:19:01 +0900695{
Eunchul Kimcb471f12012-12-14 18:10:31 +0900696#ifdef CONFIG_DRM_EXYNOS_IPP
Seung-Woo Kim43f41902013-04-23 14:02:53 +0900697 exynos_platform_device_ipp_unregister();
Eunchul Kimcb471f12012-12-14 18:10:31 +0900698 platform_driver_unregister(&ipp_driver);
699#endif
700
Eunchul Kimf2646382012-12-14 17:58:57 +0900701#ifdef CONFIG_DRM_EXYNOS_GSC
702 platform_driver_unregister(&gsc_driver);
703#endif
704
Eunchul Kimbea8a422012-12-14 17:58:56 +0900705#ifdef CONFIG_DRM_EXYNOS_ROTATOR
706 platform_driver_unregister(&rotator_driver);
707#endif
708
Eunchul Kim16102ed2012-12-14 17:58:55 +0900709#ifdef CONFIG_DRM_EXYNOS_FIMC
710 platform_driver_unregister(&fimc_driver);
711#endif
712
Joonyoung Shimd7f16422012-05-17 20:06:32 +0900713#ifdef CONFIG_DRM_EXYNOS_G2D
714 platform_driver_unregister(&g2d_driver);
715#endif
716
Joonyoung Shim132a5b92012-03-16 18:47:08 +0900717#ifdef CONFIG_DRM_EXYNOS_HDMI
Joonyoung Shim132a5b92012-03-16 18:47:08 +0900718 platform_driver_unregister(&mixer_driver);
719 platform_driver_unregister(&hdmi_driver);
720#endif
721
722#ifdef CONFIG_DRM_EXYNOS_FIMD
723 platform_driver_unregister(&fimd_driver);
724#endif
Sean Paul1417f102014-01-30 16:19:23 -0500725
Andrzej Hajda7eb8f062014-04-04 01:19:56 +0900726#ifdef CONFIG_DRM_EXYNOS_DSI
727 platform_driver_unregister(&dsi_driver);
728#endif
729
Sean Paul1417f102014-01-30 16:19:23 -0500730#ifdef CONFIG_DRM_EXYNOS_DP
731 platform_driver_unregister(&dp_driver);
732#endif
Inki Daef37cd5e2014-05-09 14:25:20 +0900733 component_master_del(&pdev->dev, &exynos_drm_ops);
734 return 0;
735}
736
737static struct platform_driver exynos_drm_platform_driver = {
738 .probe = exynos_drm_platform_probe,
739 .remove = exynos_drm_platform_remove,
740 .driver = {
741 .owner = THIS_MODULE,
742 .name = "exynos-drm",
743 .pm = &exynos_drm_pm_ops,
744 },
745};
746
747static int exynos_drm_init(void)
748{
749 int ret;
750
751 exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1,
752 NULL, 0);
753 if (IS_ERR(exynos_drm_pdev))
754 return PTR_ERR(exynos_drm_pdev);
755
756#ifdef CONFIG_DRM_EXYNOS_VIDI
757 ret = exynos_drm_probe_vidi();
758 if (ret < 0)
759 goto err_unregister_pd;
760#endif
761
762 ret = platform_driver_register(&exynos_drm_platform_driver);
763 if (ret)
764 goto err_remove_vidi;
765
766 return 0;
767
Inki Daef37cd5e2014-05-09 14:25:20 +0900768err_remove_vidi:
769#ifdef CONFIG_DRM_EXYNOS_VIDI
770 exynos_drm_remove_vidi();
Sachin Kamat0013fc92014-06-17 17:08:07 +0530771
772err_unregister_pd:
Inki Daef37cd5e2014-05-09 14:25:20 +0900773#endif
Sachin Kamat0013fc92014-06-17 17:08:07 +0530774 platform_device_unregister(exynos_drm_pdev);
Inki Daef37cd5e2014-05-09 14:25:20 +0900775
776 return ret;
777}
778
779static void exynos_drm_exit(void)
780{
Sachin Kamat0013fc92014-06-17 17:08:07 +0530781 platform_driver_unregister(&exynos_drm_platform_driver);
Inki Daef37cd5e2014-05-09 14:25:20 +0900782#ifdef CONFIG_DRM_EXYNOS_VIDI
783 exynos_drm_remove_vidi();
784#endif
785 platform_device_unregister(exynos_drm_pdev);
Inki Dae1c248b72011-10-04 19:19:01 +0900786}
787
788module_init(exynos_drm_init);
789module_exit(exynos_drm_exit);
790
791MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
792MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
793MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
794MODULE_DESCRIPTION("Samsung SoC DRM Driver");
795MODULE_LICENSE("GPL");