xref: /linux/drivers/gpu/ipu-v3/ipu-dmfc.c (revision 682b7c1c8ea8885aa681ddf530d6cf2ad4f2dc15)
139b9004dSPhilipp Zabel /*
239b9004dSPhilipp Zabel  * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
339b9004dSPhilipp Zabel  * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
439b9004dSPhilipp Zabel  *
539b9004dSPhilipp Zabel  * This program is free software; you can redistribute it and/or modify it
639b9004dSPhilipp Zabel  * under the terms of the GNU General Public License as published by the
739b9004dSPhilipp Zabel  * Free Software Foundation; either version 2 of the License, or (at your
839b9004dSPhilipp Zabel  * option) any later version.
939b9004dSPhilipp Zabel  *
1039b9004dSPhilipp Zabel  * This program is distributed in the hope that it will be useful, but
1139b9004dSPhilipp Zabel  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1239b9004dSPhilipp Zabel  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1339b9004dSPhilipp Zabel  * for more details.
1439b9004dSPhilipp Zabel  */
1539b9004dSPhilipp Zabel #include <linux/export.h>
1639b9004dSPhilipp Zabel #include <linux/types.h>
1739b9004dSPhilipp Zabel #include <linux/errno.h>
1839b9004dSPhilipp Zabel #include <linux/io.h>
1939b9004dSPhilipp Zabel 
2039b9004dSPhilipp Zabel #include <video/imx-ipu-v3.h>
2139b9004dSPhilipp Zabel #include "ipu-prv.h"
2239b9004dSPhilipp Zabel 
2339b9004dSPhilipp Zabel #define DMFC_RD_CHAN		0x0000
2439b9004dSPhilipp Zabel #define DMFC_WR_CHAN		0x0004
2539b9004dSPhilipp Zabel #define DMFC_WR_CHAN_DEF	0x0008
2639b9004dSPhilipp Zabel #define DMFC_DP_CHAN		0x000c
2739b9004dSPhilipp Zabel #define DMFC_DP_CHAN_DEF	0x0010
2839b9004dSPhilipp Zabel #define DMFC_GENERAL1		0x0014
2939b9004dSPhilipp Zabel #define DMFC_GENERAL2		0x0018
3039b9004dSPhilipp Zabel #define DMFC_IC_CTRL		0x001c
31*682b7c1cSLinus Torvalds #define DMFC_WR_CHAN_ALT	0x0020
32*682b7c1cSLinus Torvalds #define DMFC_WR_CHAN_DEF_ALT	0x0024
33*682b7c1cSLinus Torvalds #define DMFC_DP_CHAN_ALT	0x0028
34*682b7c1cSLinus Torvalds #define DMFC_DP_CHAN_DEF_ALT	0x002c
35*682b7c1cSLinus Torvalds #define DMFC_GENERAL1_ALT	0x0030
36*682b7c1cSLinus Torvalds #define DMFC_STAT		0x0034
3739b9004dSPhilipp Zabel 
3839b9004dSPhilipp Zabel #define DMFC_WR_CHAN_1_28		0
3939b9004dSPhilipp Zabel #define DMFC_WR_CHAN_2_41		8
4039b9004dSPhilipp Zabel #define DMFC_WR_CHAN_1C_42		16
4139b9004dSPhilipp Zabel #define DMFC_WR_CHAN_2C_43		24
4239b9004dSPhilipp Zabel 
4339b9004dSPhilipp Zabel #define DMFC_DP_CHAN_5B_23		0
4439b9004dSPhilipp Zabel #define DMFC_DP_CHAN_5F_27		8
4539b9004dSPhilipp Zabel #define DMFC_DP_CHAN_6B_24		16
4639b9004dSPhilipp Zabel #define DMFC_DP_CHAN_6F_29		24
4739b9004dSPhilipp Zabel 
4839b9004dSPhilipp Zabel #define DMFC_FIFO_SIZE_64		(3 << 3)
4939b9004dSPhilipp Zabel #define DMFC_FIFO_SIZE_128		(2 << 3)
5039b9004dSPhilipp Zabel #define DMFC_FIFO_SIZE_256		(1 << 3)
5139b9004dSPhilipp Zabel #define DMFC_FIFO_SIZE_512		(0 << 3)
5239b9004dSPhilipp Zabel 
5339b9004dSPhilipp Zabel #define DMFC_SEGMENT(x)			((x & 0x7) << 0)
5439b9004dSPhilipp Zabel #define DMFC_BURSTSIZE_128		(0 << 6)
5539b9004dSPhilipp Zabel #define DMFC_BURSTSIZE_64		(1 << 6)
5639b9004dSPhilipp Zabel #define DMFC_BURSTSIZE_32		(2 << 6)
5739b9004dSPhilipp Zabel #define DMFC_BURSTSIZE_16		(3 << 6)
5839b9004dSPhilipp Zabel 
5939b9004dSPhilipp Zabel struct dmfc_channel_data {
6039b9004dSPhilipp Zabel 	int		ipu_channel;
6139b9004dSPhilipp Zabel 	unsigned long	channel_reg;
6239b9004dSPhilipp Zabel 	unsigned long	shift;
6339b9004dSPhilipp Zabel 	unsigned	eot_shift;
6439b9004dSPhilipp Zabel 	unsigned	max_fifo_lines;
6539b9004dSPhilipp Zabel };
6639b9004dSPhilipp Zabel 
6739b9004dSPhilipp Zabel static const struct dmfc_channel_data dmfcdata[] = {
6839b9004dSPhilipp Zabel 	{
6939b9004dSPhilipp Zabel 		.ipu_channel	= IPUV3_CHANNEL_MEM_BG_SYNC,
7039b9004dSPhilipp Zabel 		.channel_reg	= DMFC_DP_CHAN,
7139b9004dSPhilipp Zabel 		.shift		= DMFC_DP_CHAN_5B_23,
7239b9004dSPhilipp Zabel 		.eot_shift	= 20,
7339b9004dSPhilipp Zabel 		.max_fifo_lines	= 3,
7439b9004dSPhilipp Zabel 	}, {
7539b9004dSPhilipp Zabel 		.ipu_channel	= 24,
7639b9004dSPhilipp Zabel 		.channel_reg	= DMFC_DP_CHAN,
7739b9004dSPhilipp Zabel 		.shift		= DMFC_DP_CHAN_6B_24,
7839b9004dSPhilipp Zabel 		.eot_shift	= 22,
7939b9004dSPhilipp Zabel 		.max_fifo_lines	= 1,
8039b9004dSPhilipp Zabel 	}, {
8139b9004dSPhilipp Zabel 		.ipu_channel	= IPUV3_CHANNEL_MEM_FG_SYNC,
8239b9004dSPhilipp Zabel 		.channel_reg	= DMFC_DP_CHAN,
8339b9004dSPhilipp Zabel 		.shift		= DMFC_DP_CHAN_5F_27,
8439b9004dSPhilipp Zabel 		.eot_shift	= 21,
8539b9004dSPhilipp Zabel 		.max_fifo_lines	= 2,
8639b9004dSPhilipp Zabel 	}, {
8739b9004dSPhilipp Zabel 		.ipu_channel	= IPUV3_CHANNEL_MEM_DC_SYNC,
8839b9004dSPhilipp Zabel 		.channel_reg	= DMFC_WR_CHAN,
8939b9004dSPhilipp Zabel 		.shift		= DMFC_WR_CHAN_1_28,
9039b9004dSPhilipp Zabel 		.eot_shift	= 16,
9139b9004dSPhilipp Zabel 		.max_fifo_lines	= 2,
9239b9004dSPhilipp Zabel 	}, {
9339b9004dSPhilipp Zabel 		.ipu_channel	= 29,
9439b9004dSPhilipp Zabel 		.channel_reg	= DMFC_DP_CHAN,
9539b9004dSPhilipp Zabel 		.shift		= DMFC_DP_CHAN_6F_29,
9639b9004dSPhilipp Zabel 		.eot_shift	= 23,
9739b9004dSPhilipp Zabel 		.max_fifo_lines	= 1,
9839b9004dSPhilipp Zabel 	},
9939b9004dSPhilipp Zabel };
10039b9004dSPhilipp Zabel 
10139b9004dSPhilipp Zabel #define DMFC_NUM_CHANNELS	ARRAY_SIZE(dmfcdata)
10239b9004dSPhilipp Zabel 
10339b9004dSPhilipp Zabel struct ipu_dmfc_priv;
10439b9004dSPhilipp Zabel 
10539b9004dSPhilipp Zabel struct dmfc_channel {
10639b9004dSPhilipp Zabel 	unsigned			slots;
10739b9004dSPhilipp Zabel 	unsigned			slotmask;
10839b9004dSPhilipp Zabel 	unsigned			segment;
10939b9004dSPhilipp Zabel 	int				burstsize;
11039b9004dSPhilipp Zabel 	struct ipu_soc			*ipu;
11139b9004dSPhilipp Zabel 	struct ipu_dmfc_priv		*priv;
11239b9004dSPhilipp Zabel 	const struct dmfc_channel_data	*data;
11339b9004dSPhilipp Zabel };
11439b9004dSPhilipp Zabel 
11539b9004dSPhilipp Zabel struct ipu_dmfc_priv {
11639b9004dSPhilipp Zabel 	struct ipu_soc *ipu;
11739b9004dSPhilipp Zabel 	struct device *dev;
11839b9004dSPhilipp Zabel 	struct dmfc_channel channels[DMFC_NUM_CHANNELS];
11939b9004dSPhilipp Zabel 	struct mutex mutex;
12039b9004dSPhilipp Zabel 	unsigned long bandwidth_per_slot;
12139b9004dSPhilipp Zabel 	void __iomem *base;
12239b9004dSPhilipp Zabel 	int use_count;
12339b9004dSPhilipp Zabel };
12439b9004dSPhilipp Zabel 
12539b9004dSPhilipp Zabel int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
12639b9004dSPhilipp Zabel {
12739b9004dSPhilipp Zabel 	struct ipu_dmfc_priv *priv = dmfc->priv;
12839b9004dSPhilipp Zabel 	mutex_lock(&priv->mutex);
12939b9004dSPhilipp Zabel 
13039b9004dSPhilipp Zabel 	if (!priv->use_count)
13139b9004dSPhilipp Zabel 		ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
13239b9004dSPhilipp Zabel 
13339b9004dSPhilipp Zabel 	priv->use_count++;
13439b9004dSPhilipp Zabel 
13539b9004dSPhilipp Zabel 	mutex_unlock(&priv->mutex);
13639b9004dSPhilipp Zabel 
13739b9004dSPhilipp Zabel 	return 0;
13839b9004dSPhilipp Zabel }
13939b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
14039b9004dSPhilipp Zabel 
141*682b7c1cSLinus Torvalds static void ipu_dmfc_wait_fifos(struct ipu_dmfc_priv *priv)
142*682b7c1cSLinus Torvalds {
143*682b7c1cSLinus Torvalds 	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
144*682b7c1cSLinus Torvalds 
145*682b7c1cSLinus Torvalds 	while ((readl(priv->base + DMFC_STAT) & 0x02fff000) != 0x02fff000) {
146*682b7c1cSLinus Torvalds 		if (time_after(jiffies, timeout)) {
147*682b7c1cSLinus Torvalds 			dev_warn(priv->dev,
148*682b7c1cSLinus Torvalds 				 "Timeout waiting for DMFC FIFOs to clear\n");
149*682b7c1cSLinus Torvalds 			break;
150*682b7c1cSLinus Torvalds 		}
151*682b7c1cSLinus Torvalds 		cpu_relax();
152*682b7c1cSLinus Torvalds 	}
153*682b7c1cSLinus Torvalds }
154*682b7c1cSLinus Torvalds 
15539b9004dSPhilipp Zabel void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
15639b9004dSPhilipp Zabel {
15739b9004dSPhilipp Zabel 	struct ipu_dmfc_priv *priv = dmfc->priv;
15839b9004dSPhilipp Zabel 
15939b9004dSPhilipp Zabel 	mutex_lock(&priv->mutex);
16039b9004dSPhilipp Zabel 
16139b9004dSPhilipp Zabel 	priv->use_count--;
16239b9004dSPhilipp Zabel 
163*682b7c1cSLinus Torvalds 	if (!priv->use_count) {
164*682b7c1cSLinus Torvalds 		ipu_dmfc_wait_fifos(priv);
16539b9004dSPhilipp Zabel 		ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
166*682b7c1cSLinus Torvalds 	}
16739b9004dSPhilipp Zabel 
16839b9004dSPhilipp Zabel 	if (priv->use_count < 0)
16939b9004dSPhilipp Zabel 		priv->use_count = 0;
17039b9004dSPhilipp Zabel 
17139b9004dSPhilipp Zabel 	mutex_unlock(&priv->mutex);
17239b9004dSPhilipp Zabel }
17339b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
17439b9004dSPhilipp Zabel 
17539b9004dSPhilipp Zabel static int ipu_dmfc_setup_channel(struct dmfc_channel *dmfc, int slots,
17639b9004dSPhilipp Zabel 		int segment, int burstsize)
17739b9004dSPhilipp Zabel {
17839b9004dSPhilipp Zabel 	struct ipu_dmfc_priv *priv = dmfc->priv;
17939b9004dSPhilipp Zabel 	u32 val, field;
18039b9004dSPhilipp Zabel 
18139b9004dSPhilipp Zabel 	dev_dbg(priv->dev,
18239b9004dSPhilipp Zabel 			"dmfc: using %d slots starting from segment %d for IPU channel %d\n",
18339b9004dSPhilipp Zabel 			slots, segment, dmfc->data->ipu_channel);
18439b9004dSPhilipp Zabel 
18539b9004dSPhilipp Zabel 	switch (slots) {
18639b9004dSPhilipp Zabel 	case 1:
18739b9004dSPhilipp Zabel 		field = DMFC_FIFO_SIZE_64;
18839b9004dSPhilipp Zabel 		break;
18939b9004dSPhilipp Zabel 	case 2:
19039b9004dSPhilipp Zabel 		field = DMFC_FIFO_SIZE_128;
19139b9004dSPhilipp Zabel 		break;
19239b9004dSPhilipp Zabel 	case 4:
19339b9004dSPhilipp Zabel 		field = DMFC_FIFO_SIZE_256;
19439b9004dSPhilipp Zabel 		break;
19539b9004dSPhilipp Zabel 	case 8:
19639b9004dSPhilipp Zabel 		field = DMFC_FIFO_SIZE_512;
19739b9004dSPhilipp Zabel 		break;
19839b9004dSPhilipp Zabel 	default:
19939b9004dSPhilipp Zabel 		return -EINVAL;
20039b9004dSPhilipp Zabel 	}
20139b9004dSPhilipp Zabel 
20239b9004dSPhilipp Zabel 	switch (burstsize) {
20339b9004dSPhilipp Zabel 	case 16:
20439b9004dSPhilipp Zabel 		field |= DMFC_BURSTSIZE_16;
20539b9004dSPhilipp Zabel 		break;
20639b9004dSPhilipp Zabel 	case 32:
20739b9004dSPhilipp Zabel 		field |= DMFC_BURSTSIZE_32;
20839b9004dSPhilipp Zabel 		break;
20939b9004dSPhilipp Zabel 	case 64:
21039b9004dSPhilipp Zabel 		field |= DMFC_BURSTSIZE_64;
21139b9004dSPhilipp Zabel 		break;
21239b9004dSPhilipp Zabel 	case 128:
21339b9004dSPhilipp Zabel 		field |= DMFC_BURSTSIZE_128;
21439b9004dSPhilipp Zabel 		break;
21539b9004dSPhilipp Zabel 	}
21639b9004dSPhilipp Zabel 
21739b9004dSPhilipp Zabel 	field |= DMFC_SEGMENT(segment);
21839b9004dSPhilipp Zabel 
21939b9004dSPhilipp Zabel 	val = readl(priv->base + dmfc->data->channel_reg);
22039b9004dSPhilipp Zabel 
22139b9004dSPhilipp Zabel 	val &= ~(0xff << dmfc->data->shift);
22239b9004dSPhilipp Zabel 	val |= field << dmfc->data->shift;
22339b9004dSPhilipp Zabel 
22439b9004dSPhilipp Zabel 	writel(val, priv->base + dmfc->data->channel_reg);
22539b9004dSPhilipp Zabel 
22639b9004dSPhilipp Zabel 	dmfc->slots = slots;
22739b9004dSPhilipp Zabel 	dmfc->segment = segment;
22839b9004dSPhilipp Zabel 	dmfc->burstsize = burstsize;
22939b9004dSPhilipp Zabel 	dmfc->slotmask = ((1 << slots) - 1) << segment;
23039b9004dSPhilipp Zabel 
23139b9004dSPhilipp Zabel 	return 0;
23239b9004dSPhilipp Zabel }
23339b9004dSPhilipp Zabel 
23439b9004dSPhilipp Zabel static int dmfc_bandwidth_to_slots(struct ipu_dmfc_priv *priv,
23539b9004dSPhilipp Zabel 		unsigned long bandwidth)
23639b9004dSPhilipp Zabel {
23739b9004dSPhilipp Zabel 	int slots = 1;
23839b9004dSPhilipp Zabel 
23939b9004dSPhilipp Zabel 	while (slots * priv->bandwidth_per_slot < bandwidth)
24039b9004dSPhilipp Zabel 		slots *= 2;
24139b9004dSPhilipp Zabel 
24239b9004dSPhilipp Zabel 	return slots;
24339b9004dSPhilipp Zabel }
24439b9004dSPhilipp Zabel 
24539b9004dSPhilipp Zabel static int dmfc_find_slots(struct ipu_dmfc_priv *priv, int slots)
24639b9004dSPhilipp Zabel {
24739b9004dSPhilipp Zabel 	unsigned slotmask_need, slotmask_used = 0;
24839b9004dSPhilipp Zabel 	int i, segment = 0;
24939b9004dSPhilipp Zabel 
25039b9004dSPhilipp Zabel 	slotmask_need = (1 << slots) - 1;
25139b9004dSPhilipp Zabel 
25239b9004dSPhilipp Zabel 	for (i = 0; i < DMFC_NUM_CHANNELS; i++)
25339b9004dSPhilipp Zabel 		slotmask_used |= priv->channels[i].slotmask;
25439b9004dSPhilipp Zabel 
25539b9004dSPhilipp Zabel 	while (slotmask_need <= 0xff) {
25639b9004dSPhilipp Zabel 		if (!(slotmask_used & slotmask_need))
25739b9004dSPhilipp Zabel 			return segment;
25839b9004dSPhilipp Zabel 
25939b9004dSPhilipp Zabel 		slotmask_need <<= 1;
26039b9004dSPhilipp Zabel 		segment++;
26139b9004dSPhilipp Zabel 	}
26239b9004dSPhilipp Zabel 
26339b9004dSPhilipp Zabel 	return -EBUSY;
26439b9004dSPhilipp Zabel }
26539b9004dSPhilipp Zabel 
26639b9004dSPhilipp Zabel void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc)
26739b9004dSPhilipp Zabel {
26839b9004dSPhilipp Zabel 	struct ipu_dmfc_priv *priv = dmfc->priv;
26939b9004dSPhilipp Zabel 	int i;
27039b9004dSPhilipp Zabel 
27139b9004dSPhilipp Zabel 	dev_dbg(priv->dev, "dmfc: freeing %d slots starting from segment %d\n",
27239b9004dSPhilipp Zabel 			dmfc->slots, dmfc->segment);
27339b9004dSPhilipp Zabel 
27439b9004dSPhilipp Zabel 	mutex_lock(&priv->mutex);
27539b9004dSPhilipp Zabel 
27639b9004dSPhilipp Zabel 	if (!dmfc->slots)
27739b9004dSPhilipp Zabel 		goto out;
27839b9004dSPhilipp Zabel 
27939b9004dSPhilipp Zabel 	dmfc->slotmask = 0;
28039b9004dSPhilipp Zabel 	dmfc->slots = 0;
28139b9004dSPhilipp Zabel 	dmfc->segment = 0;
28239b9004dSPhilipp Zabel 
28339b9004dSPhilipp Zabel 	for (i = 0; i < DMFC_NUM_CHANNELS; i++)
28439b9004dSPhilipp Zabel 		priv->channels[i].slotmask = 0;
28539b9004dSPhilipp Zabel 
28639b9004dSPhilipp Zabel 	for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
28739b9004dSPhilipp Zabel 		if (priv->channels[i].slots > 0) {
28839b9004dSPhilipp Zabel 			priv->channels[i].segment =
28939b9004dSPhilipp Zabel 				dmfc_find_slots(priv, priv->channels[i].slots);
29039b9004dSPhilipp Zabel 			priv->channels[i].slotmask =
29139b9004dSPhilipp Zabel 				((1 << priv->channels[i].slots) - 1) <<
29239b9004dSPhilipp Zabel 				priv->channels[i].segment;
29339b9004dSPhilipp Zabel 		}
29439b9004dSPhilipp Zabel 	}
29539b9004dSPhilipp Zabel 
29639b9004dSPhilipp Zabel 	for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
29739b9004dSPhilipp Zabel 		if (priv->channels[i].slots > 0)
29839b9004dSPhilipp Zabel 			ipu_dmfc_setup_channel(&priv->channels[i],
29939b9004dSPhilipp Zabel 					priv->channels[i].slots,
30039b9004dSPhilipp Zabel 					priv->channels[i].segment,
30139b9004dSPhilipp Zabel 					priv->channels[i].burstsize);
30239b9004dSPhilipp Zabel 	}
30339b9004dSPhilipp Zabel out:
30439b9004dSPhilipp Zabel 	mutex_unlock(&priv->mutex);
30539b9004dSPhilipp Zabel }
30639b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_free_bandwidth);
30739b9004dSPhilipp Zabel 
30839b9004dSPhilipp Zabel int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc,
30939b9004dSPhilipp Zabel 		unsigned long bandwidth_pixel_per_second, int burstsize)
31039b9004dSPhilipp Zabel {
31139b9004dSPhilipp Zabel 	struct ipu_dmfc_priv *priv = dmfc->priv;
31239b9004dSPhilipp Zabel 	int slots = dmfc_bandwidth_to_slots(priv, bandwidth_pixel_per_second);
31339b9004dSPhilipp Zabel 	int segment = -1, ret = 0;
31439b9004dSPhilipp Zabel 
31539b9004dSPhilipp Zabel 	dev_dbg(priv->dev, "dmfc: trying to allocate %ldMpixel/s for IPU channel %d\n",
31639b9004dSPhilipp Zabel 			bandwidth_pixel_per_second / 1000000,
31739b9004dSPhilipp Zabel 			dmfc->data->ipu_channel);
31839b9004dSPhilipp Zabel 
31939b9004dSPhilipp Zabel 	ipu_dmfc_free_bandwidth(dmfc);
32039b9004dSPhilipp Zabel 
32139b9004dSPhilipp Zabel 	mutex_lock(&priv->mutex);
32239b9004dSPhilipp Zabel 
32339b9004dSPhilipp Zabel 	if (slots > 8) {
32439b9004dSPhilipp Zabel 		ret = -EBUSY;
32539b9004dSPhilipp Zabel 		goto out;
32639b9004dSPhilipp Zabel 	}
32739b9004dSPhilipp Zabel 
32839b9004dSPhilipp Zabel 	/* For the MEM_BG channel, first try to allocate twice the slots */
32939b9004dSPhilipp Zabel 	if (dmfc->data->ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC)
33039b9004dSPhilipp Zabel 		segment = dmfc_find_slots(priv, slots * 2);
33139b9004dSPhilipp Zabel 	else if (slots < 2)
33239b9004dSPhilipp Zabel 		/* Always allocate at least 128*4 bytes (2 slots) */
33339b9004dSPhilipp Zabel 		slots = 2;
33439b9004dSPhilipp Zabel 
33539b9004dSPhilipp Zabel 	if (segment >= 0)
33639b9004dSPhilipp Zabel 		slots *= 2;
33739b9004dSPhilipp Zabel 	else
33839b9004dSPhilipp Zabel 		segment = dmfc_find_slots(priv, slots);
33939b9004dSPhilipp Zabel 	if (segment < 0) {
34039b9004dSPhilipp Zabel 		ret = -EBUSY;
34139b9004dSPhilipp Zabel 		goto out;
34239b9004dSPhilipp Zabel 	}
34339b9004dSPhilipp Zabel 
34439b9004dSPhilipp Zabel 	ipu_dmfc_setup_channel(dmfc, slots, segment, burstsize);
34539b9004dSPhilipp Zabel 
34639b9004dSPhilipp Zabel out:
34739b9004dSPhilipp Zabel 	mutex_unlock(&priv->mutex);
34839b9004dSPhilipp Zabel 
34939b9004dSPhilipp Zabel 	return ret;
35039b9004dSPhilipp Zabel }
35139b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_alloc_bandwidth);
35239b9004dSPhilipp Zabel 
35339b9004dSPhilipp Zabel int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width)
35439b9004dSPhilipp Zabel {
35539b9004dSPhilipp Zabel 	struct ipu_dmfc_priv *priv = dmfc->priv;
35639b9004dSPhilipp Zabel 	u32 dmfc_gen1;
35739b9004dSPhilipp Zabel 
35839b9004dSPhilipp Zabel 	dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
35939b9004dSPhilipp Zabel 
36039b9004dSPhilipp Zabel 	if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
36139b9004dSPhilipp Zabel 		dmfc_gen1 |= 1 << dmfc->data->eot_shift;
36239b9004dSPhilipp Zabel 	else
36339b9004dSPhilipp Zabel 		dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
36439b9004dSPhilipp Zabel 
36539b9004dSPhilipp Zabel 	writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
36639b9004dSPhilipp Zabel 
36739b9004dSPhilipp Zabel 	return 0;
36839b9004dSPhilipp Zabel }
36939b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_init_channel);
37039b9004dSPhilipp Zabel 
37139b9004dSPhilipp Zabel struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
37239b9004dSPhilipp Zabel {
37339b9004dSPhilipp Zabel 	struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
37439b9004dSPhilipp Zabel 	int i;
37539b9004dSPhilipp Zabel 
37639b9004dSPhilipp Zabel 	for (i = 0; i < DMFC_NUM_CHANNELS; i++)
37739b9004dSPhilipp Zabel 		if (dmfcdata[i].ipu_channel == ipu_channel)
37839b9004dSPhilipp Zabel 			return &priv->channels[i];
37939b9004dSPhilipp Zabel 	return ERR_PTR(-ENODEV);
38039b9004dSPhilipp Zabel }
38139b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_get);
38239b9004dSPhilipp Zabel 
38339b9004dSPhilipp Zabel void ipu_dmfc_put(struct dmfc_channel *dmfc)
38439b9004dSPhilipp Zabel {
38539b9004dSPhilipp Zabel 	ipu_dmfc_free_bandwidth(dmfc);
38639b9004dSPhilipp Zabel }
38739b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dmfc_put);
38839b9004dSPhilipp Zabel 
38939b9004dSPhilipp Zabel int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
39039b9004dSPhilipp Zabel 		struct clk *ipu_clk)
39139b9004dSPhilipp Zabel {
39239b9004dSPhilipp Zabel 	struct ipu_dmfc_priv *priv;
39339b9004dSPhilipp Zabel 	int i;
39439b9004dSPhilipp Zabel 
39539b9004dSPhilipp Zabel 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
39639b9004dSPhilipp Zabel 	if (!priv)
39739b9004dSPhilipp Zabel 		return -ENOMEM;
39839b9004dSPhilipp Zabel 
39939b9004dSPhilipp Zabel 	priv->base = devm_ioremap(dev, base, PAGE_SIZE);
40039b9004dSPhilipp Zabel 	if (!priv->base)
40139b9004dSPhilipp Zabel 		return -ENOMEM;
40239b9004dSPhilipp Zabel 
40339b9004dSPhilipp Zabel 	priv->dev = dev;
40439b9004dSPhilipp Zabel 	priv->ipu = ipu;
40539b9004dSPhilipp Zabel 	mutex_init(&priv->mutex);
40639b9004dSPhilipp Zabel 
40739b9004dSPhilipp Zabel 	ipu->dmfc_priv = priv;
40839b9004dSPhilipp Zabel 
40939b9004dSPhilipp Zabel 	for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
41039b9004dSPhilipp Zabel 		priv->channels[i].priv = priv;
41139b9004dSPhilipp Zabel 		priv->channels[i].ipu = ipu;
41239b9004dSPhilipp Zabel 		priv->channels[i].data = &dmfcdata[i];
41339b9004dSPhilipp Zabel 	}
41439b9004dSPhilipp Zabel 
41539b9004dSPhilipp Zabel 	writel(0x0, priv->base + DMFC_WR_CHAN);
41639b9004dSPhilipp Zabel 	writel(0x0, priv->base + DMFC_DP_CHAN);
41739b9004dSPhilipp Zabel 
41839b9004dSPhilipp Zabel 	/*
41939b9004dSPhilipp Zabel 	 * We have a total bandwidth of clkrate * 4pixel divided
42039b9004dSPhilipp Zabel 	 * into 8 slots.
42139b9004dSPhilipp Zabel 	 */
42239b9004dSPhilipp Zabel 	priv->bandwidth_per_slot = clk_get_rate(ipu_clk) * 4 / 8;
42339b9004dSPhilipp Zabel 
42439b9004dSPhilipp Zabel 	dev_dbg(dev, "dmfc: 8 slots with %ldMpixel/s bandwidth each\n",
42539b9004dSPhilipp Zabel 			priv->bandwidth_per_slot / 1000000);
42639b9004dSPhilipp Zabel 
42739b9004dSPhilipp Zabel 	writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
42839b9004dSPhilipp Zabel 	writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
42939b9004dSPhilipp Zabel 	writel(0x00000003, priv->base + DMFC_GENERAL1);
43039b9004dSPhilipp Zabel 
43139b9004dSPhilipp Zabel 	return 0;
43239b9004dSPhilipp Zabel }
43339b9004dSPhilipp Zabel 
43439b9004dSPhilipp Zabel void ipu_dmfc_exit(struct ipu_soc *ipu)
43539b9004dSPhilipp Zabel {
43639b9004dSPhilipp Zabel }
437