diff options
| -rw-r--r-- | drivers/gpu/drm/bridge/dw_hdmi.c | 54 | ||||
| -rw-r--r-- | drivers/gpu/drm/imx/dw_hdmi-imx.c | 12 | ||||
| -rw-r--r-- | drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 14 | ||||
| -rw-r--r-- | include/drm/bridge/dw_hdmi.h | 5 |
4 files changed, 45 insertions, 40 deletions
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c index cd6a70647e32..49cafb61d290 100644 --- a/drivers/gpu/drm/bridge/dw_hdmi.c +++ b/drivers/gpu/drm/bridge/dw_hdmi.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
| 17 | #include <linux/clk.h> | 17 | #include <linux/clk.h> |
| 18 | #include <linux/hdmi.h> | 18 | #include <linux/hdmi.h> |
| 19 | #include <linux/mutex.h> | ||
| 19 | #include <linux/of_device.h> | 20 | #include <linux/of_device.h> |
| 20 | 21 | ||
| 21 | #include <drm/drm_of.h> | 22 | #include <drm/drm_of.h> |
| @@ -126,6 +127,7 @@ struct dw_hdmi { | |||
| 126 | struct i2c_adapter *ddc; | 127 | struct i2c_adapter *ddc; |
| 127 | void __iomem *regs; | 128 | void __iomem *regs; |
| 128 | 129 | ||
| 130 | struct mutex audio_mutex; | ||
| 129 | unsigned int sample_rate; | 131 | unsigned int sample_rate; |
| 130 | int ratio; | 132 | int ratio; |
| 131 | 133 | ||
| @@ -177,26 +179,23 @@ static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg, | |||
| 177 | hdmi_modb(hdmi, data << shift, mask, reg); | 179 | hdmi_modb(hdmi, data << shift, mask, reg); |
| 178 | } | 180 | } |
| 179 | 181 | ||
| 180 | static void hdmi_set_clock_regenerator_n(struct dw_hdmi *hdmi, | 182 | static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts, |
| 181 | unsigned int value) | 183 | unsigned int n) |
| 182 | { | 184 | { |
| 183 | hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1); | 185 | /* Must be set/cleared first */ |
| 184 | hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2); | 186 | hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); |
| 185 | hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3); | ||
| 186 | 187 | ||
| 187 | /* nshift factor = 0 */ | 188 | /* nshift factor = 0 */ |
| 188 | hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3); | 189 | hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3); |
| 189 | } | ||
| 190 | |||
| 191 | static void hdmi_regenerate_cts(struct dw_hdmi *hdmi, unsigned int cts) | ||
| 192 | { | ||
| 193 | /* Must be set/cleared first */ | ||
| 194 | hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); | ||
| 195 | 190 | ||
| 196 | hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1); | ||
| 197 | hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2); | ||
| 198 | hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) | | 191 | hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) | |
| 199 | HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); | 192 | HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); |
| 193 | hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2); | ||
| 194 | hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1); | ||
| 195 | |||
| 196 | hdmi_writeb(hdmi, (n >> 16) & 0x0f, HDMI_AUD_N3); | ||
| 197 | hdmi_writeb(hdmi, (n >> 8) & 0xff, HDMI_AUD_N2); | ||
| 198 | hdmi_writeb(hdmi, n & 0xff, HDMI_AUD_N1); | ||
| 200 | } | 199 | } |
| 201 | 200 | ||
| 202 | static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk, | 201 | static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk, |
| @@ -355,18 +354,21 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi, | |||
| 355 | __func__, hdmi->sample_rate, hdmi->ratio, | 354 | __func__, hdmi->sample_rate, hdmi->ratio, |
| 356 | pixel_clk, clk_n, clk_cts); | 355 | pixel_clk, clk_n, clk_cts); |
| 357 | 356 | ||
| 358 | hdmi_set_clock_regenerator_n(hdmi, clk_n); | 357 | hdmi_set_cts_n(hdmi, clk_cts, clk_n); |
| 359 | hdmi_regenerate_cts(hdmi, clk_cts); | ||
| 360 | } | 358 | } |
| 361 | 359 | ||
| 362 | static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi) | 360 | static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi) |
| 363 | { | 361 | { |
| 362 | mutex_lock(&hdmi->audio_mutex); | ||
| 364 | hdmi_set_clk_regenerator(hdmi, 74250000); | 363 | hdmi_set_clk_regenerator(hdmi, 74250000); |
| 364 | mutex_unlock(&hdmi->audio_mutex); | ||
| 365 | } | 365 | } |
| 366 | 366 | ||
| 367 | static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi) | 367 | static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi) |
| 368 | { | 368 | { |
| 369 | mutex_lock(&hdmi->audio_mutex); | ||
| 369 | hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock); | 370 | hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock); |
| 371 | mutex_unlock(&hdmi->audio_mutex); | ||
| 370 | } | 372 | } |
| 371 | 373 | ||
| 372 | /* | 374 | /* |
| @@ -753,10 +755,10 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep, | |||
| 753 | { | 755 | { |
| 754 | unsigned res_idx, i; | 756 | unsigned res_idx, i; |
| 755 | u8 val, msec; | 757 | u8 val, msec; |
| 756 | const struct dw_hdmi_mpll_config *mpll_config = | 758 | const struct dw_hdmi_plat_data *plat_data = hdmi->plat_data; |
| 757 | hdmi->plat_data->mpll_cfg; | 759 | const struct dw_hdmi_mpll_config *mpll_config = plat_data->mpll_cfg; |
| 758 | const struct dw_hdmi_curr_ctrl *curr_ctrl = hdmi->plat_data->cur_ctr; | 760 | const struct dw_hdmi_curr_ctrl *curr_ctrl = plat_data->cur_ctr; |
| 759 | const struct dw_hdmi_sym_term *sym_term = hdmi->plat_data->sym_term; | 761 | const struct dw_hdmi_phy_config *phy_config = plat_data->phy_config; |
| 760 | 762 | ||
| 761 | if (prep) | 763 | if (prep) |
| 762 | return -EINVAL; | 764 | return -EINVAL; |
| @@ -827,18 +829,18 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep, | |||
| 827 | hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */ | 829 | hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */ |
| 828 | hdmi_phy_i2c_write(hdmi, 0x0006, 0x17); | 830 | hdmi_phy_i2c_write(hdmi, 0x0006, 0x17); |
| 829 | 831 | ||
| 830 | for (i = 0; sym_term[i].mpixelclock != (~0UL); i++) | 832 | for (i = 0; phy_config[i].mpixelclock != (~0UL); i++) |
| 831 | if (hdmi->hdmi_data.video_mode.mpixelclock <= | 833 | if (hdmi->hdmi_data.video_mode.mpixelclock <= |
| 832 | sym_term[i].mpixelclock) | 834 | phy_config[i].mpixelclock) |
| 833 | break; | 835 | break; |
| 834 | 836 | ||
| 835 | /* RESISTANCE TERM 133Ohm Cfg */ | 837 | /* RESISTANCE TERM 133Ohm Cfg */ |
| 836 | hdmi_phy_i2c_write(hdmi, sym_term[i].term, 0x19); /* TXTERM */ | 838 | hdmi_phy_i2c_write(hdmi, phy_config[i].term, 0x19); /* TXTERM */ |
| 837 | /* PREEMP Cgf 0.00 */ | 839 | /* PREEMP Cgf 0.00 */ |
| 838 | hdmi_phy_i2c_write(hdmi, sym_term[i].sym_ctr, 0x09); /* CKSYMTXCTRL */ | 840 | hdmi_phy_i2c_write(hdmi, phy_config[i].sym_ctr, 0x09); /* CKSYMTXCTRL */ |
| 839 | |||
| 840 | /* TX/CK LVL 10 */ | 841 | /* TX/CK LVL 10 */ |
| 841 | hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E); /* VLEVCTRL */ | 842 | hdmi_phy_i2c_write(hdmi, phy_config[i].vlev_ctr, 0x0E); /* VLEVCTRL */ |
| 843 | |||
| 842 | /* REMOVE CLK TERM */ | 844 | /* REMOVE CLK TERM */ |
| 843 | hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */ | 845 | hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */ |
| 844 | 846 | ||
| @@ -1569,6 +1571,8 @@ int dw_hdmi_bind(struct device *dev, struct device *master, | |||
| 1569 | hdmi->ratio = 100; | 1571 | hdmi->ratio = 100; |
| 1570 | hdmi->encoder = encoder; | 1572 | hdmi->encoder = encoder; |
| 1571 | 1573 | ||
| 1574 | mutex_init(&hdmi->audio_mutex); | ||
| 1575 | |||
| 1572 | of_property_read_u32(np, "reg-io-width", &val); | 1576 | of_property_read_u32(np, "reg-io-width", &val); |
| 1573 | 1577 | ||
| 1574 | switch (val) { | 1578 | switch (val) { |
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c index 1834ac8998cc..a3ecf1069b76 100644 --- a/drivers/gpu/drm/imx/dw_hdmi-imx.c +++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c | |||
| @@ -75,10 +75,10 @@ static const struct dw_hdmi_curr_ctrl imx_cur_ctr[] = { | |||
| 75 | }, | 75 | }, |
| 76 | }; | 76 | }; |
| 77 | 77 | ||
| 78 | static const struct dw_hdmi_sym_term imx_sym_term[] = { | 78 | static const struct dw_hdmi_phy_config imx_phy_config[] = { |
| 79 | /*pixelclk symbol term*/ | 79 | /*pixelclk symbol term vlev */ |
| 80 | { 148500000, 0x800d, 0x0005 }, | 80 | { 148500000, 0x800d, 0x0005, 0x01ad}, |
| 81 | { ~0UL, 0x0000, 0x0000 } | 81 | { ~0UL, 0x0000, 0x0000, 0x0000} |
| 82 | }; | 82 | }; |
| 83 | 83 | ||
| 84 | static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi) | 84 | static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi) |
| @@ -163,7 +163,7 @@ static enum drm_mode_status imx6dl_hdmi_mode_valid(struct drm_connector *con, | |||
| 163 | static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = { | 163 | static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = { |
| 164 | .mpll_cfg = imx_mpll_cfg, | 164 | .mpll_cfg = imx_mpll_cfg, |
| 165 | .cur_ctr = imx_cur_ctr, | 165 | .cur_ctr = imx_cur_ctr, |
| 166 | .sym_term = imx_sym_term, | 166 | .phy_config = imx_phy_config, |
| 167 | .dev_type = IMX6Q_HDMI, | 167 | .dev_type = IMX6Q_HDMI, |
| 168 | .mode_valid = imx6q_hdmi_mode_valid, | 168 | .mode_valid = imx6q_hdmi_mode_valid, |
| 169 | }; | 169 | }; |
| @@ -171,7 +171,7 @@ static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = { | |||
| 171 | static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = { | 171 | static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = { |
| 172 | .mpll_cfg = imx_mpll_cfg, | 172 | .mpll_cfg = imx_mpll_cfg, |
| 173 | .cur_ctr = imx_cur_ctr, | 173 | .cur_ctr = imx_cur_ctr, |
| 174 | .sym_term = imx_sym_term, | 174 | .phy_config = imx_phy_config, |
| 175 | .dev_type = IMX6DL_HDMI, | 175 | .dev_type = IMX6DL_HDMI, |
| 176 | .mode_valid = imx6dl_hdmi_mode_valid, | 176 | .mode_valid = imx6dl_hdmi_mode_valid, |
| 177 | }; | 177 | }; |
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index d236faa05b19..80d6fc8a5cee 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | |||
| @@ -133,12 +133,12 @@ static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { | |||
| 133 | } | 133 | } |
| 134 | }; | 134 | }; |
| 135 | 135 | ||
| 136 | static const struct dw_hdmi_sym_term rockchip_sym_term[] = { | 136 | static const struct dw_hdmi_phy_config rockchip_phy_config[] = { |
| 137 | /*pixelclk symbol term*/ | 137 | /*pixelclk symbol term vlev*/ |
| 138 | { 74250000, 0x8009, 0x0004 }, | 138 | { 74250000, 0x8009, 0x0004, 0x0272}, |
| 139 | { 148500000, 0x8029, 0x0004 }, | 139 | { 148500000, 0x802b, 0x0004, 0x028d}, |
| 140 | { 297000000, 0x8039, 0x0005 }, | 140 | { 297000000, 0x8039, 0x0005, 0x028d}, |
| 141 | { ~0UL, 0x0000, 0x0000 } | 141 | { ~0UL, 0x0000, 0x0000, 0x0000} |
| 142 | }; | 142 | }; |
| 143 | 143 | ||
| 144 | static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) | 144 | static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) |
| @@ -230,7 +230,7 @@ static const struct dw_hdmi_plat_data rockchip_hdmi_drv_data = { | |||
| 230 | .mode_valid = dw_hdmi_rockchip_mode_valid, | 230 | .mode_valid = dw_hdmi_rockchip_mode_valid, |
| 231 | .mpll_cfg = rockchip_mpll_cfg, | 231 | .mpll_cfg = rockchip_mpll_cfg, |
| 232 | .cur_ctr = rockchip_cur_ctr, | 232 | .cur_ctr = rockchip_cur_ctr, |
| 233 | .sym_term = rockchip_sym_term, | 233 | .phy_config = rockchip_phy_config, |
| 234 | .dev_type = RK3288_HDMI, | 234 | .dev_type = RK3288_HDMI, |
| 235 | }; | 235 | }; |
| 236 | 236 | ||
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 5a4f49005169..de13bfc35634 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h | |||
| @@ -38,17 +38,18 @@ struct dw_hdmi_curr_ctrl { | |||
| 38 | u16 curr[DW_HDMI_RES_MAX]; | 38 | u16 curr[DW_HDMI_RES_MAX]; |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | struct dw_hdmi_sym_term { | 41 | struct dw_hdmi_phy_config { |
| 42 | unsigned long mpixelclock; | 42 | unsigned long mpixelclock; |
| 43 | u16 sym_ctr; /*clock symbol and transmitter control*/ | 43 | u16 sym_ctr; /*clock symbol and transmitter control*/ |
| 44 | u16 term; /*transmission termination value*/ | 44 | u16 term; /*transmission termination value*/ |
| 45 | u16 vlev_ctr; /* voltage level control */ | ||
| 45 | }; | 46 | }; |
| 46 | 47 | ||
| 47 | struct dw_hdmi_plat_data { | 48 | struct dw_hdmi_plat_data { |
| 48 | enum dw_hdmi_devtype dev_type; | 49 | enum dw_hdmi_devtype dev_type; |
| 49 | const struct dw_hdmi_mpll_config *mpll_cfg; | 50 | const struct dw_hdmi_mpll_config *mpll_cfg; |
| 50 | const struct dw_hdmi_curr_ctrl *cur_ctr; | 51 | const struct dw_hdmi_curr_ctrl *cur_ctr; |
| 51 | const struct dw_hdmi_sym_term *sym_term; | 52 | const struct dw_hdmi_phy_config *phy_config; |
| 52 | enum drm_mode_status (*mode_valid)(struct drm_connector *connector, | 53 | enum drm_mode_status (*mode_valid)(struct drm_connector *connector, |
| 53 | struct drm_display_mode *mode); | 54 | struct drm_display_mode *mode); |
| 54 | }; | 55 | }; |
