[RFC PATCH 3/9] drm/rockchip: Convert to support atomic API

2015-12-11 Thread Mark yao
On 2015年12月02日 22:18, Daniel Stone wrote:
> Hi Mark,
> Thanks for getting back to this.
>
> On 1 December 2015 at 09:31, Mark yao  wrote:
>> On 2015年12月01日 16:18, Daniel Stone wrote:
>>> On 1 December 2015 at 03:26, Mark Yao  wrote:
> +   for_each_crtc_in_state(state, crtc, crtc_state, i) {
> +   if (!crtc->state->active)
> +   continue;
> +
> +   rockchip_crtc_wait_for_update(crtc);
> +   }
>>> I'd be much more comfortable if this passed in an explicit pointer to
>>> state, or an address to wait for, rather than have wait_for_complete
>>> dig out state with no locking. The latter is potentially racy for
>>> async operations.
>>>
>> Hi Daniel
>> "if this passed in an explicit pointer to state, or an address to wait
>> for", I don't understand, can you point how it work?
> Ah, OK. I mean that rockchip_crtc_wait_for_update takes a drm_crtc
> pointer, and establishes the state from that (e.g.
> crtc->primary->state). This can easily lead to confusion in async
> contexts, as the states attached to a drm_crtc and a drm_plane can
> change here while you wait for it.
>
> It would be better if the call was:
>
> for_each_plane_in_state(state, plane, plane_state, i) {
>  if (plane->type == DRM_PLANE_TYPE_PRIMARY)
>  rockchip_crtc_wait_for_update(plane_state->crtc, plane_state);
> }
>
> This way it is very clear, and there is no confusion as to which
> request we are waiting to complete.
>
> In general, using crtc->state or plane->state is a very bad idea,
> _except_ in the atomic_check function where you are calculating
> changes (e.g. if (plane_state->fb->pitches[0] !=
> plane->state->fb->pitches[0]) rockchip_plane_state->pitch_changed =
> true). After atomic_check, you should always pass around pointers to
> the plane state explicitly, and avoid using the pointers from drm_crtc
> and drm_plane.
>
> Does that help?

Hi Daniel

Sorry, I don't actually understand why crtc->state or plane->state is no 
recommended
except atomic_check, on atomic_update, we need use plane->state, is that 
a problem?

I guess that, drm_atomic_helper_swap_state would race with async operations,
so use crtc->state on async stack is not safe. is it correct?

I think we can make asynchronous commit serialize as tegra drm done to 
avoid this problem:


   86 /* serialize outstanding asynchronous commits */
   87 mutex_lock(>commit.lock);
   88 flush_work(>commit.work);
89
   90 /*
   91  * This is the point of no return - everything below never 
fails except
   92  * when the hw goes bonghits. Which means we can commit 
the new state on
   93  * the software side now.
   94 */
95
   96 drm_atomic_helper_swap_state(drm, state);
97
   98 if (async)
   99 tegra_atomic_schedule(tegra, state);
  100 else
  101 tegra_atomic_complete(tegra, state);
  102
  103 mutex_unlock(>commit.lock);


>
   if (is_yuv) {
   /*
* Src.x1 can be odd when do clip, but yuv plane start
 point
* need align with 2 pixel.
*/
 -   val = (src.x1 >> 16) % 2;
 -   src.x1 += val << 16;
 -   src.x2 += val << 16;
 +   uint32_t temp = (src->x1 >> 16) % 2;
 +
 +   src->x1 += temp << 16;
 +   src->x2 += temp << 16;
   }
