]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/exynos/exynos_drm_core.c
Merge remote-tracking branch 'regulator/topic/max8997' into regulator-next
[karo-tx-linux.git] / 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_encoder.h"
18 #include "exynos_drm_connector.h"
19 #include "exynos_drm_fbdev.h"
20
21 static LIST_HEAD(exynos_drm_subdrv_list);
22
23 static int exynos_drm_create_enc_conn(struct drm_device *dev,
24                                         struct exynos_drm_subdrv *subdrv)
25 {
26         struct drm_encoder *encoder;
27         struct drm_connector *connector;
28         int ret;
29
30         DRM_DEBUG_DRIVER("%s\n", __FILE__);
31
32         subdrv->manager->dev = subdrv->dev;
33
34         /* create and initialize a encoder for this sub driver. */
35         encoder = exynos_drm_encoder_create(dev, subdrv->manager,
36                         (1 << MAX_CRTC) - 1);
37         if (!encoder) {
38                 DRM_ERROR("failed to create encoder\n");
39                 return -EFAULT;
40         }
41
42         /*
43          * create and initialize a connector for this sub driver and
44          * attach the encoder created above to the connector.
45          */
46         connector = exynos_drm_connector_create(dev, encoder);
47         if (!connector) {
48                 DRM_ERROR("failed to create connector\n");
49                 ret = -EFAULT;
50                 goto err_destroy_encoder;
51         }
52
53         subdrv->encoder = encoder;
54         subdrv->connector = connector;
55
56         return 0;
57
58 err_destroy_encoder:
59         encoder->funcs->destroy(encoder);
60         return ret;
61 }
62
63 static void exynos_drm_destroy_enc_conn(struct exynos_drm_subdrv *subdrv)
64 {
65         if (subdrv->encoder) {
66                 struct drm_encoder *encoder = subdrv->encoder;
67                 encoder->funcs->destroy(encoder);
68                 subdrv->encoder = NULL;
69         }
70
71         if (subdrv->connector) {
72                 struct drm_connector *connector = subdrv->connector;
73                 connector->funcs->destroy(connector);
74                 subdrv->connector = NULL;
75         }
76 }
77
78 static int exynos_drm_subdrv_probe(struct drm_device *dev,
79                                         struct exynos_drm_subdrv *subdrv)
80 {
81         if (subdrv->probe) {
82                 int ret;
83
84                 subdrv->drm_dev = dev;
85
86                 /*
87                  * this probe callback would be called by sub driver
88                  * after setting of all resources to this sub driver,
89                  * such as clock, irq and register map are done or by load()
90                  * of exynos drm driver.
91                  *
92                  * P.S. note that this driver is considered for modularization.
93                  */
94                 ret = subdrv->probe(dev, subdrv->dev);
95                 if (ret)
96                         return ret;
97         }
98
99         return 0;
100 }
101
102 static void exynos_drm_subdrv_remove(struct drm_device *dev,
103                                       struct exynos_drm_subdrv *subdrv)
104 {
105         DRM_DEBUG_DRIVER("%s\n", __FILE__);
106
107         if (subdrv->remove)
108                 subdrv->remove(dev, subdrv->dev);
109 }
110
111 int exynos_drm_device_register(struct drm_device *dev)
112 {
113         struct exynos_drm_subdrv *subdrv, *n;
114         unsigned int fine_cnt = 0;
115         int err;
116
117         DRM_DEBUG_DRIVER("%s\n", __FILE__);
118
119         if (!dev)
120                 return -EINVAL;
121
122         list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
123                 err = exynos_drm_subdrv_probe(dev, subdrv);
124                 if (err) {
125                         DRM_DEBUG("exynos drm subdrv probe failed.\n");
126                         list_del(&subdrv->list);
127                         continue;
128                 }
129
130                 /*
131                  * if manager is null then it means that this sub driver
132                  * doesn't need encoder and connector.
133                  */
134                 if (!subdrv->manager) {
135                         fine_cnt++;
136                         continue;
137                 }
138
139                 err = exynos_drm_create_enc_conn(dev, subdrv);
140                 if (err) {
141                         DRM_DEBUG("failed to create encoder and connector.\n");
142                         exynos_drm_subdrv_remove(dev, subdrv);
143                         list_del(&subdrv->list);
144                         continue;
145                 }
146
147                 fine_cnt++;
148         }
149
150         if (!fine_cnt)
151                 return -EINVAL;
152
153         return 0;
154 }
155 EXPORT_SYMBOL_GPL(exynos_drm_device_register);
156
157 int exynos_drm_device_unregister(struct drm_device *dev)
158 {
159         struct exynos_drm_subdrv *subdrv;
160
161         DRM_DEBUG_DRIVER("%s\n", __FILE__);
162
163         if (!dev) {
164                 WARN(1, "Unexpected drm device unregister!\n");
165                 return -EINVAL;
166         }
167
168         list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
169                 exynos_drm_subdrv_remove(dev, subdrv);
170                 exynos_drm_destroy_enc_conn(subdrv);
171         }
172
173         return 0;
174 }
175 EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);
176
177 int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
178 {
179         DRM_DEBUG_DRIVER("%s\n", __FILE__);
180
181         if (!subdrv)
182                 return -EINVAL;
183
184         list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
185
186         return 0;
187 }
188 EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);
189
190 int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
191 {
192         DRM_DEBUG_DRIVER("%s\n", __FILE__);
193
194         if (!subdrv)
195                 return -EINVAL;
196
197         list_del(&subdrv->list);
198
199         return 0;
200 }
201 EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);
202
203 int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
204 {
205         struct exynos_drm_subdrv *subdrv;
206         int ret;
207
208         list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
209                 if (subdrv->open) {
210                         ret = subdrv->open(dev, subdrv->dev, file);
211                         if (ret)
212                                 goto err;
213                 }
214         }
215
216         return 0;
217
218 err:
219         list_for_each_entry_reverse(subdrv, &subdrv->list, list) {
220                 if (subdrv->close)
221                         subdrv->close(dev, subdrv->dev, file);
222         }
223         return ret;
224 }
225 EXPORT_SYMBOL_GPL(exynos_drm_subdrv_open);
226
227 void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file)
228 {
229         struct exynos_drm_subdrv *subdrv;
230
231         list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
232                 if (subdrv->close)
233                         subdrv->close(dev, subdrv->dev, file);
234         }
235 }
236 EXPORT_SYMBOL_GPL(exynos_drm_subdrv_close);