[PATCH v3 3/8] drm/rockchip: Convert to support atomic API
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 --- Changes in v3: Reported by kbuild test robot - fix rockchip_crtc_wait_for_update undefined when build drm rockchip as modules. Changes in v2: - Optimization commit planes sequence. - Get vblank count on atomic_begin to protect vblank event. Adviced by Daniel Stone - Direct return -EINVAL when yuv address is not support, instead of adjust it. - code formating and cleanup. Adviced by Thierry Reding & Daniel Vetter - Hook mode_set into crtc enable instead of hack crtc enable on mode set. drivers/gpu/drm/rockchip/rockchip_drm_drv.c |5 +- drivers/gpu/drm/rockchip/rockchip_drm_drv.h |3 +- drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 95 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 657 +++ 4 files changed, 363 insertions(+), 397 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index cfd9b83..ab3e0f6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -213,6 +213,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; @@ -276,7 +278,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..4468f98 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 @@ -38,6 +39,7 @@ struct drm_connector; struct rockchip_crtc_funcs { int (*enable_vblank)(struct drm_crtc *crtc); void (*disable_vblank)(struct drm_crtc *crtc); + void (*wait_for_update)(struct drm_crtc *crtc); }; /* @@ -63,5 +65,4 @@ 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); - #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 b8ac591..7c974a4 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,103 @@ static void rockchip_drm_output_poll_changed(struct drm_device *dev) drm_fb_helper_hotplug_event(fb_helper); } +static void rockchip_crtc_wait_for_update(struct drm_crtc *crtc) +{ + struct rockchip_drm_private *priv = crtc->dev->dev_private; + int pipe = drm_crtc_index(crtc); + const struct rockchip_crtc_funcs *crtc_funcs = priv->crtc_funcs[pipe]; + + if (crtc_funcs && crtc_funcs->wait_for_update) + crtc_funcs->wait_for_update(crtc); +} + +static void +rockchip_atomic_wait_for_complete(struct drm_atomic_state *old_state) +{ + struct drm_crtc_state *old_crtc_state; + struct drm_crtc *crtc; + int i, ret; + + for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { + /* No one cares about the old state, so abuse it for tracking +* and store whether we hold a vblank reference (and should do a +* vblank wait) in the ->enable boolean. +*/ + old_crtc_state->enable = false; + + if (!crtc->state->active) + continue; + + ret = drm_crtc_vblank_get(crtc); + if (ret != 0) + continue; + + old_crtc_state->enable = true; + } + + for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { + if (!old_crtc_state->enable) + continue; + + rockchip_crtc_wait_for_update(crtc); + 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
[PATCH v3 3/8] drm/rockchip: Convert to support atomic API
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--- Changes in v3: Reported by kbuild test robot - fix rockchip_crtc_wait_for_update undefined when build drm rockchip as modules. Changes in v2: - Optimization commit planes sequence. - Get vblank count on atomic_begin to protect vblank event. Adviced by Daniel Stone - Direct return -EINVAL when yuv address is not support, instead of adjust it. - code formating and cleanup. Adviced by Thierry Reding & Daniel Vetter - Hook mode_set into crtc enable instead of hack crtc enable on mode set. drivers/gpu/drm/rockchip/rockchip_drm_drv.c |5 +- drivers/gpu/drm/rockchip/rockchip_drm_drv.h |3 +- drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 95 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 657 +++ 4 files changed, 363 insertions(+), 397 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index cfd9b83..ab3e0f6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -213,6 +213,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; @@ -276,7 +278,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..4468f98 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 @@ -38,6 +39,7 @@ struct drm_connector; struct rockchip_crtc_funcs { int (*enable_vblank)(struct drm_crtc *crtc); void (*disable_vblank)(struct drm_crtc *crtc); + void (*wait_for_update)(struct drm_crtc *crtc); }; /* @@ -63,5 +65,4 @@ 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); - #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 b8ac591..7c974a4 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,103 @@ static void rockchip_drm_output_poll_changed(struct drm_device *dev) drm_fb_helper_hotplug_event(fb_helper); } +static void rockchip_crtc_wait_for_update(struct drm_crtc *crtc) +{ + struct rockchip_drm_private *priv = crtc->dev->dev_private; + int pipe = drm_crtc_index(crtc); + const struct rockchip_crtc_funcs *crtc_funcs = priv->crtc_funcs[pipe]; + + if (crtc_funcs && crtc_funcs->wait_for_update) + crtc_funcs->wait_for_update(crtc); +} + +static void +rockchip_atomic_wait_for_complete(struct drm_atomic_state *old_state) +{ + struct drm_crtc_state *old_crtc_state; + struct drm_crtc *crtc; + int i, ret; + + for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { + /* No one cares about the old state, so abuse it for tracking +* and store whether we hold a vblank reference (and should do a +* vblank wait) in the ->enable boolean. +*/ + old_crtc_state->enable = false; + + if (!crtc->state->active) + continue; + + ret = drm_crtc_vblank_get(crtc); + if (ret != 0) + continue; + + old_crtc_state->enable = true; + } + + for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { + if (!old_crtc_state->enable) + continue; + + rockchip_crtc_wait_for_update(crtc); + drm_crtc_vblank_put(crtc); + } +} + +int rockchip_drm_atomic_commit(struct drm_device *dev, + struct drm_atomic_state *state, + bool async) +{ + int