/** * mdss_mdp_perf_calc_pipe() - calculate performance numbers required by pipe * @pipe: Source pipe struct containing updated pipe params * @perf: Structure containing values that should be updated for * performance tuning * * Function calculates the minimum required performance calculations in order * to avoid MDP underflow. The calculations are based on the way MDP * fetches (bandwidth requirement) and processes data through MDP pipeline * (MDP clock requirement) based on frame size and scaling requirements. */ int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe, struct mdss_mdp_perf_params *perf) { struct mdss_mdp_mixer *mixer; int fps = DEFAULT_FRAME_RATE; u32 quota, rate, v_total, src_h; if (!pipe || !perf || !pipe->mixer) return -EINVAL; mixer = pipe->mixer; if (mixer->rotator_mode) { v_total = pipe->flags & MDP_ROT_90 ? pipe->dst.w : pipe->dst.h; } else if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) { struct mdss_panel_info *pinfo; pinfo = &mixer->ctl->panel_data->panel_info; fps = mdss_panel_get_framerate(pinfo); v_total = mdss_panel_get_vtotal(pinfo); } else { v_total = mixer->height; } /* * when doing vertical decimation lines will be skipped, hence there is * no need to account for these lines in MDP clock or request bus * bandwidth to fetch them. */ src_h = pipe->src.h >> pipe->vert_deci; quota = fps * pipe->src.w * src_h; if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420) quota = (quota * 3) / 2; else quota *= pipe->src_fmt->bpp; rate = pipe->dst.w; if (src_h > pipe->dst.h) rate = (rate * src_h) / pipe->dst.h; rate *= v_total * fps; if (mixer->rotator_mode) { rate /= 4; /* block mode fetch at 4 pix/clk */ quota *= 2; /* bus read + write */ perf->ib_quota = quota; } else perf->ib_quota = (src_h > pipe->dst.h) ? (quota / pipe->dst.h) * v_total : (quota / src_h) * v_total; perf->ab_quota = quota; perf->mdp_clk_rate = rate; pr_debug("mixer=%d pnum=%d clk_rate=%u bus ab=%u ib=%u\n", mixer->num, pipe->num, rate, perf->ab_quota, perf->ib_quota); return 0; }
static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer, struct mdss_mdp_perf_params *perf) { struct mdss_mdp_pipe *pipe; struct mdss_panel_info *pinfo = NULL; int fps = DEFAULT_FRAME_RATE; u32 v_total; int i; u32 max_clk_rate = 0, ab_total = 0, ib_total = 0; memset(perf, 0, sizeof(*perf)); if (!mixer->rotator_mode) { if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) { pinfo = &mixer->ctl->panel_data->panel_info; fps = mdss_panel_get_framerate(pinfo); v_total = mdss_panel_get_vtotal(pinfo); if (pinfo->type == WRITEBACK_PANEL) pinfo = NULL; } else { v_total = mixer->height; } perf->mdp_clk_rate = mixer->width * v_total * fps; perf->mdp_clk_rate = MDSS_MDP_CLK_FUDGE_FACTOR(perf->mdp_clk_rate); if (!pinfo) { /* perf for bus writeback */ perf->ab_quota = fps * mixer->width * mixer->height * 3; perf->ib_quota = perf->ab_quota; } } for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) { struct mdss_mdp_perf_params tmp; pipe = mixer->stage_pipe[i]; if (pipe == NULL) continue; if (mdss_mdp_perf_calc_pipe(pipe, &tmp)) continue; ab_total += tmp.ab_quota >> MDSS_MDP_BUS_FACTOR_SHIFT; ib_total += tmp.ib_quota >> MDSS_MDP_BUS_FACTOR_SHIFT; if (tmp.mdp_clk_rate > max_clk_rate) max_clk_rate = tmp.mdp_clk_rate; } perf->ab_quota += ab_total << MDSS_MDP_BUS_FACTOR_SHIFT; perf->ib_quota += ib_total << MDSS_MDP_BUS_FACTOR_SHIFT; if (max_clk_rate > perf->mdp_clk_rate) perf->mdp_clk_rate = max_clk_rate; }
u32 msm_fb_read_frame_rate(void){ int rdfps = 0; struct msm_fb_data_type* mfd = fbi_list[0]->par; struct mdss_panel_info *mdss_panel = mfd->panel_info; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); mutex_lock(&mdp5_data->dfps_lock); rdfps = mdss_panel_get_framerate(mdss_panel); mutex_unlock(&mdp5_data->dfps_lock); return rdfps; }
int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe, struct mdss_mdp_perf_params *perf) { struct mdss_mdp_mixer *mixer; int fps = DEFAULT_FRAME_RATE; u32 quota, rate, v_total, src_h; if (!pipe || !perf || !pipe->mixer) return -EINVAL; mixer = pipe->mixer; if (mixer->rotator_mode) { v_total = pipe->flags & MDP_ROT_90 ? pipe->dst.w : pipe->dst.h; } else if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) { struct mdss_panel_info *pinfo; pinfo = &mixer->ctl->panel_data->panel_info; fps = mdss_panel_get_framerate(pinfo); v_total = mdss_panel_get_vtotal(pinfo); } else { v_total = mixer->height; } src_h = pipe->src.h >> pipe->vert_deci; quota = fps * pipe->src.w * src_h; if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420) if (pipe->vert_deci) quota *= 2; else quota = (quota * 3) / 2; else quota *= pipe->src_fmt->bpp; rate = pipe->dst.w; if (src_h > pipe->dst.h) rate = (rate * src_h) / pipe->dst.h; rate *= v_total * fps; if (mixer->rotator_mode) { rate /= 4; quota *= 2; perf->ib_quota = quota; } else { perf->ib_quota = (quota / pipe->dst.h) * v_total; } perf->ab_quota = quota; perf->mdp_clk_rate = rate; return 0; }
static void mdss_mdp_perf_mixer_update(struct mdss_mdp_mixer *mixer, u32 *bus_ab_quota, u32 *bus_ib_quota, u32 *clk_rate) { struct mdss_mdp_pipe *pipe; struct mdss_panel_info *pinfo = NULL; int fps = DEFAULT_FRAME_RATE; u32 v_total; int i; u32 max_clk_rate = 0, ab_total = 0; u32 ib_max = 0, ib_max_smp = 0; u32 ib_quota[MDSS_MDP_MAX_STAGE]; u32 v_region[MDSS_MDP_MAX_STAGE * 2]; *bus_ab_quota = 0; *bus_ib_quota = 0; *clk_rate = 0; if (!mixer->rotator_mode) { if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) { pinfo = &mixer->ctl->panel_data->panel_info; fps = mdss_panel_get_framerate(pinfo); v_total = mdss_panel_get_vtotal(pinfo); if (pinfo->type == WRITEBACK_PANEL) pinfo = NULL; } else { v_total = mixer->height; } *clk_rate = mixer->width * v_total * fps; if (pinfo && pinfo->lcdc.v_back_porch < MDP_MIN_VBP) *clk_rate = MDSS_MDP_CLK_FUDGE_FACTOR(*clk_rate); if (!pinfo) { /* perf for bus writeback */ *bus_ab_quota = fps * mixer->width * mixer->height * 3; *bus_ab_quota >>= MDSS_MDP_BUS_FACTOR_SHIFT; *bus_ib_quota = *bus_ab_quota; } }
static void mdss_mdp_perf_mixer_update(struct mdss_mdp_mixer *mixer, u32 *bus_ab_quota, u32 *bus_ib_quota, u32 *clk_rate) { struct mdss_mdp_pipe *pipe; int fps = DEFAULT_FRAME_RATE; u32 v_total; int i; u32 max_clk_rate = 0, ab_total = 0, ib_total = 0; *bus_ab_quota = 0; *bus_ib_quota = 0; *clk_rate = 0; if (!mixer->rotator_mode) { int is_writeback = false; if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) { struct mdss_panel_info *pinfo; pinfo = &mixer->ctl->panel_data->panel_info; fps = mdss_panel_get_framerate(pinfo); v_total = mdss_panel_get_vtotal(pinfo); if (pinfo->type == WRITEBACK_PANEL) is_writeback = true; } else { v_total = mixer->height; is_writeback = true; } *clk_rate = mixer->width * v_total * fps; if (is_writeback) { /* perf for bus writeback */ *bus_ab_quota = fps * mixer->width * mixer->height * 3; *bus_ab_quota >>= MDSS_MDP_BUS_FACTOR_SHIFT; *bus_ib_quota = *bus_ab_quota; } }
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 device_node *dsi_ctrl_np = NULL; struct platform_device *ctrl_pdev = NULL; bool dynamic_fps; const char *data; struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info); enum of_gpio_flags flags; 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", __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", __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", __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", __func__, __LINE__); return -EINVAL; } for (i = 0; i < len; i++) { pinfo->mipi.dsi_phy_db.lanecfg[i] = data[i]; } ctrl_pdata->shared_pdata.broadcast_enable = of_property_read_bool( pan_node, "qcom,mdss-dsi-panel-broadcast-mode"); 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; } pinfo->panel_max_fps = mdss_panel_get_framerate(pinfo); pinfo->panel_max_vtotal = mdss_panel_get_vtotal(pinfo); 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__); 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 { int func; rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te"); if (rc) { pr_err("request TE gpio failed, rc=%d\n", rc); return -ENODEV; } if (pinfo->type == MIPI_CMD_PANEL) func = 1; else func = 0; rc = gpio_tlmm_config(GPIO_CFG( ctrl_pdata->disp_te_gpio, func, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), GPIO_CFG_ENABLE); if (rc) { pr_err("%s: unable to config tlmm = %d\n", __func__, ctrl_pdata->disp_te_gpio); gpio_free(ctrl_pdata->disp_te_gpio); return -ENODEV; } rc = gpio_direction_input(ctrl_pdata->disp_te_gpio); if (rc) { pr_err("set_direction for disp_en gpio failed, rc=%d\n", rc); gpio_free(ctrl_pdata->disp_te_gpio); return -ENODEV; } pr_debug("%s: te_gpio=%d\n", __func__, ctrl_pdata->disp_te_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__); ctrl_pdata->mode_gpio = of_get_named_gpio( ctrl_pdev->dev.of_node, "qcom,platform-mode-gpio", 0); if (pinfo->mode_gpio_state != MODE_GPIO_NOT_VALID) { if (!gpio_is_valid(ctrl_pdata->mode_gpio)) pr_info("%s:%d, mode gpio not specified\n", __func__, __LINE__); } if (ctrl_pdata->partial_mode_enabled) { ctrl_pdata->mipi_d0_sel = of_get_named_gpio_flags( ctrl_pdev->dev.of_node, "mmi,mipi-d0-sel", 0, &flags); if (!gpio_is_valid(ctrl_pdata->mipi_d0_sel)) { pr_info("%s:%d, mipi d0 sel gpio not specified\n", __func__, __LINE__); ctrl_pdata->partial_mode_enabled = false; } else { rc = gpio_request_one(ctrl_pdata->mipi_d0_sel, flags, "mipi_d0_sel"); if (rc) { pr_err("request mipi d0 sel gpio failed, rc=%d\n", rc); if (gpio_is_valid(ctrl_pdata->disp_te_gpio)) gpio_free(ctrl_pdata->disp_te_gpio); ctrl_pdata->partial_mode_enabled = false; return -ENODEV; } gpio_export(ctrl_pdata->mipi_d0_sel, 1); } } 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; 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; if (pinfo->cont_splash_enabled) { pinfo->panel_power_on = 1; /* * This call intends to call to gpio_request for display's * reset gpio, because with cont_splash_enabled, there is * no call to the mdss_dsi_panel_reset(1), but when the first * suspend call, it will call mdss_dsi_panel_reset(0). This * will call to gpio_free() for reset spio, and WARN() msg will * be called because gpio_free() is called without gpio_request */ rc = mdss_dsi_panel_reset(&(ctrl_pdata->panel_data), 1); if (rc) { pr_err("%s: Panel reset on failed\n", __func__); return rc; } rc = mdss_dsi_panel_power_on(&(ctrl_pdata->panel_data), 1); if (rc) { pr_err("%s: Panel power on failed\n", __func__); return rc; } 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_on = 0; } 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; }
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 device_node *dsi_ctrl_np = NULL; struct platform_device *ctrl_pdev = NULL; bool dynamic_fps; const char *data; struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info); 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", __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", __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", __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", __func__, __LINE__); return -EINVAL; } for (i = 0; i < len; i++) { pinfo->mipi.dsi_phy_db.lanecfg[i] = data[i]; } ctrl_pdata->shared_pdata.broadcast_enable = of_property_read_bool( pan_node, "qcom,mdss-dsi-panel-broadcast-mode"); 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; } pinfo->panel_max_fps = mdss_panel_get_framerate(pinfo); pinfo->panel_max_vtotal = mdss_panel_get_vtotal(pinfo); 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 { rc = gpio_request(ctrl_pdata->disp_en_gpio, "disp_enable"); if (rc) { pr_err("request reset gpio failed, rc=%d\n", rc); gpio_free(ctrl_pdata->disp_en_gpio); return -ENODEV; } rc = gpio_direction_output(ctrl_pdata->disp_en_gpio, 1); if (rc) { pr_err("set_direction for disp_en gpio failed, rc=%d\n", rc); gpio_free(ctrl_pdata->disp_en_gpio); return -ENODEV; } } ctrl_pdata->rst_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, "qcom,platform-reset-gpio", 0); printk("***************** ctrl_pdata->rst_gpio = %d *****************\n", ctrl_pdata->rst_gpio); if (!gpio_is_valid(ctrl_pdata->rst_gpio)) { pr_err("%s:%d, reset gpio not specified\n", __func__, __LINE__); } else { rc = gpio_request(ctrl_pdata->rst_gpio, "disp_rst_n"); if (rc) { pr_err("request reset gpio failed, rc=%d\n", rc); gpio_free(ctrl_pdata->rst_gpio); if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) gpio_free(ctrl_pdata->disp_en_gpio); return -ENODEV; } } ctrl_pdata->disp_vsn_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, "qcom,platform-vsn-gpio", 0); if (!gpio_is_valid(ctrl_pdata->disp_vsn_gpio)) { pr_err("%s:%d, vsn gpio not specified\n", __func__, __LINE__); } else { rc = gpio_request(ctrl_pdata->disp_vsn_gpio, "disp_vsn"); if (rc) { pr_err("request vsn gpio failed, rc=%d\n", rc); return -ENODEV; } } ctrl_pdata->disp_vsp_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, "qcom,platform-vsp-gpio", 0); if (!gpio_is_valid(ctrl_pdata->disp_vsp_gpio)) { pr_err("%s:%d, vsp gpio not specified\n", __func__, __LINE__); } else { rc = gpio_request(ctrl_pdata->disp_vsp_gpio, "disp_vsp"); if (rc) { pr_err("request vsp gpio failed, rc=%d\n", rc); return -ENODEV; } } ctrl_pdata->bl_outdoor_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, "qcom,platform-outdoor-gpio", 0); #if 1 if (!gpio_is_valid(ctrl_pdata->bl_outdoor_gpio)) { pr_err("%s:%d, bl_outdoor_gpio gpio not specified\n", __func__, __LINE__); } else { rc = gpio_request(ctrl_pdata->bl_outdoor_gpio, "bl_outdoor"); if (rc) { pr_err("request bl outdoor gpio failed, rc=%d\n", rc); return -ENODEV; } } #endif #ifdef ESD_FOR_LCD 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__); } if (gpio_is_valid(ctrl_pdata->disp_te_gpio)) { rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te"); if (rc) { pr_err("request TE gpio failed, rc=%d\n", rc); gpio_free(ctrl_pdata->disp_te_gpio); return -ENODEV; } INIT_DELAYED_WORK(&lcd_te_work, lcd_te_abnormal_handle); init_timer(&te_timer); te_timer.function = te_timer_handle; ctrl_pdata->te_irq = gpio_to_irq(ctrl_pdata->disp_te_gpio); rc = request_irq(ctrl_pdata->te_irq, lcd_te_irq_handle, IRQF_TRIGGER_RISING, "LCD_TE", ctrl_pdata); if (rc) { printk(KERN_ERR "lcd te request irq(%d) failure, rc = %d\n", ctrl_pdata->te_irq, rc); return -1; } te_running = 0; disable_irq(ctrl_pdata->te_irq); printk("************************** te irq %d requested *******************************\n", ctrl_pdata->te_irq); pr_debug("%s: te_gpio=%d\n", __func__, ctrl_pdata->disp_te_gpio); } #endif pr_info("[DIS] DISPLAY_GPIO[ te: %d en: %d rst: %d vsp: %d vsn: %d bl_outdoor: %d]", ctrl_pdata->disp_te_gpio ,ctrl_pdata->disp_en_gpio, ctrl_pdata->rst_gpio, ctrl_pdata->disp_vsp_gpio, ctrl_pdata->disp_vsn_gpio, ctrl_pdata->bl_outdoor_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; if (ctrl_pdata->status_mode == ESD_REG) ctrl_pdata->check_status = mdss_dsi_reg_status_check; else if (ctrl_pdata->status_mode == ESD_BTA) ctrl_pdata->check_status = mdss_dsi_bta_status_check; if (ctrl_pdata->status_mode == ESD_MAX) { pr_err("%s: Using default BTA for ESD check\n", __func__); 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; if (pinfo->cont_splash_enabled) { pinfo->panel_power_on = 1; rc = mdss_dsi_panel_power_on(&(ctrl_pdata->panel_data), 1); if (rc) { pr_err("%s: Panel power on failed\n", __func__); return rc; } 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_on = 0; } 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; }
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 device_node *dsi_ctrl_np = NULL; struct platform_device *ctrl_pdev = NULL; bool dynamic_fps; const char *data; struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info); struct mdss_panel_specific_pdata *spec_pdata = NULL; spec_pdata = ctrl_pdata->spec_pdata; if (!spec_pdata) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } 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", __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", __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", __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_debug("%s:%d, Unable to read Phy lane configure settings", __func__, __LINE__); } else { for (i = 0; i < len; i++) { pinfo->mipi.dsi_phy_db.lanecfg[i] = data[i]; } } ctrl_pdata->shared_pdata.broadcast_enable = of_property_read_bool( pan_node, "qcom,mdss-dsi-panel-broadcast-mode"); 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; } pinfo->panel_max_fps = mdss_panel_get_framerate(pinfo); pinfo->panel_max_vtotal = mdss_panel_get_vtotal(pinfo); 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__); if (pinfo->type == MIPI_CMD_PANEL) { 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__); } } if (gpio_is_valid(ctrl_pdata->disp_te_gpio) && pinfo->type == MIPI_CMD_PANEL) { rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te"); if (rc) { pr_err("request TE gpio failed, rc=%d\n", rc); return -ENODEV; } rc = gpio_tlmm_config(GPIO_CFG( ctrl_pdata->disp_te_gpio, 1, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA), GPIO_CFG_ENABLE); if (rc) { pr_err("%s: unable to config tlmm = %d\n", __func__, ctrl_pdata->disp_te_gpio); gpio_free(ctrl_pdata->disp_te_gpio); return -ENODEV; } rc = gpio_direction_input(ctrl_pdata->disp_te_gpio); if (rc) { pr_err("set_direction for disp_en gpio failed, rc=%d\n", rc); gpio_free(ctrl_pdata->disp_te_gpio); return -ENODEV; } pr_debug("%s: te_gpio=%d\n", __func__, ctrl_pdata->disp_te_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__); 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.intf_ready = mdss_dsi_intf_ready; ctrl_pdata->panel_data.event_handler = mdss_dsi_event_handler; ctrl_pdata->panel_data.detect = spec_pdata->detect; ctrl_pdata->panel_data.update_panel = spec_pdata->update_panel; ctrl_pdata->panel_data.panel_pdev = ctrl_pdev; #ifdef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL ctrl_pdata->cabc_off_cmds = spec_pdata->cabc_off_cmds[DEFAULT_CMDS]; ctrl_pdata->cabc_late_off_cmds = spec_pdata->cabc_late_off_cmds[DEFAULT_CMDS]; ctrl_pdata->off_cmds = spec_pdata->off_cmds[DEFAULT_CMDS]; #endif /* CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL */ if (ctrl_pdata->status_mode == ESD_REG) ctrl_pdata->check_status = mdss_dsi_reg_status_check; else if (ctrl_pdata->status_mode == ESD_BTA) ctrl_pdata->check_status = mdss_dsi_bta_status_check; if (ctrl_pdata->status_mode == ESD_MAX) { pr_err("%s: Using default BTA for ESD check\n", __func__); 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; if (pinfo->cont_splash_enabled) { pinfo->panel_power_on = 1; #ifndef CONFIG_FB_MSM_MDSS_SPECIFIC_PANEL rc = mdss_dsi_panel_power_on(&(ctrl_pdata->panel_data), 1); #else rc = ctrl_pdata->spec_pdata->panel_power_on( &(ctrl_pdata->panel_data), 1); #endif if (rc) { pr_err("%s: Panel power on failed\n", __func__); return rc; } 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_on = 0; } 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; }
static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer, struct mdss_mdp_perf_params *perf) { struct mdss_mdp_pipe *pipe; struct mdss_panel_info *pinfo = NULL; int fps = DEFAULT_FRAME_RATE; u32 v_total = 0; int i; u32 max_clk_rate = 0, ab_total = 0; u32 ib_max = 0; u32 ib_quota[MDSS_MDP_MAX_STAGE]; u32 v_region[MDSS_MDP_MAX_STAGE * 2]; u32 smp_bytes = 0; u64 smp_bw = 0; memset(perf, 0, sizeof(*perf)); if (!mixer->rotator_mode) { if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) { pinfo = &mixer->ctl->panel_data->panel_info; fps = mdss_panel_get_framerate(pinfo); v_total = mdss_panel_get_vtotal(pinfo); if (pinfo->type == WRITEBACK_PANEL) pinfo = NULL; } else { v_total = mixer->height; } perf->mdp_clk_rate = mixer->width * v_total * fps; if (pinfo && pinfo->lcdc.v_back_porch < MDP_MIN_VBP) perf->mdp_clk_rate = MDSS_MDP_CLK_FUDGE_FACTOR(perf->mdp_clk_rate); if (!pinfo) { /* perf for bus writeback */ perf->ab_quota = fps * mixer->width * mixer->height * 3; perf->ib_quota = perf->ab_quota; } } memset(ib_quota, 0, sizeof(u32) * MDSS_MDP_MAX_STAGE); memset(v_region, 0, sizeof(u32) * MDSS_MDP_MAX_STAGE * 2); for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) { struct mdss_mdp_perf_params tmp; pipe = mixer->stage_pipe[i]; if (pipe == NULL) continue; if (mdss_mdp_perf_calc_pipe(pipe, &tmp)) continue; smp_bytes += mdss_mdp_smp_get_size(pipe); ab_total += tmp.ab_quota >> MDSS_MDP_BUS_FACTOR_SHIFT; ib_quota[i] = tmp.ib_quota >> MDSS_MDP_BUS_FACTOR_SHIFT; v_region[2*i] = pipe->dst.y; v_region[2*i + 1] = pipe->dst.y + pipe->dst.h; if (tmp.mdp_clk_rate > max_clk_rate) max_clk_rate = tmp.mdp_clk_rate; } /* * Sort the v_region array so the total display area can be * divided into individual regions. Check how many pipes fetch * data for each region and sum them up , then the worst case * of all regions is ib request. */ sort(v_region, MDSS_MDP_MAX_STAGE * 2, sizeof(u32), cmpu32, NULL); for (i = 1; i < MDSS_MDP_MAX_STAGE * 2; i++) { int j; u32 ib_max_region = 0; u32 y0, y1; pr_debug("v_region[%d]%d\n", i, v_region[i]); if (v_region[i] == v_region[i-1]) continue; y0 = (v_region[i-1]) ? v_region[i-1] + 1 : 0 ; y1 = v_region[i]; for (j = 0; j < MDSS_MDP_MAX_STAGE; j++) { if (!ib_quota[j]) continue; pipe = mixer->stage_pipe[j]; if (mdss_mdp_perf_is_overlap (y0, y1, pipe->dst.y, (pipe->dst.y + pipe->dst.h))) ib_max_region += ib_quota[j]; pr_debug("v[%d](%d, %d)pipe[%d](%d,%d)quota=%d max=%d\n", i, y0, y1, j, pipe->dst.y, pipe->dst.y + pipe->dst.h, ib_quota[j], ib_max_region); } ib_max = max(ib_max, ib_max_region); } perf->ab_quota += ab_total << MDSS_MDP_BUS_FACTOR_SHIFT; perf->ib_quota += ib_max << MDSS_MDP_BUS_FACTOR_SHIFT; if (max_clk_rate > perf->mdp_clk_rate) perf->mdp_clk_rate = max_clk_rate; if (pinfo) { int vbp; /* * need to be able to at least fill the shared memory pool * during blanking period */ vbp = pinfo->lcdc.v_back_porch + pinfo->lcdc.v_pulse_width; smp_bw = smp_bytes * v_total * fps; do_div(smp_bw, vbp); if (smp_bw > perf->ib_quota) { pr_debug("replacing ib_quota=%llu with smp_bw=%llu\n", perf->ib_quota, smp_bw); perf->ib_quota = smp_bw; } } pr_debug("final mixer=%d clk_rate=%u bus ab=%llu ib=%llu smp=%llu\n", mixer->num, perf->mdp_clk_rate, perf->ab_quota, perf->ib_quota, smp_bw); }