xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/meson/meson_rdma.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2019 BayLibre, SAS
4*4882a593Smuzhiyun  * Author: Neil Armstrong <narmstrong@baylibre.com>
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <linux/bitfield.h>
8*4882a593Smuzhiyun #include <linux/dma-mapping.h>
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include "meson_drv.h"
11*4882a593Smuzhiyun #include "meson_registers.h"
12*4882a593Smuzhiyun #include "meson_rdma.h"
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun /*
15*4882a593Smuzhiyun  * The VPU embeds a "Register DMA" that can write a sequence of registers
16*4882a593Smuzhiyun  * on the VPU AHB bus, either manually or triggered by an internal IRQ
17*4882a593Smuzhiyun  * event like VSYNC or a line input counter.
18*4882a593Smuzhiyun  * The initial implementation handles a single channel (over 8), triggered
19*4882a593Smuzhiyun  * by the VSYNC irq and does not handle the RDMA irq.
20*4882a593Smuzhiyun  */
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define RDMA_DESC_SIZE	(sizeof(uint32_t) * 2)
23*4882a593Smuzhiyun 
meson_rdma_init(struct meson_drm * priv)24*4882a593Smuzhiyun int meson_rdma_init(struct meson_drm *priv)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun 	if (!priv->rdma.addr) {
27*4882a593Smuzhiyun 		/* Allocate a PAGE buffer */
28*4882a593Smuzhiyun 		priv->rdma.addr =
29*4882a593Smuzhiyun 			dma_alloc_coherent(priv->dev, SZ_4K,
30*4882a593Smuzhiyun 					   &priv->rdma.addr_dma,
31*4882a593Smuzhiyun 					   GFP_KERNEL);
32*4882a593Smuzhiyun 		if (!priv->rdma.addr)
33*4882a593Smuzhiyun 			return -ENOMEM;
34*4882a593Smuzhiyun 	}
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	priv->rdma.offset = 0;
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	writel_relaxed(RDMA_CTRL_SW_RESET,
39*4882a593Smuzhiyun 		       priv->io_base + _REG(RDMA_CTRL));
40*4882a593Smuzhiyun 	writel_relaxed(RDMA_DEFAULT_CONFIG |
41*4882a593Smuzhiyun 		       FIELD_PREP(RDMA_CTRL_AHB_WR_BURST, 3) |
42*4882a593Smuzhiyun 		       FIELD_PREP(RDMA_CTRL_AHB_RD_BURST, 0),
43*4882a593Smuzhiyun 		       priv->io_base + _REG(RDMA_CTRL));
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	return 0;
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun 
meson_rdma_free(struct meson_drm * priv)48*4882a593Smuzhiyun void meson_rdma_free(struct meson_drm *priv)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	if (!priv->rdma.addr && !priv->rdma.addr_dma)
51*4882a593Smuzhiyun 		return;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	meson_rdma_stop(priv);
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	dma_free_coherent(priv->dev, SZ_4K,
56*4882a593Smuzhiyun 			  priv->rdma.addr, priv->rdma.addr_dma);
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	priv->rdma.addr = NULL;
59*4882a593Smuzhiyun 	priv->rdma.addr_dma = (dma_addr_t)0;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun 
meson_rdma_setup(struct meson_drm * priv)62*4882a593Smuzhiyun void meson_rdma_setup(struct meson_drm *priv)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun 	/* Channel 1: Write Flag, No Address Increment */
65*4882a593Smuzhiyun 	writel_bits_relaxed(RDMA_ACCESS_RW_FLAG_CHAN1 |
66*4882a593Smuzhiyun 			    RDMA_ACCESS_ADDR_INC_CHAN1,
67*4882a593Smuzhiyun 			    RDMA_ACCESS_RW_FLAG_CHAN1,
68*4882a593Smuzhiyun 			    priv->io_base + _REG(RDMA_ACCESS_AUTO));
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
meson_rdma_stop(struct meson_drm * priv)71*4882a593Smuzhiyun void meson_rdma_stop(struct meson_drm *priv)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun 	writel_bits_relaxed(RDMA_IRQ_CLEAR_CHAN1,
74*4882a593Smuzhiyun 			    RDMA_IRQ_CLEAR_CHAN1,
75*4882a593Smuzhiyun 			    priv->io_base + _REG(RDMA_CTRL));
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	/* Stop Channel 1 */
78*4882a593Smuzhiyun 	writel_bits_relaxed(RDMA_ACCESS_TRIGGER_CHAN1,
79*4882a593Smuzhiyun 			    FIELD_PREP(RDMA_ACCESS_ADDR_INC_CHAN1,
80*4882a593Smuzhiyun 				       RDMA_ACCESS_TRIGGER_STOP),
81*4882a593Smuzhiyun 			    priv->io_base + _REG(RDMA_ACCESS_AUTO));
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
meson_rdma_reset(struct meson_drm * priv)84*4882a593Smuzhiyun void meson_rdma_reset(struct meson_drm *priv)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun 	meson_rdma_stop(priv);
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	priv->rdma.offset = 0;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun 
meson_rdma_writel(struct meson_drm * priv,uint32_t val,uint32_t reg)91*4882a593Smuzhiyun static void meson_rdma_writel(struct meson_drm *priv, uint32_t val,
92*4882a593Smuzhiyun 			      uint32_t reg)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	if (priv->rdma.offset >= (SZ_4K / RDMA_DESC_SIZE)) {
95*4882a593Smuzhiyun 		dev_warn_once(priv->dev, "%s: overflow\n", __func__);
96*4882a593Smuzhiyun 		return;
97*4882a593Smuzhiyun 	}
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	priv->rdma.addr[priv->rdma.offset++] = reg;
100*4882a593Smuzhiyun 	priv->rdma.addr[priv->rdma.offset++] = val;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun /*
104*4882a593Smuzhiyun  * This will add the register to the RDMA buffer and write it to the
105*4882a593Smuzhiyun  * hardware at the same time.
106*4882a593Smuzhiyun  * When meson_rdma_flush is called, the RDMA will replay the register
107*4882a593Smuzhiyun  * writes in order.
108*4882a593Smuzhiyun  */
meson_rdma_writel_sync(struct meson_drm * priv,uint32_t val,uint32_t reg)109*4882a593Smuzhiyun void meson_rdma_writel_sync(struct meson_drm *priv, uint32_t val, uint32_t reg)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	meson_rdma_writel(priv, val, reg);
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	writel_relaxed(val, priv->io_base + _REG(reg));
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun 
meson_rdma_flush(struct meson_drm * priv)116*4882a593Smuzhiyun void meson_rdma_flush(struct meson_drm *priv)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun 	meson_rdma_stop(priv);
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	/* Start of Channel 1 register writes buffer */
121*4882a593Smuzhiyun 	writel(priv->rdma.addr_dma,
122*4882a593Smuzhiyun 	       priv->io_base + _REG(RDMA_AHB_START_ADDR_1));
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	/* Last byte on Channel 1 register writes buffer */
125*4882a593Smuzhiyun 	writel(priv->rdma.addr_dma + (priv->rdma.offset * RDMA_DESC_SIZE) - 1,
126*4882a593Smuzhiyun 	       priv->io_base + _REG(RDMA_AHB_END_ADDR_1));
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	/* Trigger Channel 1 on VSYNC event */
129*4882a593Smuzhiyun 	writel_bits_relaxed(RDMA_ACCESS_TRIGGER_CHAN1,
130*4882a593Smuzhiyun 			    FIELD_PREP(RDMA_ACCESS_TRIGGER_CHAN1,
131*4882a593Smuzhiyun 				       RDMA_ACCESS_TRIGGER_VSYNC),
132*4882a593Smuzhiyun 			    priv->io_base + _REG(RDMA_ACCESS_AUTO));
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	priv->rdma.offset = 0;
135*4882a593Smuzhiyun }
136