/**
 * 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;
}
Exemple #4
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);
}
Exemple #5
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;
	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;
		}
	}
Exemple #6
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;
		}
	}
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;
}
Exemple #14
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);
}