예제 #1
0
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;

	pr_debug("mdp3_ctrl_vsync_enable =%d\n", enable);
	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
	if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma ||
		!mdp3_session->intf)
		return -ENODEV;

	if (!mdp3_session->status) {
		pr_debug("fb%d is not on yet", mfd->index);
		return -EINVAL;
	}
	if (enable) {
		vsync_client.handler = vsync_notify_handler;
		vsync_client.arg = mdp3_session;
		arg = &vsync_client;
	} else if (atomic_read(&mdp3_session->vsync_countdown)) {
		/*
		 * Now that vsync is no longer needed we will
		 * shutdown dsi clocks as soon as cnt down == 0
		 * for cmd mode panels
		 */
		vsync_client.handler = vsync_count_down;
		vsync_client.arg = mdp3_session;
		arg = &vsync_client;
		enable = 1;
	}

	mdp3_clk_enable(1, 0);
	mdp3_session->dma->vsync_enable(mdp3_session->dma, arg);
	mdp3_clk_enable(0, 0);

	/*
	 * 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)) {
		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);
	}

	return 0;
}
예제 #2
0
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;

	pr_debug("mdp3_ctrl_vsync_enable =%d\n", enable);
	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
	if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma ||
		!mdp3_session->intf)
		return -ENODEV;

	if (!mdp3_session->status) {
		pr_debug("fb%d is not on yet", mfd->index);
		return -EINVAL;
	}
	if (enable) {
		vsync_client.handler = vsync_notify_handler;
		vsync_client.arg = mdp3_session;
		arg = &vsync_client;
	} else if (atomic_read(&mdp3_session->vsync_countdown)) {
		vsync_client.handler = vsync_count_down;
		vsync_client.arg = mdp3_session;
		arg = &vsync_client;
		enable = 1;
	}

	mdp3_clk_enable(1, 0);
	mdp3_session->dma->vsync_enable(mdp3_session->dma, arg);
	mdp3_clk_enable(0, 0);

	if (enable && mdp3_session->status == 1
			&& (mdp3_session->vsync_before_commit ||
			!mdp3_session->intf->active)) {
		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);
	}

	return 0;
}
예제 #3
0
static void mdp3_dispatch_clk_off(struct work_struct *work)
{
	struct mdp3_session_data *session;

	pr_debug("%s\n", __func__);
	session = container_of(work, struct mdp3_session_data,
				clk_off_work);
	if (!session)
		return;

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

	mdp3_ctrl_vsync_enable(session->mfd, 0);
	mdp3_ctrl_clk_enable(session->mfd, 0);
	mutex_unlock(&session->lock);
}
예제 #4
0
static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd,
					struct mdp_display_commit *cmt_data)
{
	struct mdp3_session_data *mdp3_session;
	struct mdp3_img_data *data;
	struct mdss_panel_info *panel_info;
	int rc = 0;
	bool reset_done = false;
	struct mdss_panel_data *panel;

	if (!mfd || !mfd->mdp.private1)
		return -EINVAL;

	panel_info = mfd->panel_info;
	mdp3_session = mfd->mdp.private1;
	if (!mdp3_session || !mdp3_session->dma)
		return -EINVAL;

	if (mdp3_bufq_count(&mdp3_session->bufq_in) == 0) {
		pr_debug("no buffer in queue yet\n");
		return -EPERM;
	}

	panel = mdp3_session->panel;
	if (mdp3_session->in_splash_screen) {
		pr_debug("continuous splash screen, IOMMU not attached\n");
		rc = mdp3_ctrl_reset(mfd);
		if (rc) {
			pr_err("fail to reset display\n");
			return -EINVAL;
		}
		reset_done = true;
	}

	mutex_lock(&mdp3_session->lock);

	if (!mdp3_session->status) {
		pr_err("%s, display off!\n", __func__);
		mutex_unlock(&mdp3_session->lock);
		return -EPERM;
	}

	mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_BEGIN);
	data = mdp3_bufq_pop(&mdp3_session->bufq_in);
	if (data) {
		mdp3_ctrl_reset_countdown(mdp3_session, mfd);
		mdp3_ctrl_clk_enable(mfd, 1);
		rc = mdp3_session->dma->update(mdp3_session->dma,
			(void *)(int)data->addr,
			mdp3_session->intf);
		/* This is for the previous frame */
		if (rc < 0) {
			mdp3_ctrl_notify(mdp3_session,
				MDP_NOTIFY_FRAME_TIMEOUT);
		} else {
			if (mdp3_ctrl_get_intf_type(mfd) ==
						MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) {
				mdp3_ctrl_notify(mdp3_session,
					MDP_NOTIFY_FRAME_DONE);
			}
		}
		mdp3_session->dma_active = 1;
		init_completion(&mdp3_session->dma_completion);
		mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
		mdp3_bufq_push(&mdp3_session->bufq_out, data);
	}

	if (mdp3_bufq_count(&mdp3_session->bufq_out) > 1) {
		mdp3_release_splash_memory(mfd);
		data = mdp3_bufq_pop(&mdp3_session->bufq_out);
		if (data)
			mdp3_put_img(data, MDP3_CLIENT_DMA_P);
	}

	if (mdp3_session->first_commit) {
		/*wait for one frame time to ensure frame is sent to panel*/
		msleep(1000 / panel_info->mipi.frame_rate);
		mdp3_session->first_commit = false;
	}

	mdp3_session->vsync_before_commit = 0;
	if (reset_done && (panel && panel->set_backlight))
		panel->set_backlight(panel, panel->panel_info.bl_max);

	mutex_unlock(&mdp3_session->lock);

	mdss_fb_update_notify_update(mfd);

	return 0;
}
예제 #5
0
static int mdp3_ctrl_off(struct msm_fb_data_type *mfd)
{
	int rc = 0;
	struct mdp3_session_data *mdp3_session;
	struct mdss_panel_data *panel;

	pr_debug("mdp3_ctrl_off\n");
	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
	if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma ||
		!mdp3_session->intf) {
		pr_err("mdp3_ctrl_on no device");
		return -ENODEV;
	}

	panel = mdp3_session->panel;
	mutex_lock(&mdp3_session->lock);

	if (panel && panel->set_backlight)
		panel->set_backlight(panel, 0);

	if (!mdp3_session->status) {
		pr_debug("fb%d is off already", mfd->index);
		goto off_error;
	}

	mdp3_ctrl_clk_enable(mfd, 1);

	mdp3_histogram_stop(mdp3_session, MDP_BLOCK_DMA_P);

	if (panel->event_handler)
		rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
	if (rc)
		pr_err("fail to turn off the panel\n");

	rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
	if (rc)
		pr_debug("fail to stop the MDP3 dma\n");
	/* Wait for TG to turn off */
	msleep(20);

	mdp3_irq_deregister();

	pr_debug("mdp3_ctrl_off stop clock\n");
	if (mdp3_session->clk_on) {
		rc = mdp3_res_update(0, 1, MDP3_CLIENT_DMA_P);
		if (rc)
			pr_err("mdp clock resource release failed\n");

		pr_debug("mdp3_ctrl_off stop dsi controller\n");
		if (panel->event_handler)
			rc = panel->event_handler(panel,
				MDSS_EVENT_BLANK, NULL);
		if (rc)
			pr_err("fail to turn off the panel\n");
	}

	mdp3_ctrl_notifier_unregister(mdp3_session,
		&mdp3_session->mfd->mdp_sync_pt_data.notifier);
	mdp3_enable_regulator(false);
	mdp3_session->vsync_enabled = 0;
	atomic_set(&mdp3_session->vsync_countdown, 0);
	atomic_set(&mdp3_session->dma_done_cnt, 0);
	mdp3_session->clk_on = 0;
	mdp3_session->in_splash_screen = 0;
