1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
4 * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
6 #include <linux/export.h>
7 #include <linux/types.h>
8 #include <linux/errno.h>
11 #include <video/imx-ipu-v3.h>
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
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
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
39 struct dmfc_channel_data {
41 unsigned long channel_reg;
44 unsigned max_fifo_lines;
47 static const struct dmfc_channel_data dmfcdata[] = {
49 .ipu_channel = IPUV3_CHANNEL_MEM_BG_SYNC,
50 .channel_reg = DMFC_DP_CHAN,
51 .shift = DMFC_DP_CHAN_5B_23,
56 .channel_reg = DMFC_DP_CHAN,
57 .shift = DMFC_DP_CHAN_6B_24,
61 .ipu_channel = IPUV3_CHANNEL_MEM_FG_SYNC,
62 .channel_reg = DMFC_DP_CHAN,
63 .shift = DMFC_DP_CHAN_5F_27,
67 .ipu_channel = IPUV3_CHANNEL_MEM_DC_SYNC,
68 .channel_reg = DMFC_WR_CHAN,
69 .shift = DMFC_WR_CHAN_1_28,
74 .channel_reg = DMFC_DP_CHAN,
75 .shift = DMFC_DP_CHAN_6F_29,
81 #define DMFC_NUM_CHANNELS ARRAY_SIZE(dmfcdata)
88 struct ipu_dmfc_priv *priv;
89 const struct dmfc_channel_data *data;
92 struct ipu_dmfc_priv {
95 struct dmfc_channel channels[DMFC_NUM_CHANNELS];
101 int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
103 struct ipu_dmfc_priv *priv = dmfc->priv;
104 mutex_lock(&priv->mutex);
106 if (!priv->use_count)
107 ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
111 mutex_unlock(&priv->mutex);
115 EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
117 void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
119 struct ipu_dmfc_priv *priv = dmfc->priv;
121 mutex_lock(&priv->mutex);
125 if (!priv->use_count)
126 ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
128 if (priv->use_count < 0)
131 mutex_unlock(&priv->mutex);
133 EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
135 void ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width)
137 struct ipu_dmfc_priv *priv = dmfc->priv;
140 mutex_lock(&priv->mutex);
142 dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
144 if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
145 dmfc_gen1 |= 1 << dmfc->data->eot_shift;
147 dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
149 writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
151 mutex_unlock(&priv->mutex);
153 EXPORT_SYMBOL_GPL(ipu_dmfc_config_wait4eot);
155 struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
157 struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
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);
165 EXPORT_SYMBOL_GPL(ipu_dmfc_get);
167 void ipu_dmfc_put(struct dmfc_channel *dmfc)
170 EXPORT_SYMBOL_GPL(ipu_dmfc_put);
172 int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
175 struct ipu_dmfc_priv *priv;
178 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
182 priv->base = devm_ioremap(dev, base, PAGE_SIZE);
188 mutex_init(&priv->mutex);
190 ipu->dmfc_priv = priv;
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];
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;
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);
212 void ipu_dmfc_exit(struct ipu_soc *ipu)