|
@@ -34,33 +34,15 @@
|
|
|
|
|
|
static LIST_HEAD(exynos_drm_subdrv_list);
|
|
|
|
|
|
-static int exynos_drm_subdrv_probe(struct drm_device *dev,
|
|
|
+static int exynos_drm_create_enc_conn(struct drm_device *dev,
|
|
|
struct exynos_drm_subdrv *subdrv)
|
|
|
{
|
|
|
struct drm_encoder *encoder;
|
|
|
struct drm_connector *connector;
|
|
|
+ int ret;
|
|
|
|
|
|
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
|
|
|
|
|
- if (subdrv->probe) {
|
|
|
- int ret;
|
|
|
-
|
|
|
- /*
|
|
|
- * this probe callback would be called by sub driver
|
|
|
- * after setting of all resources to this sub driver,
|
|
|
- * such as clock, irq and register map are done or by load()
|
|
|
- * of exynos drm driver.
|
|
|
- *
|
|
|
- * P.S. note that this driver is considered for modularization.
|
|
|
- */
|
|
|
- ret = subdrv->probe(dev, subdrv->dev);
|
|
|
- if (ret)
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
- if (!subdrv->manager)
|
|
|
- return 0;
|
|
|
-
|
|
|
subdrv->manager->dev = subdrv->dev;
|
|
|
|
|
|
/* create and initialize a encoder for this sub driver. */
|
|
@@ -78,24 +60,22 @@ static int exynos_drm_subdrv_probe(struct drm_device *dev,
|
|
|
connector = exynos_drm_connector_create(dev, encoder);
|
|
|
if (!connector) {
|
|
|
DRM_ERROR("failed to create connector\n");
|
|
|
- encoder->funcs->destroy(encoder);
|
|
|
- return -EFAULT;
|
|
|
+ ret = -EFAULT;
|
|
|
+ goto err_destroy_encoder;
|
|
|
}
|
|
|
|
|
|
subdrv->encoder = encoder;
|
|
|
subdrv->connector = connector;
|
|
|
|
|
|
return 0;
|
|
|
+
|
|
|
+err_destroy_encoder:
|
|
|
+ encoder->funcs->destroy(encoder);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
-static void exynos_drm_subdrv_remove(struct drm_device *dev,
|
|
|
- struct exynos_drm_subdrv *subdrv)
|
|
|
+static void exynos_drm_destroy_enc_conn(struct exynos_drm_subdrv *subdrv)
|
|
|
{
|
|
|
- DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
|
|
-
|
|
|
- if (subdrv->remove)
|
|
|
- subdrv->remove(dev, subdrv->dev);
|
|
|
-
|
|
|
if (subdrv->encoder) {
|
|
|
struct drm_encoder *encoder = subdrv->encoder;
|
|
|
encoder->funcs->destroy(encoder);
|
|
@@ -109,9 +89,43 @@ static void exynos_drm_subdrv_remove(struct drm_device *dev,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static int exynos_drm_subdrv_probe(struct drm_device *dev,
|
|
|
+ struct exynos_drm_subdrv *subdrv)
|
|
|
+{
|
|
|
+ if (subdrv->probe) {
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ subdrv->drm_dev = dev;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * this probe callback would be called by sub driver
|
|
|
+ * after setting of all resources to this sub driver,
|
|
|
+ * such as clock, irq and register map are done or by load()
|
|
|
+ * of exynos drm driver.
|
|
|
+ *
|
|
|
+ * P.S. note that this driver is considered for modularization.
|
|
|
+ */
|
|
|
+ ret = subdrv->probe(dev, subdrv->dev);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void exynos_drm_subdrv_remove(struct drm_device *dev,
|
|
|
+ struct exynos_drm_subdrv *subdrv)
|
|
|
+{
|
|
|
+ DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
|
|
+
|
|
|
+ if (subdrv->remove)
|
|
|
+ subdrv->remove(dev, subdrv->dev);
|
|
|
+}
|
|
|
+
|
|
|
int exynos_drm_device_register(struct drm_device *dev)
|
|
|
{
|
|
|
struct exynos_drm_subdrv *subdrv, *n;
|
|
|
+ unsigned int fine_cnt = 0;
|
|
|
int err;
|
|
|
|
|
|
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
|
@@ -120,14 +134,36 @@ int exynos_drm_device_register(struct drm_device *dev)
|
|
|
return -EINVAL;
|
|
|
|
|
|
list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
|
|
|
- subdrv->drm_dev = dev;
|
|
|
err = exynos_drm_subdrv_probe(dev, subdrv);
|
|
|
if (err) {
|
|
|
DRM_DEBUG("exynos drm subdrv probe failed.\n");
|
|
|
list_del(&subdrv->list);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * if manager is null then it means that this sub driver
|
|
|
+ * doesn't need encoder and connector.
|
|
|
+ */
|
|
|
+ if (!subdrv->manager) {
|
|
|
+ fine_cnt++;
|
|
|
+ continue;
|
|
|
}
|
|
|
+
|
|
|
+ err = exynos_drm_create_enc_conn(dev, subdrv);
|
|
|
+ if (err) {
|
|
|
+ DRM_DEBUG("failed to create encoder and connector.\n");
|
|
|
+ exynos_drm_subdrv_remove(dev, subdrv);
|
|
|
+ list_del(&subdrv->list);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ fine_cnt++;
|
|
|
}
|
|
|
|
|
|
+ if (!fine_cnt)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(exynos_drm_device_register);
|
|
@@ -143,8 +179,10 @@ int exynos_drm_device_unregister(struct drm_device *dev)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list)
|
|
|
+ list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
|
|
|
exynos_drm_subdrv_remove(dev, subdrv);
|
|
|
+ exynos_drm_destroy_enc_conn(subdrv);
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
|
}
|