diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_core.c | 100 |
1 files changed, 69 insertions, 31 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c index 80cba2f413f4..7b0432b7a364 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c | |||
@@ -34,33 +34,15 @@ | |||
34 | 34 | ||
35 | static LIST_HEAD(exynos_drm_subdrv_list); | 35 | static LIST_HEAD(exynos_drm_subdrv_list); |
36 | 36 | ||
37 | static int exynos_drm_subdrv_probe(struct drm_device *dev, | 37 | static int exynos_drm_create_enc_conn(struct drm_device *dev, |
38 | struct exynos_drm_subdrv *subdrv) | 38 | struct exynos_drm_subdrv *subdrv) |
39 | { | 39 | { |
40 | struct drm_encoder *encoder; | 40 | struct drm_encoder *encoder; |
41 | struct drm_connector *connector; | 41 | struct drm_connector *connector; |
42 | int ret; | ||
42 | 43 | ||
43 | DRM_DEBUG_DRIVER("%s\n", __FILE__); | 44 | DRM_DEBUG_DRIVER("%s\n", __FILE__); |
44 | 45 | ||
45 | if (subdrv->probe) { | ||
46 | int ret; | ||
47 | |||
48 | /* | ||
49 | * this probe callback would be called by sub driver | ||
50 | * after setting of all resources to this sub driver, | ||
51 | * such as clock, irq and register map are done or by load() | ||
52 | * of exynos drm driver. | ||
53 | * | ||
54 | * P.S. note that this driver is considered for modularization. | ||
55 | */ | ||
56 | ret = subdrv->probe(dev, subdrv->dev); | ||
57 | if (ret) | ||
58 | return ret; | ||
59 | } | ||
60 | |||
61 | if (!subdrv->manager) | ||
62 | return 0; | ||
63 | |||
64 | subdrv->manager->dev = subdrv->dev; | 46 | subdrv->manager->dev = subdrv->dev; |
65 | 47 | ||
66 | /* create and initialize a encoder for this sub driver. */ | 48 | /* create and initialize a encoder for this sub driver. */ |
@@ -78,24 +60,22 @@ static int exynos_drm_subdrv_probe(struct drm_device *dev, | |||
78 | connector = exynos_drm_connector_create(dev, encoder); | 60 | connector = exynos_drm_connector_create(dev, encoder); |
79 | if (!connector) { | 61 | if (!connector) { |
80 | DRM_ERROR("failed to create connector\n"); | 62 | DRM_ERROR("failed to create connector\n"); |
81 | encoder->funcs->destroy(encoder); | 63 | ret = -EFAULT; |
82 | return -EFAULT; | 64 | goto err_destroy_encoder; |
83 | } | 65 | } |
84 | 66 | ||
85 | subdrv->encoder = encoder; | 67 | subdrv->encoder = encoder; |
86 | subdrv->connector = connector; | 68 | subdrv->connector = connector; |
87 | 69 | ||
88 | return 0; | 70 | return 0; |
71 | |||
72 | err_destroy_encoder: | ||
73 | encoder->funcs->destroy(encoder); | ||
74 | return ret; | ||
89 | } | 75 | } |
90 | 76 | ||
91 | static void exynos_drm_subdrv_remove(struct drm_device *dev, | 77 | static void exynos_drm_destroy_enc_conn(struct exynos_drm_subdrv *subdrv) |
92 | struct exynos_drm_subdrv *subdrv) | ||
93 | { | 78 | { |
94 | DRM_DEBUG_DRIVER("%s\n", __FILE__); | ||
95 | |||
96 | if (subdrv->remove) | ||
97 | subdrv->remove(dev, subdrv->dev); | ||
98 | |||
99 | if (subdrv->encoder) { | 79 | if (subdrv->encoder) { |
100 | struct drm_encoder *encoder = subdrv->encoder; | 80 | struct drm_encoder *encoder = subdrv->encoder; |
101 | encoder->funcs->destroy(encoder); | 81 | encoder->funcs->destroy(encoder); |
@@ -109,9 +89,43 @@ static void exynos_drm_subdrv_remove(struct drm_device *dev, | |||
109 | } | 89 | } |
110 | } | 90 | } |
111 | 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 | |||
112 | int exynos_drm_device_register(struct drm_device *dev) | 125 | int exynos_drm_device_register(struct drm_device *dev) |
113 | { | 126 | { |
114 | struct exynos_drm_subdrv *subdrv, *n; | 127 | struct exynos_drm_subdrv *subdrv, *n; |
128 | unsigned int fine_cnt = 0; | ||
115 | int err; | 129 | int err; |
116 | 130 | ||
117 | DRM_DEBUG_DRIVER("%s\n", __FILE__); | 131 | DRM_DEBUG_DRIVER("%s\n", __FILE__); |
@@ -120,14 +134,36 @@ int exynos_drm_device_register(struct drm_device *dev) | |||
120 | return -EINVAL; | 134 | return -EINVAL; |
121 | 135 | ||
122 | list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) { | 136 | list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) { |
123 | subdrv->drm_dev = dev; | ||
124 | err = exynos_drm_subdrv_probe(dev, subdrv); | 137 | err = exynos_drm_subdrv_probe(dev, subdrv); |
125 | if (err) { | 138 | if (err) { |
126 | DRM_DEBUG("exynos drm subdrv probe failed.\n"); | 139 | DRM_DEBUG("exynos drm subdrv probe failed.\n"); |
127 | list_del(&subdrv->list); | 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; | ||
128 | } | 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++; | ||
129 | } | 162 | } |
130 | 163 | ||
164 | if (!fine_cnt) | ||
165 | return -EINVAL; | ||
166 | |||
131 | return 0; | 167 | return 0; |
132 | } | 168 | } |
133 | EXPORT_SYMBOL_GPL(exynos_drm_device_register); | 169 | EXPORT_SYMBOL_GPL(exynos_drm_device_register); |
@@ -143,8 +179,10 @@ int exynos_drm_device_unregister(struct drm_device *dev) | |||
143 | return -EINVAL; | 179 | return -EINVAL; |
144 | } | 180 | } |
145 | 181 | ||
146 | list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) | 182 | list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { |
147 | exynos_drm_subdrv_remove(dev, subdrv); | 183 | exynos_drm_subdrv_remove(dev, subdrv); |
184 | exynos_drm_destroy_enc_conn(subdrv); | ||
185 | } | ||
148 | 186 | ||
149 | return 0; | 187 | return 0; |
150 | } | 188 | } |