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 
21 static LIST_HEAD(exynos_drm_subdrv_list);
22 
exynos_drm_create_enc_conn(struct drm_device * dev,struct exynos_drm_display * display)23 int exynos_drm_create_enc_conn(struct drm_device *dev,
24 					struct exynos_drm_display *display)
25 {
26 	struct drm_encoder *encoder;
27 	int ret;
28 	unsigned long possible_crtcs = 0;
29 
30 	ret = exynos_drm_crtc_get_pipe_from_type(dev, display->type);
31 	if (ret < 0)
32 		return ret;
33 
34 	possible_crtcs |= 1 << ret;
35 
36 	/* create and initialize a encoder for this sub driver. */
37 	encoder = exynos_drm_encoder_create(dev, display, possible_crtcs);
38 	if (!encoder) {
39 		DRM_ERROR("failed to create encoder\n");
40 		return -EFAULT;
41 	}
42 
43 	display->encoder = encoder;
44 
45 	ret = display->ops->create_connector(display, encoder);
46 	if (ret) {
47 		DRM_ERROR("failed to create connector ret = %d\n", ret);
48 		goto err_destroy_encoder;
49 	}
50 
51 	return 0;
52 
53 err_destroy_encoder:
54 	encoder->funcs->destroy(encoder);
55 	return ret;
56 }
57 
exynos_drm_subdrv_register(struct exynos_drm_subdrv * subdrv)58 int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
59 {
60 	if (!subdrv)
61 		return -EINVAL;
62 
63 	list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
64 
65 	return 0;
66 }
67 EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);
68 
exynos_drm_subdrv_unregister(struct exynos_drm_subdrv * subdrv)69 int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
70 {
71 	if (!subdrv)
72 		return -EINVAL;
73 
74 	list_del(&subdrv->list);
75 
76 	return 0;
77 }
78 EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);
79 
exynos_drm_device_subdrv_probe(struct drm_device * dev)80 int exynos_drm_device_subdrv_probe(struct drm_device *dev)
81 {
82 	struct exynos_drm_subdrv *subdrv, *n;
83 	int err;
84 
85 	if (!dev)
86 		return -EINVAL;
87 
88 	list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
89 		if (subdrv->probe) {
90 			subdrv->drm_dev = dev;
91 
92 			/*
93 			 * this probe callback would be called by sub driver
94 			 * after setting of all resources to this sub driver,
95 			 * such as clock, irq and register map are done.
96 			 */
97 			err = subdrv->probe(dev, subdrv->dev);
98 			if (err) {
99 				DRM_DEBUG("exynos drm subdrv probe failed.\n");
100 				list_del(&subdrv->list);
101 				continue;
102 			}
103 		}
104 	}
105 
106 	return 0;
107 }
108 EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_probe);
109 
exynos_drm_device_subdrv_remove(struct drm_device * dev)110 int exynos_drm_device_subdrv_remove(struct drm_device *dev)
111 {
112 	struct exynos_drm_subdrv *subdrv;
113 
114 	if (!dev) {
115 		WARN(1, "Unexpected drm device unregister!\n");
116 		return -EINVAL;
117 	}
118 
119 	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
120 		if (subdrv->remove)
121 			subdrv->remove(dev, subdrv->dev);
122 	}
123 
124 	return 0;
125 }
126 EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_remove);
127 
exynos_drm_subdrv_open(struct drm_device * dev,struct drm_file * file)128 int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
129 {
130 	struct exynos_drm_subdrv *subdrv;
131 	int ret;
132 
133 	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
134 		if (subdrv->open) {
135 			ret = subdrv->open(dev, subdrv->dev, file);
136 			if (ret)
137 				goto err;
138 		}
139 	}
140 
141 	return 0;
142 
143 err:
144 	list_for_each_entry_reverse(subdrv, &subdrv->list, list) {
145 		if (subdrv->close)
146 			subdrv->close(dev, subdrv->dev, file);
147 	}
148 	return ret;
149 }
150 EXPORT_SYMBOL_GPL(exynos_drm_subdrv_open);
151 
exynos_drm_subdrv_close(struct drm_device * dev,struct drm_file * file)152 void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file)
153 {
154 	struct exynos_drm_subdrv *subdrv;
155 
156 	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
157 		if (subdrv->close)
158 			subdrv->close(dev, subdrv->dev, file);
159 	}
160 }
161 EXPORT_SYMBOL_GPL(exynos_drm_subdrv_close);
162