162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * arch/arm/plat-spear/pl080.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * DMAC pl080 definitions for SPEAr platform
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 2012 ST Microelectronics
862306a36Sopenharmony_ci * Viresh Kumar <vireshk@kernel.org>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/amba/pl08x.h>
1262306a36Sopenharmony_ci#include <linux/amba/bus.h>
1362306a36Sopenharmony_ci#include <linux/bug.h>
1462306a36Sopenharmony_ci#include <linux/err.h>
1562306a36Sopenharmony_ci#include <linux/io.h>
1662306a36Sopenharmony_ci#include <linux/spinlock_types.h>
1762306a36Sopenharmony_ci#include "spear.h"
1862306a36Sopenharmony_ci#include "misc_regs.h"
1962306a36Sopenharmony_ci#include "pl080.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic spinlock_t lock = __SPIN_LOCK_UNLOCKED(x);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistruct {
2462306a36Sopenharmony_ci	unsigned char busy;
2562306a36Sopenharmony_ci	unsigned char val;
2662306a36Sopenharmony_ci} signals[16] = {{0, 0}, };
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ciint pl080_get_signal(const struct pl08x_channel_data *cd)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	unsigned int signal = cd->min_signal, val;
3162306a36Sopenharmony_ci	unsigned long flags;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	spin_lock_irqsave(&lock, flags);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	/* Return if signal is already acquired by somebody else */
3662306a36Sopenharmony_ci	if (signals[signal].busy &&
3762306a36Sopenharmony_ci			(signals[signal].val != cd->muxval)) {
3862306a36Sopenharmony_ci		spin_unlock_irqrestore(&lock, flags);
3962306a36Sopenharmony_ci		return -EBUSY;
4062306a36Sopenharmony_ci	}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	/* If acquiring for the first time, configure it */
4362306a36Sopenharmony_ci	if (!signals[signal].busy) {
4462306a36Sopenharmony_ci		val = readl(DMA_CHN_CFG);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci		/*
4762306a36Sopenharmony_ci		 * Each request line has two bits in DMA_CHN_CFG register. To
4862306a36Sopenharmony_ci		 * goto the bits of current request line, do left shift of
4962306a36Sopenharmony_ci		 * value by 2 * signal number.
5062306a36Sopenharmony_ci		 */
5162306a36Sopenharmony_ci		val &= ~(0x3 << (signal * 2));
5262306a36Sopenharmony_ci		val |= cd->muxval << (signal * 2);
5362306a36Sopenharmony_ci		writel(val, DMA_CHN_CFG);
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	signals[signal].busy++;
5762306a36Sopenharmony_ci	signals[signal].val = cd->muxval;
5862306a36Sopenharmony_ci	spin_unlock_irqrestore(&lock, flags);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	return signal;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_civoid pl080_put_signal(const struct pl08x_channel_data *cd, int signal)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	unsigned long flags;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	spin_lock_irqsave(&lock, flags);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/* if signal is not used */
7062306a36Sopenharmony_ci	if (!signals[signal].busy)
7162306a36Sopenharmony_ci		BUG();
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	signals[signal].busy--;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	spin_unlock_irqrestore(&lock, flags);
7662306a36Sopenharmony_ci}
77