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