• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
exynos_drm_create_enc_conn(struct drm_device * dev,struct exynos_drm_subdrv * subdrv)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 
exynos_drm_destroy_enc_conn(struct exynos_drm_subdrv * subdrv)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 
exynos_drm_subdrv_probe(struct drm_device * dev,struct exynos_drm_subdrv * subdrv)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 
exynos_drm_subdrv_remove(struct drm_device * dev,struct exynos_drm_subdrv * subdrv)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 
exynos_drm_device_register(struct drm_device * dev)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 
exynos_drm_device_unregister(struct drm_device * dev)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 
exynos_drm_subdrv_register(struct exynos_drm_subdrv * subdrv)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 
exynos_drm_subdrv_unregister(struct exynos_drm_subdrv * subdrv)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 
exynos_drm_subdrv_open(struct drm_device * dev,struct drm_file * file)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 
exynos_drm_subdrv_close(struct drm_device * dev,struct drm_file * file)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);
237