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