off_error:
	mdp3_session->status = 0;
	mdp3_bufq_deinit(&mdp3_session->bufq_out);
	if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST) {
		mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
		mdp3_bufq_deinit(&mdp3_session->bufq_in);
	}
	mutex_unlock(&mdp3_session->lock);
	return 0;
}
예제 #6
0
static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd)
{
	struct fb_info *fbi;
	struct mdp3_session_data *mdp3_session;
	u32 offset;
	int bpp;
	struct mdss_panel_info *panel_info;
	int rc;

	pr_debug("mdp3_ctrl_pan_display\n");
	if (!mfd || !mfd->mdp.private1)
		return;

	panel_info = mfd->panel_info;
	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
	if (!mdp3_session || !mdp3_session->dma)
		return;

	if (mdp3_session->in_splash_screen) {
		pr_debug("continuous splash screen, IOMMU not attached\n");
		rc = mdp3_ctrl_reset(mfd);
		if (rc) {
			pr_err("fail to reset display\n");
			return;
		}
	}

	mutex_lock(&mdp3_session->lock);

	if (!mdp3_session->status) {
		pr_err("mdp3_ctrl_pan_display, display off!\n");
		goto pan_error;
	}

	fbi = mfd->fbi;

	bpp = fbi->var.bits_per_pixel / 8;
	offset = fbi->var.xoffset * bpp +
		 fbi->var.yoffset * fbi->fix.line_length;

	if (offset > fbi->fix.smem_len) {
		pr_err("invalid fb offset=%u total length=%u\n",
			offset, fbi->fix.smem_len);
		goto pan_error;
	}

	if (mfd->fbi->screen_base) {
		mdp3_ctrl_reset_countdown(mdp3_session, mfd);
		mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_BEGIN);
		mdp3_ctrl_clk_enable(mfd, 1);
		rc = mdp3_session->dma->update(mdp3_session->dma,
				(void *)(int)(mfd->iova + offset),
				mdp3_session->intf);
		/* This is for the previous frame */
		if (rc < 0) {
			mdp3_ctrl_notify(mdp3_session,
				MDP_NOTIFY_FRAME_TIMEOUT);
		} else {
			if (mdp3_ctrl_get_intf_type(mfd) ==
						MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) {
				mdp3_ctrl_notify(mdp3_session,
					MDP_NOTIFY_FRAME_DONE);
			}
		}
		mdp3_session->dma_active = 1;
		init_completion(&mdp3_session->dma_completion);
		mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_FLUSHED);
	} else {
		pr_debug("mdp3_ctrl_pan_display no memory, stop interface");
		mdp3_clk_enable(1, 0);
		mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
		mdp3_clk_enable(0, 0);
	}

	if (mdp3_session->first_commit) {
		/*wait for one frame time to ensure frame is sent to panel*/
		msleep(1000 / panel_info->mipi.frame_rate);
		mdp3_session->first_commit = false;
	}

	mdp3_session->vsync_before_commit = 0;

