gpu: ipu-v3: smfc: Convert to per-channel
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / ipu-v3 / ipu-smfc.c
1 /*
2  * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
3  *
4  * The code contained herein is licensed under the GNU General Public
5  * License. You may obtain a copy of the GNU General Public License
6  * Version 2 or later at the following locations:
7  *
8  * http://www.opensource.org/licenses/gpl-license.html
9  * http://www.gnu.org/copyleft/gpl.html
10  */
11 #define DEBUG
12 #include <linux/export.h>
13 #include <linux/types.h>
14 #include <linux/init.h>
15 #include <linux/io.h>
16 #include <linux/errno.h>
17 #include <linux/spinlock.h>
18 #include <linux/delay.h>
19 #include <linux/clk.h>
20 #include <video/imx-ipu-v3.h>
21
22 #include "ipu-prv.h"
23
24 struct ipu_smfc {
25         struct ipu_smfc_priv *priv;
26         int chno;
27         bool inuse;
28 };
29
30 struct ipu_smfc_priv {
31         void __iomem *base;
32         spinlock_t lock;
33         struct ipu_soc *ipu;
34         struct ipu_smfc channel[4];
35         int use_count;
36 };
37
38 /*SMFC Registers */
39 #define SMFC_MAP        0x0000
40 #define SMFC_WMC        0x0004
41 #define SMFC_BS         0x0008
42
43 int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize)
44 {
45         struct ipu_smfc_priv *priv = smfc->priv;
46         unsigned long flags;
47         u32 val, shift;
48
49         spin_lock_irqsave(&priv->lock, flags);
50
51         shift = smfc->chno * 4;
52         val = readl(priv->base + SMFC_BS);
53         val &= ~(0xf << shift);
54         val |= burstsize << shift;
55         writel(val, priv->base + SMFC_BS);
56
57         spin_unlock_irqrestore(&priv->lock, flags);
58
59         return 0;
60 }
61 EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize);
62
63 int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id)
64 {
65         struct ipu_smfc_priv *priv = smfc->priv;
66         unsigned long flags;
67         u32 val, shift;
68
69         spin_lock_irqsave(&priv->lock, flags);
70
71         shift = smfc->chno * 3;
72         val = readl(priv->base + SMFC_MAP);
73         val &= ~(0x7 << shift);
74         val |= ((csi_id << 2) | mipi_id) << shift;
75         writel(val, priv->base + SMFC_MAP);
76
77         spin_unlock_irqrestore(&priv->lock, flags);
78
79         return 0;
80 }
81 EXPORT_SYMBOL_GPL(ipu_smfc_map_channel);
82
83 int ipu_smfc_enable(struct ipu_smfc *smfc)
84 {
85         struct ipu_smfc_priv *priv = smfc->priv;
86         unsigned long flags;
87
88         spin_lock_irqsave(&priv->lock, flags);
89
90         if (!priv->use_count)
91                 ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN);
92
93         priv->use_count++;
94
95         spin_unlock_irqrestore(&priv->lock, flags);
96
97         return 0;
98 }
99 EXPORT_SYMBOL_GPL(ipu_smfc_enable);
100
101 int ipu_smfc_disable(struct ipu_smfc *smfc)
102 {
103         struct ipu_smfc_priv *priv = smfc->priv;
104         unsigned long flags;
105
106         spin_lock_irqsave(&priv->lock, flags);
107
108         priv->use_count--;
109
110         if (!priv->use_count)
111                 ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN);
112
113         if (priv->use_count < 0)
114                 priv->use_count = 0;
115
116         spin_unlock_irqrestore(&priv->lock, flags);
117
118         return 0;
119 }
120 EXPORT_SYMBOL_GPL(ipu_smfc_disable);
121
122 struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno)
123 {
124         struct ipu_smfc_priv *priv = ipu->smfc_priv;
125         struct ipu_smfc *smfc, *ret;
126         unsigned long flags;
127
128         if (chno >= 4)
129                 return ERR_PTR(-EINVAL);
130
131         smfc = &priv->channel[chno];
132         ret = smfc;
133
134         spin_lock_irqsave(&priv->lock, flags);
135
136         if (smfc->inuse) {
137                 ret = ERR_PTR(-EBUSY);
138                 goto unlock;
139         }
140
141         smfc->inuse = true;
142 unlock:
143         spin_unlock_irqrestore(&priv->lock, flags);
144         return ret;
145 }
146 EXPORT_SYMBOL_GPL(ipu_smfc_get);
147
148 void ipu_smfc_put(struct ipu_smfc *smfc)
149 {
150         struct ipu_smfc_priv *priv = smfc->priv;
151         unsigned long flags;
152
153         spin_lock_irqsave(&priv->lock, flags);
154         smfc->inuse = false;
155         spin_unlock_irqrestore(&priv->lock, flags);
156 }
157 EXPORT_SYMBOL_GPL(ipu_smfc_put);
158
159 int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,
160                   unsigned long base)
161 {
162         struct ipu_smfc_priv *priv;
163         int i;
164
165         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
166         if (!priv)
167                 return -ENOMEM;
168
169         ipu->smfc_priv = priv;
170         spin_lock_init(&priv->lock);
171         priv->ipu = ipu;
172
173         priv->base = devm_ioremap(dev, base, PAGE_SIZE);
174         if (!priv->base)
175                 return -ENOMEM;
176
177         for (i = 0; i < 4; i++) {
178                 priv->channel[i].priv = priv;
179                 priv->channel[i].chno = i;
180         }
181
182         pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base);
183
184         return 0;
185 }
186
187 void ipu_smfc_exit(struct ipu_soc *ipu)
188 {
189 }