xref: /linux/drivers/gpu/ipu-v3/ipu-dmfc.c (revision 39b9004d1f626b88b775c7655d3f286e135dfec6)
1*39b9004dSPhilipp Zabel /*
2*39b9004dSPhilipp Zabel  * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
3*39b9004dSPhilipp Zabel  * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
4*39b9004dSPhilipp Zabel  *
5*39b9004dSPhilipp Zabel  * This program is free software; you can redistribute it and/or modify it
6*39b9004dSPhilipp Zabel  * under the terms of the GNU General Public License as published by the
7*39b9004dSPhilipp Zabel  * Free Software Foundation; either version 2 of the License, or (at your
8*39b9004dSPhilipp Zabel  * option) any later version.
9*39b9004dSPhilipp Zabel  *
10*39b9004dSPhilipp Zabel  * This program is distributed in the hope that it will be useful, but
11*39b9004dSPhilipp Zabel  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12*39b9004dSPhilipp Zabel  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13*39b9004dSPhilipp Zabel  * for more details.
14*39b9004dSPhilipp Zabel  */
15*39b9004dSPhilipp Zabel #include <linux/export.h>
16*39b9004dSPhilipp Zabel #include <linux/types.h>
17*39b9004dSPhilipp Zabel #include <linux/errno.h>
18*39b9004dSPhilipp Zabel #include <linux/io.h>
19*39b9004dSPhilipp Zabel 
20*39b9004dSPhilipp Zabel #include <video/imx-ipu-v3.h>
21*39b9004dSPhilipp Zabel #include "ipu-prv.h"
22*39b9004dSPhilipp Zabel 
23*39b9004dSPhilipp Zabel #define DMFC_RD_CHAN		0x0000
24*39b9004dSPhilipp Zabel #define DMFC_WR_CHAN		0x0004
25*39b9004dSPhilipp Zabel #define DMFC_WR_CHAN_DEF	0x0008
26*39b9004dSPhilipp Zabel #define DMFC_DP_CHAN		0x000c
27*39b9004dSPhilipp Zabel #define DMFC_DP_CHAN_DEF	0x0010
28*39b9004dSPhilipp Zabel #define DMFC_GENERAL1		0x0014
29*39b9004dSPhilipp Zabel #define DMFC_GENERAL2		0x0018
30*39b9004dSPhilipp Zabel #define DMFC_IC_CTRL		0x001c
31*39b9004dSPhilipp Zabel #define DMFC_STAT		0x0020
32*39b9004dSPhilipp Zabel 
33*39b9004dSPhilipp Zabel #define DMFC_WR_CHAN_1_28		0
34*39b9004dSPhilipp Zabel #define DMFC_WR_CHAN_2_41		8
35*39b9004dSPhilipp Zabel #define DMFC_WR_CHAN_1C_42		16
36*39b9004dSPhilipp Zabel #define DMFC_WR_CHAN_2C_43		24
37*39b9004dSPhilipp Zabel 
38*39b9004dSPhilipp Zabel #define DMFC_DP_CHAN_5B_23		0
39*39b9004dSPhilipp Zabel #define DMFC_DP_CHAN_5F_27		8
40*39b9004dSPhilipp Zabel #define DMFC_DP_CHAN_6B_24		16
41*39b9004dSPhilipp Zabel #define DMFC_DP_CHAN_6F_29		24
42*39b9004dSPhilipp Zabel 
43*39b9004dSPhilipp Zabel #define DMFC_FIFO_SIZE_64		(3 << 3)
44*39b9004dSPhilipp Zabel #define DMFC_FIFO_SIZE_128		(2 << 3)
45*39b9004dSPhilipp Zabel #define DMFC_FIFO_SIZE_256		(1 << 3)
46*39b9004dSPhilipp Zabel #define DMFC_FIFO_SIZE_512		(0 << 3)
47*39b9004dSPhilipp Zabel 
48*39b9004dSPhilipp Zabel #define DMFC_SEGMENT(x)			((x & 0x7) << 0)
49*39b9004dSPhilipp Zabel #define DMFC_BURSTSIZE_128		(0 << 6)
50*39b9004dSPhilipp Zabel #define DMFC_BURSTSIZE_64		(1 << 6)
51*39b9004dSPhilipp Zabel #define DMFC_BURSTSIZE_32		(2 << 6)
52*39b9004dSPhilipp Zabel #define DMFC_BURSTSIZE_16		(3 << 6)
53*39b9004dSPhilipp Zabel 
54*39b9004dSPhilipp Zabel struct dmfc_channel_data {
55*39b9004dSPhilipp Zabel 	int		ipu_channel;
56*39b9004dSPhilipp Zabel 	unsigned long	channel_reg;
57*39b9004dSPhilipp Zabel 	unsigned long	shift;
58*39b9004dSPhilipp Zabel 	unsigned	eot_shift;
59*39b9004dSPhilipp Zabel 	unsigned	max_fifo_lines;
60*39b9004dSPhilipp Zabel };
61*39b9004dSPhilipp Zabel 
62*39b9004dSPhilipp Zabel static const struct dmfc_channel_data dmfcdata[] = {
63*39b9004dSPhilipp Zabel 	{
64*39b9004dSPhilipp Zabel 		.ipu_channel	= IPUV3_CHANNEL_MEM_BG_SYNC,
65*39b9004dSPhilipp Zabel 		.channel_reg	= DMFC_DP_CHAN,
66*39b9004dSPhilipp Zabel 		.shift		= DMFC_DP_CHAN_5B_23,
67*39b9004dSPhilipp Zabel 		.eot_shift	= 20,
68*39b9004dSPhilipp Zabel 		.max_fifo_lines	= 3,
69*39b9004dSPhilipp Zabel 	}, {
70*39b9004dSPhilipp Zabel 		.ipu_channel	= 24,
71*39b9004dSPhilipp Zabel 		.channel_reg	= DMFC_DP_CHAN,
72*39b9004dSPhilipp Zabel 		.shift		= DMFC_DP_CHAN_6B_24,
73*39b9004dSPhilipp Zabel 		.eot_shift	= 22,
74*39b9004dSPhilipp Zabel 		.max_fifo_lines	= 1,
75*39b9004dSPhilipp Zabel 	}, {
76*39b9004dSPhilipp Zabel 		.ipu_channel	= IPUV3_CHANNEL_MEM_FG_SYNC,
77*39b9004dSPhilipp Zabel 		.channel_reg	= DMFC_DP_CHAN,
78*39b9004dSPhilipp Zabel 		.shift		= DMFC_DP_CHAN_5F_27,
79*39b9004dSPhilipp Zabel 		.eot_shift	= 21,
80*39b9004dSPhilipp Zabel 		.max_fifo_lines	= 2,
81*39b9004dSPhilipp Zabel 	}, {
82*39b9004dSPhilipp Zabel 		.ipu_channel	= IPUV3_CHANNEL_MEM_DC_SYNC,
83*39b9004dSPhilipp Zabel 		.channel_reg	= DMFC_WR_CHAN,
84*39b9004dSPhilipp Zabel 		.shift		= DMFC_WR_CHAN_1_28,
85*39b9004dSPhilipp Zabel 		.eot_shift	= 16,
86*39b9004dSPhilipp Zabel 		.max_fifo_lines	= 2,
87*39b9004dSPhilipp Zabel 	}, {
88*39b9004dSPhilipp Zabel 		.ipu_channel	= 29,
89*39b9004dSPhilipp Zabel 		.channel_reg	= DMFC_DP_CHAN,
90*39b9004dSPhilipp Zabel 		.shift		= DMFC_DP_CHAN_6F_29,
91*39b9004dSPhilipp Zabel 		.eot_shift	= 23,
92*39b9004dSPhilipp Zabel 		.max_fifo_lines	= 1,
93*39b9004dSPhilipp Zabel 	},
94*39b9004dSPhilipp Zabel };
95*39b9004dSPhilipp Zabel 
96*39b9004dSPhilipp Zabel #define DMFC_NUM_CHANNELS	ARRAY_SIZE(dmfcdata)
97*39b9004dSPhilipp Zabel 
98*39b9004dSPhilipp Zabel struct ipu_dmfc_priv;
99*39b9004dSPhilipp Zabel 
100*39b9004dSPhilipp Zabel struct dmfc_channel {
101*39b9004dSPhilipp Zabel 	unsigned			slots;
102*39b9004dSPhilipp Zabel 	unsigned			slotmask;
103*39b9004dSPhilipp Zabel 	unsigned			segment;
104*39b9004dSPhilipp Zabel 	int				burstsize;
105*39b9004dSPhilipp Zabel 	struct ipu_soc			*ipu;
106*39b9004dSPhilipp Zabel 	struct ipu_dmfc_priv		*priv;
107*39b9004dSPhilipp Zabel 	const struct dmfc_channel_data	*data;
108*39b9004dSPhilipp Zabel };
109*39b9004dSPhilipp Zabel 
110*39b9004dSPhilipp Zabel struct ipu_dmfc_priv {
111*39b9004dSPhilipp Zabel 	struct ipu_soc *ipu;
112*39b9004dSPhilipp Zabel 	struct device *dev;
113*39b9004dSPhilipp Zabel 	struct dmfc_channel channels[DMFC_NUM_CHANNELS];
114*39b9004dSPhilipp Zabel 	struct mutex mutex;
115*39b9004dSPhilipp Zabel 	unsigned long bandwidth_per_slot;
116*39b9004dSPhilipp Zabel 	void __iomem *base;
117*39b9004dSPhilipp Zabel 	int use_count;
118*39b9004dSPhilipp Zabel };
119*39b9004dSPhilipp Zabel 
120*39b9004dSPhilipp Zabel int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
121*39b9004dSPhilipp Zabel {
122*39b9004dSPhilipp Zabel 	struct ipu_dmfc_priv *priv = dmfc->priv;
123*39b9004dSPhilipp Zabel 	mutex_lock(&priv->mutex);
124*39b9004dSPhilipp Zabel 
125*39b9004dSPhilipp Zabel 	if (!priv->use_count)
126*39b9004dSPhilipp Zabel 		ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
127*39b9004dSPhilipp Zabel 
128*39b9004dSPhilipp Zabel 	priv->use_count++;
129*39b9004dSPhilipp Zabel 
130*39b9004dSPhilipp Zabel 	mutex_unlock(&priv->mutex);
131*39b9004dSPhilipp Zabel 
132*39b9004dSPhilipp Zabel 	return 0;
133*39b9004dSPhilipp Zabel }
134*39b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
135*39b9004dSPhilipp Zabel 
136*39b9004dSPhilipp Zabel void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
137*39b9004dSPhilipp Zabel {
138*39b9004dSPhilipp Zabel 	struct ipu_dmfc_priv *priv = dmfc->priv;
139*39b9004dSPhilipp Zabel 
140*39b9004dSPhilipp Zabel 	mutex_lock(&priv->mutex);
141*39b9004dSPhilipp Zabel 
142*39b9004dSPhilipp Zabel 	priv->use_count--;
143*39b9004dSPhilipp Zabel 
144*39b9004dSPhilipp Zabel 	if (!priv->use_count)
145*39b9004dSPhilipp Zabel 		ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
146*39b9004dSPhilipp Zabel 
147*39b9004dSPhilipp Zabel 	if (priv->use_count < 0)
148*39b9004dSPhilipp Zabel 		priv->use_count = 0;
149*39b9004dSPhilipp Zabel 
150*39b9004dSPhilipp Zabel 	mutex_unlock(&priv->mutex);
151*39b9004dSPhilipp Zabel }
152*39b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
153*39b9004dSPhilipp Zabel 
154*39b9004dSPhilipp Zabel static int ipu_dmfc_setup_channel(struct dmfc_channel *dmfc, int slots,
155*39b9004dSPhilipp Zabel 		int segment, int burstsize)
156*39b9004dSPhilipp Zabel {
157*39b9004dSPhilipp Zabel 	struct ipu_dmfc_priv *priv = dmfc->priv;
158*39b9004dSPhilipp Zabel 	u32 val, field;
159*39b9004dSPhilipp Zabel 
160*39b9004dSPhilipp Zabel 	dev_dbg(priv->dev,
161*39b9004dSPhilipp Zabel 			"dmfc: using %d slots starting from segment %d for IPU channel %d\n",
162*39b9004dSPhilipp Zabel 			slots, segment, dmfc->data->ipu_channel);
163*39b9004dSPhilipp Zabel 
164*39b9004dSPhilipp Zabel 	switch (slots) {
165*39b9004dSPhilipp Zabel 	case 1:
166*39b9004dSPhilipp Zabel 		field = DMFC_FIFO_SIZE_64;
167*39b9004dSPhilipp Zabel 		break;
168*39b9004dSPhilipp Zabel 	case 2:
169*39b9004dSPhilipp Zabel 		field = DMFC_FIFO_SIZE_128;
170*39b9004dSPhilipp Zabel 		break;
171*39b9004dSPhilipp Zabel 	case 4:
172*39b9004dSPhilipp Zabel 		field = DMFC_FIFO_SIZE_256;
173*39b9004dSPhilipp Zabel 		break;
174*39b9004dSPhilipp Zabel 	case 8:
175*39b9004dSPhilipp Zabel 		field = DMFC_FIFO_SIZE_512;
176*39b9004dSPhilipp Zabel 		break;
177*39b9004dSPhilipp Zabel 	default:
178*39b9004dSPhilipp Zabel 		return -EINVAL;
179*39b9004dSPhilipp Zabel 	}
180*39b9004dSPhilipp Zabel 
181*39b9004dSPhilipp Zabel 	switch (burstsize) {
182*39b9004dSPhilipp Zabel 	case 16:
183*39b9004dSPhilipp Zabel 		field |= DMFC_BURSTSIZE_16;
184*39b9004dSPhilipp Zabel 		break;
185*39b9004dSPhilipp Zabel 	case 32:
186*39b9004dSPhilipp Zabel 		field |= DMFC_BURSTSIZE_32;
187*39b9004dSPhilipp Zabel 		break;
188*39b9004dSPhilipp Zabel 	case 64:
189*39b9004dSPhilipp Zabel 		field |= DMFC_BURSTSIZE_64;
190*39b9004dSPhilipp Zabel 		break;
191*39b9004dSPhilipp Zabel 	case 128:
192*39b9004dSPhilipp Zabel 		field |= DMFC_BURSTSIZE_128;
193*39b9004dSPhilipp Zabel 		break;
194*39b9004dSPhilipp Zabel 	}
195*39b9004dSPhilipp Zabel 
196*39b9004dSPhilipp Zabel 	field |= DMFC_SEGMENT(segment);
197*39b9004dSPhilipp Zabel 
198*39b9004dSPhilipp Zabel 	val = readl(priv->base + dmfc->data->channel_reg);
199*39b9004dSPhilipp Zabel 
200*39b9004dSPhilipp Zabel 	val &= ~(0xff << dmfc->data->shift);
201*39b9004dSPhilipp Zabel 	val |= field << dmfc->data->shift;
202*39b9004dSPhilipp Zabel 
203*39b9004dSPhilipp Zabel 	writel(val, priv->base + dmfc->data->channel_reg);
204*39b9004dSPhilipp Zabel 
205*39b9004dSPhilipp Zabel 	dmfc->slots = slots;
206*39b9004dSPhilipp Zabel 	dmfc->segment = segment;
207*39b9004dSPhilipp Zabel 	dmfc->burstsize = burstsize;
208*39b9004dSPhilipp Zabel 	dmfc->slotmask = ((1 << slots) - 1) << segment;
209*39b9004dSPhilipp Zabel 
210*39b9004dSPhilipp Zabel 	return 0;
211*39b9004dSPhilipp Zabel }
212*39b9004dSPhilipp Zabel 
213*39b9004dSPhilipp Zabel static int dmfc_bandwidth_to_slots(struct ipu_dmfc_priv *priv,
214*39b9004dSPhilipp Zabel 		unsigned long bandwidth)
215*39b9004dSPhilipp Zabel {
216*39b9004dSPhilipp Zabel 	int slots = 1;
217*39b9004dSPhilipp Zabel 
218*39b9004dSPhilipp Zabel 	while (slots * priv->bandwidth_per_slot < bandwidth)
219*39b9004dSPhilipp Zabel 		slots *= 2;
220*39b9004dSPhilipp Zabel 
221*39b9004dSPhilipp Zabel 	return slots;
222*39b9004dSPhilipp Zabel }
223*39b9004dSPhilipp Zabel 
224*39b9004dSPhilipp Zabel static int dmfc_find_slots(struct ipu_dmfc_priv *priv, int slots)
225*39b9004dSPhilipp Zabel {
226*39b9004dSPhilipp Zabel 	unsigned slotmask_need, slotmask_used = 0;
227*39b9004dSPhilipp Zabel 	int i, segment = 0;
228*39b9004dSPhilipp Zabel 
229*39b9004dSPhilipp Zabel 	slotmask_need = (1 << slots) - 1;
230*39b9004dSPhilipp Zabel 
231*39b9004dSPhilipp Zabel 	for (i = 0; i < DMFC_NUM_CHANNELS; i++)
232*39b9004dSPhilipp Zabel 		slotmask_used |= priv->channels[i].slotmask;
233*39b9004dSPhilipp Zabel 
234*39b9004dSPhilipp Zabel 	while (slotmask_need <= 0xff) {
235*39b9004dSPhilipp Zabel 		if (!(slotmask_used & slotmask_need))
236*39b9004dSPhilipp Zabel 			return segment;
237*39b9004dSPhilipp Zabel 
238*39b9004dSPhilipp Zabel 		slotmask_need <<= 1;
239*39b9004dSPhilipp Zabel 		segment++;
240*39b9004dSPhilipp Zabel 	}
241*39b9004dSPhilipp Zabel 
242*39b9004dSPhilipp Zabel 	return -EBUSY;
243*39b9004dSPhilipp Zabel }
244*39b9004dSPhilipp Zabel 
245*39b9004dSPhilipp Zabel void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc)
246*39b9004dSPhilipp Zabel {
247*39b9004dSPhilipp Zabel 	struct ipu_dmfc_priv *priv = dmfc->priv;
248*39b9004dSPhilipp Zabel 	int i;
249*39b9004dSPhilipp Zabel 
250*39b9004dSPhilipp Zabel 	dev_dbg(priv->dev, "dmfc: freeing %d slots starting from segment %d\n",
251*39b9004dSPhilipp Zabel 			dmfc->slots, dmfc->segment);
252*39b9004dSPhilipp Zabel 
253*39b9004dSPhilipp Zabel 	mutex_lock(&priv->mutex);
254*39b9004dSPhilipp Zabel 
255*39b9004dSPhilipp Zabel 	if (!dmfc->slots)
256*39b9004dSPhilipp Zabel 		goto out;
257*39b9004dSPhilipp Zabel 
258*39b9004dSPhilipp Zabel 	dmfc->slotmask = 0;
259*39b9004dSPhilipp Zabel 	dmfc->slots = 0;
260*39b9004dSPhilipp Zabel 	dmfc->segment = 0;
261*39b9004dSPhilipp Zabel 
262*39b9004dSPhilipp Zabel 	for (i = 0; i < DMFC_NUM_CHANNELS; i++)
263*39b9004dSPhilipp Zabel 		priv->channels[i].slotmask = 0;
264*39b9004dSPhilipp Zabel 
265*39b9004dSPhilipp Zabel 	for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
266*39b9004dSPhilipp Zabel 		if (priv->channels[i].slots > 0) {
267*39b9004dSPhilipp Zabel 			priv->channels[i].segment =
268*39b9004dSPhilipp Zabel 				dmfc_find_slots(priv, priv->channels[i].slots);
269*39b9004dSPhilipp Zabel 			priv->channels[i].slotmask =
270*39b9004dSPhilipp Zabel 				((1 << priv->channels[i].slots) - 1) <<
271*39b9004dSPhilipp Zabel 				priv->channels[i].segment;
272*39b9004dSPhilipp Zabel 		}
273*39b9004dSPhilipp Zabel 	}
274*39b9004dSPhilipp Zabel 
275*39b9004dSPhilipp Zabel 	for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
276*39b9004dSPhilipp Zabel 		if (priv->channels[i].slots > 0)
277*39b9004dSPhilipp Zabel 			ipu_dmfc_setup_channel(&priv->channels[i],
278*39b9004dSPhilipp Zabel 					priv->channels[i].slots,
279*39b9004dSPhilipp Zabel 					priv->channels[i].segment,
280*39b9004dSPhilipp Zabel 					priv->channels[i].burstsize);
281*39b9004dSPhilipp Zabel 	}
282*39b9004dSPhilipp Zabel out:
283*39b9004dSPhilipp Zabel 	mutex_unlock(&priv->mutex);
284*39b9004dSPhilipp Zabel }
285*39b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_free_bandwidth);
286*39b9004dSPhilipp Zabel 
287*39b9004dSPhilipp Zabel int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc,
288*39b9004dSPhilipp Zabel 		unsigned long bandwidth_pixel_per_second, int burstsize)
289*39b9004dSPhilipp Zabel {
290*39b9004dSPhilipp Zabel 	struct ipu_dmfc_priv *priv = dmfc->priv;
291*39b9004dSPhilipp Zabel 	int slots = dmfc_bandwidth_to_slots(priv, bandwidth_pixel_per_second);
292*39b9004dSPhilipp Zabel 	int segment = -1, ret = 0;
293*39b9004dSPhilipp Zabel 
294*39b9004dSPhilipp Zabel 	dev_dbg(priv->dev, "dmfc: trying to allocate %ldMpixel/s for IPU channel %d\n",
295*39b9004dSPhilipp Zabel 			bandwidth_pixel_per_second / 1000000,
296*39b9004dSPhilipp Zabel 			dmfc->data->ipu_channel);
297*39b9004dSPhilipp Zabel 
298*39b9004dSPhilipp Zabel 	ipu_dmfc_free_bandwidth(dmfc);
299*39b9004dSPhilipp Zabel 
300*39b9004dSPhilipp Zabel 	mutex_lock(&priv->mutex);
301*39b9004dSPhilipp Zabel 
302*39b9004dSPhilipp Zabel 	if (slots > 8) {
303*39b9004dSPhilipp Zabel 		ret = -EBUSY;
304*39b9004dSPhilipp Zabel 		goto out;
305*39b9004dSPhilipp Zabel 	}
306*39b9004dSPhilipp Zabel 
307*39b9004dSPhilipp Zabel 	/* For the MEM_BG channel, first try to allocate twice the slots */
308*39b9004dSPhilipp Zabel 	if (dmfc->data->ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC)
309*39b9004dSPhilipp Zabel 		segment = dmfc_find_slots(priv, slots * 2);
310*39b9004dSPhilipp Zabel 	else if (slots < 2)
311*39b9004dSPhilipp Zabel 		/* Always allocate at least 128*4 bytes (2 slots) */
312*39b9004dSPhilipp Zabel 		slots = 2;
313*39b9004dSPhilipp Zabel 
314*39b9004dSPhilipp Zabel 	if (segment >= 0)
315*39b9004dSPhilipp Zabel 		slots *= 2;
316*39b9004dSPhilipp Zabel 	else
317*39b9004dSPhilipp Zabel 		segment = dmfc_find_slots(priv, slots);
318*39b9004dSPhilipp Zabel 	if (segment < 0) {
319*39b9004dSPhilipp Zabel 		ret = -EBUSY;
320*39b9004dSPhilipp Zabel 		goto out;
321*39b9004dSPhilipp Zabel 	}
322*39b9004dSPhilipp Zabel 
323*39b9004dSPhilipp Zabel 	ipu_dmfc_setup_channel(dmfc, slots, segment, burstsize);
324*39b9004dSPhilipp Zabel 
325*39b9004dSPhilipp Zabel out:
326*39b9004dSPhilipp Zabel 	mutex_unlock(&priv->mutex);
327*39b9004dSPhilipp Zabel 
328*39b9004dSPhilipp Zabel 	return ret;
329*39b9004dSPhilipp Zabel }
330*39b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_alloc_bandwidth);
331*39b9004dSPhilipp Zabel 
332*39b9004dSPhilipp Zabel int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width)
333*39b9004dSPhilipp Zabel {
334*39b9004dSPhilipp Zabel 	struct ipu_dmfc_priv *priv = dmfc->priv;
335*39b9004dSPhilipp Zabel 	u32 dmfc_gen1;
336*39b9004dSPhilipp Zabel 
337*39b9004dSPhilipp Zabel 	dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
338*39b9004dSPhilipp Zabel 
339*39b9004dSPhilipp Zabel 	if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
340*39b9004dSPhilipp Zabel 		dmfc_gen1 |= 1 << dmfc->data->eot_shift;
341*39b9004dSPhilipp Zabel 	else
342*39b9004dSPhilipp Zabel 		dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
343*39b9004dSPhilipp Zabel 
344*39b9004dSPhilipp Zabel 	writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
345*39b9004dSPhilipp Zabel 
346*39b9004dSPhilipp Zabel 	return 0;
347*39b9004dSPhilipp Zabel }
348*39b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_init_channel);
349*39b9004dSPhilipp Zabel 
350*39b9004dSPhilipp Zabel struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
351*39b9004dSPhilipp Zabel {
352*39b9004dSPhilipp Zabel 	struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
353*39b9004dSPhilipp Zabel 	int i;
354*39b9004dSPhilipp Zabel 
355*39b9004dSPhilipp Zabel 	for (i = 0; i < DMFC_NUM_CHANNELS; i++)
356*39b9004dSPhilipp Zabel 		if (dmfcdata[i].ipu_channel == ipu_channel)
357*39b9004dSPhilipp Zabel 			return &priv->channels[i];
358*39b9004dSPhilipp Zabel 	return ERR_PTR(-ENODEV);
359*39b9004dSPhilipp Zabel }
360*39b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_get);
361*39b9004dSPhilipp Zabel 
362*39b9004dSPhilipp Zabel void ipu_dmfc_put(struct dmfc_channel *dmfc)
363*39b9004dSPhilipp Zabel {
364*39b9004dSPhilipp Zabel 	ipu_dmfc_free_bandwidth(dmfc);
365*39b9004dSPhilipp Zabel }
366*39b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_put);
367*39b9004dSPhilipp Zabel 
368*39b9004dSPhilipp Zabel int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
369*39b9004dSPhilipp Zabel 		struct clk *ipu_clk)
370*39b9004dSPhilipp Zabel {
371*39b9004dSPhilipp Zabel 	struct ipu_dmfc_priv *priv;
372*39b9004dSPhilipp Zabel 	int i;
373*39b9004dSPhilipp Zabel 
374*39b9004dSPhilipp Zabel 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
375*39b9004dSPhilipp Zabel 	if (!priv)
376*39b9004dSPhilipp Zabel 		return -ENOMEM;
377*39b9004dSPhilipp Zabel 
378*39b9004dSPhilipp Zabel 	priv->base = devm_ioremap(dev, base, PAGE_SIZE);
379*39b9004dSPhilipp Zabel 	if (!priv->base)
380*39b9004dSPhilipp Zabel 		return -ENOMEM;
381*39b9004dSPhilipp Zabel 
382*39b9004dSPhilipp Zabel 	priv->dev = dev;
383*39b9004dSPhilipp Zabel 	priv->ipu = ipu;
384*39b9004dSPhilipp Zabel 	mutex_init(&priv->mutex);
385*39b9004dSPhilipp Zabel 
386*39b9004dSPhilipp Zabel 	ipu->dmfc_priv = priv;
387*39b9004dSPhilipp Zabel 
388*39b9004dSPhilipp Zabel 	for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
389*39b9004dSPhilipp Zabel 		priv->channels[i].priv = priv;
390*39b9004dSPhilipp Zabel 		priv->channels[i].ipu = ipu;
391*39b9004dSPhilipp Zabel 		priv->channels[i].data = &dmfcdata[i];
392*39b9004dSPhilipp Zabel 	}
393*39b9004dSPhilipp Zabel 
394*39b9004dSPhilipp Zabel 	writel(0x0, priv->base + DMFC_WR_CHAN);
395*39b9004dSPhilipp Zabel 	writel(0x0, priv->base + DMFC_DP_CHAN);
396*39b9004dSPhilipp Zabel 
397*39b9004dSPhilipp Zabel 	/*
398*39b9004dSPhilipp Zabel 	 * We have a total bandwidth of clkrate * 4pixel divided
399*39b9004dSPhilipp Zabel 	 * into 8 slots.
400*39b9004dSPhilipp Zabel 	 */
401*39b9004dSPhilipp Zabel 	priv->bandwidth_per_slot = clk_get_rate(ipu_clk) * 4 / 8;
402*39b9004dSPhilipp Zabel 
403*39b9004dSPhilipp Zabel 	dev_dbg(dev, "dmfc: 8 slots with %ldMpixel/s bandwidth each\n",
404*39b9004dSPhilipp Zabel 			priv->bandwidth_per_slot / 1000000);
405*39b9004dSPhilipp Zabel 
406*39b9004dSPhilipp Zabel 	writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
407*39b9004dSPhilipp Zabel 	writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
408*39b9004dSPhilipp Zabel 	writel(0x00000003, priv->base + DMFC_GENERAL1);
409*39b9004dSPhilipp Zabel 
410*39b9004dSPhilipp Zabel 	return 0;
411*39b9004dSPhilipp Zabel }
412*39b9004dSPhilipp Zabel 
413*39b9004dSPhilipp Zabel void ipu_dmfc_exit(struct ipu_soc *ipu)
414*39b9004dSPhilipp Zabel {
415*39b9004dSPhilipp Zabel }
416