xref: /linux/drivers/gpu/ipu-v3/ipu-dmfc.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
4  * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
5  */
6 #include <linux/export.h>
7 #include <linux/types.h>
8 #include <linux/errno.h>
9 #include <linux/io.h>
10 
11 #include <video/imx-ipu-v3.h>
12 #include "ipu-prv.h"
13 
14 #define DMFC_RD_CHAN		0x0000
15 #define DMFC_WR_CHAN		0x0004
16 #define DMFC_WR_CHAN_DEF	0x0008
17 #define DMFC_DP_CHAN		0x000c
18 #define DMFC_DP_CHAN_DEF	0x0010
19 #define DMFC_GENERAL1		0x0014
20 #define DMFC_GENERAL2		0x0018
21 #define DMFC_IC_CTRL		0x001c
22 #define DMFC_WR_CHAN_ALT	0x0020
23 #define DMFC_WR_CHAN_DEF_ALT	0x0024
24 #define DMFC_DP_CHAN_ALT	0x0028
25 #define DMFC_DP_CHAN_DEF_ALT	0x002c
26 #define DMFC_GENERAL1_ALT	0x0030
27 #define DMFC_STAT		0x0034
28 
29 #define DMFC_WR_CHAN_1_28		0
30 #define DMFC_WR_CHAN_2_41		8
31 #define DMFC_WR_CHAN_1C_42		16
32 #define DMFC_WR_CHAN_2C_43		24
33 
34 #define DMFC_DP_CHAN_5B_23		0
35 #define DMFC_DP_CHAN_5F_27		8
36 #define DMFC_DP_CHAN_6B_24		16
37 #define DMFC_DP_CHAN_6F_29		24
38 
39 struct dmfc_channel_data {
40 	int		ipu_channel;
41 	unsigned long	channel_reg;
42 	unsigned long	shift;
43 	unsigned	eot_shift;
44 	unsigned	max_fifo_lines;
45 };
46 
47 static const struct dmfc_channel_data dmfcdata[] = {
48 	{
49 		.ipu_channel	= IPUV3_CHANNEL_MEM_BG_SYNC,
50 		.channel_reg	= DMFC_DP_CHAN,
51 		.shift		= DMFC_DP_CHAN_5B_23,
52 		.eot_shift	= 20,
53 		.max_fifo_lines	= 3,
54 	}, {
55 		.ipu_channel	= 24,
56 		.channel_reg	= DMFC_DP_CHAN,
57 		.shift		= DMFC_DP_CHAN_6B_24,
58 		.eot_shift	= 22,
59 		.max_fifo_lines	= 1,
60 	}, {
61 		.ipu_channel	= IPUV3_CHANNEL_MEM_FG_SYNC,
62 		.channel_reg	= DMFC_DP_CHAN,
63 		.shift		= DMFC_DP_CHAN_5F_27,
64 		.eot_shift	= 21,
65 		.max_fifo_lines	= 2,
66 	}, {
67 		.ipu_channel	= IPUV3_CHANNEL_MEM_DC_SYNC,
68 		.channel_reg	= DMFC_WR_CHAN,
69 		.shift		= DMFC_WR_CHAN_1_28,
70 		.eot_shift	= 16,
71 		.max_fifo_lines	= 2,
72 	}, {
73 		.ipu_channel	= 29,
74 		.channel_reg	= DMFC_DP_CHAN,
75 		.shift		= DMFC_DP_CHAN_6F_29,
76 		.eot_shift	= 23,
77 		.max_fifo_lines	= 1,
78 	},
79 };
80 
81 #define DMFC_NUM_CHANNELS	ARRAY_SIZE(dmfcdata)
82 
83 struct ipu_dmfc_priv;
84 
85 struct dmfc_channel {
86 	unsigned			slots;
87 	struct ipu_soc			*ipu;
88 	struct ipu_dmfc_priv		*priv;
89 	const struct dmfc_channel_data	*data;
90 };
91 
92 struct ipu_dmfc_priv {
93 	struct ipu_soc *ipu;
94 	struct device *dev;
95 	struct dmfc_channel channels[DMFC_NUM_CHANNELS];
96 	struct mutex mutex;
97 	void __iomem *base;
98 	int use_count;
99 };
100 
ipu_dmfc_enable_channel(struct dmfc_channel * dmfc)101 int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
102 {
103 	struct ipu_dmfc_priv *priv = dmfc->priv;
104 	mutex_lock(&priv->mutex);
105 
106 	if (!priv->use_count)
107 		ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
108 
109 	priv->use_count++;
110 
111 	mutex_unlock(&priv->mutex);
112 
113 	return 0;
114 }
115 EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
116 
ipu_dmfc_disable_channel(struct dmfc_channel * dmfc)117 void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
118 {
119 	struct ipu_dmfc_priv *priv = dmfc->priv;
120 
121 	mutex_lock(&priv->mutex);
122 
123 	priv->use_count--;
124 
125 	if (!priv->use_count)
126 		ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
127 
128 	if (priv->use_count < 0)
129 		priv->use_count = 0;
130 
131 	mutex_unlock(&priv->mutex);
132 }
133 EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
134 
ipu_dmfc_config_wait4eot(struct dmfc_channel * dmfc,int width)135 void ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width)
136 {
137 	struct ipu_dmfc_priv *priv = dmfc->priv;
138 	u32 dmfc_gen1;
139 
140 	mutex_lock(&priv->mutex);
141 
142 	dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
143 
144 	if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
145 		dmfc_gen1 |= 1 << dmfc->data->eot_shift;
146 	else
147 		dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
148 
149 	writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
150 
151 	mutex_unlock(&priv->mutex);
152 }
153 EXPORT_SYMBOL_GPL(ipu_dmfc_config_wait4eot);
154 
ipu_dmfc_get(struct ipu_soc * ipu,int ipu_channel)155 struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
156 {
157 	struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
158 	int i;
159 
160 	for (i = 0; i < DMFC_NUM_CHANNELS; i++)
161 		if (dmfcdata[i].ipu_channel == ipu_channel)
162 			return &priv->channels[i];
163 	return ERR_PTR(-ENODEV);
164 }
165 EXPORT_SYMBOL_GPL(ipu_dmfc_get);
166 
ipu_dmfc_put(struct dmfc_channel * dmfc)167 void ipu_dmfc_put(struct dmfc_channel *dmfc)
168 {
169 }
170 EXPORT_SYMBOL_GPL(ipu_dmfc_put);
171 
ipu_dmfc_init(struct ipu_soc * ipu,struct device * dev,unsigned long base,struct clk * ipu_clk)172 int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
173 		struct clk *ipu_clk)
174 {
175 	struct ipu_dmfc_priv *priv;
176 	int i;
177 
178 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
179 	if (!priv)
180 		return -ENOMEM;
181 
182 	priv->base = devm_ioremap(dev, base, PAGE_SIZE);
183 	if (!priv->base)
184 		return -ENOMEM;
185 
186 	priv->dev = dev;
187 	priv->ipu = ipu;
188 	mutex_init(&priv->mutex);
189 
190 	ipu->dmfc_priv = priv;
191 
192 	for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
193 		priv->channels[i].priv = priv;
194 		priv->channels[i].ipu = ipu;
195 		priv->channels[i].data = &dmfcdata[i];
196 
197 		if (dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC ||
198 		    dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_FG_SYNC ||
199 		    dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_DC_SYNC)
200 			priv->channels[i].slots = 2;
201 	}
202 
203 	writel(0x00000050, priv->base + DMFC_WR_CHAN);
204 	writel(0x00005654, priv->base + DMFC_DP_CHAN);
205 	writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
206 	writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
207 	writel(0x00000003, priv->base + DMFC_GENERAL1);
208 
209 	return 0;
210 }
211 
ipu_dmfc_exit(struct ipu_soc * ipu)212 void ipu_dmfc_exit(struct ipu_soc *ipu)
213 {
214 }
215