pan_error:
	mutex_unlock(&mdp3_session->lock);
}
static int mdp3_ctrl_off(struct msm_fb_data_type *mfd)
{
	int rc = 0;
	struct mdp3_session_data *mdp3_session;
	struct mdss_panel_data *panel;

	pr_debug("mdp3_ctrl_off\n");
	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
	if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma ||
		!mdp3_session->intf) {
		pr_err("mdp3_ctrl_on no device");
		return -ENODEV;
	}

	panel = mdp3_session->panel;
	mutex_lock(&mdp3_session->lock);

	if (!mdp3_session->status) {
		pr_debug("fb%d is off already", mfd->index);
		goto off_error;
	}

	mdp3_ctrl_clk_enable(mfd, 1);

	mdp3_histogram_stop(mdp3_session, MDP_BLOCK_DMA_P);

	rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
	if (rc)
		pr_debug("fail to stop the MDP3 dma\n");


	if (panel->event_handler)
		rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
	if (rc)
		pr_err("fail to turn off the panel\n");

	mdp3_irq_deregister();

	pr_debug("mdp3_ctrl_off stop clock\n");
	if (mdp3_session->clk_on) {
		rc = mdp3_clk_enable(0, 1);
		if (rc)
			pr_err("mdp clock resource release failed\n");

		pr_debug("mdp3_ctrl_off stop dsi controller\n");
		if (panel->event_handler)
			rc = panel->event_handler(panel,
				MDSS_EVENT_BLANK, NULL);
		if (rc)
			pr_err("fail to turn off the panel\n");
	}
	mdp3_clk_unprepare();

	pr_debug("mdp3_ctrl_off release bus\n");
	rc = mdp3_ctrl_res_req_bus(mfd, 0);
	if (rc)
		pr_err("mdp bus resource release failed\n");

	rc = mdp3_iommu_disable(MDP3_CLIENT_DMA_P);
	if (rc)
		pr_err("fail to dettach MDP DMA SMMU\n");

	mdp3_ctrl_notifier_unregister(mdp3_session,
		&mdp3_session->mfd->mdp_sync_pt_data.notifier);
	mdp3_batfet_ctrl(false);
	mdp3_session->vsync_enabled = 0;
	atomic_set(&mdp3_session->vsync_countdown, 0);
	mdp3_session->clk_on = 0;
