static int mdss_dsi_off(struct mdss_panel_data *pdata, int power_state) { int ret = 0; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_panel_info *panel_info = NULL; if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); panel_info = &ctrl_pdata->panel_data.panel_info; pr_info("%s+: ctrl=%p ndx=%d power_state=%d\n", __func__, ctrl_pdata, ctrl_pdata->ndx, power_state); if (power_state == panel_info->panel_power_state) { pr_err("%s: No change in power state %d -> %d\n", __func__, panel_info->panel_power_state, power_state); goto end; } if (power_state != MDSS_PANEL_POWER_OFF) { pr_err("%s: dsi_off with panel always on\n", __func__); goto panel_power_ctrl; } if (pdata->panel_info.type == MIPI_CMD_PANEL) mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1); /* disable DSI controller */ mdss_dsi_controller_cfg(0, pdata); /* disable DSI phy */ mdss_dsi_phy_disable(ctrl_pdata); mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0); panel_power_ctrl: ret = mdss_dsi_panel_power_ctrl(pdata, power_state); if (ret) { pr_err("%s: Panel power off failed\n", __func__); } else { if (panel_info->dynamic_fps && (panel_info->dfps_update == DFPS_SUSPEND_RESUME_MODE) && (panel_info->new_fps != panel_info->mipi.frame_rate)) panel_info->mipi.frame_rate = panel_info->new_fps; } panel_info->dsi_on_status = false; end: pr_info("%s-:\n", __func__); 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; int cur_power_state; #if defined(CONFIG_FB_MSM_MDSS_SAMSUNG) struct samsung_display_driver_data *vdd = NULL; u32 reg_backup; #endif if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); cur_power_state = pdata->panel_info.panel_power_state; pr_info("%s+: ctrl=%p ndx=%d cur_power_state=%d\n", __func__, ctrl_pdata, ctrl_pdata->ndx, cur_power_state); pinfo = &pdata->panel_info; mipi = &pdata->panel_info.mipi; #if defined(CONFIG_FB_MSM_MDSS_SAMSUNG) if (pinfo->esd_recovery.esd_irq_enable) pinfo->esd_recovery.esd_irq_enable(true, false, (void *)pinfo); #endif if (mdss_dsi_is_panel_on_interactive(pdata)) { pr_err("%s: panel already on\n", __func__); goto end; } ret = mdss_dsi_panel_power_ctrl(pdata, MDSS_PANEL_POWER_ON); if (ret) { pr_err("%s:Panel power on failed. rc=%d\n", __func__, ret); return ret; } if (cur_power_state != MDSS_PANEL_POWER_OFF) { pr_debug("%s: dsi_on from panel low power state\n", __func__); goto end; } /* * Enable DSI clocks. * This is also enable the DSI core power block and reset/setup * DSI phy */ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1); mdss_dsi_sw_reset(ctrl_pdata, true); /* * Issue hardware reset line after enabling the DSI clocks and data * data lanes for LP11 init */ if (mipi->lp11_init) { #if defined(CONFIG_FB_MSM_MDSS_SAMSUNG) vdd = check_valid_ctrl(ctrl_pdata); if (!IS_ERR_OR_NULL(vdd) && vdd->dtsi_data[ctrl_pdata->ndx].samsung_lp11_init) { /* LP11 */ reg_backup = MIPI_INP((ctrl_pdata->ctrl_base) + 0xac); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0xac, 0x1F << 16); wmb(); if (mipi->init_delay) usleep(mipi->init_delay); } #endif mdss_dsi_panel_reset(pdata, 1); #if defined(CONFIG_FB_MSM_MDSS_SAMSUNG) /* LP11 Restore */ if (!IS_ERR_OR_NULL(vdd) && vdd->dtsi_data[ctrl_pdata->ndx].samsung_lp11_init) MIPI_OUTP((ctrl_pdata->ctrl_base) + 0xac, reg_backup); #endif } 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); pinfo->dsi_on_status = true; end: pr_err("%s-:\n", __func__); return 0; }
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; int cur_power_state; if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); cur_power_state = pdata->panel_info.panel_power_state; pr_debug("%s+: ctrl=%p ndx=%d cur_power_state=%d\n", __func__, ctrl_pdata, ctrl_pdata->ndx, cur_power_state); pinfo = &pdata->panel_info; mipi = &pdata->panel_info.mipi; if (mdss_dsi_is_panel_on_interactive(pdata)) { pr_debug("%s: panel already on\n", __func__); goto end; } ret = mdss_dsi_panel_power_ctrl(pdata, MDSS_PANEL_POWER_ON); if (ret) { pr_err("%s:Panel power on failed. rc=%d\n", __func__, ret); return ret; } if (cur_power_state != MDSS_PANEL_POWER_OFF) { pr_debug("%s: dsi_on from panel low power state\n", __func__); goto end; } /* * Enable DSI clocks. * This is also enable the DSI core power block and reset/setup * DSI phy */ mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1); mdss_dsi_sw_reset(ctrl_pdata, true); /* * 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); end: pr_debug("%s-:\n", __func__); return 0; }
int dsi_panel_device_register(struct device_node *pan_node, struct mdss_dsi_ctrl_pdata *ctrl_pdata) { struct mipi_panel_info *mipi; int rc, i, len; struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info); struct device_node *dsi_ctrl_np = NULL; struct platform_device *ctrl_pdev = NULL; bool dynamic_fps; const char *data; pr_info("%s : ++ \n",__func__); mipi = &(pinfo->mipi); pinfo->type = ((mipi->mode == DSI_VIDEO_MODE) ? MIPI_VIDEO_PANEL : MIPI_CMD_PANEL); rc = mdss_dsi_clk_div_config(pinfo, mipi->frame_rate); if (rc) { pr_err("%s: unable to initialize the clk dividers\n", __func__); return rc; } dsi_ctrl_np = of_parse_phandle(pan_node, "qcom,mdss-dsi-panel-controller", 0); if (!dsi_ctrl_np) { pr_err("%s: Dsi controller node not initialized\n", __func__); return -EPROBE_DEFER; } ctrl_pdev = of_find_device_by_node(dsi_ctrl_np); rc = mdss_dsi_regulator_init(ctrl_pdev); if (rc) { pr_err("%s: failed to init regulator, rc=%d\n", __func__, rc); return rc; } data = of_get_property(ctrl_pdev->dev.of_node, "qcom,platform-strength-ctrl", &len); if ((!data) || (len != 2)) { pr_err("%s:%d, Unable to read Phy Strength ctrl settings\n", __func__, __LINE__); return -EINVAL; } pinfo->mipi.dsi_phy_db.strength[0] = data[0]; pinfo->mipi.dsi_phy_db.strength[1] = data[1]; data = of_get_property(ctrl_pdev->dev.of_node, "qcom,platform-regulator-settings", &len); if ((!data) || (len != 7)) { pr_err("%s:%d, Unable to read Phy regulator settings\n", __func__, __LINE__); return -EINVAL; } for (i = 0; i < len; i++) { pinfo->mipi.dsi_phy_db.regulator[i] = data[i]; } data = of_get_property(ctrl_pdev->dev.of_node, "qcom,platform-bist-ctrl", &len); if ((!data) || (len != 6)) { pr_err("%s:%d, Unable to read Phy Bist Ctrl settings\n", __func__, __LINE__); return -EINVAL; } for (i = 0; i < len; i++) { pinfo->mipi.dsi_phy_db.bistctrl[i] = data[i]; } data = of_get_property(ctrl_pdev->dev.of_node, "qcom,platform-lane-config", &len); if ((!data) || (len != 45)) { pr_err("%s:%d, Unable to read Phy lane configure settings\n", __func__, __LINE__); return -EINVAL; } for (i = 0; i < len; i++) { pinfo->mipi.dsi_phy_db.lanecfg[i] = data[i]; } ctrl_pdata->cmd_sync_wait_broadcast = of_property_read_bool( pan_node, "qcom,cmd-sync-wait-broadcast"); ctrl_pdata->cmd_sync_wait_trigger = of_property_read_bool( pan_node, "qcom,cmd-sync-wait-trigger"); pr_debug("%s: cmd_sync_wait_enable=%d trigger=%d\n", __func__, ctrl_pdata->cmd_sync_wait_broadcast, ctrl_pdata->cmd_sync_wait_trigger); dynamic_fps = of_property_read_bool(pan_node, "qcom,mdss-dsi-pan-enable-dynamic-fps"); if (dynamic_fps) { pinfo->dynamic_fps = true; data = of_get_property(pan_node, "qcom,mdss-dsi-pan-fps-update", NULL); if (data) { if (!strcmp(data, "dfps_suspend_resume_mode")) { pinfo->dfps_update = DFPS_SUSPEND_RESUME_MODE; pr_debug("%s: dfps mode: suspend/resume\n", __func__); } else if (!strcmp(data, "dfps_immediate_clk_mode")) { pinfo->dfps_update = DFPS_IMMEDIATE_CLK_UPDATE_MODE; pr_debug("%s: dfps mode: Immediate clk\n", __func__); } else if (!strcmp(data, "dfps_immediate_porch_mode")) { pinfo->dfps_update = DFPS_IMMEDIATE_PORCH_UPDATE_MODE; pr_debug("%s: dfps mode: Immediate porch\n", __func__); } else { pr_debug("%s: dfps to default mode\n", __func__); pinfo->dfps_update = DFPS_SUSPEND_RESUME_MODE; pr_debug("%s: dfps mode: suspend/resume\n", __func__); } } else { pr_debug("%s: dfps update mode not configured\n", __func__); pinfo->dynamic_fps = false; pr_debug("%s: dynamic FPS disabled\n", __func__); } pinfo->new_fps = pinfo->mipi.frame_rate; } ctrl_pdata->disp_en_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, "qcom,platform-enable-gpio", 0); if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) pr_err("%s:%d, Disp_en gpio not specified\n", __func__, __LINE__); else pr_err("%s:%d, Disp_en gpio (%d)",__func__, __LINE__,ctrl_pdata->disp_en_gpio ); if (ctrl_pdata->panel_data.panel_info.mipi.mode == DSI_CMD_MODE) { ctrl_pdata->disp_te_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, "qcom,platform-te-gpio", 0); if (!gpio_is_valid(ctrl_pdata->disp_te_gpio)) pr_err("%s:%d, Disp_te gpio not specified\n", __func__, __LINE__); else pr_err("%s:%d, Disp_te gpio (%d)",__func__, __LINE__,ctrl_pdata->disp_en_gpio ); } ctrl_pdata->bklt_en_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, "qcom,platform-bklight-en-gpio", 0); if (!gpio_is_valid(ctrl_pdata->bklt_en_gpio)) pr_info("%s: bklt_en gpio not specified\n", __func__); else pr_info("%s bklt_en_gpio gpio : %d", __func__, ctrl_pdata->bklt_en_gpio); ctrl_pdata->rst_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, "qcom,platform-reset-gpio", 0); if (!gpio_is_valid(ctrl_pdata->rst_gpio)) pr_err("%s:%d, reset gpio not specified\n", __func__, __LINE__); else pr_info("%s reset gpio : %d", __func__, ctrl_pdata->rst_gpio); if (pinfo->mode_gpio_state != MODE_GPIO_NOT_VALID) { ctrl_pdata->mode_gpio = of_get_named_gpio( ctrl_pdev->dev.of_node, "qcom,platform-mode-gpio", 0); if (!gpio_is_valid(ctrl_pdata->mode_gpio)) pr_info("%s:%d, mode gpio not specified\n", __func__, __LINE__); } else { ctrl_pdata->mode_gpio = -EINVAL; } if (mdss_dsi_clk_init(ctrl_pdev, ctrl_pdata)) { pr_err("%s: unable to initialize Dsi ctrl clks\n", __func__); return -EPERM; } if (mdss_dsi_retrieve_ctrl_resources(ctrl_pdev, pinfo->pdest, ctrl_pdata)) { pr_err("%s: unable to get Dsi controller res\n", __func__); return -EPERM; } ctrl_pdata->panel_data.event_handler = mdss_dsi_event_handler; ctrl_pdata->check_status = mdss_dsi_bta_status_check; if (ctrl_pdata->bklt_ctrl == BL_PWM) mdss_dsi_panel_pwm_cfg(ctrl_pdata); mdss_dsi_ctrl_init(ctrl_pdata); /* * register in mdp driver */ ctrl_pdata->pclk_rate = mipi->dsi_pclk_rate; ctrl_pdata->byte_clk_rate = pinfo->clk_rate / 8; pr_debug("%s: pclk=%d, bclk=%d\n", __func__, ctrl_pdata->pclk_rate, ctrl_pdata->byte_clk_rate); ctrl_pdata->ctrl_state = CTRL_STATE_UNKNOWN; pr_info("%s : pinfo->cont_splash_enabled(%d)\n", __func__, pinfo->cont_splash_enabled); if (pinfo->cont_splash_enabled) { rc = mdss_dsi_panel_power_ctrl(&(ctrl_pdata->panel_data), MDSS_PANEL_POWER_ON); if (rc) { pr_err("%s: Panel power on failed\n", __func__); return rc; } pinfo->blank_state = MDSS_PANEL_BLANK_UNBLANK; mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1); ctrl_pdata->ctrl_state |= (CTRL_STATE_PANEL_INIT | CTRL_STATE_MDP_ACTIVE); } else { pinfo->panel_power_state = MDSS_PANEL_POWER_OFF; } pinfo->is_prim_panel = true; #if defined(CONFIG_FB_MSM_MDSS_SAMSUNG) rc = mdss_dsi_request_gpios(ctrl_pdata); if (rc) { pr_err("gpio request failed\n"); } #endif rc = mdss_register_panel(ctrl_pdev, &(ctrl_pdata->panel_data)); if (rc) { pr_err("%s: unable to register MIPI DSI panel\n", __func__); return rc; } if (pinfo->pdest == DISPLAY_1) { mdss_debug_register_base("dsi0", ctrl_pdata->ctrl_base, ctrl_pdata->reg_size); ctrl_pdata->ndx = 0; } else { mdss_debug_register_base("dsi1", ctrl_pdata->ctrl_base, ctrl_pdata->reg_size); ctrl_pdata->ndx = 1; } pr_debug("%s: Panel data initialized\n", __func__); return 0; }
/** * mdss_dsi_core_power_ctrl() - Enable/disable DSI core power * @ctrl: pointer to DSI controller structure * @enable: 1 to enable power, 0 to disable power * * When all DSI bus clocks are disabled, DSI core power module can be turned * off to save any leakage current. This function implements the necessary * programming sequence for the same. For command mode panels, the core power * can be turned off for idle-screen usecases, where additional programming is * needed to clamp DSI phy. */ static int mdss_dsi_core_power_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable) { int rc = 0; struct mdss_panel_data *pdata = NULL; u32 ctrl_rev; if (!ctrl) { pr_err("%s: invalid input\n", __func__); return -EINVAL; } pdata = &ctrl->panel_data; if (!pdata) { pr_err("%s: Invalid panel data\n", __func__); return -EINVAL; } if (enable) { if (!ctrl->core_power) { /* enable mdss gdsc */ pr_debug("%s: Enable MDP FS\n", __func__); rc = msm_dss_enable_vreg( ctrl->power_data[DSI_CORE_PM].vreg_config, ctrl->power_data[DSI_CORE_PM].num_vreg, 1); if (rc) { pr_err("%s: failed to enable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_CORE_PM)); goto error; } ctrl->core_power = true; } /* * temp workaround until framework issues pertaining to LP2 * power state transitions are fixed. For now, if we intend to * send a frame update when in LP1, we have to explicitly exit * LP2 state here */ if (mdss_dsi_is_panel_on_ulp(pdata)) mdss_dsi_panel_power_ctrl(pdata, MDSS_PANEL_POWER_LP1); rc = mdss_dsi_bus_clk_start(ctrl); if (rc) { pr_err("%s: Failed to start bus clocks. rc=%d\n", __func__, rc); goto error_bus_clk_start; } /* * Phy and controller setup is needed if coming out of idle * power collapse with clamps enabled. */ if (ctrl->mmss_clamp) { ctrl_rev = MIPI_INP(ctrl->ctrl_base); if (ctrl_rev == MDSS_DSI_HW_REV_103) mdss_dsi_20nm_phy_init(pdata); else mdss_dsi_phy_init(pdata); mdss_dsi_ctrl_setup(ctrl); } if (ctrl->ulps) { /* * ULPS Entry Request. This is needed if the lanes were * in ULPS prior to power collapse, since after * power collapse and reset, the DSI controller resets * back to idle state and not ULPS. This ulps entry * request will transition the state of the DSI * controller to ULPS which will match the state of the * DSI phy. This needs to be done prior to disabling * the DSI clamps. * * Also, reset the ulps flag so that ulps_config * function would reconfigure the controller state to * ULPS. */ ctrl->ulps = false; rc = mdss_dsi_ulps_config(ctrl, 1); if (rc) { pr_err("%s: Failed to enter ULPS. rc=%d\n", __func__, rc); goto error_ulps; } } rc = mdss_dsi_clamp_ctrl(ctrl, 0); if (rc) { pr_err("%s: Failed to disable dsi clamps. rc=%d\n", __func__, rc); goto error_ulps; } } else { /* Enable DSI clamps only if entering idle power collapse */ if (pdata->panel_info.blank_state != MDSS_PANEL_BLANK_BLANK) { rc = mdss_dsi_clamp_ctrl(ctrl, 1); if (rc) pr_err("%s: Failed to enable dsi clamps. rc=%d\n", __func__, rc); } else { /* * Make sure that controller is not in ULPS state when * the DSI link is not active. */ rc = mdss_dsi_ulps_config(ctrl, 0); if (rc) pr_err("%s: failed to disable ulps. rc=%d\n", __func__, rc); } /* * disable bus clocks irrespective of whether dsi phy was * successfully clamped or not */ mdss_dsi_bus_clk_stop(ctrl); /* disable mdss gdsc only if dsi phy was successfully clamped*/ if (rc) { pr_debug("%s: leaving mdss gdsc on\n", __func__); } else { pr_debug("%s: Disable MDP FS\n", __func__); rc = msm_dss_enable_vreg( ctrl->power_data[DSI_CORE_PM].vreg_config, ctrl->power_data[DSI_CORE_PM].num_vreg, 0); if (rc) { pr_warn("%s: failed to disable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_CORE_PM)); rc = 0; } else { ctrl->core_power = false; } } /* * temp workaround until framework issues pertaining to LP2 * power state transitions are fixed. For now, we internally * transition to LP2 state whenever core power is turned off * in LP1 state */ if (mdss_dsi_is_panel_on_lp(pdata)) mdss_dsi_panel_power_ctrl(pdata, MDSS_PANEL_POWER_LP2); } return rc; error_ulps: mdss_dsi_bus_clk_stop(ctrl); error_bus_clk_start: if (msm_dss_enable_vreg(ctrl->power_data[DSI_CORE_PM].vreg_config, ctrl->power_data[DSI_CORE_PM].num_vreg, 0)) pr_warn("%s: failed to disable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_CORE_PM)); else ctrl->core_power = false; error: return rc; }