162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
462306a36Sopenharmony_ci * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include <linux/export.h>
762306a36Sopenharmony_ci#include <linux/types.h>
862306a36Sopenharmony_ci#include <linux/errno.h>
962306a36Sopenharmony_ci#include <linux/io.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <video/imx-ipu-v3.h>
1262306a36Sopenharmony_ci#include "ipu-prv.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define DMFC_RD_CHAN		0x0000
1562306a36Sopenharmony_ci#define DMFC_WR_CHAN		0x0004
1662306a36Sopenharmony_ci#define DMFC_WR_CHAN_DEF	0x0008
1762306a36Sopenharmony_ci#define DMFC_DP_CHAN		0x000c
1862306a36Sopenharmony_ci#define DMFC_DP_CHAN_DEF	0x0010
1962306a36Sopenharmony_ci#define DMFC_GENERAL1		0x0014
2062306a36Sopenharmony_ci#define DMFC_GENERAL2		0x0018
2162306a36Sopenharmony_ci#define DMFC_IC_CTRL		0x001c
2262306a36Sopenharmony_ci#define DMFC_WR_CHAN_ALT	0x0020
2362306a36Sopenharmony_ci#define DMFC_WR_CHAN_DEF_ALT	0x0024
2462306a36Sopenharmony_ci#define DMFC_DP_CHAN_ALT	0x0028
2562306a36Sopenharmony_ci#define DMFC_DP_CHAN_DEF_ALT	0x002c
2662306a36Sopenharmony_ci#define DMFC_GENERAL1_ALT	0x0030
2762306a36Sopenharmony_ci#define DMFC_STAT		0x0034
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define DMFC_WR_CHAN_1_28		0
3062306a36Sopenharmony_ci#define DMFC_WR_CHAN_2_41		8
3162306a36Sopenharmony_ci#define DMFC_WR_CHAN_1C_42		16
3262306a36Sopenharmony_ci#define DMFC_WR_CHAN_2C_43		24
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define DMFC_DP_CHAN_5B_23		0
3562306a36Sopenharmony_ci#define DMFC_DP_CHAN_5F_27		8
3662306a36Sopenharmony_ci#define DMFC_DP_CHAN_6B_24		16
3762306a36Sopenharmony_ci#define DMFC_DP_CHAN_6F_29		24
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistruct dmfc_channel_data {
4062306a36Sopenharmony_ci	int		ipu_channel;
4162306a36Sopenharmony_ci	unsigned long	channel_reg;
4262306a36Sopenharmony_ci	unsigned long	shift;
4362306a36Sopenharmony_ci	unsigned	eot_shift;
4462306a36Sopenharmony_ci	unsigned	max_fifo_lines;
4562306a36Sopenharmony_ci};
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic const struct dmfc_channel_data dmfcdata[] = {
4862306a36Sopenharmony_ci	{
4962306a36Sopenharmony_ci		.ipu_channel	= IPUV3_CHANNEL_MEM_BG_SYNC,
5062306a36Sopenharmony_ci		.channel_reg	= DMFC_DP_CHAN,
5162306a36Sopenharmony_ci		.shift		= DMFC_DP_CHAN_5B_23,
5262306a36Sopenharmony_ci		.eot_shift	= 20,
5362306a36Sopenharmony_ci		.max_fifo_lines	= 3,
5462306a36Sopenharmony_ci	}, {
5562306a36Sopenharmony_ci		.ipu_channel	= 24,
5662306a36Sopenharmony_ci		.channel_reg	= DMFC_DP_CHAN,
5762306a36Sopenharmony_ci		.shift		= DMFC_DP_CHAN_6B_24,
5862306a36Sopenharmony_ci		.eot_shift	= 22,
5962306a36Sopenharmony_ci		.max_fifo_lines	= 1,
6062306a36Sopenharmony_ci	}, {
6162306a36Sopenharmony_ci		.ipu_channel	= IPUV3_CHANNEL_MEM_FG_SYNC,
6262306a36Sopenharmony_ci		.channel_reg	= DMFC_DP_CHAN,
6362306a36Sopenharmony_ci		.shift		= DMFC_DP_CHAN_5F_27,
6462306a36Sopenharmony_ci		.eot_shift	= 21,
6562306a36Sopenharmony_ci		.max_fifo_lines	= 2,
6662306a36Sopenharmony_ci	}, {
6762306a36Sopenharmony_ci		.ipu_channel	= IPUV3_CHANNEL_MEM_DC_SYNC,
6862306a36Sopenharmony_ci		.channel_reg	= DMFC_WR_CHAN,
6962306a36Sopenharmony_ci		.shift		= DMFC_WR_CHAN_1_28,
7062306a36Sopenharmony_ci		.eot_shift	= 16,
7162306a36Sopenharmony_ci		.max_fifo_lines	= 2,
7262306a36Sopenharmony_ci	}, {
7362306a36Sopenharmony_ci		.ipu_channel	= 29,
7462306a36Sopenharmony_ci		.channel_reg	= DMFC_DP_CHAN,
7562306a36Sopenharmony_ci		.shift		= DMFC_DP_CHAN_6F_29,
7662306a36Sopenharmony_ci		.eot_shift	= 23,
7762306a36Sopenharmony_ci		.max_fifo_lines	= 1,
7862306a36Sopenharmony_ci	},
7962306a36Sopenharmony_ci};
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#define DMFC_NUM_CHANNELS	ARRAY_SIZE(dmfcdata)
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistruct ipu_dmfc_priv;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistruct dmfc_channel {
8662306a36Sopenharmony_ci	unsigned			slots;
8762306a36Sopenharmony_ci	struct ipu_soc			*ipu;
8862306a36Sopenharmony_ci	struct ipu_dmfc_priv		*priv;
8962306a36Sopenharmony_ci	const struct dmfc_channel_data	*data;
9062306a36Sopenharmony_ci};
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistruct ipu_dmfc_priv {
9362306a36Sopenharmony_ci	struct ipu_soc *ipu;
9462306a36Sopenharmony_ci	struct device *dev;
9562306a36Sopenharmony_ci	struct dmfc_channel channels[DMFC_NUM_CHANNELS];
9662306a36Sopenharmony_ci	struct mutex mutex;
9762306a36Sopenharmony_ci	void __iomem *base;
9862306a36Sopenharmony_ci	int use_count;
9962306a36Sopenharmony_ci};
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ciint ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	struct ipu_dmfc_priv *priv = dmfc->priv;
10462306a36Sopenharmony_ci	mutex_lock(&priv->mutex);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	if (!priv->use_count)
10762306a36Sopenharmony_ci		ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	priv->use_count++;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	mutex_unlock(&priv->mutex);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	return 0;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_civoid ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	struct ipu_dmfc_priv *priv = dmfc->priv;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	mutex_lock(&priv->mutex);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	priv->use_count--;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	if (!priv->use_count)
12662306a36Sopenharmony_ci		ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	if (priv->use_count < 0)
12962306a36Sopenharmony_ci		priv->use_count = 0;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	mutex_unlock(&priv->mutex);
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_civoid ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	struct ipu_dmfc_priv *priv = dmfc->priv;
13862306a36Sopenharmony_ci	u32 dmfc_gen1;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	mutex_lock(&priv->mutex);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
14562306a36Sopenharmony_ci		dmfc_gen1 |= 1 << dmfc->data->eot_shift;
14662306a36Sopenharmony_ci	else
14762306a36Sopenharmony_ci		dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	mutex_unlock(&priv->mutex);
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_dmfc_config_wait4eot);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistruct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
15862306a36Sopenharmony_ci	int i;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	for (i = 0; i < DMFC_NUM_CHANNELS; i++)
16162306a36Sopenharmony_ci		if (dmfcdata[i].ipu_channel == ipu_channel)
16262306a36Sopenharmony_ci			return &priv->channels[i];
16362306a36Sopenharmony_ci	return ERR_PTR(-ENODEV);
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_dmfc_get);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_civoid ipu_dmfc_put(struct dmfc_channel *dmfc)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ipu_dmfc_put);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ciint ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
17362306a36Sopenharmony_ci		struct clk *ipu_clk)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	struct ipu_dmfc_priv *priv;
17662306a36Sopenharmony_ci	int i;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
17962306a36Sopenharmony_ci	if (!priv)
18062306a36Sopenharmony_ci		return -ENOMEM;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	priv->base = devm_ioremap(dev, base, PAGE_SIZE);
18362306a36Sopenharmony_ci	if (!priv->base)
18462306a36Sopenharmony_ci		return -ENOMEM;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	priv->dev = dev;
18762306a36Sopenharmony_ci	priv->ipu = ipu;
18862306a36Sopenharmony_ci	mutex_init(&priv->mutex);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	ipu->dmfc_priv = priv;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
19362306a36Sopenharmony_ci		priv->channels[i].priv = priv;
19462306a36Sopenharmony_ci		priv->channels[i].ipu = ipu;
19562306a36Sopenharmony_ci		priv->channels[i].data = &dmfcdata[i];
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci		if (dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC ||
19862306a36Sopenharmony_ci		    dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_FG_SYNC ||
19962306a36Sopenharmony_ci		    dmfcdata[i].ipu_channel == IPUV3_CHANNEL_MEM_DC_SYNC)
20062306a36Sopenharmony_ci			priv->channels[i].slots = 2;
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	writel(0x00000050, priv->base + DMFC_WR_CHAN);
20462306a36Sopenharmony_ci	writel(0x00005654, priv->base + DMFC_DP_CHAN);
20562306a36Sopenharmony_ci	writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
20662306a36Sopenharmony_ci	writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
20762306a36Sopenharmony_ci	writel(0x00000003, priv->base + DMFC_GENERAL1);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	return 0;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_civoid ipu_dmfc_exit(struct ipu_soc *ipu)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci}
215