@@ -6,6 +6,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/component.h>
#include <drm/drm_of.h>
#include "dcss-dev.h"
@@ -14,6 +15,8 @@
struct dcss_drv {
struct dcss_dev *dcss;
struct dcss_kms_dev *kms;
+
+ bool is_componentized;
};
struct dcss_dev *dcss_drv_dev_to_dcss(struct device *dev)
@@ -30,30 +33,18 @@ struct drm_device *dcss_drv_dev_to_drm(struct device *dev)
return mdrv ? &mdrv->kms->base : NULL;
}
-static int dcss_drv_platform_probe(struct platform_device *pdev)
+static int dcss_drv_init(struct device *dev, bool componentized)
{
- struct device *dev = &pdev->dev;
- struct device_node *remote;
struct dcss_drv *mdrv;
int err = 0;
- bool hdmi_output = true;
-
- if (!dev->of_node)
- return -ENODEV;
-
- remote = of_graph_get_remote_node(dev->of_node, 0, 0);
- if (!remote)
- return -ENODEV;
-
- hdmi_output = !of_device_is_compatible(remote, "fsl,imx8mq-nwl-dsi");
-
- of_node_put(remote);
mdrv = kzalloc(sizeof(*mdrv), GFP_KERNEL);
if (!mdrv)
return -ENOMEM;
- mdrv->dcss = dcss_dev_create(dev, hdmi_output);
+ mdrv->is_componentized = componentized;
+
+ mdrv->dcss = dcss_dev_create(dev, componentized);
if (IS_ERR(mdrv->dcss)) {
err = PTR_ERR(mdrv->dcss);
goto err;
@@ -61,7 +52,7 @@ static int dcss_drv_platform_probe(struct platform_device *pdev)
dev_set_drvdata(dev, mdrv);
- mdrv->kms = dcss_kms_attach(mdrv->dcss);
+ mdrv->kms = dcss_kms_attach(mdrv->dcss, componentized);
if (IS_ERR(mdrv->kms)) {
err = PTR_ERR(mdrv->kms);
goto dcss_shutoff;
@@ -79,19 +70,73 @@ static int dcss_drv_platform_probe(struct platform_device *pdev)
return err;
}
-static int dcss_drv_platform_remove(struct platform_device *pdev)
+static void dcss_drv_deinit(struct device *dev, bool componentized)
{
- struct dcss_drv *mdrv = dev_get_drvdata(&pdev->dev);
+ struct dcss_drv *mdrv = dev_get_drvdata(dev);
if (!mdrv)
- return 0;
+ return;
- dcss_kms_detach(mdrv->kms);
+ dcss_kms_detach(mdrv->kms, componentized);
dcss_dev_destroy(mdrv->dcss);
- dev_set_drvdata(&pdev->dev, NULL);
+ dev_set_drvdata(dev, NULL);
kfree(mdrv);
+}
+
+static int dcss_drv_bind(struct device *dev)
+{
+ return dcss_drv_init(dev, true);
+}
+
+static void dcss_drv_unbind(struct device *dev)
+{
+ return dcss_drv_deinit(dev, true);
+}
+
+static const struct component_master_ops dcss_master_ops = {
+ .bind = dcss_drv_bind,
+ .unbind = dcss_drv_unbind,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
+
+static int dcss_drv_platform_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct component_match *match = NULL;
+ struct device_node *remote;
+
+ if (!dev->of_node)
+ return -ENODEV;
+
+ remote = of_graph_get_remote_node(dev->of_node, 0, 0);
+ if (!remote)
+ return -ENODEV;
+
+ if (of_device_is_compatible(remote, "fsl,imx8mq-nwl-dsi")) {
+ of_node_put(remote);
+ return dcss_drv_init(dev, false);
+ }
+
+ drm_of_component_match_add(dev, &match, compare_of, remote);
+ of_node_put(remote);
+
+ return component_master_add_with_match(dev, &dcss_master_ops, match);
+}
+
+static int dcss_drv_platform_remove(struct platform_device *pdev)
+{
+ struct dcss_drv *mdrv = dev_get_drvdata(&pdev->dev);
+
+ if (mdrv->is_componentized)
+ component_master_del(&pdev->dev, &dcss_master_ops);
+ else
+ dcss_drv_deinit(&pdev->dev, false);
return 0;
}
@@ -12,6 +12,7 @@
#include <drm/drm_of.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
+#include <linux/component.h>
#include "dcss-dev.h"
#include "dcss-kms.h"
@@ -106,7 +107,7 @@ static int dcss_kms_setup_encoder(struct dcss_kms_dev *kms)
return drm_bridge_attach(encoder, bridge, NULL, 0);
}
-struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss)
+struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss, bool componentized)
{
struct dcss_kms_dev *kms;
struct drm_device *drm;
@@ -135,7 +136,11 @@ struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss)
if (ret)
goto cleanup_mode_config;
- ret = dcss_kms_setup_encoder(kms);
+ if (componentized)
+ ret = component_bind_all(dcss->dev, kms);
+ else
+ ret = dcss_kms_setup_encoder(kms);
+
if (ret)
goto cleanup_crtc;
@@ -162,9 +167,10 @@ struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss)
return ERR_PTR(ret);
}
-void dcss_kms_detach(struct dcss_kms_dev *kms)
+void dcss_kms_detach(struct dcss_kms_dev *kms, bool componentized)
{
struct drm_device *drm = &kms->base;
+ struct dcss_dev *dcss = drm->dev_private;
drm_dev_unregister(drm);
drm_kms_helper_poll_fini(drm);
@@ -173,5 +179,7 @@ void dcss_kms_detach(struct dcss_kms_dev *kms)
drm->irq_enabled = false;
drm_mode_config_cleanup(drm);
dcss_crtc_deinit(&kms->crtc, drm);
+ if (componentized)
+ component_unbind_all(dcss->dev, drm);
drm->dev_private = NULL;
}
@@ -31,8 +31,8 @@ struct dcss_kms_dev {
struct drm_encoder encoder;
};
-struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss);
-void dcss_kms_detach(struct dcss_kms_dev *kms);
+struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss, bool componentized);
+void dcss_kms_detach(struct dcss_kms_dev *kms, bool componentized);
int dcss_crtc_init(struct dcss_crtc *crtc, struct drm_device *drm);
void dcss_crtc_deinit(struct dcss_crtc *crtc, struct drm_device *drm);
struct dcss_plane *dcss_plane_init(struct drm_device *drm,