diff mbox

[v2,12/12] JUST FOR TEST: Add one-shot trigger to update display

Message ID 1435738915-31973-13-git-send-email-markz@nvidia.com
State Rejected, archived
Headers show

Commit Message

Mark Zhang July 1, 2015, 8:21 a.m. UTC
This HACK adds a workqueue to refresh the display periodically.
This is used just for testing.

Signed-off-by: Mark Zhang <markz@nvidia.com>
---
 drivers/gpu/drm/tegra/dc.c  |   37 +++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/tegra/drm.h |    1 +
 2 files changed, 38 insertions(+)

Comments

Daniel Vetter July 1, 2015, 8:36 a.m. UTC | #1
On Wed, Jul 01, 2015 at 04:21:55PM +0800, Mark Zhang wrote:
> This HACK adds a workqueue to refresh the display periodically.
> This is used just for testing.

->dirty is the drm hook you're looking for, it's meant to flush out any
frontbuffer rendering. Generic kms clients using the dumb buffers (e.g.
fedora boot splash) use this already.

And of course you need to upload a new frame every time an (atomic) flip
happens too, but I guess you have that already. No need at all for a
periodic upload hack like this.

Cheers, Daniel

> 
> Signed-off-by: Mark Zhang <markz@nvidia.com>
> ---
>  drivers/gpu/drm/tegra/dc.c  |   37 +++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/tegra/drm.h |    1 +
>  2 files changed, 38 insertions(+)
> 
> diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
> index 24a91613c4f5..4381691c73f7 100644
> --- a/drivers/gpu/drm/tegra/dc.c
> +++ b/drivers/gpu/drm/tegra/dc.c
> @@ -1296,6 +1296,8 @@ static void tegra_crtc_mode_set_nofb(struct drm_crtc *crtc)
>  		value &= ~DISP_CTRL_MODE_MASK;
>  		value |= DISP_CTRL_MODE_NC_DISPLAY;
>  		tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
> +
> +		schedule_work(&dc->one_shot_trigger);
>  	} else {
>  		value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
>  		value &= ~DISP_CTRL_MODE_MASK;
> @@ -1958,6 +1960,40 @@ static void tegra_dc_one_shot_work(struct work_struct *work)
>  	drm_modeset_unlock_all(drm);
>  }
>  
> +static void tegra_dc_one_shot_trigger(struct work_struct *work)
> +{
> +	struct tegra_dc *dc;
> +	struct drm_connector *connector;
> +	struct drm_device *drm;
> +	unsigned long update_mask = GENERAL_ACT_REQ | NC_HOST_TRIG;
> +	static int first_trigger = 1;
> +
> +	dc = container_of(work, struct tegra_dc, one_shot_trigger);
> +	drm = dc->base.dev;
> +	msleep(5000);
> +
> +	if (first_trigger) {
> +		dev_info(dc->dev, "First one-shot triggered.\n");
> +		tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL);
> +		first_trigger = 0;
> +		schedule_work(&dc->one_shot_trigger);
> +		return;
> +	}
> +
> +	dev_info(dc->dev, "one-shot: Wakeup dc/dsi/panel.\n");
> +	drm_modeset_lock_all(drm);
> +	list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
> +		if (connector->funcs->dpms)
> +			connector->funcs->dpms(connector,
> +						DRM_MODE_DPMS_STANDBY);
> +	}
> +	drm_modeset_unlock_all(drm);
> +
> +	/* Trigger the one-shot */
> +	tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL);
> +	schedule_work(&dc->one_shot_trigger);
> +}
> +
>  static int tegra_dc_probe(struct platform_device *pdev)
>  {
>  	unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;
> @@ -1977,6 +2013,7 @@ static int tegra_dc_probe(struct platform_device *pdev)
>  	spin_lock_init(&dc->lock);
>  	INIT_LIST_HEAD(&dc->list);
>  	INIT_WORK(&dc->one_shot_work, tegra_dc_one_shot_work);
> +	INIT_WORK(&dc->one_shot_trigger, tegra_dc_one_shot_trigger);
>  	dc->dev = &pdev->dev;
>  	dc->soc = id->data;
>  
> diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
> index 00daf427c831..5d606cacb098 100644
> --- a/drivers/gpu/drm/tegra/drm.h
> +++ b/drivers/gpu/drm/tegra/drm.h
> @@ -132,6 +132,7 @@ struct tegra_dc {
>  	struct drm_pending_vblank_event *event;
>  
>  	struct work_struct one_shot_work;
> +	struct work_struct one_shot_trigger;
>  
>  	const struct tegra_dc_soc_info *soc;
>  
> -- 
> 1.7.9.5
>
Daniel Vetter July 1, 2015, 8:46 a.m. UTC | #2
On Wed, Jul 01, 2015 at 10:36:17AM +0200, Daniel Vetter wrote:
> On Wed, Jul 01, 2015 at 04:21:55PM +0800, Mark Zhang wrote:
> > This HACK adds a workqueue to refresh the display periodically.
> > This is used just for testing.
> 
> ->dirty is the drm hook you're looking for, it's meant to flush out any
> frontbuffer rendering. Generic kms clients using the dumb buffers (e.g.
> fedora boot splash) use this already.
> 
> And of course you need to upload a new frame every time an (atomic) flip
> happens too, but I guess you have that already. No need at all for a
> periodic upload hack like this.

btw the nice thing with dirty is that it hands you the exact invalidation
rectangle, which means you can minimize uploads. For atomic flips we plan
to have the same, but it's not implemented yet.

Another problem is that currently the fbdev helper in drm_fb_helper.c
doesn't support the dirty callback. But there's other drivers which need
this too (e.g. i915 will gain a dirty callback soon) and qxl has all the
code implemented already. So the only thing you need to do is move the qxl
code into drm_fb_helper.c and adapt it to use the dirty callback instead
of directly calling qxl code. Then you should be all set. Note that simply
calling ->dirty from fbdev hooks doesn't work since a lot of those hooks
are called from irq context (cursors and stuff) and hence you need a
workqueue to do the actual dirty call.

Cheers, Daniel
Mark Zhang July 1, 2015, 9:01 a.m. UTC | #3
On 07/01/2015 04:36 PM, Daniel Vetter wrote:
> On Wed, Jul 01, 2015 at 04:21:55PM +0800, Mark Zhang wrote:
>> This HACK adds a workqueue to refresh the display periodically.
>> This is used just for testing.
> 
> ->dirty is the drm hook you're looking for, it's meant to flush out any
> frontbuffer rendering. Generic kms clients using the dumb buffers (e.g.
> fedora boot splash) use this already.
> 

Oh... I did a grep in drm source and are you talking about
"drm_framebuffer_funcs->dirty"? Yeah, that should work for me.. but that
requires userspace sending IOCTL to trigger, right? Honestly I'm lazy so
I created this HACK so that I don't need userspace to test.

> And of course you need to upload a new frame every time an (atomic) flip
> happens too, but I guess you have that already. No need at all for a
> periodic upload hack like this.
> 

Yep. Thanks Daniel.

Mark
> Cheers, Daniel
> 
>>
>> Signed-off-by: Mark Zhang <markz@nvidia.com>
>> ---
>>  drivers/gpu/drm/tegra/dc.c  |   37 +++++++++++++++++++++++++++++++++++++
>>  drivers/gpu/drm/tegra/drm.h |    1 +
>>  2 files changed, 38 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
>> index 24a91613c4f5..4381691c73f7 100644
>> --- a/drivers/gpu/drm/tegra/dc.c
>> +++ b/drivers/gpu/drm/tegra/dc.c
>> @@ -1296,6 +1296,8 @@ static void tegra_crtc_mode_set_nofb(struct drm_crtc *crtc)
>>  		value &= ~DISP_CTRL_MODE_MASK;
>>  		value |= DISP_CTRL_MODE_NC_DISPLAY;
>>  		tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
>> +
>> +		schedule_work(&dc->one_shot_trigger);
>>  	} else {
>>  		value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
>>  		value &= ~DISP_CTRL_MODE_MASK;
>> @@ -1958,6 +1960,40 @@ static void tegra_dc_one_shot_work(struct work_struct *work)
>>  	drm_modeset_unlock_all(drm);
>>  }
>>  
>> +static void tegra_dc_one_shot_trigger(struct work_struct *work)
>> +{
>> +	struct tegra_dc *dc;
>> +	struct drm_connector *connector;
>> +	struct drm_device *drm;
>> +	unsigned long update_mask = GENERAL_ACT_REQ | NC_HOST_TRIG;
>> +	static int first_trigger = 1;
>> +
>> +	dc = container_of(work, struct tegra_dc, one_shot_trigger);
>> +	drm = dc->base.dev;
>> +	msleep(5000);
>> +
>> +	if (first_trigger) {
>> +		dev_info(dc->dev, "First one-shot triggered.\n");
>> +		tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL);
>> +		first_trigger = 0;
>> +		schedule_work(&dc->one_shot_trigger);
>> +		return;
>> +	}
>> +
>> +	dev_info(dc->dev, "one-shot: Wakeup dc/dsi/panel.\n");
>> +	drm_modeset_lock_all(drm);
>> +	list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
>> +		if (connector->funcs->dpms)
>> +			connector->funcs->dpms(connector,
>> +						DRM_MODE_DPMS_STANDBY);
>> +	}
>> +	drm_modeset_unlock_all(drm);
>> +
>> +	/* Trigger the one-shot */
>> +	tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL);
>> +	schedule_work(&dc->one_shot_trigger);
>> +}
>> +
>>  static int tegra_dc_probe(struct platform_device *pdev)
>>  {
>>  	unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;
>> @@ -1977,6 +2013,7 @@ static int tegra_dc_probe(struct platform_device *pdev)
>>  	spin_lock_init(&dc->lock);
>>  	INIT_LIST_HEAD(&dc->list);
>>  	INIT_WORK(&dc->one_shot_work, tegra_dc_one_shot_work);
>> +	INIT_WORK(&dc->one_shot_trigger, tegra_dc_one_shot_trigger);
>>  	dc->dev = &pdev->dev;
>>  	dc->soc = id->data;
>>  
>> diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
>> index 00daf427c831..5d606cacb098 100644
>> --- a/drivers/gpu/drm/tegra/drm.h
>> +++ b/drivers/gpu/drm/tegra/drm.h
>> @@ -132,6 +132,7 @@ struct tegra_dc {
>>  	struct drm_pending_vblank_event *event;
>>  
>>  	struct work_struct one_shot_work;
>> +	struct work_struct one_shot_trigger;
>>  
>>  	const struct tegra_dc_soc_info *soc;
>>  
>> -- 
>> 1.7.9.5
>>
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Daniel Vetter July 1, 2015, 10:34 a.m. UTC | #4
On Wed, Jul 01, 2015 at 05:01:52PM +0800, Mark Zhang wrote:
> On 07/01/2015 04:36 PM, Daniel Vetter wrote:
> > On Wed, Jul 01, 2015 at 04:21:55PM +0800, Mark Zhang wrote:
> >> This HACK adds a workqueue to refresh the display periodically.
> >> This is used just for testing.
> > 
> > ->dirty is the drm hook you're looking for, it's meant to flush out any
> > frontbuffer rendering. Generic kms clients using the dumb buffers (e.g.
> > fedora boot splash) use this already.
> > 
> 
> Oh... I did a grep in drm source and are you talking about
> "drm_framebuffer_funcs->dirty"? Yeah, that should work for me.. but that
> requires userspace sending IOCTL to trigger, right? Honestly I'm lazy so
> I created this HACK so that I don't need userspace to test.

Yeah userspace needs to send ioctl already after each drawing. Generic
userspace does that already since it's required by qxl, udl, soon i915 and
probably a few others too. fbdev emulation is more annyoing but there's
code to move around in these drivers (qxl seems best to me as a starting
point) too.

Imo without this you shouldn't merge one-shot, at least not enabled by
default.
-Daniel
Mark Zhang July 1, 2015, 12:43 p.m. UTC | #5
On 07/01/2015 06:34 PM, Daniel Vetter wrote:
> On Wed, Jul 01, 2015 at 05:01:52PM +0800, Mark Zhang wrote:
>> On 07/01/2015 04:36 PM, Daniel Vetter wrote:
>>> On Wed, Jul 01, 2015 at 04:21:55PM +0800, Mark Zhang wrote:
>>>> This HACK adds a workqueue to refresh the display periodically.
>>>> This is used just for testing.
>>>
>>> ->dirty is the drm hook you're looking for, it's meant to flush out any
>>> frontbuffer rendering. Generic kms clients using the dumb buffers (e.g.
>>> fedora boot splash) use this already.
>>>
>>
>> Oh... I did a grep in drm source and are you talking about
>> "drm_framebuffer_funcs->dirty"? Yeah, that should work for me.. but that
>> requires userspace sending IOCTL to trigger, right? Honestly I'm lazy so
>> I created this HACK so that I don't need userspace to test.
> 
> Yeah userspace needs to send ioctl already after each drawing. Generic
> userspace does that already since it's required by qxl, udl, soon i915 and
> probably a few others too. fbdev emulation is more annyoing but there's
> code to move around in these drivers (qxl seems best to me as a starting
> point) too.
> 

Alright, this makes sense. I have no idea about qxl, what I have now is
an ubuntu running on Tegra114. So I'm wondering what I suppose to do is
installing qemu on the ubuntu?

Mark

> Imo without this you shouldn't merge one-shot, at least not enabled by
> default.
> -Daniel
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mark Zhang July 1, 2015, 12:51 p.m. UTC | #6
On 07/01/2015 04:46 PM, Daniel Vetter wrote:
> On Wed, Jul 01, 2015 at 10:36:17AM +0200, Daniel Vetter wrote:
>> On Wed, Jul 01, 2015 at 04:21:55PM +0800, Mark Zhang wrote:
>>> This HACK adds a workqueue to refresh the display periodically.
>>> This is used just for testing.
>>
>> ->dirty is the drm hook you're looking for, it's meant to flush out any
>> frontbuffer rendering. Generic kms clients using the dumb buffers (e.g.
>> fedora boot splash) use this already.
>>
>> And of course you need to upload a new frame every time an (atomic) flip
>> happens too, but I guess you have that already. No need at all for a
>> periodic upload hack like this.
> 
> btw the nice thing with dirty is that it hands you the exact invalidation
> rectangle, which means you can minimize uploads. For atomic flips we plan
> to have the same, but it's not implemented yet.
> 
> Another problem is that currently the fbdev helper in drm_fb_helper.c
> doesn't support the dirty callback. But there's other drivers which need
> this too (e.g. i915 will gain a dirty callback soon) and qxl has all the
> code implemented already. So the only thing you need to do is move the qxl
> code into drm_fb_helper.c and adapt it to use the dirty callback instead
> of directly calling qxl code. Then you should be all set. Note that simply
> calling ->dirty from fbdev hooks doesn't work since a lot of those hooks
> are called from irq context (cursors and stuff) and hence you need a
> workqueue to do the actual dirty call.
> 

I got it. So this is the kernel part I need. Thanks.

Mark
> Cheers, Daniel
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Daniel Vetter July 1, 2015, 2:55 p.m. UTC | #7
On Wed, Jul 01, 2015 at 08:43:01PM +0800, Mark Zhang wrote:
> On 07/01/2015 06:34 PM, Daniel Vetter wrote:
> > On Wed, Jul 01, 2015 at 05:01:52PM +0800, Mark Zhang wrote:
> >> On 07/01/2015 04:36 PM, Daniel Vetter wrote:
> >>> On Wed, Jul 01, 2015 at 04:21:55PM +0800, Mark Zhang wrote:
> >>>> This HACK adds a workqueue to refresh the display periodically.
> >>>> This is used just for testing.
> >>>
> >>> ->dirty is the drm hook you're looking for, it's meant to flush out any
> >>> frontbuffer rendering. Generic kms clients using the dumb buffers (e.g.
> >>> fedora boot splash) use this already.
> >>>
> >>
> >> Oh... I did a grep in drm source and are you talking about
> >> "drm_framebuffer_funcs->dirty"? Yeah, that should work for me.. but that
> >> requires userspace sending IOCTL to trigger, right? Honestly I'm lazy so
> >> I created this HACK so that I don't need userspace to test.
> > 
> > Yeah userspace needs to send ioctl already after each drawing. Generic
> > userspace does that already since it's required by qxl, udl, soon i915 and
> > probably a few others too. fbdev emulation is more annyoing but there's
> > code to move around in these drivers (qxl seems best to me as a starting
> > point) too.
> > 
> 
> Alright, this makes sense. I have no idea about qxl, what I have now is
> an ubuntu running on Tegra114. So I'm wondering what I suppose to do is
> installing qemu on the ubuntu?

My suggestion is just to take the qxl code, move it to the fbdev emulation
helper, make it generic and use it. If you want you can do a
compile-tested patch on top to switch qxl over to the newly added helpers.
No need to install/run qxl itself. Just that qxl seems to have the most
complete solution for what you need.
-Daniel
Mark Zhang July 3, 2015, 7:57 a.m. UTC | #8
On 07/01/2015 10:55 PM, Daniel Vetter wrote:
> On Wed, Jul 01, 2015 at 08:43:01PM +0800, Mark Zhang wrote:
>> On 07/01/2015 06:34 PM, Daniel Vetter wrote:
[...]
>>>
>>
>> Alright, this makes sense. I have no idea about qxl, what I have now is
>> an ubuntu running on Tegra114. So I'm wondering what I suppose to do is
>> installing qemu on the ubuntu?
> 
> My suggestion is just to take the qxl code, move it to the fbdev emulation
> helper, make it generic and use it. If you want you can do a
> compile-tested patch on top to switch qxl over to the newly added helpers.
> No need to install/run qxl itself. Just that qxl seems to have the most
> complete solution for what you need.

OK, thanks Daniel. I'm not quite familiar with the userspace, but I
think this is the summary:

- For legacy FB support, we can use the "->dirty" fops, port the qxl
codes to drm_fb_helper.c, just as you described.
- For atomic page flip, the one-shot can be triggered when flipping the
window/plane.
- How about the front buffer rendering/drawing? I mean, if a drm
userspace app requests a dumb buffer then draws on it, how can we
trigger the one-shot to update the display? Do we need to add an
additional IOCTL to do that?

Mark
> -Daniel
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Daniel Vetter July 3, 2015, 8:03 a.m. UTC | #9
On Fri, Jul 03, 2015 at 03:57:55PM +0800, Mark Zhang wrote:
> On 07/01/2015 10:55 PM, Daniel Vetter wrote:
> > On Wed, Jul 01, 2015 at 08:43:01PM +0800, Mark Zhang wrote:
> >> On 07/01/2015 06:34 PM, Daniel Vetter wrote:
> [...]
> >>>
> >>
> >> Alright, this makes sense. I have no idea about qxl, what I have now is
> >> an ubuntu running on Tegra114. So I'm wondering what I suppose to do is
> >> installing qemu on the ubuntu?
> > 
> > My suggestion is just to take the qxl code, move it to the fbdev emulation
> > helper, make it generic and use it. If you want you can do a
> > compile-tested patch on top to switch qxl over to the newly added helpers.
> > No need to install/run qxl itself. Just that qxl seems to have the most
> > complete solution for what you need.
> 
> OK, thanks Daniel. I'm not quite familiar with the userspace, but I
> think this is the summary:
> 
> - For legacy FB support, we can use the "->dirty" fops, port the qxl
> codes to drm_fb_helper.c, just as you described.

Note that this is for legacy frontbuffer rendering only. All other screen
updates (setplane, setcrtc, pageflip) will go through the atomic flip
path, thanks to all the atomic helpers.

> - For atomic page flip, the one-shot can be triggered when flipping the
> window/plane.
> - How about the front buffer rendering/drawing? I mean, if a drm
> userspace app requests a dumb buffer then draws on it, how can we
> trigger the one-shot to update the display? Do we need to add an
> additional IOCTL to do that?

dumb buffer userspace is required to call dirtyfb ioctl.
-Daniel
Mark Zhang July 3, 2015, 8:05 a.m. UTC | #10
Oh.. understood. Thanks.

Mark
On 07/03/2015 04:03 PM, Daniel Vetter wrote:
> On Fri, Jul 03, 2015 at 03:57:55PM +0800, Mark Zhang wrote:
>> On 07/01/2015 10:55 PM, Daniel Vetter wrote:
>>> On Wed, Jul 01, 2015 at 08:43:01PM +0800, Mark Zhang wrote:
>>>> On 07/01/2015 06:34 PM, Daniel Vetter wrote:
>> [...]
>>>>>
>>>>
>>>> Alright, this makes sense. I have no idea about qxl, what I have now is
>>>> an ubuntu running on Tegra114. So I'm wondering what I suppose to do is
>>>> installing qemu on the ubuntu?
>>>
>>> My suggestion is just to take the qxl code, move it to the fbdev emulation
>>> helper, make it generic and use it. If you want you can do a
>>> compile-tested patch on top to switch qxl over to the newly added helpers.
>>> No need to install/run qxl itself. Just that qxl seems to have the most
>>> complete solution for what you need.
>>
>> OK, thanks Daniel. I'm not quite familiar with the userspace, but I
>> think this is the summary:
>>
>> - For legacy FB support, we can use the "->dirty" fops, port the qxl
>> codes to drm_fb_helper.c, just as you described.
> 
> Note that this is for legacy frontbuffer rendering only. All other screen
> updates (setplane, setcrtc, pageflip) will go through the atomic flip
> path, thanks to all the atomic helpers.
> 
>> - For atomic page flip, the one-shot can be triggered when flipping the
>> window/plane.
>> - How about the front buffer rendering/drawing? I mean, if a drm
>> userspace app requests a dumb buffer then draws on it, how can we
>> trigger the one-shot to update the display? Do we need to add an
>> additional IOCTL to do that?
> 
> dumb buffer userspace is required to call dirtyfb ioctl.
> -Daniel
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 24a91613c4f5..4381691c73f7 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -1296,6 +1296,8 @@  static void tegra_crtc_mode_set_nofb(struct drm_crtc *crtc)
 		value &= ~DISP_CTRL_MODE_MASK;
 		value |= DISP_CTRL_MODE_NC_DISPLAY;
 		tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
+
+		schedule_work(&dc->one_shot_trigger);
 	} else {
 		value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
 		value &= ~DISP_CTRL_MODE_MASK;
@@ -1958,6 +1960,40 @@  static void tegra_dc_one_shot_work(struct work_struct *work)
 	drm_modeset_unlock_all(drm);
 }
 
+static void tegra_dc_one_shot_trigger(struct work_struct *work)
+{
+	struct tegra_dc *dc;
+	struct drm_connector *connector;
+	struct drm_device *drm;
+	unsigned long update_mask = GENERAL_ACT_REQ | NC_HOST_TRIG;
+	static int first_trigger = 1;
+
+	dc = container_of(work, struct tegra_dc, one_shot_trigger);
+	drm = dc->base.dev;
+	msleep(5000);
+
+	if (first_trigger) {
+		dev_info(dc->dev, "First one-shot triggered.\n");
+		tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL);
+		first_trigger = 0;
+		schedule_work(&dc->one_shot_trigger);
+		return;
+	}
+
+	dev_info(dc->dev, "one-shot: Wakeup dc/dsi/panel.\n");
+	drm_modeset_lock_all(drm);
+	list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
+		if (connector->funcs->dpms)
+			connector->funcs->dpms(connector,
+						DRM_MODE_DPMS_STANDBY);
+	}
+	drm_modeset_unlock_all(drm);
+
+	/* Trigger the one-shot */
+	tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL);
+	schedule_work(&dc->one_shot_trigger);
+}
+
 static int tegra_dc_probe(struct platform_device *pdev)
 {
 	unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;
@@ -1977,6 +2013,7 @@  static int tegra_dc_probe(struct platform_device *pdev)
 	spin_lock_init(&dc->lock);
 	INIT_LIST_HEAD(&dc->list);
 	INIT_WORK(&dc->one_shot_work, tegra_dc_one_shot_work);
+	INIT_WORK(&dc->one_shot_trigger, tegra_dc_one_shot_trigger);
 	dc->dev = &pdev->dev;
 	dc->soc = id->data;
 
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index 00daf427c831..5d606cacb098 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -132,6 +132,7 @@  struct tegra_dc {
 	struct drm_pending_vblank_event *event;
 
 	struct work_struct one_shot_work;
+	struct work_struct one_shot_trigger;
 
 	const struct tegra_dc_soc_info *soc;