>>> I know this isn't new, but moving the plane around is bad. If the user
>>> gives you a pixel boundary that you can't actually use, please reject
>>> the configuration rather than silently trying to fix it up.
>> the origin src.x1 would align with 2 pixel, but when we move the dest
>> window, and do clip by output, the src.x1 may be clipped to odd.
>> regect this configuration may let user confuse, sometimes good, sometimes
>> bad.
> For me, it is more confusing when the display shows something
> different to what I have requested. In some media usecases, doing this
> is a showstopper and will result in products failing acceptance
> testing. Userspace can make a policy decision to try different
> alignments to get _something_ to show (even if it's not what was
> explicitly requested), but doing this in the kernel is inappropriate:
> please just reject it, and have userspace fall back to another
> composition method (e.g. GL) in these cases.
>
 -static void vop_plane_destroy(struct drm_plane *plane)
 +static void vop_atomic_plane_destroy_state(struct drm_plane *plane,
 +  struct drm_plane_state *state)
{
 -   vop_disable_plane(plane);
 -   drm_plane_cleanup(plane);
 +   struct vop_plane_state *vop_state = to_vop_plane_state(state);
 +
 +   if (state->fb)
 +   drm_framebuffer_unreference(state->fb);
 +
 +   kfree(vop_state);
}

[RFC PATCH 3/9] drm/rockchip: Convert to support atomic API

2015-12-02 Thread Daniel Stone
Hi Mark,

On 2 December 2015 at 14:18, Daniel Stone  wrote:
> On 1 December 2015 at 09:31, Mark yao  wrote:
>> Can you share your Weston environment to me, I'm interesting to test drm
>> rockchip on weston.
>
> Of course. You can download Weston from http://wayland.freedesktop.org
> - the most interesting dependencies are libevdev, libinput, and
> wayland itself. If you are building newer Weston from git, you'll need
> the wayland-protocols repository as well, from
> anongit.freedesktop.org/git/wayland/wayland-protocols/. Please let me
> know privately if you need some more help with building these, but
> they should be quite straightforward.

Sorry, left one thing out. When running, if you do not have
GBM/Wayland enabled for Mali (or no Mali support), you should run
with:
weston --use-pixman
or:
weston-launch -- --use-pixman

Launching from SSH is a bit more complicated:
sudo weston-launch --user=$username --tty=/dev/tty3 -- --use-pixman

(Replace tty3 with the TTY of your choice: it must be in text mode.)

Once you have done this, you will find three issues:
  - passing -1 to drm_send_vblank event causes OOPS - now fixed in your tree
  - not sending pageflip events for same-fb flips causes Weston hang -
fixed with my patch, and I believe now fixed in atomic (though it may
still have some timing issues; I hope to get to review this early next
week)
  - not having a preclose hook causes OOPS when Weston exits in the
middle of rendering - fixed in
https://git.collabora.com/cgit/user/daniels/linux.git/commit/?h=wip/4.4.x/rockchip-drm-fixes=d14f21bcd7e7a1b9ca129c411a9da9c911037965
and the preceding commit, which I hope to re-send for 4.4 -fixes in
the next couple of days

Hope this helps.

Cheers,
Daniel


[RFC PATCH 3/9] drm/rockchip: Convert to support atomic API

2015-12-02 Thread Daniel Stone
Hi Mark,
Thanks for getting back to this.

On 1 December 2015 at 09:31, Mark yao  wrote:
> On 2015年12月01日 16:18, Daniel Stone wrote:
>> On 1 December 2015 at 03:26, Mark Yao  wrote:
>>> >+   for_each_crtc_in_state(state, crtc, crtc_state, i) {
>>> >+   if (!crtc->state->active)
>>> >+   continue;
>>> >+
>>> >+   rockchip_crtc_wait_for_update(crtc);
>>> >+   }
>>
>> I'd be much more comfortable if this passed in an explicit pointer to
>> state, or an address to wait for, rather than have wait_for_complete
>> dig out state with no locking. The latter is potentially racy for
>> async operations.
>>
> Hi Daniel
>"if this passed in an explicit pointer to state, or an address to wait
> for", I don't understand, can you point how it work?

Ah, OK. I mean that rockchip_crtc_wait_for_update takes a drm_crtc
pointer, and establishes the state from that (e.g.
crtc->primary->state). This can easily lead to confusion in async
contexts, as the states attached to a drm_crtc and a drm_plane can
change here while you wait for it.

