]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/staging/imx-drm/imx-drm-core.c
Merge branch 'topic/of-graph' of git://git.pengutronix.de/git/pza/linux into imx...
[mirror_ubuntu-artful-kernel.git] / drivers / staging / imx-drm / imx-drm-core.c
CommitLineData
e692da4d
SH
1/*
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 */
17b5001b 16#include <linux/component.h>
e692da4d 17#include <linux/device.h>
e7d6231e
RK
18#include <linux/fb.h>
19#include <linux/module.h>
e692da4d
SH
20#include <linux/platform_device.h>
21#include <drm/drmP.h>
22#include <drm/drm_fb_helper.h>
23#include <drm/drm_crtc_helper.h>
e692da4d
SH
24#include <drm/drm_gem_cma_helper.h>
25#include <drm/drm_fb_cma_helper.h>
26
27#include "imx-drm.h"
28
29#define MAX_CRTC 4
30
887eceac
RK
31struct imx_drm_crtc;
32
e692da4d
SH
33struct imx_drm_device {
34 struct drm_device *drm;
887eceac 35 struct imx_drm_crtc *crtc[MAX_CRTC];
e692da4d
SH
36 int pipes;
37 struct drm_fbdev_cma *fbhelper;
38};
39
40struct imx_drm_crtc {
41 struct drm_crtc *crtc;
e692da4d
SH
42 int pipe;
43 struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs;
e7d6231e
RK
44 void *cookie;
45 int id;
e76171b0 46 int mux_id;
e692da4d
SH
47};
48
8acba02f
RK
49static int legacyfb_depth = 16;
50module_param(legacyfb_depth, int, 0444);
51
b8d181e4
PZ
52int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
53{
54 return crtc->pipe;
55}
9c74360f 56EXPORT_SYMBOL_GPL(imx_drm_crtc_id);
b8d181e4 57
e692da4d
SH
58static void imx_drm_driver_lastclose(struct drm_device *drm)
59{
8acba02f 60#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
e692da4d
SH
61 struct imx_drm_device *imxdrm = drm->dev_private;
62
63 if (imxdrm->fbhelper)
64 drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
8acba02f 65#endif
e692da4d
SH
66}
67
68static int imx_drm_driver_unload(struct drm_device *drm)
69{
8acba02f 70#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
e692da4d 71 struct imx_drm_device *imxdrm = drm->dev_private;
3e68439b
RK
72#endif
73
74 drm_kms_helper_poll_fini(drm);
e692da4d 75
3e68439b 76#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
8acba02f
RK
77 if (imxdrm->fbhelper)
78 drm_fbdev_cma_fini(imxdrm->fbhelper);
79#endif
80
17b5001b
RK
81 component_unbind_all(drm->dev, drm);
82
020a9ea7 83 drm_vblank_cleanup(drm);
020a9ea7 84 drm_mode_config_cleanup(drm);
e692da4d
SH
85
86 return 0;
87}
88
887eceac 89struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
e692da4d 90{
32266b45 91 struct imx_drm_device *imxdrm = crtc->dev->dev_private;
887eceac
RK
92 unsigned i;
93
94 for (i = 0; i < MAX_CRTC; i++)
95 if (imxdrm->crtc[i] && imxdrm->crtc[i]->crtc == crtc)
96 return imxdrm->crtc[i];
e692da4d 97
e692da4d
SH
98 return NULL;
99}
100
f2d66aad 101int imx_drm_panel_format_pins(struct drm_encoder *encoder,
2ea42608 102 u32 interface_pix_fmt, int hsync_pin, int vsync_pin)
e692da4d 103{
e692da4d 104 struct imx_drm_crtc_helper_funcs *helper;
887eceac 105 struct imx_drm_crtc *imx_crtc;
e692da4d 106
f2d66aad 107 imx_crtc = imx_drm_find_crtc(encoder->crtc);
887eceac
RK
108 if (!imx_crtc)
109 return -EINVAL;
e692da4d 110
e692da4d
SH
111 helper = &imx_crtc->imx_drm_helper_funcs;
112 if (helper->set_interface_pix_fmt)
f2d66aad
RK
113 return helper->set_interface_pix_fmt(encoder->crtc,
114 encoder->encoder_type, interface_pix_fmt,
2ea42608 115 hsync_pin, vsync_pin);
e692da4d
SH
116 return 0;
117}
f2d66aad 118EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins);
2ea42608 119
f2d66aad 120int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt)
2ea42608 121{
f2d66aad 122 return imx_drm_panel_format_pins(encoder, interface_pix_fmt, 2, 3);
2ea42608 123}
f2d66aad 124EXPORT_SYMBOL_GPL(imx_drm_panel_format);
e692da4d
SH
125
126int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
127{
b5ea1492 128 return drm_vblank_get(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
e692da4d
SH
129}
130EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get);
131
132void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc)
133{
b5ea1492 134 drm_vblank_put(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
e692da4d
SH
135}
136EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put);
137
138void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc)
139{
b5ea1492 140 drm_handle_vblank(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
e692da4d
SH
141}
142EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
143
144static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
145{
146 struct imx_drm_device *imxdrm = drm->dev_private;
887eceac 147 struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
e692da4d
SH
148 int ret;
149
e692da4d
SH
150 if (!imx_drm_crtc)
151 return -EINVAL;
152
153 if (!imx_drm_crtc->imx_drm_helper_funcs.enable_vblank)
154 return -ENOSYS;
155
156 ret = imx_drm_crtc->imx_drm_helper_funcs.enable_vblank(
157 imx_drm_crtc->crtc);
158
159 return ret;
160}
161
162static void imx_drm_disable_vblank(struct drm_device *drm, int crtc)
163{
164 struct imx_drm_device *imxdrm = drm->dev_private;
887eceac 165 struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
e692da4d 166
e692da4d
SH
167 if (!imx_drm_crtc)
168 return;
169
170 if (!imx_drm_crtc->imx_drm_helper_funcs.disable_vblank)
171 return;
172
173 imx_drm_crtc->imx_drm_helper_funcs.disable_vblank(imx_drm_crtc->crtc);
174}
175
6ee4d7fe
SH
176static void imx_drm_driver_preclose(struct drm_device *drm,
177 struct drm_file *file)
178{
179 int i;
180
181 if (!file->is_master)
182 return;
183
942325c8
RK
184 for (i = 0; i < MAX_CRTC; i++)
185 imx_drm_disable_vblank(drm, i);
6ee4d7fe
SH
186}
187
e692da4d
SH
188static const struct file_operations imx_drm_driver_fops = {
189 .owner = THIS_MODULE,
190 .open = drm_open,
191 .release = drm_release,
192 .unlocked_ioctl = drm_ioctl,
193 .mmap = drm_gem_cma_mmap,
194 .poll = drm_poll,
e692da4d
SH
195 .read = drm_read,
196 .llseek = noop_llseek,
197};
198
baa68c4b
RK
199int imx_drm_connector_mode_valid(struct drm_connector *connector,
200 struct drm_display_mode *mode)
201{
202 return MODE_OK;
203}
204EXPORT_SYMBOL(imx_drm_connector_mode_valid);
205
8a51a33b
RK
206void imx_drm_connector_destroy(struct drm_connector *connector)
207{
208 drm_sysfs_connector_remove(connector);
209 drm_connector_cleanup(connector);
210}
211EXPORT_SYMBOL_GPL(imx_drm_connector_destroy);
212
213void imx_drm_encoder_destroy(struct drm_encoder *encoder)
214{
215 drm_encoder_cleanup(encoder);
216}
217EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
218
3e68439b
RK
219static void imx_drm_output_poll_changed(struct drm_device *drm)
220{
221#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
222 struct imx_drm_device *imxdrm = drm->dev_private;
223
224 drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
225#endif
226}
227
1df8b530
RK
228static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
229 .fb_create = drm_fb_cma_create,
3e68439b 230 .output_poll_changed = imx_drm_output_poll_changed,
1df8b530
RK
231};
232
e692da4d 233/*
17b5001b
RK
234 * Main DRM initialisation. This binds, initialises and registers
235 * with DRM the subcomponents of the driver.
e692da4d
SH
236 */
237static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
238{
b85f2b5d 239 struct imx_drm_device *imxdrm;
e355e7dd 240 struct drm_connector *connector;
e692da4d
SH
241 int ret;
242
b85f2b5d
RK
243 imxdrm = devm_kzalloc(drm->dev, sizeof(*imxdrm), GFP_KERNEL);
244 if (!imxdrm)
245 return -ENOMEM;
246
e692da4d
SH
247 imxdrm->drm = drm;
248
249 drm->dev_private = imxdrm;
250
251 /*
252 * enable drm irq mode.
4423843c 253 * - with irq_enabled = true, we can use the vblank feature.
e692da4d
SH
254 *
255 * P.S. note that we wouldn't use drm irq handler but
256 * just specific driver own one instead because
257 * drm framework supports only one irq handler and
258 * drivers can well take care of their interrupts
259 */
4423843c 260 drm->irq_enabled = true;
e692da4d 261
1df8b530
RK
262 /*
263 * set max width and height as default value(4096x4096).
264 * this value would be used to check framebuffer size limitation
265 * at drm_mode_addfb().
266 */
267 drm->mode_config.min_width = 64;
268 drm->mode_config.min_height = 64;
269 drm->mode_config.max_width = 4096;
270 drm->mode_config.max_height = 4096;
271 drm->mode_config.funcs = &imx_drm_mode_config_funcs;
272
e692da4d 273 drm_mode_config_init(drm);
e692da4d 274
020a9ea7 275 ret = drm_vblank_init(drm, MAX_CRTC);
e692da4d 276 if (ret)
8007875f 277 goto err_kms;
e692da4d
SH
278
279 /*
e7d6231e
RK
280 * with vblank_disable_allowed = true, vblank interrupt will be
281 * disabled by drm timer once a current process gives up ownership
282 * of vblank event. (after drm_vblank_put function is called)
e692da4d 283 */
020a9ea7 284 drm->vblank_disable_allowed = true;
e692da4d 285
a72f8bee 286 platform_set_drvdata(drm->platformdev, drm);
8d71de61 287
17b5001b
RK
288 /* Now try and bind all our sub-components */
289 ret = component_bind_all(drm->dev, drm);
290 if (ret)
ccec7f62 291 goto err_vblank;
e355e7dd
RK
292
293 /*
294 * All components are now added, we can publish the connector sysfs
295 * entries to userspace. This will generate hotplug events and so
296 * userspace will expect to be able to access DRM at this point.
297 */
298 list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
299 ret = drm_sysfs_connector_add(connector);
300 if (ret) {
301 dev_err(drm->dev,
302 "[CONNECTOR:%d:%s] drm_sysfs_connector_add failed: %d\n",
303 connector->base.id,
304 drm_get_connector_name(connector), ret);
305 goto err_unbind;
306 }
307 }
308
8acba02f
RK
309 /*
310 * All components are now initialised, so setup the fb helper.
311 * The fb helper takes copies of key hardware information, so the
312 * crtcs/connectors/encoders must not change after this point.
313 */
314#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
315 if (legacyfb_depth != 16 && legacyfb_depth != 32) {
316 dev_warn(drm->dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n");
317 legacyfb_depth = 16;
318 }
319 imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
320 drm->mode_config.num_crtc, MAX_CRTC);
321 if (IS_ERR(imxdrm->fbhelper)) {
322 ret = PTR_ERR(imxdrm->fbhelper);
323 imxdrm->fbhelper = NULL;
324 goto err_unbind;
325 }
326#endif
3e68439b
RK
327
328 drm_kms_helper_poll_init(drm);
329
8007875f 330 return 0;
a72f8bee 331
e355e7dd
RK
332err_unbind:
333 component_unbind_all(drm->dev, drm);
ccec7f62 334err_vblank:
8007875f
RK
335 drm_vblank_cleanup(drm);
336err_kms:
8007875f 337 drm_mode_config_cleanup(drm);
e692da4d
SH
338
339 return ret;
340}
341
e692da4d
SH
342/*
343 * imx_drm_add_crtc - add a new crtc
344 *
345 * The return value if !NULL is a cookie for the caller to pass to
346 * imx_drm_remove_crtc later.
347 */
32266b45 348int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
e692da4d
SH
349 struct imx_drm_crtc **new_crtc,
350 const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
32266b45 351 void *cookie, int id)
e692da4d 352{
32266b45 353 struct imx_drm_device *imxdrm = drm->dev_private;
e692da4d 354 struct imx_drm_crtc *imx_drm_crtc;
e692da4d
SH
355 int ret;
356
fd6040ed
RK
357 /*
358 * The vblank arrays are dimensioned by MAX_CRTC - we can't
359 * pass IDs greater than this to those functions.
360 */
e7d6231e
RK
361 if (imxdrm->pipes >= MAX_CRTC)
362 return -EINVAL;
fd6040ed 363
e7d6231e
RK
364 if (imxdrm->drm->open_count)
365 return -EBUSY;
e692da4d
SH
366
367 imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL);
e7d6231e
RK
368 if (!imx_drm_crtc)
369 return -ENOMEM;
e692da4d
SH
370
371 imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
372 imx_drm_crtc->pipe = imxdrm->pipes++;
e7d6231e
RK
373 imx_drm_crtc->cookie = cookie;
374 imx_drm_crtc->id = id;
e76171b0 375 imx_drm_crtc->mux_id = imx_drm_crtc->pipe;
e692da4d 376 imx_drm_crtc->crtc = crtc;
e692da4d 377
887eceac 378 imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
e692da4d
SH
379
380 *new_crtc = imx_drm_crtc;
381
ec9557d7 382 ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256);
e692da4d
SH
383 if (ret)
384 goto err_register;
385
ec9557d7
RK
386 drm_crtc_helper_add(crtc,
387 imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
388
32266b45 389 drm_crtc_init(drm, crtc,
ec9557d7
RK
390 imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
391
e692da4d
SH
392 return 0;
393
394err_register:
887eceac 395 imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
e692da4d 396 kfree(imx_drm_crtc);
e692da4d
SH
397 return ret;
398}
399EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
400
401/*
402 * imx_drm_remove_crtc - remove a crtc
403 */
404int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
405{
ccec7f62 406 struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private;
e692da4d
SH
407
408 drm_crtc_cleanup(imx_drm_crtc->crtc);
409
887eceac 410 imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
e692da4d 411
e692da4d
SH
412 kfree(imx_drm_crtc);
413
414 return 0;
415}
416EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
417
9e2d410d
RK
418/*
419 * Find the DRM CRTC possible mask for the device node cookie/id.
420 *
421 * The encoder possible masks are defined by their position in the
422 * mode_config crtc_list. This means that CRTCs must not be added
423 * or removed once the DRM device has been fully initialised.
424 */
425static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
426 void *cookie, int id)
427{
428 unsigned i;
429
430 for (i = 0; i < MAX_CRTC; i++) {
431 struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
e7d6231e
RK
432 if (imx_drm_crtc && imx_drm_crtc->id == id &&
433 imx_drm_crtc->cookie == cookie)
9e2d410d
RK
434 return drm_crtc_mask(imx_drm_crtc->crtc);
435 }
436
437 return 0;
438}
439
440int imx_drm_encoder_parse_of(struct drm_device *drm,
441 struct drm_encoder *encoder, struct device_node *np)
442{
443 struct imx_drm_device *imxdrm = drm->dev_private;
444 uint32_t crtc_mask = 0;
445 int i, ret = 0;
446
447 for (i = 0; !ret; i++) {
448 struct of_phandle_args args;
449 uint32_t mask;
450 int id;
451
452 ret = of_parse_phandle_with_args(np, "crtcs", "#crtc-cells", i,
453 &args);
454 if (ret == -ENOENT)
455 break;
456 if (ret < 0)
457 return ret;
458
459 id = args.args_count > 0 ? args.args[0] : 0;
460 mask = imx_drm_find_crtc_mask(imxdrm, args.np, id);
461 of_node_put(args.np);
462
463 /*
464 * If we failed to find the CRTC(s) which this encoder is
465 * supposed to be connected to, it's because the CRTC has
466 * not been registered yet. Defer probing, and hope that
467 * the required CRTC is added later.
468 */
469 if (mask == 0)
470 return -EPROBE_DEFER;
471
472 crtc_mask |= mask;
473 }
474
475 encoder->possible_crtcs = crtc_mask;
476
477 /* FIXME: this is the mask of outputs which can clone this output. */
478 encoder->possible_clones = ~0;
479
480 return 0;
481}
482EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
483
e76171b0 484int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder)
e692da4d 485{
887eceac 486 struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc);
e692da4d 487
887eceac 488 return imx_crtc ? imx_crtc->mux_id : -EINVAL;
e692da4d 489}
ea8d1583 490EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
e692da4d 491
baa70943 492static const struct drm_ioctl_desc imx_drm_ioctls[] = {
e692da4d
SH
493 /* none so far */
494};
495
496static struct drm_driver imx_drm_driver = {
bd3665c9 497 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
e692da4d
SH
498 .load = imx_drm_driver_load,
499 .unload = imx_drm_driver_unload,
e692da4d 500 .lastclose = imx_drm_driver_lastclose,
6ee4d7fe 501 .preclose = imx_drm_driver_preclose,
e692da4d
SH
502 .gem_free_object = drm_gem_cma_free_object,
503 .gem_vm_ops = &drm_gem_cma_vm_ops,
504 .dumb_create = drm_gem_cma_dumb_create,
505 .dumb_map_offset = drm_gem_cma_dumb_map_offset,
43387b37 506 .dumb_destroy = drm_gem_dumb_destroy,
e692da4d 507
bd3665c9
PZ
508 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
509 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
510 .gem_prime_import = drm_gem_prime_import,
511 .gem_prime_export = drm_gem_prime_export,
512 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
513 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
514 .gem_prime_vmap = drm_gem_cma_prime_vmap,
515 .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
516 .gem_prime_mmap = drm_gem_cma_prime_mmap,
e692da4d
SH
517 .get_vblank_counter = drm_vblank_count,
518 .enable_vblank = imx_drm_enable_vblank,
519 .disable_vblank = imx_drm_disable_vblank,
520 .ioctls = imx_drm_ioctls,
521 .num_ioctls = ARRAY_SIZE(imx_drm_ioctls),
522 .fops = &imx_drm_driver_fops,
523 .name = "imx-drm",
524 .desc = "i.MX DRM graphics",
525 .date = "20120507",
526 .major = 1,
527 .minor = 0,
528 .patchlevel = 0,
529};
530
17b5001b
RK
531static int compare_parent_of(struct device *dev, void *data)
532{
533 struct of_phandle_args *args = data;
534 return dev->parent && dev->parent->of_node == args->np;
535}
536
537static int compare_of(struct device *dev, void *data)
538{
539 return dev->of_node == data;
540}
541
542static int imx_drm_add_components(struct device *master, struct master *m)
543{
544 struct device_node *np = master->of_node;
545 unsigned i;
546 int ret;
547
548 for (i = 0; ; i++) {
549 struct of_phandle_args args;
550
551 ret = of_parse_phandle_with_fixed_args(np, "crtcs", 1,
552 i, &args);
553 if (ret)
554 break;
555
556 ret = component_master_add_child(m, compare_parent_of, &args);
557 of_node_put(args.np);
558
559 if (ret)
560 return ret;
561 }
562
563 for (i = 0; ; i++) {
564 struct device_node *node;
565
566 node = of_parse_phandle(np, "connectors", i);
567 if (!node)
568 break;
569
570 ret = component_master_add_child(m, compare_of, node);
571 of_node_put(node);
572
573 if (ret)
574 return ret;
575 }
576 return 0;
577}
578
579static int imx_drm_bind(struct device *dev)
580{
581 return drm_platform_init(&imx_drm_driver, to_platform_device(dev));
582}
583
584static void imx_drm_unbind(struct device *dev)
585{
586 drm_put_dev(dev_get_drvdata(dev));
587}
588
589static const struct component_master_ops imx_drm_ops = {
590 .add_components = imx_drm_add_components,
591 .bind = imx_drm_bind,
592 .unbind = imx_drm_unbind,
593};
594
e692da4d
SH
595static int imx_drm_platform_probe(struct platform_device *pdev)
596{
4cdbb4ff
RK
597 int ret;
598
599 ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
600 if (ret)
601 return ret;
602
17b5001b 603 return component_master_add(&pdev->dev, &imx_drm_ops);
e692da4d
SH
604}
605
606static int imx_drm_platform_remove(struct platform_device *pdev)
607{
17b5001b 608 component_master_del(&pdev->dev, &imx_drm_ops);
e692da4d
SH
609 return 0;
610}
611
17b5001b
RK
612static const struct of_device_id imx_drm_dt_ids[] = {
613 { .compatible = "fsl,imx-drm", },
614 { /* sentinel */ },
615};
616MODULE_DEVICE_TABLE(of, imx_drm_dt_ids);
617
e692da4d
SH
618static struct platform_driver imx_drm_pdrv = {
619 .probe = imx_drm_platform_probe,
99c28f10 620 .remove = imx_drm_platform_remove,
e692da4d
SH
621 .driver = {
622 .owner = THIS_MODULE,
623 .name = "imx-drm",
17b5001b 624 .of_match_table = imx_drm_dt_ids,
e692da4d
SH
625 },
626};
b85f2b5d 627module_platform_driver(imx_drm_pdrv);
e692da4d
SH
628
629MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
630MODULE_DESCRIPTION("i.MX drm driver core");
631MODULE_LICENSE("GPL");