On Mon, Apr 29, 2013 at 10:50 AM, Rahul Sharma <rahul.sha...@samsung.com> wrote: > 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 */
Doesn't conform with Documentation/CodingStyle & s/initialied/initialized/ & s/repective/respective/ > +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; This isn't consistent with your last patch. In that patch, you exposed the driver directly through exynos_drm_hdmi.h and registered the driver directly. Here, you expose a helper function to do it for you. These should at least work the same way. > + > 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; > +} > + I think I've said this before, but in case I haven't, here it goes. If you didn't platform_driverize all of this stuff, and instead encapsulated the various functionality in callbacks central to one drm driver, you wouldn't need to do this kind of thing. > 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); > + This is a hack. You have a stubbed out exynos_drm_encoder_prepare function in exynos_drm_connector.c that exists entirely for this purpose. > + if (hdmiphy_ops && hdmiphy_ops->config_apply) > + hdmiphy_ops->config_apply(ctx->hdmiphy_ctx->ctx); Why name it config_apply instead of commit? > + > 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); Shouldn't the order of this be dependent on dpms mode? ie for DPMS_ON do hdmi->dpms then phy->dpms and for DPMS_OFF do phy->dpms then hdmi->dpms > } > > 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; EFAULT is the wrong error to return here. ENODEV would be more appropriate, IMO. > + } > + > 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. > + */ I think this comment is kind of obvious and unneeded, but if you think it's useful, it should only take up one line. > +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; This can be removed if you're using the register/unregister helpers. > 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); You don't need to export it if you're using these helpers. > -- > 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