int mdss_dsi_on(struct mdss_panel_data *pdata) { int ret = 0; struct mdss_panel_info *pinfo; struct mipi_panel_info *mipi; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } if (pdata->panel_info.panel_power_on) { pr_warn("%s:%d Panel already on.\n", __func__, __LINE__); return 0; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); pr_info("%s+: ctrl=%p ndx=%d\n", __func__, ctrl_pdata, ctrl_pdata->ndx); pinfo = &pdata->panel_info; mipi = &pdata->panel_info.mipi; if (ctrl_pdata->partial_mode_enabled && !pdata->panel_info.panel_dead) { mdss_dsi_ulps_config_sub(ctrl_pdata, 0, 1); mdata->ulps = false; pdata->panel_info.panel_power_on = 1; mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1); } else { if (ctrl_pdata->partial_mode_enabled && pdata->panel_info.panel_dead) pr_warn("%s: Panel is dead, bring up DSI\n", __func__); ret = mdss_dsi_panel_power_on(pdata, 1); if (ret) { pr_err("%s:Panel power on failed. rc=%d\n", __func__, ret); return ret; } mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 1); if (ret) { pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__, ret); ret = mdss_dsi_panel_power_on(pdata, 0); if (ret) { pr_err("%s: Panel reset failed. rc=%d\n", __func__, ret); return ret; } pdata->panel_info.panel_power_on = 0; return ret; } pdata->panel_info.panel_power_on = 1; mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base)); mdss_dsi_phy_init(pdata); mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0); mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1); __mdss_dsi_ctrl_setup(pdata); mdss_dsi_sw_reset(pdata); mdss_dsi_host_init(pdata); } /* * Issue hardware reset line after enabling the DSI clocks and data * data lanes for LP11 init */ if (mipi->lp11_init) mdss_dsi_panel_reset(pdata, 1); if (mipi->init_delay) usleep(mipi->init_delay); if (mipi->force_clk_lane_hs) { u32 tmp; tmp = MIPI_INP((ctrl_pdata->ctrl_base) + 0xac); tmp |= (1<<28); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0xac, tmp); wmb(); } if (pdata->panel_info.type == MIPI_CMD_PANEL) mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0); pr_info("%s-:\n", __func__); return 0; }
static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata, int enable, int partial) { int ret = 0; struct mdss_panel_data *pdata = NULL; struct mipi_panel_info *pinfo = NULL; u32 lane_status = 0; u32 active_lanes = 0; if (!ctrl_pdata) { pr_err("%s: invalid input\n", __func__); return -EINVAL; } pdata = &ctrl_pdata->panel_data; if (!pdata) { pr_err("%s: Invalid panel data\n", __func__); return -EINVAL; } pinfo = &pdata->panel_info.mipi; if (!partial && !__mdss_dsi_ulps_feature_enabled(pdata)) { pr_debug("%s: ULPS feature not supported. enable=%d\n", __func__, enable); return -ENOTSUPP; } if (enable && !ctrl_pdata->ulps) { /* No need to configure ULPS mode when entering suspend state */ if (!partial && !pdata->panel_info.panel_power_on) { pr_err("%s: panel off. returning\n", __func__); goto error; } if (!partial && __mdss_dsi_clk_enabled(ctrl_pdata, DSI_LINK_CLKS)) { pr_err("%s: cannot enter ulps mode if dsi clocks are on\n", __func__); ret = -EPERM; goto error; } ret = mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1); if (ret) { pr_err("%s: Failed to enable clocks. rc=%d\n", __func__, ret); goto error; } /* * ULPS Entry Request. * Wait for a short duration to ensure that the lanes * enter ULP state. */ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x01F); usleep(100); /* Check to make sure that all active data lanes are in ULPS */ if (pinfo->data_lane3) active_lanes |= BIT(11); if (pinfo->data_lane2) active_lanes |= BIT(10); if (pinfo->data_lane1) active_lanes |= BIT(9); if (pinfo->data_lane0) active_lanes |= BIT(8); active_lanes |= BIT(12); /* clock lane */ lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8); if (lane_status & active_lanes) { pr_err("%s: ULPS entry req failed. Lane status=0x%08x\n", __func__, lane_status); ret = -EINVAL; mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0); goto error; } /* Enable MMSS DSI Clamps */ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x3FF); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x83FF); wmb(); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x1); /* disable DSI controller */ mdss_dsi_controller_cfg(0, pdata); mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0); ctrl_pdata->ulps = true; } else if (ctrl_pdata->ulps) { ret = mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 1); if (ret) { pr_err("%s: Failed to enable bus clocks. rc=%d\n", __func__, ret); goto error; } MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x0); mdss_dsi_phy_init(pdata); __mdss_dsi_ctrl_setup(pdata); mdss_dsi_sw_reset(pdata); mdss_dsi_host_init(pdata); mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, pdata); /* * ULPS Entry Request. This is needed because, after power * collapse and reset, the DSI controller resets back to * idle state and not ULPS. * Wait for a short duration to ensure that the lanes * enter ULP state. */ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x01F); usleep(100); /* Disable MMSS DSI Clamps */ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x3FF); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, 0x0); ret = mdss_dsi_clk_ctrl(ctrl_pdata, DSI_LINK_CLKS, 1); if (ret) { pr_err("%s: Failed to enable link clocks. rc=%d\n", __func__, ret); mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0); goto error; } /* * ULPS Exit Request * Hardware requirement is to wait for at least 1ms */ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x1F00); usleep(1000); MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x0); /* * Wait for a short duration before enabling * data transmission */ usleep(100); lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8); mdss_dsi_clk_ctrl(ctrl_pdata, DSI_LINK_CLKS, 0); mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0); ctrl_pdata->ulps = false; } pr_debug("%s: DSI lane status = 0x%08x. Ulps %s\n", __func__, lane_status, enable ? "enabled" : "disabled"); error: return ret; }
int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata, int enable) { int ret = 0; struct mdss_panel_data *pdata = NULL; struct mdss_panel_info *pinfo; struct mipi_panel_info *mipi; u32 lane_status = 0, regval; u32 active_lanes = 0, clamp_reg; if (!ctrl_pdata) { pr_err("%s: invalid input\n", __func__); return -EINVAL; } if (&ctrl_pdata->mmss_misc_io == NULL) { pr_err("%s: mmss_misc_io is NULL. ULPS not valid\n", __func__); return -EINVAL; } pdata = &ctrl_pdata->panel_data; if (!pdata) { pr_err("%s: Invalid panel data\n", __func__); return -EINVAL; } pinfo = &pdata->panel_info; mipi = &pinfo->mipi; if (!mdss_dsi_ulps_feature_enabled(pdata)) { pr_debug("%s: ULPS feature not supported. enable=%d\n", __func__, enable); return -ENOTSUPP; } /* * No need to enter ULPS when transitioning from splash screen to * boot animation since it is expected that the clocks would be turned * right back on. */ if (pinfo->cont_splash_enabled) { pr_debug("%s: skip ULPS config with splash screen enabled\n", __func__); return 0; } /* clock lane will always be programmed for ulps and will be clamped */ active_lanes = BIT(4); clamp_reg = BIT(8) | BIT(9); /* * make a note of all active data lanes for which ulps entry/exit * as well as DSI clamps are needed */ if (mipi->data_lane0) { active_lanes |= BIT(0); clamp_reg |= (BIT(0) | BIT(1)); } if (mipi->data_lane1) { active_lanes |= BIT(1); clamp_reg |= (BIT(2) | BIT(3)); } if (mipi->data_lane2) { active_lanes |= BIT(2); clamp_reg |= (BIT(4) | BIT(5)); } if (mipi->data_lane3) { active_lanes |= BIT(3); clamp_reg |= (BIT(6) | BIT(7)); } pr_debug("%s: configuring ulps (%s) for ctrl%d, active lanes=0x%08x\n", __func__, (enable ? "on" : "off"), ctrl_pdata->ndx, active_lanes); if (enable && !ctrl_pdata->ulps) { /* * ULPS Entry Request. * Wait for a short duration to ensure that the lanes * enter ULP state. */ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes); usleep(100); /* Check to make sure that all active data lanes are in ULPS */ lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8); if (lane_status & (active_lanes << 8)) { pr_err("%s: ULPS entry req failed for ctrl%d. Lane status=0x%08x\n", __func__, ctrl_pdata->ndx, lane_status); ret = -EINVAL; goto error; } /* Enable MMSS DSI Clamps */ if (ctrl_pdata->ndx == DSI_CTRL_0) { regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, regval | clamp_reg); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, regval | (clamp_reg | BIT(15))); } else if (ctrl_pdata->ndx == DSI_CTRL_1) { regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, regval | (clamp_reg << 16)); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, regval | ((clamp_reg << 16) | BIT(31))); } wmb(); /* * This register write ensures that DSI PHY will not be * reset when mdss ahb clock reset is asserted while coming * out of power collapse */ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x1); ctrl_pdata->ulps = true; } else if (ctrl_pdata->ulps) { MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x0); mdss_dsi_phy_init(pdata); __mdss_dsi_ctrl_setup(pdata); mdss_dsi_sw_reset(pdata); mdss_dsi_host_init(pdata); mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, pdata); /* * ULPS Entry Request. This is needed because, after power * collapse and reset, the DSI controller resets back to * idle state and not ULPS. * Wait for a short duration to ensure that the lanes * enter ULP state. */ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes); usleep(100); /* Disable MMSS DSI Clamps */ if (ctrl_pdata->ndx == DSI_CTRL_0) { regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, regval & ~(clamp_reg | BIT(15))); } else if (ctrl_pdata->ndx == DSI_CTRL_1) { regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, regval & ~((clamp_reg << 16) | BIT(31))); } /* * ULPS Exit Request * Hardware requirement is to wait for at least 1ms */ MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes << 8); usleep(1000); MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x0); /* * Wait for a short duration before enabling * data transmission */ usleep(100); lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8); ctrl_pdata->ulps = false; } pr_debug("%s: DSI lane status = 0x%08x. Ulps %s\n", __func__, lane_status, enable ? "enabled" : "disabled"); error: return ret; }
int mdss_dsi_on(struct mdss_panel_data *pdata) { int ret = 0; struct mdss_panel_info *pinfo; struct mipi_panel_info *mipi; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } if (pdata->panel_info.panel_power_on) { pr_warn("%s:%d Panel already on.\n", __func__, __LINE__); return 0; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); pr_debug("%s+: ctrl=%p ndx=%d\n", __func__, ctrl_pdata, ctrl_pdata->ndx); pinfo = &pdata->panel_info; mipi = &pdata->panel_info.mipi; ret = mdss_dsi_panel_power_on(pdata, 1); if (ret) { pr_err("%s:Panel power on failed. rc=%d\n", __func__, ret); return ret; } mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 1); if (ret) { pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__, ret); ret = mdss_dsi_panel_power_on(pdata, 0); if (ret) { pr_err("%s: Panel reset failed. rc=%d\n", __func__, ret); return ret; } pdata->panel_info.panel_power_on = 0; return ret; } if (!mipi->lp11_init) { pdata->panel_info.panel_power_on = 1; } mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base)); mdss_dsi_phy_init(pdata); mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0); mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1); __mdss_dsi_ctrl_setup(pdata); mdss_dsi_sw_reset(pdata); mdss_dsi_host_init(pdata); /* * Issue hardware reset line after enabling the DSI clocks and data * data lanes for LP11 init */ if (mipi->lp11_init) { usleep(mipi->lp11_rst_delay); if (mdss_dsi_pinctrl_set_state(ctrl_pdata, true)) pr_debug("reset enable: pinctrl not enabled\n"); mdss_dsi_panel_reset(pdata, 1); pdata->panel_info.panel_power_on = 1; } if (mipi->init_delay) usleep(mipi->init_delay); if (mipi->force_clk_lane_hs) { u32 tmp; tmp = MIPI_INP((ctrl_pdata->ctrl_base) + 0xac); tmp |= (1<<28); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0xac, tmp); wmb(); } if (pdata->panel_info.type == MIPI_CMD_PANEL) mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0); pr_debug("%s-:\n", __func__); return 0; }
int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata, int enable) { int ret = 0; struct mdss_panel_data *pdata = NULL; struct mdss_panel_info *pinfo; struct mipi_panel_info *mipi; u32 lane_status = 0, regval; u32 active_lanes = 0, clamp_reg; if (!ctrl_pdata) { pr_err("%s: invalid input\n", __func__); return -EINVAL; } if (&ctrl_pdata->mmss_misc_io == NULL) { pr_err("%s: mmss_misc_io is NULL. ULPS not valid\n", __func__); return -EINVAL; } pdata = &ctrl_pdata->panel_data; if (!pdata) { pr_err("%s: Invalid panel data\n", __func__); return -EINVAL; } pinfo = &pdata->panel_info; mipi = &pinfo->mipi; if (!mdss_dsi_ulps_feature_enabled(pdata)) { pr_debug("%s: ULPS feature not supported. enable=%d\n", __func__, enable); return -ENOTSUPP; } if (pinfo->cont_splash_enabled) { pr_debug("%s: skip ULPS config with splash screen enabled\n", __func__); return 0; } active_lanes = BIT(4); clamp_reg = BIT(8) | BIT(9); if (mipi->data_lane0) { active_lanes |= BIT(0); clamp_reg |= (BIT(0) | BIT(1)); } if (mipi->data_lane1) { active_lanes |= BIT(1); clamp_reg |= (BIT(2) | BIT(3)); } if (mipi->data_lane2) { active_lanes |= BIT(2); clamp_reg |= (BIT(4) | BIT(5)); } if (mipi->data_lane3) { active_lanes |= BIT(3); clamp_reg |= (BIT(6) | BIT(7)); } pr_debug("%s: configuring ulps (%s) for ctrl%d, active lanes=0x%08x\n", __func__, (enable ? "on" : "off"), ctrl_pdata->ndx, active_lanes); if (enable && !ctrl_pdata->ulps) { MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes); usleep(100); lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8); if (lane_status & (active_lanes << 8)) { pr_err("%s: ULPS entry req failed for ctrl%d. Lane status=0x%08x\n", __func__, ctrl_pdata->ndx, lane_status); ret = -EINVAL; goto error; } if (ctrl_pdata->ndx == DSI_CTRL_0) { regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, regval | clamp_reg); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, regval | (clamp_reg | BIT(15))); } else if (ctrl_pdata->ndx == DSI_CTRL_1) { regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, regval | (clamp_reg << 16)); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, regval | ((clamp_reg << 16) | BIT(31))); } wmb(); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x1); ctrl_pdata->ulps = true; } else if (ctrl_pdata->ulps) { MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x0); mdss_dsi_phy_init(pdata); __mdss_dsi_ctrl_setup(pdata); mdss_dsi_sw_reset(pdata); mdss_dsi_host_init(pdata); mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, pdata); MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes); usleep(100); if (ctrl_pdata->ndx == DSI_CTRL_0) { regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, regval & ~(clamp_reg | BIT(15))); } else if (ctrl_pdata->ndx == DSI_CTRL_1) { regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, regval & ~((clamp_reg << 16) | BIT(31))); } MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes << 8); usleep(1000); MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x0); usleep(100); lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8); ctrl_pdata->ulps = false; } pr_debug("%s: DSI lane status = 0x%08x. Ulps %s\n", __func__, lane_status, enable ? "enabled" : "disabled"); error: return ret; }