]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/gpu/ipu-v3/ipu-dmfc.c
drm: msm: Add ASoC generic hdmi audio codec support.
[karo-tx-linux.git] / drivers / gpu / ipu-v3 / ipu-dmfc.c
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 #define DMFC_FIFO_SIZE_64               (3 << 3)
49 #define DMFC_FIFO_SIZE_128              (2 << 3)
50 #define DMFC_FIFO_SIZE_256              (1 << 3)
51 #define DMFC_FIFO_SIZE_512              (0 << 3)
52
53 #define DMFC_SEGMENT(x)                 ((x & 0x7) << 0)
54 #define DMFC_BURSTSIZE_128              (0 << 6)
55 #define DMFC_BURSTSIZE_64               (1 << 6)
56 #define DMFC_BURSTSIZE_32               (2 << 6)
57 #define DMFC_BURSTSIZE_16               (3 << 6)
58
59 struct dmfc_channel_data {
60         int             ipu_channel;
61         unsigned long   channel_reg;
62         unsigned long   shift;
63         unsigned        eot_shift;
64         unsigned        max_fifo_lines;
65 };
66
67 static const struct dmfc_channel_data dmfcdata[] = {
68         {
69                 .ipu_channel    = IPUV3_CHANNEL_MEM_BG_SYNC,
70                 .channel_reg    = DMFC_DP_CHAN,
71                 .shift          = DMFC_DP_CHAN_5B_23,
72                 .eot_shift      = 20,
73                 .max_fifo_lines = 3,
74         }, {
75                 .ipu_channel    = 24,
76                 .channel_reg    = DMFC_DP_CHAN,
77                 .shift          = DMFC_DP_CHAN_6B_24,
78                 .eot_shift      = 22,
79                 .max_fifo_lines = 1,
80         }, {
81                 .ipu_channel    = IPUV3_CHANNEL_MEM_FG_SYNC,
82                 .channel_reg    = DMFC_DP_CHAN,
83                 .shift          = DMFC_DP_CHAN_5F_27,
84                 .eot_shift      = 21,
85                 .max_fifo_lines = 2,
86         }, {
87                 .ipu_channel    = IPUV3_CHANNEL_MEM_DC_SYNC,
88                 .channel_reg    = DMFC_WR_CHAN,
89                 .shift          = DMFC_WR_CHAN_1_28,
90                 .eot_shift      = 16,
91                 .max_fifo_lines = 2,
92         }, {
93                 .ipu_channel    = 29,
94                 .channel_reg    = DMFC_DP_CHAN,
95                 .shift          = DMFC_DP_CHAN_6F_29,
96                 .eot_shift      = 23,
97                 .max_fifo_lines = 1,
98         },
99 };
100
101 #define DMFC_NUM_CHANNELS       ARRAY_SIZE(dmfcdata)
102
103 struct ipu_dmfc_priv;
104
105 struct dmfc_channel {
106         unsigned                        slots;
107         unsigned                        slotmask;
108         unsigned                        segment;
109         int                             burstsize;
110         struct ipu_soc                  *ipu;
111         struct ipu_dmfc_priv            *priv;
112         const struct dmfc_channel_data  *data;
113 };
114
115 struct ipu_dmfc_priv {
116         struct ipu_soc *ipu;
117         struct device *dev;
118         struct dmfc_channel channels[DMFC_NUM_CHANNELS];
119         struct mutex mutex;
120         unsigned long bandwidth_per_slot;
121         void __iomem *base;
122         int use_count;
123 };
124
125 int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
126 {
127         struct ipu_dmfc_priv *priv = dmfc->priv;
128         mutex_lock(&priv->mutex);
129
130         if (!priv->use_count)
131                 ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN);
132
133         priv->use_count++;
134
135         mutex_unlock(&priv->mutex);
136
137         return 0;
138 }
139 EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
140
141 static void ipu_dmfc_wait_fifos(struct ipu_dmfc_priv *priv)
142 {
143         unsigned long timeout = jiffies + msecs_to_jiffies(1000);
144
145         while ((readl(priv->base + DMFC_STAT) & 0x02fff000) != 0x02fff000) {
146                 if (time_after(jiffies, timeout)) {
147                         dev_warn(priv->dev,
148                                  "Timeout waiting for DMFC FIFOs to clear\n");
149                         break;
150                 }
151                 cpu_relax();
152         }
153 }
154
155 void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
156 {
157         struct ipu_dmfc_priv *priv = dmfc->priv;
158
159         mutex_lock(&priv->mutex);
160
161         priv->use_count--;
162
163         if (!priv->use_count) {
164                 ipu_dmfc_wait_fifos(priv);
165                 ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN);
166         }
167
168         if (priv->use_count < 0)
169                 priv->use_count = 0;
170
171         mutex_unlock(&priv->mutex);
172 }
173 EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
174
175 static int ipu_dmfc_setup_channel(struct dmfc_channel *dmfc, int slots,
176                 int segment, int burstsize)
177 {
178         struct ipu_dmfc_priv *priv = dmfc->priv;
179         u32 val, field;
180
181         dev_dbg(priv->dev,
182                         "dmfc: using %d slots starting from segment %d for IPU channel %d\n",
183                         slots, segment, dmfc->data->ipu_channel);
184
185         switch (slots) {
186         case 1:
187                 field = DMFC_FIFO_SIZE_64;
188                 break;
189         case 2:
190                 field = DMFC_FIFO_SIZE_128;
191                 break;
192         case 4:
193                 field = DMFC_FIFO_SIZE_256;
194                 break;
195         case 8:
196                 field = DMFC_FIFO_SIZE_512;
197                 break;
198         default:
199                 return -EINVAL;
200         }
201
202         switch (burstsize) {
203         case 16:
204                 field |= DMFC_BURSTSIZE_16;
205                 break;
206         case 32:
207                 field |= DMFC_BURSTSIZE_32;
208                 break;
209         case 64:
210                 field |= DMFC_BURSTSIZE_64;
211                 break;
212         case 128:
213                 field |= DMFC_BURSTSIZE_128;
214                 break;
215         }
216
217         field |= DMFC_SEGMENT(segment);
218
219         val = readl(priv->base + dmfc->data->channel_reg);
220
221         val &= ~(0xff << dmfc->data->shift);
222         val |= field << dmfc->data->shift;
223
224         writel(val, priv->base + dmfc->data->channel_reg);
225
226         dmfc->slots = slots;
227         dmfc->segment = segment;
228         dmfc->burstsize = burstsize;
229         dmfc->slotmask = ((1 << slots) - 1) << segment;
230
231         return 0;
232 }
233
234 static int dmfc_bandwidth_to_slots(struct ipu_dmfc_priv *priv,
235                 unsigned long bandwidth)
236 {
237         int slots = 1;
238
239         while (slots * priv->bandwidth_per_slot < bandwidth)
240                 slots *= 2;
241
242         return slots;
243 }
244
245 static int dmfc_find_slots(struct ipu_dmfc_priv *priv, int slots)
246 {
247         unsigned slotmask_need, slotmask_used = 0;
248         int i, segment = 0;
249
250         slotmask_need = (1 << slots) - 1;
251
252         for (i = 0; i < DMFC_NUM_CHANNELS; i++)
253                 slotmask_used |= priv->channels[i].slotmask;
254
255         while (slotmask_need <= 0xff) {
256                 if (!(slotmask_used & slotmask_need))
257                         return segment;
258
259                 slotmask_need <<= 1;
260                 segment++;
261         }
262
263         return -EBUSY;
264 }
265
266 void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc)
267 {
268         struct ipu_dmfc_priv *priv = dmfc->priv;
269         int i;
270
271         dev_dbg(priv->dev, "dmfc: freeing %d slots starting from segment %d\n",
272                         dmfc->slots, dmfc->segment);
273
274         mutex_lock(&priv->mutex);
275
276         if (!dmfc->slots)
277                 goto out;
278
279         dmfc->slotmask = 0;
280         dmfc->slots = 0;
281         dmfc->segment = 0;
282
283         for (i = 0; i < DMFC_NUM_CHANNELS; i++)
284                 priv->channels[i].slotmask = 0;
285
286         for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
287                 if (priv->channels[i].slots > 0) {
288                         priv->channels[i].segment =
289                                 dmfc_find_slots(priv, priv->channels[i].slots);
290                         priv->channels[i].slotmask =
291                                 ((1 << priv->channels[i].slots) - 1) <<
292                                 priv->channels[i].segment;
293                 }
294         }
295
296         for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
297                 if (priv->channels[i].slots > 0)
298                         ipu_dmfc_setup_channel(&priv->channels[i],
299                                         priv->channels[i].slots,
300                                         priv->channels[i].segment,
301                                         priv->channels[i].burstsize);
302         }
303 out:
304         mutex_unlock(&priv->mutex);
305 }
306 EXPORT_SYMBOL_GPL(ipu_dmfc_free_bandwidth);
307
308 int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc,
309                 unsigned long bandwidth_pixel_per_second, int burstsize)
310 {
311         struct ipu_dmfc_priv *priv = dmfc->priv;
312         int slots = dmfc_bandwidth_to_slots(priv, bandwidth_pixel_per_second);
313         int segment = -1, ret = 0;
314
315         dev_dbg(priv->dev, "dmfc: trying to allocate %ldMpixel/s for IPU channel %d\n",
316                         bandwidth_pixel_per_second / 1000000,
317                         dmfc->data->ipu_channel);
318
319         ipu_dmfc_free_bandwidth(dmfc);
320
321         mutex_lock(&priv->mutex);
322
323         if (slots > 8) {
324                 ret = -EBUSY;
325                 goto out;
326         }
327
328         /* For the MEM_BG channel, first try to allocate twice the slots */
329         if (dmfc->data->ipu_channel == IPUV3_CHANNEL_MEM_BG_SYNC)
330                 segment = dmfc_find_slots(priv, slots * 2);
331         else if (slots < 2)
332                 /* Always allocate at least 128*4 bytes (2 slots) */
333                 slots = 2;
334
335         if (segment >= 0)
336                 slots *= 2;
337         else
338                 segment = dmfc_find_slots(priv, slots);
339         if (segment < 0) {
340                 ret = -EBUSY;
341                 goto out;
342         }
343
344         ipu_dmfc_setup_channel(dmfc, slots, segment, burstsize);
345
346 out:
347         mutex_unlock(&priv->mutex);
348
349         return ret;
350 }
351 EXPORT_SYMBOL_GPL(ipu_dmfc_alloc_bandwidth);
352
353 int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width)
354 {
355         struct ipu_dmfc_priv *priv = dmfc->priv;
356         u32 dmfc_gen1;
357
358         dmfc_gen1 = readl(priv->base + DMFC_GENERAL1);
359
360         if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines)
361                 dmfc_gen1 |= 1 << dmfc->data->eot_shift;
362         else
363                 dmfc_gen1 &= ~(1 << dmfc->data->eot_shift);
364
365         writel(dmfc_gen1, priv->base + DMFC_GENERAL1);
366
367         return 0;
368 }
369 EXPORT_SYMBOL_GPL(ipu_dmfc_init_channel);
370
371 struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
372 {
373         struct ipu_dmfc_priv *priv = ipu->dmfc_priv;
374         int i;
375
376         for (i = 0; i < DMFC_NUM_CHANNELS; i++)
377                 if (dmfcdata[i].ipu_channel == ipu_channel)
378                         return &priv->channels[i];
379         return ERR_PTR(-ENODEV);
380 }
381 EXPORT_SYMBOL_GPL(ipu_dmfc_get);
382
383 void ipu_dmfc_put(struct dmfc_channel *dmfc)
384 {
385         ipu_dmfc_free_bandwidth(dmfc);
386 }
387 EXPORT_SYMBOL_GPL(ipu_dmfc_put);
388
389 int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base,
390                 struct clk *ipu_clk)
391 {
392         struct ipu_dmfc_priv *priv;
393         int i;
394
395         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
396         if (!priv)
397                 return -ENOMEM;
398
399         priv->base = devm_ioremap(dev, base, PAGE_SIZE);
400         if (!priv->base)
401                 return -ENOMEM;
402
403         priv->dev = dev;
404         priv->ipu = ipu;
405         mutex_init(&priv->mutex);
406
407         ipu->dmfc_priv = priv;
408
409         for (i = 0; i < DMFC_NUM_CHANNELS; i++) {
410                 priv->channels[i].priv = priv;
411                 priv->channels[i].ipu = ipu;
412                 priv->channels[i].data = &dmfcdata[i];
413         }
414
415         writel(0x0, priv->base + DMFC_WR_CHAN);
416         writel(0x0, priv->base + DMFC_DP_CHAN);
417
418         /*
419          * We have a total bandwidth of clkrate * 4pixel divided
420          * into 8 slots.
421          */
422         priv->bandwidth_per_slot = clk_get_rate(ipu_clk) * 4 / 8;
423
424         dev_dbg(dev, "dmfc: 8 slots with %ldMpixel/s bandwidth each\n",
425                         priv->bandwidth_per_slot / 1000000);
426
427         writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF);
428         writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF);
429         writel(0x00000003, priv->base + DMFC_GENERAL1);
430
431         return 0;
432 }
433
434 void ipu_dmfc_exit(struct ipu_soc *ipu)
435 {
436 }