brintos

brintos / linux-shallow public Read only

0
0
Text · 4.1 KiB · 46ffc0a Raw
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