On 15/10/2019 13:33, Neil Armstrong wrote: > The VPU embeds a "Register DMA" that can write a sequence of registers > on the VPU AHB bus, either manually or triggered by an internal IRQ > event like VSYNC or a line input counter. > > The initial implementation handles a single channel (over 8), triggered > by the VSYNC irq and does not handle the RDMA irq. > > The RDMA will be usefull to reset and program the AFBC decoder unit > on each vsync without involving the interrupt handler that can > be masked for a long period of time, producing display glitches. > > Signed-off-by: Neil Armstrong <narmstrong@xxxxxxxxxxxx> > --- > drivers/gpu/drm/meson/Makefile | 2 +- > drivers/gpu/drm/meson/meson_drv.c | 14 +++- > drivers/gpu/drm/meson/meson_drv.h | 6 ++ > drivers/gpu/drm/meson/meson_rdma.c | 123 +++++++++++++++++++++++++++++ > drivers/gpu/drm/meson/meson_rdma.h | 20 +++++ > 5 files changed, 161 insertions(+), 4 deletions(-) > create mode 100644 drivers/gpu/drm/meson/meson_rdma.c > create mode 100644 drivers/gpu/drm/meson/meson_rdma.h > > diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile > index b1fa055aaed3..9e36f0c7b816 100644 > --- a/drivers/gpu/drm/meson/Makefile > +++ b/drivers/gpu/drm/meson/Makefile > @@ -1,7 +1,7 @@ > # SPDX-License-Identifier: GPL-2.0-only > meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o > meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_overlay.o > -meson-drm-y += meson_osd_afbcd.o > +meson-drm-y += meson_osd_afbcd.o meson_rdma.o > > obj-$(CONFIG_DRM_MESON) += meson-drm.o > obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o > diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c > index 0f31e70bb94f..2200d8b5252e 100644 > --- a/drivers/gpu/drm/meson/meson_drv.c > +++ b/drivers/gpu/drm/meson/meson_drv.c > @@ -33,6 +33,7 @@ > #include "meson_venc_cvbs.h" > #include "meson_viu.h" > #include "meson_vpp.h" > +#include "meson_rdma.h" > > #define DRIVER_NAME "meson" > #define DRIVER_DESC "Amlogic Meson DRM driver" > @@ -295,8 +296,11 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) > meson_venc_init(priv); > meson_vpp_init(priv); > meson_viu_init(priv); > - if (priv->afbcd.ops) > - priv->afbcd.ops->init(priv); > + if (priv->afbcd.ops) { > + ret = priv->afbcd.ops->init(priv); > + if (ret) > + return ret; > + } > > /* Encoder Initialization */ > > @@ -367,12 +371,16 @@ static void meson_drv_unbind(struct device *dev) > meson_canvas_free(priv->canvas, priv->canvas_id_vd1_2); > } > > + if (priv->afbcd.ops) { > + priv->afbcd.ops->reset(priv); > + meson_rdma_free(priv); > + } > + > drm_dev_unregister(drm); > drm_irq_uninstall(drm); > drm_kms_helper_poll_fini(drm); > drm_mode_config_cleanup(drm); > drm_dev_put(drm); > - > } > > static const struct component_master_ops meson_drv_master_ops = { > diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h > index de25349be8aa..9995d74c5ded 100644 > --- a/drivers/gpu/drm/meson/meson_drv.h > +++ b/drivers/gpu/drm/meson/meson_drv.h > @@ -139,6 +139,12 @@ struct meson_drm { > u64 modifier; > u32 format; > } afbcd; > + > + struct { > + dma_addr_t addr_phys; > + uint32_t *addr; > + unsigned int offset; > + } rdma; > }; > > static inline int meson_vpu_is_compatible(struct meson_drm *priv, > diff --git a/drivers/gpu/drm/meson/meson_rdma.c b/drivers/gpu/drm/meson/meson_rdma.c > new file mode 100644 > index 000000000000..13fd9b173439 > --- /dev/null > +++ b/drivers/gpu/drm/meson/meson_rdma.c > @@ -0,0 +1,123 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Copyright (C) 2019 BayLibre, SAS > + * Author: Neil Armstrong <narmstrong@xxxxxxxxxxxx> > + */ > + > +#include <linux/bitfield.h> > +#include <linux/dma-mapping.h> > + > +#include "meson_drv.h" > +#include "meson_registers.h" > +#include "meson_rdma.h" > + > +/* > + * The VPU embeds a "Register DMA" that can write a sequence of registers > + * on the VPU AHB bus, either manually or triggered by an internal IRQ > + * event like VSYNC or a line input counter. > + * The initial implementation handles a single channel (over 8), triggered > + * by the VSYNC irq and does not handle the RDMA irq. > + */ > + > +int meson_rdma_init(struct meson_drm *priv) > +{ > + /* Allocate a PAGE buffer */ Should be "Allocate a 4K buffer" > + priv->rdma.addr = dma_alloc_coherent(priv->dev, SZ_4K, > + &priv->rdma.addr_phys, > + GFP_KERNEL); > + if (!priv->rdma.addr) > + return -ENOMEM; > + > + priv->rdma.offset = 0; > + > + writel_relaxed(RDMA_CTRL_SW_RESET, > + priv->io_base + _REG(RDMA_CTRL)); > + writel_relaxed(RDMA_DEFAULT_CONFIG | > + FIELD_PREP(RDMA_CTRL_AHB_WR_BURST, 3) | > + FIELD_PREP(RDMA_CTRL_AHB_RD_BURST, 0), > + priv->io_base + _REG(RDMA_CTRL)); > + > + return 0; > +} > + > +void meson_rdma_free(struct meson_drm *priv) > +{ > + if (!priv->rdma.addr && !priv->rdma.addr_phys) > + return; > + > + meson_rdma_stop(priv); > + > + dma_free_coherent(priv->dev, SZ_4K, > + priv->rdma.addr, priv->rdma.addr_phys); > + > + priv->rdma.addr = NULL; > + priv->rdma.addr_phys = (dma_addr_t)NULL; > +} > + > +void meson_rdma_setup(struct meson_drm *priv) > +{ > + /* Channel 1: Write Flag, No Address Increment */ > + writel_bits_relaxed(RDMA_ACCESS_RW_FLAG_CHAN1 | > + RDMA_ACCESS_ADDR_INC_CHAN1, > + RDMA_ACCESS_RW_FLAG_CHAN1, > + priv->io_base + _REG(RDMA_ACCESS_AUTO)); > +} > + > +void meson_rdma_stop(struct meson_drm *priv) > +{ > + writel_bits_relaxed(RDMA_IRQ_CLEAR_CHAN1, > + RDMA_IRQ_CLEAR_CHAN1, > + priv->io_base + _REG(RDMA_CTRL)); > + > + /* Stop Channel 1 */ > + writel_bits_relaxed(RDMA_ACCESS_TRIGGER_CHAN1, > + FIELD_PREP(RDMA_ACCESS_ADDR_INC_CHAN1, > + RDMA_ACCESS_TRIGGER_STOP), > + priv->io_base + _REG(RDMA_ACCESS_AUTO)); > +} A meson_rdma_reset() call is missing to reset priv->rdma.offset and stop the RDMA and should be called by afbcd_reset instead of stop other wise the meson_rdma_writel() will overflow when not using AFBC. > + > +static void meson_rdma_writel(struct meson_drm *priv, uint32_t val, > + uint32_t reg) > +{ > + if (priv->rdma.offset == SZ_4K) { Found a regression here, should be SZ_4K/8 > + dev_warn_once(priv->dev, "%s: overflow\n", __func__); > + return; > + } > + > + priv->rdma.addr[priv->rdma.offset++] = reg; > + priv->rdma.addr[priv->rdma.offset++] = val; > +} > + > +/* > + * This will add the register to the RDMA buffer and write it to the > + * hardware at the same time. > + * When meson_rdma_flush is called, the RDMA will replay the register > + * writes in order. > + */ > +void meson_rdma_writel_sync(struct meson_drm *priv, uint32_t val, uint32_t reg) > +{ > + meson_rdma_writel(priv, val, reg); > + > + writel_relaxed(val, priv->io_base + _REG(reg)); > +} > + > +void meson_rdma_flush(struct meson_drm *priv) > +{ > + meson_rdma_stop(priv); > + > + /* Start of Channel 1 register writes buffer */ > + writel(priv->rdma.addr_phys, > + priv->io_base + _REG(RDMA_AHB_START_ADDR_1)); > + > + /* Last byte on Channel 1 register writes buffer */ > + writel(priv->rdma.addr_phys + (priv->rdma.offset * 8) - 1, 8 should have a define > + priv->io_base + _REG(RDMA_AHB_END_ADDR_1)); > + > + /* Trigger Channel 1 on VSYNC event */ > + writel_bits_relaxed(RDMA_ACCESS_TRIGGER_CHAN1, > + FIELD_PREP(RDMA_ACCESS_TRIGGER_CHAN1, > + RDMA_ACCESS_TRIGGER_VSYNC), > + priv->io_base + _REG(RDMA_ACCESS_AUTO)); > + > + priv->rdma.offset = 0; > +} > diff --git a/drivers/gpu/drm/meson/meson_rdma.h b/drivers/gpu/drm/meson/meson_rdma.h > new file mode 100644 > index 000000000000..84c882f97d28 > --- /dev/null > +++ b/drivers/gpu/drm/meson/meson_rdma.h > @@ -0,0 +1,20 @@ > +/* SPDX-License-Identifier: GPL-2.0+ */ > +/* > + * Copyright (C) 2019 BayLibre, SAS > + * Author: Neil Armstrong <narmstrong@xxxxxxxxxxxx> > + */ > + > +#ifndef __MESON_RDMA_H > +#define __MESON_RDMA_H > + > +#include "meson_drv.h" > + > +int meson_rdma_init(struct meson_drm *priv); > +void meson_rdma_free(struct meson_drm *priv); > +void meson_rdma_setup(struct meson_drm *priv); > +void meson_rdma_stop(struct meson_drm *priv); > + > +void meson_rdma_writel_sync(struct meson_drm *priv, uint32_t val, uint32_t reg); > +void meson_rdma_flush(struct meson_drm *priv); > + > +#endif /* __MESON_RDMA_H */ > Will send a V2 shortly with these fixes. Neil _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel