diff options
Diffstat (limited to 'drivers/gpu/drm/msm/msm_fb.c')
| -rw-r--r-- | drivers/gpu/drm/msm/msm_fb.c | 113 |
1 files changed, 79 insertions, 34 deletions
diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c index 4d34df5354e0..1eff615ff9bf 100644 --- a/drivers/gpu/drm/msm/msm_fb.c +++ b/drivers/gpu/drm/msm/msm_fb.c @@ -8,6 +8,7 @@ #include <drm/drm_damage_helper.h> #include <drm/drm_file.h> #include <drm/drm_fourcc.h> +#include <drm/drm_framebuffer.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_probe_helper.h> @@ -18,16 +19,41 @@ struct msm_framebuffer { struct drm_framebuffer base; const struct msm_format *format; + + /* Count of # of attached planes which need dirtyfb: */ + refcount_t dirtyfb; + + /* Framebuffer per-plane address, if pinned, else zero: */ + uint64_t iova[DRM_FORMAT_MAX_PLANES]; + atomic_t prepare_count; }; #define to_msm_framebuffer(x) container_of(x, struct msm_framebuffer, base) static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, + const struct drm_format_info *info, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos); +static int msm_framebuffer_dirtyfb(struct drm_framebuffer *fb, + struct drm_file *file_priv, unsigned int flags, + unsigned int color, struct drm_clip_rect *clips, + unsigned int num_clips) +{ + struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); + + /* If this fb is not used on any display requiring pixel data to be + * flushed, then skip dirtyfb + */ + if (refcount_read(&msm_fb->dirtyfb) == 1) + return 0; + + return drm_atomic_helper_dirtyfb(fb, file_priv, flags, color, + clips, num_clips); +} + static const struct drm_framebuffer_funcs msm_framebuffer_funcs = { .create_handle = drm_gem_fb_create_handle, .destroy = drm_gem_fb_destroy, - .dirty = drm_atomic_helper_dirtyfb, + .dirty = msm_framebuffer_dirtyfb, }; #ifdef CONFIG_DEBUG_FS @@ -48,20 +74,26 @@ void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m) } #endif -/* prepare/pin all the fb's bo's for scanout. Note that it is not valid - * to prepare an fb more multiple different initiator 'id's. But that - * should be fine, since only the scanout (mdpN) side of things needs - * this, the gpu doesn't care about fb's. +/* prepare/pin all the fb's bo's for scanout. */ -int msm_framebuffer_prepare(struct drm_framebuffer *fb, - struct msm_gem_address_space *aspace) +int msm_framebuffer_prepare(struct drm_framebuffer *fb, bool needs_dirtyfb) { + struct msm_drm_private *priv = fb->dev->dev_private; + struct drm_gpuvm *vm = priv->kms->vm; + struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); int ret, i, n = fb->format->num_planes; - uint64_t iova; + + if (needs_dirtyfb) + refcount_inc(&msm_fb->dirtyfb); + + if (atomic_inc_return(&msm_fb->prepare_count) > 1) + return 0; for (i = 0; i < n; i++) { - ret = msm_gem_get_and_pin_iova(fb->obj[i], aspace, &iova); - drm_dbg_state(fb->dev, "FB[%u]: iova[%d]: %08llx (%d)", fb->base.id, i, iova, ret); + msm_gem_vma_get(fb->obj[i]); + ret = msm_gem_get_and_pin_iova(fb->obj[i], vm, &msm_fb->iova[i]); + drm_dbg_state(fb->dev, "FB[%u]: iova[%d]: %08llx (%d)\n", + fb->base.id, i, msm_fb->iova[i], ret); if (ret) return ret; } @@ -69,21 +101,31 @@ int msm_framebuffer_prepare(struct drm_framebuffer *fb, return 0; } -void msm_framebuffer_cleanup(struct drm_framebuffer *fb, - struct msm_gem_address_space *aspace) +void msm_framebuffer_cleanup(struct drm_framebuffer *fb, bool needed_dirtyfb) { + struct msm_drm_private *priv = fb->dev->dev_private; + struct drm_gpuvm *vm = priv->kms->vm; + struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); int i, n = fb->format->num_planes; - for (i = 0; i < n; i++) - msm_gem_unpin_iova(fb->obj[i], aspace); + if (needed_dirtyfb) + refcount_dec(&msm_fb->dirtyfb); + + if (atomic_dec_return(&msm_fb->prepare_count)) + return; + + memset(msm_fb->iova, 0, sizeof(msm_fb->iova)); + + for (i = 0; i < n; i++) { + msm_gem_unpin_iova(fb->obj[i], vm); + msm_gem_vma_put(fb->obj[i]); + } } -uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb, - struct msm_gem_address_space *aspace, int plane) +uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb, int plane) { - if (!fb->obj[plane]) - return 0; - return msm_gem_iova(fb->obj[plane], aspace) + fb->offsets[plane]; + struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb); + return msm_fb->iova[plane] + fb->offsets[plane]; } struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane) @@ -98,10 +140,9 @@ const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb) } struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, - struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd) + struct drm_file *file, const struct drm_format_info *info, + const struct drm_mode_fb_cmd2 *mode_cmd) { - const struct drm_format_info *info = drm_get_format_info(dev, - mode_cmd); struct drm_gem_object *bos[4] = {0}; struct drm_framebuffer *fb; int ret, i, n = info->num_planes; @@ -114,7 +155,7 @@ struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, } } - fb = msm_framebuffer_init(dev, mode_cmd, bos); + fb = msm_framebuffer_init(dev, info, mode_cmd, bos); if (IS_ERR(fb)) { ret = PTR_ERR(fb); goto out_unref; @@ -129,10 +170,9 @@ out_unref: } static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, + const struct drm_format_info *info, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos) { - const struct drm_format_info *info = drm_get_format_info(dev, - mode_cmd); struct msm_drm_private *priv = dev->dev_private; struct msm_kms *kms = priv->kms; struct msm_framebuffer *msm_fb = NULL; @@ -140,16 +180,16 @@ static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, const struct msm_format *format; int ret, i, n; - drm_dbg_state(dev, "create framebuffer: mode_cmd=%p (%dx%d@%4.4s)", - mode_cmd, mode_cmd->width, mode_cmd->height, - (char *)&mode_cmd->pixel_format); + drm_dbg_state(dev, "create framebuffer: mode_cmd=%p (%dx%d@%p4cc)\n", + mode_cmd, mode_cmd->width, mode_cmd->height, + &mode_cmd->pixel_format); n = info->num_planes; - format = kms->funcs->get_format(kms, mode_cmd->pixel_format, + format = mdp_get_format(kms, mode_cmd->pixel_format, mode_cmd->modifier[0]); if (!format) { - DRM_DEV_ERROR(dev->dev, "unsupported pixel format: %4.4s\n", - (char *)&mode_cmd->pixel_format); + DRM_DEV_ERROR(dev->dev, "unsupported pixel format: %p4cc\n", + &mode_cmd->pixel_format); ret = -EINVAL; goto fail; } @@ -186,7 +226,7 @@ static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, msm_fb->base.obj[i] = bos[i]; } - drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd); + drm_helper_mode_fill_fb_struct(dev, fb, info, mode_cmd); ret = drm_framebuffer_init(dev, fb, &msm_framebuffer_funcs); if (ret) { @@ -194,7 +234,9 @@ static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, goto fail; } - drm_dbg_state(dev, "create: FB ID: %d (%p)", fb->base.id, fb); + refcount_set(&msm_fb->dirtyfb, 1); + + drm_dbg_state(dev, "create: FB ID: %d (%p)\n", fb->base.id, fb); return fb; @@ -233,7 +275,10 @@ msm_alloc_stolen_fb(struct drm_device *dev, int w, int h, int p, uint32_t format msm_gem_object_set_name(bo, "stolenfb"); - fb = msm_framebuffer_init(dev, &mode_cmd, &bo); + fb = msm_framebuffer_init(dev, + drm_get_format_info(dev, mode_cmd.pixel_format, + mode_cmd.modifier[0]), + &mode_cmd, &bo); if (IS_ERR(fb)) { DRM_DEV_ERROR(dev->dev, "failed to allocate fb\n"); /* note: if fb creation failed, we can't rely on fb destroy |
