blob: 4ef910991413019503d95d2e3868ce06e70f7e05 [file] [log] [blame]
Philipp Zabel35de9252012-05-09 16:59:01 +02001/*
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 */
Philipp Zabel35de9252012-05-09 16:59:01 +020011#include <linux/export.h>
12#include <linux/types.h>
13#include <linux/init.h>
14#include <linux/io.h>
15#include <linux/errno.h>
16#include <linux/spinlock.h>
17#include <linux/delay.h>
18#include <linux/clk.h>
19#include <video/imx-ipu-v3.h>
20
21#include "ipu-prv.h"
22
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -070023struct ipu_smfc {
24 struct ipu_smfc_priv *priv;
25 int chno;
26 bool inuse;
27};
28
Philipp Zabel35de9252012-05-09 16:59:01 +020029struct ipu_smfc_priv {
30 void __iomem *base;
31 spinlock_t lock;
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -070032 struct ipu_soc *ipu;
33 struct ipu_smfc channel[4];
34 int use_count;
Philipp Zabel35de9252012-05-09 16:59:01 +020035};
36
37/*SMFC Registers */
38#define SMFC_MAP 0x0000
39#define SMFC_WMC 0x0004
40#define SMFC_BS 0x0008
41
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -070042int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize)
Philipp Zabel35de9252012-05-09 16:59:01 +020043{
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -070044 struct ipu_smfc_priv *priv = smfc->priv;
Philipp Zabel35de9252012-05-09 16:59:01 +020045 unsigned long flags;
46 u32 val, shift;
47
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -070048 spin_lock_irqsave(&priv->lock, flags);
Philipp Zabel35de9252012-05-09 16:59:01 +020049
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -070050 shift = smfc->chno * 4;
51 val = readl(priv->base + SMFC_BS);
Philipp Zabel35de9252012-05-09 16:59:01 +020052 val &= ~(0xf << shift);
53 val |= burstsize << shift;
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -070054 writel(val, priv->base + SMFC_BS);
Philipp Zabel35de9252012-05-09 16:59:01 +020055
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -070056 spin_unlock_irqrestore(&priv->lock, flags);
Philipp Zabel35de9252012-05-09 16:59:01 +020057
58 return 0;
59}
60EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize);
61
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -070062int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id)
Philipp Zabel35de9252012-05-09 16:59:01 +020063{
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -070064 struct ipu_smfc_priv *priv = smfc->priv;
Philipp Zabel35de9252012-05-09 16:59:01 +020065 unsigned long flags;
66 u32 val, shift;
67
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -070068 spin_lock_irqsave(&priv->lock, flags);
Philipp Zabel35de9252012-05-09 16:59:01 +020069
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -070070 shift = smfc->chno * 3;
71 val = readl(priv->base + SMFC_MAP);
Philipp Zabel35de9252012-05-09 16:59:01 +020072 val &= ~(0x7 << shift);
73 val |= ((csi_id << 2) | mipi_id) << shift;
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -070074 writel(val, priv->base + SMFC_MAP);
Philipp Zabel35de9252012-05-09 16:59:01 +020075
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -070076 spin_unlock_irqrestore(&priv->lock, flags);
Philipp Zabel35de9252012-05-09 16:59:01 +020077
78 return 0;
79}
80EXPORT_SYMBOL_GPL(ipu_smfc_map_channel);
81
Steve Longerbeama2be35e2014-06-25 18:05:35 -070082int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level)
83{
84 struct ipu_smfc_priv *priv = smfc->priv;
85 unsigned long flags;
86 u32 val, shift;
87
88 spin_lock_irqsave(&priv->lock, flags);
89
90 shift = smfc->chno * 6 + (smfc->chno > 1 ? 4 : 0);
91 val = readl(priv->base + SMFC_WMC);
92 val &= ~(0x3f << shift);
93 val |= ((clr_level << 3) | set_level) << shift;
94 writel(val, priv->base + SMFC_WMC);
95
96 spin_unlock_irqrestore(&priv->lock, flags);
97
98 return 0;
99}
100EXPORT_SYMBOL_GPL(ipu_smfc_set_watermark);
101
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -0700102int ipu_smfc_enable(struct ipu_smfc *smfc)
Steve Longerbeamfc435352014-06-25 18:05:33 -0700103{
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -0700104 struct ipu_smfc_priv *priv = smfc->priv;
105 unsigned long flags;
106
107 spin_lock_irqsave(&priv->lock, flags);
108
109 if (!priv->use_count)
110 ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN);
111
112 priv->use_count++;
113
114 spin_unlock_irqrestore(&priv->lock, flags);
115
116 return 0;
Steve Longerbeamfc435352014-06-25 18:05:33 -0700117}
118EXPORT_SYMBOL_GPL(ipu_smfc_enable);
119
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -0700120int ipu_smfc_disable(struct ipu_smfc *smfc)
Steve Longerbeamfc435352014-06-25 18:05:33 -0700121{
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -0700122 struct ipu_smfc_priv *priv = smfc->priv;
123 unsigned long flags;
124
125 spin_lock_irqsave(&priv->lock, flags);
126
127 priv->use_count--;
128
129 if (!priv->use_count)
130 ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN);
131
132 if (priv->use_count < 0)
133 priv->use_count = 0;
134
135 spin_unlock_irqrestore(&priv->lock, flags);
136
137 return 0;
Steve Longerbeamfc435352014-06-25 18:05:33 -0700138}
139EXPORT_SYMBOL_GPL(ipu_smfc_disable);
140
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -0700141struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno)
142{
143 struct ipu_smfc_priv *priv = ipu->smfc_priv;
144 struct ipu_smfc *smfc, *ret;
145 unsigned long flags;
146
147 if (chno >= 4)
148 return ERR_PTR(-EINVAL);
149
150 smfc = &priv->channel[chno];
151 ret = smfc;
152
153 spin_lock_irqsave(&priv->lock, flags);
154
155 if (smfc->inuse) {
156 ret = ERR_PTR(-EBUSY);
157 goto unlock;
158 }
159
160 smfc->inuse = true;
161unlock:
162 spin_unlock_irqrestore(&priv->lock, flags);
163 return ret;
164}
165EXPORT_SYMBOL_GPL(ipu_smfc_get);
166
167void ipu_smfc_put(struct ipu_smfc *smfc)
168{
169 struct ipu_smfc_priv *priv = smfc->priv;
170 unsigned long flags;
171
172 spin_lock_irqsave(&priv->lock, flags);
173 smfc->inuse = false;
174 spin_unlock_irqrestore(&priv->lock, flags);
175}
176EXPORT_SYMBOL_GPL(ipu_smfc_put);
177
Philipp Zabel35de9252012-05-09 16:59:01 +0200178int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,
179 unsigned long base)
180{
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -0700181 struct ipu_smfc_priv *priv;
182 int i;
Philipp Zabel35de9252012-05-09 16:59:01 +0200183
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -0700184 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
185 if (!priv)
Philipp Zabel35de9252012-05-09 16:59:01 +0200186 return -ENOMEM;
187
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -0700188 ipu->smfc_priv = priv;
189 spin_lock_init(&priv->lock);
190 priv->ipu = ipu;
Philipp Zabel35de9252012-05-09 16:59:01 +0200191
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -0700192 priv->base = devm_ioremap(dev, base, PAGE_SIZE);
193 if (!priv->base)
Philipp Zabel35de9252012-05-09 16:59:01 +0200194 return -ENOMEM;
195
Steve Longerbeam7fafa8f2014-06-25 18:05:34 -0700196 for (i = 0; i < 4; i++) {
197 priv->channel[i].priv = priv;
198 priv->channel[i].chno = i;
199 }
200
201 pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base);
Philipp Zabel35de9252012-05-09 16:59:01 +0200202
203 return 0;
204}
205
206void ipu_smfc_exit(struct ipu_soc *ipu)
207{
208}