It would be better if the call was:

for_each_plane_in_state(state, plane, plane_state, i) {
if (plane->type == DRM_PLANE_TYPE_PRIMARY)
rockchip_crtc_wait_for_update(plane_state->crtc, plane_state);
}

This way it is very clear, and there is no confusion as to which
request we are waiting to complete.

In general, using crtc->state or plane->state is a very bad idea,
_except_ in the atomic_check function where you are calculating
changes (e.g. if (plane_state->fb->pitches[0] !=
plane->state->fb->pitches[0]) rockchip_plane_state->pitch_changed =
true). After atomic_check, you should always pass around pointers to
the plane state explicitly, and avoid using the pointers from drm_crtc
and drm_plane.

Does that help?

>>>  if (is_yuv) {
>>>  /*
>>>   * Src.x1 can be odd when do clip, but yuv plane start
>>> point
>>>   * need align with 2 pixel.
>>>   */
>>> -   val = (src.x1 >> 16) % 2;
>>> -   src.x1 += val << 16;
>>> -   src.x2 += val << 16;
>>> +   uint32_t temp = (src->x1 >> 16) % 2;
>>> +
>>> +   src->x1 += temp << 16;
>>> +   src->x2 += temp << 16;
>>>  }
>>
>> I know this isn't new, but moving the plane around is bad. If the user
>> gives you a pixel boundary that you can't actually use, please reject
>> the configuration rather than silently trying to fix it up.
>
> the origin src.x1 would align with 2 pixel, but when we move the dest
> window, and do clip by output, the src.x1 may be clipped to odd.
> regect this configuration may let user confuse, sometimes good, sometimes
> bad.

For me, it is more confusing when the display shows something
different to what I have requested. In some media usecases, doing this
is a showstopper and will result in products failing acceptance
testing. Userspace can make a policy decision to try different
alignments to get _something_ to show (even if it's not what was
explicitly requested), but doing this in the kernel is inappropriate:
please just reject it, and have userspace fall back to another
composition method (e.g. GL) in these cases.

>>> -static void vop_plane_destroy(struct drm_plane *plane)
>>> +static void vop_atomic_plane_destroy_state(struct drm_plane *plane,
>>> +  struct drm_plane_state *state)
>>>   {
>>> -   vop_disable_plane(plane);
>>> -   drm_plane_cleanup(plane);
>>> +   struct vop_plane_state *vop_state = to_vop_plane_state(state);
>>> +
>>> +   if (state->fb)
>>> +   drm_framebuffer_unreference(state->fb);
>>> +
>>> +   kfree(vop_state);
>>>   }
>>
>> You can replace this hook with drm_atomic_helper_plane_destroy_state.
>
>
> Hmm, only can hook with __drm_atomic_helper_plane_destroy_state.

Ah yes, you're right. But still, using that would be better than duplicating it.

> Can you share your Weston environment to me, I'm interesting to test drm
> rockchip on weston.

Of course. You can download Weston from http://wayland.freedesktop.org
- the most interesting dependencies are libevdev, libinput, and
wayland itself. If you are building newer Weston from git, you'll need
the wayland-protocols repository as well, from
anongit.freedesktop.org/git/wayland/wayland-protocols/. Please let me
know privately if you need some more help with building these, but
they should be quite straightforward.

Cheers,
Daniel


[RFC PATCH 3/9] drm/rockchip: Convert to support atomic API

