blob: 835dec1c8fea8106637c1a15a6718559cf55d7e1 [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 Daef37cd5e2014-05-09 14:25:20 +090018#include <linux/component.h>
Inki Dae96f54212013-12-20 19:16:24 +090019
Inki Dae1c248b72011-10-04 19:19:01 +090020#include <drm/exynos_drm.h>
21
22#include "exynos_drm_drv.h"
23#include "exynos_drm_crtc.h"
Inki Daed081f562012-02-15 11:25:19 +090024#include "exynos_drm_encoder.h"
Inki Dae1c248b72011-10-04 19:19:01 +090025#include "exynos_drm_fbdev.h"
26#include "exynos_drm_fb.h"
27#include "exynos_drm_gem.h"
Joonyoung Shim864ee9e2011-12-08 17:54:07 +090028#include "exynos_drm_plane.h"
Inki Daeb73d1232012-03-21 10:55:26 +090029#include "exynos_drm_vidi.h"
Inki Daeb2df26c2012-04-23 21:01:28 +090030#include "exynos_drm_dmabuf.h"
Joonyoung Shimd7f16422012-05-17 20:06:32 +090031#include "exynos_drm_g2d.h"
Eunchul Kimcb471f142012-12-14 18:10:31 +090032#include "exynos_drm_ipp.h"
Inki Dae0519f9a2012-10-20 07:53:42 -070033#include "exynos_drm_iommu.h"
Inki Dae1c248b72011-10-04 19:19:01 +090034
Inki Dae0edf9932011-12-15 17:31:24 +090035#define DRIVER_NAME "exynos"
Inki Dae1c248b72011-10-04 19:19:01 +090036#define DRIVER_DESC "Samsung SoC DRM"
37#define DRIVER_DATE "20110530"
38#define DRIVER_MAJOR 1
39#define DRIVER_MINOR 0
40
Inki Daef37cd5e2014-05-09 14:25:20 +090041static DEFINE_MUTEX(drm_component_lock);
42static LIST_HEAD(drm_component_list);
43
44struct component_dev {
45 struct list_head list;
Inki Daedf5225b2014-05-29 18:28:02 +090046 struct device *crtc_dev;
47 struct device *conn_dev;
48 enum exynos_drm_output_type out_type;
49 unsigned int dev_type_flag;
Inki Daef37cd5e2014-05-09 14:25:20 +090050};
51
Inki Dae1c248b72011-10-04 19:19:01 +090052static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
53{
54 struct exynos_drm_private *private;
55 int ret;
Inki Dae1c248b72011-10-04 19:19:01 +090056
Inki Dae1c248b72011-10-04 19:19:01 +090057 private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL);
Sachin Kamat38bb5252013-08-19 19:04:55 +090058 if (!private)
Inki Dae1c248b72011-10-04 19:19:01 +090059 return -ENOMEM;
Inki Dae1c248b72011-10-04 19:19:01 +090060
Sean Paulaf65c802014-01-30 16:19:27 -050061 dev_set_drvdata(dev->dev, dev);
Inki Dae1c248b72011-10-04 19:19:01 +090062 dev->dev_private = (void *)private;
63
Inki Dae0519f9a2012-10-20 07:53:42 -070064 /*
65 * create mapping to manage iommu table and set a pointer to iommu
66 * mapping structure to iommu_mapping of private data.
67 * also this iommu_mapping can be used to check if iommu is supported
68 * or not.
69 */
70 ret = drm_create_iommu_mapping(dev);
71 if (ret < 0) {
72 DRM_ERROR("failed to create iommu mapping.\n");
Inki Daed2ba65f2014-02-28 18:37:02 +090073 goto err_free_private;
Inki Dae0519f9a2012-10-20 07:53:42 -070074 }
75
Inki Dae1c248b72011-10-04 19:19:01 +090076 drm_mode_config_init(dev);
77
78 exynos_drm_mode_config_init(dev);
79
Inki Daed081f562012-02-15 11:25:19 +090080 /* setup possible_clones. */
81 exynos_drm_encoder_setup(dev);
82
Daniel Vettera9a346d2013-12-11 11:34:23 +010083 platform_set_drvdata(dev->platformdev, dev);
84
Inki Daef37cd5e2014-05-09 14:25:20 +090085 /* Try to bind all sub drivers. */
86 ret = component_bind_all(dev->dev, dev);
87 if (ret)
Andrzej Hajdac52142e2014-10-07 22:09:14 +090088 goto err_mode_config_cleanup;
89
90 ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
91 if (ret)
92 goto err_unbind_all;
Inki Daef37cd5e2014-05-09 14:25:20 +090093
Inki Daed1afe7d2014-04-14 12:55:55 +090094 /* Probe non kms sub drivers and virtual display driver. */
Inki Daef37cd5e2014-05-09 14:25:20 +090095 ret = exynos_drm_device_subdrv_probe(dev);
96 if (ret)
Andrzej Hajdac52142e2014-10-07 22:09:14 +090097 goto err_cleanup_vblank;
Inki Daef37cd5e2014-05-09 14:25:20 +090098
Gustavo Padovan4ea95262015-06-01 12:04:44 -030099 drm_mode_config_reset(dev);
100
Joonyoung Shim4a3ffed2014-09-18 17:50:35 +0900101 /*
102 * enable drm irq mode.
103 * - with irq_enabled = true, we can use the vblank feature.
104 *
105 * P.S. note that we wouldn't use drm irq handler but
106 * just specific driver own one instead because
107 * drm framework supports only one irq handler.
108 */
109 dev->irq_enabled = true;
110
111 /*
112 * with vblank_disable_allowed = true, vblank interrupt will be disabled
113 * by drm timer once a current process gives up ownership of
114 * vblank event.(after drm_vblank_put function is called)
115 */
116 dev->vblank_disable_allowed = true;
117
Andrzej Hajda3cb68302014-10-10 14:31:54 +0200118 /* init kms poll for handling hpd */
119 drm_kms_helper_poll_init(dev);
120
121 /* force connectors detection */
122 drm_helper_hpd_irq_event(dev);
123
Inki Dae1c248b72011-10-04 19:19:01 +0900124 return 0;
125
Inki Daef37cd5e2014-05-09 14:25:20 +0900126err_cleanup_vblank:
Inki Dae1c248b72011-10-04 19:19:01 +0900127 drm_vblank_cleanup(dev);
Andrzej Hajdac52142e2014-10-07 22:09:14 +0900128err_unbind_all:
129 component_unbind_all(dev->dev, dev);
Sean Paul080be03d2014-02-19 21:02:55 +0900130err_mode_config_cleanup:
131 drm_mode_config_cleanup(dev);
Inki Dae0519f9a2012-10-20 07:53:42 -0700132 drm_release_iommu_mapping(dev);
Inki Daed2ba65f2014-02-28 18:37:02 +0900133err_free_private:
Inki Dae1c248b72011-10-04 19:19:01 +0900134 kfree(private);
135
136 return ret;
137}
138
139static int exynos_drm_unload(struct drm_device *dev)
140{
Inki Daef37cd5e2014-05-09 14:25:20 +0900141 exynos_drm_device_subdrv_remove(dev);
142
Inki Dae1c248b72011-10-04 19:19:01 +0900143 exynos_drm_fbdev_fini(dev);
Seung-Woo Kim7db3eba2011-10-18 16:58:05 +0900144 drm_kms_helper_poll_fini(dev);
Inki Dae1c248b72011-10-04 19:19:01 +0900145
Andrzej Hajda9f3dd7d2014-09-09 15:16:06 +0200146 drm_vblank_cleanup(dev);
Andrzej Hajdac52142e2014-10-07 22:09:14 +0900147 component_unbind_all(dev->dev, dev);
Andrzej Hajda9f3dd7d2014-09-09 15:16:06 +0200148 drm_mode_config_cleanup(dev);
149 drm_release_iommu_mapping(dev);
150
151 kfree(dev->dev_private);
Inki Dae1c248b72011-10-04 19:19:01 +0900152 dev->dev_private = NULL;
153
154 return 0;
155}
156
Sean Paulaf65c802014-01-30 16:19:27 -0500157static int exynos_drm_suspend(struct drm_device *dev, pm_message_t state)
158{
159 struct drm_connector *connector;
160
161 drm_modeset_lock_all(dev);
162 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
163 int old_dpms = connector->dpms;
164
165 if (connector->funcs->dpms)
166 connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
167
168 /* Set the old mode back to the connector for resume */
169 connector->dpms = old_dpms;
170 }
171 drm_modeset_unlock_all(dev);
172
173 return 0;
174}
175
176static int exynos_drm_resume(struct drm_device *dev)
177{
178 struct drm_connector *connector;
179
180 drm_modeset_lock_all(dev);
181 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
Andrzej Hajda74cfe072014-10-10 14:31:56 +0200182 if (connector->funcs->dpms) {
183 int dpms = connector->dpms;
184
185 connector->dpms = DRM_MODE_DPMS_OFF;
186 connector->funcs->dpms(connector, dpms);
187 }
Sean Paulaf65c802014-01-30 16:19:27 -0500188 }
Takashi Iwaia16f2232014-05-09 08:14:15 +0200189 drm_modeset_unlock_all(dev);
Sean Paulaf65c802014-01-30 16:19:27 -0500190
Sean Paulaf65c802014-01-30 16:19:27 -0500191 return 0;
192}
193
Joonyoung Shim9084f7b2012-03-16 18:47:09 +0900194static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
Inki Daeccf4d882011-10-14 13:29:51 +0900195{
Joonyoung Shimd7f16422012-05-17 20:06:32 +0900196 struct drm_exynos_file_private *file_priv;
YoungJun Choba3706c2013-07-01 17:00:47 +0900197 int ret;
Joonyoung Shimd7f16422012-05-17 20:06:32 +0900198
Joonyoung Shimd7f16422012-05-17 20:06:32 +0900199 file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
200 if (!file_priv)
201 return -ENOMEM;
202
Joonyoung Shimd7f16422012-05-17 20:06:32 +0900203 file->driver_priv = file_priv;
Inki Daeb2df26c2012-04-23 21:01:28 +0900204
YoungJun Choba3706c2013-07-01 17:00:47 +0900205 ret = exynos_drm_subdrv_open(dev, file);
Sachin Kamat6ca605f2014-01-16 11:31:26 +0530206 if (ret)
Daniel Kurtz307ceaf2014-03-17 11:28:06 +0800207 goto err_file_priv_free;
YoungJun Choba3706c2013-07-01 17:00:47 +0900208
209 return ret;
Daniel Kurtz307ceaf2014-03-17 11:28:06 +0800210
Daniel Kurtz307ceaf2014-03-17 11:28:06 +0800211err_file_priv_free:
Sachin Kamat6ca605f2014-01-16 11:31:26 +0530212 kfree(file_priv);
213 file->driver_priv = NULL;
214 return ret;
Joonyoung Shim9084f7b2012-03-16 18:47:09 +0900215}
216
Inki Daeccf4d882011-10-14 13:29:51 +0900217static void exynos_drm_preclose(struct drm_device *dev,
218 struct drm_file *file)
219{
Joonyoung Shim9084f7b2012-03-16 18:47:09 +0900220 exynos_drm_subdrv_close(dev, file);
Inki Daeccf4d882011-10-14 13:29:51 +0900221}
222
Inki Dae53ef2992012-02-15 11:25:22 +0900223static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
224{
Inki Dae0cbc3302013-10-01 14:51:37 +0900225 struct drm_pending_event *e, *et;
226 unsigned long flags;
227
Inki Dae53ef2992012-02-15 11:25:22 +0900228 if (!file->driver_priv)
229 return;
230
Inki Dae0cbc3302013-10-01 14:51:37 +0900231 spin_lock_irqsave(&dev->event_lock, flags);
Inki Dae0cbc3302013-10-01 14:51:37 +0900232 /* Release all events handled by page flip handler but not freed. */
233 list_for_each_entry_safe(e, et, &file->event_list, link) {
234 list_del(&e->link);
235 e->destroy(e);
236 }
237 spin_unlock_irqrestore(&dev->event_lock, flags);
238
Inki Dae53ef2992012-02-15 11:25:22 +0900239 kfree(file->driver_priv);
240 file->driver_priv = NULL;
241}
242
Inki Dae1c248b72011-10-04 19:19:01 +0900243static void exynos_drm_lastclose(struct drm_device *dev)
244{
Inki Dae1c248b72011-10-04 19:19:01 +0900245 exynos_drm_fbdev_restore_mode(dev);
246}
247
Laurent Pinchart78b68552012-05-17 13:27:22 +0200248static const struct vm_operations_struct exynos_drm_gem_vm_ops = {
Inki Dae1c248b72011-10-04 19:19:01 +0900249 .fault = exynos_drm_gem_fault,
250 .open = drm_gem_vm_open,
251 .close = drm_gem_vm_close,
252};
253
Rob Clarkbaa70942013-08-02 13:27:49 -0400254static const struct drm_ioctl_desc exynos_ioctls[] = {
Inki Dae1c248b72011-10-04 19:19:01 +0900255 DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl,
256 DRM_UNLOCKED | DRM_AUTH),
Inki Dae40cd7e02012-05-04 15:51:17 +0900257 DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET,
258 exynos_drm_gem_get_ioctl, DRM_UNLOCKED),
Inki Daeb73d1232012-03-21 10:55:26 +0900259 DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION,
260 vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH),
Joonyoung Shimd7f16422012-05-17 20:06:32 +0900261 DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER,
262 exynos_g2d_get_ver_ioctl, DRM_UNLOCKED | DRM_AUTH),
263 DRM_IOCTL_DEF_DRV(EXYNOS_G2D_SET_CMDLIST,
264 exynos_g2d_set_cmdlist_ioctl, DRM_UNLOCKED | DRM_AUTH),
265 DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC,
266 exynos_g2d_exec_ioctl, DRM_UNLOCKED | DRM_AUTH),
Eunchul Kimcb471f142012-12-14 18:10:31 +0900267 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_PROPERTY,
268 exynos_drm_ipp_get_property, DRM_UNLOCKED | DRM_AUTH),
269 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_SET_PROPERTY,
270 exynos_drm_ipp_set_property, DRM_UNLOCKED | DRM_AUTH),
271 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_QUEUE_BUF,
272 exynos_drm_ipp_queue_buf, DRM_UNLOCKED | DRM_AUTH),
273 DRM_IOCTL_DEF_DRV(EXYNOS_IPP_CMD_CTRL,
274 exynos_drm_ipp_cmd_ctrl, DRM_UNLOCKED | DRM_AUTH),
Inki Dae1c248b72011-10-04 19:19:01 +0900275};
276
Joonyoung Shimac2bdf72011-12-08 15:00:20 +0900277static const struct file_operations exynos_drm_driver_fops = {
278 .owner = THIS_MODULE,
279 .open = drm_open,
280 .mmap = exynos_drm_gem_mmap,
281 .poll = drm_poll,
282 .read = drm_read,
283 .unlocked_ioctl = drm_ioctl,
Keith Packard804d74a2012-07-09 15:40:07 -0700284#ifdef CONFIG_COMPAT
285 .compat_ioctl = drm_compat_ioctl,
286#endif
Joonyoung Shimac2bdf72011-12-08 15:00:20 +0900287 .release = drm_release,
288};
289
Inki Dae1c248b72011-10-04 19:19:01 +0900290static struct drm_driver exynos_drm_driver = {
Joonyoung Shimbe9b64a2014-04-12 09:39:52 +0900291 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
Inki Dae1c248b72011-10-04 19:19:01 +0900292 .load = exynos_drm_load,
293 .unload = exynos_drm_unload,
Sean Paulaf65c802014-01-30 16:19:27 -0500294 .suspend = exynos_drm_suspend,
295 .resume = exynos_drm_resume,
Joonyoung Shim9084f7b2012-03-16 18:47:09 +0900296 .open = exynos_drm_open,
Inki Daeccf4d882011-10-14 13:29:51 +0900297 .preclose = exynos_drm_preclose,
Inki Dae1c248b72011-10-04 19:19:01 +0900298 .lastclose = exynos_drm_lastclose,
Inki Dae53ef2992012-02-15 11:25:22 +0900299 .postclose = exynos_drm_postclose,
David Herrmann915b4d12014-08-29 12:12:43 +0200300 .set_busid = drm_platform_set_busid,
Inki Dae1c248b72011-10-04 19:19:01 +0900301 .get_vblank_counter = drm_vblank_count,
302 .enable_vblank = exynos_drm_crtc_enable_vblank,
303 .disable_vblank = exynos_drm_crtc_disable_vblank,
Inki Dae1c248b72011-10-04 19:19:01 +0900304 .gem_free_object = exynos_drm_gem_free_object,
305 .gem_vm_ops = &exynos_drm_gem_vm_ops,
306 .dumb_create = exynos_drm_gem_dumb_create,
307 .dumb_map_offset = exynos_drm_gem_dumb_map_offset,
Daniel Vetter43387b32013-07-16 09:12:04 +0200308 .dumb_destroy = drm_gem_dumb_destroy,
Inki Daeb2df26c2012-04-23 21:01:28 +0900309 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
310 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
311 .gem_prime_export = exynos_dmabuf_prime_export,
312 .gem_prime_import = exynos_dmabuf_prime_import,
Inki Dae1c248b72011-10-04 19:19:01 +0900313 .ioctls = exynos_ioctls,
Rob Clarkbaa70942013-08-02 13:27:49 -0400314 .num_ioctls = ARRAY_SIZE(exynos_ioctls),
Joonyoung Shimac2bdf72011-12-08 15:00:20 +0900315 .fops = &exynos_drm_driver_fops,
Inki Dae1c248b72011-10-04 19:19:01 +0900316 .name = DRIVER_NAME,
317 .desc = DRIVER_DESC,
318 .date = DRIVER_DATE,
319 .major = DRIVER_MAJOR,
320 .minor = DRIVER_MINOR,
321};
322
Sean Paulaf65c802014-01-30 16:19:27 -0500323#ifdef CONFIG_PM_SLEEP
324static int exynos_drm_sys_suspend(struct device *dev)
325{
326 struct drm_device *drm_dev = dev_get_drvdata(dev);
327 pm_message_t message;
328
Krzysztof Kozlowskid50a1902014-06-30 15:25:44 +0200329 if (pm_runtime_suspended(dev) || !drm_dev)
Sean Paulaf65c802014-01-30 16:19:27 -0500330 return 0;
331
332 message.event = PM_EVENT_SUSPEND;
333 return exynos_drm_suspend(drm_dev, message);
334}
335
336static int exynos_drm_sys_resume(struct device *dev)
337{
338 struct drm_device *drm_dev = dev_get_drvdata(dev);
339
Krzysztof Kozlowskid50a1902014-06-30 15:25:44 +0200340 if (pm_runtime_suspended(dev) || !drm_dev)
Sean Paulaf65c802014-01-30 16:19:27 -0500341 return 0;
342
343 return exynos_drm_resume(drm_dev);
344}
345#endif
346
Sean Paulaf65c802014-01-30 16:19:27 -0500347static const struct dev_pm_ops exynos_drm_pm_ops = {
348 SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_sys_suspend, exynos_drm_sys_resume)
Sean Paulaf65c802014-01-30 16:19:27 -0500349};
350
Inki Daef37cd5e2014-05-09 14:25:20 +0900351int exynos_drm_component_add(struct device *dev,
Inki Daedf5225b2014-05-29 18:28:02 +0900352 enum exynos_drm_device_type dev_type,
353 enum exynos_drm_output_type out_type)
Inki Daef37cd5e2014-05-09 14:25:20 +0900354{
355 struct component_dev *cdev;
Inki Daedf5225b2014-05-29 18:28:02 +0900356
357 if (dev_type != EXYNOS_DEVICE_TYPE_CRTC &&
358 dev_type != EXYNOS_DEVICE_TYPE_CONNECTOR) {
359 DRM_ERROR("invalid device type.\n");
360 return -EINVAL;
361 }
362
363 mutex_lock(&drm_component_lock);
364
365 /*
366 * Make sure to check if there is a component which has two device
367 * objects, for connector and for encoder/connector.
368 * It should make sure that crtc and encoder/connector drivers are
369 * ready before exynos drm core binds them.
370 */
371 list_for_each_entry(cdev, &drm_component_list, list) {
372 if (cdev->out_type == out_type) {
373 /*
374 * If crtc and encoder/connector device objects are
375 * added already just return.
376 */
377 if (cdev->dev_type_flag == (EXYNOS_DEVICE_TYPE_CRTC |
378 EXYNOS_DEVICE_TYPE_CONNECTOR)) {
379 mutex_unlock(&drm_component_lock);
380 return 0;
381 }
382
383 if (dev_type == EXYNOS_DEVICE_TYPE_CRTC) {
384 cdev->crtc_dev = dev;
385 cdev->dev_type_flag |= dev_type;
386 }
387
388 if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR) {
389 cdev->conn_dev = dev;
390 cdev->dev_type_flag |= dev_type;
391 }
392
393 mutex_unlock(&drm_component_lock);
394 return 0;
395 }
396 }
397
398 mutex_unlock(&drm_component_lock);
Inki Daef37cd5e2014-05-09 14:25:20 +0900399
400 cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
401 if (!cdev)
402 return -ENOMEM;
403
Inki Daedf5225b2014-05-29 18:28:02 +0900404 if (dev_type == EXYNOS_DEVICE_TYPE_CRTC)
405 cdev->crtc_dev = dev;
406 if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR)
407 cdev->conn_dev = dev;
Inki Daef37cd5e2014-05-09 14:25:20 +0900408
Inki Daedf5225b2014-05-29 18:28:02 +0900409 cdev->out_type = out_type;
410 cdev->dev_type_flag = dev_type;
Inki Daef37cd5e2014-05-09 14:25:20 +0900411
412 mutex_lock(&drm_component_lock);
413 list_add_tail(&cdev->list, &drm_component_list);
414 mutex_unlock(&drm_component_lock);
415
416 return 0;
417}
418
419void exynos_drm_component_del(struct device *dev,
Inki Daedf5225b2014-05-29 18:28:02 +0900420 enum exynos_drm_device_type dev_type)
Inki Daef37cd5e2014-05-09 14:25:20 +0900421{
422 struct component_dev *cdev, *next;
423
424 mutex_lock(&drm_component_lock);
425
426 list_for_each_entry_safe(cdev, next, &drm_component_list, list) {
Inki Daedf5225b2014-05-29 18:28:02 +0900427 if (dev_type == EXYNOS_DEVICE_TYPE_CRTC) {
428 if (cdev->crtc_dev == dev) {
429 cdev->crtc_dev = NULL;
430 cdev->dev_type_flag &= ~dev_type;
431 }
432 }
433
434 if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR) {
435 if (cdev->conn_dev == dev) {
436 cdev->conn_dev = NULL;
437 cdev->dev_type_flag &= ~dev_type;
438 }
439 }
440
441 /*
442 * Release cdev object only in case that both of crtc and
443 * encoder/connector device objects are NULL.
444 */
445 if (!cdev->crtc_dev && !cdev->conn_dev) {
Inki Daef37cd5e2014-05-09 14:25:20 +0900446 list_del(&cdev->list);
447 kfree(cdev);
Inki Daef37cd5e2014-05-09 14:25:20 +0900448 }
449 }
450
451 mutex_unlock(&drm_component_lock);
Inki Daef37cd5e2014-05-09 14:25:20 +0900452}
453
Inki Dae53c55582014-09-11 17:04:03 +0900454static int compare_dev(struct device *dev, void *data)
Inki Daef37cd5e2014-05-09 14:25:20 +0900455{
456 return dev == (struct device *)data;
457}
458
Inki Dae53c55582014-09-11 17:04:03 +0900459static struct component_match *exynos_drm_match_add(struct device *dev)
Inki Daef37cd5e2014-05-09 14:25:20 +0900460{
Inki Dae53c55582014-09-11 17:04:03 +0900461 struct component_match *match = NULL;
Inki Daef37cd5e2014-05-09 14:25:20 +0900462 struct component_dev *cdev;
Inki Daedf5225b2014-05-29 18:28:02 +0900463 unsigned int attach_cnt = 0;
Inki Daef37cd5e2014-05-09 14:25:20 +0900464
465 mutex_lock(&drm_component_lock);
466
Inki Daef7c2f36f2014-11-06 23:00:37 +0900467 /* Do not retry to probe if there is no any kms driver regitered. */
468 if (list_empty(&drm_component_list)) {
469 mutex_unlock(&drm_component_lock);
470 return ERR_PTR(-ENODEV);
471 }
472
Inki Daef37cd5e2014-05-09 14:25:20 +0900473 list_for_each_entry(cdev, &drm_component_list, list) {
Inki Daedf5225b2014-05-29 18:28:02 +0900474 /*
475 * Add components to master only in case that crtc and
476 * encoder/connector device objects exist.
477 */
478 if (!cdev->crtc_dev || !cdev->conn_dev)
479 continue;
480
481 attach_cnt++;
482
Inki Daef37cd5e2014-05-09 14:25:20 +0900483 mutex_unlock(&drm_component_lock);
484
Inki Daedf5225b2014-05-29 18:28:02 +0900485 /*
486 * fimd and dpi modules have same device object so add
487 * only crtc device object in this case.
Inki Daedf5225b2014-05-29 18:28:02 +0900488 */
489 if (cdev->crtc_dev == cdev->conn_dev) {
Inki Dae53c55582014-09-11 17:04:03 +0900490 component_match_add(dev, &match, compare_dev,
491 cdev->crtc_dev);
Inki Daedf5225b2014-05-29 18:28:02 +0900492 goto out_lock;
493 }
494
495 /*
496 * Do not chage below call order.
497 * crtc device first should be added to master because
498 * connector/encoder need pipe number of crtc when they
499 * are created.
500 */
Inki Dae53c55582014-09-11 17:04:03 +0900501 component_match_add(dev, &match, compare_dev, cdev->crtc_dev);
502 component_match_add(dev, &match, compare_dev, cdev->conn_dev);
Inki Daedf5225b2014-05-29 18:28:02 +0900503
504out_lock:
Inki Daef37cd5e2014-05-09 14:25:20 +0900505 mutex_lock(&drm_component_lock);
506 }
507
508 mutex_unlock(&drm_component_lock);
509
Inki Dae53c55582014-09-11 17:04:03 +0900510 return attach_cnt ? match : ERR_PTR(-EPROBE_DEFER);
Inki Daef37cd5e2014-05-09 14:25:20 +0900511}
512
513static int exynos_drm_bind(struct device *dev)
514{
Inki Daef37cd5e2014-05-09 14:25:20 +0900515 return drm_platform_init(&exynos_drm_driver, to_platform_device(dev));
516}
517
518static void exynos_drm_unbind(struct device *dev)
519{
520 drm_put_dev(dev_get_drvdata(dev));
521}
522
523static const struct component_master_ops exynos_drm_ops = {
Inki Daef37cd5e2014-05-09 14:25:20 +0900524 .bind = exynos_drm_bind,
525 .unbind = exynos_drm_unbind,
Inki Dae1c248b72011-10-04 19:19:01 +0900526};
527
Andrzej Hajda417133e2015-06-11 23:20:52 +0900528static int exynos_drm_platform_probe(struct platform_device *pdev)
529{
530 struct component_match *match;
531
532 pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
533 exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls);
534
535 match = exynos_drm_match_add(&pdev->dev);
536 if (IS_ERR(match))
537 return PTR_ERR(match);
538
539 return component_master_add_with_match(&pdev->dev, &exynos_drm_ops,
540 match);
541}
542
543static int exynos_drm_platform_remove(struct platform_device *pdev)
544{
545 component_master_del(&pdev->dev, &exynos_drm_ops);
546 return 0;
547}
548
549static struct platform_driver exynos_drm_platform_driver = {
550 .probe = exynos_drm_platform_probe,
551 .remove = exynos_drm_platform_remove,
552 .driver = {
553 .name = "exynos-drm",
554 .pm = &exynos_drm_pm_ops,
555 },
556};
557
Andrzej Hajda72390672014-11-13 16:37:57 +0900558static struct platform_driver *const exynos_drm_kms_drivers[] = {
Andrzej Hajda417133e2015-06-11 23:20:52 +0900559#ifdef CONFIG_DRM_EXYNOS_VIDI
560 &vidi_driver,
561#endif
Andrzej Hajda72390672014-11-13 16:37:57 +0900562#ifdef CONFIG_DRM_EXYNOS_FIMD
563 &fimd_driver,
564#endif
Ajay Kumar96976c32015-02-05 21:24:04 +0530565#ifdef CONFIG_DRM_EXYNOS7_DECON
566 &decon_driver,
567#endif
Andrzej Hajda72390672014-11-13 16:37:57 +0900568#ifdef CONFIG_DRM_EXYNOS_DP
569 &dp_driver,
570#endif
571#ifdef CONFIG_DRM_EXYNOS_DSI
572 &dsi_driver,
573#endif
574#ifdef CONFIG_DRM_EXYNOS_HDMI
575 &mixer_driver,
576 &hdmi_driver,
577#endif
578};
579
580static struct platform_driver *const exynos_drm_non_kms_drivers[] = {
581#ifdef CONFIG_DRM_EXYNOS_G2D
582 &g2d_driver,
583#endif
584#ifdef CONFIG_DRM_EXYNOS_FIMC
585 &fimc_driver,
586#endif
587#ifdef CONFIG_DRM_EXYNOS_ROTATOR
588 &rotator_driver,
589#endif
590#ifdef CONFIG_DRM_EXYNOS_GSC
591 &gsc_driver,
592#endif
593#ifdef CONFIG_DRM_EXYNOS_IPP
594 &ipp_driver,
595#endif
Andrzej Hajda417133e2015-06-11 23:20:52 +0900596 &exynos_drm_platform_driver,
Andrzej Hajda72390672014-11-13 16:37:57 +0900597};
598
Andrzej Hajda417133e2015-06-11 23:20:52 +0900599
600static struct platform_driver *const exynos_drm_drv_with_simple_dev[] = {
601#ifdef CONFIG_DRM_EXYNOS_VIDI
602 &vidi_driver,
603#endif
604#ifdef CONFIG_DRM_EXYNOS_IPP
605 &ipp_driver,
606#endif
607 &exynos_drm_platform_driver,
608};
609
610#define PDEV_COUNT ARRAY_SIZE(exynos_drm_drv_with_simple_dev)
611
612static struct platform_device *exynos_drm_pdevs[PDEV_COUNT];
613
614static void exynos_drm_unregister_devices(void)
Inki Dae1c248b72011-10-04 19:19:01 +0900615{
Andrzej Hajda417133e2015-06-11 23:20:52 +0900616 int i = PDEV_COUNT;
Joonyoung Shim132a5b92012-03-16 18:47:08 +0900617
Andrzej Hajda417133e2015-06-11 23:20:52 +0900618 while (--i >= 0) {
619 platform_device_unregister(exynos_drm_pdevs[i]);
620 exynos_drm_pdevs[i] = NULL;
Inki Dae7afbfcc2014-11-07 21:32:34 +0900621 }
Inki Dae1c248b72011-10-04 19:19:01 +0900622}
623
Andrzej Hajda417133e2015-06-11 23:20:52 +0900624static int exynos_drm_register_devices(void)
Inki Dae1c248b72011-10-04 19:19:01 +0900625{
Andrzej Hajda417133e2015-06-11 23:20:52 +0900626 int i;
627
628 for (i = 0; i < PDEV_COUNT; ++i) {
629 struct platform_driver *d = exynos_drm_drv_with_simple_dev[i];
630 struct platform_device *pdev =
631 platform_device_register_simple(d->driver.name, -1,
632 NULL, 0);
633
634 if (!IS_ERR(pdev)) {
635 exynos_drm_pdevs[i] = pdev;
636 continue;
637 }
638 while (--i >= 0) {
639 platform_device_unregister(exynos_drm_pdevs[i]);
640 exynos_drm_pdevs[i] = NULL;
641 }
642
643 return PTR_ERR(pdev);
644 }
645
Inki Daef37cd5e2014-05-09 14:25:20 +0900646 return 0;
647}
648
Andrzej Hajda417133e2015-06-11 23:20:52 +0900649static void exynos_drm_unregister_drivers(struct platform_driver * const *drv,
650 int count)
651{
652 while (--count >= 0)
653 platform_driver_unregister(drv[count]);
654}
655
656static int exynos_drm_register_drivers(struct platform_driver * const *drv,
657 int count)
658{
659 int i, ret;
660
661 for (i = 0; i < count; ++i) {
662 ret = platform_driver_register(drv[i]);
663 if (!ret)
664 continue;
665
666 while (--i >= 0)
667 platform_driver_unregister(drv[i]);
668
669 return ret;
670 }
671
672 return 0;
673}
674
675static inline int exynos_drm_register_kms_drivers(void)
676{
677 return exynos_drm_register_drivers(exynos_drm_kms_drivers,
678 ARRAY_SIZE(exynos_drm_kms_drivers));
679}
680
681static inline int exynos_drm_register_non_kms_drivers(void)
682{
683 return exynos_drm_register_drivers(exynos_drm_non_kms_drivers,
684 ARRAY_SIZE(exynos_drm_non_kms_drivers));
685}
686
687static inline void exynos_drm_unregister_kms_drivers(void)
688{
689 exynos_drm_unregister_drivers(exynos_drm_kms_drivers,
690 ARRAY_SIZE(exynos_drm_kms_drivers));
691}
692
693static inline void exynos_drm_unregister_non_kms_drivers(void)
694{
695 exynos_drm_unregister_drivers(exynos_drm_non_kms_drivers,
696 ARRAY_SIZE(exynos_drm_non_kms_drivers));
697}
698
Inki Dae4846e452014-11-24 17:08:00 +0900699static const char * const strings[] = {
700 "samsung,exynos3",
701 "samsung,exynos4",
702 "samsung,exynos5",
Ajay Kumar96976c32015-02-05 21:24:04 +0530703 "samsung,exynos7",
Inki Dae4846e452014-11-24 17:08:00 +0900704};
705
Inki Daef37cd5e2014-05-09 14:25:20 +0900706static int exynos_drm_init(void)
707{
Inki Dae4846e452014-11-24 17:08:00 +0900708 bool is_exynos = false;
Andrzej Hajda417133e2015-06-11 23:20:52 +0900709 int ret, i;
Inki Daef37cd5e2014-05-09 14:25:20 +0900710
Inki Dae5cbb37d2014-11-06 19:23:35 +0900711 /*
712 * Register device object only in case of Exynos SoC.
713 *
714 * Below codes resolves temporarily infinite loop issue incurred
715 * by Exynos drm driver when using multi-platform kernel.
716 * So these codes will be replaced with more generic way later.
717 */
Inki Dae4846e452014-11-24 17:08:00 +0900718 for (i = 0; i < ARRAY_SIZE(strings); i++) {
719 if (of_machine_is_compatible(strings[i])) {
720 is_exynos = true;
721 break;
722 }
723 }
724
725 if (!is_exynos)
Inki Dae5cbb37d2014-11-06 19:23:35 +0900726 return -ENODEV;
Inki Daef37cd5e2014-05-09 14:25:20 +0900727
Andrzej Hajda417133e2015-06-11 23:20:52 +0900728 ret = exynos_drm_register_devices();
Inki Daef37cd5e2014-05-09 14:25:20 +0900729 if (ret)
Andrzej Hajda417133e2015-06-11 23:20:52 +0900730 return ret;
731
732 ret = exynos_drm_register_kms_drivers();
733 if (ret)
734 goto err_unregister_pdevs;
735
736 ret = exynos_drm_register_non_kms_drivers();
737 if (ret)
738 goto err_unregister_kms_drivers;
Inki Daef37cd5e2014-05-09 14:25:20 +0900739
740 return 0;
741
Gustavo Padovan820687be2014-11-24 16:37:26 +0900742err_unregister_kms_drivers:
Andrzej Hajda417133e2015-06-11 23:20:52 +0900743 exynos_drm_unregister_kms_drivers();
Gustavo Padovan820687be2014-11-24 16:37:26 +0900744
Andrzej Hajda417133e2015-06-11 23:20:52 +0900745err_unregister_pdevs:
746 exynos_drm_unregister_devices();
Inki Daef37cd5e2014-05-09 14:25:20 +0900747
748 return ret;
749}
750
751static void exynos_drm_exit(void)
752{
Andrzej Hajda417133e2015-06-11 23:20:52 +0900753 exynos_drm_unregister_non_kms_drivers();
754 exynos_drm_unregister_kms_drivers();
755 exynos_drm_unregister_devices();
Inki Dae1c248b72011-10-04 19:19:01 +0900756}
757
758module_init(exynos_drm_init);
759module_exit(exynos_drm_exit);
760
761MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
762MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
763MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
764MODULE_DESCRIPTION("Samsung SoC DRM Driver");
765MODULE_LICENSE("GPL");