203 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.4 */5#include <linux/export.h>6#include <linux/types.h>7#include <linux/init.h>8#include <linux/io.h>9#include <linux/errno.h>10#include <linux/spinlock.h>11#include <linux/delay.h>12#include <linux/clk.h>13#include <video/imx-ipu-v3.h>14 15#include "ipu-prv.h"16 17struct ipu_smfc {18 struct ipu_smfc_priv *priv;19 int chno;20 bool inuse;21};22 23struct ipu_smfc_priv {24 void __iomem *base;25 spinlock_t lock;26 struct ipu_soc *ipu;27 struct ipu_smfc channel[4];28 int use_count;29};30 31/*SMFC Registers */32#define SMFC_MAP 0x000033#define SMFC_WMC 0x000434#define SMFC_BS 0x000835 36int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize)37{38 struct ipu_smfc_priv *priv = smfc->priv;39 unsigned long flags;40 u32 val, shift;41 42 spin_lock_irqsave(&priv->lock, flags);43 44 shift = smfc->chno * 4;45 val = readl(priv->base + SMFC_BS);46 val &= ~(0xf << shift);47 val |= burstsize << shift;48 writel(val, priv->base + SMFC_BS);49 50 spin_unlock_irqrestore(&priv->lock, flags);51 52 return 0;53}54EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize);55 56int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id)57{58 struct ipu_smfc_priv *priv = smfc->priv;59 unsigned long flags;60 u32 val, shift;61 62 spin_lock_irqsave(&priv->lock, flags);63 64 shift = smfc->chno * 3;65 val = readl(priv->base + SMFC_MAP);66 val &= ~(0x7 << shift);67 val |= ((csi_id << 2) | mipi_id) << shift;68 writel(val, priv->base + SMFC_MAP);69 70 spin_unlock_irqrestore(&priv->lock, flags);71 72 return 0;73}74EXPORT_SYMBOL_GPL(ipu_smfc_map_channel);75 76int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level)77{78 struct ipu_smfc_priv *priv = smfc->priv;79 unsigned long flags;80 u32 val, shift;81 82 spin_lock_irqsave(&priv->lock, flags);83 84 shift = smfc->chno * 6 + (smfc->chno > 1 ? 4 : 0);85 val = readl(priv->base + SMFC_WMC);86 val &= ~(0x3f << shift);87 val |= ((clr_level << 3) | set_level) << shift;88 writel(val, priv->base + SMFC_WMC);89 90 spin_unlock_irqrestore(&priv->lock, flags);91 92 return 0;93}94EXPORT_SYMBOL_GPL(ipu_smfc_set_watermark);95 96int ipu_smfc_enable(struct ipu_smfc *smfc)97{98 struct ipu_smfc_priv *priv = smfc->priv;99 unsigned long flags;100 101 spin_lock_irqsave(&priv->lock, flags);102 103 if (!priv->use_count)104 ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN);105 106 priv->use_count++;107 108 spin_unlock_irqrestore(&priv->lock, flags);109 110 return 0;111}112EXPORT_SYMBOL_GPL(ipu_smfc_enable);113 114int ipu_smfc_disable(struct ipu_smfc *smfc)115{116 struct ipu_smfc_priv *priv = smfc->priv;117 unsigned long flags;118 119 spin_lock_irqsave(&priv->lock, flags);120 121 priv->use_count--;122 123 if (!priv->use_count)124 ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN);125 126 if (priv->use_count < 0)127 priv->use_count = 0;128 129 spin_unlock_irqrestore(&priv->lock, flags);130 131 return 0;132}133EXPORT_SYMBOL_GPL(ipu_smfc_disable);134 135struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno)136{137 struct ipu_smfc_priv *priv = ipu->smfc_priv;138 struct ipu_smfc *smfc, *ret;139 unsigned long flags;140 141 if (chno >= 4)142 return ERR_PTR(-EINVAL);143 144 smfc = &priv->channel[chno];145 ret = smfc;146 147 spin_lock_irqsave(&priv->lock, flags);148 149 if (smfc->inuse) {150 ret = ERR_PTR(-EBUSY);151 goto unlock;152 }153 154 smfc->inuse = true;155unlock:156 spin_unlock_irqrestore(&priv->lock, flags);157 return ret;158}159EXPORT_SYMBOL_GPL(ipu_smfc_get);160 161void ipu_smfc_put(struct ipu_smfc *smfc)162{163 struct ipu_smfc_priv *priv = smfc->priv;164 unsigned long flags;165 166 spin_lock_irqsave(&priv->lock, flags);167 smfc->inuse = false;168 spin_unlock_irqrestore(&priv->lock, flags);169}170EXPORT_SYMBOL_GPL(ipu_smfc_put);171 172int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,173 unsigned long base)174{175 struct ipu_smfc_priv *priv;176 int i;177 178 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);179 if (!priv)180 return -ENOMEM;181 182 ipu->smfc_priv = priv;183 spin_lock_init(&priv->lock);184 priv->ipu = ipu;185 186 priv->base = devm_ioremap(dev, base, PAGE_SIZE);187 if (!priv->base)188 return -ENOMEM;189 190 for (i = 0; i < 4; i++) {191 priv->channel[i].priv = priv;192 priv->channel[i].chno = i;193 }194 195 pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base);196 197 return 0;198}199 200void ipu_smfc_exit(struct ipu_soc *ipu)201{202}203