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