2015-12-01 Thread Mark yao
On 2015年12月01日 16:18, Daniel Stone wrote:
> Hi Mark,
>
> On 1 December 2015 at 03:26, Mark Yao  wrote:
>> >+static void rockchip_atomic_wait_for_complete(struct drm_atomic_state 
>> >*state)
>> >+{
>> >+   struct drm_crtc_state *crtc_state;
>> >+   struct drm_crtc *crtc;
>> >+   int i;
>> >+
>> >+   for_each_crtc_in_state(state, crtc, crtc_state, i) {
>> >+   if (!crtc->state->active)
>> >+   continue;
>> >+
>> >+   WARN_ON(drm_crtc_vblank_get(crtc));
>> >+   }
>> >+
>> >+   for_each_crtc_in_state(state, crtc, crtc_state, i) {
>> >+   if (!crtc->state->active)
>> >+   continue;
>> >+
>> >+   rockchip_crtc_wait_for_update(crtc);
>> >+   }
> I'd be much more comfortable if this passed in an explicit pointer to
> state, or an address to wait for, rather than have wait_for_complete
> dig out state with no locking. The latter is potentially racy for
> async operations.
>
Hi Daniel
"if this passed in an explicit pointer to state, or an address to 
wait for", I don't understand, can you point how it work?

-- 
ï¼­ark Yao




[RFC PATCH 3/9] drm/rockchip: Convert to support atomic API

2015-12-01 Thread Mark yao
On 2015年12月01日 16:18, Daniel Stone wrote:
> Hi Mark,
>
> On 1 December 2015 at 03:26, Mark Yao  wrote:
>> +static void rockchip_atomic_wait_for_complete(struct drm_atomic_state 
>> *state)
>> +{
>> +   struct drm_crtc_state *crtc_state;
>> +   struct drm_crtc *crtc;
>> +   int i;
>> +
>> +   for_each_crtc_in_state(state, crtc, crtc_state, i) {
>> +   if (!crtc->state->active)
>> +   continue;
>> +
>> +   WARN_ON(drm_crtc_vblank_get(crtc));
>> +   }
>> +
>> +   for_each_crtc_in_state(state, crtc, crtc_state, i) {
>> +   if (!crtc->state->active)
>> +   continue;
>> +
>> +   rockchip_crtc_wait_for_update(crtc);
>> +   }
> I'd be much more comfortable if this passed in an explicit pointer to
> state, or an address to wait for, rather than have wait_for_complete
> dig out state with no locking. The latter is potentially racy for
> async operations.
>
>> +struct vop_plane_state {
>> +   struct drm_plane_state base;
>> +   dma_addr_t dma_addr[ROCKCHIP_MAX_FB_BUFFER];
> Can you get rid of this by just using the pointer to a
> rockchip_gem_object already provided?

Good idea, I will do that.

>> -static int vop_update_plane_event(struct drm_plane *plane,
>> - struct drm_crtc *crtc,
>> - struct drm_framebuffer *fb, int crtc_x,
>> - int crtc_y, unsigned int crtc_w,
>> - unsigned int crtc_h, uint32_t src_x,
>> - uint32_t src_y, uint32_t src_w,
>> - uint32_t src_h,
>> - struct drm_pending_vblank_event *event)
>> +static int vop_plane_atomic_check(struct drm_plane *plane,
>> +  struct drm_plane_state *state)
>>   {
>> +   struct drm_crtc *crtc = state->crtc;
>> +   struct drm_framebuffer *fb = state->fb;
>>  struct vop_win *vop_win = to_vop_win(plane);
>> +   struct vop_plane_state *vop_plane_state = to_vop_plane_state(state);
>>  const struct vop_win_data *win = vop_win->data;
>> -   struct vop *vop = to_vop(crtc);
>>  struct drm_gem_object *obj;
>>  struct rockchip_gem_object *rk_obj;
>> -   struct drm_gem_object *uv_obj;
>> -   struct rockchip_gem_object *rk_uv_obj;
>>  unsigned long offset;
>> -   unsigned int actual_w;
>> -   unsigned int actual_h;
>> -   unsigned int dsp_stx;
>> -   unsigned int dsp_sty;
>> -   unsigned int y_vir_stride;
>> -   unsigned int uv_vir_stride = 0;
>> -   dma_addr_t yrgb_mst;
>> -   dma_addr_t uv_mst = 0;
>> -   enum vop_data_format format;
>> -   uint32_t val;
>> -   bool is_alpha;
>> -   bool rb_swap;
>>  bool is_yuv;
>>  bool visible;
>>  int ret;
>> -   struct drm_rect dest = {
>> -   .x1 = crtc_x,
>> -   .y1 = crtc_y,
>> -   .x2 = crtc_x + crtc_w,
>> -   .y2 = crtc_y + crtc_h,
>> -   };
>> -   struct drm_rect src = {
>> -   /* 16.16 fixed point */
>> -   .x1 = src_x,
>> -   .y1 = src_y,
>> -   .x2 = src_x + src_w,
>> -   .y2 = src_y + src_h,
>> -   };
>> -   const struct drm_rect clip = {
>> -   .x2 = crtc->mode.hdisplay,
>> -   .y2 = crtc->mode.vdisplay,
>> -   };
>> -   bool can_position = plane->type != DRM_PLANE_TYPE_PRIMARY;
>> +   struct drm_rect *dest = _plane_state->dest;
>> +   struct drm_rect *src = _plane_state->src;
>> +   struct drm_rect clip;
>>  int min_scale = win->phy->scl ? FRAC_16_16(1, 8) :
>>  DRM_PLANE_HELPER_NO_SCALING;
>>  int max_scale = win->phy->scl ? FRAC_16_16(8, 1) :
>>  DRM_PLANE_HELPER_NO_SCALING;
>>
>> -   ret = drm_plane_helper_check_update(plane, crtc, fb,
>> -   , , ,
>> +   crtc = crtc ? crtc : plane->state->crtc;
>> +   /*
>> +* Both crtc or plane->state->crtc can be null.
>> +*/
>> +   if (!crtc || !fb)
>> +   goto out_disable;
>> +   src->x1 = state->src_x;
>> +   src->y1 = state->src_y;
>> +   src->x2 = state->src_x + state->src_w;
>> +   src->y2 = state->src_y + state->src_h;
>> +   dest->x1 = state->crtc_x;
>> +   dest->y1 = state->crtc_y;
>> +   dest->x2 = state->crtc_x + state->crtc_w;
>> +   dest->y2 = state->crtc_y + state->crtc_h;
>> +
>> +   clip.x1 = 0;
>> +   clip.y1 = 0;
>> +   clip.x2 = crtc->mode.hdisplay;
>> +   clip.y2 = crtc->mode.vdisplay;
>> +
>> +   ret = drm_plane_helper_check_update(plane, crtc, state->fb,
>> +   src, dest, ,
>>  

[RFC PATCH 3/9] drm/rockchip: Convert to support atomic API

2015-12-01 Thread Mark Yao
Rockchip vop not support hw vblank counter, needed check the committed
register if it's really take effect.

Signed-off-by: Mark Yao 
Signed-off-by: Tomasz Figa 
---
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c |5 +-
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |2 +
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c  |   65 +++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c |  603 ++-
 4 files changed, 301 insertions(+), 374 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index ccd46f2..5de51fd 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -214,6 +214,8 @@ static int rockchip_drm_load(struct drm_device *drm_dev, 
unsigned long flags)
 */
drm_dev->vblank_disable_allowed = true;

+   drm_mode_config_reset(drm_dev);
+
ret = rockchip_drm_fbdev_init(drm_dev);
if (ret)
goto err_vblank_cleanup;
@@ -277,7 +279,8 @@ const struct vm_operations_struct rockchip_drm_vm_ops = {
 };

 static struct drm_driver rockchip_drm_driver = {
-   .driver_features= DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
+   .driver_features= DRIVER_MODESET | DRIVER_GEM |
+ DRIVER_PRIME | DRIVER_ATOMIC,
.load   = rockchip_drm_load,
.unload = rockchip_drm_unload,
.lastclose  = rockchip_drm_lastclose,
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h 
b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 069d6d4..513ff98 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -18,6 +18,7 @@
 #define _ROCKCHIP_DRM_DRV_H

 #include 
+#include 
 #include 

 #include 
@@ -63,5 +64,6 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
   struct device *dev);
 void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
struct device *dev);
+void rockchip_crtc_wait_for_update(struct drm_crtc *crtc);

 #endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 002645b..c86d93a 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 

@@ -166,9 +167,73 @@ static void rockchip_drm_output_poll_changed(struct 
drm_device *dev)
drm_fb_helper_hotplug_event(fb_helper);
 }

+static void rockchip_atomic_wait_for_complete(struct drm_atomic_state *state)
+{
+   struct drm_crtc_state *crtc_state;
+   struct drm_crtc *crtc;
+   int i;
+
+   for_each_crtc_in_state(state, crtc, crtc_state, i) {
+   if (!crtc->state->active)
+   continue;
+
+   WARN_ON(drm_crtc_vblank_get(crtc));
+   }
+
+   for_each_crtc_in_state(state, crtc, crtc_state, i) {
+   if (!crtc->state->active)
+   continue;
+
+   rockchip_crtc_wait_for_update(crtc);
+   }
+
+   for_each_crtc_in_state(state, crtc, crtc_state, i) {
+   if (!crtc->state->active)
+   continue;
+
+   drm_crtc_vblank_put(crtc);
+   }
+}
+
+int rockchip_drm_atomic_commit(struct drm_device *dev,
+  struct drm_atomic_state *state,
+  bool async)
+{
+   int ret;
+
+   if (async)
+   return -EBUSY;
+
+   ret = drm_atomic_helper_prepare_planes(dev, state);
+   if (ret)
+   return ret;
+
+   drm_atomic_helper_swap_state(dev, state);
+
+   /*
+* TODO: do fence wait here.
+*/
+
+   drm_atomic_helper_commit_modeset_disables(dev, state);
+
+   drm_atomic_helper_commit_planes(dev, state, false);
+
+   drm_atomic_helper_commit_modeset_enables(dev, state);
+
+   rockchip_atomic_wait_for_complete(state);
+
+   drm_atomic_helper_cleanup_planes(dev, state);
+
+   drm_atomic_state_free(state);
+
+   return 0;
+}
+
 static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
.fb_create = rockchip_user_fb_create,
.output_poll_changed = rockchip_drm_output_poll_changed,
+   .atomic_check = drm_atomic_helper_check,
+   .atomic_commit = rockchip_drm_atomic_commit,
 };

 struct drm_framebuffer *
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c 
b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 3d16e70..a28e255 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -14,6 +14,7 @@

 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -63,12 +64,16 @@

 #define to_vop(x) container_of(x, struct vop, crtc)
 #define to_vop_win(x) 

[RFC PATCH 3/9] drm/rockchip: Convert to support atomic API

2015-12-01 Thread Daniel Stone
Hi Mark,

On 1 December 2015 at 03:26, Mark Yao  wrote:
> +static void rockchip_atomic_wait_for_complete(struct drm_atomic_state *state)
> +{
> +   struct drm_crtc_state *crtc_state;
> +   struct drm_crtc *crtc;
> +   int i;
> +
> +   for_each_crtc_in_state(state, crtc, crtc_state, i) {
> +   if (!crtc->state->active)
> +   continue;
> +
> +   WARN_ON(drm_crtc_vblank_get(crtc));
> +   }
> +
> +   for_each_crtc_in_state(state, crtc, crtc_state, i) {
> +   if (!crtc->state->active)
> +   continue;
> +
> +   rockchip_crtc_wait_for_update(crtc);
> +   }

I'd be much more comfortable if this passed in an explicit pointer to
state, or an address to wait for, rather than have wait_for_complete
dig out state with no locking. The latter is potentially racy for
async operations.

> +struct vop_plane_state {
> +   struct drm_plane_state base;
> +   dma_addr_t dma_addr[ROCKCHIP_MAX_FB_BUFFER];

Can you get rid of this by just using the pointer to a
rockchip_gem_object already provided?

> -static int vop_update_plane_event(struct drm_plane *plane,
> - struct drm_crtc *crtc,
> - struct drm_framebuffer *fb, int crtc_x,
> - int crtc_y, unsigned int crtc_w,
> - unsigned int crtc_h, uint32_t src_x,
> - uint32_t src_y, uint32_t src_w,
> - uint32_t src_h,
> - struct drm_pending_vblank_event *event)
> +static int vop_plane_atomic_check(struct drm_plane *plane,
> +  struct drm_plane_state *state)
>  {
> +   struct drm_crtc *crtc = state->crtc;
> +   struct drm_framebuffer *fb = state->fb;
> struct vop_win *vop_win = to_vop_win(plane);
> +   struct vop_plane_state *vop_plane_state = to_vop_plane_state(state);
> const struct vop_win_data *win = vop_win->data;
> -   struct vop *vop = to_vop(crtc);
> struct drm_gem_object *obj;
> struct rockchip_gem_object *rk_obj;
> -   struct drm_gem_object *uv_obj;
> -   struct rockchip_gem_object *rk_uv_obj;
> unsigned long offset;
> -   unsigned int actual_w;
> -   unsigned int actual_h;
> -   unsigned int dsp_stx;
> -   unsigned int dsp_sty;
> -   unsigned int y_vir_stride;
> -   unsigned int uv_vir_stride = 0;
> -   dma_addr_t yrgb_mst;
> -   dma_addr_t uv_mst = 0;
> -   enum vop_data_format format;
> -   uint32_t val;
> -   bool is_alpha;
> -   bool rb_swap;
> bool is_yuv;
> bool visible;
> int ret;
> -   struct drm_rect dest = {
> -   .x1 = crtc_x,
> -   .y1 = crtc_y,
> -   .x2 = crtc_x + crtc_w,
> -   .y2 = crtc_y + crtc_h,
> -   };
> -   struct drm_rect src = {
> -   /* 16.16 fixed point */
> -   .x1 = src_x,
> -   .y1 = src_y,
> -   .x2 = src_x + src_w,
> -   .y2 = src_y + src_h,
> -   };
> -   const struct drm_rect clip = {
> -   .x2 = crtc->mode.hdisplay,
> -   .y2 = crtc->mode.vdisplay,
> -   };
> -   bool can_position = plane->type != DRM_PLANE_TYPE_PRIMARY;
> +   struct drm_rect *dest = _plane_state->dest;
> +   struct drm_rect *src = _plane_state->src;
> +   struct drm_rect clip;
> int min_scale = win->phy->scl ? FRAC_16_16(1, 8) :
> DRM_PLANE_HELPER_NO_SCALING;
> int max_scale = win->phy->scl ? FRAC_16_16(8, 1) :
> DRM_PLANE_HELPER_NO_SCALING;
>
> -   ret = drm_plane_helper_check_update(plane, crtc, fb,
> -   , , ,
> +   crtc = crtc ? crtc : plane->state->crtc;
> +   /*
> +* Both crtc or plane->state->crtc can be null.
> +*/
> +   if (!crtc || !fb)
> +   goto out_disable;
> +   src->x1 = state->src_x;
> +   src->y1 = state->src_y;
> +   src->x2 = state->src_x + state->src_w;
> +   src->y2 = state->src_y + state->src_h;
> +   dest->x1 = state->crtc_x;
> +   dest->y1 = state->crtc_y;
> +   dest->x2 = state->crtc_x + state->crtc_w;
> +   dest->y2 = state->crtc_y + state->crtc_h;
> +
> +   clip.x1 = 0;
> +   clip.y1 = 0;
> +   clip.x2 = crtc->mode.hdisplay;
> +   clip.y2 = crtc->mode.vdisplay;
> +
> +   ret = drm_plane_helper_check_update(plane, crtc, state->fb,
> +   src, dest, ,
> min_scale,
> max_scale,
> -   can_position, false, );
> +   true, true, );
> if (ret)
>