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