[PATCH v4] gpu/drm: ingenic: Add option to mmap GEM buffers cached
Paul Cercueil
paul at crapouillou.net
Wed Sep 9 13:26:52 UTC 2020
Any love for my patch? I have more pending :)
Thanks,
-Paul
Le sam. 22 août 2020 à 18:42, Paul Cercueil <paul at crapouillou.net> a
écrit :
> Ingenic SoCs are most notably used in cheap chinese handheld gaming
> consoles. There, the games and applications generally render in
> software
> directly into GEM buffers.
>
> Traditionally, GEM buffers are mapped write-combine. Writes to the
> buffer are accelerated, and reads are slow. Application doing lots of
> alpha-blending paint inside shadow buffers, which is then memcpy'd
> into
> the final GEM buffer.
>
> On recent Ingenic SoCs however, it is much faster to have a fully
> cached
> GEM buffer, in which applications paint directly, and whose data is
> invalidated before scanout, than having a write-combine GEM buffer,
> even
> when alpha blending is not used.
>
> Add an optional 'cached_gem_buffers' parameter to the ingenic-drm
> driver
> to allow GEM buffers to be mapped fully-cached, in order to speed up
> software rendering.
>
> v2: Use standard noncoherent DMA APIs
>
> v3: Use damage clips instead of invalidating full frames
>
> v4: Avoid dma_pgprot() which is not exported. Using vm_get_page_prot()
> is enough in this case.
>
> Signed-off-by: Paul Cercueil <paul at crapouillou.net>
> ---
> drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 107
> +++++++++++++++++++++-
> drivers/gpu/drm/ingenic/ingenic-drm.h | 4 +
> drivers/gpu/drm/ingenic/ingenic-ipu.c | 12 ++-
> 3 files changed, 119 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
> b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
> index 5dab9c3d0a52..bf571411b73f 100644
> --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
> +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
> @@ -9,6 +9,8 @@
> #include <linux/component.h>
> #include <linux/clk.h>
> #include <linux/dma-mapping.h>
> +#include <linux/dma-noncoherent.h>
> +#include <linux/io.h>
> #include <linux/module.h>
> #include <linux/of_device.h>
> #include <linux/platform_device.h>
> @@ -19,6 +21,7 @@
> #include <drm/drm_bridge.h>
> #include <drm/drm_crtc.h>
> #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_damage_helper.h>
> #include <drm/drm_drv.h>
> #include <drm/drm_gem_cma_helper.h>
> #include <drm/drm_fb_cma_helper.h>
> @@ -76,6 +79,11 @@ static const u32 ingenic_drm_primary_formats[] = {
> DRM_FORMAT_XRGB8888,
> };
>
> +static bool ingenic_drm_cached_gem_buf;
> +module_param_named(cached_gem_buffers, ingenic_drm_cached_gem_buf,
> bool, 0400);
> +MODULE_PARM_DESC(cached_gem_buffers,
> + "Enable fully cached GEM buffers [default=false]");
> +
> static bool ingenic_drm_writeable_reg(struct device *dev, unsigned
> int reg)
> {
> switch (reg) {
> @@ -338,6 +346,8 @@ static int ingenic_drm_plane_atomic_check(struct
> drm_plane *plane,
> plane->state->fb->format->format != state->fb->format->format))
> crtc_state->mode_changed = true;
>
> + drm_atomic_helper_check_plane_damage(state->state, state);
> +
> return 0;
> }
>
> @@ -440,6 +450,38 @@ void ingenic_drm_plane_config(struct device *dev,
> }
> }
>
> +void ingenic_drm_sync_data(struct device *dev,
> + struct drm_plane_state *old_state,
> + struct drm_plane_state *state)
> +{
> + const struct drm_format_info *finfo = state->fb->format;
> + struct ingenic_drm *priv = dev_get_drvdata(dev);
> + struct drm_atomic_helper_damage_iter iter;
> + unsigned int offset, i;
> + struct drm_rect clip;
> + dma_addr_t paddr;
> + void *addr;
> +
> + if (!ingenic_drm_cached_gem_buf)
> + return;
> +
> + drm_atomic_helper_damage_iter_init(&iter, old_state, state);
> +
> + drm_atomic_for_each_plane_damage(&iter, &clip) {
> + for (i = 0; i < finfo->num_planes; i++) {
> + paddr = drm_fb_cma_get_gem_addr(state->fb, state, i);
> + addr = phys_to_virt(paddr);
> +
> + /* Ignore x1/x2 values, invalidate complete lines */
> + offset = clip.y1 * state->fb->pitches[i];
> +
> + dma_cache_sync(priv->dev, addr + offset,
> + (clip.y2 - clip.y1) * state->fb->pitches[i],
> + DMA_TO_DEVICE);
> + }
> + }
> +}
> +
> static void ingenic_drm_plane_atomic_update(struct drm_plane *plane,
> struct drm_plane_state *oldstate)
> {
> @@ -450,6 +492,8 @@ static void
> ingenic_drm_plane_atomic_update(struct drm_plane *plane,
> dma_addr_t addr;
>
> if (state && state->fb) {
> + ingenic_drm_sync_data(priv->dev, oldstate, state);
> +
> addr = drm_fb_cma_get_gem_addr(state->fb, state, 0);
> width = state->src_w >> 16;
> height = state->src_h >> 16;
> @@ -605,7 +649,62 @@ static void ingenic_drm_disable_vblank(struct
> drm_crtc *crtc)
> regmap_update_bits(priv->map, JZ_REG_LCD_CTRL, JZ_LCD_CTRL_EOF_IRQ,
> 0);
> }
>
> -DEFINE_DRM_GEM_CMA_FOPS(ingenic_drm_fops);
> +static struct drm_framebuffer *
> +ingenic_drm_gem_fb_create(struct drm_device *dev, struct drm_file
> *file,
> + const struct drm_mode_fb_cmd2 *mode_cmd)
> +{
> + if (ingenic_drm_cached_gem_buf)
> + return drm_gem_fb_create_with_dirty(dev, file, mode_cmd);
> +
> + return drm_gem_fb_create(dev, file, mode_cmd);
> +}
> +
> +static int ingenic_drm_gem_mmap(struct drm_gem_object *obj,
> + struct vm_area_struct *vma)
> +{
> + struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(obj);
> + struct device *dev = cma_obj->base.dev->dev;
> +
> + if (!ingenic_drm_cached_gem_buf)
> + return drm_gem_cma_prime_mmap(obj, vma);
> +
> + /*
> + * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set
> the
> + * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want
> to map
> + * the whole buffer.
> + */
> + vma->vm_flags &= ~VM_PFNMAP;
> + vma->vm_pgoff = 0;
> + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
> +
> + return dma_mmap_attrs(dev, vma, cma_obj->vaddr, cma_obj->paddr,
> + vma->vm_end - vma->vm_start,
> + DMA_ATTR_NON_CONSISTENT);
> +}
> +
> +static int ingenic_drm_gem_cma_mmap(struct file *filp,
> + struct vm_area_struct *vma)
> +{
> + int ret;
> +
> + ret = drm_gem_mmap(filp, vma);
> + if (ret)
> + return ret;
> +
> + return ingenic_drm_gem_mmap(vma->vm_private_data, vma);
> +}
> +
> +static const struct file_operations ingenic_drm_fops = {
> + .owner = THIS_MODULE,
> + .open = drm_open,
> + .release = drm_release,
> + .unlocked_ioctl = drm_ioctl,
> + .compat_ioctl = drm_compat_ioctl,
> + .poll = drm_poll,
> + .read = drm_read,
> + .llseek = noop_llseek,
> + .mmap = ingenic_drm_gem_cma_mmap,
> +};
>
> static struct drm_driver ingenic_drm_driver_data = {
> .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
> @@ -669,7 +768,7 @@ static const struct drm_encoder_helper_funcs
> ingenic_drm_encoder_helper_funcs =
> };
>
> static const struct drm_mode_config_funcs
> ingenic_drm_mode_config_funcs = {
> - .fb_create = drm_gem_fb_create,
> + .fb_create = ingenic_drm_gem_fb_create,
> .output_poll_changed = drm_fb_helper_output_poll_changed,
> .atomic_check = drm_atomic_helper_check,
> .atomic_commit = drm_atomic_helper_commit,
> @@ -796,6 +895,8 @@ static int ingenic_drm_bind(struct device *dev)
> return ret;
> }
>
> + drm_plane_enable_fb_damage_clips(&priv->f1);
> +
> drm_crtc_helper_add(&priv->crtc, &ingenic_drm_crtc_helper_funcs);
>
> ret = drm_crtc_init_with_planes(drm, &priv->crtc, &priv->f1,
> @@ -821,6 +922,8 @@ static int ingenic_drm_bind(struct device *dev)
> return ret;
> }
>
> + drm_plane_enable_fb_damage_clips(&priv->f0);
> +
> if (IS_ENABLED(CONFIG_DRM_INGENIC_IPU)) {
> ret = component_bind_all(dev, drm);
> if (ret) {
> diff --git a/drivers/gpu/drm/ingenic/ingenic-drm.h
> b/drivers/gpu/drm/ingenic/ingenic-drm.h
> index 43f7d959cff7..df99f0f75d39 100644
> --- a/drivers/gpu/drm/ingenic/ingenic-drm.h
> +++ b/drivers/gpu/drm/ingenic/ingenic-drm.h
> @@ -168,6 +168,10 @@ void ingenic_drm_plane_config(struct device *dev,
> struct drm_plane *plane, u32 fourcc);
> void ingenic_drm_plane_disable(struct device *dev, struct drm_plane
> *plane);
>
> +void ingenic_drm_sync_data(struct device *dev,
> + struct drm_plane_state *old_state,
> + struct drm_plane_state *state);
> +
> extern struct platform_driver *ingenic_ipu_driver_ptr;
>
> #endif /* DRIVERS_GPU_DRM_INGENIC_INGENIC_DRM_H */
> diff --git a/drivers/gpu/drm/ingenic/ingenic-ipu.c
> b/drivers/gpu/drm/ingenic/ingenic-ipu.c
> index fc8c6e970ee3..38c83e8cc6a5 100644
> --- a/drivers/gpu/drm/ingenic/ingenic-ipu.c
> +++ b/drivers/gpu/drm/ingenic/ingenic-ipu.c
> @@ -20,6 +20,7 @@
>
> #include <drm/drm_atomic.h>
> #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_damage_helper.h>
> #include <drm/drm_drv.h>
> #include <drm/drm_fb_cma_helper.h>
> #include <drm/drm_fourcc.h>
> @@ -316,6 +317,8 @@ static void
> ingenic_ipu_plane_atomic_update(struct drm_plane *plane,
> JZ_IPU_CTRL_CHIP_EN | JZ_IPU_CTRL_LCDC_SEL);
> }
>
> + ingenic_drm_sync_data(ipu->master, oldstate, state);
> +
> /* New addresses will be committed in vblank handler... */
> ipu->addr_y = drm_fb_cma_get_gem_addr(state->fb, state, 0);
> if (finfo->num_planes > 1)
> @@ -534,7 +537,7 @@ static int ingenic_ipu_plane_atomic_check(struct
> drm_plane *plane,
>
> if (!state->crtc ||
> !crtc_state->mode.hdisplay || !crtc_state->mode.vdisplay)
> - return 0;
> + goto out_check_damage;
>
> /* Plane must be fully visible */
> if (state->crtc_x < 0 || state->crtc_y < 0 ||
> @@ -551,7 +554,7 @@ static int ingenic_ipu_plane_atomic_check(struct
> drm_plane *plane,
> return -EINVAL;
>
> if (!osd_changed(state, plane->state))
> - return 0;
> + goto out_check_damage;
>
> crtc_state->mode_changed = true;
>
> @@ -578,6 +581,9 @@ static int ingenic_ipu_plane_atomic_check(struct
> drm_plane *plane,
> ipu->denom_w = denom_w;
> ipu->denom_h = denom_h;
>
> +out_check_damage:
> + drm_atomic_helper_check_plane_damage(state->state, state);
> +
> return 0;
> }
>
> @@ -759,6 +765,8 @@ static int ingenic_ipu_bind(struct device *dev,
> struct device *master, void *d)
> return err;
> }
>
> + drm_plane_enable_fb_damage_clips(plane);
> +
> /*
> * Sharpness settings range is [0,32]
> * 0 : nearest-neighbor
> --
> 2.28.0
>
More information about the dri-devel
mailing list