aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/imx/imx-drm-core.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-12-15 18:52:01 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-12-15 18:52:01 -0500
commit988adfdffdd43cfd841df734664727993076d7cb (patch)
tree6794f7bba8f595500c2b7d33376ad6614adcfaf2 /drivers/gpu/drm/imx/imx-drm-core.c
parent26178ec11ef3c6c814bf16a0a2b9c2f7242e3c64 (diff)
parent4e0cd68115620bc3236ff4e58e4c073948629b41 (diff)
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie: "Highlights: - AMD KFD driver merge This is the AMD HSA interface for exposing a lowlevel interface for GPGPU use. They have an open source userspace built on top of this interface, and the code looks as good as it was going to get out of tree. - Initial atomic modesetting work The need for an atomic modesetting interface to allow userspace to try and send a complete set of modesetting state to the driver has arisen, and been suffering from neglect this past year. No more, the start of the common code and changes for msm driver to use it are in this tree. Ongoing work to get the userspace ioctl finished and the code clean will probably wait until next kernel. - DisplayID 1.3 and tiled monitor exposed to userspace. Tiled monitor property is now exposed for userspace to make use of. - Rockchip drm driver merged. - imx gpu driver moved out of staging Other stuff: - core: panel - MIPI DSI + new panels. expose suggested x/y properties for virtual GPUs - i915: Initial Skylake (SKL) support gen3/4 reset work start of dri1/ums removal infoframe tracking fixes for lots of things. - nouveau: tegra k1 voltage support GM204 modesetting support GT21x memory reclocking work - radeon: CI dpm fixes GPUVM improvements Initial DPM fan control - rcar-du: HDMI support added removed some support for old boards slave encoder driver for Analog Devices adv7511 - exynos: Exynos4415 SoC support - msm: a4xx gpu support atomic helper conversion - tegra: iommu support universal plane support ganged-mode DSI support - sti: HDMI i2c improvements - vmwgfx: some late fixes. - qxl: use suggested x/y properties" * 'drm-next' of git://people.freedesktop.org/~airlied/linux: (969 commits) drm: sti: fix module compilation issue drm/i915: save/restore GMBUS freq across suspend/resume on gen4 drm: sti: correctly cleanup CRTC and planes drm: sti: add HQVDP plane drm: sti: add cursor plane drm: sti: enable auxiliary CRTC drm: sti: fix delay in VTG programming drm: sti: prepare sti_tvout to support auxiliary crtc drm: sti: use drm_crtc_vblank_{on/off} instead of drm_vblank_{on/off} drm: sti: fix hdmi avi infoframe drm: sti: remove event lock while disabling vblank drm: sti: simplify gdp code drm: sti: clear all mixer control drm: sti: remove gpio for HDMI hot plug detection drm: sti: allow to change hdmi ddc i2c adapter drm/doc: Document drm_add_modes_noedid() usage drm/i915: Remove '& 0xffff' from the mask given to WA_REG() drm/i915: Invert the mask and val arguments in wa_add() and WA_REG() drm: Zero out DRM object memory upon cleanup drm/i915/bdw: Fix the write setting up the WIZ hashing mode ...
Diffstat (limited to 'drivers/gpu/drm/imx/imx-drm-core.c')
-rw-r--r--drivers/gpu/drm/imx/imx-drm-core.c704
1 files changed, 704 insertions, 0 deletions
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
new file mode 100644
index 000000000000..e48b2211d2d6
--- /dev/null
+++ b/drivers/gpu/drm/imx/imx-drm-core.c
@@ -0,0 +1,704 @@
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 */
16#include <linux/component.h>
17#include <linux/device.h>
18#include <linux/fb.h>
19#include <linux/module.h>
20#include <linux/of_graph.h>
21#include <linux/platform_device.h>
22#include <drm/drmP.h>
23#include <drm/drm_fb_helper.h>
24#include <drm/drm_crtc_helper.h>
25#include <drm/drm_gem_cma_helper.h>
26#include <drm/drm_fb_cma_helper.h>
27#include <drm/drm_plane_helper.h>
28
29#include "imx-drm.h"
30
31#define MAX_CRTC 4
32
33struct imx_drm_crtc;
34
35struct imx_drm_component {
36 struct device_node *of_node;
37 struct list_head list;
38};
39
40struct imx_drm_device {
41 struct drm_device *drm;
42 struct imx_drm_crtc *crtc[MAX_CRTC];
43 int pipes;
44 struct drm_fbdev_cma *fbhelper;
45};
46
47struct imx_drm_crtc {
48 struct drm_crtc *crtc;
49 int pipe;
50 struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs;
51 struct device_node *port;
52};
53
54static int legacyfb_depth = 16;
55module_param(legacyfb_depth, int, 0444);
56
57int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
58{
59 return crtc->pipe;
60}
61EXPORT_SYMBOL_GPL(imx_drm_crtc_id);
62
63static void imx_drm_driver_lastclose(struct drm_device *drm)
64{
65#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
66 struct imx_drm_device *imxdrm = drm->dev_private;
67
68 if (imxdrm->fbhelper)
69 drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
70#endif
71}
72
73static int imx_drm_driver_unload(struct drm_device *drm)
74{
75#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
76 struct imx_drm_device *imxdrm = drm->dev_private;
77#endif
78
79 drm_kms_helper_poll_fini(drm);
80
81#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
82 if (imxdrm->fbhelper)
83 drm_fbdev_cma_fini(imxdrm->fbhelper);
84#endif
85
86 component_unbind_all(drm->dev, drm);
87
88 drm_vblank_cleanup(drm);
89 drm_mode_config_cleanup(drm);
90
91 platform_set_drvdata(drm->platformdev, NULL);
92
93 return 0;
94}
95
96static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
97{
98 struct imx_drm_device *imxdrm = crtc->dev->dev_private;
99 unsigned i;
100
101 for (i = 0; i < MAX_CRTC; i++)
102 if (imxdrm->crtc[i] && imxdrm->crtc[i]->crtc == crtc)
103 return imxdrm->crtc[i];
104
105 return NULL;
106}
107
108int imx_drm_panel_format_pins(struct drm_encoder *encoder,
109 u32 interface_pix_fmt, int hsync_pin, int vsync_pin)
110{
111 struct imx_drm_crtc_helper_funcs *helper;
112 struct imx_drm_crtc *imx_crtc;
113
114 imx_crtc = imx_drm_find_crtc(encoder->crtc);
115 if (!imx_crtc)
116 return -EINVAL;
117
118 helper = &imx_crtc->imx_drm_helper_funcs;
119 if (helper->set_interface_pix_fmt)
120 return helper->set_interface_pix_fmt(encoder->crtc,
121 encoder->encoder_type, interface_pix_fmt,
122 hsync_pin, vsync_pin);
123 return 0;
124}
125EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins);
126
127int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt)
128{
129 return imx_drm_panel_format_pins(encoder, interface_pix_fmt, 2, 3);
130}
131EXPORT_SYMBOL_GPL(imx_drm_panel_format);
132
133int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
134{
135 return drm_vblank_get(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
136}
137EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get);
138
139void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc)
140{
141 drm_vblank_put(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
142}
143EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put);
144
145void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc)
146{
147 drm_handle_vblank(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
148}
149EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
150
151static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
152{
153 struct imx_drm_device *imxdrm = drm->dev_private;
154 struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
155 int ret;
156
157 if (!imx_drm_crtc)
158 return -EINVAL;
159
160 if (!imx_drm_crtc->imx_drm_helper_funcs.enable_vblank)
161 return -ENOSYS;
162
163 ret = imx_drm_crtc->imx_drm_helper_funcs.enable_vblank(
164 imx_drm_crtc->crtc);
165
166 return ret;
167}
168
169static void imx_drm_disable_vblank(struct drm_device *drm, int crtc)
170{
171 struct imx_drm_device *imxdrm = drm->dev_private;
172 struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
173
174 if (!imx_drm_crtc)
175 return;
176
177 if (!imx_drm_crtc->imx_drm_helper_funcs.disable_vblank)
178 return;
179
180 imx_drm_crtc->imx_drm_helper_funcs.disable_vblank(imx_drm_crtc->crtc);
181}
182
183static void imx_drm_driver_preclose(struct drm_device *drm,
184 struct drm_file *file)
185{
186 int i;
187
188 if (!file->is_master)
189 return;
190
191 for (i = 0; i < MAX_CRTC; i++)
192 imx_drm_disable_vblank(drm, i);
193}
194
195static const struct file_operations imx_drm_driver_fops = {
196 .owner = THIS_MODULE,
197 .open = drm_open,
198 .release = drm_release,
199 .unlocked_ioctl = drm_ioctl,
200 .mmap = drm_gem_cma_mmap,
201 .poll = drm_poll,
202 .read = drm_read,
203 .llseek = noop_llseek,
204};
205
206void imx_drm_connector_destroy(struct drm_connector *connector)
207{
208 drm_connector_unregister(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
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
228static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
229 .fb_create = drm_fb_cma_create,
230 .output_poll_changed = imx_drm_output_poll_changed,
231};
232
233/*
234 * Main DRM initialisation. This binds, initialises and registers
235 * with DRM the subcomponents of the driver.
236 */
237static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
238{
239 struct imx_drm_device *imxdrm;
240 struct drm_connector *connector;
241 int ret;
242
243 imxdrm = devm_kzalloc(drm->dev, sizeof(*imxdrm), GFP_KERNEL);
244 if (!imxdrm)
245 return -ENOMEM;
246
247 imxdrm->drm = drm;
248
249 drm->dev_private = imxdrm;
250
251 /*
252 * enable drm irq mode.
253 * - with irq_enabled = true, we can use the vblank feature.
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 */
260 drm->irq_enabled = true;
261
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
273 drm_mode_config_init(drm);
274
275 ret = drm_vblank_init(drm, MAX_CRTC);
276 if (ret)
277 goto err_kms;
278
279 /*
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)
283 */
284 drm->vblank_disable_allowed = true;
285
286 platform_set_drvdata(drm->platformdev, drm);
287
288 /* Now try and bind all our sub-components */
289 ret = component_bind_all(drm->dev, drm);
290 if (ret)
291 goto err_vblank;
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_connector_register(connector);
300 if (ret) {
301 dev_err(drm->dev,
302 "[CONNECTOR:%d:%s] drm_connector_register failed: %d\n",
303 connector->base.id,
304 connector->name, ret);
305 goto err_unbind;
306 }
307 }
308
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
327
328 drm_kms_helper_poll_init(drm);
329
330 return 0;
331
332err_unbind:
333 component_unbind_all(drm->dev, drm);
334err_vblank:
335 drm_vblank_cleanup(drm);
336err_kms:
337 drm_mode_config_cleanup(drm);
338
339 return ret;
340}
341
342/*
343 * imx_drm_add_crtc - add a new crtc
344 */
345int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
346 struct imx_drm_crtc **new_crtc,
347 const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
348 struct device_node *port)
349{
350 struct imx_drm_device *imxdrm = drm->dev_private;
351 struct imx_drm_crtc *imx_drm_crtc;
352 int ret;
353
354 /*
355 * The vblank arrays are dimensioned by MAX_CRTC - we can't
356 * pass IDs greater than this to those functions.
357 */
358 if (imxdrm->pipes >= MAX_CRTC)
359 return -EINVAL;
360
361 if (imxdrm->drm->open_count)
362 return -EBUSY;
363
364 imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL);
365 if (!imx_drm_crtc)
366 return -ENOMEM;
367
368 imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
369 imx_drm_crtc->pipe = imxdrm->pipes++;
370 imx_drm_crtc->port = port;
371 imx_drm_crtc->crtc = crtc;
372
373 imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
374
375 *new_crtc = imx_drm_crtc;
376
377 ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256);
378 if (ret)
379 goto err_register;
380
381 drm_crtc_helper_add(crtc,
382 imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
383
384 drm_crtc_init(drm, crtc,
385 imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
386
387 return 0;
388
389err_register:
390 imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
391 kfree(imx_drm_crtc);
392 return ret;
393}
394EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
395
396/*
397 * imx_drm_remove_crtc - remove a crtc
398 */
399int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
400{
401 struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private;
402
403 drm_crtc_cleanup(imx_drm_crtc->crtc);
404
405 imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
406
407 kfree(imx_drm_crtc);
408
409 return 0;
410}
411EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
412
413/*
414 * Find the DRM CRTC possible mask for the connected endpoint.
415 *
416 * The encoder possible masks are defined by their position in the
417 * mode_config crtc_list. This means that CRTCs must not be added
418 * or removed once the DRM device has been fully initialised.
419 */
420static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
421 struct device_node *endpoint)
422{
423 struct device_node *port;
424 unsigned i;
425
426 port = of_graph_get_remote_port(endpoint);
427 if (!port)
428 return 0;
429 of_node_put(port);
430
431 for (i = 0; i < MAX_CRTC; i++) {
432 struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
433
434 if (imx_drm_crtc && imx_drm_crtc->port == port)
435 return drm_crtc_mask(imx_drm_crtc->crtc);
436 }
437
438 return 0;
439}
440
441static struct device_node *imx_drm_of_get_next_endpoint(
442 const struct device_node *parent, struct device_node *prev)
443{
444 struct device_node *node = of_graph_get_next_endpoint(parent, prev);
445
446 of_node_put(prev);
447 return node;
448}
449
450int imx_drm_encoder_parse_of(struct drm_device *drm,
451 struct drm_encoder *encoder, struct device_node *np)
452{
453 struct imx_drm_device *imxdrm = drm->dev_private;
454 struct device_node *ep = NULL;
455 uint32_t crtc_mask = 0;
456 int i;
457
458 for (i = 0; ; i++) {
459 u32 mask;
460
461 ep = imx_drm_of_get_next_endpoint(np, ep);
462 if (!ep)
463 break;
464
465 mask = imx_drm_find_crtc_mask(imxdrm, ep);
466
467 /*
468 * If we failed to find the CRTC(s) which this encoder is
469 * supposed to be connected to, it's because the CRTC has
470 * not been registered yet. Defer probing, and hope that
471 * the required CRTC is added later.
472 */
473 if (mask == 0)
474 return -EPROBE_DEFER;
475
476 crtc_mask |= mask;
477 }
478
479 of_node_put(ep);
480 if (i == 0)
481 return -ENOENT;
482
483 encoder->possible_crtcs = crtc_mask;
484
485 /* FIXME: this is the mask of outputs which can clone this output. */
486 encoder->possible_clones = ~0;
487
488 return 0;
489}
490EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
491
492/*
493 * @node: device tree node containing encoder input ports
494 * @encoder: drm_encoder
495 */
496int imx_drm_encoder_get_mux_id(struct device_node *node,
497 struct drm_encoder *encoder)
498{
499 struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc);
500 struct device_node *ep = NULL;
501 struct of_endpoint endpoint;
502 struct device_node *port;
503 int ret;
504
505 if (!node || !imx_crtc)
506 return -EINVAL;
507
508 do {
509 ep = imx_drm_of_get_next_endpoint(node, ep);
510 if (!ep)
511 break;
512
513 port = of_graph_get_remote_port(ep);
514 of_node_put(port);
515 if (port == imx_crtc->port) {
516 ret = of_graph_parse_endpoint(ep, &endpoint);
517 return ret ? ret : endpoint.port;
518 }
519 } while (ep);
520
521 return -EINVAL;
522}
523EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
524
525static const struct drm_ioctl_desc imx_drm_ioctls[] = {
526 /* none so far */
527};
528
529static struct drm_driver imx_drm_driver = {
530 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
531 .load = imx_drm_driver_load,
532 .unload = imx_drm_driver_unload,
533 .lastclose = imx_drm_driver_lastclose,
534 .preclose = imx_drm_driver_preclose,
535 .set_busid = drm_platform_set_busid,
536 .gem_free_object = drm_gem_cma_free_object,
537 .gem_vm_ops = &drm_gem_cma_vm_ops,
538 .dumb_create = drm_gem_cma_dumb_create,
539 .dumb_map_offset = drm_gem_cma_dumb_map_offset,
540 .dumb_destroy = drm_gem_dumb_destroy,
541
542 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
543 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
544 .gem_prime_import = drm_gem_prime_import,
545 .gem_prime_export = drm_gem_prime_export,
546 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
547 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
548 .gem_prime_vmap = drm_gem_cma_prime_vmap,
549 .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
550 .gem_prime_mmap = drm_gem_cma_prime_mmap,
551 .get_vblank_counter = drm_vblank_count,
552 .enable_vblank = imx_drm_enable_vblank,
553 .disable_vblank = imx_drm_disable_vblank,
554 .ioctls = imx_drm_ioctls,
555 .num_ioctls = ARRAY_SIZE(imx_drm_ioctls),
556 .fops = &imx_drm_driver_fops,
557 .name = "imx-drm",
558 .desc = "i.MX DRM graphics",
559 .date = "20120507",
560 .major = 1,
561 .minor = 0,
562 .patchlevel = 0,
563};
564
565static int compare_of(struct device *dev, void *data)
566{
567 struct device_node *np = data;
568
569 /* Special case for LDB, one device for two channels */
570 if (of_node_cmp(np->name, "lvds-channel") == 0) {
571 np = of_get_parent(np);
572 of_node_put(np);
573 }
574
575 return dev->of_node == np;
576}
577
578static int imx_drm_bind(struct device *dev)
579{
580 return drm_platform_init(&imx_drm_driver, to_platform_device(dev));
581}
582
583static void imx_drm_unbind(struct device *dev)
584{
585 drm_put_dev(dev_get_drvdata(dev));
586}
587
588static const struct component_master_ops imx_drm_ops = {
589 .bind = imx_drm_bind,
590 .unbind = imx_drm_unbind,
591};
592
593static int imx_drm_platform_probe(struct platform_device *pdev)
594{
595 struct device_node *ep, *port, *remote;
596 struct component_match *match = NULL;
597 int ret;
598 int i;
599
600 /*
601 * Bind the IPU display interface ports first, so that
602 * imx_drm_encoder_parse_of called from encoder .bind callbacks
603 * works as expected.
604 */
605 for (i = 0; ; i++) {
606 port = of_parse_phandle(pdev->dev.of_node, "ports", i);
607 if (!port)
608 break;
609
610 component_match_add(&pdev->dev, &match, compare_of, port);
611 }
612
613 if (i == 0) {
614 dev_err(&pdev->dev, "missing 'ports' property\n");
615 return -ENODEV;
616 }
617
618 /* Then bind all encoders */
619 for (i = 0; ; i++) {
620 port = of_parse_phandle(pdev->dev.of_node, "ports", i);
621 if (!port)
622 break;
623
624 for_each_child_of_node(port, ep) {
625 remote = of_graph_get_remote_port_parent(ep);
626 if (!remote || !of_device_is_available(remote)) {
627 of_node_put(remote);
628 continue;
629 } else if (!of_device_is_available(remote->parent)) {
630 dev_warn(&pdev->dev, "parent device of %s is not available\n",
631 remote->full_name);
632 of_node_put(remote);
633 continue;
634 }
635
636 component_match_add(&pdev->dev, &match, compare_of, remote);
637 of_node_put(remote);
638 }
639 of_node_put(port);
640 }
641
642 ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
643 if (ret)
644 return ret;
645
646 return component_master_add_with_match(&pdev->dev, &imx_drm_ops, match);
647}
648
649static int imx_drm_platform_remove(struct platform_device *pdev)
650{
651 component_master_del(&pdev->dev, &imx_drm_ops);
652 return 0;
653}
654
655#ifdef CONFIG_PM_SLEEP
656static int imx_drm_suspend(struct device *dev)
657{
658 struct drm_device *drm_dev = dev_get_drvdata(dev);
659
660 /* The drm_dev is NULL before .load hook is called */
661 if (drm_dev == NULL)
662 return 0;
663
664 drm_kms_helper_poll_disable(drm_dev);
665
666 return 0;
667}
668
669static int imx_drm_resume(struct device *dev)
670{
671 struct drm_device *drm_dev = dev_get_drvdata(dev);
672
673 if (drm_dev == NULL)
674 return 0;
675
676 drm_helper_resume_force_mode(drm_dev);
677 drm_kms_helper_poll_enable(drm_dev);
678
679 return 0;
680}
681#endif
682
683static SIMPLE_DEV_PM_OPS(imx_drm_pm_ops, imx_drm_suspend, imx_drm_resume);
684
685static const struct of_device_id imx_drm_dt_ids[] = {
686 { .compatible = "fsl,imx-display-subsystem", },
687 { /* sentinel */ },
688};
689MODULE_DEVICE_TABLE(of, imx_drm_dt_ids);
690
691static struct platform_driver imx_drm_pdrv = {
692 .probe = imx_drm_platform_probe,
693 .remove = imx_drm_platform_remove,
694 .driver = {
695 .name = "imx-drm",
696 .pm = &imx_drm_pm_ops,
697 .of_match_table = imx_drm_dt_ids,
698 },
699};
700module_platform_driver(imx_drm_pdrv);
701
702MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
703MODULE_DESCRIPTION("i.MX drm driver core");
704MODULE_LICENSE("GPL");