/*
* DMA driver for Xilinx Video DMA Engine
*
* Copyright (C) 2010-2014 Xilinx, Inc. All rights reserved.
*
* Based on the Freescale DMA driver.
*
* Description:
* The AXI Video Direct Memory Access (AXI VDMA) core is a soft Xilinx IP
* core that provides high-bandwidth direct memory access between memory
* and AXI4-Stream type video target peripherals. The core provides efficient
* two dimensional DMA operations with independent asynchronous read (S2MM)
* and write (MM2S) channel operation. It can be configured to have either
* one channel or two channels. If configured as two channels, one is to
* transmit to the video device (MM2S) and another is to receive from the
* video device (S2MM). Initialization, status, interrupt and management
* registers are accessed through an AXI4-Lite slave interface.
*
* 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.
*/
#include <linux/amba/xilinx_dma.h>
#include <linux/bitops.h>
#include <linux/dmapool.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_dma.h>
#include <linux/of_platform.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#include "../dmaengine.h"
/* Register/Descriptor Offsets */
#define XILINX_VDMA_MM2S_CTRL_OFFSET 0x0000
#define XILINX_VDMA_S2MM_CTRL_OFFSET 0x0030
#define XILINX_VDMA_MM2S_DESC_OFFSET 0x0050
#define XILINX_VDMA_S2MM_DESC_OFFSET 0x00a0
/* Control Registers */
#define XILINX_VDMA_REG_DMACR 0x0000
#define XILINX_VDMA_DMACR_DELAY_MAX 0xff
#define XILINX_VDMA_DMACR_DELAY_SHIFT 24
#define XILINX_VDMA_DMACR_FRAME_COUNT_MAX 0xff
#define XILINX_VDMA_DMACR_FRAME_COUNT_SHIFT 16
#define XILINX_VDMA_DMACR_ERR_IRQ BIT(14)
#define XILINX_VDMA_DMACR_DLY_CNT_IRQ BIT(13)
#define XILINX_VDMA_DMACR_FRM_CNT_IRQ BIT(12)
#define XILINX_VDMA_DMACR_MASTER_SHIFT 8
#define XILINX_VDMA_DMACR_FSYNCSRC_SHIFT 5
#define XILINX_VDMA_DMACR_FRAMECNT_EN BIT(4)
#define XILINX_VDMA_DMACR_GENLOCK_EN BIT(3)
#define XILINX_VDMA_DMACR_RESET BIT(2)
#define XILINX_VDMA_DMACR_CIRC_EN BIT(1)
#define XILINX_VDMA_DMACR_RUNSTOP BIT(0)
#define XILINX_VDMA_DMACR_FSYNCSRC_MASK GENMASK(6, 5)
#define XILINX_VDMA_REG_DMASR 0x0004
#define XILINX_VDMA_DMASR_EOL_LATE_ERR BIT(15)
#define XILINX_VDMA_DMASR_ERR_IRQ BIT(14)
#define XILINX_VDMA_DMASR_DLY_CNT_IRQ BIT(13)
#define XILINX_VDMA_DMASR_FRM_CNT_IRQ BIT(12)
#define XILINX_VDMA_DMASR_SOF_LATE_ERR BIT(11)
#define XILINX_VDMA_DMASR_SG_DEC_ERR BIT(10)
#define XILINX_VDMA_DMASR_SG_SLV_ERR BIT(9)
#define XILINX_VDMA_DMASR_EOF_EARLY_ERR BIT(8)
#define XILINX_VDMA_DMASR_SOF_EARLY_ERR BIT(7)
#define XILINX_VDMA_DMASR_DMA_DEC_ERR BIT(6)
#define XILINX_VDMA_DMASR_DMA_SLAVE_ERR BIT(5)
#define XILINX_VDMA_DMASR_DMA_INT_ERR BIT(4)
#define XILINX_VDMA_DMASR_IDLE BIT(1)
#define XILINX_VDMA_DMASR_HALTED BIT(0)
#define XILINX_VDMA_DMASR_DELAY_MASK GENMASK(31, 24)
#define XILINX_VDMA_DMASR_FRAME_COUNT_MASK GENMASK(23, 16)
#define XILINX_VDMA_REG_CURDESC 0x0008
#define XILINX_VDMA_REG_TAILDESC 0x0010
#define XILINX_VDMA_REG_REG_INDEX 0x0014
#define XILINX_VDMA_REG_FRMSTORE 0x0018
#define XILINX_VDMA_REG_THRESHOLD 0x001c
#define XILINX_VDMA_REG_FRMPTR_STS 0x0024
#define XILINX_VDMA_REG_PARK_PTR 0x0028
#define XILINX_VDMA_PARK_PTR_WR_REF_SHIFT 8
#define XILINX_VDMA_PARK_PTR_RD_REF_SHIFT 0
#define XILINX_VDMA_REG_VDMA_VERSION 0x002c
/* Register Direct Mode Registers */
#define XILINX_VDMA_REG_VSIZE 0x0000
#define XILINX_VDMA_REG_HSIZE 0x0004
#define XILINX_VDMA_REG_FRMDLY_STRIDE 0x0008
#define XILINX_VDMA_FRMDLY_STRIDE_FRMDLY_SHIFT 24
#define XILINX_VDMA_FRMDLY_STRIDE_STRIDE_SHIFT 0
#define XILINX_VDMA_REG_START_ADDRESS(n) (0x000c + 4 * (n))
/* HW specific definitions */
#define XILINX_VDMA_MAX_CHANS_PER_DEVICE 0x2
#define XILINX_VDMA_DMAXR_ALL_IRQ_MASK \
(XILINX_VDMA_DMASR_FRM_CNT_IRQ | \
XILINX_VDMA_DMASR_DLY_CNT_IRQ | \
XILINX_VDMA_DMASR_ERR_IRQ)
#define XILINX_VDMA_DMASR_ALL_ERR_MASK \
(XILINX_VDMA_DMASR_EOL_LATE_ERR | \
XILINX_VDMA_DMASR_SOF_LATE_ERR | \
XILINX_VDMA_DMASR_SG_DEC_ERR | \
XILINX_VDMA_DMASR_SG_SLV_ERR | \
XILINX_VDMA_DMASR_EOF_EARLY_ERR | \
XILINX_VDMA_DMASR_SOF_EARLY_ERR | \
XILINX_VDMA_DMASR_DMA_DEC_ERR | \
XILINX_VDMA_DMASR_DMA_SLAVE_ERR | \
XILINX_VDMA_DMASR_DMA_INT_ERR)
/*
* Recoverable errors are DMA Internal error, SOF Early, EOF Early
* and SOF Late. They are only recoverable when C_FLUSH_ON_FSYNC
* is enabled in the h/w system.
*/
#define XILINX_VDMA_DMASR_ERR_RECOVER_MASK \
(XILINX_VDMA_DMASR_SOF_LATE_ERR | \
XILINX_VDMA_DMASR_EOF_EARLY_ERR | \
XILINX_VDMA_DMASR_SOF_EARLY_ERR | \
XILINX_VDMA_DMASR_DMA_INT_ERR)
/* Axi VDMA Flush on Fsync bits */
#define XILINX_VDMA_FLUSH_S2MM 3
#define XILINX_VDMA_FLUSH_MM2S 2
#define XILINX_VDMA_FLUSH_BOTH 1
/* Delay loop counter to prevent hardware failure */
#define XILINX_VDMA_LOOP_COUNT 1000000
/**
* struct xilinx_vdma_desc_hw - Hardware Descriptor
* @next_desc: Next Descriptor Pointer @0x00
* @pad1: Reserved @0x04
* @buf_addr: Buffer address @0x08
* @pad2: Reserved @0x0C
* @vsize: Vertical Size @0x10
* @hsize: Horizontal Size @0x14
* @stride: Number of bytes between the first
* pixels of each horizontal line @0x18
*/
struct xilinx_vdma_desc_hw {
u32 next_desc;
u32 pad1;