1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
4 * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
5 */
6#include <linux/export.h>
7#include <linux/types.h>
8#include <linux/errno.h>
9#include <linux/io.h>
10
11#include <video/imx-ipu-v3.h>
12#include "ipu-prv.h"
13
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
28
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
33
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
38
39struct dmfc_channel_data {
40 int ipu_channel;
41 unsigned long channel_reg;
42 unsigned long shift;
43 unsigned eot_shift;
44 unsigned max_fifo_lines;
45};
46
47static const struct dmfc_channel_data dmfcdata[] = {
48 {
49 .ipu_channel = IPUV3_CHANNEL_MEM_BG_SYNC,
50 .channel_reg = DMFC_DP_CHAN,
51 .shift = DMFC_DP_CHAN_5B_23,
52 .eot_shift = 20,
53 .max_fifo_lines = 3,
54 }, {
55 .ipu_channel = 24,
56 .channel_reg = DMFC_DP_CHAN,
57 .shift = DMFC_DP_CHAN_6B_24,
58 .eot_shift = 22,
59 .max_fifo_lines = 1,
60 }, {
61 .ipu_channel = IPUV3_CHANNEL_MEM_FG_SYNC,
62 .channel_reg = DMFC_DP_CHAN,
63 .shift = DMFC_DP_CHAN_5F_27,
64 .eot_shift = 21,
65 .max_fifo_lines = 2,
66 }, {
67 .ipu_channel = IPUV3_CHANNEL_MEM_DC_SYNC,
68 .channel_reg = DMFC_WR_CHAN,
69 .shift = DMFC_WR_CHAN_1_28,
70 .eot_shift = 16,
71 .max_fifo_lines = 2,
72 }, {
73 .ipu_channel = 29,
74 .channel_reg = DMFC_DP_CHAN,
75 .shift = DMFC_DP_CHAN_6F_29,
76 .eot_shift = 23,
77 .max_fifo_lines = 1,
78 },
79};
80
81#define DMFC_NUM_CHANNELS ARRAY_SIZE(dmfcdata)
82
83struct ipu_dmfc_priv;
84
85struct dmfc_channel {
86 unsigned slots;
87 struct ipu_soc *ipu;
88 struct ipu_dmfc_priv *priv;
89 const struct dmfc_channel_data *data;
90};
91
92struct ipu_dmfc_priv {
93 struct ipu_soc *ipu;
94 struct device *dev;
95 struct dmfc_channel channels[DMFC_NUM_CHANNELS];
96 struct mutex mutex;
97 void __iomem *base;
98 int use_count;
99};
100
101int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
102{
103 struct ipu_dmfc_priv *priv = dmfc->priv;
104 mutex_lock(&priv->mutex);
105
106 if (!priv->use_count)
107 ipu_module_enable(ipu: priv->ipu, mask: IPU_CONF_DMFC_EN);
108
109 priv->use_count++;
110
111 mutex_unlock(lock: &priv->mutex);
112
113 return 0;
114}
115EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
116
117void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
118{
119 struct ipu_dmfc_priv *priv = dmfc->priv;
120
121 mutex_lock(&priv->mutex);
122
123 priv->use_count--;
124
125 if (!priv->use_count)
126 ipu_module_disable(ipu: priv->ipu, mask: IPU_CONF_DMFC_EN);
127
128 if (priv->use_count < 0)
129 priv->use_count = 0;
130
131 mutex_unlock(lock: &priv->mutex);
132}
133EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
134
135void ipu_dmfc_config_wait4eot(struct dmfc_channel *dmfc, int width)
136{
137 struct ipu_dmfc_priv *priv = dmfc->priv;
138 u32 dmfc_gen1;
139
140 mutex_lock(&priv->mutex);
141
142 dmfc_gen1 = readl(addr: priv->base + DMFC_GENERAL1);
143
144 if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
145 dmfc_gen1 |= 1 << dmfc->data->eot_shift;
146 else
147 dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
148
149 writel(val: dmfc_gen1, addr: priv->base + DMFC_GENERAL1);
150
151 mutex_unlock(lock: &priv->mutex);
152}
153EXPORT_SYMBOL_GPL(ipu_dmfc_config_wait4eot);
154
155struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
156{
157 struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
158 int i;
159
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(error: -ENODEV);
164}
165EXPORT_SYMBOL_GPL(ipu_dmfc_get);
166
167void ipu_dmfc_put(struct dmfc_channel *dmfc)
168{
169}
170EXPORT_SYMBOL_GPL(ipu_dmfc_put);
171
172int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
173 struct clk *ipu_clk)
174{
175 struct ipu_dmfc_priv *priv;
176 int i;
177
178 priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL);
179 if (!priv)
180 return -ENOMEM;
181
182 priv->base = devm_ioremap(dev, offset: base, PAGE_SIZE);
183 if (!priv->base)
184 return -ENOMEM;
185
186 priv->dev = dev;
187 priv->ipu = ipu;
188 mutex_init(&priv->mutex);
189
190 ipu->dmfc_priv = priv;
191
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];
196
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;
201 }
202
203 writel(val: 0x00000050, addr: priv->base + DMFC_WR_CHAN);
204 writel(val: 0x00005654, addr: priv->base + DMFC_DP_CHAN);
205 writel(val: 0x202020f6, addr: priv->base + DMFC_WR_CHAN_DEF);
206 writel(val: 0x2020f6f6, addr: priv->base + DMFC_DP_CHAN_DEF);
207 writel(val: 0x00000003, addr: priv->base + DMFC_GENERAL1);
208
209 return 0;
210}
211
212void ipu_dmfc_exit(struct ipu_soc *ipu)
213{
214}
215

source code of linux/drivers/gpu/ipu-v3/ipu-dmfc.c