linux/drivers/gpu/ipu-v3/ipu-smfc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   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        0x0000
  33#define SMFC_WMC        0x0004
  34#define SMFC_BS         0x0008
  35
  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