On Mon, Mar 4, 2013 at 7:35 PM, Rahul Sharma <r.sh.open@xxxxxxxxx> wrote: > Thanks Sean, > > On Wed, Feb 27, 2013 at 9:47 PM, Sean Paul <seanpaul@xxxxxxxxxx> wrote: >> On Wed, Feb 27, 2013 at 8:22 AM, Rahul Sharma <rahul.sharma@xxxxxxxxxxx> 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@xxxxxxxxxxxxxxxxxxxxx/msg34733.html >>> http://www.mail-archive.com/dri-devel@xxxxxxxxxxxxxxxxxxxxx/msg34861.html >>> http://www.mail-archive.com/dri-devel@xxxxxxxxxxxxxxxxxxxxx/msg34862.html >>> >>> Signed-off-by: Rahul Sharma <rahul.sharma@xxxxxxxxxxx> >>> --- >>> 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? 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@xxxxxxxxxxx > Samsung India. -- Regards, Rahul Sharma, email to: rahul.sharma@xxxxxxxxxxx Samsung India. _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel