imx-drm: provide common connector mode validation function
[deliverable/linux.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 */
16
17#include <linux/device.h>
18#include <linux/platform_device.h>
19#include <drm/drmP.h>
20#include <drm/drm_fb_helper.h>
21#include <drm/drm_crtc_helper.h>
22#include <linux/fb.h>
23#include <linux/module.h>
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
31struct crtc_cookie {
32 void *cookie;
33 int id;
34 struct list_head list;
35};
36
887eceac
RK
37struct imx_drm_crtc;
38
e692da4d
SH
39struct imx_drm_device {
40 struct drm_device *drm;
41 struct device *dev;
887eceac 42 struct imx_drm_crtc *crtc[MAX_CRTC];
e692da4d
SH
43 struct list_head encoder_list;
44 struct list_head connector_list;
45 struct mutex mutex;
e692da4d
SH
46 int pipes;
47 struct drm_fbdev_cma *fbhelper;
48};
49
50struct imx_drm_crtc {
51 struct drm_crtc *crtc;
e692da4d
SH
52 struct imx_drm_device *imxdrm;
53 int pipe;
54 struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs;
55 struct module *owner;
56 struct crtc_cookie cookie;
e76171b0 57 int mux_id;
e692da4d
SH
58};
59
60struct imx_drm_encoder {
61 struct drm_encoder *encoder;
62 struct list_head list;
63 struct module *owner;
64 struct list_head possible_crtcs;
65};
66
67struct imx_drm_connector {
68 struct drm_connector *connector;
69 struct list_head list;
70 struct module *owner;
71};
72
887eceac
RK
73static struct imx_drm_device *__imx_drm_device(void);
74
b8d181e4
PZ
75int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
76{
77 return crtc->pipe;
78}
9c74360f 79EXPORT_SYMBOL_GPL(imx_drm_crtc_id);
b8d181e4 80
e692da4d
SH
81static void imx_drm_driver_lastclose(struct drm_device *drm)
82{
83 struct imx_drm_device *imxdrm = drm->dev_private;
84
85 if (imxdrm->fbhelper)
86 drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
e692da4d
SH
87}
88
89static int imx_drm_driver_unload(struct drm_device *drm)
90{
91 struct imx_drm_device *imxdrm = drm->dev_private;
92
aaba4b58
DV
93 imx_drm_device_put();
94
020a9ea7
RK
95 drm_vblank_cleanup(drm);
96 drm_kms_helper_poll_fini(drm);
97 drm_mode_config_cleanup(drm);
e692da4d
SH
98
99 return 0;
100}
101
887eceac 102struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
e692da4d 103{
887eceac
RK
104 struct imx_drm_device *imxdrm = __imx_drm_device();
105 unsigned i;
106
107 for (i = 0; i < MAX_CRTC; i++)
108 if (imxdrm->crtc[i] && imxdrm->crtc[i]->crtc == crtc)
109 return imxdrm->crtc[i];
e692da4d 110
e692da4d
SH
111 return NULL;
112}
113
2ea42608
PZ
114int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type,
115 u32 interface_pix_fmt, int hsync_pin, int vsync_pin)
e692da4d 116{
e692da4d 117 struct imx_drm_crtc_helper_funcs *helper;
887eceac 118 struct imx_drm_crtc *imx_crtc;
e692da4d 119
887eceac
RK
120 imx_crtc = imx_drm_find_crtc(crtc);
121 if (!imx_crtc)
122 return -EINVAL;
e692da4d 123
e692da4d
SH
124 helper = &imx_crtc->imx_drm_helper_funcs;
125 if (helper->set_interface_pix_fmt)
126 return helper->set_interface_pix_fmt(crtc,
2ea42608
PZ
127 encoder_type, interface_pix_fmt,
128 hsync_pin, vsync_pin);
e692da4d
SH
129 return 0;
130}
2ea42608
PZ
131EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format_pins);
132
133int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
134 u32 interface_pix_fmt)
135{
136 return imx_drm_crtc_panel_format_pins(crtc, encoder_type,
079461bf 137 interface_pix_fmt, 2, 3);
2ea42608 138}
aecfbdb1 139EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format);
e692da4d
SH
140
141int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
142{
b5ea1492 143 return drm_vblank_get(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
e692da4d
SH
144}
145EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get);
146
147void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc)
148{
b5ea1492 149 drm_vblank_put(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
e692da4d
SH
150}
151EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put);
152
153void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc)
154{
b5ea1492 155 drm_handle_vblank(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
e692da4d
SH
156}
157EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
158
159static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
160{
161 struct imx_drm_device *imxdrm = drm->dev_private;
887eceac 162 struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
e692da4d
SH
163 int ret;
164
e692da4d
SH
165 if (!imx_drm_crtc)
166 return -EINVAL;
167
168 if (!imx_drm_crtc->imx_drm_helper_funcs.enable_vblank)
169 return -ENOSYS;
170
171 ret = imx_drm_crtc->imx_drm_helper_funcs.enable_vblank(
172 imx_drm_crtc->crtc);
173
174 return ret;
175}
176
177static void imx_drm_disable_vblank(struct drm_device *drm, int crtc)
178{
179 struct imx_drm_device *imxdrm = drm->dev_private;
887eceac 180 struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
e692da4d 181
e692da4d
SH
182 if (!imx_drm_crtc)
183 return;
184
185 if (!imx_drm_crtc->imx_drm_helper_funcs.disable_vblank)
186 return;
187
188 imx_drm_crtc->imx_drm_helper_funcs.disable_vblank(imx_drm_crtc->crtc);
189}
190
6ee4d7fe
SH
191static void imx_drm_driver_preclose(struct drm_device *drm,
192 struct drm_file *file)
193{
194 int i;
195
196 if (!file->is_master)
197 return;
198
942325c8
RK
199 for (i = 0; i < MAX_CRTC; i++)
200 imx_drm_disable_vblank(drm, i);
6ee4d7fe
SH
201}
202
e692da4d
SH
203static const struct file_operations imx_drm_driver_fops = {
204 .owner = THIS_MODULE,
205 .open = drm_open,
206 .release = drm_release,
207 .unlocked_ioctl = drm_ioctl,
208 .mmap = drm_gem_cma_mmap,
209 .poll = drm_poll,
e692da4d
SH
210 .read = drm_read,
211 .llseek = noop_llseek,
212};
213
baa68c4b
RK
214int imx_drm_connector_mode_valid(struct drm_connector *connector,
215 struct drm_display_mode *mode)
216{
217 return MODE_OK;
218}
219EXPORT_SYMBOL(imx_drm_connector_mode_valid);
220
e692da4d
SH
221static struct imx_drm_device *imx_drm_device;
222
223static struct imx_drm_device *__imx_drm_device(void)
224{
225 return imx_drm_device;
226}
227
228struct drm_device *imx_drm_device_get(void)
229{
230 struct imx_drm_device *imxdrm = __imx_drm_device();
231 struct imx_drm_encoder *enc;
232 struct imx_drm_connector *con;
233 struct imx_drm_crtc *crtc;
234
e692da4d
SH
235 list_for_each_entry(enc, &imxdrm->encoder_list, list) {
236 if (!try_module_get(enc->owner)) {
237 dev_err(imxdrm->dev, "could not get module %s\n",
238 module_name(enc->owner));
239 goto unwind_enc;
240 }
241 }
242
243 list_for_each_entry(con, &imxdrm->connector_list, list) {
244 if (!try_module_get(con->owner)) {
245 dev_err(imxdrm->dev, "could not get module %s\n",
246 module_name(con->owner));
247 goto unwind_con;
248 }
249 }
250
251 list_for_each_entry(crtc, &imxdrm->crtc_list, list) {
252 if (!try_module_get(crtc->owner)) {
253 dev_err(imxdrm->dev, "could not get module %s\n",
254 module_name(crtc->owner));
255 goto unwind_crtc;
256 }
257 }
258
e692da4d
SH
259 return imxdrm->drm;
260
261unwind_crtc:
262 list_for_each_entry_continue_reverse(crtc, &imxdrm->crtc_list, list)
263 module_put(crtc->owner);
264unwind_con:
265 list_for_each_entry_continue_reverse(con, &imxdrm->connector_list, list)
266 module_put(con->owner);
267unwind_enc:
268 list_for_each_entry_continue_reverse(enc, &imxdrm->encoder_list, list)
269 module_put(enc->owner);
270
271 mutex_unlock(&imxdrm->mutex);
272
273 return NULL;
274
275}
276EXPORT_SYMBOL_GPL(imx_drm_device_get);
277
278void imx_drm_device_put(void)
279{
280 struct imx_drm_device *imxdrm = __imx_drm_device();
281 struct imx_drm_encoder *enc;
282 struct imx_drm_connector *con;
283 struct imx_drm_crtc *crtc;
284
285 mutex_lock(&imxdrm->mutex);
286
287 list_for_each_entry(crtc, &imxdrm->crtc_list, list)
288 module_put(crtc->owner);
289
290 list_for_each_entry(con, &imxdrm->connector_list, list)
291 module_put(con->owner);
292
293 list_for_each_entry(enc, &imxdrm->encoder_list, list)
294 module_put(enc->owner);
295
e692da4d
SH
296 mutex_unlock(&imxdrm->mutex);
297}
298EXPORT_SYMBOL_GPL(imx_drm_device_put);
299
300static int drm_mode_group_reinit(struct drm_device *dev)
301{
302 struct drm_mode_group *group = &dev->primary->mode_group;
303 uint32_t *id_list = group->id_list;
304 int ret;
305
306 ret = drm_mode_group_init_legacy_group(dev, group);
307 if (ret < 0)
308 return ret;
309
310 kfree(id_list);
311 return 0;
312}
313
314/*
315 * register an encoder to the drm core
316 */
317static int imx_drm_encoder_register(struct imx_drm_encoder *imx_drm_encoder)
318{
319 struct imx_drm_device *imxdrm = __imx_drm_device();
320
321 INIT_LIST_HEAD(&imx_drm_encoder->possible_crtcs);
322
323 drm_encoder_init(imxdrm->drm, imx_drm_encoder->encoder,
324 imx_drm_encoder->encoder->funcs,
325 imx_drm_encoder->encoder->encoder_type);
326
327 drm_mode_group_reinit(imxdrm->drm);
328
329 return 0;
330}
331
332/*
333 * unregister an encoder from the drm core
334 */
335static void imx_drm_encoder_unregister(struct imx_drm_encoder
336 *imx_drm_encoder)
337{
338 struct imx_drm_device *imxdrm = __imx_drm_device();
339
340 drm_encoder_cleanup(imx_drm_encoder->encoder);
341
342 drm_mode_group_reinit(imxdrm->drm);
343}
344
345/*
346 * register a connector to the drm core
347 */
348static int imx_drm_connector_register(
349 struct imx_drm_connector *imx_drm_connector)
350{
351 struct imx_drm_device *imxdrm = __imx_drm_device();
352
353 drm_connector_init(imxdrm->drm, imx_drm_connector->connector,
354 imx_drm_connector->connector->funcs,
355 imx_drm_connector->connector->connector_type);
356 drm_mode_group_reinit(imxdrm->drm);
357
358 return drm_sysfs_connector_add(imx_drm_connector->connector);
359}
360
361/*
362 * unregister a connector from the drm core
363 */
364static void imx_drm_connector_unregister(
365 struct imx_drm_connector *imx_drm_connector)
366{
367 struct imx_drm_device *imxdrm = __imx_drm_device();
368
369 drm_sysfs_connector_remove(imx_drm_connector->connector);
370 drm_connector_cleanup(imx_drm_connector->connector);
371
372 drm_mode_group_reinit(imxdrm->drm);
373}
374
e692da4d
SH
375/*
376 * Called by the CRTC driver when all CRTCs are registered. This
377 * puts all the pieces together and initializes the driver.
378 * Once this is called no more CRTCs can be registered since
379 * the drm core has hardcoded the number of crtcs in several
380 * places.
381 */
382static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
383{
384 struct imx_drm_device *imxdrm = __imx_drm_device();
385 int ret;
386
387 imxdrm->drm = drm;
388
389 drm->dev_private = imxdrm;
390
391 /*
392 * enable drm irq mode.
4423843c 393 * - with irq_enabled = true, we can use the vblank feature.
e692da4d
SH
394 *
395 * P.S. note that we wouldn't use drm irq handler but
396 * just specific driver own one instead because
397 * drm framework supports only one irq handler and
398 * drivers can well take care of their interrupts
399 */
4423843c 400 drm->irq_enabled = true;
e692da4d
SH
401
402 drm_mode_config_init(drm);
403 imx_drm_mode_config_init(drm);
404
405 mutex_lock(&imxdrm->mutex);
406
020a9ea7 407 drm_kms_helper_poll_init(drm);
e692da4d
SH
408
409 /* setup the grouping for the legacy output */
020a9ea7
RK
410 ret = drm_mode_group_init_legacy_group(drm,
411 &drm->primary->mode_group);
e692da4d 412 if (ret)
8007875f 413 goto err_kms;
e692da4d 414
020a9ea7 415 ret = drm_vblank_init(drm, MAX_CRTC);
e692da4d 416 if (ret)
8007875f 417 goto err_kms;
e692da4d
SH
418
419 /*
ba0bf120 420 * with vblank_disable_allowed = true, vblank interrupt will be disabled
e692da4d
SH
421 * by drm timer once a current process gives up ownership of
422 * vblank event.(after drm_vblank_put function is called)
423 */
020a9ea7 424 drm->vblank_disable_allowed = true;
e692da4d 425
8007875f 426 if (!imx_drm_device_get()) {
aaba4b58 427 ret = -EINVAL;
8007875f
RK
428 goto err_vblank;
429 }
aaba4b58 430
a72f8bee 431 platform_set_drvdata(drm->platformdev, drm);
8007875f
RK
432 mutex_unlock(&imxdrm->mutex);
433 return 0;
a72f8bee 434
8007875f
RK
435err_vblank:
436 drm_vblank_cleanup(drm);
437err_kms:
438 drm_kms_helper_poll_fini(drm);
439 drm_mode_config_cleanup(drm);
e692da4d
SH
440 mutex_unlock(&imxdrm->mutex);
441
442 return ret;
443}
444
445static void imx_drm_update_possible_crtcs(void)
446{
447 struct imx_drm_device *imxdrm = __imx_drm_device();
448 struct imx_drm_crtc *imx_drm_crtc;
449 struct imx_drm_encoder *enc;
450 struct crtc_cookie *cookie;
451
452 list_for_each_entry(enc, &imxdrm->encoder_list, list) {
453 u32 possible_crtcs = 0;
454
455 list_for_each_entry(cookie, &enc->possible_crtcs, list) {
456 list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list) {
457 if (imx_drm_crtc->cookie.cookie == cookie->cookie &&
458 imx_drm_crtc->cookie.id == cookie->id) {
459 possible_crtcs |= 1 << imx_drm_crtc->pipe;
460 }
461 }
462 }
463 enc->encoder->possible_crtcs = possible_crtcs;
464 enc->encoder->possible_clones = possible_crtcs;
465 }
466}
467
468/*
469 * imx_drm_add_crtc - add a new crtc
470 *
471 * The return value if !NULL is a cookie for the caller to pass to
472 * imx_drm_remove_crtc later.
473 */
474int imx_drm_add_crtc(struct drm_crtc *crtc,
475 struct imx_drm_crtc **new_crtc,
476 const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
477 struct module *owner, void *cookie, int id)
478{
479 struct imx_drm_device *imxdrm = __imx_drm_device();
480 struct imx_drm_crtc *imx_drm_crtc;
e692da4d
SH
481 int ret;
482
483 mutex_lock(&imxdrm->mutex);
484
fd6040ed
RK
485 /*
486 * The vblank arrays are dimensioned by MAX_CRTC - we can't
487 * pass IDs greater than this to those functions.
488 */
489 if (imxdrm->pipes >= MAX_CRTC) {
490 ret = -EINVAL;
491 goto err_busy;
492 }
493
099326d8 494 if (imxdrm->drm->open_count) {
e692da4d
SH
495 ret = -EBUSY;
496 goto err_busy;
497 }
498
499 imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL);
500 if (!imx_drm_crtc) {
501 ret = -ENOMEM;
502 goto err_alloc;
503 }
504
505 imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
506 imx_drm_crtc->pipe = imxdrm->pipes++;
507 imx_drm_crtc->cookie.cookie = cookie;
508 imx_drm_crtc->cookie.id = id;
e76171b0 509 imx_drm_crtc->mux_id = imx_drm_crtc->pipe;
e692da4d
SH
510 imx_drm_crtc->crtc = crtc;
511 imx_drm_crtc->imxdrm = imxdrm;
512
513 imx_drm_crtc->owner = owner;
514
887eceac 515 imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
e692da4d
SH
516
517 *new_crtc = imx_drm_crtc;
518
ec9557d7 519 ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256);
e692da4d
SH
520 if (ret)
521 goto err_register;
522
ec9557d7
RK
523 drm_crtc_helper_add(crtc,
524 imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
525
526 drm_crtc_init(imxdrm->drm, crtc,
527 imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
528
529 drm_mode_group_reinit(imxdrm->drm);
530
e692da4d
SH
531 imx_drm_update_possible_crtcs();
532
533 mutex_unlock(&imxdrm->mutex);
534
535 return 0;
536
537err_register:
887eceac 538 imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
e692da4d
SH
539 kfree(imx_drm_crtc);
540err_alloc:
541err_busy:
542 mutex_unlock(&imxdrm->mutex);
543 return ret;
544}
545EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
546
547/*
548 * imx_drm_remove_crtc - remove a crtc
549 */
550int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
551{
552 struct imx_drm_device *imxdrm = imx_drm_crtc->imxdrm;
553
554 mutex_lock(&imxdrm->mutex);
555
556 drm_crtc_cleanup(imx_drm_crtc->crtc);
557
887eceac 558 imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
e692da4d
SH
559
560 drm_mode_group_reinit(imxdrm->drm);
561
562 mutex_unlock(&imxdrm->mutex);
563
564 kfree(imx_drm_crtc);
565
566 return 0;
567}
568EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
569
570/*
571 * imx_drm_add_encoder - add a new encoder
572 */
573int imx_drm_add_encoder(struct drm_encoder *encoder,
574 struct imx_drm_encoder **newenc, struct module *owner)
575{
576 struct imx_drm_device *imxdrm = __imx_drm_device();
577 struct imx_drm_encoder *imx_drm_encoder;
578 int ret;
579
580 mutex_lock(&imxdrm->mutex);
581
099326d8 582 if (imxdrm->drm->open_count) {
e692da4d
SH
583 ret = -EBUSY;
584 goto err_busy;
585 }
586
587 imx_drm_encoder = kzalloc(sizeof(*imx_drm_encoder), GFP_KERNEL);
588 if (!imx_drm_encoder) {
589 ret = -ENOMEM;
590 goto err_alloc;
591 }
592
593 imx_drm_encoder->encoder = encoder;
594 imx_drm_encoder->owner = owner;
595
596 ret = imx_drm_encoder_register(imx_drm_encoder);
597 if (ret) {
e692da4d
SH
598 ret = -ENOMEM;
599 goto err_register;
600 }
601
602 list_add_tail(&imx_drm_encoder->list, &imxdrm->encoder_list);
603
604 *newenc = imx_drm_encoder;
605
606 mutex_unlock(&imxdrm->mutex);
607
608 return 0;
609
610err_register:
611 kfree(imx_drm_encoder);
612err_alloc:
613err_busy:
614 mutex_unlock(&imxdrm->mutex);
615
616 return ret;
617}
618EXPORT_SYMBOL_GPL(imx_drm_add_encoder);
619
620int imx_drm_encoder_add_possible_crtcs(
621 struct imx_drm_encoder *imx_drm_encoder,
622 struct device_node *np)
623{
624 struct imx_drm_device *imxdrm = __imx_drm_device();
625 struct of_phandle_args args;
626 struct crtc_cookie *c;
627 int ret = 0;
628 int i;
629
630 if (!list_empty(&imx_drm_encoder->possible_crtcs))
631 return -EBUSY;
632
633 for (i = 0; !ret; i++) {
634 ret = of_parse_phandle_with_args(np, "crtcs",
635 "#crtc-cells", i, &args);
636 if (ret < 0)
637 break;
638
639 c = kzalloc(sizeof(*c), GFP_KERNEL);
640 if (!c) {
641 of_node_put(args.np);
642 return -ENOMEM;
643 }
644
645 c->cookie = args.np;
646 c->id = args.args_count > 0 ? args.args[0] : 0;
647
648 of_node_put(args.np);
649
650 mutex_lock(&imxdrm->mutex);
651
652 list_add_tail(&c->list, &imx_drm_encoder->possible_crtcs);
653
654 mutex_unlock(&imxdrm->mutex);
655 }
656
657 imx_drm_update_possible_crtcs();
658
659 return 0;
660}
aecfbdb1 661EXPORT_SYMBOL_GPL(imx_drm_encoder_add_possible_crtcs);
e692da4d 662
e76171b0 663int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder)
e692da4d 664{
887eceac 665 struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc);
e692da4d 666
887eceac 667 return imx_crtc ? imx_crtc->mux_id : -EINVAL;
e692da4d 668}
ea8d1583 669EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
e692da4d
SH
670
671/*
672 * imx_drm_remove_encoder - remove an encoder
673 */
674int imx_drm_remove_encoder(struct imx_drm_encoder *imx_drm_encoder)
675{
676 struct imx_drm_device *imxdrm = __imx_drm_device();
677 struct crtc_cookie *c, *tmp;
678
679 mutex_lock(&imxdrm->mutex);
680
681 imx_drm_encoder_unregister(imx_drm_encoder);
682
683 list_del(&imx_drm_encoder->list);
684
685 list_for_each_entry_safe(c, tmp, &imx_drm_encoder->possible_crtcs,
686 list)
687 kfree(c);
688
689 mutex_unlock(&imxdrm->mutex);
690
691 kfree(imx_drm_encoder);
692
693 return 0;
694}
695EXPORT_SYMBOL_GPL(imx_drm_remove_encoder);
696
697/*
698 * imx_drm_add_connector - add a connector
699 */
700int imx_drm_add_connector(struct drm_connector *connector,
701 struct imx_drm_connector **new_con,
702 struct module *owner)
703{
704 struct imx_drm_device *imxdrm = __imx_drm_device();
705 struct imx_drm_connector *imx_drm_connector;
706 int ret;
707
708 mutex_lock(&imxdrm->mutex);
709
099326d8 710 if (imxdrm->drm->open_count) {
e692da4d
SH
711 ret = -EBUSY;
712 goto err_busy;
713 }
714
715 imx_drm_connector = kzalloc(sizeof(*imx_drm_connector), GFP_KERNEL);
716 if (!imx_drm_connector) {
717 ret = -ENOMEM;
718 goto err_alloc;
719 }
720
721 imx_drm_connector->connector = connector;
722 imx_drm_connector->owner = owner;
723
724 ret = imx_drm_connector_register(imx_drm_connector);
725 if (ret)
726 goto err_register;
727
728 list_add_tail(&imx_drm_connector->list, &imxdrm->connector_list);
729
730 *new_con = imx_drm_connector;
731
732 mutex_unlock(&imxdrm->mutex);
733
734 return 0;
735
736err_register:
737 kfree(imx_drm_connector);
738err_alloc:
739err_busy:
740 mutex_unlock(&imxdrm->mutex);
741
742 return ret;
743}
744EXPORT_SYMBOL_GPL(imx_drm_add_connector);
745
746void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper)
747{
748 struct imx_drm_device *imxdrm = __imx_drm_device();
749
750 imxdrm->fbhelper = fbdev_helper;
751}
752EXPORT_SYMBOL_GPL(imx_drm_fb_helper_set);
753
754/*
755 * imx_drm_remove_connector - remove a connector
756 */
757int imx_drm_remove_connector(struct imx_drm_connector *imx_drm_connector)
758{
759 struct imx_drm_device *imxdrm = __imx_drm_device();
760
761 mutex_lock(&imxdrm->mutex);
762
763 imx_drm_connector_unregister(imx_drm_connector);
764
765 list_del(&imx_drm_connector->list);
766
767 mutex_unlock(&imxdrm->mutex);
768
769 kfree(imx_drm_connector);
770
771 return 0;
772}
773EXPORT_SYMBOL_GPL(imx_drm_remove_connector);
774
baa70943 775static const struct drm_ioctl_desc imx_drm_ioctls[] = {
e692da4d
SH
776 /* none so far */
777};
778
779static struct drm_driver imx_drm_driver = {
bd3665c9 780 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
e692da4d
SH
781 .load = imx_drm_driver_load,
782 .unload = imx_drm_driver_unload,
e692da4d 783 .lastclose = imx_drm_driver_lastclose,
6ee4d7fe 784 .preclose = imx_drm_driver_preclose,
e692da4d
SH
785 .gem_free_object = drm_gem_cma_free_object,
786 .gem_vm_ops = &drm_gem_cma_vm_ops,
787 .dumb_create = drm_gem_cma_dumb_create,
788 .dumb_map_offset = drm_gem_cma_dumb_map_offset,
43387b37 789 .dumb_destroy = drm_gem_dumb_destroy,
e692da4d 790
bd3665c9
PZ
791 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
792 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
793 .gem_prime_import = drm_gem_prime_import,
794 .gem_prime_export = drm_gem_prime_export,
795 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
796 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
797 .gem_prime_vmap = drm_gem_cma_prime_vmap,
798 .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
799 .gem_prime_mmap = drm_gem_cma_prime_mmap,
e692da4d
SH
800 .get_vblank_counter = drm_vblank_count,
801 .enable_vblank = imx_drm_enable_vblank,
802 .disable_vblank = imx_drm_disable_vblank,
803 .ioctls = imx_drm_ioctls,
804 .num_ioctls = ARRAY_SIZE(imx_drm_ioctls),
805 .fops = &imx_drm_driver_fops,
806 .name = "imx-drm",
807 .desc = "i.MX DRM graphics",
808 .date = "20120507",
809 .major = 1,
810 .minor = 0,
811 .patchlevel = 0,
812};
813
814static int imx_drm_platform_probe(struct platform_device *pdev)
815{
4cdbb4ff
RK
816 int ret;
817
818 ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
819 if (ret)
820 return ret;
821
e692da4d
SH
822 imx_drm_device->dev = &pdev->dev;
823
824 return drm_platform_init(&imx_drm_driver, pdev);
825}
826
827static int imx_drm_platform_remove(struct platform_device *pdev)
828{
a72f8bee 829 drm_put_dev(platform_get_drvdata(pdev));
e692da4d
SH
830
831 return 0;
832}
833
834static struct platform_driver imx_drm_pdrv = {
835 .probe = imx_drm_platform_probe,
99c28f10 836 .remove = imx_drm_platform_remove,
e692da4d
SH
837 .driver = {
838 .owner = THIS_MODULE,
839 .name = "imx-drm",
840 },
841};
842
843static struct platform_device *imx_drm_pdev;
844
845static int __init imx_drm_init(void)
846{
847 int ret;
848
849 imx_drm_device = kzalloc(sizeof(*imx_drm_device), GFP_KERNEL);
850 if (!imx_drm_device)
851 return -ENOMEM;
852
853 mutex_init(&imx_drm_device->mutex);
e692da4d
SH
854 INIT_LIST_HEAD(&imx_drm_device->connector_list);
855 INIT_LIST_HEAD(&imx_drm_device->encoder_list);
856
857 imx_drm_pdev = platform_device_register_simple("imx-drm", -1, NULL, 0);
2eaaccde
WY
858 if (IS_ERR(imx_drm_pdev)) {
859 ret = PTR_ERR(imx_drm_pdev);
e692da4d
SH
860 goto err_pdev;
861 }
862
e692da4d
SH
863 ret = platform_driver_register(&imx_drm_pdrv);
864 if (ret)
865 goto err_pdrv;
866
867 return 0;
868
869err_pdrv:
870 platform_device_unregister(imx_drm_pdev);
871err_pdev:
872 kfree(imx_drm_device);
873
874 return ret;
875}
876
877static void __exit imx_drm_exit(void)
878{
879 platform_device_unregister(imx_drm_pdev);
880 platform_driver_unregister(&imx_drm_pdrv);
881
882 kfree(imx_drm_device);
883}
884
885module_init(imx_drm_init);
886module_exit(imx_drm_exit);
887
888MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
889MODULE_DESCRIPTION("i.MX drm driver core");
890MODULE_LICENSE("GPL");
This page took 0.235534 seconds and 5 git commands to generate.