Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0ad4f494 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: mdss: fix race condition in idle power collapse logic"

parents bf3d7f64 1a6b2764
Loading
Loading
Loading
Loading
+49 −10
Original line number Diff line number Diff line
@@ -159,7 +159,6 @@ static irqreturn_t mdp3_irq_handler(int irq, void *ptr)
		spin_unlock(&mdata->irq_lock);
		return IRQ_HANDLED;
	}

	mdp_status = MDP3_REG_READ(MDP3_REG_INTR_STATUS);
	mdp_interrupt = mdp_status;
	pr_debug("mdp3_irq_handler irq=%d\n", mdp_interrupt);
@@ -1072,6 +1071,17 @@ u64 mdp3_get_panic_lut_cfg(u32 panel_width)
	return panic_config;
}

int mdp3_enable_panic_ctrl(void)
{
	int rc = 0;

	if (MDP3_REG_READ(MDP3_PANIC_ROBUST_CTRL) == 0) {
		pr_err("%s: Enable Panic Control\n", __func__);
		MDP3_REG_WRITE(MDP3_PANIC_ROBUST_CTRL, BIT(0));
	}
	return rc;
}

int mdp3_qos_remapper_setup(struct mdss_panel_data *panel)
{
	int rc = 0;
@@ -2196,9 +2206,10 @@ static int mdp3_is_display_on(struct mdss_panel_data *pdata)

	mdp3_res->splash_mem_addr = MDP3_REG_READ(MDP3_REG_DMA_P_IBUF_ADDR);

	rc = mdp3_clk_enable(0, 0);
	if (rc)
	if (pdata->panel_info.type == MIPI_CMD_PANEL) {
		if (mdp3_clk_enable(0, 0))
			pr_err("fail to turn off MDP core clks\n");
	}
	return rc;
}

@@ -2293,10 +2304,30 @@ static int mdp3_panel_register_done(struct mdss_panel_data *pdata)
	return rc;
}

/* mdp3_clear_irq() - Clear interrupt
 * @ interrupt_mask : interrupt mask
 *
 * This function clear sync irq for command mode panel.
 * When system is entering in idle screen state.
 */
void mdp3_clear_irq(u32 interrupt_mask)
{
	unsigned long flag;
	u32 irq_status = 0;

	spin_lock_irqsave(&mdp3_res->irq_lock, flag);
	irq_status = interrupt_mask &
		MDP3_REG_READ(MDP3_REG_INTR_STATUS);
	if (irq_status)
		MDP3_REG_WRITE(MDP3_REG_INTR_CLEAR, irq_status);
	spin_unlock_irqrestore(&mdp3_res->irq_lock, flag);

}

/* mdp3_autorefresh_disable() - Disable Auto refresh
 * @ panel_info : pointer to panel configuration structure
 *
 * This function displable Auto refresh block for command mode panel.
 * This function disable Auto refresh block for command mode panel.
 */
int mdp3_autorefresh_disable(struct mdss_panel_info *panel_info)
{
@@ -2598,10 +2629,12 @@ int mdp3_footswitch_ctrl(int enable)
	int rc = 0;
	int active_cnt = 0;

	mutex_lock(&mdp3_res->fs_idle_pc_lock);
	if (!mdp3_res->fs_ena && enable) {
		rc = regulator_enable(mdp3_res->fs);
		if (rc) {
			pr_err("mdp footswitch ctrl enable failed\n");
			mutex_unlock(&mdp3_res->fs_idle_pc_lock);
			return -EINVAL;
		}
		pr_debug("mdp footswitch ctrl enable success\n");
@@ -2622,13 +2655,16 @@ int mdp3_footswitch_ctrl(int enable)
		rc = regulator_disable(mdp3_res->fs);
		if (rc) {
			pr_err("mdp footswitch ctrl disable failed\n");
			mutex_unlock(&mdp3_res->fs_idle_pc_lock);
			return -EINVAL;
		}
			mdp3_res->fs_ena = false;
		pr_debug("mdp3 footswitch ctrl disable configured\n");
	} else {
		pr_debug("mdp3 footswitch ctrl already configured\n");
	}

	mutex_unlock(&mdp3_res->fs_idle_pc_lock);
	return rc;
}