off_error:
	mdp3_session->status = 0;
	mdp3_bufq_deinit(&mdp3_session->bufq_out);
	mutex_unlock(&mdp3_session->lock);
	if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST)
		mdp3_overlay_unset(mfd, mdp3_session->overlay.id);
	return 0;
}
예제 #8
0
static int mdp3_ctrl_display_commit_kickoff(struct msm_fb_data_type *mfd,
					struct mdp_display_commit *cmt_data)
{
	struct mdp3_session_data *mdp3_session;
	struct mdp3_img_data *data;
	struct mdss_panel_info *panel_info = mfd->panel_info;
	int rc = 0;
	bool reset_done = false;
	struct mdss_panel_data *panel;

	if (!mfd || !mfd->mdp.private1)
		return -EINVAL;

	mdp3_session = mfd->mdp.private1;
	if (!mdp3_session || !mdp3_session->dma)
		return -EINVAL;

	if (mdp3_bufq_count(&mdp3_session->bufq_in) == 0) {
		pr_debug("no buffer in queue yet\n");
		return -EPERM;
	}

	panel = mdp3_session->panel;
	if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
		pr_debug("continuous splash screen, IOMMU not attached\n");
		mdp3_ctrl_reset(mfd);
		reset_done = true;
	}
	mdp3_release_splash_memory();

	mutex_lock(&mdp3_session->lock);

	if (!mdp3_session->status) {
		pr_err("%s, display off!\n", __func__);
		mutex_unlock(&mdp3_session->lock);
		return -EPERM;
	}

	data = mdp3_bufq_pop(&mdp3_session->bufq_in);
	if (data) {
		mdp3_ctrl_reset_countdown(mdp3_session, mfd);
		mdp3_ctrl_clk_enable(mfd, 1);
		mdp3_session->dma->update(mdp3_session->dma,
			(void *)data->addr,
			mdp3_session->intf);
		mdp3_bufq_push(&mdp3_session->bufq_out, data);
	}

	if (mdp3_bufq_count(&mdp3_session->bufq_out) > 2) {
		data = mdp3_bufq_pop(&mdp3_session->bufq_out);
		mdp3_put_img(data, MDP3_CLIENT_DMA_P);
	}

	if (mdp3_session->first_commit) {
		/*wait for one frame time to ensure frame is sent to panel*/
		msleep(1000 / panel_info->mipi.frame_rate);
		mdp3_session->first_commit = false;
	}

        mdp3_session->vsync_before_commit = 0;
	if (reset_done && (panel && panel->set_backlight)){
#if defined(CONFIG_FB_MSM_MIPI_TIANMA_CMD_HVGA_PT)
        msleep(1);
#endif
		panel->set_backlight(panel, panel->panel_info.bl_max);
	}

	mutex_unlock(&mdp3_session->lock);

	mdss_fb_update_notify_update(mfd);

	return rc;
}
예제 #9
0
static void mdp3_ctrl_pan_display(struct msm_fb_data_type *mfd)
{
	struct fb_info *fbi;
	struct mdp3_session_data *mdp3_session;
	u32 offset;
	int bpp;
	struct mdss_panel_info *panel_info = mfd->panel_info;
#if defined(CONFIG_FB_MSM_MIPI_TIANMA_CMD_HVGA_PT) || defined(CONFIG_MACH_MSM8X10_W5) || defined(CONFIG_MACH_MSM8X10_W6)
	bool reset_done = false;
	struct mdss_panel_data *panel;
#endif

	pr_debug("mdp3_ctrl_pan_display\n");
	if (!mfd || !mfd->mdp.private1)
		return;

	mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
	if (!mdp3_session || !mdp3_session->dma)
		return;

#if defined(CONFIG_FB_MSM_MIPI_TIANMA_CMD_HVGA_PT) || defined(CONFIG_MACH_MSM8X10_W5) || defined(CONFIG_MACH_MSM8X10_W6)
	panel = mdp3_session->panel;
#endif
	if (!mdp3_iommu_is_attached(MDP3_CLIENT_DMA_P)) {
		pr_debug("continuous splash screen, IOMMU not attached\n");
		mdp3_ctrl_reset(mfd);
#if defined(CONFIG_FB_MSM_MIPI_TIANMA_CMD_HVGA_PT) || defined(CONFIG_MACH_MSM8X10_W5) || defined(CONFIG_MACH_MSM8X10_W6)
		reset_done = true;
#endif
	}
	mdp3_release_splash_memory();

	mutex_lock(&mdp3_session->lock);

	if (!mdp3_session->status) {
		pr_err("mdp3_ctrl_pan_display, display off!\n");
		goto pan_error;
	}

	fbi = mfd->fbi;

	bpp = fbi->var.bits_per_pixel / 8;
	offset = fbi->var.xoffset * bpp +
		 fbi->var.yoffset * fbi->fix.line_length;

	if (offset > fbi->fix.smem_len) {
		pr_err("invalid fb offset=%u total length=%u\n",
			offset, fbi->fix.smem_len);
		goto pan_error;
	}

	if (mfd->fbi->screen_base) {
		mdp3_ctrl_reset_countdown(mdp3_session, mfd);
		mdp3_ctrl_clk_enable(mfd, 1);
		mdp3_session->dma->update(mdp3_session->dma,
				(void *)mfd->iova + offset,
				mdp3_session->intf);
	} else {
		pr_debug("mdp3_ctrl_pan_display no memory, stop interface");
		mdp3_clk_enable(1, 0);
		mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
		mdp3_clk_enable(0, 0);
	}

	if (mdp3_session->first_commit) {
		/*wait for one frame time to ensure frame is sent to panel*/
		msleep(1000 / panel_info->mipi.frame_rate);
		mdp3_session->first_commit = false;
	}
#if defined(CONFIG_FB_MSM_MIPI_TIANMA_CMD_HVGA_PT) || defined(CONFIG_MACH_MSM8X10_W5) || defined(CONFIG_MACH_MSM8X10_W6)
	if (reset_done && (panel && panel->set_backlight)){
		panel->set_backlight(panel, panel->panel_info.bl_max);
    }
#endif

	mdp3_session->vsync_before_commit = 0;

pan_error:
	mutex_unlock(&mdp3_session->lock);
}