/*
 * Copyright © 2006, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */
#ifndef _ADMA_H
#define _ADMA_H
#include <linux/types.h>
#include <linux/io.h>
#include <mach/hardware.h>
#include <asm/hardware/iop_adma.h>

/* Memory copy units */
#define DMA_CCR(chan)		(chan->mmr_base + 0x0)
#define DMA_CSR(chan)		(chan->mmr_base + 0x4)
#define DMA_DAR(chan)		(chan->mmr_base + 0xc)
#define DMA_NDAR(chan)		(chan->mmr_base + 0x10)
#define DMA_PADR(chan)		(chan->mmr_base + 0x14)
#define DMA_PUADR(chan)	(chan->mmr_base + 0x18)
#define DMA_LADR(chan)		(chan->mmr_base + 0x1c)
#define DMA_BCR(chan)		(chan->mmr_base + 0x20)
#define DMA_DCR(chan)		(chan->mmr_base + 0x24)

/* Application accelerator unit  */
#define AAU_ACR(chan)		(chan->mmr_base + 0x0)
#define AAU_ASR(chan)		(chan->mmr_base + 0x4)
#define AAU_ADAR(chan)		(chan->mmr_base + 0x8)
#define AAU_ANDAR(chan)	(chan->mmr_base + 0xc)
#define AAU_SAR(src, chan)	(chan->mmr_base + (0x10 + ((src) << 2)))
#define AAU_DAR(chan)		(chan->mmr_base + 0x20)
#define AAU_ABCR(chan)		(chan->mmr_base + 0x24)
#define AAU_ADCR(chan)		(chan->mmr_base + 0x28)
#define AAU_SAR_EDCR(src_edc)	(chan->mmr_base + (0x02c + ((src_edc-4) << 2)))
#define AAU_EDCR0_IDX	8
#define AAU_EDCR1_IDX	17
#define AAU_EDCR2_IDX	26

#define DMA0_ID 0
#define DMA1_ID 1
#define AAU_ID 2

struct iop3xx_aau_desc_ctrl {
	unsigned int int_en:1;
	unsigned int blk1_cmd_ctrl:3;
	unsigned int blk2_cmd_ctrl:3;
	unsigned int blk3_cmd_ctrl:3;
	unsigned int blk4_cmd_ctrl:3;
	unsigned int blk5_cmd_ctrl:3;
	unsigned int blk6_cmd_ctrl:3;
	unsigned int blk7_cmd_ctrl:3;
	unsigned int blk8_cmd_ctrl:3;
	unsigned int blk_ctrl:2;
	unsigned int dual_xor_en:1;
	unsigned int tx_complete:1;
	unsigned int zero_result_err:1;
	unsigned int zero_result_en:1;
	unsigned int dest_write_en:1;
};

struct iop3xx_aau_e_desc_ctrl {
	unsigned int reserved:1;
	unsigned int blk1_cmd_ctrl:3;
	unsigned int blk2_cmd_ctrl:3;
	unsigned int blk3_cmd_ctrl:3;
	unsigned int blk4_cmd_ctrl:3;
	unsigned int blk5_cmd_ctrl:3;
	unsigned int blk6_cmd_ctrl:3;
	unsigned int blk7_cmd_ctrl:3;
	unsigned int blk8_cmd_ctrl:3;
	unsigned int reserved2:7;
};

struct iop3xx_dma_desc_ctrl {
	unsigned int pci_transaction:4;
	unsigned int int_en:1;
	unsigned int dac_cycle_en:1;
	unsigned int mem_to_mem_en:1;
	unsigned int crc_data_tx_en:1;
	unsigned int crc_gen_en:1;
	unsigned int crc_seed_dis:1;
	unsigned int reserved:21;
	unsigned int crc_tx_complete:1;
};

struct iop3xx_desc_dma {
	u32 next_desc;
	union {
		u32 pci_src_addr;
		u32 pci_dest_addr;
		u32 src_addr;
	};
	union {
		u32 upper_pci_src_addr;
		u32 upper_pci_dest_addr;
	};
	union {
		u32 local_pci_src_addr;
		u32 local_pci_dest_addr;
		u32 dest_addr;
	};
	u32 byte_count;
	union {
		u32 desc_ctrl;
		struct iop3xx_dma_desc_ctrl desc_ctrl_field;
	};
	u32 crc_addr;
};

