135de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel/* 235de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. 335de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel * 435de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel * The code contained herein is licensed under the GNU General Public 535de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel * License. You may obtain a copy of the GNU General Public License 635de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel * Version 2 or later at the following locations: 735de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel * 835de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel * http://www.opensource.org/licenses/gpl-license.html 935de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel * http://www.gnu.org/copyleft/gpl.html 1035de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel */ 1135de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel#include <linux/export.h> 1235de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel#include <linux/types.h> 1335de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel#include <linux/init.h> 1435de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel#include <linux/io.h> 1535de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel#include <linux/errno.h> 1635de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel#include <linux/spinlock.h> 1735de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel#include <linux/delay.h> 1835de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel#include <linux/clk.h> 1935de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel#include <video/imx-ipu-v3.h> 2035de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 2135de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel#include "ipu-prv.h" 2235de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 237fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeamstruct ipu_smfc { 247fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam struct ipu_smfc_priv *priv; 257fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam int chno; 267fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam bool inuse; 277fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam}; 287fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 2935de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabelstruct ipu_smfc_priv { 3035de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel void __iomem *base; 3135de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel spinlock_t lock; 327fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam struct ipu_soc *ipu; 337fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam struct ipu_smfc channel[4]; 347fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam int use_count; 3535de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel}; 3635de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 3735de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel/*SMFC Registers */ 3835de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel#define SMFC_MAP 0x0000 3935de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel#define SMFC_WMC 0x0004 4035de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel#define SMFC_BS 0x0008 4135de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 427fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeamint ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize) 4335de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel{ 447fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam struct ipu_smfc_priv *priv = smfc->priv; 4535de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel unsigned long flags; 4635de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel u32 val, shift; 4735de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 487fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam spin_lock_irqsave(&priv->lock, flags); 4935de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 507fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam shift = smfc->chno * 4; 517fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam val = readl(priv->base + SMFC_BS); 5235de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel val &= ~(0xf << shift); 5335de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel val |= burstsize << shift; 547fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam writel(val, priv->base + SMFC_BS); 5535de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 567fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam spin_unlock_irqrestore(&priv->lock, flags); 5735de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 5835de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel return 0; 5935de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel} 6035de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp ZabelEXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize); 6135de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 627fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeamint ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id) 6335de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel{ 647fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam struct ipu_smfc_priv *priv = smfc->priv; 6535de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel unsigned long flags; 6635de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel u32 val, shift; 6735de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 687fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam spin_lock_irqsave(&priv->lock, flags); 6935de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 707fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam shift = smfc->chno * 3; 717fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam val = readl(priv->base + SMFC_MAP); 7235de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel val &= ~(0x7 << shift); 7335de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel val |= ((csi_id << 2) | mipi_id) << shift; 747fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam writel(val, priv->base + SMFC_MAP); 7535de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 767fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam spin_unlock_irqrestore(&priv->lock, flags); 7735de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 7835de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel return 0; 7935de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel} 8035de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp ZabelEXPORT_SYMBOL_GPL(ipu_smfc_map_channel); 8135de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 82a2be35e3320b27c84488729e9fb56a62e74d65faSteve Longerbeamint ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level) 83a2be35e3320b27c84488729e9fb56a62e74d65faSteve Longerbeam{ 84a2be35e3320b27c84488729e9fb56a62e74d65faSteve Longerbeam struct ipu_smfc_priv *priv = smfc->priv; 85a2be35e3320b27c84488729e9fb56a62e74d65faSteve Longerbeam unsigned long flags; 86a2be35e3320b27c84488729e9fb56a62e74d65faSteve Longerbeam u32 val, shift; 87a2be35e3320b27c84488729e9fb56a62e74d65faSteve Longerbeam 88a2be35e3320b27c84488729e9fb56a62e74d65faSteve Longerbeam spin_lock_irqsave(&priv->lock, flags); 89a2be35e3320b27c84488729e9fb56a62e74d65faSteve Longerbeam 90a2be35e3320b27c84488729e9fb56a62e74d65faSteve Longerbeam shift = smfc->chno * 6 + (smfc->chno > 1 ? 4 : 0); 91a2be35e3320b27c84488729e9fb56a62e74d65faSteve Longerbeam val = readl(priv->base + SMFC_WMC); 92a2be35e3320b27c84488729e9fb56a62e74d65faSteve Longerbeam val &= ~(0x3f << shift); 93a2be35e3320b27c84488729e9fb56a62e74d65faSteve Longerbeam val |= ((clr_level << 3) | set_level) << shift; 94a2be35e3320b27c84488729e9fb56a62e74d65faSteve Longerbeam writel(val, priv->base + SMFC_WMC); 95a2be35e3320b27c84488729e9fb56a62e74d65faSteve Longerbeam 96a2be35e3320b27c84488729e9fb56a62e74d65faSteve Longerbeam spin_unlock_irqrestore(&priv->lock, flags); 97a2be35e3320b27c84488729e9fb56a62e74d65faSteve Longerbeam 98a2be35e3320b27c84488729e9fb56a62e74d65faSteve Longerbeam return 0; 99a2be35e3320b27c84488729e9fb56a62e74d65faSteve Longerbeam} 100a2be35e3320b27c84488729e9fb56a62e74d65faSteve LongerbeamEXPORT_SYMBOL_GPL(ipu_smfc_set_watermark); 101a2be35e3320b27c84488729e9fb56a62e74d65faSteve Longerbeam 1027fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeamint ipu_smfc_enable(struct ipu_smfc *smfc) 103fc4353559e587f5962f22c24ca7e015bdbea1e49Steve Longerbeam{ 1047fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam struct ipu_smfc_priv *priv = smfc->priv; 1057fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam unsigned long flags; 1067fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 1077fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam spin_lock_irqsave(&priv->lock, flags); 1087fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 1097fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam if (!priv->use_count) 1107fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN); 1117fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 1127fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam priv->use_count++; 1137fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 1147fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam spin_unlock_irqrestore(&priv->lock, flags); 1157fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 1167fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam return 0; 117fc4353559e587f5962f22c24ca7e015bdbea1e49Steve Longerbeam} 118fc4353559e587f5962f22c24ca7e015bdbea1e49Steve LongerbeamEXPORT_SYMBOL_GPL(ipu_smfc_enable); 119fc4353559e587f5962f22c24ca7e015bdbea1e49Steve Longerbeam 1207fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeamint ipu_smfc_disable(struct ipu_smfc *smfc) 121fc4353559e587f5962f22c24ca7e015bdbea1e49Steve Longerbeam{ 1227fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam struct ipu_smfc_priv *priv = smfc->priv; 1237fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam unsigned long flags; 1247fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 1257fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam spin_lock_irqsave(&priv->lock, flags); 1267fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 1277fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam priv->use_count--; 1287fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 1297fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam if (!priv->use_count) 1307fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN); 1317fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 1327fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam if (priv->use_count < 0) 1337fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam priv->use_count = 0; 1347fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 1357fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam spin_unlock_irqrestore(&priv->lock, flags); 1367fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 1377fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam return 0; 138fc4353559e587f5962f22c24ca7e015bdbea1e49Steve Longerbeam} 139fc4353559e587f5962f22c24ca7e015bdbea1e49Steve LongerbeamEXPORT_SYMBOL_GPL(ipu_smfc_disable); 140fc4353559e587f5962f22c24ca7e015bdbea1e49Steve Longerbeam 1417fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeamstruct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno) 1427fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam{ 1437fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam struct ipu_smfc_priv *priv = ipu->smfc_priv; 1447fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam struct ipu_smfc *smfc, *ret; 1457fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam unsigned long flags; 1467fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 1477fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam if (chno >= 4) 1487fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam return ERR_PTR(-EINVAL); 1497fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 1507fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam smfc = &priv->channel[chno]; 1517fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam ret = smfc; 1527fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 1537fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam spin_lock_irqsave(&priv->lock, flags); 1547fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 1557fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam if (smfc->inuse) { 1567fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam ret = ERR_PTR(-EBUSY); 1577fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam goto unlock; 1587fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam } 1597fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 1607fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam smfc->inuse = true; 1617fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeamunlock: 1627fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam spin_unlock_irqrestore(&priv->lock, flags); 1637fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam return ret; 1647fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam} 1657fafa8f06f9bdf32b806b4612bfe387de8e34125Steve LongerbeamEXPORT_SYMBOL_GPL(ipu_smfc_get); 1667fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 1677fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeamvoid ipu_smfc_put(struct ipu_smfc *smfc) 1687fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam{ 1697fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam struct ipu_smfc_priv *priv = smfc->priv; 1707fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam unsigned long flags; 1717fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 1727fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam spin_lock_irqsave(&priv->lock, flags); 1737fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam smfc->inuse = false; 1747fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam spin_unlock_irqrestore(&priv->lock, flags); 1757fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam} 1767fafa8f06f9bdf32b806b4612bfe387de8e34125Steve LongerbeamEXPORT_SYMBOL_GPL(ipu_smfc_put); 1777fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 17835de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabelint ipu_smfc_init(struct ipu_soc *ipu, struct device *dev, 17935de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel unsigned long base) 18035de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel{ 1817fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam struct ipu_smfc_priv *priv; 1827fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam int i; 18335de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 1847fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 1857fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam if (!priv) 18635de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel return -ENOMEM; 18735de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 1887fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam ipu->smfc_priv = priv; 1897fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam spin_lock_init(&priv->lock); 1907fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam priv->ipu = ipu; 19135de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 1927fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam priv->base = devm_ioremap(dev, base, PAGE_SIZE); 1937fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam if (!priv->base) 19435de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel return -ENOMEM; 19535de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 1967fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam for (i = 0; i < 4; i++) { 1977fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam priv->channel[i].priv = priv; 1987fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam priv->channel[i].chno = i; 1997fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam } 2007fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam 2017fafa8f06f9bdf32b806b4612bfe387de8e34125Steve Longerbeam pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base); 20235de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 20335de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel return 0; 20435de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel} 20535de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel 20635de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabelvoid ipu_smfc_exit(struct ipu_soc *ipu) 20735de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel{ 20835de925ffaa67971e073d3ebf1e0600be0d0d3f1Philipp Zabel} 209