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