[PATCH RFC] drm/exynos: hdmi: move hdmiphy related code to hdmiphy driver

Inki Dae inki.dae at samsung.com
Tue Mar 12 05:07:00 PDT 2013


2013/3/12 Rahul Sharma <r.sh.open at gmail.com>:
> On Mon, Mar 4, 2013 at 7:35 PM, Rahul Sharma <r.sh.open at gmail.com> wrote:
>> Thanks Sean,
>>
>> On Wed, Feb 27, 2013 at 9:47 PM, Sean Paul <seanpaul at google.com> wrote:
>>> On Wed, Feb 27, 2013 at 8:22 AM, Rahul Sharma <rahul.sharma at samsung.com> wrote:
>>>> Right now hdmiphy operations and configs are kept inside hdmi driver. hdmiphy related
>>>> code is tightly coupled with hdmi ip driver. Physicaly they are different devices and
>>>
>>> s/Physicaly/Physically/
>>>
>>>> should be instantiated independently.
>>>>
>>>> In terms of versions/mapping/configurations Hdmi and hdmiphy are independent of each
>>>> other. It is preferred to isolate them and maintained independently.
>>>>
>>>> This implementations is tested for:
>>>> 1) Resolutions supported by exynos4 and 5 hdmi.
>>>> 2) Runtime PM and S2R scenarions for exynos5.
>>>>
>>>
>>> I don't like the idea of spawning off yet another driver in here. It
>>> adds more globals, more suspend/resume ordering issues, and more
>>> implicit dependencies. I understand, however, that this is the Chosen
>>> Way for the exynos driver, so I will save my rant.
>>>
>>
>> I agree to it. splitting phy to a new driver will complicate the power related
>> scenarios. But in upcoming SoC,s, Phy is changing considerably in terms of
>> config values, mapping (i2c/platform bus) etc. Handling this diversity
>> inside hdmi driver is complicating it with unrelated changes.
>>
>> I have tested this RFC for Runtime PM / S2R. But if we see any major roadblock
>> we should re-factor this by explicitly calling power related callbacks
>> of mixer, phy,
>> hdmi drivers in a required order. We can call them from exynos-drm-hdmi plf
>> device. AFAIR something like this is already in place in chrome-kernel.
>>
>>> I've made some comments below.
>>>
>>>> This patch is dependent on
>>>> http://www.mail-archive.com/dri-devel@lists.freedesktop.org/msg34733.html
>>>> http://www.mail-archive.com/dri-devel@lists.freedesktop.org/msg34861.html
>>>> http://www.mail-archive.com/dri-devel@lists.freedesktop.org/msg34862.html
>>>>
>>>> Signed-off-by: Rahul Sharma <rahul.sharma at samsung.com>
>>>> ---
>>>> It is based on exynos-drm-next-todo branch at
>>>> git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos.git
>>>>
>>>>  drivers/gpu/drm/exynos/exynos_drm_drv.c  |   8 +
>>>>  drivers/gpu/drm/exynos/exynos_drm_drv.h  |   6 +
>>>>  drivers/gpu/drm/exynos/exynos_drm_hdmi.c |  58 ++-
>>>>  drivers/gpu/drm/exynos/exynos_drm_hdmi.h |  11 +
>>>>  drivers/gpu/drm/exynos/exynos_hdmi.c     | 375 ++------------------
>>>>  drivers/gpu/drm/exynos/exynos_hdmi.h     |   1 -
>>>>  drivers/gpu/drm/exynos/exynos_hdmiphy.c  | 586 ++++++++++++++++++++++++++++++-
>>>>  drivers/gpu/drm/exynos/regs-hdmiphy.h    |  61 ++++
>>>>  8 files changed, 738 insertions(+), 368 deletions(-)
>>>>  create mode 100644 drivers/gpu/drm/exynos/regs-hdmiphy.h
>>>>
>>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
>>>> index 3da5c2d..03acb6b 100644
>>>> --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
>>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
>>>> @@ -334,6 +334,11 @@ static int __init exynos_drm_init(void)
>>>>         ret = platform_driver_register(&hdmi_driver);
>>>>         if (ret < 0)
>>>>                 goto out_hdmi;
>>>> +
>>>> +       ret = exynos_hdmiphy_driver_register();
>>>
>>> Not sure why you need to obfuscate the type of driver here. All the
>>> other ones are directly registered as platform drivers, I don't see
>>> the harm in just doing the i2c_add_driver directly here.
>>>
>>
>> AIMB, Phy is likely to get mapped as a platform device in later soc's.
>> I want to make driver registration (inside exynos_drm_drv.c) independent
>> of this changes. We can handle this inside exynos_hdmiphy_driver_register().
>>
>>>> +       if (ret < 0)
>>>> +               goto out_hdmiphy;
>>>> +
>>>>         ret = platform_driver_register(&mixer_driver);
>>>>         if (ret < 0)
>>>>                 goto out_mixer;
>>>
>>>
>>> I think this ordering is how you plan on enforcing the suspend/resume
>>> order for hdmi/mixer/hdmiphy. In that case, however, I don't think it
>>> makes sense to suspend/resume hdmiphy in between mixer and hdmi.
>>> Ideally, hdmiphy should go down first and come up last.
>>>
>>
>> I just wanted to keep, hdmi and hdmiphy things together. But what you said
>> above makes sense. I will do that change.
>>
>>>
>>>> @@ -436,6 +441,8 @@ out_common_hdmi_dev:
>>>>  out_common_hdmi:
>>>>         platform_driver_unregister(&mixer_driver);
>>>>  out_mixer:
>>>> +       exynos_hdmiphy_driver_unregister();
>>>> +out_hdmiphy:
>>>>         platform_driver_unregister(&hdmi_driver);
>>>>  out_hdmi:
>>>>  #endif
>>>> @@ -479,6 +486,7 @@ static void __exit exynos_drm_exit(void)
>>>>         exynos_platform_device_hdmi_unregister();
>>>>         platform_driver_unregister(&exynos_drm_common_hdmi_driver);
>>>>         platform_driver_unregister(&mixer_driver);
>>>> +       exynos_hdmiphy_driver_unregister();
>>>>         platform_driver_unregister(&hdmi_driver);
>>>>  #endif
>>>>
>>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
>>>> index 4606fac..17c53e3 100644
>>>> --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
>>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
>>>> @@ -325,6 +325,12 @@ void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
>>>>  extern int exynos_platform_device_hdmi_register(void);
>>>>
>>>>  /*
>>>> + * these functions registers/unregisters exynos drm hdmiphy driver.
>>>> + */
>>>> +extern int exynos_hdmiphy_driver_register(void);
>>>> +extern void exynos_hdmiphy_driver_unregister(void);
>>>> +
>>>> +/*
>>>>   * this function unregisters exynos drm hdmi platform device if it exists.
>>>>   */
>>>>  void exynos_platform_device_hdmi_unregister(void);
>>>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
>>>> index 5dc956b..45ef331 100644
>>>> --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
>>>> +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
>>>> @@ -32,19 +32,22 @@
>>>>  /* 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 *hdmi_ctx;
>>>> +static struct exynos_drm_hdmi_context *hdmiphy_ctx;
>>>>  static struct exynos_drm_hdmi_context *mixer_ctx;
>>>>
>>>>  /* these callback points shoud be set by specific drivers. */
>>>>  static struct exynos_hdmi_ops *hdmi_ops;
>>>> +static struct exynos_hdmiphy_ops *hdmiphy_ops;
>>>>  static struct exynos_mixer_ops *mixer_ops;
>>>>
>>>
>>> This stuff really sets my teeth on edge. I can't stand these global
>>> variables and the set-here, set-there, set-here dance that is done on
>>> probe.
>>>
>>> IMO, this and the suspend/resume ordering should be enough motivation
>>> to avoid separating everything out into their own drivers.
>>>
>>> Instead of adding more kruft to this list, we should be working to remove it.
>>>
>>> /rant
>>>
>>
>> Let me think over it. Please suggest me something if you have any idea to
>> correct this.
>>
>
> Hi all,
>
> I replaced these variables with a global LIST of subdrv's with associated
> type (HDMI / PHY / MIXER) and ops struct.
>
> drm-common-hdmi callback will parse this list and based on the subdrv
> type calls subdrv functions, but this adds overhead of parsing the list
> multiple times.
>
> If I cache the subdrvs in drm-common-hdmi context and parsing of the list
> can be avoided.
>
> What you think about above approach?
>

