blob: 0f579206489a75aa155a948e4cbf6c970e8b4fdf [file] [log] [blame]
Sascha Hauere692da42012-09-21 10:07:47 +02001/*
2 * Freescale i.MX drm driver
3 *
4 * Copyright (C) 2011 Sascha Hauer, Pengutronix
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
Russell King17b50012013-11-03 11:23:34 +000016#include <linux/component.h>
Sascha Hauere692da42012-09-21 10:07:47 +020017#include <linux/device.h>
Liu Ying5f2f9112016-07-08 17:40:59 +080018#include <linux/dma-buf.h>
Russell Kinge7d62312013-11-03 15:38:09 +000019#include <linux/module.h>
Sascha Hauere692da42012-09-21 10:07:47 +020020#include <linux/platform_device.h>
Liu Ying5f2f9112016-07-08 17:40:59 +080021#include <linux/reservation.h>
Sascha Hauere692da42012-09-21 10:07:47 +020022#include <drm/drmP.h>
Liu Ying5f2f9112016-07-08 17:40:59 +080023#include <drm/drm_atomic.h>
24#include <drm/drm_atomic_helper.h>
Sascha Hauere692da42012-09-21 10:07:47 +020025#include <drm/drm_fb_helper.h>
26#include <drm/drm_crtc_helper.h>
Sascha Hauere692da42012-09-21 10:07:47 +020027#include <drm/drm_gem_cma_helper.h>
28#include <drm/drm_fb_cma_helper.h>
Daniel Vetter3cb9ae42014-10-29 10:03:57 +010029#include <drm/drm_plane_helper.h>
Russell King6457b972014-07-03 17:52:57 +010030#include <drm/drm_of.h>
Philipp Zabel310944d2016-05-12 15:00:44 +020031#include <video/imx-ipu-v3.h>
Sascha Hauere692da42012-09-21 10:07:47 +020032
33#include "imx-drm.h"
34
35#define MAX_CRTC 4
36
Philipp Zabel655b43c2014-03-05 10:20:52 +010037struct imx_drm_component {
38 struct device_node *of_node;
39 struct list_head list;
40};
41
Sascha Hauere692da42012-09-21 10:07:47 +020042struct imx_drm_device {
43 struct drm_device *drm;
Russell King887eceac2013-11-24 13:23:17 +000044 struct imx_drm_crtc *crtc[MAX_CRTC];
Thierry Redingd2ab8ad2015-12-15 12:20:51 +010045 unsigned int pipes;
Sascha Hauere692da42012-09-21 10:07:47 +020046 struct drm_fbdev_cma *fbhelper;
Liu Ying5f2f9112016-07-08 17:40:59 +080047 struct drm_atomic_state *state;
Sascha Hauere692da42012-09-21 10:07:47 +020048};
49
50struct imx_drm_crtc {
51 struct drm_crtc *crtc;
Sascha Hauere692da42012-09-21 10:07:47 +020052 struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs;
Sascha Hauere692da42012-09-21 10:07:47 +020053};
54
Archit Tanejac1ff5a72015-10-27 13:40:57 +053055#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
Russell King8acba022013-11-03 12:13:47 +000056static int legacyfb_depth = 16;
57module_param(legacyfb_depth, int, 0444);
Archit Tanejac1ff5a72015-10-27 13:40:57 +053058#endif
Russell King8acba022013-11-03 12:13:47 +000059
Thierry Redingd2ab8ad2015-12-15 12:20:51 +010060unsigned int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
Philipp Zabelb8d181e2013-10-10 16:18:45 +020061{
Thierry Redingd4b20e42015-12-15 12:20:52 +010062 return drm_crtc_index(crtc->crtc);
Philipp Zabelb8d181e2013-10-10 16:18:45 +020063}
Josh Boyer9c743602013-11-12 12:15:45 -050064EXPORT_SYMBOL_GPL(imx_drm_crtc_id);
Philipp Zabelb8d181e2013-10-10 16:18:45 +020065
Sascha Hauere692da42012-09-21 10:07:47 +020066static void imx_drm_driver_lastclose(struct drm_device *drm)
67{
68 struct imx_drm_device *imxdrm = drm->dev_private;
69
Markus Elfring3f3a7282015-07-05 22:45:23 +020070 drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
Sascha Hauere692da42012-09-21 10:07:47 +020071}
72
73static int imx_drm_driver_unload(struct drm_device *drm)
74{
75 struct imx_drm_device *imxdrm = drm->dev_private;
76
Russell King3e684392013-11-03 22:18:40 +000077 drm_kms_helper_poll_fini(drm);
78
Russell King8acba022013-11-03 12:13:47 +000079 if (imxdrm->fbhelper)
80 drm_fbdev_cma_fini(imxdrm->fbhelper);
Russell King8acba022013-11-03 12:13:47 +000081
Russell King17b50012013-11-03 11:23:34 +000082 component_unbind_all(drm->dev, drm);
83
Russell King020a9ea2013-12-17 19:10:47 +000084 drm_vblank_cleanup(drm);
Russell King020a9ea2013-12-17 19:10:47 +000085 drm_mode_config_cleanup(drm);
Sascha Hauere692da42012-09-21 10:07:47 +020086
Shawn Guobfe945c2014-09-10 22:43:51 +080087 platform_set_drvdata(drm->platformdev, NULL);
88
Sascha Hauere692da42012-09-21 10:07:47 +020089 return 0;
90}
91
Sascha Hauere692da42012-09-21 10:07:47 +020092int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
93{
Thierry Redingd4b20e42015-12-15 12:20:52 +010094 return drm_crtc_vblank_get(imx_drm_crtc->crtc);
Sascha Hauere692da42012-09-21 10:07:47 +020095}
96EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get);
97
98void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc)
99{
Thierry Redingd4b20e42015-12-15 12:20:52 +0100100 drm_crtc_vblank_put(imx_drm_crtc->crtc);
Sascha Hauere692da42012-09-21 10:07:47 +0200101}
102EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put);
103
104void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc)
105{
Thierry Redingd4b20e42015-12-15 12:20:52 +0100106 drm_crtc_handle_vblank(imx_drm_crtc->crtc);
Sascha Hauere692da42012-09-21 10:07:47 +0200107}
108EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
109
Thierry Reding88e72712015-09-24 18:35:31 +0200110static int imx_drm_enable_vblank(struct drm_device *drm, unsigned int pipe)
Sascha Hauere692da42012-09-21 10:07:47 +0200111{
112 struct imx_drm_device *imxdrm = drm->dev_private;
Thierry Reding88e72712015-09-24 18:35:31 +0200113 struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[pipe];
Sascha Hauere692da42012-09-21 10:07:47 +0200114 int ret;
115
Sascha Hauere692da42012-09-21 10:07:47 +0200116 if (!imx_drm_crtc)
117 return -EINVAL;
118
119 if (!imx_drm_crtc->imx_drm_helper_funcs.enable_vblank)
120 return -ENOSYS;
121
122 ret = imx_drm_crtc->imx_drm_helper_funcs.enable_vblank(
123 imx_drm_crtc->crtc);
124
125 return ret;
126}
127
Thierry Reding88e72712015-09-24 18:35:31 +0200128static void imx_drm_disable_vblank(struct drm_device *drm, unsigned int pipe)
Sascha Hauere692da42012-09-21 10:07:47 +0200129{
130 struct imx_drm_device *imxdrm = drm->dev_private;
Thierry Reding88e72712015-09-24 18:35:31 +0200131 struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[pipe];
Sascha Hauere692da42012-09-21 10:07:47 +0200132
Sascha Hauere692da42012-09-21 10:07:47 +0200133 if (!imx_drm_crtc)
134 return;
135
136 if (!imx_drm_crtc->imx_drm_helper_funcs.disable_vblank)
137 return;
138
139 imx_drm_crtc->imx_drm_helper_funcs.disable_vblank(imx_drm_crtc->crtc);
140}
141
142static const struct file_operations imx_drm_driver_fops = {
143 .owner = THIS_MODULE,
144 .open = drm_open,
145 .release = drm_release,
146 .unlocked_ioctl = drm_ioctl,
147 .mmap = drm_gem_cma_mmap,
148 .poll = drm_poll,
Sascha Hauere692da42012-09-21 10:07:47 +0200149 .read = drm_read,
150 .llseek = noop_llseek,
151};
152
Russell King8a51a332013-11-03 13:28:24 +0000153void imx_drm_connector_destroy(struct drm_connector *connector)
154{
Thomas Wood34ea3d32014-05-29 16:57:41 +0100155 drm_connector_unregister(connector);
Russell King8a51a332013-11-03 13:28:24 +0000156 drm_connector_cleanup(connector);
157}
158EXPORT_SYMBOL_GPL(imx_drm_connector_destroy);
159
160void imx_drm_encoder_destroy(struct drm_encoder *encoder)
161{
162 drm_encoder_cleanup(encoder);
163}
164EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
165
Russell King3e684392013-11-03 22:18:40 +0000166static void imx_drm_output_poll_changed(struct drm_device *drm)
167{
Russell King3e684392013-11-03 22:18:40 +0000168 struct imx_drm_device *imxdrm = drm->dev_private;
169
170 drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
Russell King3e684392013-11-03 22:18:40 +0000171}
172
Ville Syrjälä7ae847d2015-12-15 12:21:09 +0100173static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
Russell King1df8b532013-11-03 16:04:48 +0000174 .fb_create = drm_fb_cma_create,
Russell King3e684392013-11-03 22:18:40 +0000175 .output_poll_changed = imx_drm_output_poll_changed,
Liu Ying5f2f9112016-07-08 17:40:59 +0800176 .atomic_check = drm_atomic_helper_check,
177 .atomic_commit = drm_atomic_helper_commit,
178};
179
180static void imx_drm_atomic_commit_tail(struct drm_atomic_state *state)
181{
182 struct drm_device *dev = state->dev;
183 struct drm_crtc *crtc;
184 struct drm_crtc_state *crtc_state;
185 struct drm_plane_state *plane_state;
186 struct drm_gem_cma_object *cma_obj;
187 struct fence *excl;
188 unsigned shared_count;
189 struct fence **shared;
190 unsigned int i, j;
191 int ret;
192
193 /* Wait for fences. */
194 for_each_crtc_in_state(state, crtc, crtc_state, i) {
195 plane_state = crtc->primary->state;
196 if (plane_state->fb) {
197 cma_obj = drm_fb_cma_get_gem_obj(plane_state->fb, 0);
198 if (cma_obj->base.dma_buf) {
199 ret = reservation_object_get_fences_rcu(
200 cma_obj->base.dma_buf->resv, &excl,
201 &shared_count, &shared);
202 if (unlikely(ret))
203 DRM_ERROR("failed to get fences "
204 "for buffer\n");
205
206 if (excl) {
207 fence_wait(excl, false);
208 fence_put(excl);
209 }
210 for (j = 0; j < shared_count; i++) {
211 fence_wait(shared[j], false);
212 fence_put(shared[j]);
213 }
214 }
215 }
216 }
217
218 drm_atomic_helper_commit_modeset_disables(dev, state);
219
220 drm_atomic_helper_commit_planes(dev, state, true);
221
222 drm_atomic_helper_commit_modeset_enables(dev, state);
223
224 drm_atomic_helper_commit_hw_done(state);
225
226 drm_atomic_helper_wait_for_vblanks(dev, state);
227
228 drm_atomic_helper_cleanup_planes(dev, state);
229}
230
231static struct drm_mode_config_helper_funcs imx_drm_mode_config_helpers = {
232 .atomic_commit_tail = imx_drm_atomic_commit_tail,
Russell King1df8b532013-11-03 16:04:48 +0000233};
234
Sascha Hauere692da42012-09-21 10:07:47 +0200235/*
Russell King17b50012013-11-03 11:23:34 +0000236 * Main DRM initialisation. This binds, initialises and registers
237 * with DRM the subcomponents of the driver.
Sascha Hauere692da42012-09-21 10:07:47 +0200238 */
239static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
240{
Russell Kingb85f2b52013-11-03 15:31:22 +0000241 struct imx_drm_device *imxdrm;
Russell Kinge355e7d2013-11-03 18:39:29 +0000242 struct drm_connector *connector;
Sascha Hauere692da42012-09-21 10:07:47 +0200243 int ret;
244
Russell Kingb85f2b52013-11-03 15:31:22 +0000245 imxdrm = devm_kzalloc(drm->dev, sizeof(*imxdrm), GFP_KERNEL);
246 if (!imxdrm)
247 return -ENOMEM;
248
Sascha Hauere692da42012-09-21 10:07:47 +0200249 imxdrm->drm = drm;
250
251 drm->dev_private = imxdrm;
252
253 /*
254 * enable drm irq mode.
Ville Syrjälä44238432013-10-04 14:53:37 +0300255 * - with irq_enabled = true, we can use the vblank feature.
Sascha Hauere692da42012-09-21 10:07:47 +0200256 *
257 * P.S. note that we wouldn't use drm irq handler but
258 * just specific driver own one instead because
259 * drm framework supports only one irq handler and
260 * drivers can well take care of their interrupts
261 */
Ville Syrjälä44238432013-10-04 14:53:37 +0300262 drm->irq_enabled = true;
Sascha Hauere692da42012-09-21 10:07:47 +0200263
Russell King1df8b532013-11-03 16:04:48 +0000264 /*
265 * set max width and height as default value(4096x4096).
266 * this value would be used to check framebuffer size limitation
267 * at drm_mode_addfb().
268 */
269 drm->mode_config.min_width = 64;
270 drm->mode_config.min_height = 64;
271 drm->mode_config.max_width = 4096;
272 drm->mode_config.max_height = 4096;
273 drm->mode_config.funcs = &imx_drm_mode_config_funcs;
Liu Ying5f2f9112016-07-08 17:40:59 +0800274 drm->mode_config.helper_private = &imx_drm_mode_config_helpers;
Russell King1df8b532013-11-03 16:04:48 +0000275
Sascha Hauere692da42012-09-21 10:07:47 +0200276 drm_mode_config_init(drm);
Sascha Hauere692da42012-09-21 10:07:47 +0200277
Russell King020a9ea2013-12-17 19:10:47 +0000278 ret = drm_vblank_init(drm, MAX_CRTC);
Sascha Hauere692da42012-09-21 10:07:47 +0200279 if (ret)
Russell King80078752013-12-16 11:33:44 +0000280 goto err_kms;
Sascha Hauere692da42012-09-21 10:07:47 +0200281
Daniel Vettera72f8be2013-11-03 14:31:09 +0100282 platform_set_drvdata(drm->platformdev, drm);
Russell King8d71de62013-11-03 13:55:34 +0000283
Russell King17b50012013-11-03 11:23:34 +0000284 /* Now try and bind all our sub-components */
285 ret = component_bind_all(drm->dev, drm);
286 if (ret)
Russell Kingccec7f62013-11-03 15:20:18 +0000287 goto err_vblank;
Russell Kinge355e7d2013-11-03 18:39:29 +0000288
289 /*
290 * All components are now added, we can publish the connector sysfs
291 * entries to userspace. This will generate hotplug events and so
292 * userspace will expect to be able to access DRM at this point.
293 */
294 list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
Thomas Wood34ea3d32014-05-29 16:57:41 +0100295 ret = drm_connector_register(connector);
Russell Kinge355e7d2013-11-03 18:39:29 +0000296 if (ret) {
297 dev_err(drm->dev,
Thomas Wood34ea3d32014-05-29 16:57:41 +0100298 "[CONNECTOR:%d:%s] drm_connector_register failed: %d\n",
Russell Kinge355e7d2013-11-03 18:39:29 +0000299 connector->base.id,
Jani Nikula4a2a4502014-06-03 14:56:16 +0300300 connector->name, ret);
Russell Kinge355e7d2013-11-03 18:39:29 +0000301 goto err_unbind;
302 }
303 }
304
Liu Ying255c35f2016-07-08 17:40:56 +0800305 drm_mode_config_reset(drm);
306
Russell King8acba022013-11-03 12:13:47 +0000307 /*
308 * All components are now initialised, so setup the fb helper.
309 * The fb helper takes copies of key hardware information, so the
310 * crtcs/connectors/encoders must not change after this point.
311 */
Archit Tanejac1ff5a72015-10-27 13:40:57 +0530312#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
Russell King8acba022013-11-03 12:13:47 +0000313 if (legacyfb_depth != 16 && legacyfb_depth != 32) {
314 dev_warn(drm->dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n");
315 legacyfb_depth = 16;
316 }
317 imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
318 drm->mode_config.num_crtc, MAX_CRTC);
319 if (IS_ERR(imxdrm->fbhelper)) {
320 ret = PTR_ERR(imxdrm->fbhelper);
321 imxdrm->fbhelper = NULL;
322 goto err_unbind;
323 }
324#endif
Russell King3e684392013-11-03 22:18:40 +0000325
326 drm_kms_helper_poll_init(drm);
327
Russell King80078752013-12-16 11:33:44 +0000328 return 0;
Daniel Vettera72f8be2013-11-03 14:31:09 +0100329
Russell Kinge355e7d2013-11-03 18:39:29 +0000330err_unbind:
331 component_unbind_all(drm->dev, drm);
Russell Kingccec7f62013-11-03 15:20:18 +0000332err_vblank:
Russell King80078752013-12-16 11:33:44 +0000333 drm_vblank_cleanup(drm);
334err_kms:
Russell King80078752013-12-16 11:33:44 +0000335 drm_mode_config_cleanup(drm);
Sascha Hauere692da42012-09-21 10:07:47 +0200336
337 return ret;
338}
339
Sascha Hauere692da42012-09-21 10:07:47 +0200340/*
341 * imx_drm_add_crtc - add a new crtc
Sascha Hauere692da42012-09-21 10:07:47 +0200342 */
Russell King32266b42013-11-03 12:26:23 +0000343int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
Philipp Zabel43895592015-11-06 11:08:02 +0100344 struct imx_drm_crtc **new_crtc, struct drm_plane *primary_plane,
Sascha Hauere692da42012-09-21 10:07:47 +0200345 const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
Philipp Zabel655b43c2014-03-05 10:20:52 +0100346 struct device_node *port)
Sascha Hauere692da42012-09-21 10:07:47 +0200347{
Russell King32266b42013-11-03 12:26:23 +0000348 struct imx_drm_device *imxdrm = drm->dev_private;
Sascha Hauere692da42012-09-21 10:07:47 +0200349 struct imx_drm_crtc *imx_drm_crtc;
Sascha Hauere692da42012-09-21 10:07:47 +0200350
Russell Kingfd6040e2013-12-16 12:39:31 +0000351 /*
352 * The vblank arrays are dimensioned by MAX_CRTC - we can't
353 * pass IDs greater than this to those functions.
354 */
Russell Kinge7d62312013-11-03 15:38:09 +0000355 if (imxdrm->pipes >= MAX_CRTC)
356 return -EINVAL;
Russell Kingfd6040e2013-12-16 12:39:31 +0000357
Russell Kinge7d62312013-11-03 15:38:09 +0000358 if (imxdrm->drm->open_count)
359 return -EBUSY;
Sascha Hauere692da42012-09-21 10:07:47 +0200360
361 imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL);
Russell Kinge7d62312013-11-03 15:38:09 +0000362 if (!imx_drm_crtc)
363 return -ENOMEM;
Sascha Hauere692da42012-09-21 10:07:47 +0200364
365 imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
Sascha Hauere692da42012-09-21 10:07:47 +0200366 imx_drm_crtc->crtc = crtc;
Sascha Hauere692da42012-09-21 10:07:47 +0200367
Russell King6457b972014-07-03 17:52:57 +0100368 crtc->port = port;
369
Thierry Redingd4b20e42015-12-15 12:20:52 +0100370 imxdrm->crtc[imxdrm->pipes++] = imx_drm_crtc;
Sascha Hauere692da42012-09-21 10:07:47 +0200371
372 *new_crtc = imx_drm_crtc;
373
Russell Kingec9557d2013-12-17 19:11:07 +0000374 drm_crtc_helper_add(crtc,
375 imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
376
Philipp Zabel43895592015-11-06 11:08:02 +0100377 drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL,
Ville Syrjäläf9882872015-12-09 16:19:31 +0200378 imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs, NULL);
Russell Kingec9557d2013-12-17 19:11:07 +0000379
Sascha Hauere692da42012-09-21 10:07:47 +0200380 return 0;
Sascha Hauere692da42012-09-21 10:07:47 +0200381}
382EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
383
384/*
385 * imx_drm_remove_crtc - remove a crtc
386 */
387int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
388{
Russell Kingccec7f62013-11-03 15:20:18 +0000389 struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private;
Thierry Redingd4b20e42015-12-15 12:20:52 +0100390 unsigned int pipe = drm_crtc_index(imx_drm_crtc->crtc);
Sascha Hauere692da42012-09-21 10:07:47 +0200391
392 drm_crtc_cleanup(imx_drm_crtc->crtc);
393
Thierry Redingd4b20e42015-12-15 12:20:52 +0100394 imxdrm->crtc[pipe] = NULL;
Sascha Hauere692da42012-09-21 10:07:47 +0200395
Sascha Hauere692da42012-09-21 10:07:47 +0200396 kfree(imx_drm_crtc);
397
398 return 0;
399}
400EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
401
Russell King9e2d4102013-11-03 14:04:47 +0000402int imx_drm_encoder_parse_of(struct drm_device *drm,
403 struct drm_encoder *encoder, struct device_node *np)
404{
Russell King6457b972014-07-03 17:52:57 +0100405 uint32_t crtc_mask = drm_of_find_possible_crtcs(drm, np);
Russell King9e2d4102013-11-03 14:04:47 +0000406
Russell King6457b972014-07-03 17:52:57 +0100407 /*
408 * If we failed to find the CRTC(s) which this encoder is
409 * supposed to be connected to, it's because the CRTC has
410 * not been registered yet. Defer probing, and hope that
411 * the required CRTC is added later.
412 */
413 if (crtc_mask == 0)
414 return -EPROBE_DEFER;
Philipp Zabel655b43c2014-03-05 10:20:52 +0100415
Russell King9e2d4102013-11-03 14:04:47 +0000416 encoder->possible_crtcs = crtc_mask;
417
418 /* FIXME: this is the mask of outputs which can clone this output. */
419 encoder->possible_clones = ~0;
420
421 return 0;
422}
423EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
424
Rob Clarkbaa70942013-08-02 13:27:49 -0400425static const struct drm_ioctl_desc imx_drm_ioctls[] = {
Sascha Hauere692da42012-09-21 10:07:47 +0200426 /* none so far */
427};
428
429static struct drm_driver imx_drm_driver = {
Liu Ying8535c022016-07-08 17:41:02 +0800430 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
431 DRIVER_ATOMIC,
Sascha Hauere692da42012-09-21 10:07:47 +0200432 .load = imx_drm_driver_load,
433 .unload = imx_drm_driver_unload,
Sascha Hauere692da42012-09-21 10:07:47 +0200434 .lastclose = imx_drm_driver_lastclose,
Daniel Vetter4b193662016-04-26 19:29:52 +0200435 .gem_free_object_unlocked = drm_gem_cma_free_object,
Sascha Hauere692da42012-09-21 10:07:47 +0200436 .gem_vm_ops = &drm_gem_cma_vm_ops,
437 .dumb_create = drm_gem_cma_dumb_create,
438 .dumb_map_offset = drm_gem_cma_dumb_map_offset,
Daniel Vetter43387b32013-07-16 09:12:04 +0200439 .dumb_destroy = drm_gem_dumb_destroy,
Sascha Hauere692da42012-09-21 10:07:47 +0200440
Philipp Zabelbd3665c2013-10-10 16:18:46 +0200441 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
442 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
443 .gem_prime_import = drm_gem_prime_import,
444 .gem_prime_export = drm_gem_prime_export,
445 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
446 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
447 .gem_prime_vmap = drm_gem_cma_prime_vmap,
448 .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
449 .gem_prime_mmap = drm_gem_cma_prime_mmap,
Ville Syrjäläb44f8402015-09-30 16:46:48 +0300450 .get_vblank_counter = drm_vblank_no_hw_counter,
Sascha Hauere692da42012-09-21 10:07:47 +0200451 .enable_vblank = imx_drm_enable_vblank,
452 .disable_vblank = imx_drm_disable_vblank,
453 .ioctls = imx_drm_ioctls,
454 .num_ioctls = ARRAY_SIZE(imx_drm_ioctls),
455 .fops = &imx_drm_driver_fops,
456 .name = "imx-drm",
457 .desc = "i.MX DRM graphics",
458 .date = "20120507",
459 .major = 1,
460 .minor = 0,
461 .patchlevel = 0,
462};
463
Russell King17b50012013-11-03 11:23:34 +0000464static int compare_of(struct device *dev, void *data)
465{
Philipp Zabel655b43c2014-03-05 10:20:52 +0100466 struct device_node *np = data;
467
Philipp Zabel310944d2016-05-12 15:00:44 +0200468 /* Special case for DI, dev->of_node may not be set yet */
469 if (strcmp(dev->driver->name, "imx-ipuv3-crtc") == 0) {
470 struct ipu_client_platformdata *pdata = dev->platform_data;
471
472 return pdata->of_node == np;
473 }
474
Philipp Zabel655b43c2014-03-05 10:20:52 +0100475 /* Special case for LDB, one device for two channels */
476 if (of_node_cmp(np->name, "lvds-channel") == 0) {
477 np = of_get_parent(np);
478 of_node_put(np);
479 }
480
481 return dev->of_node == np;
Russell King17b50012013-11-03 11:23:34 +0000482}
483
Russell King17b50012013-11-03 11:23:34 +0000484static int imx_drm_bind(struct device *dev)
485{
486 return drm_platform_init(&imx_drm_driver, to_platform_device(dev));
487}
488
489static void imx_drm_unbind(struct device *dev)
490{
491 drm_put_dev(dev_get_drvdata(dev));
492}
493
494static const struct component_master_ops imx_drm_ops = {
Russell King17b50012013-11-03 11:23:34 +0000495 .bind = imx_drm_bind,
496 .unbind = imx_drm_unbind,
497};
498
Sascha Hauere692da42012-09-21 10:07:47 +0200499static int imx_drm_platform_probe(struct platform_device *pdev)
500{
Liviu Dudau9cace322015-10-20 10:23:13 +0100501 int ret = drm_of_component_probe(&pdev->dev, compare_of, &imx_drm_ops);
Philipp Zabel655b43c2014-03-05 10:20:52 +0100502
Liviu Dudau9cace322015-10-20 10:23:13 +0100503 if (!ret)
504 ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
Philipp Zabel655b43c2014-03-05 10:20:52 +0100505
Liviu Dudau9cace322015-10-20 10:23:13 +0100506 return ret;
Sascha Hauere692da42012-09-21 10:07:47 +0200507}
508
509static int imx_drm_platform_remove(struct platform_device *pdev)
510{
Russell King17b50012013-11-03 11:23:34 +0000511 component_master_del(&pdev->dev, &imx_drm_ops);
Sascha Hauere692da42012-09-21 10:07:47 +0200512 return 0;
513}
514
Shawn Guobfe945c2014-09-10 22:43:51 +0800515#ifdef CONFIG_PM_SLEEP
516static int imx_drm_suspend(struct device *dev)
517{
518 struct drm_device *drm_dev = dev_get_drvdata(dev);
Liu Ying5f2f9112016-07-08 17:40:59 +0800519 struct imx_drm_device *imxdrm;
Shawn Guobfe945c2014-09-10 22:43:51 +0800520
521 /* The drm_dev is NULL before .load hook is called */
522 if (drm_dev == NULL)
523 return 0;
524
525 drm_kms_helper_poll_disable(drm_dev);
526
Liu Ying5f2f9112016-07-08 17:40:59 +0800527 imxdrm = drm_dev->dev_private;
528 imxdrm->state = drm_atomic_helper_suspend(drm_dev);
529 if (IS_ERR(imxdrm->state)) {
530 drm_kms_helper_poll_enable(drm_dev);
531 return PTR_ERR(imxdrm->state);
532 }
533
Shawn Guobfe945c2014-09-10 22:43:51 +0800534 return 0;
535}
536
537static int imx_drm_resume(struct device *dev)
538{
539 struct drm_device *drm_dev = dev_get_drvdata(dev);
Liu Ying5f2f9112016-07-08 17:40:59 +0800540 struct imx_drm_device *imx_drm;
Shawn Guobfe945c2014-09-10 22:43:51 +0800541
542 if (drm_dev == NULL)
543 return 0;
544
Liu Ying5f2f9112016-07-08 17:40:59 +0800545 imx_drm = drm_dev->dev_private;
546 drm_atomic_helper_resume(drm_dev, imx_drm->state);
Shawn Guobfe945c2014-09-10 22:43:51 +0800547 drm_kms_helper_poll_enable(drm_dev);
548
549 return 0;
550}
551#endif
552
553static SIMPLE_DEV_PM_OPS(imx_drm_pm_ops, imx_drm_suspend, imx_drm_resume);
554
Russell King17b50012013-11-03 11:23:34 +0000555static const struct of_device_id imx_drm_dt_ids[] = {
Philipp Zabel655b43c2014-03-05 10:20:52 +0100556 { .compatible = "fsl,imx-display-subsystem", },
Russell King17b50012013-11-03 11:23:34 +0000557 { /* sentinel */ },
558};
559MODULE_DEVICE_TABLE(of, imx_drm_dt_ids);
560
Sascha Hauere692da42012-09-21 10:07:47 +0200561static struct platform_driver imx_drm_pdrv = {
562 .probe = imx_drm_platform_probe,
Bill Pemberton99c28f12012-11-19 13:20:51 -0500563 .remove = imx_drm_platform_remove,
Sascha Hauere692da42012-09-21 10:07:47 +0200564 .driver = {
Sascha Hauere692da42012-09-21 10:07:47 +0200565 .name = "imx-drm",
Shawn Guobfe945c2014-09-10 22:43:51 +0800566 .pm = &imx_drm_pm_ops,
Russell King17b50012013-11-03 11:23:34 +0000567 .of_match_table = imx_drm_dt_ids,
Sascha Hauere692da42012-09-21 10:07:47 +0200568 },
569};
Russell Kingb85f2b52013-11-03 15:31:22 +0000570module_platform_driver(imx_drm_pdrv);
Sascha Hauere692da42012-09-21 10:07:47 +0200571
572MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
573MODULE_DESCRIPTION("i.MX drm driver core");
574MODULE_LICENSE("GPL");