/*
* S3C24XX DMA handling
*
* Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
*
* based on amba-pl08x.c
*
* Copyright (c) 2006 ARM Ltd.
* Copyright (c) 2010 ST-Ericsson SA
*
* Author: Peter Pearse <peter.pearse@arm.com>
* Author: Linus Walleij <linus.walleij@stericsson.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* The DMA controllers in S3C24XX SoCs have a varying number of DMA signals
* that can be routed to any of the 4 to 8 hardware-channels.
*
* Therefore on these DMA controllers the number of channels
* and the number of incoming DMA signals are two totally different things.
* It is usually not possible to theoretically handle all physical signals,
* so a multiplexing scheme with possible denial of use is necessary.
*
* Open items:
* - bursts
*/
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_data/dma-s3c24xx.h>
#include "dmaengine.h"
#include "virt-dma.h"
#define MAX_DMA_CHANNELS 8
#define S3C24XX_DISRC 0x00
#define S3C24XX_DISRCC 0x04
#define S3C24XX_DISRCC_INC_INCREMENT 0
#define S3C24XX_DISRCC_INC_FIXED BIT(0)
#define S3C24XX_DISRCC_LOC_AHB 0
#define S3C24XX_DISRCC_LOC_APB BIT(1)
#define S3C24XX_DIDST 0x08
#define S3C24XX_DIDSTC 0x0c
#define S3C24XX_DIDSTC_INC_INCREMENT 0
#define S3C24XX_DIDSTC_INC_FIXED BIT(0)
#define S3C24XX_DIDSTC_LOC_AHB 0
#define S3C24XX_DIDSTC_LOC_APB BIT(1)
#define S3C24XX_DIDSTC_INT_TC0 0
#define S3C24XX_DIDSTC_INT_RELOAD BIT(2)
#define S3C24XX_DCON 0x10
#define S3C24XX_DCON_TC_MASK 0xfffff
#define S3C24XX_DCON_DSZ_BYTE (0 << 20)
#define S3C24XX_DCON_DSZ_HALFWORD (1 << 20)
#define S3C24XX_DCON_DSZ_WORD (2 << 20)
#define S3C24XX_DCON_DSZ_MASK (3 << 20)
#define S3C24XX_DCON_DSZ_SHIFT 20
#define S3C24XX_DCON_AUTORELOAD 0
#define S3C24XX_DCON_NORELOAD BIT(22)
#define S3C24XX_DCON_HWTRIG BIT(23)
#define S3C24XX_DCON_HWSRC_SHIFT 24
#define S3C24XX_DCON_SERV_SINGLE 0
#define S3C24XX_DCON_SERV_WHOLE BIT(27)
#define S3C24XX_DCON_TSZ_UNIT 0
#define S3C24XX_DCON_TSZ_BURST4 BIT(28)
#define S3C24XX_DCON_INT BIT(29)
#define S3C24XX_DCON_SYNC_PCLK 0
#define S3C24XX_DCON_SYNC_HCLK BIT(30)
#define S3C24XX_DCON_DEMAND 0
#define S3C24XX_DCON_HANDSHAKE BIT(31)
#define S3C24XX_DSTAT 0x14
#define S3C24XX_DSTAT_STAT_BUSY BIT(20)
#define S3C24XX_DSTAT_CURRTC_MASK 0xfffff
#define S3C24XX_DMASKTRIG 0x20
#define S3C24XX_DMASKTRIG_SWTRIG BIT(0)
#define S3C24XX_DMASKTRIG_ON BIT(1)
#define S3C24XX_DMASKTRIG_STOP BIT(2)
#define S3C24XX_DMAREQSEL 0x24
#define S3C24XX_DMAREQSEL_HW BIT(0)
/*
* S3C2410, S3C2440 and S3C2442 SoCs cannot select any physical channel
* for a DMA source. Instead only specific channels are valid.
* All of these SoCs have 4 physical channels and the number of request
* source bits is 3. Additionally we also need 1 bit to mark the channel
* as valid.
* Therefore we separate the chansel element of the channel data into 4
* parts of 4 bits each, to hold the information if the channel is valid
* and the hw request source to use.
*
* Example:
* SDI is valid on channels 0, 2 and 3 - with varying hw request sources.
* For it the chansel field would look like
*
* ((BIT(3) | 1) << 3 * 4) | // channel 3, with request source 1
* ((BIT(3) | 2) << 2 * 4) | // channel 2, with request source 2
* ((BIT(3) | 2) << 0 * 4) // channel 0, with request source 2
*/
#define S3C24XX_CHANSEL_WIDTH 4
#define S3C24XX_CHANSEL_VALID BIT(3)
#define S3C24XX_CHANSEL_REQ_MASK 7
/*
* struct soc_data - vendor-specific config parameters for individual SoCs
* @stride: spacing between the registers of each channel
* @has_reqsel: does the controller use the newer requestselection mechanism
* @has_clocks: are controllable dma-clocks present
*/
struct soc_data {
int stride;
bool has_reqsel;
bool has_clocks;
};
/*
* enum s3c24xx_dma_chan_state - holds the virtual