xref: /linux/drivers/gpu/ipu-v3/ipu-dp.c (revision 4618cb79)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
239b9004dSPhilipp Zabel /*
339b9004dSPhilipp Zabel  * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
439b9004dSPhilipp Zabel  * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
539b9004dSPhilipp Zabel  */
639b9004dSPhilipp Zabel #include <linux/export.h>
739b9004dSPhilipp Zabel #include <linux/kernel.h>
839b9004dSPhilipp Zabel #include <linux/types.h>
939b9004dSPhilipp Zabel #include <linux/errno.h>
1039b9004dSPhilipp Zabel #include <linux/io.h>
1139b9004dSPhilipp Zabel #include <linux/err.h>
1239b9004dSPhilipp Zabel 
13*4618cb79SPhilipp Zabel #include <drm/drm_color_mgmt.h>
1439b9004dSPhilipp Zabel #include <video/imx-ipu-v3.h>
1539b9004dSPhilipp Zabel #include "ipu-prv.h"
1639b9004dSPhilipp Zabel 
1739b9004dSPhilipp Zabel #define DP_SYNC 0
1839b9004dSPhilipp Zabel #define DP_ASYNC0 0x60
1939b9004dSPhilipp Zabel #define DP_ASYNC1 0xBC
2039b9004dSPhilipp Zabel 
2139b9004dSPhilipp Zabel #define DP_COM_CONF		0x0
2239b9004dSPhilipp Zabel #define DP_GRAPH_WIND_CTRL	0x0004
2339b9004dSPhilipp Zabel #define DP_FG_POS		0x0008
2439b9004dSPhilipp Zabel #define DP_CSC_A_0		0x0044
2539b9004dSPhilipp Zabel #define DP_CSC_A_1		0x0048
2639b9004dSPhilipp Zabel #define DP_CSC_A_2		0x004C
2739b9004dSPhilipp Zabel #define DP_CSC_A_3		0x0050
2839b9004dSPhilipp Zabel #define DP_CSC_0		0x0054
2939b9004dSPhilipp Zabel #define DP_CSC_1		0x0058
3039b9004dSPhilipp Zabel 
3139b9004dSPhilipp Zabel #define DP_COM_CONF_FG_EN		(1 << 0)
3239b9004dSPhilipp Zabel #define DP_COM_CONF_GWSEL		(1 << 1)
3339b9004dSPhilipp Zabel #define DP_COM_CONF_GWAM		(1 << 2)
3439b9004dSPhilipp Zabel #define DP_COM_CONF_GWCKE		(1 << 3)
3539b9004dSPhilipp Zabel #define DP_COM_CONF_CSC_DEF_MASK	(3 << 8)
3639b9004dSPhilipp Zabel #define DP_COM_CONF_CSC_DEF_OFFSET	8
3739b9004dSPhilipp Zabel #define DP_COM_CONF_CSC_DEF_FG		(3 << 8)
3839b9004dSPhilipp Zabel #define DP_COM_CONF_CSC_DEF_BG		(2 << 8)
3939b9004dSPhilipp Zabel #define DP_COM_CONF_CSC_DEF_BOTH	(1 << 8)
4039b9004dSPhilipp Zabel 
4139b9004dSPhilipp Zabel #define IPUV3_NUM_FLOWS		3
4239b9004dSPhilipp Zabel 
4339b9004dSPhilipp Zabel struct ipu_dp_priv;
4439b9004dSPhilipp Zabel 
4539b9004dSPhilipp Zabel struct ipu_dp {
4639b9004dSPhilipp Zabel 	u32 flow;
4739b9004dSPhilipp Zabel 	bool in_use;
4839b9004dSPhilipp Zabel 	bool foreground;
4939b9004dSPhilipp Zabel 	enum ipu_color_space in_cs;
5039b9004dSPhilipp Zabel };
5139b9004dSPhilipp Zabel 
5239b9004dSPhilipp Zabel struct ipu_flow {
5339b9004dSPhilipp Zabel 	struct ipu_dp foreground;
5439b9004dSPhilipp Zabel 	struct ipu_dp background;
5539b9004dSPhilipp Zabel 	enum ipu_color_space out_cs;
5639b9004dSPhilipp Zabel 	void __iomem *base;
5739b9004dSPhilipp Zabel 	struct ipu_dp_priv *priv;
5839b9004dSPhilipp Zabel };
5939b9004dSPhilipp Zabel 
6039b9004dSPhilipp Zabel struct ipu_dp_priv {
6139b9004dSPhilipp Zabel 	struct ipu_soc *ipu;
6239b9004dSPhilipp Zabel 	struct device *dev;
6339b9004dSPhilipp Zabel 	void __iomem *base;
6439b9004dSPhilipp Zabel 	struct ipu_flow flow[IPUV3_NUM_FLOWS];
6539b9004dSPhilipp Zabel 	struct mutex mutex;
6639b9004dSPhilipp Zabel 	int use_count;
6739b9004dSPhilipp Zabel };
6839b9004dSPhilipp Zabel 
6939b9004dSPhilipp Zabel static u32 ipu_dp_flow_base[] = {DP_SYNC, DP_ASYNC0, DP_ASYNC1};
7039b9004dSPhilipp Zabel 
to_flow(struct ipu_dp * dp)7139b9004dSPhilipp Zabel static inline struct ipu_flow *to_flow(struct ipu_dp *dp)
7239b9004dSPhilipp Zabel {
7339b9004dSPhilipp Zabel 	if (dp->foreground)
7439b9004dSPhilipp Zabel 		return container_of(dp, struct ipu_flow, foreground);
7539b9004dSPhilipp Zabel 	else
7639b9004dSPhilipp Zabel 		return container_of(dp, struct ipu_flow, background);
7739b9004dSPhilipp Zabel }
7839b9004dSPhilipp Zabel 
ipu_dp_set_global_alpha(struct ipu_dp * dp,bool enable,u8 alpha,bool bg_chan)7939b9004dSPhilipp Zabel int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable,
8039b9004dSPhilipp Zabel 		u8 alpha, bool bg_chan)
8139b9004dSPhilipp Zabel {
8239b9004dSPhilipp Zabel 	struct ipu_flow *flow = to_flow(dp);
8339b9004dSPhilipp Zabel 	struct ipu_dp_priv *priv = flow->priv;
8439b9004dSPhilipp Zabel 	u32 reg;
8539b9004dSPhilipp Zabel 
8639b9004dSPhilipp Zabel 	mutex_lock(&priv->mutex);
8739b9004dSPhilipp Zabel 
8839b9004dSPhilipp Zabel 	reg = readl(flow->base + DP_COM_CONF);
8939b9004dSPhilipp Zabel 	if (bg_chan)
9039b9004dSPhilipp Zabel 		reg &= ~DP_COM_CONF_GWSEL;
9139b9004dSPhilipp Zabel 	else
9239b9004dSPhilipp Zabel 		reg |= DP_COM_CONF_GWSEL;
9339b9004dSPhilipp Zabel 	writel(reg, flow->base + DP_COM_CONF);
9439b9004dSPhilipp Zabel 
9539b9004dSPhilipp Zabel 	if (enable) {
9639b9004dSPhilipp Zabel 		reg = readl(flow->base + DP_GRAPH_WIND_CTRL) & 0x00FFFFFFL;
9739b9004dSPhilipp Zabel 		writel(reg | ((u32) alpha << 24),
9839b9004dSPhilipp Zabel 			     flow->base + DP_GRAPH_WIND_CTRL);
9939b9004dSPhilipp Zabel 
10039b9004dSPhilipp Zabel 		reg = readl(flow->base + DP_COM_CONF);
10139b9004dSPhilipp Zabel 		writel(reg | DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
10239b9004dSPhilipp Zabel 	} else {
10339b9004dSPhilipp Zabel 		reg = readl(flow->base + DP_COM_CONF);
10439b9004dSPhilipp Zabel 		writel(reg & ~DP_COM_CONF_GWAM, flow->base + DP_COM_CONF);
10539b9004dSPhilipp Zabel 	}
10639b9004dSPhilipp Zabel 
107f9bb7acbSPhilipp Zabel 	ipu_srm_dp_update(priv->ipu, true);
10839b9004dSPhilipp Zabel 
10939b9004dSPhilipp Zabel 	mutex_unlock(&priv->mutex);
11039b9004dSPhilipp Zabel 
11139b9004dSPhilipp Zabel 	return 0;
11239b9004dSPhilipp Zabel }
11339b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dp_set_global_alpha);
11439b9004dSPhilipp Zabel 
ipu_dp_set_window_pos(struct ipu_dp * dp,u16 x_pos,u16 y_pos)11539b9004dSPhilipp Zabel int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos)
11639b9004dSPhilipp Zabel {
11739b9004dSPhilipp Zabel 	struct ipu_flow *flow = to_flow(dp);
11839b9004dSPhilipp Zabel 	struct ipu_dp_priv *priv = flow->priv;
11939b9004dSPhilipp Zabel 
12039b9004dSPhilipp Zabel 	writel((x_pos << 16) | y_pos, flow->base + DP_FG_POS);
12139b9004dSPhilipp Zabel 
122f9bb7acbSPhilipp Zabel 	ipu_srm_dp_update(priv->ipu, true);
12339b9004dSPhilipp Zabel 
12439b9004dSPhilipp Zabel 	return 0;
12539b9004dSPhilipp Zabel }
12639b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dp_set_window_pos);
12739b9004dSPhilipp Zabel 
ipu_dp_csc_init(struct ipu_flow * flow,enum drm_color_encoding ycbcr_enc,enum drm_color_range range,enum ipu_color_space in,enum ipu_color_space out,u32 place)12839b9004dSPhilipp Zabel static void ipu_dp_csc_init(struct ipu_flow *flow,
129*4618cb79SPhilipp Zabel 		enum drm_color_encoding ycbcr_enc,
130*4618cb79SPhilipp Zabel 		enum drm_color_range range,
13139b9004dSPhilipp Zabel 		enum ipu_color_space in,
13239b9004dSPhilipp Zabel 		enum ipu_color_space out,
13339b9004dSPhilipp Zabel 		u32 place)
13439b9004dSPhilipp Zabel {
13539b9004dSPhilipp Zabel 	u32 reg;
13639b9004dSPhilipp Zabel 
13739b9004dSPhilipp Zabel 	reg = readl(flow->base + DP_COM_CONF);
13839b9004dSPhilipp Zabel 	reg &= ~DP_COM_CONF_CSC_DEF_MASK;
13939b9004dSPhilipp Zabel 
14039b9004dSPhilipp Zabel 	if (in == out) {
14139b9004dSPhilipp Zabel 		writel(reg, flow->base + DP_COM_CONF);
14239b9004dSPhilipp Zabel 		return;
14339b9004dSPhilipp Zabel 	}
14439b9004dSPhilipp Zabel 
14539b9004dSPhilipp Zabel 	if (in == IPUV3_COLORSPACE_RGB && out == IPUV3_COLORSPACE_YUV) {
14639b9004dSPhilipp Zabel 		writel(0x099 | (0x12d << 16), flow->base + DP_CSC_A_0);
14739b9004dSPhilipp Zabel 		writel(0x03a | (0x3a9 << 16), flow->base + DP_CSC_A_1);
14839b9004dSPhilipp Zabel 		writel(0x356 | (0x100 << 16), flow->base + DP_CSC_A_2);
14939b9004dSPhilipp Zabel 		writel(0x100 | (0x329 << 16), flow->base + DP_CSC_A_3);
15039b9004dSPhilipp Zabel 		writel(0x3d6 | (0x0000 << 16) | (2 << 30),
15139b9004dSPhilipp Zabel 				flow->base + DP_CSC_0);
15239b9004dSPhilipp Zabel 		writel(0x200 | (2 << 14) | (0x200 << 16) | (2 << 30),
15339b9004dSPhilipp Zabel 				flow->base + DP_CSC_1);
154*4618cb79SPhilipp Zabel 	} else if (ycbcr_enc == DRM_COLOR_YCBCR_BT709) {
155*4618cb79SPhilipp Zabel 		/* Rec.709 limited range */
156*4618cb79SPhilipp Zabel 		writel(0x095 | (0x000 << 16), flow->base + DP_CSC_A_0);
157*4618cb79SPhilipp Zabel 		writel(0x0e5 | (0x095 << 16), flow->base + DP_CSC_A_1);
158*4618cb79SPhilipp Zabel 		writel(0x3e5 | (0x3bc << 16), flow->base + DP_CSC_A_2);
159*4618cb79SPhilipp Zabel 		writel(0x095 | (0x10e << 16), flow->base + DP_CSC_A_3);
160*4618cb79SPhilipp Zabel 		writel(0x000 | (0x3e10 << 16) | (1 << 30),
161*4618cb79SPhilipp Zabel 				flow->base + DP_CSC_0);
162*4618cb79SPhilipp Zabel 		writel(0x09a | (1 << 14) | (0x3dbe << 16) | (1 << 30),
163*4618cb79SPhilipp Zabel 				flow->base + DP_CSC_1);
16439b9004dSPhilipp Zabel 	} else {
165*4618cb79SPhilipp Zabel 		/* BT.601 limited range */
16639b9004dSPhilipp Zabel 		writel(0x095 | (0x000 << 16), flow->base + DP_CSC_A_0);
16739b9004dSPhilipp Zabel 		writel(0x0cc | (0x095 << 16), flow->base + DP_CSC_A_1);
16839b9004dSPhilipp Zabel 		writel(0x3ce | (0x398 << 16), flow->base + DP_CSC_A_2);
16939b9004dSPhilipp Zabel 		writel(0x095 | (0x0ff << 16), flow->base + DP_CSC_A_3);
17039b9004dSPhilipp Zabel 		writel(0x000 | (0x3e42 << 16) | (1 << 30),
17139b9004dSPhilipp Zabel 				flow->base + DP_CSC_0);
17239b9004dSPhilipp Zabel 		writel(0x10a | (1 << 14) | (0x3dd6 << 16) | (1 << 30),
17339b9004dSPhilipp Zabel 				flow->base + DP_CSC_1);
17439b9004dSPhilipp Zabel 	}
17539b9004dSPhilipp Zabel 
17639b9004dSPhilipp Zabel 	reg |= place;
17739b9004dSPhilipp Zabel 
17839b9004dSPhilipp Zabel 	writel(reg, flow->base + DP_COM_CONF);
17939b9004dSPhilipp Zabel }
18039b9004dSPhilipp Zabel 
ipu_dp_setup_channel(struct ipu_dp * dp,enum drm_color_encoding ycbcr_enc,enum drm_color_range range,enum ipu_color_space in,enum ipu_color_space out)18139b9004dSPhilipp Zabel int ipu_dp_setup_channel(struct ipu_dp *dp,
182*4618cb79SPhilipp Zabel 		enum drm_color_encoding ycbcr_enc,
183*4618cb79SPhilipp Zabel 		enum drm_color_range range,
18439b9004dSPhilipp Zabel 		enum ipu_color_space in,
18539b9004dSPhilipp Zabel 		enum ipu_color_space out)
18639b9004dSPhilipp Zabel {
18739b9004dSPhilipp Zabel 	struct ipu_flow *flow = to_flow(dp);
18839b9004dSPhilipp Zabel 	struct ipu_dp_priv *priv = flow->priv;
18939b9004dSPhilipp Zabel 
19039b9004dSPhilipp Zabel 	mutex_lock(&priv->mutex);
19139b9004dSPhilipp Zabel 
19239b9004dSPhilipp Zabel 	dp->in_cs = in;
19339b9004dSPhilipp Zabel 
19439b9004dSPhilipp Zabel 	if (!dp->foreground)
19539b9004dSPhilipp Zabel 		flow->out_cs = out;
19639b9004dSPhilipp Zabel 
19739b9004dSPhilipp Zabel 	if (flow->foreground.in_cs == flow->background.in_cs) {
19839b9004dSPhilipp Zabel 		/*
19939b9004dSPhilipp Zabel 		 * foreground and background are of same colorspace, put
20039b9004dSPhilipp Zabel 		 * colorspace converter after combining unit.
20139b9004dSPhilipp Zabel 		 */
202*4618cb79SPhilipp Zabel 		ipu_dp_csc_init(flow, ycbcr_enc, range,
203*4618cb79SPhilipp Zabel 				flow->foreground.in_cs, flow->out_cs,
20439b9004dSPhilipp Zabel 				DP_COM_CONF_CSC_DEF_BOTH);
20539b9004dSPhilipp Zabel 	} else {
206d4fad0a4SLucas Stach 		if (flow->foreground.in_cs == IPUV3_COLORSPACE_UNKNOWN ||
207d4fad0a4SLucas Stach 		    flow->foreground.in_cs == flow->out_cs)
20839b9004dSPhilipp Zabel 			/*
20939b9004dSPhilipp Zabel 			 * foreground identical to output, apply color
21039b9004dSPhilipp Zabel 			 * conversion on background
21139b9004dSPhilipp Zabel 			 */
212*4618cb79SPhilipp Zabel 			ipu_dp_csc_init(flow, ycbcr_enc, range,
213*4618cb79SPhilipp Zabel 					flow->background.in_cs,
21439b9004dSPhilipp Zabel 					flow->out_cs, DP_COM_CONF_CSC_DEF_BG);
21539b9004dSPhilipp Zabel 		else
216*4618cb79SPhilipp Zabel 			ipu_dp_csc_init(flow, ycbcr_enc, range,
217*4618cb79SPhilipp Zabel 					flow->foreground.in_cs,
21839b9004dSPhilipp Zabel 					flow->out_cs, DP_COM_CONF_CSC_DEF_FG);
21939b9004dSPhilipp Zabel 	}
22039b9004dSPhilipp Zabel 
221f9bb7acbSPhilipp Zabel 	ipu_srm_dp_update(priv->ipu, true);
22239b9004dSPhilipp Zabel 
22339b9004dSPhilipp Zabel 	mutex_unlock(&priv->mutex);
22439b9004dSPhilipp Zabel 
22539b9004dSPhilipp Zabel 	return 0;
22639b9004dSPhilipp Zabel }
22739b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dp_setup_channel);
22839b9004dSPhilipp Zabel 
ipu_dp_enable(struct ipu_soc * ipu)229682b7c1cSLinus Torvalds int ipu_dp_enable(struct ipu_soc *ipu)
23039b9004dSPhilipp Zabel {
231682b7c1cSLinus Torvalds 	struct ipu_dp_priv *priv = ipu->dp_priv;
23239b9004dSPhilipp Zabel 
23339b9004dSPhilipp Zabel 	mutex_lock(&priv->mutex);
23439b9004dSPhilipp Zabel 
23539b9004dSPhilipp Zabel 	if (!priv->use_count)
23639b9004dSPhilipp Zabel 		ipu_module_enable(priv->ipu, IPU_CONF_DP_EN);
23739b9004dSPhilipp Zabel 
23839b9004dSPhilipp Zabel 	priv->use_count++;
23939b9004dSPhilipp Zabel 
240682b7c1cSLinus Torvalds 	mutex_unlock(&priv->mutex);
241682b7c1cSLinus Torvalds 
242682b7c1cSLinus Torvalds 	return 0;
243682b7c1cSLinus Torvalds }
244682b7c1cSLinus Torvalds EXPORT_SYMBOL_GPL(ipu_dp_enable);
245682b7c1cSLinus Torvalds 
ipu_dp_enable_channel(struct ipu_dp * dp)246682b7c1cSLinus Torvalds int ipu_dp_enable_channel(struct ipu_dp *dp)
247682b7c1cSLinus Torvalds {
248682b7c1cSLinus Torvalds 	struct ipu_flow *flow = to_flow(dp);
249682b7c1cSLinus Torvalds 	struct ipu_dp_priv *priv = flow->priv;
25039b9004dSPhilipp Zabel 	u32 reg;
25139b9004dSPhilipp Zabel 
252682b7c1cSLinus Torvalds 	if (!dp->foreground)
253682b7c1cSLinus Torvalds 		return 0;
254682b7c1cSLinus Torvalds 
255682b7c1cSLinus Torvalds 	mutex_lock(&priv->mutex);
256682b7c1cSLinus Torvalds 
25739b9004dSPhilipp Zabel 	reg = readl(flow->base + DP_COM_CONF);
25839b9004dSPhilipp Zabel 	reg |= DP_COM_CONF_FG_EN;
25939b9004dSPhilipp Zabel 	writel(reg, flow->base + DP_COM_CONF);
26039b9004dSPhilipp Zabel 
261f9bb7acbSPhilipp Zabel 	ipu_srm_dp_update(priv->ipu, true);
26239b9004dSPhilipp Zabel 
26339b9004dSPhilipp Zabel 	mutex_unlock(&priv->mutex);
26439b9004dSPhilipp Zabel 
26539b9004dSPhilipp Zabel 	return 0;
26639b9004dSPhilipp Zabel }
26739b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dp_enable_channel);
26839b9004dSPhilipp Zabel 
ipu_dp_disable_channel(struct ipu_dp * dp,bool sync)269f9bb7acbSPhilipp Zabel void ipu_dp_disable_channel(struct ipu_dp *dp, bool sync)
27039b9004dSPhilipp Zabel {
27139b9004dSPhilipp Zabel 	struct ipu_flow *flow = to_flow(dp);
27239b9004dSPhilipp Zabel 	struct ipu_dp_priv *priv = flow->priv;
273682b7c1cSLinus Torvalds 	u32 reg, csc;
274682b7c1cSLinus Torvalds 
275d4fad0a4SLucas Stach 	dp->in_cs = IPUV3_COLORSPACE_UNKNOWN;
276d4fad0a4SLucas Stach 
277682b7c1cSLinus Torvalds 	if (!dp->foreground)
278682b7c1cSLinus Torvalds 		return;
27939b9004dSPhilipp Zabel 
28039b9004dSPhilipp Zabel 	mutex_lock(&priv->mutex);
28139b9004dSPhilipp Zabel 
28239b9004dSPhilipp Zabel 	reg = readl(flow->base + DP_COM_CONF);
28339b9004dSPhilipp Zabel 	csc = reg & DP_COM_CONF_CSC_DEF_MASK;
28439b9004dSPhilipp Zabel 	reg &= ~DP_COM_CONF_CSC_DEF_MASK;
285d4fad0a4SLucas Stach 	if (csc == DP_COM_CONF_CSC_DEF_BOTH || csc == DP_COM_CONF_CSC_DEF_BG)
286d4fad0a4SLucas Stach 		reg |= DP_COM_CONF_CSC_DEF_BG;
28739b9004dSPhilipp Zabel 
28839b9004dSPhilipp Zabel 	reg &= ~DP_COM_CONF_FG_EN;
28939b9004dSPhilipp Zabel 	writel(reg, flow->base + DP_COM_CONF);
29039b9004dSPhilipp Zabel 
29139b9004dSPhilipp Zabel 	writel(0, flow->base + DP_FG_POS);
292f9bb7acbSPhilipp Zabel 	ipu_srm_dp_update(priv->ipu, sync);
293682b7c1cSLinus Torvalds 
294682b7c1cSLinus Torvalds 	mutex_unlock(&priv->mutex);
29539b9004dSPhilipp Zabel }
296682b7c1cSLinus Torvalds EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
297682b7c1cSLinus Torvalds 
ipu_dp_disable(struct ipu_soc * ipu)298682b7c1cSLinus Torvalds void ipu_dp_disable(struct ipu_soc *ipu)
299682b7c1cSLinus Torvalds {
300682b7c1cSLinus Torvalds 	struct ipu_dp_priv *priv = ipu->dp_priv;
301682b7c1cSLinus Torvalds 
302682b7c1cSLinus Torvalds 	mutex_lock(&priv->mutex);
303682b7c1cSLinus Torvalds 
304682b7c1cSLinus Torvalds 	priv->use_count--;
30539b9004dSPhilipp Zabel 
30639b9004dSPhilipp Zabel 	if (!priv->use_count)
30739b9004dSPhilipp Zabel 		ipu_module_disable(priv->ipu, IPU_CONF_DP_EN);
30839b9004dSPhilipp Zabel 
30939b9004dSPhilipp Zabel 	if (priv->use_count < 0)
31039b9004dSPhilipp Zabel 		priv->use_count = 0;
31139b9004dSPhilipp Zabel 
31239b9004dSPhilipp Zabel 	mutex_unlock(&priv->mutex);
31339b9004dSPhilipp Zabel }
314682b7c1cSLinus Torvalds EXPORT_SYMBOL_GPL(ipu_dp_disable);
31539b9004dSPhilipp Zabel 
ipu_dp_get(struct ipu_soc * ipu,unsigned int flow)31639b9004dSPhilipp Zabel struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow)
31739b9004dSPhilipp Zabel {
31839b9004dSPhilipp Zabel 	struct ipu_dp_priv *priv = ipu->dp_priv;
31939b9004dSPhilipp Zabel 	struct ipu_dp *dp;
32039b9004dSPhilipp Zabel 
32139b9004dSPhilipp Zabel 	if ((flow >> 1) >= IPUV3_NUM_FLOWS)
32239b9004dSPhilipp Zabel 		return ERR_PTR(-EINVAL);
32339b9004dSPhilipp Zabel 
32439b9004dSPhilipp Zabel 	if (flow & 1)
32539b9004dSPhilipp Zabel 		dp = &priv->flow[flow >> 1].foreground;
32639b9004dSPhilipp Zabel 	else
32739b9004dSPhilipp Zabel 		dp = &priv->flow[flow >> 1].background;
32839b9004dSPhilipp Zabel 
32939b9004dSPhilipp Zabel 	if (dp->in_use)
33039b9004dSPhilipp Zabel 		return ERR_PTR(-EBUSY);
33139b9004dSPhilipp Zabel 
33239b9004dSPhilipp Zabel 	dp->in_use = true;
33339b9004dSPhilipp Zabel 
33439b9004dSPhilipp Zabel 	return dp;
33539b9004dSPhilipp Zabel }
33639b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dp_get);
33739b9004dSPhilipp Zabel 
ipu_dp_put(struct ipu_dp * dp)33839b9004dSPhilipp Zabel void ipu_dp_put(struct ipu_dp *dp)
33939b9004dSPhilipp Zabel {
34039b9004dSPhilipp Zabel 	dp->in_use = false;
34139b9004dSPhilipp Zabel }
34239b9004dSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_dp_put);
34339b9004dSPhilipp Zabel 
ipu_dp_init(struct ipu_soc * ipu,struct device * dev,unsigned long base)34439b9004dSPhilipp Zabel int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
34539b9004dSPhilipp Zabel {
34639b9004dSPhilipp Zabel 	struct ipu_dp_priv *priv;
34739b9004dSPhilipp Zabel 	int i;
34839b9004dSPhilipp Zabel 
34939b9004dSPhilipp Zabel 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
35039b9004dSPhilipp Zabel 	if (!priv)
35139b9004dSPhilipp Zabel 		return -ENOMEM;
35239b9004dSPhilipp Zabel 	priv->dev = dev;
35339b9004dSPhilipp Zabel 	priv->ipu = ipu;
35439b9004dSPhilipp Zabel 
35539b9004dSPhilipp Zabel 	ipu->dp_priv = priv;
35639b9004dSPhilipp Zabel 
35739b9004dSPhilipp Zabel 	priv->base = devm_ioremap(dev, base, PAGE_SIZE);
35839b9004dSPhilipp Zabel 	if (!priv->base)
35939b9004dSPhilipp Zabel 		return -ENOMEM;
36039b9004dSPhilipp Zabel 
36139b9004dSPhilipp Zabel 	mutex_init(&priv->mutex);
36239b9004dSPhilipp Zabel 
36339b9004dSPhilipp Zabel 	for (i = 0; i < IPUV3_NUM_FLOWS; i++) {
364d4fad0a4SLucas Stach 		priv->flow[i].background.in_cs = IPUV3_COLORSPACE_UNKNOWN;
365d4fad0a4SLucas Stach 		priv->flow[i].foreground.in_cs = IPUV3_COLORSPACE_UNKNOWN;
36639b9004dSPhilipp Zabel 		priv->flow[i].foreground.foreground = true;
36739b9004dSPhilipp Zabel 		priv->flow[i].base = priv->base + ipu_dp_flow_base[i];
36839b9004dSPhilipp Zabel 		priv->flow[i].priv = priv;
36939b9004dSPhilipp Zabel 	}
37039b9004dSPhilipp Zabel 
37139b9004dSPhilipp Zabel 	return 0;
37239b9004dSPhilipp Zabel }
37339b9004dSPhilipp Zabel 
ipu_dp_exit(struct ipu_soc * ipu)37439b9004dSPhilipp Zabel void ipu_dp_exit(struct ipu_soc *ipu)
37539b9004dSPhilipp Zabel {
37639b9004dSPhilipp Zabel }
377