0001
0002
0003
0004
0005
0006
0007 #include <linux/bitfield.h>
0008 #include <linux/dma-mapping.h>
0009
0010 #include "meson_drv.h"
0011 #include "meson_registers.h"
0012 #include "meson_rdma.h"
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022 #define RDMA_DESC_SIZE (sizeof(uint32_t) * 2)
0023
0024 int meson_rdma_init(struct meson_drm *priv)
0025 {
0026 if (!priv->rdma.addr) {
0027
0028 priv->rdma.addr =
0029 dma_alloc_coherent(priv->dev, SZ_4K,
0030 &priv->rdma.addr_dma,
0031 GFP_KERNEL);
0032 if (!priv->rdma.addr)
0033 return -ENOMEM;
0034 }
0035
0036 priv->rdma.offset = 0;
0037
0038 writel_relaxed(RDMA_CTRL_SW_RESET,
0039 priv->io_base + _REG(RDMA_CTRL));
0040 writel_relaxed(RDMA_DEFAULT_CONFIG |
0041 FIELD_PREP(RDMA_CTRL_AHB_WR_BURST, 3) |
0042 FIELD_PREP(RDMA_CTRL_AHB_RD_BURST, 0),
0043 priv->io_base + _REG(RDMA_CTRL));
0044
0045 return 0;
0046 }
0047
0048 void meson_rdma_free(struct meson_drm *priv)
0049 {
0050 if (!priv->rdma.addr && !priv->rdma.addr_dma)
0051 return;
0052
0053 meson_rdma_stop(priv);
0054
0055 dma_free_coherent(priv->dev, SZ_4K,
0056 priv->rdma.addr, priv->rdma.addr_dma);
0057
0058 priv->rdma.addr = NULL;
0059 priv->rdma.addr_dma = (dma_addr_t)0;
0060 }
0061
0062 void meson_rdma_setup(struct meson_drm *priv)
0063 {
0064
0065 writel_bits_relaxed(RDMA_ACCESS_RW_FLAG_CHAN1 |
0066 RDMA_ACCESS_ADDR_INC_CHAN1,
0067 RDMA_ACCESS_RW_FLAG_CHAN1,
0068 priv->io_base + _REG(RDMA_ACCESS_AUTO));
0069 }
0070
0071 void meson_rdma_stop(struct meson_drm *priv)
0072 {
0073 writel_bits_relaxed(RDMA_IRQ_CLEAR_CHAN1,
0074 RDMA_IRQ_CLEAR_CHAN1,
0075 priv->io_base + _REG(RDMA_CTRL));
0076
0077
0078 writel_bits_relaxed(RDMA_ACCESS_TRIGGER_CHAN1,
0079 FIELD_PREP(RDMA_ACCESS_ADDR_INC_CHAN1,
0080 RDMA_ACCESS_TRIGGER_STOP),
0081 priv->io_base + _REG(RDMA_ACCESS_AUTO));
0082 }
0083
0084 void meson_rdma_reset(struct meson_drm *priv)
0085 {
0086 meson_rdma_stop(priv);
0087
0088 priv->rdma.offset = 0;
0089 }
0090
0091 static void meson_rdma_writel(struct meson_drm *priv, uint32_t val,
0092 uint32_t reg)
0093 {
0094 if (priv->rdma.offset >= (SZ_4K / RDMA_DESC_SIZE)) {
0095 dev_warn_once(priv->dev, "%s: overflow\n", __func__);
0096 return;
0097 }
0098
0099 priv->rdma.addr[priv->rdma.offset++] = reg;
0100 priv->rdma.addr[priv->rdma.offset++] = val;
0101 }
0102
0103
0104
0105
0106
0107
0108
0109 void meson_rdma_writel_sync(struct meson_drm *priv, uint32_t val, uint32_t reg)
0110 {
0111 meson_rdma_writel(priv, val, reg);
0112
0113 writel_relaxed(val, priv->io_base + _REG(reg));
0114 }
0115
0116 void meson_rdma_flush(struct meson_drm *priv)
0117 {
0118 meson_rdma_stop(priv);
0119
0120
0121 writel(priv->rdma.addr_dma,
0122 priv->io_base + _REG(RDMA_AHB_START_ADDR_1));
0123
0124
0125 writel(priv->rdma.addr_dma + (priv->rdma.offset * RDMA_DESC_SIZE) - 1,
0126 priv->io_base + _REG(RDMA_AHB_END_ADDR_1));
0127
0128
0129 writel_bits_relaxed(RDMA_ACCESS_TRIGGER_CHAN1,
0130 FIELD_PREP(RDMA_ACCESS_TRIGGER_CHAN1,
0131 RDMA_ACCESS_TRIGGER_VSYNC),
0132 priv->io_base + _REG(RDMA_ACCESS_AUTO));
0133
0134 priv->rdma.offset = 0;
0135 }