hdmiphy hardware block is a physically separate device. Hdmiphy driver
is glued inside hdmi driver and acessed through hdmi callbacks. With
increasing diversities in the hdmiphy mapping and configurations, hdmi
driver is expanding with un-related changes.

This patch registers hdmiphy as a independent driver, having own set
of requried callbacks which are called by common drm hdmi, parallel to
hdmi and mixer driver.

Signed-off-by: Rahul Sharma <rahul.sha...@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_hdmi.c |   61 +++++++++++++++++++++++++++---
 drivers/gpu/drm/exynos/exynos_drm_hdmi.h |   17 +++++++++
 drivers/gpu/drm/exynos/exynos_hdmi.c     |   26 ++-----------
 drivers/gpu/drm/exynos/exynos_hdmi.h     |    1 -
 drivers/gpu/drm/exynos/exynos_hdmiphy.c  |   13 ++++++-
 5 files changed, 87 insertions(+), 31 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c 
b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index 7ab5f9f..25fe012 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -32,12 +32,14 @@
 /* platform device pointer for common drm hdmi device. */
 static struct platform_device *exynos_drm_hdmi_pdev;
 
-/* Common hdmi subdrv needs to access the hdmi and mixer though context.
-* These should be initialied by the repective drivers */
+/* Common hdmi subdrv needs to access the hdmi, hdmiphy and mixer though
+*  context. These should be initialied by the repective drivers */
+static struct exynos_drm_hdmi_context *hdmiphy_ctx;
 static struct exynos_drm_hdmi_context *hdmi_ctx;
 static struct exynos_drm_hdmi_context *mixer_ctx;
 
 /* these callback points shoud be set by specific drivers. */
+static struct exynos_hdmiphy_ops *hdmiphy_ops;
 static struct exynos_hdmi_ops *hdmi_ops;
 static struct exynos_mixer_ops *mixer_ops;
 
@@ -45,6 +47,7 @@ struct platform_driver exynos_drm_common_hdmi_driver;
 
 struct drm_hdmi_context {
        struct exynos_drm_subdrv        subdrv;
+       struct exynos_drm_hdmi_context  *hdmiphy_ctx;
        struct exynos_drm_hdmi_context  *hdmi_ctx;
        struct exynos_drm_hdmi_context  *mixer_ctx;
 
@@ -59,6 +62,10 @@ int exynos_common_hdmi_register(void)
        if (exynos_drm_hdmi_pdev)
                return -EEXIST;
 
+       ret = exynos_hdmiphy_driver_register();
+       if (ret < 0)
+               goto out_hdmiphy;
+
        ret = platform_driver_register(&hdmi_driver);
        if (ret < 0)
                goto out_hdmi;
@@ -88,6 +95,8 @@ out_common_hdmi:
 out_mixer:
        platform_driver_unregister(&hdmi_driver);
 out_hdmi:
+       exynos_hdmiphy_driver_unregister();
+out_hdmiphy:
        return ret;
 }
 
@@ -99,9 +108,16 @@ void exynos_common_hdmi_unregister(void)
        platform_driver_unregister(&exynos_drm_common_hdmi_driver);
        platform_driver_unregister(&mixer_driver);
        platform_driver_unregister(&hdmi_driver);
+       exynos_hdmiphy_driver_unregister();
        exynos_drm_hdmi_pdev = NULL;
 }
 
+void exynos_hdmiphy_drv_attach(struct exynos_drm_hdmi_context *ctx)
+{
+       if (ctx)
+               hdmiphy_ctx = ctx;
+}
+
 void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx)
 {
        if (ctx)
@@ -114,6 +130,14 @@ void exynos_mixer_drv_attach(struct 
exynos_drm_hdmi_context *ctx)
                mixer_ctx = ctx;
 }
 
+void exynos_hdmiphy_ops_register(struct exynos_hdmiphy_ops *ops)
+{
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       if (ops)
+               hdmiphy_ops = ops;
+}
+
 void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops)
 {
        DRM_DEBUG_KMS("%s\n", __FILE__);
@@ -164,8 +188,8 @@ static int drm_hdmi_check_mode(struct device *dev,
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
        /*
-       * Both, mixer and hdmi should be able to handle the requested mode.
-       * If any of the two fails, return mode as BAD.
+       * Mixer, hdmi and hdmiphy should be able to handle the requested mode.
+       * If any of the them fails, return mode as BAD.
        */
 
        if (mixer_ops && mixer_ops->check_mode)
@@ -175,7 +199,13 @@ static int drm_hdmi_check_mode(struct device *dev,
                return ret;
 
        if (hdmi_ops && hdmi_ops->check_mode)
-               return hdmi_ops->check_mode(ctx->hdmi_ctx->ctx, mode);
+               ret = hdmi_ops->check_mode(ctx->hdmi_ctx->ctx, mode);
+
+       if (ret)
+               return ret;
+
+       if (hdmiphy_ops && hdmiphy_ops->check_mode)
+               return hdmiphy_ops->check_mode(ctx->hdmiphy_ctx->ctx, mode);
 
        return 0;
 }
@@ -289,6 +319,9 @@ static void drm_hdmi_mode_set(struct device *subdrv_dev, 
void *mode)
 
        if (hdmi_ops && hdmi_ops->mode_set)
                hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
+
+       if (hdmiphy_ops && hdmiphy_ops->mode_set)
+               hdmiphy_ops->mode_set(ctx->hdmiphy_ctx->ctx, mode);
 }
 
 static void drm_hdmi_get_max_resol(struct device *subdrv_dev,
@@ -308,6 +341,15 @@ static void drm_hdmi_commit(struct device *subdrv_dev)
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
+       if (hdmiphy_ops && hdmiphy_ops->prepare)
+               hdmiphy_ops->prepare(ctx->hdmiphy_ctx->ctx);
+
+       if (hdmi_ops && hdmi_ops->prepare)
+               hdmi_ops->prepare(ctx->hdmi_ctx->ctx);
+
+       if (hdmiphy_ops && hdmiphy_ops->config_apply)
+               hdmiphy_ops->config_apply(ctx->hdmiphy_ctx->ctx);
+
        if (hdmi_ops && hdmi_ops->commit)
                hdmi_ops->commit(ctx->hdmi_ctx->ctx);
 }
@@ -323,6 +365,9 @@ static void drm_hdmi_dpms(struct device *subdrv_dev, int 
mode)
 
        if (hdmi_ops && hdmi_ops->dpms)
                hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
+
+       if (hdmiphy_ops && hdmiphy_ops->dpms)
+               hdmiphy_ops->dpms(ctx->hdmiphy_ctx->ctx, mode);
 }
 
 static void drm_hdmi_apply(struct device *subdrv_dev)
@@ -428,6 +473,11 @@ static int hdmi_subdrv_probe(struct drm_device *drm_dev,
                return -EFAULT;
        }
 
+       if (!hdmiphy_ctx) {
+               DRM_ERROR("hdmiphy context not initialized.\n");
+               return -EFAULT;
+       }
+
        if (!mixer_ctx) {
                DRM_ERROR("mixer context not initialized.\n");
                return -EFAULT;
@@ -441,6 +491,7 @@ static int hdmi_subdrv_probe(struct drm_device *drm_dev,
        }
 
        ctx->hdmi_ctx = hdmi_ctx;
+       ctx->hdmiphy_ctx = hdmiphy_ctx;
        ctx->mixer_ctx = mixer_ctx;
 
        ctx->hdmi_ctx->drm_dev = drm_dev;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h 
b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
index 8861b90..8c8974f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
@@ -39,10 +39,19 @@ struct exynos_hdmi_ops {
        void (*mode_set)(void *ctx, struct drm_display_mode *mode);
        void (*get_max_resol)(void *ctx, unsigned int *width,
                                unsigned int *height);
+       void (*prepare)(void *ctx);
        void (*commit)(void *ctx);
        void (*dpms)(void *ctx, int mode);
 };
 
+struct exynos_hdmiphy_ops {
+       int (*check_mode)(void *ctx, struct drm_display_mode *mode);
+       void (*mode_set)(void *ctx, struct drm_display_mode *mode);
+       void (*prepare)(void *ctx);
+       int (*config_apply)(void *ctx);
+       void (*dpms)(void *ctx, int mode);
+};
+
 struct exynos_mixer_ops {
        /* manager */
        int (*iommu_on)(void *ctx, bool enable);
@@ -63,8 +72,16 @@ struct exynos_mixer_ops {
 extern struct platform_driver hdmi_driver;
 extern struct platform_driver mixer_driver;
 
+/*
+ * these functions registers/unregisters exynos drm hdmiphy driver.
+ */
+extern int exynos_hdmiphy_driver_register(void);
+extern void exynos_hdmiphy_driver_unregister(void);
+
+void exynos_hdmiphy_drv_attach(struct exynos_drm_hdmi_context *ctx);
 void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx);
 void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx);
+void exynos_hdmiphy_ops_register(struct exynos_hdmiphy_ops *ops);
 void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops);
 void exynos_mixer_ops_register(struct exynos_mixer_ops *ops);
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c 
b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 6bcd7fc..520c4af 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -1856,7 +1856,7 @@ fail:
        return -ENODEV;
 }
 