struct iop3xx_desc_aau {
	u32 next_desc;
	u32 src[4];
	u32 dest_addr;
	u32 byte_count;
	union {
		u32 desc_ctrl;
		struct iop3xx_aau_desc_ctrl desc_ctrl_field;
	};
	union {
		u32 src_addr;
		u32 e_desc_ctrl;
		struct iop3xx_aau_e_desc_ctrl e_desc_ctrl_field;
	} src_edc[31];
};

struct iop3xx_aau_gfmr {
	unsigned int gfmr1:8;
	unsigned int gfmr2:8;
	unsigned int gfmr3:8;
	unsigned int gfmr4:8;
};

struct iop3xx_desc_pq_xor {
	u32 next_desc;
	u32 src[3];
	union {
		u32 data_mult1;
		struct iop3xx_aau_gfmr data_mult1_field;
	};
	u32 dest_addr;
	u32 byte_count;
	union {
		u32 desc_ctrl;
		struct iop3xx_aau_desc_ctrl desc_ctrl_field;
	};
	union {
		u32 src_addr;
		u32 e_desc_ctrl;
		struct iop3xx_aau_e_desc_ctrl e_desc_ctrl_field;
		u32 data_multiplier;
		struct iop3xx_aau_gfmr data_mult_field;
		u32 reserved;
	} src_edc_gfmr[19];
};

struct iop3xx_desc_dual_xor {
	u32 next_desc;
	u32 src0_addr;
	u32 src1_addr;
	u32 h_src_addr;
	u32 d_src_addr;
	u32 h_dest_addr;
	u32 byte_count;
	union {
		u32 desc_ctrl;
		struct iop3xx_aau_desc_ctrl desc_ctrl_field;
	};
	u32 d_dest_addr;
};

union iop3xx_desc {
	struct iop3xx_desc_aau *aau;
	struct iop3xx_desc_dma *dma;
	struct iop3xx_desc_pq_xor *pq_xor;
	struct iop3xx_desc_dual_xor *dual_xor;
	void *ptr;
};

/* No support for p+q operations */
static inline int
iop_chan_pq_slot_count(size_t len, int src_cnt, int *slots_per_op)
{
	BUG();
	return 0;
}

static inline void
iop_desc_init_pq(struct iop_adma_desc_slot *desc, int src_cnt,
		  unsigned long flags)
{
	BUG();
}

static inline void
iop_desc_set_pq_addr(struct iop_adma_desc_slot *desc, dma_addr_t *addr)
{
	BUG();
}

static inline void
iop_desc_set_pq_src_addr(struct iop_adma_desc_slot *desc, int src_idx,
			 dma_addr_t addr, unsigned char coef)
{
	BUG();
}

static inline int
iop_chan_pq_zero_sum_slot_count(size_t len, int src_cnt, int *slots_per_op)
{
	BUG();
	return 0;
}

static inline void
iop_desc_init_pq_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt,
			  unsigned long flags)
{
	BUG();
}

static inline void
iop_desc_set_pq_zero_sum_byte_count(struct iop_adma_desc_slot *desc, u32 len)
{
	BUG();
}

#define iop_desc_set_pq_zero_sum_src_addr iop_desc_set_pq_src_addr

static inline void
iop_desc_set_pq_zero_sum_addr(struct iop_adma_desc_slot *desc, int pq_idx,
			      dma_addr_t *src)
{
	BUG();
}

static inline int iop_adma_get_max_xor(void)
{
	return 32;
}

static inline int iop_adma_get_max_pq(void)
{
	BUG();
	return 0;
}

static inline u32 iop_chan_get_current_descriptor(struct iop_adma_chan *chan)
{
	int id = chan->device->id;

	switch (id) {
	case DMA0_ID:
	case DMA1_ID:
		return __raw_readl(DMA_DAR(chan));
	case AAU_ID:
		return __raw_readl(AAU_ADAR(chan));
	default:
		BUG();
