xref: /linux/drivers/gpu/ipu-v3/ipu-prg.c (revision ea9c260514c15f14d43a4c099646c44238dccf1e)
1*ea9c2605SLucas Stach /*
2*ea9c2605SLucas Stach  * Copyright (c) 2016-2017 Lucas Stach, Pengutronix
3*ea9c2605SLucas Stach  *
4*ea9c2605SLucas Stach  * This program is free software; you can redistribute it and/or modify it
5*ea9c2605SLucas Stach  * under the terms and conditions of the GNU General Public License,
6*ea9c2605SLucas Stach  * version 2, as published by the Free Software Foundation.
7*ea9c2605SLucas Stach  *
8*ea9c2605SLucas Stach  * This program is distributed in the hope it will be useful, but WITHOUT
9*ea9c2605SLucas Stach  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10*ea9c2605SLucas Stach  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11*ea9c2605SLucas Stach  * more details.
12*ea9c2605SLucas Stach  */
13*ea9c2605SLucas Stach 
14*ea9c2605SLucas Stach #include <drm/drm_fourcc.h>
15*ea9c2605SLucas Stach #include <linux/clk.h>
16*ea9c2605SLucas Stach #include <linux/err.h>
17*ea9c2605SLucas Stach #include <linux/mfd/syscon.h>
18*ea9c2605SLucas Stach #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
19*ea9c2605SLucas Stach #include <linux/module.h>
20*ea9c2605SLucas Stach #include <linux/of.h>
21*ea9c2605SLucas Stach #include <linux/platform_device.h>
22*ea9c2605SLucas Stach #include <linux/regmap.h>
23*ea9c2605SLucas Stach #include <video/imx-ipu-v3.h>
24*ea9c2605SLucas Stach 
25*ea9c2605SLucas Stach #include "ipu-prv.h"
26*ea9c2605SLucas Stach 
27*ea9c2605SLucas Stach #define IPU_PRG_CTL				0x00
28*ea9c2605SLucas Stach #define  IPU_PRG_CTL_BYPASS(i)			(1 << (0 + i))
29*ea9c2605SLucas Stach #define  IPU_PRG_CTL_SOFT_ARID_MASK		0x3
30*ea9c2605SLucas Stach #define  IPU_PRG_CTL_SOFT_ARID_SHIFT(i)		(8 + i * 2)
31*ea9c2605SLucas Stach #define  IPU_PRG_CTL_SOFT_ARID(i, v)		((v & 0x3) << (8 + 2 * i))
32*ea9c2605SLucas Stach #define  IPU_PRG_CTL_SO(i)			(1 << (16 + i))
33*ea9c2605SLucas Stach #define  IPU_PRG_CTL_VFLIP(i)			(1 << (19 + i))
34*ea9c2605SLucas Stach #define  IPU_PRG_CTL_BLOCK_MODE(i)		(1 << (22 + i))
35*ea9c2605SLucas Stach #define  IPU_PRG_CTL_CNT_LOAD_EN(i)		(1 << (25 + i))
36*ea9c2605SLucas Stach #define  IPU_PRG_CTL_SOFTRST			(1 << 30)
37*ea9c2605SLucas Stach #define  IPU_PRG_CTL_SHADOW_EN			(1 << 31)
38*ea9c2605SLucas Stach 
39*ea9c2605SLucas Stach #define IPU_PRG_STATUS				0x04
40*ea9c2605SLucas Stach #define  IPU_PRG_STATUS_BUFFER0_READY(i)	(1 << (0 + i * 2))
41*ea9c2605SLucas Stach #define  IPU_PRG_STATUS_BUFFER1_READY(i)	(1 << (1 + i * 2))
42*ea9c2605SLucas Stach 
43*ea9c2605SLucas Stach #define IPU_PRG_QOS				0x08
44*ea9c2605SLucas Stach #define  IPU_PRG_QOS_ARID_MASK			0xf
45*ea9c2605SLucas Stach #define  IPU_PRG_QOS_ARID_SHIFT(i)		(0 + i * 4)
46*ea9c2605SLucas Stach 
47*ea9c2605SLucas Stach #define IPU_PRG_REG_UPDATE			0x0c
48*ea9c2605SLucas Stach #define  IPU_PRG_REG_UPDATE_REG_UPDATE		(1 << 0)
49*ea9c2605SLucas Stach 
50*ea9c2605SLucas Stach #define IPU_PRG_STRIDE(i)			(0x10 + i * 0x4)
51*ea9c2605SLucas Stach #define  IPU_PRG_STRIDE_STRIDE_MASK		0x3fff
52*ea9c2605SLucas Stach 
53*ea9c2605SLucas Stach #define IPU_PRG_CROP_LINE			0x1c
54*ea9c2605SLucas Stach 
55*ea9c2605SLucas Stach #define IPU_PRG_THD				0x20
56*ea9c2605SLucas Stach 
57*ea9c2605SLucas Stach #define IPU_PRG_BADDR(i)			(0x24 + i * 0x4)
58*ea9c2605SLucas Stach 
59*ea9c2605SLucas Stach #define IPU_PRG_OFFSET(i)			(0x30 + i * 0x4)
60*ea9c2605SLucas Stach 
61*ea9c2605SLucas Stach #define IPU_PRG_ILO(i)				(0x3c + i * 0x4)
62*ea9c2605SLucas Stach 
63*ea9c2605SLucas Stach #define IPU_PRG_HEIGHT(i)			(0x48 + i * 0x4)
64*ea9c2605SLucas Stach #define  IPU_PRG_HEIGHT_PRE_HEIGHT_MASK		0xfff
65*ea9c2605SLucas Stach #define  IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT	0
66*ea9c2605SLucas Stach #define  IPU_PRG_HEIGHT_IPU_HEIGHT_MASK		0xfff
67*ea9c2605SLucas Stach #define  IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT	16
68*ea9c2605SLucas Stach 
69*ea9c2605SLucas Stach struct ipu_prg_channel {
70*ea9c2605SLucas Stach 	bool			enabled;
71*ea9c2605SLucas Stach 	int			used_pre;
72*ea9c2605SLucas Stach };
73*ea9c2605SLucas Stach 
74*ea9c2605SLucas Stach struct ipu_prg {
75*ea9c2605SLucas Stach 	struct list_head	list;
76*ea9c2605SLucas Stach 	struct device		*dev;
77*ea9c2605SLucas Stach 	int			id;
78*ea9c2605SLucas Stach 
79*ea9c2605SLucas Stach 	void __iomem		*regs;
80*ea9c2605SLucas Stach 	struct clk		*clk_ipg, *clk_axi;
81*ea9c2605SLucas Stach 	struct regmap		*iomuxc_gpr;
82*ea9c2605SLucas Stach 	struct ipu_pre		*pres[3];
83*ea9c2605SLucas Stach 
84*ea9c2605SLucas Stach 	struct ipu_prg_channel	chan[3];
85*ea9c2605SLucas Stach };
86*ea9c2605SLucas Stach 
87*ea9c2605SLucas Stach static DEFINE_MUTEX(ipu_prg_list_mutex);
88*ea9c2605SLucas Stach static LIST_HEAD(ipu_prg_list);
89*ea9c2605SLucas Stach 
90*ea9c2605SLucas Stach struct ipu_prg *
91*ea9c2605SLucas Stach ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id)
92*ea9c2605SLucas Stach {
93*ea9c2605SLucas Stach 	struct device_node *prg_node = of_parse_phandle(dev->of_node,
94*ea9c2605SLucas Stach 							name, 0);
95*ea9c2605SLucas Stach 	struct ipu_prg *prg;
96*ea9c2605SLucas Stach 
97*ea9c2605SLucas Stach 	mutex_lock(&ipu_prg_list_mutex);
98*ea9c2605SLucas Stach 	list_for_each_entry(prg, &ipu_prg_list, list) {
99*ea9c2605SLucas Stach 		if (prg_node == prg->dev->of_node) {
100*ea9c2605SLucas Stach 			mutex_unlock(&ipu_prg_list_mutex);
101*ea9c2605SLucas Stach 			device_link_add(dev, prg->dev, DL_FLAG_AUTOREMOVE);
102*ea9c2605SLucas Stach 			prg->id = ipu_id;
103*ea9c2605SLucas Stach 			return prg;
104*ea9c2605SLucas Stach 		}
105*ea9c2605SLucas Stach 	}
106*ea9c2605SLucas Stach 	mutex_unlock(&ipu_prg_list_mutex);
107*ea9c2605SLucas Stach 
108*ea9c2605SLucas Stach 	return NULL;
109*ea9c2605SLucas Stach }
110*ea9c2605SLucas Stach 
111*ea9c2605SLucas Stach int ipu_prg_max_active_channels(void)
112*ea9c2605SLucas Stach {
113*ea9c2605SLucas Stach 	return ipu_pre_get_available_count();
114*ea9c2605SLucas Stach }
115*ea9c2605SLucas Stach EXPORT_SYMBOL_GPL(ipu_prg_max_active_channels);
116*ea9c2605SLucas Stach 
117*ea9c2605SLucas Stach bool ipu_prg_present(struct ipu_soc *ipu)
118*ea9c2605SLucas Stach {
119*ea9c2605SLucas Stach 	if (ipu->prg_priv)
120*ea9c2605SLucas Stach 		return true;
121*ea9c2605SLucas Stach 
122*ea9c2605SLucas Stach 	return false;
123*ea9c2605SLucas Stach }
124*ea9c2605SLucas Stach EXPORT_SYMBOL_GPL(ipu_prg_present);
125*ea9c2605SLucas Stach 
126*ea9c2605SLucas Stach bool ipu_prg_format_supported(struct ipu_soc *ipu, uint32_t format,
127*ea9c2605SLucas Stach 			      uint64_t modifier)
128*ea9c2605SLucas Stach {
129*ea9c2605SLucas Stach 	const struct drm_format_info *info = drm_format_info(format);
130*ea9c2605SLucas Stach 
131*ea9c2605SLucas Stach 	if (info->num_planes != 1)
132*ea9c2605SLucas Stach 		return false;
133*ea9c2605SLucas Stach 
134*ea9c2605SLucas Stach 	return true;
135*ea9c2605SLucas Stach }
136*ea9c2605SLucas Stach EXPORT_SYMBOL_GPL(ipu_prg_format_supported);
137*ea9c2605SLucas Stach 
138*ea9c2605SLucas Stach int ipu_prg_enable(struct ipu_soc *ipu)
139*ea9c2605SLucas Stach {
140*ea9c2605SLucas Stach 	struct ipu_prg *prg = ipu->prg_priv;
141*ea9c2605SLucas Stach 	int ret;
142*ea9c2605SLucas Stach 
143*ea9c2605SLucas Stach 	if (!prg)
144*ea9c2605SLucas Stach 		return 0;
145*ea9c2605SLucas Stach 
146*ea9c2605SLucas Stach 	ret = clk_prepare_enable(prg->clk_axi);
147*ea9c2605SLucas Stach 	if (ret)
148*ea9c2605SLucas Stach 		goto fail_disable_ipg;
149*ea9c2605SLucas Stach 
150*ea9c2605SLucas Stach 	return 0;
151*ea9c2605SLucas Stach 
152*ea9c2605SLucas Stach fail_disable_ipg:
153*ea9c2605SLucas Stach 	clk_disable_unprepare(prg->clk_ipg);
154*ea9c2605SLucas Stach 
155*ea9c2605SLucas Stach 	return ret;
156*ea9c2605SLucas Stach }
157*ea9c2605SLucas Stach EXPORT_SYMBOL_GPL(ipu_prg_enable);
158*ea9c2605SLucas Stach 
159*ea9c2605SLucas Stach void ipu_prg_disable(struct ipu_soc *ipu)
160*ea9c2605SLucas Stach {
161*ea9c2605SLucas Stach 	struct ipu_prg *prg = ipu->prg_priv;
162*ea9c2605SLucas Stach 
163*ea9c2605SLucas Stach 	if (!prg)
164*ea9c2605SLucas Stach 		return;
165*ea9c2605SLucas Stach 
166*ea9c2605SLucas Stach 	clk_disable_unprepare(prg->clk_axi);
167*ea9c2605SLucas Stach }
168*ea9c2605SLucas Stach EXPORT_SYMBOL_GPL(ipu_prg_disable);
169*ea9c2605SLucas Stach 
170*ea9c2605SLucas Stach /*
171*ea9c2605SLucas Stach  * The channel configuartion functions below are not thread safe, as they
172*ea9c2605SLucas Stach  * must be only called from the atomic commit path in the DRM driver, which
173*ea9c2605SLucas Stach  * is properly serialized.
174*ea9c2605SLucas Stach  */
175*ea9c2605SLucas Stach static int ipu_prg_ipu_to_prg_chan(int ipu_chan)
176*ea9c2605SLucas Stach {
177*ea9c2605SLucas Stach 	/*
178*ea9c2605SLucas Stach 	 * This isn't clearly documented in the RM, but IPU to PRG channel
179*ea9c2605SLucas Stach 	 * assignment is fixed, as only with this mapping the control signals
180*ea9c2605SLucas Stach 	 * match up.
181*ea9c2605SLucas Stach 	 */
182*ea9c2605SLucas Stach 	switch (ipu_chan) {
183*ea9c2605SLucas Stach 	case IPUV3_CHANNEL_MEM_BG_SYNC:
184*ea9c2605SLucas Stach 		return 0;
185*ea9c2605SLucas Stach 	case IPUV3_CHANNEL_MEM_FG_SYNC:
186*ea9c2605SLucas Stach 		return 1;
187*ea9c2605SLucas Stach 	case IPUV3_CHANNEL_MEM_DC_SYNC:
188*ea9c2605SLucas Stach 		return 2;
189*ea9c2605SLucas Stach 	default:
190*ea9c2605SLucas Stach 		return -EINVAL;
191*ea9c2605SLucas Stach 	}
192*ea9c2605SLucas Stach }
193*ea9c2605SLucas Stach 
194*ea9c2605SLucas Stach static int ipu_prg_get_pre(struct ipu_prg *prg, int prg_chan)
195*ea9c2605SLucas Stach {
196*ea9c2605SLucas Stach 	int i, ret;
197*ea9c2605SLucas Stach 
198*ea9c2605SLucas Stach 	/* channel 0 is special as it is hardwired to one of the PREs */
199*ea9c2605SLucas Stach 	if (prg_chan == 0) {
200*ea9c2605SLucas Stach 		ret = ipu_pre_get(prg->pres[0]);
201*ea9c2605SLucas Stach 		if (ret)
202*ea9c2605SLucas Stach 			goto fail;
203*ea9c2605SLucas Stach 		prg->chan[prg_chan].used_pre = 0;
204*ea9c2605SLucas Stach 		return 0;
205*ea9c2605SLucas Stach 	}
206*ea9c2605SLucas Stach 
207*ea9c2605SLucas Stach 	for (i = 1; i < 3; i++) {
208*ea9c2605SLucas Stach 		ret = ipu_pre_get(prg->pres[i]);
209*ea9c2605SLucas Stach 		if (!ret) {
210*ea9c2605SLucas Stach 			u32 val, mux;
211*ea9c2605SLucas Stach 			int shift;
212*ea9c2605SLucas Stach 
213*ea9c2605SLucas Stach 			prg->chan[prg_chan].used_pre = i;
214*ea9c2605SLucas Stach 
215*ea9c2605SLucas Stach 			/* configure the PRE to PRG channel mux */
216*ea9c2605SLucas Stach 			shift = (i == 1) ? 12 : 14;
217*ea9c2605SLucas Stach 			mux = (prg->id << 1) | (prg_chan - 1);
218*ea9c2605SLucas Stach 			regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
219*ea9c2605SLucas Stach 					   0x3 << shift, mux << shift);
220*ea9c2605SLucas Stach 
221*ea9c2605SLucas Stach 			/* check other mux, must not point to same channel */
222*ea9c2605SLucas Stach 			shift = (i == 1) ? 14 : 12;
223*ea9c2605SLucas Stach 			regmap_read(prg->iomuxc_gpr, IOMUXC_GPR5, &val);
224*ea9c2605SLucas Stach 			if (((val >> shift) & 0x3) == mux) {
225*ea9c2605SLucas Stach 				regmap_update_bits(prg->iomuxc_gpr, IOMUXC_GPR5,
226*ea9c2605SLucas Stach 						   0x3 << shift,
227*ea9c2605SLucas Stach 						   (mux ^ 0x1) << shift);
228*ea9c2605SLucas Stach 			}
229*ea9c2605SLucas Stach 
230*ea9c2605SLucas Stach 			return 0;
231*ea9c2605SLucas Stach 		}
232*ea9c2605SLucas Stach 	}
233*ea9c2605SLucas Stach 
234*ea9c2605SLucas Stach fail:
235*ea9c2605SLucas Stach 	dev_err(prg->dev, "could not get PRE for PRG chan %d", prg_chan);
236*ea9c2605SLucas Stach 	return ret;
237*ea9c2605SLucas Stach }
238*ea9c2605SLucas Stach 
239*ea9c2605SLucas Stach static void ipu_prg_put_pre(struct ipu_prg *prg, int prg_chan)
240*ea9c2605SLucas Stach {
241*ea9c2605SLucas Stach 	struct ipu_prg_channel *chan = &prg->chan[prg_chan];
242*ea9c2605SLucas Stach 
243*ea9c2605SLucas Stach 	ipu_pre_put(prg->pres[chan->used_pre]);
244*ea9c2605SLucas Stach 	chan->used_pre = -1;
245*ea9c2605SLucas Stach }
246*ea9c2605SLucas Stach 
247*ea9c2605SLucas Stach void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan)
248*ea9c2605SLucas Stach {
249*ea9c2605SLucas Stach 	int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
250*ea9c2605SLucas Stach 	struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
251*ea9c2605SLucas Stach 	struct ipu_prg_channel *chan = &prg->chan[prg_chan];
252*ea9c2605SLucas Stach 	u32 val;
253*ea9c2605SLucas Stach 
254*ea9c2605SLucas Stach 	if (!chan->enabled || prg_chan < 0)
255*ea9c2605SLucas Stach 		return;
256*ea9c2605SLucas Stach 
257*ea9c2605SLucas Stach 	clk_prepare_enable(prg->clk_ipg);
258*ea9c2605SLucas Stach 
259*ea9c2605SLucas Stach 	val = readl(prg->regs + IPU_PRG_CTL);
260*ea9c2605SLucas Stach 	val |= IPU_PRG_CTL_BYPASS(prg_chan);
261*ea9c2605SLucas Stach 	writel(val, prg->regs + IPU_PRG_CTL);
262*ea9c2605SLucas Stach 
263*ea9c2605SLucas Stach 	val = IPU_PRG_REG_UPDATE_REG_UPDATE;
264*ea9c2605SLucas Stach 	writel(val, prg->regs + IPU_PRG_REG_UPDATE);
265*ea9c2605SLucas Stach 
266*ea9c2605SLucas Stach 	clk_disable_unprepare(prg->clk_ipg);
267*ea9c2605SLucas Stach 
268*ea9c2605SLucas Stach 	ipu_prg_put_pre(prg, prg_chan);
269*ea9c2605SLucas Stach 
270*ea9c2605SLucas Stach 	chan->enabled = false;
271*ea9c2605SLucas Stach }
272*ea9c2605SLucas Stach EXPORT_SYMBOL_GPL(ipu_prg_channel_disable);
273*ea9c2605SLucas Stach 
274*ea9c2605SLucas Stach int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
275*ea9c2605SLucas Stach 			      unsigned int axi_id, unsigned int width,
276*ea9c2605SLucas Stach 			      unsigned int height, unsigned int stride,
277*ea9c2605SLucas Stach 			      u32 format, unsigned long *eba)
278*ea9c2605SLucas Stach {
279*ea9c2605SLucas Stach 	int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
280*ea9c2605SLucas Stach 	struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
281*ea9c2605SLucas Stach 	struct ipu_prg_channel *chan = &prg->chan[prg_chan];
282*ea9c2605SLucas Stach 	u32 val;
283*ea9c2605SLucas Stach 	int ret;
284*ea9c2605SLucas Stach 
285*ea9c2605SLucas Stach 	if (prg_chan < 0)
286*ea9c2605SLucas Stach 		return prg_chan;
287*ea9c2605SLucas Stach 
288*ea9c2605SLucas Stach 	if (chan->enabled) {
289*ea9c2605SLucas Stach 		ipu_pre_update(prg->pres[chan->used_pre], *eba);
290*ea9c2605SLucas Stach 		return 0;
291*ea9c2605SLucas Stach 	}
292*ea9c2605SLucas Stach 
293*ea9c2605SLucas Stach 	ret = ipu_prg_get_pre(prg, prg_chan);
294*ea9c2605SLucas Stach 	if (ret)
295*ea9c2605SLucas Stach 		return ret;
296*ea9c2605SLucas Stach 
297*ea9c2605SLucas Stach 	ipu_pre_configure(prg->pres[chan->used_pre],
298*ea9c2605SLucas Stach 			  width, height, stride, format, *eba);
299*ea9c2605SLucas Stach 
300*ea9c2605SLucas Stach 
301*ea9c2605SLucas Stach 	ret = clk_prepare_enable(prg->clk_ipg);
302*ea9c2605SLucas Stach 	if (ret) {
303*ea9c2605SLucas Stach 		ipu_prg_put_pre(prg, prg_chan);
304*ea9c2605SLucas Stach 		return ret;
305*ea9c2605SLucas Stach 	}
306*ea9c2605SLucas Stach 
307*ea9c2605SLucas Stach 	val = (stride - 1) & IPU_PRG_STRIDE_STRIDE_MASK;
308*ea9c2605SLucas Stach 	writel(val, prg->regs + IPU_PRG_STRIDE(prg_chan));
309*ea9c2605SLucas Stach 
310*ea9c2605SLucas Stach 	val = ((height & IPU_PRG_HEIGHT_PRE_HEIGHT_MASK) <<
311*ea9c2605SLucas Stach 	       IPU_PRG_HEIGHT_PRE_HEIGHT_SHIFT) |
312*ea9c2605SLucas Stach 	      ((height & IPU_PRG_HEIGHT_IPU_HEIGHT_MASK) <<
313*ea9c2605SLucas Stach 	       IPU_PRG_HEIGHT_IPU_HEIGHT_SHIFT);
314*ea9c2605SLucas Stach 	writel(val, prg->regs + IPU_PRG_HEIGHT(prg_chan));
315*ea9c2605SLucas Stach 
316*ea9c2605SLucas Stach 	val = ipu_pre_get_baddr(prg->pres[chan->used_pre]);
317*ea9c2605SLucas Stach 	*eba = val;
318*ea9c2605SLucas Stach 	writel(val, prg->regs + IPU_PRG_BADDR(prg_chan));
319*ea9c2605SLucas Stach 
320*ea9c2605SLucas Stach 	val = readl(prg->regs + IPU_PRG_CTL);
321*ea9c2605SLucas Stach 	/* counter load enable */
322*ea9c2605SLucas Stach 	val |= IPU_PRG_CTL_CNT_LOAD_EN(prg_chan);
323*ea9c2605SLucas Stach 	/* config AXI ID */
324*ea9c2605SLucas Stach 	val &= ~(IPU_PRG_CTL_SOFT_ARID_MASK <<
325*ea9c2605SLucas Stach 		 IPU_PRG_CTL_SOFT_ARID_SHIFT(prg_chan));
326*ea9c2605SLucas Stach 	val |= IPU_PRG_CTL_SOFT_ARID(prg_chan, axi_id);
327*ea9c2605SLucas Stach 	/* enable channel */
328*ea9c2605SLucas Stach 	val &= ~IPU_PRG_CTL_BYPASS(prg_chan);
329*ea9c2605SLucas Stach 	writel(val, prg->regs + IPU_PRG_CTL);
330*ea9c2605SLucas Stach 
331*ea9c2605SLucas Stach 	val = IPU_PRG_REG_UPDATE_REG_UPDATE;
332*ea9c2605SLucas Stach 	writel(val, prg->regs + IPU_PRG_REG_UPDATE);
333*ea9c2605SLucas Stach 
334*ea9c2605SLucas Stach 	clk_disable_unprepare(prg->clk_ipg);
335*ea9c2605SLucas Stach 
336*ea9c2605SLucas Stach 	chan->enabled = true;
337*ea9c2605SLucas Stach 	return 0;
338*ea9c2605SLucas Stach }
339*ea9c2605SLucas Stach EXPORT_SYMBOL_GPL(ipu_prg_channel_configure);
340*ea9c2605SLucas Stach 
341*ea9c2605SLucas Stach static int ipu_prg_probe(struct platform_device *pdev)
342*ea9c2605SLucas Stach {
343*ea9c2605SLucas Stach 	struct device *dev = &pdev->dev;
344*ea9c2605SLucas Stach 	struct resource *res;
345*ea9c2605SLucas Stach 	struct ipu_prg *prg;
346*ea9c2605SLucas Stach 	u32 val;
347*ea9c2605SLucas Stach 	int i, ret;
348*ea9c2605SLucas Stach 
349*ea9c2605SLucas Stach 	prg = devm_kzalloc(dev, sizeof(*prg), GFP_KERNEL);
350*ea9c2605SLucas Stach 	if (!prg)
351*ea9c2605SLucas Stach 		return -ENOMEM;
352*ea9c2605SLucas Stach 
353*ea9c2605SLucas Stach 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
354*ea9c2605SLucas Stach 	prg->regs = devm_ioremap_resource(&pdev->dev, res);
355*ea9c2605SLucas Stach 	if (IS_ERR(prg->regs))
356*ea9c2605SLucas Stach 		return PTR_ERR(prg->regs);
357*ea9c2605SLucas Stach 
358*ea9c2605SLucas Stach 
359*ea9c2605SLucas Stach 	prg->clk_ipg = devm_clk_get(dev, "ipg");
360*ea9c2605SLucas Stach 	if (IS_ERR(prg->clk_ipg))
361*ea9c2605SLucas Stach 		return PTR_ERR(prg->clk_ipg);
362*ea9c2605SLucas Stach 
363*ea9c2605SLucas Stach 	prg->clk_axi = devm_clk_get(dev, "axi");
364*ea9c2605SLucas Stach 	if (IS_ERR(prg->clk_axi))
365*ea9c2605SLucas Stach 		return PTR_ERR(prg->clk_axi);
366*ea9c2605SLucas Stach 
367*ea9c2605SLucas Stach 	prg->iomuxc_gpr =
368*ea9c2605SLucas Stach 		syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
369*ea9c2605SLucas Stach 	if (IS_ERR(prg->iomuxc_gpr))
370*ea9c2605SLucas Stach 		return PTR_ERR(prg->iomuxc_gpr);
371*ea9c2605SLucas Stach 
372*ea9c2605SLucas Stach 	for (i = 0; i < 3; i++) {
373*ea9c2605SLucas Stach 		prg->pres[i] = ipu_pre_lookup_by_phandle(dev, "fsl,pres", i);
374*ea9c2605SLucas Stach 		if (!prg->pres[i])
375*ea9c2605SLucas Stach 			return -EPROBE_DEFER;
376*ea9c2605SLucas Stach 	}
377*ea9c2605SLucas Stach 
378*ea9c2605SLucas Stach 	ret = clk_prepare_enable(prg->clk_ipg);
379*ea9c2605SLucas Stach 	if (ret)
380*ea9c2605SLucas Stach 		return ret;
381*ea9c2605SLucas Stach 
382*ea9c2605SLucas Stach 	/* init to free running mode */
383*ea9c2605SLucas Stach 	val = readl(prg->regs + IPU_PRG_CTL);
384*ea9c2605SLucas Stach 	val |= IPU_PRG_CTL_SHADOW_EN;
385*ea9c2605SLucas Stach 	writel(val, prg->regs + IPU_PRG_CTL);
386*ea9c2605SLucas Stach 
387*ea9c2605SLucas Stach 	/* disable address threshold */
388*ea9c2605SLucas Stach 	writel(0xffffffff, prg->regs + IPU_PRG_THD);
389*ea9c2605SLucas Stach 
390*ea9c2605SLucas Stach 	clk_disable_unprepare(prg->clk_ipg);
391*ea9c2605SLucas Stach 
392*ea9c2605SLucas Stach 	prg->dev = dev;
393*ea9c2605SLucas Stach 	platform_set_drvdata(pdev, prg);
394*ea9c2605SLucas Stach 	mutex_lock(&ipu_prg_list_mutex);
395*ea9c2605SLucas Stach 	list_add(&prg->list, &ipu_prg_list);
396*ea9c2605SLucas Stach 	mutex_unlock(&ipu_prg_list_mutex);
397*ea9c2605SLucas Stach 
398*ea9c2605SLucas Stach 	return 0;
399*ea9c2605SLucas Stach }
400*ea9c2605SLucas Stach 
401*ea9c2605SLucas Stach static int ipu_prg_remove(struct platform_device *pdev)
402*ea9c2605SLucas Stach {
403*ea9c2605SLucas Stach 	struct ipu_prg *prg = platform_get_drvdata(pdev);
404*ea9c2605SLucas Stach 
405*ea9c2605SLucas Stach 	mutex_lock(&ipu_prg_list_mutex);
406*ea9c2605SLucas Stach 	list_del(&prg->list);
407*ea9c2605SLucas Stach 	mutex_unlock(&ipu_prg_list_mutex);
408*ea9c2605SLucas Stach 
409*ea9c2605SLucas Stach 	return 0;
410*ea9c2605SLucas Stach }
411*ea9c2605SLucas Stach 
412*ea9c2605SLucas Stach static const struct of_device_id ipu_prg_dt_ids[] = {
413*ea9c2605SLucas Stach 	{ .compatible = "fsl,imx6qp-prg", },
414*ea9c2605SLucas Stach 	{ /* sentinel */ },
415*ea9c2605SLucas Stach };
416*ea9c2605SLucas Stach 
417*ea9c2605SLucas Stach struct platform_driver ipu_prg_drv = {
418*ea9c2605SLucas Stach 	.probe		= ipu_prg_probe,
419*ea9c2605SLucas Stach 	.remove		= ipu_prg_remove,
420*ea9c2605SLucas Stach 	.driver		= {
421*ea9c2605SLucas Stach 		.name	= "imx-ipu-prg",
422*ea9c2605SLucas Stach 		.of_match_table = ipu_prg_dt_ids,
423*ea9c2605SLucas Stach 	},
424*ea9c2605SLucas Stach };
425