ae682084a10a9bdd622ae7590e544cbafb6e3075
[sfrench/cifs-2.6.git] / drivers / gpu / ipu-v3 / ipu-dmfc.c
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
39 struct 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
47 static 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
83 struct ipu_dmfc_priv;
84
85 struct 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
92 struct 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
101 int 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(priv->ipu, IPU_CONF_DMFC_EN);
108
109         priv->use_count++;
110
111         mutex_unlock(&priv->mutex);
112
113         return 0;
114 }
115 EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
116
117 void 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(priv->ipu, IPU_CONF_DMFC_EN);
127
128         if (priv->use_count < 0)
129                 priv->use_count = 0;
130
131         mutex_unlock(&priv->mutex);
132 }
133 EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
134
135 void 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(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(dmfc_gen1, priv->base + DMFC_GENERAL1);
150
151         mutex_unlock(&priv->mutex);
152 }
153 EXPORT_SYMBOL_GPL(ipu_dmfc_config_wait4eot);
154
155 struct 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(-ENODEV);
164 }
165 EXPORT_SYMBOL_GPL(ipu_dmfc_get);
166
167 void ipu_dmfc_put(struct dmfc_channel *dmfc)
168 {
169 }
170 EXPORT_SYMBOL_GPL(ipu_dmfc_put);
171
172 int 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, sizeof(*priv), GFP_KERNEL);
179         if (!priv)
180                 return -ENOMEM;
181
182         priv->base = devm_ioremap(dev, 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(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);
208
209         return 0;
210 }
211
212 void ipu_dmfc_exit(struct ipu_soc *ipu)
213 {
214 }