xref: /openbmc/linux/drivers/gpu/ipu-v3/ipu-smfc.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*fcaf2036SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
235de925fSPhilipp Zabel /*
335de925fSPhilipp Zabel  * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
435de925fSPhilipp Zabel  */
535de925fSPhilipp Zabel #include <linux/export.h>
635de925fSPhilipp Zabel #include <linux/types.h>
735de925fSPhilipp Zabel #include <linux/init.h>
835de925fSPhilipp Zabel #include <linux/io.h>
935de925fSPhilipp Zabel #include <linux/errno.h>
1035de925fSPhilipp Zabel #include <linux/spinlock.h>
1135de925fSPhilipp Zabel #include <linux/delay.h>
1235de925fSPhilipp Zabel #include <linux/clk.h>
1335de925fSPhilipp Zabel #include <video/imx-ipu-v3.h>
1435de925fSPhilipp Zabel 
1535de925fSPhilipp Zabel #include "ipu-prv.h"
1635de925fSPhilipp Zabel 
177fafa8f0SSteve Longerbeam struct ipu_smfc {
187fafa8f0SSteve Longerbeam 	struct ipu_smfc_priv *priv;
197fafa8f0SSteve Longerbeam 	int chno;
207fafa8f0SSteve Longerbeam 	bool inuse;
217fafa8f0SSteve Longerbeam };
227fafa8f0SSteve Longerbeam 
2335de925fSPhilipp Zabel struct ipu_smfc_priv {
2435de925fSPhilipp Zabel 	void __iomem *base;
2535de925fSPhilipp Zabel 	spinlock_t lock;
267fafa8f0SSteve Longerbeam 	struct ipu_soc *ipu;
277fafa8f0SSteve Longerbeam 	struct ipu_smfc channel[4];
287fafa8f0SSteve Longerbeam 	int use_count;
2935de925fSPhilipp Zabel };
3035de925fSPhilipp Zabel 
3135de925fSPhilipp Zabel /*SMFC Registers */
3235de925fSPhilipp Zabel #define SMFC_MAP	0x0000
3335de925fSPhilipp Zabel #define SMFC_WMC	0x0004
3435de925fSPhilipp Zabel #define SMFC_BS		0x0008
3535de925fSPhilipp Zabel 
ipu_smfc_set_burstsize(struct ipu_smfc * smfc,int burstsize)367fafa8f0SSteve Longerbeam int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize)
3735de925fSPhilipp Zabel {
387fafa8f0SSteve Longerbeam 	struct ipu_smfc_priv *priv = smfc->priv;
3935de925fSPhilipp Zabel 	unsigned long flags;
4035de925fSPhilipp Zabel 	u32 val, shift;
4135de925fSPhilipp Zabel 
427fafa8f0SSteve Longerbeam 	spin_lock_irqsave(&priv->lock, flags);
4335de925fSPhilipp Zabel 
447fafa8f0SSteve Longerbeam 	shift = smfc->chno * 4;
457fafa8f0SSteve Longerbeam 	val = readl(priv->base + SMFC_BS);
4635de925fSPhilipp Zabel 	val &= ~(0xf << shift);
4735de925fSPhilipp Zabel 	val |= burstsize << shift;
487fafa8f0SSteve Longerbeam 	writel(val, priv->base + SMFC_BS);
4935de925fSPhilipp Zabel 
507fafa8f0SSteve Longerbeam 	spin_unlock_irqrestore(&priv->lock, flags);
5135de925fSPhilipp Zabel 
5235de925fSPhilipp Zabel 	return 0;
5335de925fSPhilipp Zabel }
5435de925fSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize);
5535de925fSPhilipp Zabel 
ipu_smfc_map_channel(struct ipu_smfc * smfc,int csi_id,int mipi_id)567fafa8f0SSteve Longerbeam int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id)
5735de925fSPhilipp Zabel {
587fafa8f0SSteve Longerbeam 	struct ipu_smfc_priv *priv = smfc->priv;
5935de925fSPhilipp Zabel 	unsigned long flags;
6035de925fSPhilipp Zabel 	u32 val, shift;
6135de925fSPhilipp Zabel 
627fafa8f0SSteve Longerbeam 	spin_lock_irqsave(&priv->lock, flags);
6335de925fSPhilipp Zabel 
647fafa8f0SSteve Longerbeam 	shift = smfc->chno * 3;
657fafa8f0SSteve Longerbeam 	val = readl(priv->base + SMFC_MAP);
6635de925fSPhilipp Zabel 	val &= ~(0x7 << shift);
6735de925fSPhilipp Zabel 	val |= ((csi_id << 2) | mipi_id) << shift;
687fafa8f0SSteve Longerbeam 	writel(val, priv->base + SMFC_MAP);
6935de925fSPhilipp Zabel 
707fafa8f0SSteve Longerbeam 	spin_unlock_irqrestore(&priv->lock, flags);
7135de925fSPhilipp Zabel 
7235de925fSPhilipp Zabel 	return 0;
7335de925fSPhilipp Zabel }
7435de925fSPhilipp Zabel EXPORT_SYMBOL_GPL(ipu_smfc_map_channel);
7535de925fSPhilipp Zabel 
ipu_smfc_set_watermark(struct ipu_smfc * smfc,u32 set_level,u32 clr_level)76a2be35e3SSteve Longerbeam int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level)
77a2be35e3SSteve Longerbeam {
78a2be35e3SSteve Longerbeam 	struct ipu_smfc_priv *priv = smfc->priv;
79a2be35e3SSteve Longerbeam 	unsigned long flags;
80a2be35e3SSteve Longerbeam 	u32 val, shift;
81a2be35e3SSteve Longerbeam 
82a2be35e3SSteve Longerbeam 	spin_lock_irqsave(&priv->lock, flags);
83a2be35e3SSteve Longerbeam 
84a2be35e3SSteve Longerbeam 	shift = smfc->chno * 6 + (smfc->chno > 1 ? 4 : 0);
85a2be35e3SSteve Longerbeam 	val = readl(priv->base + SMFC_WMC);
86a2be35e3SSteve Longerbeam 	val &= ~(0x3f << shift);
87a2be35e3SSteve Longerbeam 	val |= ((clr_level << 3) | set_level) << shift;
88a2be35e3SSteve Longerbeam 	writel(val, priv->base + SMFC_WMC);
89a2be35e3SSteve Longerbeam 
90a2be35e3SSteve Longerbeam 	spin_unlock_irqrestore(&priv->lock, flags);
91a2be35e3SSteve Longerbeam 
92a2be35e3SSteve Longerbeam 	return 0;
93a2be35e3SSteve Longerbeam }
94a2be35e3SSteve Longerbeam EXPORT_SYMBOL_GPL(ipu_smfc_set_watermark);
95a2be35e3SSteve Longerbeam 
ipu_smfc_enable(struct ipu_smfc * smfc)967fafa8f0SSteve Longerbeam int ipu_smfc_enable(struct ipu_smfc *smfc)
97fc435355SSteve Longerbeam {
987fafa8f0SSteve Longerbeam 	struct ipu_smfc_priv *priv = smfc->priv;
997fafa8f0SSteve Longerbeam 	unsigned long flags;
1007fafa8f0SSteve Longerbeam 
1017fafa8f0SSteve Longerbeam 	spin_lock_irqsave(&priv->lock, flags);
1027fafa8f0SSteve Longerbeam 
1037fafa8f0SSteve Longerbeam 	if (!priv->use_count)
1047fafa8f0SSteve Longerbeam 		ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN);
1057fafa8f0SSteve Longerbeam 
1067fafa8f0SSteve Longerbeam 	priv->use_count++;
1077fafa8f0SSteve Longerbeam 
1087fafa8f0SSteve Longerbeam 	spin_unlock_irqrestore(&priv->lock, flags);
1097fafa8f0SSteve Longerbeam 
1107fafa8f0SSteve Longerbeam 	return 0;
111fc435355SSteve Longerbeam }
112fc435355SSteve Longerbeam EXPORT_SYMBOL_GPL(ipu_smfc_enable);
113fc435355SSteve Longerbeam 
ipu_smfc_disable(struct ipu_smfc * smfc)1147fafa8f0SSteve Longerbeam int ipu_smfc_disable(struct ipu_smfc *smfc)
115fc435355SSteve Longerbeam {
1167fafa8f0SSteve Longerbeam 	struct ipu_smfc_priv *priv = smfc->priv;
1177fafa8f0SSteve Longerbeam 	unsigned long flags;
1187fafa8f0SSteve Longerbeam 
1197fafa8f0SSteve Longerbeam 	spin_lock_irqsave(&priv->lock, flags);
1207fafa8f0SSteve Longerbeam 
1217fafa8f0SSteve Longerbeam 	priv->use_count--;
1227fafa8f0SSteve Longerbeam 
1237fafa8f0SSteve Longerbeam 	if (!priv->use_count)
1247fafa8f0SSteve Longerbeam 		ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN);
1257fafa8f0SSteve Longerbeam 
1267fafa8f0SSteve Longerbeam 	if (priv->use_count < 0)
1277fafa8f0SSteve Longerbeam 		priv->use_count = 0;
1287fafa8f0SSteve Longerbeam 
1297fafa8f0SSteve Longerbeam 	spin_unlock_irqrestore(&priv->lock, flags);
1307fafa8f0SSteve Longerbeam 
1317fafa8f0SSteve Longerbeam 	return 0;
132fc435355SSteve Longerbeam }
133fc435355SSteve Longerbeam EXPORT_SYMBOL_GPL(ipu_smfc_disable);
134fc435355SSteve Longerbeam 
ipu_smfc_get(struct ipu_soc * ipu,unsigned int chno)1357fafa8f0SSteve Longerbeam struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno)
1367fafa8f0SSteve Longerbeam {
1377fafa8f0SSteve Longerbeam 	struct ipu_smfc_priv *priv = ipu->smfc_priv;
1387fafa8f0SSteve Longerbeam 	struct ipu_smfc *smfc, *ret;
1397fafa8f0SSteve Longerbeam 	unsigned long flags;
1407fafa8f0SSteve Longerbeam 
1417fafa8f0SSteve Longerbeam 	if (chno >= 4)
1427fafa8f0SSteve Longerbeam 		return ERR_PTR(-EINVAL);
1437fafa8f0SSteve Longerbeam 
1447fafa8f0SSteve Longerbeam 	smfc = &priv->channel[chno];
1457fafa8f0SSteve Longerbeam 	ret = smfc;
1467fafa8f0SSteve Longerbeam 
1477fafa8f0SSteve Longerbeam 	spin_lock_irqsave(&priv->lock, flags);
1487fafa8f0SSteve Longerbeam 
1497fafa8f0SSteve Longerbeam 	if (smfc->inuse) {
1507fafa8f0SSteve Longerbeam 		ret = ERR_PTR(-EBUSY);
1517fafa8f0SSteve Longerbeam 		goto unlock;
1527fafa8f0SSteve Longerbeam 	}
1537fafa8f0SSteve Longerbeam 
1547fafa8f0SSteve Longerbeam 	smfc->inuse = true;
1557fafa8f0SSteve Longerbeam unlock:
1567fafa8f0SSteve Longerbeam 	spin_unlock_irqrestore(&priv->lock, flags);
1577fafa8f0SSteve Longerbeam 	return ret;
1587fafa8f0SSteve Longerbeam }
1597fafa8f0SSteve Longerbeam EXPORT_SYMBOL_GPL(ipu_smfc_get);
1607fafa8f0SSteve Longerbeam 
ipu_smfc_put(struct ipu_smfc * smfc)1617fafa8f0SSteve Longerbeam void ipu_smfc_put(struct ipu_smfc *smfc)
1627fafa8f0SSteve Longerbeam {
1637fafa8f0SSteve Longerbeam 	struct ipu_smfc_priv *priv = smfc->priv;
1647fafa8f0SSteve Longerbeam 	unsigned long flags;
1657fafa8f0SSteve Longerbeam 
1667fafa8f0SSteve Longerbeam 	spin_lock_irqsave(&priv->lock, flags);
1677fafa8f0SSteve Longerbeam 	smfc->inuse = false;
1687fafa8f0SSteve Longerbeam 	spin_unlock_irqrestore(&priv->lock, flags);
1697fafa8f0SSteve Longerbeam }
1707fafa8f0SSteve Longerbeam EXPORT_SYMBOL_GPL(ipu_smfc_put);
1717fafa8f0SSteve Longerbeam 
ipu_smfc_init(struct ipu_soc * ipu,struct device * dev,unsigned long base)17235de925fSPhilipp Zabel int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,
17335de925fSPhilipp Zabel 		  unsigned long base)
17435de925fSPhilipp Zabel {
1757fafa8f0SSteve Longerbeam 	struct ipu_smfc_priv *priv;
1767fafa8f0SSteve Longerbeam 	int i;
17735de925fSPhilipp Zabel 
1787fafa8f0SSteve Longerbeam 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
1797fafa8f0SSteve Longerbeam 	if (!priv)
18035de925fSPhilipp Zabel 		return -ENOMEM;
18135de925fSPhilipp Zabel 
1827fafa8f0SSteve Longerbeam 	ipu->smfc_priv = priv;
1837fafa8f0SSteve Longerbeam 	spin_lock_init(&priv->lock);
1847fafa8f0SSteve Longerbeam 	priv->ipu = ipu;
18535de925fSPhilipp Zabel 
1867fafa8f0SSteve Longerbeam 	priv->base = devm_ioremap(dev, base, PAGE_SIZE);
1877fafa8f0SSteve Longerbeam 	if (!priv->base)
18835de925fSPhilipp Zabel 		return -ENOMEM;
18935de925fSPhilipp Zabel 
1907fafa8f0SSteve Longerbeam 	for (i = 0; i < 4; i++) {
1917fafa8f0SSteve Longerbeam 		priv->channel[i].priv = priv;
1927fafa8f0SSteve Longerbeam 		priv->channel[i].chno = i;
1937fafa8f0SSteve Longerbeam 	}
1947fafa8f0SSteve Longerbeam 
1957fafa8f0SSteve Longerbeam 	pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base);
19635de925fSPhilipp Zabel 
19735de925fSPhilipp Zabel 	return 0;
19835de925fSPhilipp Zabel }
19935de925fSPhilipp Zabel 
ipu_smfc_exit(struct ipu_soc * ipu)20035de925fSPhilipp Zabel void ipu_smfc_exit(struct ipu_soc *ipu)
20135de925fSPhilipp Zabel {
20235de925fSPhilipp Zabel }
203