-static struct i2c_client *hdmi_ddc, *hdmi_hdmiphy;
+static struct i2c_client *hdmi_ddc;
 
 void hdmi_attach_ddc_client(struct i2c_client *ddc)
 {
@@ -1864,12 +1864,6 @@ void hdmi_attach_ddc_client(struct i2c_client *ddc)
                hdmi_ddc = ddc;
 }
 
-void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy)
-{
-       if (hdmiphy)
-               hdmi_hdmiphy = hdmiphy;
-}
-
 #ifdef CONFIG_OF
 static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
                                        (struct device *dev)
@@ -2027,20 +2021,11 @@ static int hdmi_probe(struct platform_device *pdev)
 
        hdata->ddc_port = hdmi_ddc;
 
-       /* hdmiphy i2c driver */
-       if (i2c_add_driver(&hdmiphy_driver)) {
-               DRM_ERROR("failed to register hdmiphy i2c driver\n");
-               ret = -ENOENT;
-               goto err_ddc;
-       }
-
-       hdata->hdmiphy_port = hdmi_hdmiphy;
-
        hdata->irq = gpio_to_irq(hdata->hpd_gpio);
        if (hdata->irq < 0) {
                DRM_ERROR("failed to get GPIO irq\n");
                ret = hdata->irq;
-               goto err_hdmiphy;
+               goto err_ddc;
        }
 
        hdata->hpd = gpio_get_value(hdata->hpd_gpio);
@@ -2051,7 +2036,7 @@ static int hdmi_probe(struct platform_device *pdev)
                        "hdmi", drm_hdmi_ctx);
        if (ret) {
                DRM_ERROR("failed to register hdmi interrupt\n");
-               goto err_hdmiphy;
+               goto err_ddc;
        }
 
        /* Attach HDMI Driver to common hdmi. */
@@ -2064,8 +2049,6 @@ static int hdmi_probe(struct platform_device *pdev)
 
        return 0;
 
-err_hdmiphy:
-       i2c_del_driver(&hdmiphy_driver);
 err_ddc:
        i2c_del_driver(&ddc_driver);
        return ret;
@@ -2083,9 +2066,6 @@ static int hdmi_remove(struct platform_device *pdev)
 
        free_irq(hdata->irq, hdata);
 
-
-       /* hdmiphy i2c driver */
-       i2c_del_driver(&hdmiphy_driver);
        /* DDC i2c driver */
        i2c_del_driver(&ddc_driver);
 
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.h 
b/drivers/gpu/drm/exynos/exynos_hdmi.h
index 0ddf395..6595d7b 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.h
@@ -15,7 +15,6 @@
 #define _EXYNOS_HDMI_H_
 
 void hdmi_attach_ddc_client(struct i2c_client *ddc);
-void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy);
 
 extern struct i2c_driver hdmiphy_driver;
 extern struct i2c_driver ddc_driver;
diff --git a/drivers/gpu/drm/exynos/exynos_hdmiphy.c 
b/drivers/gpu/drm/exynos/exynos_hdmiphy.c
index ea49d13..eee2510 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmiphy.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmiphy.c
@@ -24,8 +24,6 @@
 static int hdmiphy_probe(struct i2c_client *client,
        const struct i2c_device_id *id)
 {
-       hdmi_attach_hdmiphy_client(client);
-
        dev_info(&client->adapter->dev, "attached s5p_hdmiphy "
                "into i2c adapter successfully\n");
 
@@ -67,4 +65,15 @@ struct i2c_driver hdmiphy_driver = {
        .remove         = hdmiphy_remove,
        .command                = NULL,
 };
+
+extern int exynos_hdmiphy_driver_register(void)
+{
+       return i2c_add_driver(&hdmiphy_driver);
+}
+
+extern void exynos_hdmiphy_driver_unregister(void)
+{
+       i2c_del_driver(&hdmiphy_driver);
+}
+
 EXPORT_SYMBOL(hdmiphy_driver);
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to