diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_hdmi.c')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_hdmi.c | 738 |
1 files changed, 331 insertions, 407 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index e148d728e28c..0f87acb4cf21 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -7,9 +7,9 @@ * * Based on drivers/media/video/s5p-tv/hdmi_drv.c * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * */ @@ -49,14 +49,16 @@ /* AVI header and aspect ratio */ #define HDMI_AVI_VERSION 0x02 -#define HDMI_AVI_LENGTH 0x0D +#define HDMI_AVI_LENGTH 0x0d /* AUI header info */ -#define HDMI_AUI_VERSION 0x01 -#define HDMI_AUI_LENGTH 0x0A -#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x8 -#define AVI_4_3_CENTER_RATIO 0x9 -#define AVI_16_9_CENTER_RATIO 0xa +#define HDMI_AUI_VERSION 0x01 +#define HDMI_AUI_LENGTH 0x0a + +/* AVI active format aspect ratio */ +#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x08 +#define AVI_4_3_CENTER_RATIO 0x09 +#define AVI_16_9_CENTER_RATIO 0x0a enum hdmi_type { HDMI_TYPE13, @@ -90,11 +92,34 @@ static const char * const supply[] = { "vdd_pll", }; +struct hdmiphy_config { + int pixel_clock; + u8 conf[32]; +}; + +struct hdmiphy_configs { + int count; + const struct hdmiphy_config *data; +}; + +struct string_array_spec { + int count; + const char * const *data; +}; + +#define INIT_ARRAY_SPEC(a) { .count = ARRAY_SIZE(a), .data = a } + struct hdmi_driver_data { unsigned int type; - const struct hdmiphy_config *phy_confs; - unsigned int phy_conf_count; unsigned int is_apb_phy:1; + unsigned int has_sysreg:1; + struct hdmiphy_configs phy_confs; + struct string_array_spec clk_gates; + /* + * Array of triplets (p_off, p_on, clock), where p_off and p_on are + * required parents of clock when HDMI-PHY is respectively off or on. + */ + struct string_array_spec clk_muxes; }; struct hdmi_context { @@ -116,11 +141,9 @@ struct hdmi_context { struct gpio_desc *hpd_gpio; int irq; struct regmap *pmureg; - struct clk *hdmi; - struct clk *sclk_hdmi; - struct clk *sclk_pixel; - struct clk *sclk_hdmiphy; - struct clk *mout_hdmi; + struct regmap *sysreg; + struct clk **clk_gates; + struct clk **clk_muxes; struct regulator_bulk_data regul_bulk[ARRAY_SIZE(supply)]; struct regulator *reg_hdmi_en; }; @@ -135,12 +158,6 @@ static inline struct hdmi_context *connector_to_hdmi(struct drm_connector *c) return container_of(c, struct hdmi_context, connector); } -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, @@ -501,25 +518,136 @@ static const struct hdmiphy_config hdmiphy_5420_configs[] = { }, }; -static struct hdmi_driver_data exynos5420_hdmi_driver_data = { +static const struct hdmiphy_config hdmiphy_5433_configs[] = { + { + .pixel_clock = 27000000, + .conf = { + 0x01, 0x51, 0x22, 0x51, 0x08, 0xfc, 0x88, 0x46, + 0x72, 0x50, 0x24, 0x0c, 0x24, 0x0f, 0x7c, 0xa5, + 0xd4, 0x2b, 0x87, 0x00, 0x00, 0x04, 0x00, 0x30, + 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, + }, + }, + { + .pixel_clock = 27027000, + .conf = { + 0x01, 0x51, 0x2d, 0x72, 0x64, 0x09, 0x88, 0xc3, + 0x71, 0x50, 0x24, 0x14, 0x24, 0x0f, 0x7c, 0xa5, + 0xd4, 0x2b, 0x87, 0x00, 0x00, 0x04, 0x00, 0x30, + 0x28, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, + }, + }, + { + .pixel_clock = 40000000, + .conf = { + 0x01, 0x51, 0x32, 0x55, 0x01, 0x00, 0x88, 0x02, + 0x4d, 0x50, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC, + 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30, + 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, + }, + }, + { + .pixel_clock = 50000000, + .conf = { + 0x01, 0x51, 0x34, 0x40, 0x64, 0x09, 0x88, 0xc3, + 0x3d, 0x50, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC, + 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30, + 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, + }, + }, + { + .pixel_clock = 65000000, + .conf = { + 0x01, 0x51, 0x36, 0x31, 0x40, 0x10, 0x04, 0xc6, + 0x2e, 0xe8, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC, + 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30, + 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, + }, + }, + { + .pixel_clock = 74176000, + .conf = { + 0x01, 0x51, 0x3E, 0x35, 0x5B, 0xDE, 0x88, 0x42, + 0x53, 0x51, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC, + 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30, + 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, + }, + }, + { + .pixel_clock = 74250000, + .conf = { + 0x01, 0x51, 0x3E, 0x35, 0x40, 0xF0, 0x88, 0xC2, + 0x52, 0x51, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC, + 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30, + 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, + }, + }, + { + .pixel_clock = 108000000, + .conf = { + 0x01, 0x51, 0x2d, 0x15, 0x01, 0x00, 0x88, 0x02, + 0x72, 0x52, 0x44, 0x8C, 0x27, 0x00, 0x7C, 0xAC, + 0xD6, 0x2B, 0x67, 0x00, 0x00, 0x04, 0x00, 0x30, + 0x08, 0x10, 0x01, 0x01, 0x48, 0x40, 0x00, 0x40, + }, + }, + { + .pixel_clock = 148500000, + .conf = { + 0x01, 0x51, 0x1f, 0x00, 0x40, 0xf8, 0x88, 0xc1, + 0x52, 0x52, 0x24, 0x0c, 0x24, 0x0f, 0x7c, 0xa5, + 0xd4, 0x2b, 0x87, 0x00, 0x00, 0x04, 0x00, 0x30, + 0x08, 0x10, 0x01, 0x01, 0x48, 0x4a, 0x00, 0x40, + }, + }, +}; + +static const char * const hdmi_clk_gates4[] = { + "hdmi", "sclk_hdmi" +}; + +static const char * const hdmi_clk_muxes4[] = { + "sclk_pixel", "sclk_hdmiphy", "mout_hdmi" +}; + +static const char * const hdmi_clk_gates5433[] = { + "hdmi_pclk", "hdmi_i_pclk", "i_tmds_clk", "i_pixel_clk", "i_spdif_clk" +}; + +static const char * const hdmi_clk_muxes5433[] = { + "oscclk", "tmds_clko", "tmds_clko_user", + "oscclk", "pixel_clko", "pixel_clko_user" +}; + +static const struct hdmi_driver_data exynos4210_hdmi_driver_data = { + .type = HDMI_TYPE13, + .phy_confs = INIT_ARRAY_SPEC(hdmiphy_v13_configs), + .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4), + .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4), +}; + +static const struct hdmi_driver_data exynos4212_hdmi_driver_data = { .type = HDMI_TYPE14, - .phy_confs = hdmiphy_5420_configs, - .phy_conf_count = ARRAY_SIZE(hdmiphy_5420_configs), - .is_apb_phy = 1, + .phy_confs = INIT_ARRAY_SPEC(hdmiphy_v14_configs), + .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4), + .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4), }; -static struct hdmi_driver_data exynos4212_hdmi_driver_data = { +static const struct hdmi_driver_data exynos5420_hdmi_driver_data = { .type = HDMI_TYPE14, - .phy_confs = hdmiphy_v14_configs, - .phy_conf_count = ARRAY_SIZE(hdmiphy_v14_configs), - .is_apb_phy = 0, + .is_apb_phy = 1, + .phy_confs = INIT_ARRAY_SPEC(hdmiphy_5420_configs), + .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates4), + .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes4), }; -static struct hdmi_driver_data exynos4210_hdmi_driver_data = { - .type = HDMI_TYPE13, - .phy_confs = hdmiphy_v13_configs, - .phy_conf_count = ARRAY_SIZE(hdmiphy_v13_configs), - .is_apb_phy = 0, +static const struct hdmi_driver_data exynos5433_hdmi_driver_data = { + .type = HDMI_TYPE14, + .is_apb_phy = 1, + .has_sysreg = 1, + .phy_confs = INIT_ARRAY_SPEC(hdmiphy_5433_configs), + .clk_gates = INIT_ARRAY_SPEC(hdmi_clk_gates5433), + .clk_muxes = INIT_ARRAY_SPEC(hdmi_clk_muxes5433), }; static inline u32 hdmi_map_reg(struct hdmi_context *hdata, u32 reg_id) @@ -585,266 +713,52 @@ static int hdmiphy_reg_write_buf(struct hdmi_context *hdata, } } -static void hdmi_v13_regs_dump(struct hdmi_context *hdata, char *prefix) +static int hdmi_clk_enable_gates(struct hdmi_context *hdata) { -#define DUMPREG(reg_id) \ - DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \ - readl(hdata->regs + reg_id)) - DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix); - DUMPREG(HDMI_INTC_FLAG); - DUMPREG(HDMI_INTC_CON); - DUMPREG(HDMI_HPD_STATUS); - DUMPREG(HDMI_V13_PHY_RSTOUT); - DUMPREG(HDMI_V13_PHY_VPLL); - DUMPREG(HDMI_V13_PHY_CMU); - DUMPREG(HDMI_V13_CORE_RSTOUT); - - DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix); - DUMPREG(HDMI_CON_0); - DUMPREG(HDMI_CON_1); - DUMPREG(HDMI_CON_2); - DUMPREG(HDMI_SYS_STATUS); - DUMPREG(HDMI_V13_PHY_STATUS); - DUMPREG(HDMI_STATUS_EN); - DUMPREG(HDMI_HPD); - DUMPREG(HDMI_MODE_SEL); - DUMPREG(HDMI_V13_HPD_GEN); - DUMPREG(HDMI_V13_DC_CONTROL); - DUMPREG(HDMI_V13_VIDEO_PATTERN_GEN); - - DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix); - DUMPREG(HDMI_H_BLANK_0); - DUMPREG(HDMI_H_BLANK_1); - DUMPREG(HDMI_V13_V_BLANK_0); - DUMPREG(HDMI_V13_V_BLANK_1); - DUMPREG(HDMI_V13_V_BLANK_2); - DUMPREG(HDMI_V13_H_V_LINE_0); - DUMPREG(HDMI_V13_H_V_LINE_1); - DUMPREG(HDMI_V13_H_V_LINE_2); - DUMPREG(HDMI_VSYNC_POL); - DUMPREG(HDMI_INT_PRO_MODE); - DUMPREG(HDMI_V13_V_BLANK_F_0); - DUMPREG(HDMI_V13_V_BLANK_F_1); - DUMPREG(HDMI_V13_V_BLANK_F_2); - DUMPREG(HDMI_V13_H_SYNC_GEN_0); - DUMPREG(HDMI_V13_H_SYNC_GEN_1); - DUMPREG(HDMI_V13_H_SYNC_GEN_2); - DUMPREG(HDMI_V13_V_SYNC_GEN_1_0); - DUMPREG(HDMI_V13_V_SYNC_GEN_1_1); - DUMPREG(HDMI_V13_V_SYNC_GEN_1_2); - DUMPREG(HDMI_V13_V_SYNC_GEN_2_0); - DUMPREG(HDMI_V13_V_SYNC_GEN_2_1); - DUMPREG(HDMI_V13_V_SYNC_GEN_2_2); - DUMPREG(HDMI_V13_V_SYNC_GEN_3_0); - DUMPREG(HDMI_V13_V_SYNC_GEN_3_1); - DUMPREG(HDMI_V13_V_SYNC_GEN_3_2); - - DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix); - DUMPREG(HDMI_TG_CMD); - DUMPREG(HDMI_TG_H_FSZ_L); - DUMPREG(HDMI_TG_H_FSZ_H); - DUMPREG(HDMI_TG_HACT_ST_L); - DUMPREG(HDMI_TG_HACT_ST_H); - DUMPREG(HDMI_TG_HACT_SZ_L); - DUMPREG(HDMI_TG_HACT_SZ_H); - DUMPREG(HDMI_TG_V_FSZ_L); - DUMPREG(HDMI_TG_V_FSZ_H); - DUMPREG(HDMI_TG_VSYNC_L); - DUMPREG(HDMI_TG_VSYNC_H); - DUMPREG(HDMI_TG_VSYNC2_L); - DUMPREG(HDMI_TG_VSYNC2_H); - DUMPREG(HDMI_TG_VACT_ST_L); - DUMPREG(HDMI_TG_VACT_ST_H); - DUMPREG(HDMI_TG_VACT_SZ_L); - DUMPREG(HDMI_TG_VACT_SZ_H); - DUMPREG(HDMI_TG_FIELD_CHG_L); - DUMPREG(HDMI_TG_FIELD_CHG_H); - DUMPREG(HDMI_TG_VACT_ST2_L); - DUMPREG(HDMI_TG_VACT_ST2_H); - DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L); - DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H); - DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L); - DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H); - DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L); - DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H); - DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L); - DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H); -#undef DUMPREG + int i, ret; + + for (i = 0; i < hdata->drv_data->clk_gates.count; ++i) { + ret = clk_prepare_enable(hdata->clk_gates[i]); + if (!ret) + continue; + + dev_err(hdata->dev, "Cannot enable clock '%s', %d\n", + hdata->drv_data->clk_gates.data[i], ret); + while (i--) + clk_disable_unprepare(hdata->clk_gates[i]); + return ret; + } + + return 0; } -static void hdmi_v14_regs_dump(struct hdmi_context *hdata, char *prefix) +static void hdmi_clk_disable_gates(struct hdmi_context *hdata) { - int i; + int i = hdata->drv_data->clk_gates.count; -#define DUMPREG(reg_id) \ - DRM_DEBUG_KMS("%s:" #reg_id " = %08x\n", prefix, \ - readl(hdata->regs + reg_id)) - - DRM_DEBUG_KMS("%s: ---- CONTROL REGISTERS ----\n", prefix); - DUMPREG(HDMI_INTC_CON); - DUMPREG(HDMI_INTC_FLAG); - DUMPREG(HDMI_HPD_STATUS); - DUMPREG(HDMI_INTC_CON_1); - DUMPREG(HDMI_INTC_FLAG_1); - DUMPREG(HDMI_PHY_STATUS_0); - DUMPREG(HDMI_PHY_STATUS_PLL); - DUMPREG(HDMI_PHY_CON_0); - DUMPREG(HDMI_V14_PHY_RSTOUT); - DUMPREG(HDMI_PHY_VPLL); - DUMPREG(HDMI_PHY_CMU); - DUMPREG(HDMI_CORE_RSTOUT); - - DRM_DEBUG_KMS("%s: ---- CORE REGISTERS ----\n", prefix); - DUMPREG(HDMI_CON_0); - DUMPREG(HDMI_CON_1); - DUMPREG(HDMI_CON_2); - DUMPREG(HDMI_SYS_STATUS); - DUMPREG(HDMI_PHY_STATUS_0); - DUMPREG(HDMI_STATUS_EN); - DUMPREG(HDMI_HPD); - DUMPREG(HDMI_MODE_SEL); - DUMPREG(HDMI_ENC_EN); - DUMPREG(HDMI_DC_CONTROL); - DUMPREG(HDMI_VIDEO_PATTERN_GEN); - - DRM_DEBUG_KMS("%s: ---- CORE SYNC REGISTERS ----\n", prefix); - DUMPREG(HDMI_H_BLANK_0); - DUMPREG(HDMI_H_BLANK_1); - DUMPREG(HDMI_V2_BLANK_0); - DUMPREG(HDMI_V2_BLANK_1); - DUMPREG(HDMI_V1_BLANK_0); - DUMPREG(HDMI_V1_BLANK_1); - DUMPREG(HDMI_V_LINE_0); - DUMPREG(HDMI_V_LINE_1); - DUMPREG(HDMI_H_LINE_0); - DUMPREG(HDMI_H_LINE_1); - DUMPREG(HDMI_HSYNC_POL); - - DUMPREG(HDMI_VSYNC_POL); - DUMPREG(HDMI_INT_PRO_MODE); - DUMPREG(HDMI_V_BLANK_F0_0); - DUMPREG(HDMI_V_BLANK_F0_1); - DUMPREG(HDMI_V_BLANK_F1_0); - DUMPREG(HDMI_V_BLANK_F1_1); - - DUMPREG(HDMI_H_SYNC_START_0); - DUMPREG(HDMI_H_SYNC_START_1); - DUMPREG(HDMI_H_SYNC_END_0); - DUMPREG(HDMI_H_SYNC_END_1); - - DUMPREG(HDMI_V_SYNC_LINE_BEF_2_0); - DUMPREG(HDMI_V_SYNC_LINE_BEF_2_1); - DUMPREG(HDMI_V_SYNC_LINE_BEF_1_0); - DUMPREG(HDMI_V_SYNC_LINE_BEF_1_1); - - DUMPREG(HDMI_V_SYNC_LINE_AFT_2_0); - DUMPREG(HDMI_V_SYNC_LINE_AFT_2_1); - DUMPREG(HDMI_V_SYNC_LINE_AFT_1_0); - DUMPREG(HDMI_V_SYNC_LINE_AFT_1_1); - - DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_0); - DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_2_1); - DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_0); - DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_1_1); - - DUMPREG(HDMI_V_BLANK_F2_0); - DUMPREG(HDMI_V_BLANK_F2_1); - DUMPREG(HDMI_V_BLANK_F3_0); - DUMPREG(HDMI_V_BLANK_F3_1); - DUMPREG(HDMI_V_BLANK_F4_0); - DUMPREG(HDMI_V_BLANK_F4_1); - DUMPREG(HDMI_V_BLANK_F5_0); - DUMPREG(HDMI_V_BLANK_F5_1); - - DUMPREG(HDMI_V_SYNC_LINE_AFT_3_0); - DUMPREG(HDMI_V_SYNC_LINE_AFT_3_1); - DUMPREG(HDMI_V_SYNC_LINE_AFT_4_0); - DUMPREG(HDMI_V_SYNC_LINE_AFT_4_1); - DUMPREG(HDMI_V_SYNC_LINE_AFT_5_0); - DUMPREG(HDMI_V_SYNC_LINE_AFT_5_1); - DUMPREG(HDMI_V_SYNC_LINE_AFT_6_0); - DUMPREG(HDMI_V_SYNC_LINE_AFT_6_1); - - DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_0); - DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_3_1); - DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_0); - DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_4_1); - DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_0); - DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_5_1); - DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_0); - DUMPREG(HDMI_V_SYNC_LINE_AFT_PXL_6_1); - - DUMPREG(HDMI_VACT_SPACE_1_0); - DUMPREG(HDMI_VACT_SPACE_1_1); - DUMPREG(HDMI_VACT_SPACE_2_0); - DUMPREG(HDMI_VACT_SPACE_2_1); - DUMPREG(HDMI_VACT_SPACE_3_0); - DUMPREG(HDMI_VACT_SPACE_3_1); - DUMPREG(HDMI_VACT_SPACE_4_0); - DUMPREG(HDMI_VACT_SPACE_4_1); - DUMPREG(HDMI_VACT_SPACE_5_0); - DUMPREG(HDMI_VACT_SPACE_5_1); - DUMPREG(HDMI_VACT_SPACE_6_0); - DUMPREG(HDMI_VACT_SPACE_6_1); - - DRM_DEBUG_KMS("%s: ---- TG REGISTERS ----\n", prefix); - DUMPREG(HDMI_TG_CMD); - DUMPREG(HDMI_TG_H_FSZ_L); - DUMPREG(HDMI_TG_H_FSZ_H); - DUMPREG(HDMI_TG_HACT_ST_L); - DUMPREG(HDMI_TG_HACT_ST_H); - DUMPREG(HDMI_TG_HACT_SZ_L); - DUMPREG(HDMI_TG_HACT_SZ_H); - DUMPREG(HDMI_TG_V_FSZ_L); - DUMPREG(HDMI_TG_V_FSZ_H); - DUMPREG(HDMI_TG_VSYNC_L); - DUMPREG(HDMI_TG_VSYNC_H); - DUMPREG(HDMI_TG_VSYNC2_L); - DUMPREG(HDMI_TG_VSYNC2_H); - DUMPREG(HDMI_TG_VACT_ST_L); - DUMPREG(HDMI_TG_VACT_ST_H); - DUMPREG(HDMI_TG_VACT_SZ_L); - DUMPREG(HDMI_TG_VACT_SZ_H); - DUMPREG(HDMI_TG_FIELD_CHG_L); - DUMPREG(HDMI_TG_FIELD_CHG_H); - DUMPREG(HDMI_TG_VACT_ST2_L); - DUMPREG(HDMI_TG_VACT_ST2_H); - DUMPREG(HDMI_TG_VACT_ST3_L); - DUMPREG(HDMI_TG_VACT_ST3_H); - DUMPREG(HDMI_TG_VACT_ST4_L); - DUMPREG(HDMI_TG_VACT_ST4_H); - DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_L); - DUMPREG(HDMI_TG_VSYNC_TOP_HDMI_H); - DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_L); - DUMPREG(HDMI_TG_VSYNC_BOT_HDMI_H); - DUMPREG(HDMI_TG_FIELD_TOP_HDMI_L); - DUMPREG(HDMI_TG_FIELD_TOP_HDMI_H); - DUMPREG(HDMI_TG_FIELD_BOT_HDMI_L); - DUMPREG(HDMI_TG_FIELD_BOT_HDMI_H); - DUMPREG(HDMI_TG_3D); - - DRM_DEBUG_KMS("%s: ---- PACKET REGISTERS ----\n", prefix); - DUMPREG(HDMI_AVI_CON); - DUMPREG(HDMI_AVI_HEADER0); - DUMPREG(HDMI_AVI_HEADER1); - DUMPREG(HDMI_AVI_HEADER2); - DUMPREG(HDMI_AVI_CHECK_SUM); - DUMPREG(HDMI_VSI_CON); - DUMPREG(HDMI_VSI_HEADER0); - DUMPREG(HDMI_VSI_HEADER1); - DUMPREG(HDMI_VSI_HEADER2); - for (i = 0; i < 7; ++i) - DUMPREG(HDMI_VSI_DATA(i)); - -#undef DUMPREG + while (i--) + clk_disable_unprepare(hdata->clk_gates[i]); } -static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix) +static int hdmi_clk_set_parents(struct hdmi_context *hdata, bool to_phy) { - if (hdata->drv_data->type == HDMI_TYPE13) - hdmi_v13_regs_dump(hdata, prefix); - else - hdmi_v14_regs_dump(hdata, prefix); + struct device *dev = hdata->dev; + int ret = 0; + int i; + + for (i = 0; i < hdata->drv_data->clk_muxes.count; i += 3) { + struct clk **c = &hdata->clk_muxes[i]; + + ret = clk_set_parent(c[2], c[to_phy]); + if (!ret) + continue; + + dev_err(dev, "Cannot set clock parent of '%s' to '%s', %d\n", + hdata->drv_data->clk_muxes.data[i + 2], + hdata->drv_data->clk_muxes.data[i + to_phy], ret); + } + + return ret; } static u8 hdmi_chksum(struct hdmi_context *hdata, @@ -993,10 +907,11 @@ static int hdmi_get_modes(struct drm_connector *connector) static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock) { + const struct hdmiphy_configs *confs = &hdata->drv_data->phy_confs; int i; - for (i = 0; i < hdata->drv_data->phy_conf_count; i++) - if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock) + for (i = 0; i < confs->count; i++) + if (confs->data[i].pixel_clock == pixel_clock) return i; DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock); @@ -1078,13 +993,11 @@ static bool hdmi_mode_fixup(struct drm_encoder *encoder, mode_ok = hdmi_mode_valid(connector, adjusted_mode); - /* just return if user desired mode exists. */ if (mode_ok == MODE_OK) return true; /* - * otherwise, find the most suitable mode among modes and change it - * to adjusted_mode. + * Find the most suitable mode and copy it to adjusted_mode. */ list_for_each_entry(m, &connector->modes, head) { mode_ok = hdmi_mode_valid(connector, m); @@ -1129,15 +1042,15 @@ static void hdmi_audio_init(struct hdmi_context *hdata) switch (bits_per_sample) { case 20: data_num = 2; - bit_ch = 1; + bit_ch = 1; break; case 24: data_num = 3; - bit_ch = 1; + bit_ch = 1; break; default: data_num = 1; - bit_ch = 0; + bit_ch = 0; break; } @@ -1230,13 +1143,12 @@ static void hdmi_conf_init(struct hdmi_context *hdata) /* choose HDMI mode */ hdmi_reg_writemask(hdata, HDMI_MODE_SEL, HDMI_MODE_HDMI_EN, HDMI_MODE_MASK); - /* Apply Video preable and Guard band in HDMI mode only */ + /* apply video pre-amble and guard band in HDMI mode only */ hdmi_reg_writeb(hdata, HDMI_CON_2, 0); /* disable bluescreen */ hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN); if (hdata->dvi_mode) { - /* choose DVI mode */ hdmi_reg_writemask(hdata, HDMI_MODE_SEL, HDMI_MODE_DVI_EN, HDMI_MODE_MASK); hdmi_reg_writeb(hdata, HDMI_CON_2, @@ -1308,7 +1220,7 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata) val = (m->hsync_start - m->hdisplay - 2); val |= ((m->hsync_end - m->hdisplay - 2) << 10); - val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20; + val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20; hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val); /* @@ -1319,7 +1231,6 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata) /* Following values & calculations differ for different type of modes */ if (m->flags & DRM_MODE_FLAG_INTERLACE) { - /* Interlaced Mode */ val = ((m->vsync_end - m->vdisplay) / 2); val |= ((m->vsync_start - m->vdisplay) / 2) << 12; hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val); @@ -1348,8 +1259,6 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata) hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249); } else { - /* Progressive Mode */ - val = m->vtotal; val |= (m->vtotal - m->vdisplay) << 11; hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val); @@ -1365,21 +1274,12 @@ static void hdmi_v13_mode_apply(struct hdmi_context *hdata) hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2, m->vtotal - m->vdisplay); hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay); - hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248); } - /* Timing generator registers */ hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal); hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay); hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay); hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal); - hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1); - hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233); - hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233); - hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1); - hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233); - hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1); - hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233); } static void hdmi_v14_mode_apply(struct hdmi_context *hdata) @@ -1390,7 +1290,7 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata) hdmi_reg_writev(hdata, HDMI_V_LINE_0, 2, m->vtotal); hdmi_reg_writev(hdata, HDMI_H_LINE_0, 2, m->htotal); hdmi_reg_writev(hdata, HDMI_HSYNC_POL, 1, - (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0); + (m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0); hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0); hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, @@ -1404,7 +1304,6 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata) /* Following values & calculations differ for different type of modes */ if (m->flags & DRM_MODE_FLAG_INTERLACE) { - /* Interlaced Mode */ hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2, (m->vsync_end - m->vdisplay) / 2); hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2, @@ -1437,7 +1336,6 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata) hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x0); hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x0); } else { - /* Progressive Mode */ hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_2_0, 2, m->vsync_end - m->vdisplay); hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_BEF_1_0, 2, @@ -1454,15 +1352,8 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata) hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2, m->vtotal - m->vdisplay); hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay); - hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248); - hdmi_reg_writev(hdata, HDMI_TG_VACT_ST3_L, 2, 0x47b); - hdmi_reg_writev(hdata, HDMI_TG_VACT_ST4_L, 2, 0x6ae); - hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233); - hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233); - hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233); } - /* Following values & calculations are same irrespective of mode type */ hdmi_reg_writev(hdata, HDMI_H_SYNC_START_0, 2, m->hsync_start - m->hdisplay - 2); hdmi_reg_writev(hdata, HDMI_H_SYNC_END_0, 2, @@ -1486,16 +1377,12 @@ static void hdmi_v14_mode_apply(struct hdmi_context *hdata) hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_5_0, 2, 0xffff); hdmi_reg_writev(hdata, HDMI_V_SYNC_LINE_AFT_PXL_6_0, 2, 0xffff); - /* Timing generator registers */ hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal); hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay); hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay); hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal); - hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1); - hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233); - hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1); - hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1); - hdmi_reg_writev(hdata, HDMI_TG_3D, 1, 0x0); + if (hdata->drv_data == &exynos5433_hdmi_driver_data) + hdmi_reg_writeb(hdata, HDMI_TG_DECON_EN, 1); } static void hdmi_mode_apply(struct hdmi_context *hdata) @@ -1505,62 +1392,65 @@ static void hdmi_mode_apply(struct hdmi_context *hdata) else hdmi_v14_mode_apply(hdata); - hdmiphy_wait_for_pll(hdata); - - clk_set_parent(hdata->mout_hdmi, hdata->sclk_hdmiphy); - - /* enable HDMI and timing generator */ hdmi_start(hdata, true); } static void hdmiphy_conf_reset(struct hdmi_context *hdata) { - clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel); - - /* reset hdmiphy */ + hdmi_reg_writemask(hdata, HDMI_CORE_RSTOUT, 0, 1); + usleep_range(10000, 12000); + hdmi_reg_writemask(hdata, HDMI_CORE_RSTOUT, ~0, 1); + usleep_range(10000, 12000); hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT); usleep_range(10000, 12000); - hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT); + hdmi_reg_writemask(hdata, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT); usleep_range(10000, 12000); } +static void hdmiphy_enable_mode_set(struct hdmi_context *hdata, bool enable) +{ + u8 v = enable ? HDMI_PHY_ENABLE_MODE_SET : HDMI_PHY_DISABLE_MODE_SET; + + if (hdata->drv_data == &exynos5433_hdmi_driver_data) + writel(v, hdata->regs_hdmiphy + HDMIPHY5433_MODE_SET_DONE); +} + static void hdmiphy_conf_apply(struct hdmi_context *hdata) { int ret; - int i; + const u8 *phy_conf; - /* pixel clock */ - i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000); - if (i < 0) { + ret = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000); + if (ret < 0) { DRM_ERROR("failed to find hdmiphy conf\n"); return; } + phy_conf = hdata->drv_data->phy_confs.data[ret].conf; + + hdmi_clk_set_parents(hdata, false); + + hdmiphy_conf_reset(hdata); - ret = hdmiphy_reg_write_buf(hdata, 0, - hdata->drv_data->phy_confs[i].conf, 32); + hdmiphy_enable_mode_set(hdata, true); + ret = hdmiphy_reg_write_buf(hdata, 0, phy_conf, 32); if (ret) { DRM_ERROR("failed to configure hdmiphy\n"); return; } - + hdmiphy_enable_mode_set(hdata, false); + hdmi_clk_set_parents(hdata, true); usleep_range(10000, 12000); + hdmiphy_wait_for_pll(hdata); } static void hdmi_conf_apply(struct hdmi_context *hdata) { - hdmiphy_conf_reset(hdata); hdmiphy_conf_apply(hdata); - hdmi_start(hdata, false); hdmi_conf_init(hdata); - hdmi_audio_init(hdata); - - /* setting core registers */ hdmi_mode_apply(hdata); hdmi_audio_control(hdata, true); - - hdmi_regs_dump(hdata, "start"); } static void hdmi_mode_set(struct drm_encoder *encoder, @@ -1579,6 +1469,15 @@ static void hdmi_mode_set(struct drm_encoder *encoder, hdata->cea_video_id = drm_match_cea_mode(mode); } +static void hdmi_set_refclk(struct hdmi_context *hdata, bool on) +{ + if (!hdata->sysreg) + return; + + regmap_update_bits(hdata->sysreg, EXYNOS5433_SYSREG_DISP_HDMI_PHY, + SYSREG_HDMI_REFCLK_INT_CLK, on ? ~0 : 0); +} + static void hdmi_enable(struct drm_encoder *encoder) { struct hdmi_context *hdata = encoder_to_hdmi(encoder); @@ -1591,10 +1490,13 @@ static void hdmi_enable(struct drm_encoder *encoder) if (regulator_bulk_enable(ARRAY_SIZE(supply), hdata->regul_bulk)) DRM_DEBUG_KMS("failed to enable regulator bulk\n"); - /* set pmu hdmiphy control bit to enable hdmiphy */ regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL, PMU_HDMI_PHY_ENABLE_BIT, 1); + hdmi_set_refclk(hdata, true); + + hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0, HDMI_PHY_POWER_OFF_EN); + hdmi_conf_apply(hdata); hdata->powered = true; @@ -1623,12 +1525,14 @@ static void hdmi_disable(struct drm_encoder *encoder) if (funcs && funcs->disable) (*funcs->disable)(crtc); - /* HDMI System Disable */ hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN); cancel_delayed_work(&hdata->hotplug_work); - /* reset pmu hdmiphy control bit to disable hdmiphy */ + hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0, HDMI_PHY_POWER_OFF_EN); + + hdmi_set_refclk(hdata, false); + regmap_update_bits(hdata->pmureg, PMU_HDMI_PHY_CONTROL, PMU_HDMI_PHY_ENABLE_BIT, 0); @@ -1670,6 +1574,57 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg) return IRQ_HANDLED; } +static int hdmi_clks_get(struct hdmi_context *hdata, + const struct string_array_spec *names, + struct clk **clks) +{ + struct device *dev = hdata->dev; + int i; + + for (i = 0; i < names->count; ++i) { + struct clk *clk = devm_clk_get(dev, names->data[i]); + + if (IS_ERR(clk)) { + int ret = PTR_ERR(clk); + + dev_err(dev, "Cannot get clock %s, %d\n", + names->data[i], ret); + + return ret; + } + + clks[i] = clk; + } + + return 0; +} + +static int hdmi_clk_init(struct hdmi_context *hdata) +{ + const struct hdmi_driver_data *drv_data = hdata->drv_data; + int count = drv_data->clk_gates.count + drv_data->clk_muxes.count; + struct device *dev = hdata->dev; + struct clk **clks; + int ret; + + if (!count) + return 0; + + clks = devm_kzalloc(dev, sizeof(*clks) * count, GFP_KERNEL); + if (!clks) + return -ENOMEM; + + hdata->clk_gates = clks; + hdata->clk_muxes = clks + drv_data->clk_gates.count; + + ret = hdmi_clks_get(hdata, &drv_data->clk_gates, hdata->clk_gates); + if (ret) + return ret; + + return hdmi_clks_get(hdata, &drv_data->clk_muxes, hdata->clk_muxes); +} + + static int hdmi_resources_init(struct hdmi_context *hdata) { struct device *dev = hdata->dev; @@ -1688,39 +1643,14 @@ static int hdmi_resources_init(struct hdmi_context *hdata) DRM_ERROR("failed to get GPIO irq\n"); return hdata->irq; } - /* get clocks, power */ - hdata->hdmi = devm_clk_get(dev, "hdmi"); - if (IS_ERR(hdata->hdmi)) { - DRM_ERROR("failed to get clock 'hdmi'\n"); - ret = PTR_ERR(hdata->hdmi); - goto fail; - } - hdata->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi"); - if (IS_ERR(hdata->sclk_hdmi)) { - DRM_ERROR("failed to get clock 'sclk_hdmi'\n"); - ret = PTR_ERR(hdata->sclk_hdmi); - goto fail; - } - hdata->sclk_pixel = devm_clk_get(dev, "sclk_pixel"); - if (IS_ERR(hdata->sclk_pixel)) { - DRM_ERROR("failed to get clock 'sclk_pixel'\n"); - ret = PTR_ERR(hdata->sclk_pixel); - goto fail; - } - hdata->sclk_hdmiphy = devm_clk_get(dev, "sclk_hdmiphy"); - if (IS_ERR(hdata->sclk_hdmiphy)) { - DRM_ERROR("failed to get clock 'sclk_hdmiphy'\n"); - ret = PTR_ERR(hdata->sclk_hdmiphy); - goto fail; - } - hdata->mout_hdmi = devm_clk_get(dev, "mout_hdmi"); - if (IS_ERR(hdata->mout_hdmi)) { - DRM_ERROR("failed to get clock 'mout_hdmi'\n"); - ret = PTR_ERR(hdata->mout_hdmi); - goto fail; - } - clk_set_parent(hdata->mout_hdmi, hdata->sclk_pixel); + ret = hdmi_clk_init(hdata); + if (ret) + return ret; + + ret = hdmi_clk_set_parents(hdata, false); + if (ret) + return ret; for (i = 0; i < ARRAY_SIZE(supply); ++i) { hdata->regul_bulk[i].supply = supply[i]; @@ -1745,9 +1675,6 @@ static int hdmi_resources_init(struct hdmi_context *hdata) DRM_ERROR("failed to enable hdmi-en regulator\n"); return ret; -fail: - DRM_ERROR("HDMI resource init - failed\n"); - return ret; } static struct of_device_id hdmi_match_types[] = { @@ -1761,6 +1688,9 @@ static struct of_device_id hdmi_match_types[] = { .compatible = "samsung,exynos5420-hdmi", .data = &exynos5420_hdmi_driver_data, }, { + .compatible = "samsung,exynos5433-hdmi", + .data = &exynos5433_hdmi_driver_data, + }, { /* end node */ } }; @@ -1830,7 +1760,6 @@ static struct device_node *hdmi_legacy_phy_dt_binding(struct device *dev) static int hdmi_probe(struct platform_device *pdev) { struct device_node *ddc_node, *phy_node; - const struct of_device_id *match; struct device *dev = &pdev->dev; struct hdmi_context *hdata; struct resource *res; @@ -1840,11 +1769,7 @@ static int hdmi_probe(struct platform_device *pdev) if (!hdata) return -ENOMEM; - match = of_match_device(hdmi_match_types, dev); - if (!match) - return -ENODEV; - - hdata->drv_data = match->data; + hdata->drv_data = of_device_get_match_data(dev); platform_set_drvdata(pdev, hdata); @@ -1867,7 +1792,6 @@ static int hdmi_probe(struct platform_device *pdev) if (ddc_node) goto out_get_ddc_adpt; - /* DDC i2c driver */ ddc_node = of_parse_phandle(dev->of_node, "ddc", 0); if (!ddc_node) { DRM_ERROR("Failed to find ddc node in device tree\n"); @@ -1885,7 +1809,6 @@ out_get_ddc_adpt: if (phy_node) goto out_get_phy_port; - /* hdmiphy i2c driver */ phy_node = of_parse_phandle(dev->of_node, "phy", 0); if (!phy_node) { DRM_ERROR("Failed to find hdmiphy node in device tree\n"); @@ -1929,6 +1852,16 @@ out_get_phy_port: goto err_hdmiphy; } + if (hdata->drv_data->has_sysreg) { + hdata->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node, + "samsung,sysreg-phandle"); + if (IS_ERR(hdata->sysreg)) { + DRM_ERROR("sysreg regmap lookup failed.\n"); + ret = -EPROBE_DEFER; + goto err_hdmiphy; + } + } + pm_runtime_enable(dev); ret = component_add(&pdev->dev, &hdmi_component_ops); @@ -1975,8 +1908,7 @@ static int exynos_hdmi_suspend(struct device *dev) { struct hdmi_context *hdata = dev_get_drvdata(dev); - clk_disable_unprepare(hdata->sclk_hdmi); - clk_disable_unprepare(hdata->hdmi); + hdmi_clk_disable_gates(hdata); return 0; } @@ -1986,17 +1918,9 @@ static int exynos_hdmi_resume(struct device *dev) struct hdmi_context *hdata = dev_get_drvdata(dev); int ret; - ret = clk_prepare_enable(hdata->hdmi); - if (ret < 0) { - DRM_ERROR("Failed to prepare_enable the hdmi clk [%d]\n", ret); - return ret; - } - ret = clk_prepare_enable(hdata->sclk_hdmi); - if (ret < 0) { - DRM_ERROR("Failed to prepare_enable the sclk_mixer clk [%d]\n", - ret); + ret = hdmi_clk_enable_gates(hdata); + if (ret < 0) return ret; - } return 0; } |