diff --git a/drivers/clk/msm/mdss/mdss-dp-pll-cobalt-util.c b/drivers/clk/msm/mdss/mdss-dp-pll-cobalt-util.c index 9a080e4ee39b..a574a9cd2b5a 100644 --- a/drivers/clk/msm/mdss/mdss-dp-pll-cobalt-util.c +++ b/drivers/clk/msm/mdss/mdss-dp-pll-cobalt-util.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "mdss-pll.h" #include "mdss-dp-pll.h" @@ -172,9 +173,27 @@ int dp_config_vco_rate(struct dp_pll_vco_clk *vco, unsigned long rate) { u32 res = 0; struct mdss_pll_resources *dp_res = vco->priv; + u8 orientation, ln_cnt; + u32 spare_value; + + spare_value = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_SPARE0); + ln_cnt = spare_value & 0x0F; + orientation = (spare_value & 0xF0) >> 4; + pr_debug("%s: spare_value=0x%x, ln_cnt=0x%x, orientation=0x%x\n", + __func__, spare_value, ln_cnt, orientation); + + if (ln_cnt != 4) { + if (orientation == ORIENTATION_CC2) + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_PD_CTL, 0x2d); + else + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_PD_CTL, 0x35); + } else { + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_PD_CTL, 0x3d); + } - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_PD_CTL, 0x3d); /* Make sure the PHY register writes are done */ wmb(); MDSS_PLL_REG_W(dp_res->pll_base, @@ -314,8 +333,13 @@ int dp_config_vco_rate(struct dp_pll_vco_clk *vco, unsigned long rate) /* Make sure the PLL register writes are done */ wmb(); - MDSS_PLL_REG_W(dp_res->phy_base, - DP_PHY_MODE, 0x58); + if (orientation == ORIENTATION_CC2) + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_MODE, 0x48); + else + MDSS_PLL_REG_W(dp_res->phy_base, + DP_PHY_MODE, 0x58); + MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_TX0_TX1_LANE_CTL, 0x05); MDSS_PLL_REG_W(dp_res->phy_base, @@ -427,6 +451,12 @@ static int dp_pll_enable(struct clk *c) u32 status; struct dp_pll_vco_clk *vco = mdss_dp_to_vco_clk(c); struct mdss_pll_resources *dp_res = vco->priv; + u8 orientation, ln_cnt; + u32 spare_value, bias_en, drvr_en; + + spare_value = MDSS_PLL_REG_R(dp_res->phy_base, DP_PHY_SPARE0); + ln_cnt = spare_value & 0x0F; + orientation = (spare_value & 0xF0) >> 4; MDSS_PLL_REG_W(dp_res->phy_base, DP_PHY_CFG, 0x01); @@ -474,18 +504,45 @@ static int dp_pll_enable(struct clk *c) pr_debug("%s: PLL is locked\n", __func__); - MDSS_PLL_REG_W(dp_res->phy_base, + if (ln_cnt == 1) { + bias_en = 0x3e; + drvr_en = 0x13; + } else { + bias_en = 0x3f; + drvr_en = 0x10; + } + + if (ln_cnt != 4) { + if (orientation == ORIENTATION_CC1) { + MDSS_PLL_REG_W(dp_res->phy_base, QSERDES_TX1_OFFSET + TXn_TRANSCEIVER_BIAS_EN, - 0x3f); - MDSS_PLL_REG_W(dp_res->phy_base, + bias_en); + MDSS_PLL_REG_W(dp_res->phy_base, QSERDES_TX1_OFFSET + TXn_HIGHZ_DRVR_EN, - 0x10); - MDSS_PLL_REG_W(dp_res->phy_base, + drvr_en); + } else { + MDSS_PLL_REG_W(dp_res->phy_base, QSERDES_TX0_OFFSET + TXn_TRANSCEIVER_BIAS_EN, - 0x3f); - MDSS_PLL_REG_W(dp_res->phy_base, + bias_en); + MDSS_PLL_REG_W(dp_res->phy_base, QSERDES_TX0_OFFSET + TXn_HIGHZ_DRVR_EN, - 0x10); + drvr_en); + } + } else { + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_TRANSCEIVER_BIAS_EN, + bias_en); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX0_OFFSET + TXn_HIGHZ_DRVR_EN, + drvr_en); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_TRANSCEIVER_BIAS_EN, + bias_en); + MDSS_PLL_REG_W(dp_res->phy_base, + QSERDES_TX1_OFFSET + TXn_HIGHZ_DRVR_EN, + drvr_en); + } + MDSS_PLL_REG_W(dp_res->phy_base, QSERDES_TX0_OFFSET + TXn_TX_POL_INV, 0x0a); @@ -615,7 +672,7 @@ int dp_vco_prepare(struct clk *c) rc = dp_pll_enable(c); if (rc) { mdss_pll_resource_enable(dp_pll_res, false); - pr_err("ndx=%d failed to enable dsi pll\n", + pr_err("ndx=%d failed to enable dp pll\n", dp_pll_res->index); goto error; } diff --git a/drivers/clk/msm/mdss/mdss-dp-pll-cobalt.h b/drivers/clk/msm/mdss/mdss-dp-pll-cobalt.h index d89545b38e64..28f21ed1fe0d 100644 --- a/drivers/clk/msm/mdss/mdss-dp-pll-cobalt.h +++ b/drivers/clk/msm/mdss/mdss-dp-pll-cobalt.h @@ -41,6 +41,7 @@ #define DP_PHY_TX0_TX1_LANE_CTL 0x0068 #define DP_PHY_TX2_TX3_LANE_CTL 0x0084 +#define DP_PHY_SPARE0 0x00A8 #define DP_PHY_STATUS 0x00BC /* Tx registers */ diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index 57e18a7dc5e1..42334941f809 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -789,17 +789,34 @@ void mdss_dp_config_ctrl(struct mdss_dp_drv_pdata *dp) cap = &dp->dpcd; - data = dp->lane_cnt - 1; - data <<= 4; + data |= (2 << 13); /* Default-> LSCLK DIV: 1/4 LCLK */ + + /* Color Format */ + switch (dp->panel_data.panel_info.out_format) { + case MDP_Y_CBCR_H2V2: + data |= (1 << 11); /* YUV420 */ + break; + case MDP_Y_CBCR_H2V1: + data |= (2 << 11); /* YUV422 */ + break; + default: + data |= (0 << 11); /* RGB */ + break; + } + + /* Scrambler reset enable */ + if (cap->scrambler_reset) + data |= (1 << 10); + + if (dp->edid.color_depth != 6) + data |= 0x100; /* Default: 8 bits */ + + /* Num of Lanes */ + data |= ((dp->lane_cnt - 1) << 4); if (cap->enhanced_frame) data |= 0x40; - if (dp->edid.color_depth == 8) { - /* 0 == 6 bits, 1 == 8 bits */ - data |= 0x100; /* bit 8 */ - } - if (!timing->interlaced) /* progressive */ data |= 0x04; @@ -863,6 +880,8 @@ static int dp_audio_info_setup(struct platform_device *pdev, mdss_dp_set_safe_to_exit_level(&dp_ctrl->ctrl_io, dp_ctrl->lane_cnt); mdss_dp_audio_enable(&dp_ctrl->ctrl_io, true); + dp_ctrl->wait_for_audio_comp = true; + return rc; } /* dp_audio_info_setup */ @@ -885,6 +904,17 @@ static int dp_get_audio_edid_blk(struct platform_device *pdev, return rc; } /* dp_get_audio_edid_blk */ +static void dp_audio_codec_teardown_done(struct platform_device *pdev) +{ + struct mdss_dp_drv_pdata *dp = platform_get_drvdata(pdev); + + if (!dp) + pr_err("invalid input\n"); + + pr_debug("audio codec teardown done\n"); + complete_all(&dp->audio_comp); +} + static int mdss_dp_init_ext_disp(struct mdss_dp_drv_pdata *dp) { int ret = 0; @@ -906,6 +936,8 @@ static int mdss_dp_init_ext_disp(struct mdss_dp_drv_pdata *dp) dp_get_audio_edid_blk; dp->ext_audio_data.codec_ops.cable_status = dp_get_cable_status; + dp->ext_audio_data.codec_ops.teardown_done = + dp_audio_codec_teardown_done; if (!dp->pdev->dev.of_node) { pr_err("%s cannot find dp dev.of_node\n", __func__); @@ -987,6 +1019,13 @@ static int dp_init_panel_info(struct mdss_dp_drv_pdata *dp_drv, u32 vic) return 0; } /* dp_init_panel_info */ +static inline void mdss_dp_set_audio_switch_node( + struct mdss_dp_drv_pdata *dp, int val) +{ + if (dp && dp->ext_audio_data.intf_ops.notify) + dp->ext_audio_data.intf_ops.notify(dp->ext_pdev, + val); +} int mdss_dp_on(struct mdss_panel_data *pdata) { @@ -1054,6 +1093,9 @@ int mdss_dp_on(struct mdss_panel_data *pdata) goto exit; } + mdss_dp_phy_share_lane_config(&dp_drv->phy_io, + orientation, dp_drv->dpcd.max_lane_count); + pr_debug("link_rate = 0x%x\n", dp_drv->link_rate); dp_drv->power_data[DP_CTRL_PM].clk_config[0].rate = @@ -1096,6 +1138,7 @@ int mdss_dp_on(struct mdss_panel_data *pdata) pr_debug("mainlink ready\n"); dp_drv->power_on = true; + mdss_dp_set_audio_switch_node(dp_drv, true); pr_debug("End-\n"); exit: @@ -1119,14 +1162,15 @@ int mdss_dp_off(struct mdss_panel_data *pdata) mutex_lock(&dp_drv->train_mutex); reinit_completion(&dp_drv->idle_comp); - - mdss_dp_state_ctrl(&dp_drv->ctrl_io, 0); + mdss_dp_state_ctrl(&dp_drv->ctrl_io, ST_PUSH_IDLE); if (dp_drv->link_clks_on) mdss_dp_mainlink_ctrl(&dp_drv->ctrl_io, false); mdss_dp_aux_ctrl(&dp_drv->ctrl_io, false); + mdss_dp_audio_enable(&dp_drv->ctrl_io, false); + mdss_dp_irq_disable(dp_drv); mdss_dp_config_gpios(dp_drv, false); @@ -1147,14 +1191,6 @@ int mdss_dp_off(struct mdss_panel_data *pdata) return 0; } -static inline void mdss_dp_set_audio_switch_node( - struct mdss_dp_drv_pdata *dp, int val) -{ - if (dp && dp->ext_audio_data.intf_ops.notify) - dp->ext_audio_data.intf_ops.notify(dp->ext_pdev, - val); -} - static void mdss_dp_send_cable_notification( struct mdss_dp_drv_pdata *dp, int val) { @@ -1169,6 +1205,38 @@ static void mdss_dp_send_cable_notification( dp->ext_audio_data.type, val); } +static void mdss_dp_audio_codec_wait(struct mdss_dp_drv_pdata *dp) +{ + const int audio_completion_timeout_ms = HZ * 3; + int ret = 0; + + if (!dp->wait_for_audio_comp) + return; + + reinit_completion(&dp->audio_comp); + ret = wait_for_completion_timeout(&dp->audio_comp, + audio_completion_timeout_ms); + if (ret <= 0) + pr_warn("audio codec teardown timed out\n"); + + dp->wait_for_audio_comp = false; +} + +static void mdss_dp_notify_clients(struct mdss_dp_drv_pdata *dp, bool enable) +{ + if (enable) { + mdss_dp_send_cable_notification(dp, enable); + } else { + mdss_dp_set_audio_switch_node(dp, enable); + mdss_dp_audio_codec_wait(dp); + mdss_dp_send_cable_notification(dp, enable); + } + + pr_debug("notify state %s done\n", + enable ? "ENABLE" : "DISABLE"); +} + + static int mdss_dp_edid_init(struct mdss_panel_data *pdata) { struct mdss_dp_drv_pdata *dp_drv = NULL; @@ -1236,15 +1304,19 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata) mdss_dp_aux_init(dp_drv); + mdss_dp_phy_initialize(dp_drv); + mdss_dp_ctrl_reset(&dp_drv->ctrl_io); mdss_dp_phy_reset(&dp_drv->ctrl_io); mdss_dp_aux_reset(&dp_drv->ctrl_io); - mdss_dp_phy_initialize(dp_drv); mdss_dp_aux_ctrl(&dp_drv->ctrl_io, true); pr_debug("Ctrl_hw_rev =0x%x, phy hw_rev =0x%x\n", mdss_dp_get_ctrl_hw_version(&dp_drv->ctrl_io), mdss_dp_get_phy_hw_version(&dp_drv->phy_io)); + pr_debug("plug Orientation = %d\n", + usbpd_get_plug_orientation(dp_drv->pd)); + mdss_dp_phy_aux_setup(&dp_drv->phy_io); mdss_dp_irq_enable(dp_drv); @@ -1264,8 +1336,7 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata) goto edid_error; } - mdss_dp_send_cable_notification(dp_drv, true); - mdss_dp_set_audio_switch_node(dp_drv, true); + mdss_dp_notify_clients(dp_drv, true); dp_drv->dp_initialized = true; return ret; @@ -1771,8 +1842,7 @@ static void dp_send_events(struct mdss_dp_drv_pdata *dp, u32 events) { spin_lock(&dp->event_lock); dp->current_event = events; - queue_delayed_work(dp->workq, - &dp->dwork, HZ); + queue_delayed_work(dp->workq, &dp->dwork, HZ / 100); spin_unlock(&dp->event_lock); } @@ -1883,8 +1953,7 @@ static void usbpd_disconnect_callback(struct usbpd_svid_handler *hdlr) mutex_lock(&dp_drv->pd_msg_mutex); dp_drv->cable_connected = false; mutex_unlock(&dp_drv->pd_msg_mutex); - mdss_dp_send_cable_notification(dp_drv, false); - mdss_dp_set_audio_switch_node(dp_drv, false); + mdss_dp_notify_clients(dp_drv, false); } static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd, @@ -2135,6 +2204,8 @@ static int mdss_dp_probe(struct platform_device *pdev) mdss_dp_device_register(dp_drv); dp_drv->inited = true; + dp_drv->wait_for_audio_comp = false; + init_completion(&dp_drv->audio_comp); pr_debug("done\n"); diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h index 4710cf7a98e2..ddadb7b6709c 100644 --- a/drivers/video/fbdev/msm/mdss_dp.h +++ b/drivers/video/fbdev/msm/mdss_dp.h @@ -399,6 +399,7 @@ struct mdss_dp_drv_pdata { struct completion train_comp; struct completion idle_comp; struct completion video_comp; + struct completion audio_comp; struct mutex aux_mutex; struct mutex train_mutex; struct mutex pd_msg_mutex; @@ -423,6 +424,7 @@ struct mdss_dp_drv_pdata { char delay_start; u32 bpp; struct dp_statistic dp_stat; + bool wait_for_audio_comp; /* event */ struct workqueue_struct *workq; diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c index d9297a7af764..136dbb13cc62 100644 --- a/drivers/video/fbdev/msm/mdss_dp_aux.c +++ b/drivers/video/fbdev/msm/mdss_dp_aux.c @@ -1113,17 +1113,17 @@ static void dp_host_train_set(struct mdss_dp_drv_pdata *ep, int train) } char vm_pre_emphasis[4][4] = { - {0x00, 0x06, 0x09, 0x0C}, /* pe0, 0 db */ - {0x00, 0x06, 0x09, 0xFF}, /* pe1, 3.5 db */ - {0x03, 0x06, 0xFF, 0xFF}, /* pe2, 6.0 db */ - {0x03, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */ + {0x00, 0x09, 0x11, 0x0C}, /* pe0, 0 db */ + {0x00, 0x0A, 0x10, 0xFF}, /* pe1, 3.5 db */ + {0x00, 0x0C, 0xFF, 0xFF}, /* pe2, 6.0 db */ + {0x00, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */ }; /* voltage swing, 0.2v and 1.0v are not support */ char vm_voltage_swing[4][4] = { - {0x0a, 0x18, 0x1A, 0x1E}, /* sw0, 0.4v */ - {0x07, 0x1A, 0x1E, 0xFF}, /* sw1, 0.6 v */ - {0x1A, 0x1E, 0xFF, 0xFF}, /* sw1, 0.8 v */ + {0x07, 0x0f, 0x12, 0x1E}, /* sw0, 0.4v */ + {0x11, 0x1D, 0x1F, 0xFF}, /* sw1, 0.6 v */ + {0x18, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */ {0x1E, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */ }; diff --git a/drivers/video/fbdev/msm/mdss_dp_util.c b/drivers/video/fbdev/msm/mdss_dp_util.c index bdf5d92f7053..f6f2b54c2d80 100644 --- a/drivers/video/fbdev/msm/mdss_dp_util.c +++ b/drivers/video/fbdev/msm/mdss_dp_util.c @@ -143,6 +143,18 @@ void mdss_dp_aux_reset(struct dss_io_data *ctrl_io) writel_relaxed(aux_ctrl, ctrl_io->base + DP_AUX_CTRL); } +/* reset DP controller */ +void mdss_dp_ctrl_reset(struct dss_io_data *ctrl_io) +{ + u32 sw_reset = readl_relaxed(ctrl_io->base + DP_SW_RESET); + + sw_reset |= BIT(0); + writel_relaxed(sw_reset, ctrl_io->base + DP_SW_RESET); + udelay(1000); + sw_reset &= ~BIT(0); + writel_relaxed(sw_reset, ctrl_io->base + DP_SW_RESET); +} + /* reset DP Mainlink */ void mdss_dp_mainlink_reset(struct dss_io_data *ctrl_io) { @@ -441,6 +453,17 @@ u32 mdss_dp_usbpd_gen_config_pkt(struct mdss_dp_drv_pdata *dp) return config; } +void mdss_dp_phy_share_lane_config(struct dss_io_data *phy_io, + u8 orientation, u8 ln_cnt) +{ + u32 info = 0x0; + + info |= (ln_cnt & 0x0F); + info |= ((orientation & 0x0F) << 4); + pr_debug("Shared Info = 0x%x\n", info); + writel_relaxed(info, phy_io->base + DP_PHY_SPARE0); +} + void mdss_dp_config_audio_acr_ctrl(struct dss_io_data *ctrl_io, char link_rate) { u32 acr_ctrl = 0; diff --git a/drivers/video/fbdev/msm/mdss_dp_util.h b/drivers/video/fbdev/msm/mdss_dp_util.h index 5eb9d092476f..80dedba33ec5 100644 --- a/drivers/video/fbdev/msm/mdss_dp_util.h +++ b/drivers/video/fbdev/msm/mdss_dp_util.h @@ -150,6 +150,8 @@ #define DP_PHY_AUX_INTERRUPT_MASK (0x00000044) #define DP_PHY_AUX_INTERRUPT_CLEAR (0x00000048) +#define DP_PHY_SPARE0 0x00A8 + #define QSERDES_TX0_OFFSET 0x0400 #define QSERDES_TX1_OFFSET 0x0800 @@ -205,6 +207,7 @@ int dp_aux_write(void *ep, struct edp_cmd *cmd); void mdss_dp_state_ctrl(struct dss_io_data *ctrl_io, u32 data); u32 mdss_dp_get_ctrl_hw_version(struct dss_io_data *ctrl_io); u32 mdss_dp_get_phy_hw_version(struct dss_io_data *phy_io); +void mdss_dp_ctrl_reset(struct dss_io_data *ctrl_io); void mdss_dp_aux_reset(struct dss_io_data *ctrl_io); void mdss_dp_mainlink_reset(struct dss_io_data *ctrl_io); void mdss_dp_phy_reset(struct dss_io_data *ctrl_io); @@ -231,6 +234,8 @@ void mdss_dp_usbpd_ext_dp_status(struct usbpd_dp_status *dp_status); u32 mdss_dp_usbpd_gen_config_pkt(struct mdss_dp_drv_pdata *dp); void mdss_dp_ctrl_lane_mapping(struct dss_io_data *ctrl_io, struct lane_mapping l_map); +void mdss_dp_phy_share_lane_config(struct dss_io_data *phy_io, + u8 orientation, u8 ln_cnt); void mdss_dp_config_audio_acr_ctrl(struct dss_io_data *ctrl_io, char link_rate); void mdss_dp_audio_setup_sdps(struct dss_io_data *ctrl_io); diff --git a/drivers/video/fbdev/msm/msm_ext_display.c b/drivers/video/fbdev/msm/msm_ext_display.c index e229f52057d4..4899231787f2 100644 --- a/drivers/video/fbdev/msm/msm_ext_display.c +++ b/drivers/video/fbdev/msm/msm_ext_display.c @@ -365,6 +365,7 @@ static int msm_ext_disp_hpd(struct platform_device *pdev, ext_disp->ops->get_audio_edid_blk = NULL; ext_disp->ops->cable_status = NULL; ext_disp->ops->get_intf_id = NULL; + ext_disp->ops->teardown_done = NULL; } ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX; @@ -463,6 +464,20 @@ end: return ret; } +static void msm_ext_disp_teardown_done(struct platform_device *pdev) +{ + int ret = 0; + struct msm_ext_disp_init_data *data = NULL; + + ret = msm_ext_disp_get_intf_data_helper(pdev, &data); + if (ret || !data) { + pr_err("invalid input"); + return; + } + + data->codec_ops.teardown_done(data->pdev); +} + static int msm_ext_disp_get_intf_id(struct platform_device *pdev) { int ret = 0; @@ -545,6 +560,8 @@ static int msm_ext_disp_notify(struct platform_device *pdev, msm_ext_disp_cable_status; ext_disp->ops->get_intf_id = msm_ext_disp_get_intf_id; + ext_disp->ops->teardown_done = + msm_ext_disp_teardown_done; } switch_set_state(&ext_disp->audio_sdev, (int)new_state); @@ -614,6 +631,7 @@ static int msm_ext_disp_audio_ack(struct platform_device *pdev, u32 ack) ext_disp->ops->get_audio_edid_blk = NULL; ext_disp->ops->cable_status = NULL; ext_disp->ops->get_intf_id = NULL; + ext_disp->ops->teardown_done = NULL; } ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX; diff --git a/include/linux/msm_ext_display.h b/include/linux/msm_ext_display.h index 873a778d5370..59ba776b5f9b 100644 --- a/include/linux/msm_ext_display.h +++ b/include/linux/msm_ext_display.h @@ -108,6 +108,7 @@ struct msm_ext_disp_audio_codec_ops { struct msm_ext_disp_audio_edid_blk *blk); int (*cable_status)(struct platform_device *pdev, u32 vote); int (*get_intf_id)(struct platform_device *pdev); + void (*teardown_done)(struct platform_device *pdev); }; /*