/** * 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; }
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; }
void mdss_panel_debugfsinfo_to_panelinfo(struct mdss_panel_info *panel_info) { struct mdss_panel_data *pdata; struct mdss_panel_info *pinfo; pdata = container_of(panel_info, struct mdss_panel_data, panel_info); do { pinfo = &pdata->panel_info; pinfo->xres = pinfo->debugfs_info->xres; pinfo->yres = pinfo->debugfs_info->yres; pinfo->lcdc = pinfo->debugfs_info->lcdc; pinfo->panel_max_vtotal = mdss_panel_get_vtotal(pinfo); pinfo->fbc = pinfo->debugfs_info->fbc; pinfo->mipi.frame_rate = pinfo->debugfs_info->frame_rate; pdata = pdata->next; } while (pdata); }
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; const int fps = 60; #ifndef QCT_UNDERRUN_PATCH /*maintain QMC original code */ u32 quota, rate; #endif 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; #ifdef QCT_UNDERRUN_PATCH 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; 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; } }
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; } }
static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps) { int rc = 0; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; u32 dsi_ctrl; pr_debug("%s+:\n", __func__); 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); if (!ctrl_pdata->panel_data.panel_info.dynamic_fps) { pr_err("%s: Dynamic fps not enabled for this panel\n", __func__); return -EINVAL; } if (new_fps != ctrl_pdata->panel_data.panel_info.mipi.frame_rate) { if (pdata->panel_info.dfps_update == DFPS_IMMEDIATE_PORCH_UPDATE_MODE) { u32 hsync_period, vsync_period; u32 new_dsi_v_total, current_dsi_v_total; vsync_period = mdss_panel_get_vtotal(&pdata->panel_info); hsync_period = mdss_panel_get_htotal(&pdata->panel_info); current_dsi_v_total = MIPI_INP((ctrl_pdata->ctrl_base) + 0x2C); new_dsi_v_total = ((vsync_period - 1) << 16) | (hsync_period - 1); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C, (current_dsi_v_total | 0x8000000)); if (new_dsi_v_total & 0x8000000) { MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C, new_dsi_v_total); } else { MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C, (new_dsi_v_total | 0x8000000)); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x2C, (new_dsi_v_total & 0x7ffffff)); } pdata->panel_info.mipi.frame_rate = new_fps; } else { rc = mdss_dsi_clk_div_config (&ctrl_pdata->panel_data.panel_info, new_fps); if (rc) { pr_err("%s: unable to initialize the clk dividers\n", __func__); return rc; } ctrl_pdata->pclk_rate = pdata->panel_info.mipi.dsi_pclk_rate; ctrl_pdata->byte_clk_rate = pdata->panel_info.clk_rate / 8; if (pdata->panel_info.dfps_update == DFPS_IMMEDIATE_CLK_UPDATE_MODE) { dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0004); pdata->panel_info.mipi.frame_rate = new_fps; dsi_ctrl &= ~0x2; MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, dsi_ctrl); mdss_dsi_controller_cfg(true, pdata); mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0); mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1); dsi_ctrl |= 0x2; MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, dsi_ctrl); } } } else { pr_debug("%s: Panel is already at this FPS\n", __func__); } return rc; }
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 mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info, int frame_rate) { u32 fb_divider, rate, vco; u32 div_ratio = 0; u32 pll_analog_posDiv = 1; u32 h_period, v_period; u32 dsi_pclk_rate; u8 lanes = 0, bpp; struct dsi_clk_mnd_table const *mnd_entry = mnd_table; if (panel_info->mipi.data_lane3) lanes += 1; if (panel_info->mipi.data_lane2) lanes += 1; if (panel_info->mipi.data_lane1) lanes += 1; if (panel_info->mipi.data_lane0) lanes += 1; switch (panel_info->mipi.dst_format) { case DSI_CMD_DST_FORMAT_RGB888: case DSI_VIDEO_DST_FORMAT_RGB888: case DSI_VIDEO_DST_FORMAT_RGB666_LOOSE: bpp = 3; break; case DSI_CMD_DST_FORMAT_RGB565: case DSI_VIDEO_DST_FORMAT_RGB565: bpp = 2; break; default: bpp = 3; /* Default format set to RGB888 */ break; } h_period = mdss_panel_get_htotal(panel_info, true); v_period = mdss_panel_get_vtotal(panel_info); if ((frame_rate != panel_info->mipi.frame_rate) || (!panel_info->clk_rate)) { h_period += panel_info->lcdc.xres_pad; v_period += panel_info->lcdc.yres_pad; if (lanes > 0) { panel_info->clk_rate = ((h_period * v_period * frame_rate * bpp * 8) / lanes); } else { pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__); panel_info->clk_rate = (h_period * v_period * frame_rate * bpp * 8); } } pll_divider_config.clk_rate = panel_info->clk_rate; if (pll_divider_config.clk_rate == 0) pll_divider_config.clk_rate = 454000000; rate = (pll_divider_config.clk_rate / 2) / 1000000; /* Half Bit Clock In Mhz */ if (rate < 43) { vco = rate * 16; div_ratio = 16; pll_analog_posDiv = 8; } else if (rate < 85) { vco = rate * 8; div_ratio = 8; pll_analog_posDiv = 4; } else if (rate < 170) { vco = rate * 4; div_ratio = 4; pll_analog_posDiv = 2; } else if (rate < 340) { vco = rate * 2; div_ratio = 2; pll_analog_posDiv = 1; } else { /* DSI PLL Direct path configuration */ vco = rate * 1; div_ratio = 1; pll_analog_posDiv = 1; } /* find the mnd settings from mnd_table entry */ for (; mnd_entry < mnd_table + ARRAY_SIZE(mnd_table); ++mnd_entry) { if (((mnd_entry->lanes) == lanes) && ((mnd_entry->bpp) == bpp)) break; } if (mnd_entry == mnd_table + ARRAY_SIZE(mnd_table)) { pr_err("%s: requested Lanes, %u & BPP, %u, not supported\n", __func__, lanes, bpp); return -EINVAL; } fb_divider = ((vco * PREF_DIV_RATIO) / 27); pll_divider_config.fb_divider = fb_divider; pll_divider_config.ref_divider_ratio = PREF_DIV_RATIO; pll_divider_config.bit_clk_divider = div_ratio; pll_divider_config.byte_clk_divider = pll_divider_config.bit_clk_divider * 8; pll_divider_config.analog_posDiv = pll_analog_posDiv; pll_divider_config.digital_posDiv = (mnd_entry->pll_digital_posDiv) * div_ratio; if ((mnd_entry->pclk_d == 0) || (mnd_entry->pclk_m == 1)) { dsi_pclk.mnd_mode = 0; dsi_pclk.src = 0x3; dsi_pclk.pre_div_func = (mnd_entry->pclk_n - 1); } else { dsi_pclk.mnd_mode = 2; dsi_pclk.src = 0x3; dsi_pclk.m = mnd_entry->pclk_m; dsi_pclk.n = mnd_entry->pclk_n; dsi_pclk.d = mnd_entry->pclk_d; } dsi_pclk_rate = (((pll_divider_config.clk_rate) * lanes) / (8 * bpp)); if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 250000000)) dsi_pclk_rate = 35000000; panel_info->mipi.dsi_pclk_rate = dsi_pclk_rate; return 0; }
int mdss_dsi_phy_calc_timing_param(struct mdss_panel_info *pinfo, u32 phy_rev, u32 frate_hz) { struct dsi_phy_t_clk_param t_clk; struct dsi_phy_timing t_param; int hsync_period; int vsync_period; unsigned long inter_num; uint32_t lane_config = 0; unsigned long x, y; int rc = 0; if (!pinfo) { pr_err("invalid panel info\n"); return -EINVAL; } hsync_period = mdss_panel_get_htotal(pinfo, true); vsync_period = mdss_panel_get_vtotal(pinfo); inter_num = pinfo->bpp * frate_hz; if (pinfo->mipi.data_lane0) lane_config++; if (pinfo->mipi.data_lane1) lane_config++; if (pinfo->mipi.data_lane2) lane_config++; if (pinfo->mipi.data_lane3) lane_config++; x = mult_frac(vsync_period * hsync_period, inter_num, lane_config); y = rounddown(x, 1); t_clk.bitclk_mbps = rounddown(mult_frac(y, 1, 1000000), 1); t_clk.escclk_numer = ESC_CLK_MHZ; t_clk.escclk_denom = ESCCLK_MMSS_CC_PREDIV; t_clk.tlpx_numer_ns = TLPX_NUMER; t_clk.treot_ns = TR_EOT; pr_debug("hperiod=%d, vperiod=%d, inter_num=%lu, lane_cfg=%d\n", hsync_period, vsync_period, inter_num, lane_config); pr_debug("x=%lu, y=%lu, bitrate=%d\n", x, y, t_clk.bitclk_mbps); switch (phy_rev) { case DSI_PHY_REV_10: rc = mdss_dsi_phy_initialize_defaults(&t_clk, &t_param, phy_rev); if (rc) { pr_err("phy%d initialization failed\n", phy_rev); goto timing_calc_end; } mdss_dsi_phy_calc_param_phy_rev_1(&t_clk, &t_param); mdss_dsi_phy_update_timing_param(pinfo, &t_param); break; case DSI_PHY_REV_20: rc = mdss_dsi_phy_initialize_defaults(&t_clk, &t_param, phy_rev); if (rc) { pr_err("phy%d initialization failed\n", phy_rev); goto timing_calc_end; } rc = mdss_dsi_phy_calc_param_phy_rev_2(&t_clk, &t_param); if (rc) { pr_err("Phy timing calculations failed\n"); goto timing_calc_end; } mdss_dsi_phy_update_timing_param_rev_2(pinfo, &t_param); break; default: pr_err("phy rev %d not supported\n", phy_rev); return -EINVAL; } timing_calc_end: return rc; }
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); }