Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 21static LIST_HEAD(exynos_drm_subdrv_list);
 22static LIST_HEAD(exynos_drm_manager_list);
 23static LIST_HEAD(exynos_drm_display_list);
 24
 25static int exynos_drm_create_enc_conn(struct drm_device *dev,
 26					struct exynos_drm_display *display)
 27{
 28	struct drm_encoder *encoder;
 29	struct exynos_drm_manager *manager;
 30	int ret;
 31	unsigned long possible_crtcs = 0;
 32
 33	/* Find possible crtcs for this display */
 34	list_for_each_entry(manager, &exynos_drm_manager_list, list)
 35		if (manager->type == display->type)
 36			possible_crtcs |= 1 << manager->pipe;
 37
 38	/* create and initialize a encoder for this sub driver. */
 39	encoder = exynos_drm_encoder_create(dev, display, possible_crtcs);
 40	if (!encoder) {
 41		DRM_ERROR("failed to create encoder\n");
 42		return -EFAULT;
 43	}
 44
 45	display->encoder = encoder;
 46
 47	ret = display->ops->create_connector(display, encoder);
 48	if (ret) {
 49		DRM_ERROR("failed to create connector ret = %d\n", ret);
 50		goto err_destroy_encoder;
 51	}
 52
 53	return 0;
 54
 55err_destroy_encoder:
 56	encoder->funcs->destroy(encoder);
 57	return ret;
 58}
 59
 60static int exynos_drm_subdrv_probe(struct drm_device *dev,
 61					struct exynos_drm_subdrv *subdrv)
 62{
 63	if (subdrv->probe) {
 64		int ret;
 65
 66		subdrv->drm_dev = dev;
 67
 68		/*
 69		 * this probe callback would be called by sub driver
 70		 * after setting of all resources to this sub driver,
 71		 * such as clock, irq and register map are done or by load()
 72		 * of exynos drm driver.
 73		 *
 74		 * P.S. note that this driver is considered for modularization.
 75		 */
 76		ret = subdrv->probe(dev, subdrv->dev);
 77		if (ret)
 78			return ret;
 79	}
 80
 81	return 0;
 82}
 83
 84static void exynos_drm_subdrv_remove(struct drm_device *dev,
 85				      struct exynos_drm_subdrv *subdrv)
 86{
 87	if (subdrv->remove)
 88		subdrv->remove(dev, subdrv->dev);
 89}
 90
 91int exynos_drm_initialize_managers(struct drm_device *dev)
 92{
 93	struct exynos_drm_manager *manager, *n;
 94	int ret, pipe = 0;
 95
 96	list_for_each_entry(manager, &exynos_drm_manager_list, list) {
 97		if (manager->ops->initialize) {
 98			ret = manager->ops->initialize(manager, dev, pipe);
 99			if (ret) {
100				DRM_ERROR("Mgr init [%d] failed with %d\n",
101						manager->type, ret);
102				goto err;
103			}
104		}
105
106		manager->drm_dev = dev;
107		manager->pipe = pipe++;
108
109		ret = exynos_drm_crtc_create(manager);
110		if (ret) {
111			DRM_ERROR("CRTC create [%d] failed with %d\n",
112					manager->type, ret);
113			goto err;
114		}
115	}
116	return 0;
117
118err:
119	list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list) {
120		if (pipe-- > 0)
121			exynos_drm_manager_unregister(manager);
122		else
123			list_del(&manager->list);
124	}
125	return ret;
126}
127
128void exynos_drm_remove_managers(struct drm_device *dev)
129{
130	struct exynos_drm_manager *manager, *n;
131
132	list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list)
133		exynos_drm_manager_unregister(manager);
134}
135
136int exynos_drm_initialize_displays(struct drm_device *dev)
137{
138	struct exynos_drm_display *display, *n;
139	int ret, initialized = 0;
140
141	list_for_each_entry(display, &exynos_drm_display_list, list) {
142		if (display->ops->initialize) {
143			ret = display->ops->initialize(display, dev);
144			if (ret) {
145				DRM_ERROR("Display init [%d] failed with %d\n",
146						display->type, ret);
147				goto err;
148			}
149		}
150
151		initialized++;
152
153		ret = exynos_drm_create_enc_conn(dev, display);
154		if (ret) {
155			DRM_ERROR("Encoder create [%d] failed with %d\n",
156					display->type, ret);
157			goto err;
158		}
159	}
160	return 0;
161
162err:
163	list_for_each_entry_safe(display, n, &exynos_drm_display_list, list) {
164		if (initialized-- > 0)
165			exynos_drm_display_unregister(display);
166		else
167			list_del(&display->list);
168	}
169	return ret;
170}
171
172void exynos_drm_remove_displays(struct drm_device *dev)
173{
174	struct exynos_drm_display *display, *n;
175
176	list_for_each_entry_safe(display, n, &exynos_drm_display_list, list)
177		exynos_drm_display_unregister(display);
178}
179
180int exynos_drm_device_register(struct drm_device *dev)
181{
182	struct exynos_drm_subdrv *subdrv, *n;
183	int err;
184
185	if (!dev)
186		return -EINVAL;
187
188	list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
189		err = exynos_drm_subdrv_probe(dev, subdrv);
190		if (err) {
191			DRM_DEBUG("exynos drm subdrv probe failed.\n");
192			list_del(&subdrv->list);
193			continue;
194		}
195	}
196
197	return 0;
198}
199EXPORT_SYMBOL_GPL(exynos_drm_device_register);
200
201int exynos_drm_device_unregister(struct drm_device *dev)
202{
203	struct exynos_drm_subdrv *subdrv;
204
205	if (!dev) {
206		WARN(1, "Unexpected drm device unregister!\n");
207		return -EINVAL;
208	}
209
210	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
211		exynos_drm_subdrv_remove(dev, subdrv);
212	}
213
214	return 0;
215}
216EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);
217
218int exynos_drm_manager_register(struct exynos_drm_manager *manager)
219{
220	BUG_ON(!manager->ops);
221	list_add_tail(&manager->list, &exynos_drm_manager_list);
222	return 0;
223}
224
225int exynos_drm_manager_unregister(struct exynos_drm_manager *manager)
226{
227	if (manager->ops->remove)
228		manager->ops->remove(manager);
229
230	list_del(&manager->list);
231	return 0;
232}
233
234int exynos_drm_display_register(struct exynos_drm_display *display)
235{
236	BUG_ON(!display->ops);
237	list_add_tail(&display->list, &exynos_drm_display_list);
238	return 0;
239}
240
241int exynos_drm_display_unregister(struct exynos_drm_display *display)
242{
243	if (display->ops->remove)
244		display->ops->remove(display);
245
246	list_del(&display->list);
247	return 0;
248}
249
250int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
251{
252	if (!subdrv)
253		return -EINVAL;
254
255	list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
256
257	return 0;
258}
259EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);
260
261int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
262{
263	if (!subdrv)
264		return -EINVAL;
265
266	list_del(&subdrv->list);
267
268	return 0;
269}
270EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);
271
272int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
273{
274	struct exynos_drm_subdrv *subdrv;
275	int ret;
276
277	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
278		if (subdrv->open) {
279			ret = subdrv->open(dev, subdrv->dev, file);
280			if (ret)
281				goto err;
282		}
283	}
284
285	return 0;
286
287err:
288	list_for_each_entry_reverse(subdrv, &subdrv->list, list) {
289		if (subdrv->close)
290			subdrv->close(dev, subdrv->dev, file);
291	}
292	return ret;
293}
294EXPORT_SYMBOL_GPL(exynos_drm_subdrv_open);
295
296void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file)
297{
298	struct exynos_drm_subdrv *subdrv;
299
300	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
301		if (subdrv->close)
302			subdrv->close(dev, subdrv->dev, file);
303	}
304}
305EXPORT_SYMBOL_GPL(exynos_drm_subdrv_close);