@@ -2649,9 +2685,11 @@ int mdp3_panel_get_intf_status(u32 disp_num, u32 intf_type)
	/* DSI video mode or command mode */
	rc = (status == 0x180000) || (status == 0x080000);

	rc = mdp3_clk_enable(0, 0);
	if (rc)
	/* For Video mode panel do not disable clock */
	if (status == 0x80000) {
		if (mdp3_clk_enable(0, 0))
			pr_err("fail to turn off MDP core clks\n");
	}
	return rc;
}

@@ -2690,6 +2728,7 @@ static int mdp3_probe(struct platform_device *pdev)
	pdev->id = 0;
	mdp3_res->pdev = pdev;
	mutex_init(&mdp3_res->res_mutex);
	mutex_init(&mdp3_res->fs_idle_pc_lock);
	spin_lock_init(&mdp3_res->irq_lock);
	platform_set_drvdata(pdev, mdp3_res);
	atomic_set(&mdp3_res->active_intf_cnt, 0);
+3 −1
Original line number Diff line number Diff line
@@ -169,6 +169,7 @@ struct mdp3_hw_resource {
	bool allow_iommu_update;
	struct ion_handle *ion_handle;
	struct mutex iommu_lock;
	struct mutex fs_idle_pc_lock;

	struct mdp3_dma dma[MDP3_DMA_MAX];
	struct mdp3_intf intf[MDP3_DMA_OUTPUT_SEL_MAX];
@@ -265,7 +266,8 @@ u64 mdp3_clk_round_off(u64 clk_rate);

void mdp3_calc_dma_res(struct mdss_panel_info *panel_info, u64 *clk_rate,
		u64 *ab, u64 *ib, uint32_t bpp);

void mdp3_clear_irq(u32 interrupt_mask);
int mdp3_enable_panic_ctrl(void);

#define MDP3_REG_WRITE(addr, val) writel_relaxed(val, mdp3_res->mdp_base + addr)
#define MDP3_REG_READ(addr) readl_relaxed(mdp3_res->mdp_base + addr)
+83 −23
Original line number Diff line number Diff line
@@ -172,9 +172,9 @@ static void mdp3_dispatch_clk_off(struct work_struct *work)

	mutex_lock(&session->lock);
	if (session->vsync_enabled ||
		atomic_read(&session->vsync_countdown) != 0) {
		atomic_read(&session->vsync_countdown) > 0) {
		mutex_unlock(&session->lock);
		pr_debug("Ignoring clk shut down\n");
		pr_debug("%s: Ignoring clk shut down\n", __func__);
		return;
	}

@@ -201,7 +201,6 @@ retry_dma_done:
			}
		}
	}

	mdp3_ctrl_vsync_enable(session->mfd, 0);
	mdp3_ctrl_clk_enable(session->mfd, 0);
	mutex_unlock(&session->lock);
@@ -226,6 +225,7 @@ void vsync_count_down(void *arg)
{
	struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
	/* We are counting down to turn off clocks */
	if (atomic_read(&session->vsync_countdown) > 0)
		atomic_dec(&session->vsync_countdown);
	if (atomic_read(&session->vsync_countdown) == 0)
		schedule_work(&session->clk_off_work);
@@ -243,6 +243,7 @@ static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable)
	struct mdp3_session_data *mdp3_session;
	struct mdp3_notification vsync_client;
	struct mdp3_notification *arg = NULL;
	bool mod_vsync_timer = false;

	pr_debug("mdp3_ctrl_vsync_enable =%d\n", enable);
	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
@@ -258,7 +259,7 @@ static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable)
		vsync_client.handler = vsync_notify_handler;
		vsync_client.arg = mdp3_session;
		arg = &vsync_client;
	} else if (atomic_read(&mdp3_session->vsync_countdown)) {
	} else if (atomic_read(&mdp3_session->vsync_countdown) > 0) {
		/*
		 * Now that vsync is no longer needed we will
		 * shutdown dsi clocks as soon as cnt down == 0
@@ -270,6 +271,18 @@ static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable)
		enable = 1;
	}

	if (enable) {
		if (mdp3_session->status == 1 &&
			(mdp3_session->vsync_before_commit ||
			!mdp3_session->intf->active)) {
			mod_vsync_timer = true;
		} else if (!mdp3_session->clk_on) {
			/* Enable clocks before enabling the vsync interrupt */
			mdp3_ctrl_reset_countdown(mdp3_session, mfd);
			mdp3_ctrl_clk_enable(mfd, 1);
		}
	}

	mdp3_clk_enable(1, 0);
	mdp3_session->dma->vsync_enable(mdp3_session->dma, arg);
	mdp3_clk_enable(0, 0);
