ipu-smfc.c 3.8 KB
Newer Older
P
Philipp Zabel 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
 *
 * The code contained herein is licensed under the GNU General Public
 * License. You may obtain a copy of the GNU General Public License
 * Version 2 or later at the following locations:
 *
 * http://www.opensource.org/licenses/gpl-license.html
 * http://www.gnu.org/copyleft/gpl.html
 */
#define DEBUG
#include <linux/export.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <video/imx-ipu-v3.h>

#include "ipu-prv.h"

24 25 26 27 28 29
struct ipu_smfc {
	struct ipu_smfc_priv *priv;
	int chno;
	bool inuse;
};

P
Philipp Zabel 已提交
30 31 32
struct ipu_smfc_priv {
	void __iomem *base;
	spinlock_t lock;
33 34 35
	struct ipu_soc *ipu;
	struct ipu_smfc channel[4];
	int use_count;
P
Philipp Zabel 已提交
36 37 38 39 40 41 42
};

/*SMFC Registers */
#define SMFC_MAP	0x0000
#define SMFC_WMC	0x0004
#define SMFC_BS		0x0008

43
int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize)
P
Philipp Zabel 已提交
44
{
45
	struct ipu_smfc_priv *priv = smfc->priv;
P
Philipp Zabel 已提交
46 47 48
	unsigned long flags;
	u32 val, shift;

49
	spin_lock_irqsave(&priv->lock, flags);
P
Philipp Zabel 已提交
50

51 52
	shift = smfc->chno * 4;
	val = readl(priv->base + SMFC_BS);
P
Philipp Zabel 已提交
53 54
	val &= ~(0xf << shift);
	val |= burstsize << shift;
55
	writel(val, priv->base + SMFC_BS);
P
Philipp Zabel 已提交
56

57
	spin_unlock_irqrestore(&priv->lock, flags);
P
Philipp Zabel 已提交
58 59 60 61 62

	return 0;
}
EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize);

63
int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id)
P
Philipp Zabel 已提交
64
{
65
	struct ipu_smfc_priv *priv = smfc->priv;
P
Philipp Zabel 已提交
66 67 68
	unsigned long flags;
	u32 val, shift;

69
	spin_lock_irqsave(&priv->lock, flags);
P
Philipp Zabel 已提交
70

71 72
	shift = smfc->chno * 3;
	val = readl(priv->base + SMFC_MAP);
P
Philipp Zabel 已提交
73 74
	val &= ~(0x7 << shift);
	val |= ((csi_id << 2) | mipi_id) << shift;
75
	writel(val, priv->base + SMFC_MAP);
P
Philipp Zabel 已提交
76

77
	spin_unlock_irqrestore(&priv->lock, flags);
P
Philipp Zabel 已提交
78 79 80 81 82

	return 0;
}
EXPORT_SYMBOL_GPL(ipu_smfc_map_channel);

83
int ipu_smfc_enable(struct ipu_smfc *smfc)
84
{
85 86 87 88 89 90 91 92 93 94 95 96 97
	struct ipu_smfc_priv *priv = smfc->priv;
	unsigned long flags;

	spin_lock_irqsave(&priv->lock, flags);

	if (!priv->use_count)
		ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN);

	priv->use_count++;

	spin_unlock_irqrestore(&priv->lock, flags);

	return 0;
98 99 100
}
EXPORT_SYMBOL_GPL(ipu_smfc_enable);

101
int ipu_smfc_disable(struct ipu_smfc *smfc)
102
{
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
	struct ipu_smfc_priv *priv = smfc->priv;
	unsigned long flags;

	spin_lock_irqsave(&priv->lock, flags);

	priv->use_count--;

	if (!priv->use_count)
		ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN);

	if (priv->use_count < 0)
		priv->use_count = 0;

	spin_unlock_irqrestore(&priv->lock, flags);

	return 0;
119 120 121
}
EXPORT_SYMBOL_GPL(ipu_smfc_disable);

122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno)
{
	struct ipu_smfc_priv *priv = ipu->smfc_priv;
	struct ipu_smfc *smfc, *ret;
	unsigned long flags;

	if (chno >= 4)
		return ERR_PTR(-EINVAL);

	smfc = &priv->channel[chno];
	ret = smfc;

	spin_lock_irqsave(&priv->lock, flags);

	if (smfc->inuse) {
		ret = ERR_PTR(-EBUSY);
		goto unlock;
	}

	smfc->inuse = true;
unlock:
	spin_unlock_irqrestore(&priv->lock, flags);
	return ret;
}
EXPORT_SYMBOL_GPL(ipu_smfc_get);

void ipu_smfc_put(struct ipu_smfc *smfc)
{
	struct ipu_smfc_priv *priv = smfc->priv;
	unsigned long flags;

	spin_lock_irqsave(&priv->lock, flags);
	smfc->inuse = false;
	spin_unlock_irqrestore(&priv->lock, flags);
}
EXPORT_SYMBOL_GPL(ipu_smfc_put);

P
Philipp Zabel 已提交
159 160 161
int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,
		  unsigned long base)
{
162 163
	struct ipu_smfc_priv *priv;
	int i;
P
Philipp Zabel 已提交
164

165 166
	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
P
Philipp Zabel 已提交
167 168
		return -ENOMEM;

169 170 171
	ipu->smfc_priv = priv;
	spin_lock_init(&priv->lock);
	priv->ipu = ipu;
P
Philipp Zabel 已提交
172

173 174
	priv->base = devm_ioremap(dev, base, PAGE_SIZE);
	if (!priv->base)
P
Philipp Zabel 已提交
175 176
		return -ENOMEM;

177 178 179 180 181 182
	for (i = 0; i < 4; i++) {
		priv->channel[i].priv = priv;
		priv->channel[i].chno = i;
	}

	pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base);
P
Philipp Zabel 已提交
183 184 185 186 187 188 189

	return 0;
}

void ipu_smfc_exit(struct ipu_soc *ipu)
{
}