Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
0004  */
0005 #include <linux/export.h>
0006 #include <linux/types.h>
0007 #include <linux/init.h>
0008 #include <linux/io.h>
0009 #include <linux/errno.h>
0010 #include <linux/spinlock.h>
0011 #include <linux/delay.h>
0012 #include <linux/clk.h>
0013 #include <video/imx-ipu-v3.h>
0014 
0015 #include "ipu-prv.h"
0016 
0017 struct ipu_smfc {
0018     struct ipu_smfc_priv *priv;
0019     int chno;
0020     bool inuse;
0021 };
0022 
0023 struct ipu_smfc_priv {
0024     void __iomem *base;
0025     spinlock_t lock;
0026     struct ipu_soc *ipu;
0027     struct ipu_smfc channel[4];
0028     int use_count;
0029 };
0030 
0031 /*SMFC Registers */
0032 #define SMFC_MAP    0x0000
0033 #define SMFC_WMC    0x0004
0034 #define SMFC_BS     0x0008
0035 
0036 int ipu_smfc_set_burstsize(struct ipu_smfc *smfc, int burstsize)
0037 {
0038     struct ipu_smfc_priv *priv = smfc->priv;
0039     unsigned long flags;
0040     u32 val, shift;
0041 
0042     spin_lock_irqsave(&priv->lock, flags);
0043 
0044     shift = smfc->chno * 4;
0045     val = readl(priv->base + SMFC_BS);
0046     val &= ~(0xf << shift);
0047     val |= burstsize << shift;
0048     writel(val, priv->base + SMFC_BS);
0049 
0050     spin_unlock_irqrestore(&priv->lock, flags);
0051 
0052     return 0;
0053 }
0054 EXPORT_SYMBOL_GPL(ipu_smfc_set_burstsize);
0055 
0056 int ipu_smfc_map_channel(struct ipu_smfc *smfc, int csi_id, int mipi_id)
0057 {
0058     struct ipu_smfc_priv *priv = smfc->priv;
0059     unsigned long flags;
0060     u32 val, shift;
0061 
0062     spin_lock_irqsave(&priv->lock, flags);
0063 
0064     shift = smfc->chno * 3;
0065     val = readl(priv->base + SMFC_MAP);
0066     val &= ~(0x7 << shift);
0067     val |= ((csi_id << 2) | mipi_id) << shift;
0068     writel(val, priv->base + SMFC_MAP);
0069 
0070     spin_unlock_irqrestore(&priv->lock, flags);
0071 
0072     return 0;
0073 }
0074 EXPORT_SYMBOL_GPL(ipu_smfc_map_channel);
0075 
0076 int ipu_smfc_set_watermark(struct ipu_smfc *smfc, u32 set_level, u32 clr_level)
0077 {
0078     struct ipu_smfc_priv *priv = smfc->priv;
0079     unsigned long flags;
0080     u32 val, shift;
0081 
0082     spin_lock_irqsave(&priv->lock, flags);
0083 
0084     shift = smfc->chno * 6 + (smfc->chno > 1 ? 4 : 0);
0085     val = readl(priv->base + SMFC_WMC);
0086     val &= ~(0x3f << shift);
0087     val |= ((clr_level << 3) | set_level) << shift;
0088     writel(val, priv->base + SMFC_WMC);
0089 
0090     spin_unlock_irqrestore(&priv->lock, flags);
0091 
0092     return 0;
0093 }
0094 EXPORT_SYMBOL_GPL(ipu_smfc_set_watermark);
0095 
0096 int ipu_smfc_enable(struct ipu_smfc *smfc)
0097 {
0098     struct ipu_smfc_priv *priv = smfc->priv;
0099     unsigned long flags;
0100 
0101     spin_lock_irqsave(&priv->lock, flags);
0102 
0103     if (!priv->use_count)
0104         ipu_module_enable(priv->ipu, IPU_CONF_SMFC_EN);
0105 
0106     priv->use_count++;
0107 
0108     spin_unlock_irqrestore(&priv->lock, flags);
0109 
0110     return 0;
0111 }
0112 EXPORT_SYMBOL_GPL(ipu_smfc_enable);
0113 
0114 int ipu_smfc_disable(struct ipu_smfc *smfc)
0115 {
0116     struct ipu_smfc_priv *priv = smfc->priv;
0117     unsigned long flags;
0118 
0119     spin_lock_irqsave(&priv->lock, flags);
0120 
0121     priv->use_count--;
0122 
0123     if (!priv->use_count)
0124         ipu_module_disable(priv->ipu, IPU_CONF_SMFC_EN);
0125 
0126     if (priv->use_count < 0)
0127         priv->use_count = 0;
0128 
0129     spin_unlock_irqrestore(&priv->lock, flags);
0130 
0131     return 0;
0132 }
0133 EXPORT_SYMBOL_GPL(ipu_smfc_disable);
0134 
0135 struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu, unsigned int chno)
0136 {
0137     struct ipu_smfc_priv *priv = ipu->smfc_priv;
0138     struct ipu_smfc *smfc, *ret;
0139     unsigned long flags;
0140 
0141     if (chno >= 4)
0142         return ERR_PTR(-EINVAL);
0143 
0144     smfc = &priv->channel[chno];
0145     ret = smfc;
0146 
0147     spin_lock_irqsave(&priv->lock, flags);
0148 
0149     if (smfc->inuse) {
0150         ret = ERR_PTR(-EBUSY);
0151         goto unlock;
0152     }
0153 
0154     smfc->inuse = true;
0155 unlock:
0156     spin_unlock_irqrestore(&priv->lock, flags);
0157     return ret;
0158 }
0159 EXPORT_SYMBOL_GPL(ipu_smfc_get);
0160 
0161 void ipu_smfc_put(struct ipu_smfc *smfc)
0162 {
0163     struct ipu_smfc_priv *priv = smfc->priv;
0164     unsigned long flags;
0165 
0166     spin_lock_irqsave(&priv->lock, flags);
0167     smfc->inuse = false;
0168     spin_unlock_irqrestore(&priv->lock, flags);
0169 }
0170 EXPORT_SYMBOL_GPL(ipu_smfc_put);
0171 
0172 int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,
0173           unsigned long base)
0174 {
0175     struct ipu_smfc_priv *priv;
0176     int i;
0177 
0178     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0179     if (!priv)
0180         return -ENOMEM;
0181 
0182     ipu->smfc_priv = priv;
0183     spin_lock_init(&priv->lock);
0184     priv->ipu = ipu;
0185 
0186     priv->base = devm_ioremap(dev, base, PAGE_SIZE);
0187     if (!priv->base)
0188         return -ENOMEM;
0189 
0190     for (i = 0; i < 4; i++) {
0191         priv->channel[i].priv = priv;
0192         priv->channel[i].chno = i;
0193     }
0194 
0195     pr_debug("%s: ioremap 0x%08lx -> %p\n", __func__, base, priv->base);
0196 
0197     return 0;
0198 }
0199 
0200 void ipu_smfc_exit(struct ipu_soc *ipu)
0201 {
0202 }