@@ -278,14 +291,9 @@ static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable)
	 * Need to fake vsync whenever dsi interface is not
	 * active or when dsi clocks are currently off
	 */
	if (enable && mdp3_session->status == 1
			&& (mdp3_session->vsync_before_commit ||
			!mdp3_session->intf->active)) {
	if (mod_vsync_timer) {
		mod_timer(&mdp3_session->vsync_timer,
			jiffies + msecs_to_jiffies(mdp3_session->vsync_period));
	} else if (enable && !mdp3_session->clk_on) {
		mdp3_ctrl_reset_countdown(mdp3_session, mfd);
		mdp3_ctrl_clk_enable(mfd, 1);
	} else if (!enable) {
		del_timer(&mdp3_session->vsync_timer);
	}
@@ -750,8 +758,6 @@ static int mdp3_ctrl_on(struct msm_fb_data_type *mfd)
	mutex_lock(&mdp3_session->lock);

	panel = mdp3_session->panel;
	pr_err("%s %d in_splash_screen %d\n", __func__, __LINE__,
		mdp3_session->in_splash_screen);
	/* make sure DSI host is initialized properly */
	if (panel) {
		pr_debug("%s : dsi host init, power state = %d Splash %d\n",
@@ -760,7 +766,6 @@ static int mdp3_ctrl_on(struct msm_fb_data_type *mfd)
		if (mdss_fb_is_power_on_lp(mfd) ||
			mdp3_session->in_splash_screen) {
			/* Turn on panel so that it can exit low power mode */
		pr_err("%s %d\n", __func__, __LINE__);
			mdp3_clk_enable(1, 0);
		rc = panel->event_handler(panel,
				MDSS_EVENT_LINK_READY, NULL);
@@ -768,12 +773,14 @@ static int mdp3_ctrl_on(struct msm_fb_data_type *mfd)
				MDSS_EVENT_UNBLANK, NULL);
		rc |= panel->event_handler(panel,
				MDSS_EVENT_PANEL_ON, NULL);
		if (mdss_fb_is_power_on_ulp(mfd))
			rc |= mdp3_enable_panic_ctrl();
			mdp3_clk_enable(0, 0);
		}
	}

	if (mdp3_session->status) {
		pr_err("fb%d is on already\n", mfd->index);
		pr_debug("fb%d is on already\n", mfd->index);
		goto end;
	}

@@ -1011,6 +1018,32 @@ static int mdp3_ctrl_off(struct msm_fb_data_type *mfd)
			mdp3_bufq_deinit(&mdp3_session->bufq_in);
		}
	}

	if (mdss_fb_is_power_on_ulp(mfd) &&
		(mfd->panel.type == MIPI_CMD_PANEL)) {
		pr_debug("%s: Disable MDP3 clocks in ULP\n", __func__);
		if (!mdp3_session->clk_on)
			mdp3_ctrl_clk_enable(mfd, 1);
		/*
		 * STOP DMA transfer first and signal vsync notification
		 * Before releasing the resource in ULP state.
		 */
		rc = mdp3_session->dma->stop(mdp3_session->dma,
					mdp3_session->intf);
		if (rc)
			pr_warn("fail to stop the MDP3 dma in ULP\n");
		/* Wait to ensure TG to turn off */
		msleep(20);
		/*
		 * Handle ULP request initiated from fb_pm_suspend.
		 * For ULP panel power state disabling vsync and set
		 * vsync_count to zero and Turn off MDP3 clocks
		 */
		atomic_set(&mdp3_session->vsync_countdown, 0);
		mdp3_session->vsync_enabled = 0;
		mdp3_ctrl_vsync_enable(mdp3_session->mfd, 0);
		mdp3_ctrl_clk_enable(mdp3_session->mfd, 0);
	}
off_error:
	mutex_unlock(&mdp3_session->lock);
	/* Release the last reference to the runtime device */
