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 } 190