Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / gpu / drm / exynos / exynos_drm_core.c
1 /* exynos_drm_core.c
2  *
3  * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4  * Author:
5  *      Inki Dae <inki.dae@samsung.com>
6  *      Joonyoung Shim <jy0922.shim@samsung.com>
7  *      Seung-Woo Kim <sw0312.kim@samsung.com>
8  *
9  * This program is free software; you can redistribute  it and/or modify it
10  * under  the terms of  the GNU General  Public License as published by the
11  * Free Software Foundation;  either version 2 of the  License, or (at your
12  * option) any later version.
13  */
14
15 #include <drm/drmP.h>
16 #include "exynos_drm_drv.h"
17 #include "exynos_drm_crtc.h"
18 #include "exynos_drm_encoder.h"
19 #include "exynos_drm_fbdev.h"
20
21 static LIST_HEAD(exynos_drm_subdrv_list);
22
23 int exynos_drm_create_enc_conn(struct drm_device *dev,
24                                         struct exynos_drm_display *display)
25 {
26         struct drm_encoder *encoder;
27         int ret;
28         unsigned long possible_crtcs = 0;
29
30         ret = exynos_drm_crtc_get_pipe_from_type(dev, display->type);
31         if (ret < 0)
32                 return ret;
33
34         possible_crtcs |= 1 << ret;
35
36         /* create and initialize a encoder for this sub driver. */
37         encoder = exynos_drm_encoder_create(dev, display, possible_crtcs);
38         if (!encoder) {
39                 DRM_ERROR("failed to create encoder\n");
40                 return -EFAULT;
41         }
42
43         display->encoder = encoder;
44
45         ret = display->ops->create_connector(display, encoder);
46         if (ret) {
47                 DRM_ERROR("failed to create connector ret = %d\n", ret);
48                 goto err_destroy_encoder;
49         }
50
51         return 0;
52
53 err_destroy_encoder:
54         encoder->funcs->destroy(encoder);
55         return ret;
56 }
57
58 int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
59 {
60         if (!subdrv)
61                 return -EINVAL;
62
63         list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
64
65         return 0;
66 }
67 EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);
68
69 int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
70 {
71         if (!subdrv)
72                 return -EINVAL;
73
74         list_del(&subdrv->list);
75
76         return 0;
77 }
78 EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);
79
80 int exynos_drm_device_subdrv_probe(struct drm_device *dev)
81 {
82         struct exynos_drm_subdrv *subdrv, *n;
83         int err;
84
85         if (!dev)
86                 return -EINVAL;
87
88         list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
89                 if (subdrv->probe) {
90                         subdrv->drm_dev = dev;
91
92                         /*
93                          * this probe callback would be called by sub driver
94                          * after setting of all resources to this sub driver,
95                          * such as clock, irq and register map are done.
96                          */
97                         err = subdrv->probe(dev, subdrv->dev);
98                         if (err) {
99                                 DRM_DEBUG("exynos drm subdrv probe failed.\n");
100                                 list_del(&subdrv->list);
101                                 continue;
102                         }
103                 }
104         }
105
106         return 0;
107 }
108 EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_probe);
109
110 int exynos_drm_device_subdrv_remove(struct drm_device *dev)
111 {
112         struct exynos_drm_subdrv *subdrv;
113
114         if (!dev) {
115                 WARN(1, "Unexpected drm device unregister!\n");
116                 return -EINVAL;
117         }
118
119         list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
120                 if (subdrv->remove)
121                         subdrv->remove(dev, subdrv->dev);
122         }
123
124         return 0;
125 }
126 EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_remove);
127
128 int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
129 {
130         struct exynos_drm_subdrv *subdrv;
131         int ret;
132
133         list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
134                 if (subdrv->open) {
135                         ret = subdrv->open(dev, subdrv->dev, file);
136                         if (ret)
137                                 goto err;
138                 }
139         }
140
141         return 0;
142
143 err:
144         list_for_each_entry_reverse(subdrv, &subdrv->list, list) {
145                 if (subdrv->close)
146                         subdrv->close(dev, subdrv->dev, file);
147         }
148         return ret;
149 }
150 EXPORT_SYMBOL_GPL(exynos_drm_subdrv_open);
151
152 void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file)
153 {
154         struct exynos_drm_subdrv *subdrv;
155
156         list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
157                 if (subdrv->close)
158                         subdrv->close(dev, subdrv->dev, file);
159         }
160 }
161 EXPORT_SYMBOL_GPL(exynos_drm_subdrv_close);