@@ -1038,7 +1071,10 @@ static int mdp3_ctrl_reset(struct msm_fb_data_type *mfd)
	panel = mdp3_session->panel;
	mdp3_dma = mdp3_session->dma;
	mutex_lock(&mdp3_session->lock);
	if (mdp3_res->idle_pc) {
	pr_debug("mdp3_ctrl_reset idle_pc %s FS_EN %s\n",
		mdp3_res->idle_pc ? "True":"False",
		mdp3_res->fs_ena ? "True":"False");
	if (mdp3_res->idle_pc || mdp3_res->fs_ena) {
		mdp3_clk_enable(1, 0);
		mdp3_dynamic_clock_gating_ctrl(0);
		mdp3_qos_remapper_setup(panel);
@@ -1047,7 +1083,7 @@ static int mdp3_ctrl_reset(struct msm_fb_data_type *mfd)
	rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P);
	if (rc) {
		pr_err("fail to attach dma iommu\n");
		if (mdp3_res->idle_pc)
		if (mdp3_res->idle_pc || mdp3_res->fs_ena)
			mdp3_clk_enable(0, 0);
		goto reset_error;
	}
@@ -1166,16 +1202,26 @@ static int mdp3_overlay_queue_buffer(struct msm_fb_data_type *mfd,
					struct msmfb_overlay_data *req)
{
	int rc;
	bool is_panel_type_cmd = false;
	struct mdp3_session_data *mdp3_session = mfd->mdp.private1;
	struct msmfb_data *img = &req->data;
	struct mdp3_img_data data;
	struct mdp3_dma *dma = mdp3_session->dma;

	memset(&data, 0, sizeof(struct mdp3_img_data));
	if (mfd->panel.type == MIPI_CMD_PANEL)
		is_panel_type_cmd = true;
	if (is_panel_type_cmd) {
		rc = mdp3_iommu_enable(MDP3_CLIENT_DMA_P);
		if (rc) {
			pr_err("fail to enable iommu\n");
			return rc;
		}
	}
	rc = mdp3_get_img(img, &data, MDP3_CLIENT_DMA_P);
	if (rc) {
		pr_err("fail to get overlay buffer\n");
		return rc;
		goto err;
	}

	if (data.len < dma->source_config.stride * dma->source_config.height) {
@@ -1183,16 +1229,20 @@ static int mdp3_overlay_queue_buffer(struct msm_fb_data_type *mfd,
			data.len, (dma->source_config.stride *
			dma->source_config.height));
		mdp3_put_img(&data, MDP3_CLIENT_DMA_P);
		return -EINVAL;
		rc = -EINVAL;
		goto err;
	}

	rc = mdp3_bufq_push(&mdp3_session->bufq_in, &data);
	if (rc) {
		pr_err("fail to queue the overlay buffer, buffer drop\n");
		mdp3_put_img(&data, MDP3_CLIENT_DMA_P);
		return rc;
		goto err;
	}
	return 0;
	rc = 0;
err:
	if (is_panel_type_cmd)
		mdp3_iommu_disable(MDP3_CLIENT_DMA_P);
	return rc;
}

static int mdp3_overlay_play(struct msm_fb_data_type *mfd,
@@ -1276,6 +1326,7 @@ static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd,
	}

	panel = mdp3_session->panel;
	mutex_lock(&mdp3_res->fs_idle_pc_lock);
	if (mdp3_session->in_splash_screen ||
		mdp3_res->idle_pc) {
		pr_debug("%s: reset- in_splash = %d, idle_pc = %d", __func__,
@@ -1283,9 +1334,11 @@ static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd,
		rc = mdp3_ctrl_reset(mfd);
		if (rc) {
			pr_err("fail to reset display\n");
			mutex_unlock(&mdp3_res->fs_idle_pc_lock);
			return -EINVAL;
		}
	}
	mutex_unlock(&mdp3_res->fs_idle_pc_lock);

	mutex_lock(&mdp3_session->lock);

@@ -1418,6 +1471,7 @@ static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd)
	if (!mdp3_session || !mdp3_session->dma)
		return;

	mutex_lock(&mdp3_res->fs_idle_pc_lock);
	if (mdp3_session->in_splash_screen ||
		mdp3_res->idle_pc) {
		pr_debug("%s: reset- in_splash = %d, idle_pc = %d", __func__,
@@ -1425,9 +1479,11 @@ static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd)
		rc = mdp3_ctrl_reset(mfd);
		if (rc) {
			pr_err("fail to reset display\n");
			mutex_unlock(&mdp3_res->fs_idle_pc_lock);
			return;
		}
	}
	mutex_unlock(&mdp3_res->fs_idle_pc_lock);

	mutex_lock(&mdp3_session->lock);

@@ -2493,17 +2549,21 @@ static int mdp3_ctrl_ioctl_handler(struct msm_fb_data_type *mfd,
		}
		break;
	case MSMFB_ASYNC_BLIT:
		mutex_lock(&mdp3_res->fs_idle_pc_lock);
		if (mdp3_session->in_splash_screen || mdp3_res->idle_pc) {
			pr_err("%s: reset- in_splash = %d, idle_pc = %d",
			pr_debug("%s: reset- in_splash = %d, idle_pc = %d",
				__func__, mdp3_session->in_splash_screen,
				mdp3_res->idle_pc);
			mdp3_ctrl_reset(mfd);
		}
		mutex_unlock(&mdp3_res->fs_idle_pc_lock);
		rc = mdp3_ctrl_async_blit_req(mfd, argp);
		break;
	case MSMFB_BLIT:
		mutex_lock(&mdp3_res->fs_idle_pc_lock);
		if (mdp3_session->in_splash_screen)
			mdp3_ctrl_reset(mfd);
		mutex_unlock(&mdp3_res->fs_idle_pc_lock);
		rc = mdp3_ctrl_blit_req(mfd, argp);
		break;
	case MSMFB_METADATA_GET:
+6 −1
Original line number Diff line number Diff line
@@ -153,6 +153,12 @@ void mdp3_dma_callback_disable(struct mdp3_dma *dma, int type)
			irq_bit = MDP3_INTR_SYNC_PRIMARY_LINE;
			irq_bit += dma->dma_sel;
			mdp3_irq_disable(irq_bit);
			/*
			 * Clear read pointer interrupt before disabling clocks.
			 * Else pending ISR handling will result in NOC error
			 * since the clock will be disable after this point.
			 */
			mdp3_clear_irq(irq_bit);
		}

		if (type & MDP3_DMA_CALLBACK_TYPE_DMA_DONE) {
@@ -721,7 +727,6 @@ retry_dma_done:
retry_vsync:
		rc = wait_for_completion_timeout(&dma->vsync_comp,
			KOFF_TIMEOUT);
		pr_err("%s VID DMA Buff Addr %pK\n", __func__, buf);
		if (rc <= 0 && --retry_count) {
			int vsync = MDP3_REG_READ(MDP3_REG_INTR_STATUS) &
					(1 << MDP3_INTR_LCDC_START_OF_FRAME);
+7 −3
Original line number Diff line number Diff line
@@ -530,6 +530,8 @@ int mdp3_calc_ppp_res(struct msm_fb_data_type *mfd,
	int i, lcount = 0;
	struct mdp_blit_req *req;
	struct bpp_info bpp;
	u64 old_solid_fill_pixel = 0;
	u64 new_solid_fill_pixel = 0;
	u64 src_read_bw = 0;
	u32 bg_read_bw = 0;
	u32 dst_write_bw = 0;
@@ -548,12 +550,14 @@ int mdp3_calc_ppp_res(struct msm_fb_data_type *mfd,
	if (lreq->req_list[0].flags & MDP_SOLID_FILL) {
		req = &(lreq->req_list[0]);
		mdp3_get_bpp_info(req->dst.format, &bpp);
		ppp_res.solid_fill_pixel += req->dst_rect.w * req->dst_rect.h;
		old_solid_fill_pixel = ppp_res.solid_fill_pixel;
		new_solid_fill_pixel = req->dst_rect.w * req->dst_rect.h;
		ppp_res.solid_fill_pixel += new_solid_fill_pixel;
		ppp_res.solid_fill_byte += req->dst_rect.w * req->dst_rect.h *
						bpp.bpp_num / bpp.bpp_den;
		if ((panel_info->yres/2 > req->dst_rect.h) ||
		if ((old_solid_fill_pixel >= new_solid_fill_pixel) ||
			(mdp3_res->solid_fill_vote_en)) {
			pr_debug("Solid fill less than H/2 or fill vote %d\n",
			pr_debug("Last fill pixels are higher or fill_en %d\n",
				mdp3_res->solid_fill_vote_en);
			ATRACE_END(__func__);
			return 0;
Loading