Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
exynos_drm_core.c
Go to the documentation of this file.
1 /* exynos_drm_core.c
2  *
3  * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4  * Author:
5  * Inki Dae <[email protected]>
6  * Joonyoung Shim <[email protected]>
7  * Seung-Woo Kim <[email protected]>
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the "Software"),
11  * to deal in the Software without restriction, including without limitation
12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  * and/or sell copies of the Software, and to permit persons to whom the
14  * Software is furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice (including the next
17  * paragraph) shall be included in all copies or substantial portions of the
18  * Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26  * OTHER DEALINGS IN THE SOFTWARE.
27  */
28 
29 #include <drm/drmP.h>
30 #include "exynos_drm_drv.h"
31 #include "exynos_drm_encoder.h"
32 #include "exynos_drm_connector.h"
33 #include "exynos_drm_fbdev.h"
34 
35 static LIST_HEAD(exynos_drm_subdrv_list);
36 
37 static int exynos_drm_create_enc_conn(struct drm_device *dev,
38  struct exynos_drm_subdrv *subdrv)
39 {
40  struct drm_encoder *encoder;
41  struct drm_connector *connector;
42  int ret;
43 
44  DRM_DEBUG_DRIVER("%s\n", __FILE__);
45 
46  subdrv->manager->dev = subdrv->dev;
47 
48  /* create and initialize a encoder for this sub driver. */
49  encoder = exynos_drm_encoder_create(dev, subdrv->manager,
50  (1 << MAX_CRTC) - 1);
51  if (!encoder) {
52  DRM_ERROR("failed to create encoder\n");
53  return -EFAULT;
54  }
55 
56  /*
57  * create and initialize a connector for this sub driver and
58  * attach the encoder created above to the connector.
59  */
60  connector = exynos_drm_connector_create(dev, encoder);
61  if (!connector) {
62  DRM_ERROR("failed to create connector\n");
63  ret = -EFAULT;
64  goto err_destroy_encoder;
65  }
66 
67  subdrv->encoder = encoder;
68  subdrv->connector = connector;
69 
70  return 0;
71 
72 err_destroy_encoder:
73  encoder->funcs->destroy(encoder);
74  return ret;
75 }
76 
77 static void exynos_drm_destroy_enc_conn(struct exynos_drm_subdrv *subdrv)
78 {
79  if (subdrv->encoder) {
80  struct drm_encoder *encoder = subdrv->encoder;
81  encoder->funcs->destroy(encoder);
82  subdrv->encoder = NULL;
83  }
84 
85  if (subdrv->connector) {
86  struct drm_connector *connector = subdrv->connector;
87  connector->funcs->destroy(connector);
88  subdrv->connector = NULL;
89  }
90 }
91 
92 static int exynos_drm_subdrv_probe(struct drm_device *dev,
93  struct exynos_drm_subdrv *subdrv)
94 {
95  if (subdrv->probe) {
96  int ret;
97 
98  subdrv->drm_dev = dev;
99 
100  /*
101  * this probe callback would be called by sub driver
102  * after setting of all resources to this sub driver,
103  * such as clock, irq and register map are done or by load()
104  * of exynos drm driver.
105  *
106  * P.S. note that this driver is considered for modularization.
107  */
108  ret = subdrv->probe(dev, subdrv->dev);
109  if (ret)
110  return ret;
111  }
112 
113  return 0;
114 }
115 
116 static void exynos_drm_subdrv_remove(struct drm_device *dev,
117  struct exynos_drm_subdrv *subdrv)
118 {
119  DRM_DEBUG_DRIVER("%s\n", __FILE__);
120 
121  if (subdrv->remove)
122  subdrv->remove(dev, subdrv->dev);
123 }
124 
126 {
127  struct exynos_drm_subdrv *subdrv, *n;
128  unsigned int fine_cnt = 0;
129  int err;
130 
131  DRM_DEBUG_DRIVER("%s\n", __FILE__);
132 
133  if (!dev)
134  return -EINVAL;
135 
136  list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
137  err = exynos_drm_subdrv_probe(dev, subdrv);
138  if (err) {
139  DRM_DEBUG("exynos drm subdrv probe failed.\n");
140  list_del(&subdrv->list);
141  continue;
142  }
143 
144  /*
145  * if manager is null then it means that this sub driver
146  * doesn't need encoder and connector.
147  */
148  if (!subdrv->manager) {
149  fine_cnt++;
150  continue;
151  }
152 
153  err = exynos_drm_create_enc_conn(dev, subdrv);
154  if (err) {
155  DRM_DEBUG("failed to create encoder and connector.\n");
156  exynos_drm_subdrv_remove(dev, subdrv);
157  list_del(&subdrv->list);
158  continue;
159  }
160 
161  fine_cnt++;
162  }
163 
164  if (!fine_cnt)
165  return -EINVAL;
166 
167  return 0;
168 }
170 
172 {
173  struct exynos_drm_subdrv *subdrv;
174 
175  DRM_DEBUG_DRIVER("%s\n", __FILE__);
176 
177  if (!dev) {
178  WARN(1, "Unexpected drm device unregister!\n");
179  return -EINVAL;
180  }
181 
182  list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
183  exynos_drm_subdrv_remove(dev, subdrv);
184  exynos_drm_destroy_enc_conn(subdrv);
185  }
186 
187  return 0;
188 }
190 
192 {
193  DRM_DEBUG_DRIVER("%s\n", __FILE__);
194 
195  if (!subdrv)
196  return -EINVAL;
197 
198  list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
199 
200  return 0;
201 }
203 
205 {
206  DRM_DEBUG_DRIVER("%s\n", __FILE__);
207 
208  if (!subdrv)
209  return -EINVAL;
210 
211  list_del(&subdrv->list);
212 
213  return 0;
214 }
216 
217 int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
218 {
219  struct exynos_drm_subdrv *subdrv;
220  int ret;
221 
222  list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
223  if (subdrv->open) {
224  ret = subdrv->open(dev, subdrv->dev, file);
225  if (ret)
226  goto err;
227  }
228  }
229 
230  return 0;
231 
232 err:
233  list_for_each_entry_reverse(subdrv, &subdrv->list, list) {
234  if (subdrv->close)
235  subdrv->close(dev, subdrv->dev, file);
236  }
237  return ret;
238 }
240 
241 void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file)
242 {
243  struct exynos_drm_subdrv *subdrv;
244 
245  list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
246  if (subdrv->close)
247  subdrv->close(dev, subdrv->dev, file);
248  }
249 }