diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index a349b09906d7..d74d891a761c 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -35,8 +35,6 @@ /* Master structure to hold all the information about the DSI/panel */ static struct mdss_dsi_data *mdss_dsi_res; -static struct dsi_drv_cm_data shared_ctrl_data; - static int mdss_dsi_pinctrl_set_state(struct mdss_dsi_ctrl_pdata *ctrl_pdata, bool active); @@ -1939,12 +1937,12 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, ctrl_pdata->refresh_clk_rate = true; break; case MDSS_EVENT_LINK_READY: + mdss_dsi_get_hw_revision(ctrl_pdata); rc = mdss_dsi_on(pdata); mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, pdata); break; case MDSS_EVENT_UNBLANK: - mdss_dsi_get_hw_revision(ctrl_pdata); if (ctrl_pdata->refresh_clk_rate) rc = mdss_dsi_clk_refresh(pdata); @@ -2450,6 +2448,8 @@ static int mdss_dsi_res_init(struct platform_device *pdev) goto mem_fail; } + mutex_init(&sdata->phy_reg_lock); + for (i = 0; i < DSI_CTRL_MAX; i++) { mdss_dsi_res->ctrl_pdata[i] = devm_kzalloc(&pdev->dev, sizeof(struct mdss_dsi_ctrl_pdata), @@ -2741,18 +2741,15 @@ int mdss_dsi_retrieve_ctrl_resources(struct platform_device *pdev, int mode, return rc; } - ctrl->shared_ctrl_data = &shared_ctrl_data; - rc = msm_dss_ioremap_byname(pdev, - &ctrl->shared_ctrl_data->phy_regulator_io, + rc = msm_dss_ioremap_byname(pdev, &ctrl->phy_regulator_io, "dsi_phy_regulator"); if (rc) pr_debug("%s:%d unable to remap dsi phy regulator resources\n", __func__, __LINE__); else pr_info("%s: phy_regulator_base=%p phy_regulator_size=%x\n", - __func__, - ctrl->shared_ctrl_data->phy_regulator_io.base, - ctrl->shared_ctrl_data->phy_regulator_io.len); + __func__, ctrl->phy_regulator_io.base, + ctrl->phy_regulator_io.len); pr_info("%s: ctrl_base=%p ctrl_size=%x phy_base=%p phy_size=%x\n", __func__, ctrl->ctrl_base, ctrl->reg_size, ctrl->phy_io.base, @@ -3094,6 +3091,7 @@ int dsi_panel_device_register(struct platform_device *ctrl_pdev, mdss_dsi_panel_pwm_enable(ctrl_pdata); pinfo->blank_state = MDSS_PANEL_BLANK_UNBLANK; mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1); + ctrl_pdata->is_phyreg_enabled = 1; ctrl_pdata->ctrl_state |= (CTRL_STATE_PANEL_INIT | CTRL_STATE_MDP_ACTIVE); } else { @@ -3109,18 +3107,16 @@ int dsi_panel_device_register(struct platform_device *ctrl_pdev, if (pinfo->pdest == DISPLAY_1) { mdss_debug_register_io("dsi0_ctrl", &ctrl_pdata->ctrl_io, NULL); mdss_debug_register_io("dsi0_phy", &ctrl_pdata->phy_io, NULL); - if (ctrl_pdata->shared_ctrl_data->phy_regulator_io.len) + if (ctrl_pdata->phy_regulator_io.len) mdss_debug_register_io("dsi0_phy_regulator", - &ctrl_pdata->shared_ctrl_data->phy_regulator_io, - NULL); + &ctrl_pdata->phy_regulator_io, NULL); ctrl_pdata->ndx = 0; } else { mdss_debug_register_io("dsi1_ctrl", &ctrl_pdata->ctrl_io, NULL); mdss_debug_register_io("dsi1_phy", &ctrl_pdata->phy_io, NULL); - if (ctrl_pdata->shared_ctrl_data->phy_regulator_io.len) + if (ctrl_pdata->phy_regulator_io.len) mdss_debug_register_io("dsi1_phy_regulator", - &ctrl_pdata->shared_ctrl_data->phy_regulator_io, - NULL); + &ctrl_pdata->phy_regulator_io, NULL); ctrl_pdata->ndx = 1; } diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index 2600590a24af..858231f95b4f 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -251,6 +251,9 @@ struct dsi_shared_data { /* DSI core regulators */ struct dss_module_power power_data[DSI_MAX_PM]; + + /* Shared mutex for DSI PHY regulator */ + struct mutex phy_reg_lock; }; struct mdss_dsi_data { @@ -305,11 +308,6 @@ struct dsi_kickoff_action { void *data; }; -struct dsi_drv_cm_data { - struct dss_io_data phy_regulator_io; - int phy_disable_refcount; -}; - struct dsi_pinctrl_res { struct pinctrl *pinctrl; struct pinctrl_state *gpio_state_active; @@ -360,6 +358,7 @@ struct mdss_dsi_ctrl_pdata { struct dss_io_data ctrl_io; struct dss_io_data mmss_misc_io; struct dss_io_data phy_io; + struct dss_io_data phy_regulator_io; int reg_size; u32 core_clk_cnt; u32 link_clk_cnt; @@ -403,7 +402,6 @@ struct mdss_dsi_ctrl_pdata { struct mdss_rect roi; struct pwm_device *pwm_bl; - struct dsi_drv_cm_data *shared_ctrl_data; u32 pclk_rate; u32 byte_clk_rate; bool refresh_clk_rate; /* flag to recalculate clk_rate */ @@ -445,6 +443,8 @@ struct mdss_dsi_ctrl_pdata { bool core_power; bool mmss_clamp; char dlane_swap; /* data lane swap */ + bool is_phyreg_enabled; + struct dsi_buf tx_buf; struct dsi_buf rx_buf; diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index 2ed624ec2203..2a0779e739d5 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -265,9 +265,9 @@ void mdss_dsi_read_hw_revision(struct mdss_dsi_ctrl_pdata *ctrl) void mdss_dsi_get_hw_revision(struct mdss_dsi_ctrl_pdata *ctrl) { - mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 1); + mdss_dsi_clk_ctrl(ctrl, DSI_CORE_CLKS, 1); ctrl->shared_data->hw_rev = MIPI_INP(ctrl->ctrl_base); - mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 0); + mdss_dsi_clk_ctrl(ctrl, DSI_CORE_CLKS, 0); pr_debug("%s: ndx=%d hw_rev=%x\n", __func__, ctrl->ndx, ctrl->shared_data->hw_rev); diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c index c951a56e4774..f884af10b793 100644 --- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c +++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c @@ -122,11 +122,10 @@ static void mdss_dsi_phy_regulator_disable(struct mdss_dsi_ctrl_pdata *ctrl) MDSS_DSI_HW_REV_104)) return; - MIPI_OUTP(ctrl->shared_ctrl_data->phy_regulator_io.base - + 0x018, 0x000); + MIPI_OUTP(ctrl->phy_regulator_io.base + 0x018, 0x000); } -static void mdss_dsi_phy_lane_shutdown(struct mdss_dsi_ctrl_pdata *ctrl) +static void mdss_dsi_phy_shutdown(struct mdss_dsi_ctrl_pdata *ctrl) { if (!ctrl) { pr_err("%s: Invalid input data\n", __func__); @@ -141,41 +140,6 @@ static void mdss_dsi_phy_lane_shutdown(struct mdss_dsi_ctrl_pdata *ctrl) } -void mdss_dsi_phy_disable(struct mdss_dsi_ctrl_pdata *ctrl) -{ - struct mdss_dsi_ctrl_pdata *other_ctrl; - if (ctrl == NULL) { - pr_err("%s: Invalid input data\n", __func__); - return; - } - - ctrl->shared_ctrl_data->phy_disable_refcount++; - - /* - * In split-dsi configuration, the phy should be disabled for the - * first controller only when the second controller is disabled. - * This is true regardless of whether broadcast mode is enabled. - */ - if (!mdss_dsi_is_hw_config_split(ctrl->shared_data) || - ctrl->shared_ctrl_data->phy_disable_refcount == 2) { - - other_ctrl = mdss_dsi_get_other_ctrl(ctrl); - if (other_ctrl) - mdss_dsi_phy_lane_shutdown(other_ctrl); - - mdss_dsi_phy_lane_shutdown(ctrl); - - mdss_dsi_phy_regulator_disable(ctrl); - - /* - * Wait for the registers writes to complete in order to - * ensure that the phy is completely disabled - */ - wmb(); - ctrl->shared_ctrl_data->phy_disable_refcount = 0; - } -} - /** * mdss_dsi_lp_cd_rx() -- enable LP and CD at receiving * @ctrl: pointer to DSI controller structure @@ -211,27 +175,26 @@ static void mdss_dsi_28nm_phy_regulator_enable( if (pd->reg_ldo_mode) { /* Regulator ctrl 0 */ - MIPI_OUTP(ctrl_pdata->shared_ctrl_data->phy_regulator_io.base, - 0x0); + MIPI_OUTP(ctrl_pdata->phy_regulator_io.base, 0x0); /* Regulator ctrl - CAL_PWR_CFG */ - MIPI_OUTP((ctrl_pdata->shared_ctrl_data->phy_regulator_io.base) + MIPI_OUTP((ctrl_pdata->phy_regulator_io.base) + 0x18, pd->regulator[6]); /* Add H/w recommended delay */ udelay(1000); /* Regulator ctrl - TEST */ - MIPI_OUTP((ctrl_pdata->shared_ctrl_data->phy_regulator_io.base) + MIPI_OUTP((ctrl_pdata->phy_regulator_io.base) + 0x14, pd->regulator[5]); /* Regulator ctrl 3 */ - MIPI_OUTP((ctrl_pdata->shared_ctrl_data->phy_regulator_io.base) + MIPI_OUTP((ctrl_pdata->phy_regulator_io.base) + 0xc, pd->regulator[3]); /* Regulator ctrl 2 */ - MIPI_OUTP((ctrl_pdata->shared_ctrl_data->phy_regulator_io.base) + MIPI_OUTP((ctrl_pdata->phy_regulator_io.base) + 0x8, pd->regulator[2]); /* Regulator ctrl 1 */ - MIPI_OUTP((ctrl_pdata->shared_ctrl_data->phy_regulator_io.base) + MIPI_OUTP((ctrl_pdata->phy_regulator_io.base) + 0x4, pd->regulator[1]); /* Regulator ctrl 4 */ - MIPI_OUTP((ctrl_pdata->shared_ctrl_data->phy_regulator_io.base) + MIPI_OUTP((ctrl_pdata->phy_regulator_io.base) + 0x10, pd->regulator[4]); /* LDO ctrl */ if (MIPI_INP(ctrl_pdata->ctrl_base) == MDSS_DSI_HW_REV_103_1) @@ -240,34 +203,34 @@ static void mdss_dsi_28nm_phy_regulator_enable( MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x1dc, 0x0d); } else { /* Regulator ctrl 0 */ - MIPI_OUTP(ctrl_pdata->shared_ctrl_data->phy_regulator_io.base, + MIPI_OUTP(ctrl_pdata->phy_regulator_io.base, 0x0); /* Regulator ctrl - CAL_PWR_CFG */ - MIPI_OUTP((ctrl_pdata->shared_ctrl_data->phy_regulator_io.base) + MIPI_OUTP((ctrl_pdata->phy_regulator_io.base) + 0x18, pd->regulator[6]); /* Add H/w recommended delay */ udelay(1000); /* Regulator ctrl 1 */ - MIPI_OUTP((ctrl_pdata->shared_ctrl_data->phy_regulator_io.base) + MIPI_OUTP((ctrl_pdata->phy_regulator_io.base) + 0x4, pd->regulator[1]); /* Regulator ctrl 2 */ - MIPI_OUTP((ctrl_pdata->shared_ctrl_data->phy_regulator_io.base) + MIPI_OUTP((ctrl_pdata->phy_regulator_io.base) + 0x8, pd->regulator[2]); /* Regulator ctrl 3 */ - MIPI_OUTP((ctrl_pdata->shared_ctrl_data->phy_regulator_io.base) + MIPI_OUTP((ctrl_pdata->phy_regulator_io.base) + 0xc, pd->regulator[3]); /* Regulator ctrl 4 */ - MIPI_OUTP((ctrl_pdata->shared_ctrl_data->phy_regulator_io.base) + MIPI_OUTP((ctrl_pdata->phy_regulator_io.base) + 0x10, pd->regulator[4]); /* LDO ctrl */ MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x1dc, 0x00); /* Regulator ctrl 0 */ - MIPI_OUTP(ctrl_pdata->shared_ctrl_data->phy_regulator_io.base, + MIPI_OUTP(ctrl_pdata->phy_regulator_io.base, pd->regulator[0]); } } -static void mdss_dsi_28nm_phy_init(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +static void mdss_dsi_28nm_phy_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata) { struct mdss_dsi_phy_ctrl *pd; int i, off, ln, offset; @@ -279,10 +242,10 @@ static void mdss_dsi_28nm_phy_init(struct mdss_dsi_ctrl_pdata *ctrl_pdata) pd = &(((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db); - /* Strength ctrl 0 */ - MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x0184, pd->strength[0]); - - mdss_dsi_28nm_phy_regulator_enable(ctrl_pdata); + /* Strength ctrl 0 for 28nm PHY*/ + if ((ctrl_pdata->shared_data->hw_rev <= MDSS_DSI_HW_REV_103) && + (ctrl_pdata->shared_data->hw_rev != MDSS_DSI_HW_REV_103)) + MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x0184, pd->strength[0]); off = 0x0140; /* phy timing ctrl 0 - 11 */ for (i = 0; i < 12; i++) { @@ -338,7 +301,7 @@ static void mdss_dsi_20nm_phy_regulator_enable(struct mdss_dsi_ctrl_pdata void __iomem *phy_io_base; pd = &(((ctrl_pdata->panel_data).panel_info.mipi).dsi_phy_db); - phy_io_base = ctrl_pdata->shared_ctrl_data->phy_regulator_io.base; + phy_io_base = ctrl_pdata->phy_regulator_io.base; if (pd->regulator_len != 7) { pr_err("%s: wrong regulator settings\n", __func__); @@ -481,6 +444,38 @@ static void mdss_dsi_8996_pll_source_from_left( MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_GLBL_TEST_CTRL, data); } +static void mdss_dsi_8996_phy_regulator_enable( + struct mdss_dsi_ctrl_pdata *ctrl) +{ + struct mdss_dsi_phy_ctrl *pd; + int j, off, ln, cnt, ln_off; + char *ip; + void __iomem *base; + + pd = &(((ctrl->panel_data).panel_info.mipi).dsi_phy_db); + /* 4 lanes + clk lane configuration */ + for (ln = 0; ln < 5; ln++) { + /* + * data lane offset frome base: 0x100 + * data lane size: 0x80 + */ + base = ctrl->phy_io.base + + DATALANE_OFFSET_FROM_BASE_8996; + base += (ln * DATALANE_SIZE_8996); /* lane base */ + + /* vreg ctrl, 1 * 5 */ + cnt = 1; + ln_off = cnt * ln; + ip = &pd->regulator[ln_off]; + off = 0x64; + for (j = 0; j < cnt; j++, off += 4) + MIPI_OUTP(base + off, *ip++); + } + + wmb(); /* make sure registers committed */ + +} + static void mdss_dsi_8996_phy_config(struct mdss_dsi_ctrl_pdata *ctrl) { struct mdss_dsi_phy_ctrl *pd; @@ -548,14 +543,6 @@ static void mdss_dsi_8996_phy_config(struct mdss_dsi_ctrl_pdata *ctrl) off = 0x38; for (j = 0; j < cnt; j++, off += 4) MIPI_OUTP(base + off, *ip++); - - /* vreg ctrl, 1 * 5 */ - cnt = 1; - ln_off = cnt * ln; - ip = &pd->regulator[ln_off]; - off = 0x64; - for (j = 0; j < cnt; j++, off += 4) - MIPI_OUTP(base + off, *ip++); } wmb(); /* make sure registers committed */ @@ -581,47 +568,113 @@ static void mdss_dsi_8996_phy_config(struct mdss_dsi_ctrl_pdata *ctrl) wmb(); /* make sure registers committed */ } -static void mdss_dsi_20nm_phy_init(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +static void mdss_dsi_phy_regulator_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, + bool enable) { - if (!ctrl_pdata) { - pr_err("%s: Invalid input data\n", __func__); - return; - } + struct mdss_dsi_ctrl_pdata *other_ctrl; + struct dsi_shared_data *sdata; - mdss_dsi_20nm_phy_regulator_enable(ctrl_pdata); - - mdss_dsi_20nm_phy_config(ctrl_pdata); -} - -static void mdss_dsi_8996_phy_init(struct mdss_dsi_ctrl_pdata *ctrl_pdata) -{ - if (!ctrl_pdata) { - pr_err("%s: Invalid input data\n", __func__); - return; - } - - mdss_dsi_8996_phy_config(ctrl_pdata); -} - -static void mdss_dsi_phy_init(struct mdss_dsi_ctrl_pdata *ctrl) -{ if (!ctrl) { pr_err("%s: Invalid input data\n", __func__); return; } - switch (ctrl->shared_data->hw_rev) { - case MDSS_DSI_HW_REV_104: - case MDSS_DSI_HW_REV_104_1: - mdss_dsi_8996_phy_init(ctrl); - break; - case MDSS_DSI_HW_REV_103: - mdss_dsi_20nm_phy_init(ctrl); - break; - default: - mdss_dsi_28nm_phy_init(ctrl); - break; + sdata = ctrl->shared_data; + + mutex_lock(&sdata->phy_reg_lock); + if (enable) { + switch (ctrl->shared_data->hw_rev) { + case MDSS_DSI_HW_REV_104: + case MDSS_DSI_HW_REV_104_1: + mdss_dsi_8996_phy_regulator_enable(ctrl); + break; + case MDSS_DSI_HW_REV_103: + mdss_dsi_20nm_phy_regulator_enable(ctrl); + break; + default: + mdss_dsi_28nm_phy_regulator_enable(ctrl); + break; + } + ctrl->is_phyreg_enabled = 1; + } else { + /* + * In split-dsi/dual-dsi configuration, the dsi phy regulator + * should be turned off only when both the DSI devices are + * going to be turned off since it is shared. + */ + if (mdss_dsi_is_hw_config_split(ctrl->shared_data) || + mdss_dsi_is_hw_config_dual(ctrl->shared_data)) { + other_ctrl = mdss_dsi_get_other_ctrl(ctrl); + if (other_ctrl && !other_ctrl->is_phyreg_enabled) + mdss_dsi_phy_regulator_disable(ctrl); + } else { + mdss_dsi_phy_regulator_disable(ctrl); + } + ctrl->is_phyreg_enabled = 0; } + mutex_unlock(&sdata->phy_reg_lock); +} + +static void mdss_dsi_phy_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, bool enable) +{ + struct mdss_dsi_ctrl_pdata *other_ctrl; + if (!ctrl) { + pr_err("%s: Invalid input data\n", __func__); + return; + } + + if (enable) { + switch (ctrl->shared_data->hw_rev) { + case MDSS_DSI_HW_REV_104: + case MDSS_DSI_HW_REV_104_1: + mdss_dsi_8996_phy_config(ctrl); + break; + case MDSS_DSI_HW_REV_103: + mdss_dsi_20nm_phy_config(ctrl); + break; + default: + mdss_dsi_28nm_phy_config(ctrl); + break; + } + } else { + /* + * In split-dsi configuration, the phy should be disabled for + * the first controller only when the second controller is + * disabled. This is true regardless of whether broadcast + * mode is enabled. + */ + if (mdss_dsi_is_hw_config_split(ctrl->shared_data)) { + other_ctrl = mdss_dsi_get_other_ctrl(ctrl); + if (mdss_dsi_is_right_ctrl(ctrl) && other_ctrl) { + mdss_dsi_phy_shutdown(other_ctrl); + mdss_dsi_phy_shutdown(ctrl); + } + } else { + mdss_dsi_phy_shutdown(ctrl); + } + } +} + +void mdss_dsi_phy_disable(struct mdss_dsi_ctrl_pdata *ctrl) +{ + if (ctrl == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return; + } + + mdss_dsi_phy_ctrl(ctrl, false); + mdss_dsi_phy_regulator_ctrl(ctrl, false); + /* + * Wait for the registers writes to complete in order to + * ensure that the phy is completely disabled + */ + wmb(); +} + +void mdss_dsi_phy_init(struct mdss_dsi_ctrl_pdata *ctrl) +{ + mdss_dsi_phy_regulator_ctrl(ctrl, true); + mdss_dsi_phy_ctrl(ctrl, true); } void mdss_dsi_core_clk_deinit(struct device *dev, struct dsi_shared_data *sdata)