I think it's good to use existing exynos drm core framework. But I'm
anxious about probing point and existing subdrv callbacks with this.
Could you share that patch as RFC?

Thanks,
Inki Dae

> regards,
> Rahul Sharma.
>
>>>>  struct drm_hdmi_context {
>>>>         struct exynos_drm_subdrv        subdrv;
>>>>         struct exynos_drm_hdmi_context  *hdmi_ctx;
>>>>         struct exynos_drm_hdmi_context  *mixer_ctx;
>>>> +       struct exynos_drm_hdmi_context  *hdmiphy_ctx;
>>>>
>>>>         bool    enabled[MIXER_WIN_NR];
>>>>  };
>>>> @@ -74,6 +77,12 @@ void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx)
>>>>                 hdmi_ctx = ctx;
>>>>  }
>>>>
>>>> +void exynos_hdmiphy_drv_attach(struct exynos_drm_hdmi_context *ctx)
>>>> +{
>>>> +       if (ctx)
>>>> +               hdmiphy_ctx = ctx;
>>>> +}
>>>> +
>>>>  void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx)
>>>>  {
>>>>         if (ctx)
>>>> @@ -88,6 +97,14 @@ void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops)
>>>>                 hdmi_ops = ops;
>>>>  }
>>>>
>>>> +void exynos_hdmiphy_ops_register(struct exynos_hdmiphy_ops *ops)
>>>> +{
>>>> +       DRM_DEBUG_KMS("%s\n", __FILE__);
>>>
>>> Listing __FILE__ in these DRM_DEBUG_KMS traces is pretty useless. I'm
>>> sure we can determine the file from the function name. It would be
>>> slightly more useful to list __LINE__, but even more useful if you
>>> actually printed state relevant to the current function.
>>>
>>
>> OK. I will correct this.
>>
>>>> +
>>>> +       if (ops)
>>>> +               hdmiphy_ops = ops;
>>>> +}
>>>> +
>>>>  void exynos_mixer_ops_register(struct exynos_mixer_ops *ops)
>>>>  {
>>>>         DRM_DEBUG_KMS("%s\n", __FILE__);
>>>> @@ -121,7 +138,7 @@ struct edid *drm_hdmi_get_edid(struct device *dev,
>>>>         return NULL;
>>>>  }
>>>>
>>>> -static int drm_hdmi_check_timing(struct device *dev, void *timing)
>>>> +static int drm_hdmi_check_timing(struct device *dev, void *mode)
>>>>  {
>>>>         struct drm_hdmi_context *ctx = to_context(dev);
>>>>         int ret = 0;
>>>> @@ -129,18 +146,24 @@ static int drm_hdmi_check_timing(struct device *dev, void *timing)
>>>>         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_timing)
>>>> -               ret = mixer_ops->check_timing(ctx->mixer_ctx->ctx, timing);
>>>> +               ret = mixer_ops->check_timing(ctx->mixer_ctx->ctx, mode);
>>>>
>>>>         if (ret)
>>>>                 return ret;
>>>>
>>>>         if (hdmi_ops && hdmi_ops->check_timing)
>>>> -               return hdmi_ops->check_timing(ctx->hdmi_ctx->ctx, timing);
>>>> +               ret = hdmi_ops->check_timing(ctx->hdmi_ctx->ctx, mode);
>>>> +
>>>> +       if (ret)
>>>> +               return ret;
>>>> +
>>>> +       if (hdmiphy_ops && hdmiphy_ops->check_timing)
>>>> +               return hdmiphy_ops->check_timing(ctx->hdmiphy_ctx->ctx, mode);
>>>>
>>>>         return 0;
>>>>  }
>>>> @@ -254,6 +277,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,
>>>> @@ -273,6 +299,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);
>>>> +
>>>
>>> Why are you calling these prepare functions in commit? Isn't that
>>> precisely the reason drm has a prepare callback?
>>
>> True. Currently exynos_drm_encoder_prepare is blank. I will move this to
>> prepare callback.
>>
>>>
>>>> +       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);
>>>>  }
>>>> @@ -288,6 +323,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);
>>>
>>> I think you have to be more careful about the ordering of things here
>>> since you'll want to power on in a different order than you power off.
>>>
>>>>  }
>>>>
>>>>  static void drm_hdmi_apply(struct device *subdrv_dev)
>>>> @@ -393,6 +431,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;
>>>> @@ -406,6 +449,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 fd2ff9f..10db62e 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_timing)(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);
>>>> @@ -61,7 +70,9 @@ struct exynos_mixer_ops {
>>>>  };
>>>>
>>>>  void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx);
>>>> +void exynos_hdmiphy_drv_attach(struct exynos_drm_hdmi_context *ctx);
>>>>  void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx);
>>>>  void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops);
>>>> +void exynos_hdmiphy_ops_register(struct exynos_hdmiphy_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 a5ca2cc..7ee350d 100644
>>>> --- a/drivers/gpu/drm/exynos/exynos_hdmi.c
>>>> +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
>>>> @@ -194,7 +194,6 @@ struct hdmi_context {
>>>>         int                             internal_irq;
>>>>
>>>>         struct i2c_client               *ddc_port;
>>>> -       struct i2c_client               *hdmiphy_port;
>>>>
>>>>         /* current hdmiphy conf regs */
>>>>         struct hdmi_conf_regs           mode_conf;
>>>> @@ -206,180 +205,6 @@ struct hdmi_context {
>>>>         enum hdmi_type                  type;
>>>>  };
>>>>
>>>> -struct hdmiphy_config {
>>>> -       int pixel_clock;
>>>> -       u8 conf[32];
>>>> -};
>>>> -
>>>> -/* list of phy config settings */
>>>> -static const struct hdmiphy_config hdmiphy_v13_configs[] = {
>>>> -       {
>>>> -               .pixel_clock = 27000000,
>>>> -               .conf = {
>>>> -                       0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
>>>> -                       0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
>>>> -                       0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
>>>> -                       0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
>>>> -               },
>>>> -       },
>>>> -       {
>>>> -               .pixel_clock = 27027000,
>>>> -               .conf = {
>>>> -                       0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
>>>> -                       0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
>>>> -                       0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
>>>> -                       0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
>>>> -               },
>>>> -       },
>>>> -       {
>>>> -               .pixel_clock = 74176000,
>>>> -               .conf = {
>>>> -                       0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
>>>> -                       0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
>>>> -                       0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
>>>> -                       0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
>>>> -               },
>>>> -       },
>>>> -       {
>>>> -               .pixel_clock = 74250000,
>>>> -               .conf = {
>>>> -                       0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
>>>> -                       0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
>>>> -                       0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
>>>> -                       0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
>>>> -               },
>>>> -       },
>>>> -       {
>>>> -               .pixel_clock = 148500000,
>>>> -               .conf = {
>>>> -                       0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
>>>> -                       0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
>>>> -                       0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
>>>> -                       0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
>>>> -               },
>>>> -       },
>>>> -};
>>>> -
>>>> -static const struct hdmiphy_config hdmiphy_v14_configs[] = {
>>>> -       {
>>>> -               .pixel_clock = 25200000,
>>>> -               .conf = {
>>>> -                       0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
>>>> -                       0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
>>>> -                       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> -                       0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
>>>> -               },
>>>> -       },
>>>> -       {
>>>> -               .pixel_clock = 27000000,
>>>> -               .conf = {
>>>> -                       0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
>>>> -                       0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
>>>> -                       0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> -                       0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
>>>> -               },
>>>> -       },
>>>> -       {
>>>> -               .pixel_clock = 27027000,
>>>> -               .conf = {
>>>> -                       0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
>>>> -                       0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
>>>> -                       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> -                       0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
>>>> -               },
>>>> -       },
>>>> -       {
>>>> -               .pixel_clock = 36000000,
>>>> -               .conf = {
>>>> -                       0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
>>>> -                       0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
>>>> -                       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> -                       0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
>>>> -               },
>>>> -       },
>>>> -       {
>>>> -               .pixel_clock = 40000000,
>>>> -               .conf = {
>>>> -                       0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
>>>> -                       0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
>>>> -                       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> -                       0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
>>>> -               },
>>>> -       },
>>>> -       {
>>>> -               .pixel_clock = 65000000,
>>>> -               .conf = {
>>>> -                       0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
>>>> -                       0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
>>>> -                       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> -                       0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
>>>> -               },
>>>> -       },
>>>> -       {
>>>> -               .pixel_clock = 74176000,
>>>> -               .conf = {
>>>> -                       0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
>>>> -                       0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
>>>> -                       0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> -                       0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
>>>> -               },
>>>> -       },
>>>> -       {
>>>> -               .pixel_clock = 74250000,
>>>> -               .conf = {
>>>> -                       0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
>>>> -                       0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
>>>> -                       0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> -                       0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
>>>> -               },
>>>> -       },
>>>> -       {
>>>> -               .pixel_clock = 83500000,
>>>> -               .conf = {
>>>> -                       0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
>>>> -                       0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
>>>> -                       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> -                       0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
>>>> -               },
>>>> -       },
>>>> -       {
>>>> -               .pixel_clock = 106500000,
>>>> -               .conf = {
>>>> -                       0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
>>>> -                       0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
>>>> -                       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> -                       0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
>>>> -               },
>>>> -       },
>>>> -       {
>>>> -               .pixel_clock = 108000000,
>>>> -               .conf = {
>>>> -                       0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
>>>> -                       0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
>>>> -                       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> -                       0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
>>>> -               },
>>>> -       },
>>>> -       {
>>>> -               .pixel_clock = 146250000,
>>>> -               .conf = {
>>>> -                       0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
>>>> -                       0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
>>>> -                       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> -                       0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
>>>> -               },
>>>> -       },
>>>> -       {
>>>> -               .pixel_clock = 148500000,
>>>> -               .conf = {
>>>> -                       0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
>>>> -                       0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
>>>> -                       0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> -                       0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
>>>> -               },
>>>> -       },
>>>> -};
>>>> -
>>>>  struct hdmi_infoframe {
>>>>         enum HDMI_PACKET_TYPE type;
>>>>         u8 ver;
>>>> @@ -774,46 +599,6 @@ static struct edid *hdmi_get_edid(void *ctx, struct drm_connector *connector)
>>>>         return raw_edid;
>>>>  }
>>>>
>>>> -static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
>>>> -{
>>>> -       const struct hdmiphy_config *confs;
>>>> -       int count, i;
>>>> -
>>>> -       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
>>>> -
>>>> -       if (hdata->type == HDMI_TYPE13) {
>>>> -               confs = hdmiphy_v13_configs;
>>>> -               count = ARRAY_SIZE(hdmiphy_v13_configs);
>>>> -       } else if (hdata->type == HDMI_TYPE14) {
>>>> -               confs = hdmiphy_v14_configs;
>>>> -               count = ARRAY_SIZE(hdmiphy_v14_configs);
>>>> -       } else
>>>> -               return -EINVAL;
>>>> -
>>>> -       for (i = 0; i < count; i++)
>>>> -               if (confs[i].pixel_clock == pixel_clock)
>>>> -                       return i;
>>>> -
>>>> -       DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
>>>> -       return -EINVAL;
>>>> -}
>>>> -
>>>> -static int hdmi_check_timing(void *ctx, struct drm_display_mode *mode)
>>>> -{
>>>> -       struct hdmi_context *hdata = ctx;
>>>> -       int ret;
>>>> -
>>>> -       DRM_DEBUG_KMS("%s : xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
>>>> -               __func__, mode->hdisplay, mode->vdisplay,
>>>> -               mode->vrefresh, (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
>>>> -               false, mode->clock * 1000);
>>>> -
>>>> -       ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
>>>> -       if (ret < 0)
>>>> -               return ret;
>>>> -       return 0;
>>>> -}
>>>> -
>>>>  static void hdmi_set_acr(u32 freq, u8 *acr)
>>>>  {
>>>>         u32 n, cts;
>>>> @@ -1309,20 +1094,12 @@ static void hdmi_timing_apply(struct hdmi_context *hdata)
>>>>
>>>>  static void hdmiphy_conf_reset(struct hdmi_context *hdata)
>>>>  {
>>>> -       u8 buffer[2];
>>>>         u32 reg;
>>>>
>>>>         clk_disable(hdata->res.sclk_hdmi);
>>>>         clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_pixel);
>>>>         clk_enable(hdata->res.sclk_hdmi);
>>>>
>>>> -       /* operation mode */
>>>> -       buffer[0] = 0x1f;
>>>> -       buffer[1] = 0x00;
>>>> -
>>>> -       if (hdata->hdmiphy_port)
>>>> -               i2c_master_send(hdata->hdmiphy_port, buffer, 2);
>>>> -
>>>>         if (hdata->type == HDMI_TYPE13)
>>>>                 reg = HDMI_V13_PHY_RSTOUT;
>>>>         else
>>>> @@ -1335,102 +1112,6 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata)
>>>>         usleep_range(10000, 12000);
>>>>  }
>>>>
>>>> -static void hdmiphy_poweron(struct hdmi_context *hdata)
>>>> -{
>>>> -       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
>>>> -
>>>> -       if (hdata->type == HDMI_TYPE14)
>>>> -               hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0,
>>>> -                       HDMI_PHY_POWER_OFF_EN);
>>>> -}
>>>> -
>>>> -static void hdmiphy_poweroff(struct hdmi_context *hdata)
>>>> -{
>>>> -       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
>>>> -
>>>> -       if (hdata->type == HDMI_TYPE14)
>>>> -               hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0,
>>>> -                       HDMI_PHY_POWER_OFF_EN);
>>>
>>> I assume these register writes are replaced with i2c operations in the
>>> new phy driver?
>>
>> It is done for exynos5 phy. I am not having the sequence for exynos4. I
>> will add it later.
>>
>>>
>>>> -}
>>>> -
>>>> -static void hdmiphy_conf_apply(struct hdmi_context *hdata)
>>>> -{
>>>> -       const u8 *hdmiphy_data;
>>>> -       u8 buffer[32];
>>>> -       u8 operation[2];
>>>> -       u8 read_buffer[32] = {0, };
>>>> -       int ret;
>>>> -       int i;
>>>> -
>>>> -       if (!hdata->hdmiphy_port) {
>>>> -               DRM_ERROR("hdmiphy is not attached\n");
>>>> -               return;
>>>> -       }
>>>> -
>>>> -       /* pixel clock */
>>>> -       i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
>>>> -       if (i < 0) {
>>>> -               DRM_ERROR("failed to find hdmiphy conf\n");
>>>> -               return;
>>>> -       }
>>>> -
>>>> -       if (hdata->type == HDMI_TYPE13) {
>>>> -               hdmiphy_data = hdmiphy_v13_configs[i].conf;
>>>> -       } else {
>>>> -               hdmiphy_data = hdmiphy_v14_configs[i].conf;
>>>> -       }
>>>> -
>>>> -       memcpy(buffer, hdmiphy_data, 32);
>>>> -       ret = i2c_master_send(hdata->hdmiphy_port, buffer, 32);
>>>> -       if (ret != 32) {
>>>> -               DRM_ERROR("failed to configure HDMIPHY via I2C\n");
>>>> -               return;
>>>> -       }
>>>> -
>>>> -       usleep_range(10000, 12000);
>>>> -
>>>> -       /* operation mode */
>>>> -       operation[0] = 0x1f;
>>>> -       operation[1] = 0x80;
>>>> -
>>>> -       ret = i2c_master_send(hdata->hdmiphy_port, operation, 2);
>>>> -       if (ret != 2) {
>>>> -               DRM_ERROR("failed to enable hdmiphy\n");
>>>> -               return;
>>>> -       }
>>>> -
>>>> -       ret = i2c_master_recv(hdata->hdmiphy_port, read_buffer, 32);
>>>> -       if (ret < 0) {
>>>> -               DRM_ERROR("failed to read hdmiphy config\n");
>>>> -               return;
>>>> -       }
>>>> -
>>>> -       for (i = 0; i < ret; i++)
>>>> -               DRM_DEBUG_KMS("hdmiphy[0x%02x] write[0x%02x] - "
>>>> -                       "recv [0x%02x]\n", i, buffer[i], read_buffer[i]);
>>>> -}
>>>> -
>>>> -static void hdmi_conf_apply(struct hdmi_context *hdata)
>>>> -{
>>>> -       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
>>>> -
>>>> -       hdmiphy_conf_reset(hdata);
>>>> -       hdmiphy_conf_apply(hdata);
>>>> -
>>>> -       mutex_lock(&hdata->hdmi_mutex);
>>>> -       hdmi_conf_reset(hdata);
>>>> -       hdmi_conf_init(hdata);
>>>> -       mutex_unlock(&hdata->hdmi_mutex);
>>>> -
>>>> -       hdmi_audio_init(hdata);
>>>> -
>>>> -       /* setting core registers */
>>>> -       hdmi_timing_apply(hdata);
>>>> -       hdmi_audio_control(hdata, true);
>>>> -
>>>> -       hdmi_regs_dump(hdata, "start");
>>>> -}
>>>> -
>>>>  static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
>>>>  {
>>>>         int i;
>>>> @@ -1448,7 +1129,6 @@ static void hdmi_v13_mode_set(struct hdmi_context *hdata,
>>>>
>>>>         hdata->mode_conf.cea_video_id =
>>>>                 drm_match_cea_mode((struct drm_display_mode *)m);
>>>> -       hdata->mode_conf.pixel_clock = m->clock * 1000;
>>>
>>> I don't think you use pixel_clock in mode_conf any longer, please
>>> remove it from the struct.
>>>
>>
>> Correct. I will remove pixel_clock from struct hdmi_conf_regs.
>>
>>>>
>>>>         hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
>>>>         hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
>>>> @@ -1544,7 +1224,6 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata,
>>>>
>>>>         hdata->mode_conf.cea_video_id =
>>>>                 drm_match_cea_mode((struct drm_display_mode *)m);
>>>> -       hdata->mode_conf.pixel_clock = m->clock * 1000;
>>>>
>>>>         hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
>>>>         hdmi_set_reg(core->v_line, 2, m->vtotal);
>>>> @@ -1670,13 +1349,32 @@ static void hdmi_get_max_resol(void *ctx, unsigned int *width,
>>>>         *height = MAX_HEIGHT;
>>>>  }
>>>>
>>>> +static void hdmi_commit_prepare(void *ctx)
>>>
>>> I don't know why the "_commit" is there, just hdmi_prepare will be fine.
>>>
>> Ok.
>>
>>>> +{
>>>> +       struct hdmi_context *hdata = ctx;
>>>> +       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
>>>> +
>>>> +       hdmiphy_conf_reset(hdata);
>>>
>>> There's still phy-specific kruft laying around the driver. There are
>>> now a bunch of implicit dependencies between the hdmi driver and the
>>> hdmiphy driver.
>>>
>>
>> I need to follow this sequence:
>>
>> phy off (hdmiphy_prepare) -> phy reset using HDMI IP REG (hdmi_prepare) ->
>> phy config (hdmiphy_config_apply) -> hdmi ip config  (hdmi_commit)
>>
>> Phy reset needs to be done by toggling Phy_reset bit in HDMI IP register which
>> cannot be accessed in hdmiphy driver. I didn't see any better way.
>>
>>> Another example is the sclk_hdmiphy clock, which is still controlled
>>> by the hdmi driver, it should be controlled by the phy.
>>>
>>
>> sclk_hdmiphy is one of the source clock for hdmi IP. HDMI IP needs to change the
>> source between sclk_hdmiphy (only if stable) else pixel clock. Above
>> code looks ok
>> to me. Please explain a bit mode on this.
>>
>>>> +}
>>>> +
>>>>  static void hdmi_commit(void *ctx)
>>>>  {
>>>>         struct hdmi_context *hdata = ctx;
>>>>
>>>>         DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
>>>>
>>>> -       hdmi_conf_apply(hdata);
>>>> +       mutex_lock(&hdata->hdmi_mutex);
>>>> +       hdmi_conf_reset(hdata);
>>>> +       hdmi_conf_init(hdata);
>>>> +       mutex_unlock(&hdata->hdmi_mutex);
>>>> +
>>>> +       hdmi_audio_init(hdata);
>>>> +
>>>> +       /* setting core registers */
>>>> +       hdmi_timing_apply(hdata);
>>>> +       hdmi_audio_control(hdata, true);
>>>> +
>>>> +       hdmi_regs_dump(hdata, "start");
>>>>  }
>>>>
>>>>  static void hdmi_poweron(struct hdmi_context *hdata)
>>>> @@ -1699,8 +1397,6 @@ static void hdmi_poweron(struct hdmi_context *hdata)
>>>>         clk_enable(res->hdmiphy);
>>>>         clk_enable(res->hdmi);
>>>>         clk_enable(res->sclk_hdmi);
>>>> -
>>>> -       hdmiphy_poweron(hdata);
>>>>  }
>>>>
>>>>  static void hdmi_poweroff(struct hdmi_context *hdata)
>>>> @@ -1719,7 +1415,6 @@ static void hdmi_poweroff(struct hdmi_context *hdata)
>>>>          * its reset state seems to meet the condition.
>>>>          */
>>>>         hdmiphy_conf_reset(hdata);
>>>> -       hdmiphy_poweroff(hdata);
>>>>
>>>>         clk_disable(res->sclk_hdmi);
>>>>         clk_disable(res->hdmi);
>>>> @@ -1761,11 +1456,11 @@ static struct exynos_hdmi_ops hdmi_ops = {
>>>>         /* display */
>>>>         .is_connected   = hdmi_is_connected,
>>>>         .get_edid       = hdmi_get_edid,
>>>> -       .check_timing   = hdmi_check_timing,
>>>>
>>>>         /* manager */
>>>>         .mode_set       = hdmi_mode_set,
>>>>         .get_max_resol  = hdmi_get_max_resol,
>>>> +       .prepare                = hdmi_commit_prepare,
>>>>         .commit         = hdmi_commit,
>>>>         .dpms           = hdmi_dpms,
>>>>  };
>>>> @@ -1878,7 +1573,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)
>>>>  {
>>>> @@ -1886,12 +1581,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)
>>>> @@ -2051,27 +1740,18 @@ 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->external_irq = gpio_to_irq(hdata->hpd_gpio);
>>>>         if (hdata->external_irq < 0) {
>>>>                 DRM_ERROR("failed to get GPIO external irq\n");
>>>>                 ret = hdata->external_irq;
>>>> -               goto err_hdmiphy;
>>>> +               goto err_ddc;
>>>>         }
>>>>
>>>>         hdata->internal_irq = platform_get_irq(pdev, 0);
>>>>         if (hdata->internal_irq < 0) {
>>>>                 DRM_ERROR("failed to get platform internal irq\n");
>>>>                 ret = hdata->internal_irq;
>>>> -               goto err_hdmiphy;
>>>> +               goto err_ddc;
>>>>         }
>>>>
>>>>         hdata->hpd = gpio_get_value(hdata->hpd_gpio);
>>>> @@ -2082,7 +1762,7 @@ static int hdmi_probe(struct platform_device *pdev)
>>>>                         "hdmi_external", drm_hdmi_ctx);
>>>>         if (ret) {
>>>>                 DRM_ERROR("failed to register hdmi external interrupt\n");
>>>> -               goto err_hdmiphy;
>>>> +               goto err_ddc;
>>>>         }
>>>>
>>>>         ret = request_threaded_irq(hdata->internal_irq, NULL,
>>>> @@ -2105,8 +1785,6 @@ static int hdmi_probe(struct platform_device *pdev)
>>>>
>>>>  err_free_irq:
>>>>         free_irq(hdata->external_irq, drm_hdmi_ctx);
>>>> -err_hdmiphy:
>>>> -       i2c_del_driver(&hdmiphy_driver);
>>>>  err_ddc:
>>>>         i2c_del_driver(&ddc_driver);
>>>>         return ret;
>>>> @@ -2125,9 +1803,6 @@ static int hdmi_remove(struct platform_device *pdev)
>>>>         free_irq(hdata->internal_irq, hdata);
>>>>         free_irq(hdata->external_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..0d47302 100644
>>>> --- a/drivers/gpu/drm/exynos/exynos_hdmiphy.c
>>>> +++ b/drivers/gpu/drm/exynos/exynos_hdmiphy.c
>>>> @@ -16,33 +16,437 @@
>>>>  #include <linux/kernel.h>
>>>>  #include <linux/i2c.h>
>>>>  #include <linux/module.h>
>>>> +#include <linux/pm_runtime.h>
>>>> +#include <linux/clk.h>
>>>>
>>>>  #include "exynos_drm_drv.h"
>>>> +#include "exynos_drm_hdmi.h"
>>>>  #include "exynos_hdmi.h"
>>>>
>>>> +#include "regs-hdmiphy.h"
>>>>
>>>> -static int hdmiphy_probe(struct i2c_client *client,
>>>> -       const struct i2c_device_id *id)
>>>> +#define HDMIPHY_REG_COUNT              (32)
>>>
>>> No need to include parentheses.
>>
>> Ok.
>>>
>>>> +
>>>> +enum hdmiphy_type {
>>>> +       HDMIPHY_EXYNOS4210,
>>>> +       HDMIPHY_EXYNOS4212,
>>>> +};
>>>> +
>>>> +struct hdmiphy_context {
>>>> +       struct device           *dev;
>>>> +       bool                    powered;
>>>> +       void                    *parent_ctx;
>>>> +       enum hdmiphy_type               type;
>>>> +       const struct hdmiphy_config     *conf;
>>>> +       struct clk              *hdmiphy;
>>>> +};
>>>> +
>>>> +struct hdmiphy_config {
>>>> +       int pixel_clock;
>>>> +       u8 conf[HDMIPHY_REG_COUNT];
>>>> +};
>>>> +
>>>> +/* list of all required phy config settings */
>>>> +static const struct hdmiphy_config hdmiphy_4212_configs[] = {
>>>> +       {
>>>> +               .pixel_clock = 25200000,
>>>> +               .conf = {
>>>> +                       0x01, 0x51, 0x2A, 0x75, 0x40, 0x01, 0x00, 0x08,
>>>> +                       0x82, 0x80, 0xfc, 0xd8, 0x45, 0xa0, 0xac, 0x80,
>>>> +                       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> +                       0x54, 0xf4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
>>>> +               },
>>>> +       },
>>>> +       {
>>>> +               .pixel_clock = 27000000,
>>>> +               .conf = {
>>>> +                       0x01, 0xd1, 0x22, 0x51, 0x40, 0x08, 0xfc, 0x20,
>>>> +                       0x98, 0xa0, 0xcb, 0xd8, 0x45, 0xa0, 0xac, 0x80,
>>>> +                       0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> +                       0x54, 0xe4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
>>>> +               },
>>>> +       },
>>>> +       {
>>>> +               .pixel_clock = 27027000,
>>>> +               .conf = {
>>>> +                       0x01, 0xd1, 0x2d, 0x72, 0x40, 0x64, 0x12, 0x08,
>>>> +                       0x43, 0xa0, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
>>>> +                       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> +                       0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
>>>> +               },
>>>> +       },
>>>> +       {
>>>> +               .pixel_clock = 36000000,
>>>> +               .conf = {
>>>> +                       0x01, 0x51, 0x2d, 0x55, 0x40, 0x01, 0x00, 0x08,
>>>> +                       0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
>>>> +                       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> +                       0x54, 0xab, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
>>>> +               },
>>>> +       },
>>>> +       {
>>>> +               .pixel_clock = 40000000,
>>>> +               .conf = {
>>>> +                       0x01, 0x51, 0x32, 0x55, 0x40, 0x01, 0x00, 0x08,
>>>> +                       0x82, 0x80, 0x2c, 0xd9, 0x45, 0xa0, 0xac, 0x80,
>>>> +                       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> +                       0x54, 0x9a, 0x24, 0x00, 0x00, 0x00, 0x01, 0x80,
>>>> +               },
>>>> +       },
>>>> +       {
>>>> +               .pixel_clock = 65000000,
>>>> +               .conf = {
>>>> +                       0x01, 0xd1, 0x36, 0x34, 0x40, 0x1e, 0x0a, 0x08,
>>>> +                       0x82, 0xa0, 0x45, 0xd9, 0x45, 0xa0, 0xac, 0x80,
>>>> +                       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> +                       0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
>>>> +               },
>>>> +       },
>>>> +       {
>>>> +               .pixel_clock = 74176000,
>>>> +               .conf = {
>>>> +                       0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08,
>>>> +                       0x82, 0xa0, 0x73, 0xd9, 0x45, 0xa0, 0xac, 0x80,
>>>> +                       0x56, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> +                       0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
>>>> +               },
>>>> +       },
>>>> +       {
>>>> +               .pixel_clock = 74250000,
>>>> +               .conf = {
>>>> +                       0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
>>>> +                       0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
>>>> +                       0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> +                       0x54, 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
>>>> +               },
>>>> +       },
>>>> +       {
>>>> +               .pixel_clock = 83500000,
>>>> +               .conf = {
>>>> +                       0x01, 0xd1, 0x23, 0x11, 0x40, 0x0c, 0xfb, 0x08,
>>>> +                       0x85, 0xa0, 0xd1, 0xd8, 0x45, 0xa0, 0xac, 0x80,
>>>> +                       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> +                       0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
>>>> +               },
>>>> +       },
>>>> +       {
>>>> +               .pixel_clock = 106500000,
>>>> +               .conf = {
>>>> +                       0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08,
>>>> +                       0x84, 0xa0, 0x0a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
>>>> +                       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> +                       0x54, 0x73, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
>>>> +               },
>>>> +       },
>>>> +       {
>>>> +               .pixel_clock = 108000000,
>>>> +               .conf = {
>>>> +                       0x01, 0x51, 0x2d, 0x15, 0x40, 0x01, 0x00, 0x08,
>>>> +                       0x82, 0x80, 0x0e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
>>>> +                       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> +                       0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
>>>> +               },
>>>> +       },
>>>> +       {
>>>> +               .pixel_clock = 146250000,
>>>> +               .conf = {
>>>> +                       0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08,
>>>> +                       0x83, 0xa0, 0x6e, 0xd9, 0x45, 0xa0, 0xac, 0x80,
>>>> +                       0x08, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> +                       0x54, 0x50, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
>>>> +               },
>>>> +       },
>>>> +       {
>>>> +               .pixel_clock = 148500000,
>>>> +               .conf = {
>>>> +                       0x01, 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0x08,
>>>> +                       0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
>>>> +                       0x3c, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
>>>> +                       0x54, 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00,
>>>> +               },
>>>> +       },
>>>> +};
>>>> +
>>>> +static const struct hdmiphy_config hdmiphy_4210_configs[] = {
>>>> +       {
>>>> +               .pixel_clock = 27000000,
>>>> +               .conf = {
>>>> +                       0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
>>>> +                       0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
>>>> +                       0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
>>>> +                       0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
>>>> +               },
>>>> +       },
>>>> +       {
>>>> +               .pixel_clock = 27027000,
>>>> +               .conf = {
>>>> +                       0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
>>>> +                       0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
>>>> +                       0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
>>>> +                       0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00,
>>>> +               },
>>>> +       },
>>>> +       {
>>>> +               .pixel_clock = 74176000,
>>>> +               .conf = {
>>>> +                       0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
>>>> +                       0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
>>>> +                       0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
>>>> +                       0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
>>>> +               },
>>>> +       },
>>>> +       {
>>>> +               .pixel_clock = 74250000,
>>>> +               .conf = {
>>>> +                       0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
>>>> +                       0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
>>>> +                       0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xe0,
>>>> +                       0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
>>>> +               },
>>>> +       },
>>>> +       {
>>>> +               .pixel_clock = 148500000,
>>>> +               .conf = {
>>>> +                       0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
>>>> +                       0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
>>>> +                       0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
>>>> +                       0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
>>>> +               },
>>>> +       },
>>>> +};
>>>> +
>>>> +static const struct hdmiphy_config *hdmiphy_find_conf(void *ctx,
>>>> +                       const struct drm_display_mode *mode)
>>>> +{
>>>> +       struct hdmiphy_context *hdata = ctx;
>>>> +       const struct hdmiphy_config *confs;
>>>> +       int count, i;
>>>> +
>>>> +       switch (hdata->type) {
>>>> +       case HDMIPHY_EXYNOS4212:
>>>> +               confs = hdmiphy_4212_configs;
>>>> +               count = ARRAY_SIZE(hdmiphy_4212_configs);
>>>> +               break;
>>>> +       case HDMIPHY_EXYNOS4210:
>>>> +               confs = hdmiphy_4210_configs;
>>>> +               count = ARRAY_SIZE(hdmiphy_4210_configs);
>>>> +               break;
>>>> +       default:
>>>> +               return NULL;
>>>
>>> Should probably DRM_ERROR here.
>>>
>> ok. I will add that.
>>
>>>> +       }
>>>> +
>>>> +       for (i = 0; i < count; i++)
>>>> +               if (confs[i].pixel_clock == (mode->clock * 1000))
>>>> +                       return &confs[i];
>>>> +
>>>> +       return NULL;
>>>> +}
>>>> +
>>>> +static int hdmiphy_check_timing(void *ctx, struct drm_display_mode *mode)
>>>>  {
>>>> -       hdmi_attach_hdmiphy_client(client);
>>>> +       const struct hdmiphy_config *conf;
>>>> +       DRM_DEBUG_KMS("%s : xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
>>>> +               __func__, mode->hdisplay, mode->vdisplay,
>>>> +               mode->vrefresh, (mode->flags & DRM_MODE_FLAG_INTERLACE)
>>>> +               ? true : false, mode->clock * 1000);
>>>
>>> No need to print __func__ here, DRM_DEBUG_KMS will do that for you. I
>>> think you should also parse the flags to a string instead of a bool
>>> cast to an int.
>>>
>> ok.
>>
>>>>
>>>> -       dev_info(&client->adapter->dev, "attached s5p_hdmiphy "
>>>> -               "into i2c adapter successfully\n");
>>>> +       conf = hdmiphy_find_conf(ctx, mode);
>>>> +       if (!conf) {
>>>> +               DRM_DEBUG_KMS("Display Mode is not supported.\n");
>>>> +               return -EINVAL;
>>>> +       }
>>>>
>>>>         return 0;
>>>>  }
>>>>
>>>> -static int hdmiphy_remove(struct i2c_client *client)
>>>> +static void hdmiphy_mode_set(void *ctx, struct drm_display_mode *mode)
>>>> +{
>>>> +       struct hdmiphy_context *hdata = ctx;
>>>> +
>>>> +       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
>>>
>>> No need to print __func__ here, DRM_DEBUG_KMS will do that for you.
>>> This comment stand for the rest of the calls, as well.
>>>
>>>> +
>>>> +       hdata->conf = hdmiphy_find_conf(ctx, mode);
>>>> +}
>>>> +
>>>> +static void hdmiphy_config_prepare(void *ctx)
>>>> +{
>>>> +       struct hdmiphy_context *hdata = ctx;
>>>> +       const struct i2c_client *client = to_i2c_client(hdata->dev);
>>>> +       u8 buffer[2];
>>>> +
>>>> +       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
>>>> +
>>>> +       /* operation mode */
>>>> +       buffer[0] = HDMIPHY_MODE_SET_DONE;
>>>> +       buffer[1] = 0x00;
>>>> +
>>>> +       if (client)
>>>> +               i2c_master_send(client, buffer, 2);
>>>> +}
>>>> +
>>>> +static int hdmiphy_config_apply(void *ctx)
>>>>  {
>>>> -       dev_info(&client->adapter->dev, "detached s5p_hdmiphy "
>>>> -               "from i2c adapter successfully\n");
>>>> +       struct hdmiphy_context *hdata = ctx;
>>>> +       struct i2c_client *client = to_i2c_client(hdata->dev);
>>>> +       const u8 *hdmiphy_data;
>>>> +       u8 buffer[HDMIPHY_REG_COUNT];
>>>> +       u8 operation[2];
>>>> +       u8 read_buffer[HDMIPHY_REG_COUNT] = {0, };
>>>> +       int ret;
>>>> +       int i;
>>>> +
>>>> +       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
>>>> +
>>>> +       /* pixel clock */
>>>> +       if (hdata->conf && client)
>>>> +               hdmiphy_data = hdata->conf->conf;
>>>> +       else
>>>> +               return -EINVAL;
>>>> +
>>>> +       memcpy(buffer, hdmiphy_data, HDMIPHY_REG_COUNT);
>>>> +
>>>> +       ret = i2c_master_send(client, buffer, HDMIPHY_REG_COUNT);
>>>> +       if (ret != HDMIPHY_REG_COUNT) {
>>>> +               DRM_ERROR("failed to configure HDMIPHY via I2C\n");
>>>> +               return ret;
>>>> +       }
>>>> +
>>>> +       usleep_range(10000, 12000);
>>>> +
>>>> +       /* operation mode */
>>>> +       operation[0] = HDMIPHY_MODE_SET_DONE;
>>>> +       operation[1] = HDMIPHY_MODE_EN;
>>>> +
>>>> +       ret = i2c_master_send(client, operation, 2);
>>>> +       if (ret != 2) {
>>>> +               DRM_ERROR("failed to enable hdmiphy\n");
>>>> +               return ret;
>>>> +       }
>>>> +
>>>> +       ret = i2c_master_recv(client, read_buffer, HDMIPHY_REG_COUNT);
>>>> +       if (ret < 0) {
>>>> +               DRM_ERROR("failed to read hdmiphy config\n");
>>>> +               return ret;
>>>> +       }
>>>> +
>>>> +       for (i = 0; i < ret; i++)
>>>> +               DRM_DEBUG_KMS("hdmiphy[0x%02x] wr[0x%02x], rd[0x%02x]\n",
>>>> +                               i, buffer[i], read_buffer[i]);
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +static void hdmiphy_dpms(void *ctx, int mode)
>>>> +{
>>>> +       struct hdmiphy_context *hdata = ctx;
>>>> +
>>>> +       DRM_DEBUG_KMS("[%d] %s mode %d\n", __LINE__, __func__, mode);
>>>> +
>>>> +       switch (mode) {
>>>> +       case DRM_MODE_DPMS_ON:
>>>> +               if (pm_runtime_suspended(hdata->dev))
>>>> +                       pm_runtime_get_sync(hdata->dev);
>>>> +               break;
>>>> +       case DRM_MODE_DPMS_STANDBY:
>>>> +       case DRM_MODE_DPMS_SUSPEND:
>>>> +       case DRM_MODE_DPMS_OFF:
>>>> +               if (!pm_runtime_suspended(hdata->dev))
>>>> +                       pm_runtime_put_sync(hdata->dev);
>>>> +               break;
>>>> +       default:
>>>> +               DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
>>>> +               break;
>>>> +       }
>>>> +}
>>>> +
>>>> +static int hdmiphy_update_bits(struct i2c_client *client, u8 *reg_cache,
>>>> +                              u8 reg, u8 mask, u8 val)
>>>> +{
>>>> +       int ret;
>>>> +       u8 buffer[2];
>>>> +
>>>> +       buffer[0] = reg;
>>>> +       buffer[1] = (reg_cache[reg] & ~mask) | (val & mask);
>>>> +       reg_cache[reg] = buffer[1];
>>>> +
>>>> +       ret = i2c_master_send(client, buffer, 2);
>>>> +       if (ret != 2)
>>>> +               return -EIO;
>>>>
>>>>         return 0;
>>>>  }
>>>>
>>>> +static int hdmiphy_4412_turn_on(struct i2c_client *client, bool on)
>>>
>>> This name is misleading. Please change it to something that doesn't
>>> convey a power state, such as hdmiphy_4412_power
>>>
>> ok. I will change that.
>>
>>>> +{
>>>> +       u8 reg_cache[HDMIPHY_REG_COUNT] = { 0 };
>>>> +       u8 buffer[2];
>>>> +       int ret;
>>>> +
>>>> +       DRM_DEBUG_KMS("%s: hdmiphy is %s\n", __func__, on ? "on" : "off");
>>>> +
>>>> +       /* Cache all hdmi-phy registers to make the code below faster */
>>>> +       buffer[0] = 0x0;
>>>> +       ret = i2c_master_send(client, buffer, 1);
>>>> +       if (ret != 1) {
>>>> +               ret = -EIO;
>>>> +               goto exit;
>>>> +       }
>>>> +       ret = i2c_master_recv(client, reg_cache, HDMIPHY_REG_COUNT);
>>>> +       if (ret != HDMIPHY_REG_COUNT) {
>>>> +               ret = -EIO;
>>>> +               goto exit;
>>>> +       }
>>>> +
>>>> +       /* Change to/from configuration from/to operation mode */
>>>> +       ret = hdmiphy_update_bits(client, reg_cache, HDMIPHY_MODE_SET_DONE,
>>>> +                               HDMIPHY_MODE_EN, on ? ~0 : 0);
>>>> +       if (ret)
>>>> +               goto exit;
>>>> +
>>>> +       /*
>>>> +        * Turn off "oscpad" if !on; it turns on again in
>>>> +        * during phy-configuration.
>>>> +        */
>>>> +       if (!on)
>>>> +               ret = hdmiphy_update_bits(client, reg_cache,
>>>> +                       HDMIPHY_4212_OSC_PAD_CON, HDMIPHY_OSC_PAD_EN, 0);
>>>> +               if (ret)
>>>> +                       goto exit;
>>>> +
>>>> +       /* Disable powerdown if on; enable if !on */
>>>
>>> This comment really isn't useful, it's just describing the code.
>>
>> I will remove this comment.
>>
>>>
>>>> +       ret = hdmiphy_update_bits(client, reg_cache, HDMIPHY_4212_PD_CON,
>>>> +                       HDMIPHY_PDEN, on ? 0 : ~0);
>>>> +       if (ret)
>>>> +               goto exit;
>>>> +       ret = hdmiphy_update_bits(client, reg_cache, HDMIPHY_4212_PD_CON,
>>>> +                       HDMIPHY_PD_ALL, on ? 0 : ~0);
>>>> +       if (ret)
>>>> +               goto exit;
>>>> +
>>>> +       /* Disable pixel clock generator block if !on */
>>>> +       if (!on)
>>>> +               ret = hdmiphy_update_bits(client, reg_cache,
>>>> +                       HDMIPHY_4212_PCG_CON, HDMIPHY_PCG_RESET_EN, 0);
>>>> +               if (ret)
>>>> +                       goto exit;
>>>> +
>>>> +exit:
>>>> +       /* Don't expect any errors so just do a single warn */
>>>> +       WARN_ON(ret);
>>>> +
>>>> +       return ret;
>>>> +}
>>>> +
>>>> +static struct exynos_hdmiphy_ops hdmiphy_ops = {
>>>> +       .check_timing   = hdmiphy_check_timing,
>>>> +       .mode_set               = hdmiphy_mode_set,
>>>> +       .prepare                = hdmiphy_config_prepare,
>>>> +       .config_apply   = hdmiphy_config_apply,
>>>> +       .dpms           = hdmiphy_dpms,
>>>> +};
>>>> +
>>>>  static const struct i2c_device_id hdmiphy_id[] = {
>>>> -       { "s5p_hdmiphy", 0 },
>>>> -       { "exynos5-hdmiphy", 0 },
>>>> +       { "s5p_hdmiphy", HDMIPHY_EXYNOS4210 },
>>>> +       { "exynos5-hdmiphy", HDMIPHY_EXYNOS4212 },
>>>>         { },
>>>>  };
>>>>
>>>> @@ -50,21 +454,183 @@ static const struct i2c_device_id hdmiphy_id[] = {
>>>>  static struct of_device_id hdmiphy_match_types[] = {
>>>>         {
>>>>                 .compatible = "samsung,exynos5-hdmiphy",
>>>> +               .data   = (void *)HDMIPHY_EXYNOS4212,
>>>>         }, {
>>>>                 /* end node */
>>>>         }
>>>>  };
>>>>  #endif
>>>>
>>>> +static int hdmiphy_probe(struct i2c_client *client,
>>>> +       const struct i2c_device_id *id)
>>>> +{
>>>> +       struct device *dev = &client->dev;
>>>> +       struct hdmiphy_context *hdata;
>>>> +       struct exynos_drm_hdmi_context *drm_hdmi_ctx;
>>>> +
>>>> +       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
>>>> +
>>>> +       drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx),
>>>> +                                       GFP_KERNEL);
>>>> +       if (!drm_hdmi_ctx) {
>>>> +               DRM_ERROR("failed to allocate common hdmi context.\n");
>>>> +               return -ENOMEM;
>>>> +       }
>>>> +
>>>> +       hdata = devm_kzalloc(dev, sizeof(*hdata), GFP_KERNEL);
>>>> +       if (!hdata) {
>>>> +               DRM_ERROR("failed to allocate hdmiphy context.\n");
>>>> +               return -ENOMEM;
>>>> +       }
>>>> +
>>>> +       if (dev->of_node) {
>>>> +               const struct of_device_id *match;
>>>> +               match = of_match_node(of_match_ptr(hdmiphy_match_types),
>>>> +                                       dev->of_node);
>>>> +               if (match == NULL)
>>>> +                       return -ENODEV;
>>>> +               hdata->type = (enum hdmiphy_type)match->data;
>>>> +       } else {
>>>> +               hdata->type = (enum hdmiphy_type)id->driver_data;
>>>> +       }
>>>> +
>>>> +       drm_hdmi_ctx->ctx = (void *)hdata;
>>>> +       hdata->parent_ctx = (void *)drm_hdmi_ctx;
>>>> +       hdata->dev = dev;
>>>> +
>>>> +       hdata->hdmiphy = devm_clk_get(dev, "hdmiphy");
>>>
>>> I don't see this call removed in the hdmi driver, am I missing something?
>>>
>>
>> I took it wrong. I thought hdmi IP is clocked by hdmiphy clock. Actually it is
>> sclk_hdmiphy clock. I will remove this from hdmi driver.
>>
>>>> +       if (IS_ERR_OR_NULL(hdata->hdmiphy)) {
>>>> +               DRM_ERROR("failed to get clock 'hdmiphy'\n");
>>>> +               return PTR_ERR(hdata->hdmiphy);
>>>> +       }
>>>> +
>>>> +       i2c_set_clientdata(client, hdata);
>>>> +
>>>> +       /* Attach HDMI-PHY Driver to common hdmi. */
>>>> +       exynos_hdmiphy_drv_attach(drm_hdmi_ctx);
>>>> +
>>>> +       /* register specific callbacks to common hdmi. */
>>>> +       exynos_hdmiphy_ops_register(&hdmiphy_ops);
>>>> +
>>>> +       pm_runtime_enable(dev);
>>>> +
>>>> +       dev_info(&client->adapter->dev,
>>>> +               "attached s5p_hdmiphy into i2c adapter successfully\n");
>>>> +
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +static int hdmiphy_remove(struct i2c_client *client)
>>>> +{
>>>> +       dev_info(&client->adapter->dev,
>>>> +               "detached s5p_hdmiphy from i2c adapter successfully\n");
>>>> +
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +static void hdmiphy_poweroff(struct device *dev)
>>>> +{
>>>> +       struct i2c_client *client = to_i2c_client(dev);
>>>> +       struct hdmiphy_context *hdata = i2c_get_clientdata(client);
>>>> +
>>>> +       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
>>>> +
>>>> +       if (hdata->type == HDMIPHY_EXYNOS4212)
>>>> +               hdmiphy_4412_turn_on(client, 0);
>>>> +
>>>> +       clk_disable(hdata->hdmiphy);
>>>> +}
>>>> +
>>>> +static void hdmiphy_poweron(struct device *dev)
>>>> +{
>>>> +       struct i2c_client *client = to_i2c_client(dev);
>>>> +       struct hdmiphy_context *hdata = i2c_get_clientdata(client);
>>>> +
>>>> +       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
>>>> +
>>>> +       clk_enable(hdata->hdmiphy);
>>>> +
>>>> +       if (hdata->type == HDMIPHY_EXYNOS4212)
>>>> +               hdmiphy_4412_turn_on(client, 1);
>>>> +}
>>>> +
>>>> +#ifdef CONFIG_PM_SLEEP
>>>> +static int hdmiphy_suspend(struct device *dev)
>>>> +{
>>>> +       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
>>>> +
>>>> +       if (pm_runtime_suspended(dev)) {
>>>> +               DRM_DEBUG_KMS("%s: already runtime-suspended.\n",
>>>> +               __func__);
>>>> +               return 0;
>>>> +       }
>>>> +
>>>> +       hdmiphy_poweroff(dev);
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +static int hdmiphy_resume(struct device *dev)
>>>> +{
>>>> +       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
>>>> +
>>>> +       if (pm_runtime_suspended(dev)) {
>>>> +               /* dpms callback should resume the mixer. */
>>>> +               DRM_DEBUG_KMS("%s: already runtime-suspended.\n",
>>>> +               __func__);
>>>> +               return 0;
>>>> +       }
>>>> +
>>>> +       hdmiphy_poweron(dev);
>>>> +       return 0;
>>>> +}
>>>> +#endif
>>>> +
>>>> +
>>>> +#ifdef CONFIG_PM_RUNTIME
>>>> +static int hdmiphy_runtime_suspend(struct device *dev)
>>>> +{
>>>> +       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
>>>> +
>>>> +       hdmiphy_poweroff(dev);
>>>> +       return 0;
>>>> +}
>>>> +
>>>> +static int hdmiphy_runtime_resume(struct device *dev)
>>>> +{
>>>> +       DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
>>>> +
>>>> +       hdmiphy_poweron(dev);
>>>> +       return 0;
>>>> +}
>>>> +#endif
>>>> +
>>>> +static const struct dev_pm_ops hdmiphy_pm_ops = {
>>>> +       SET_SYSTEM_SLEEP_PM_OPS(hdmiphy_suspend, hdmiphy_resume)
>>>> +       SET_RUNTIME_PM_OPS(hdmiphy_runtime_suspend,
>>>> +               hdmiphy_runtime_resume, NULL)
>>>> +};
>>>> +
>>>>  struct i2c_driver hdmiphy_driver = {
>>>>         .driver = {
>>>>                 .name   = "exynos-hdmiphy",
>>>>                 .owner  = THIS_MODULE,
>>>>                 .of_match_table = of_match_ptr(hdmiphy_match_types),
>>>> +               .pm     = &hdmiphy_pm_ops,
>>>>         },
>>>>         .id_table = hdmiphy_id,
>>>>         .probe          = hdmiphy_probe,
>>>>         .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);
>>>> diff --git a/drivers/gpu/drm/exynos/regs-hdmiphy.h b/drivers/gpu/drm/exynos/regs-hdmiphy.h
>>>> new file mode 100644
>>>> index 0000000..8f906c6
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/exynos/regs-hdmiphy.h
>>>> @@ -0,0 +1,61 @@
>>>> +/*
>>>> + *
>>>> + *  regs-hdmiphy.h
>>>> + *
>>>> + * Copyright (c) 2013 Samsung Electronics Co., Ltd.
>>>> + * http://www.samsung.com/
>>>> + *
>>>> + * HDMI-PHY register header file for Samsung TVOUT driver
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify
>>>> + * it under the terms of the GNU General Public License version 2 as
>>>> + * published by the Free Software Foundation.
>>>> +*/
>>>> +
>>>> +#ifndef SAMSUNG_REGS_HDMIPHY_H
>>>> +#define SAMSUNG_REGS_HDMIPHY_H
>>>> +
>>>> +/*
>>>> + * Register part
>>>> +*/
>>>> +
>>>> +/* HDMI PHY Version Common */
>>>> +#define HDMIPHY_MODE_SET_DONE          (0x1f)
>>>> +
>>>> +/* HDMI PHY Version 4212 */
>>>> +#define HDMIPHY_4212_PCG_CON           (0x04)
>>>> +#define HDMIPHY_4212_OSC_PAD_CON       (0x0b)
>>>> +#define HDMIPHY_4212_PD_CON            (0x1d)
>>>> +
>>>> +/*
>>>> + * Bit definition part
>>>> + */
>>>> +
>>>> +/* HDMIPHY_MODE_SET_DONE */
>>>> +#define HDMIPHY_MODE_EN                        (1 << 7)
>>>> +
>>>> +/* HDMIPHY_4212_PCG_CON */
>>>> +#define HDMIPHY_PCG_RESET_EN           (1 << 3)
>>>> +
>>>> +/* HDMIPHY_4212_OSC_PAD_CON */
>>>> +#define HDMIPHY_OSC_PAD_EN             (3 << 6)
>>>> +
>>>> +/* HDMIPHY_4212_PD_CON */
>>>> +#define HDMIPHY_PDEN                   (1 << 7)
>>>> +
>>>> +#define HDMIPHY_PLL_PD                 (1 << 6)
>>>> +#define HDMIPHY_CLKSER_PD              (1 << 5)
>>>> +#define HDMIPHY_CLKDRV_PD              (1 << 4)
>>>> +
>>>> +#define HDMIPHY_DRV_PD                 (1 << 2)
>>>> +#define HDMIPHY_SER_PD                 (1 << 1)
>>>> +#define HDMIPHY_ICLK_PD                        (1 << 0)
>>>> +
>>>> +#define HDMIPHY_PD_ALL                 (HDMIPHY_PLL_PD |\
>>>> +                                       HDMIPHY_CLKSER_PD |\
>>>> +                                       HDMIPHY_CLKDRV_PD|\
>>>> +                                       HDMIPHY_DRV_PD|\
>>>> +                                       HDMIPHY_SER_PD|\
>>>> +                                       HDMIPHY_ICLK_PD)
>>>> +
>>>> +#endif /* SAMSUNG_REGS_HDMIPHY_H */
>>>> --
>>>> 1.8.0
>>>>
>>
>> --
>> Regards,
>> Rahul Sharma,
>> email to: rahul.sharma at samsung.com
>> Samsung India.
>
>
>
> --
> Regards,
> Rahul Sharma,
> email to: rahul.sharma at samsung.com
> Samsung India.
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel


More information about the dri-devel mailing list