/*
* EP93XX PATA controller driver.
*
* Copyright (c) 2012, Metasoft s.c.
* Rafal Prylowski <prylowski@metasoft.pl>
*
* Based on pata_scc.c, pata_icside.c and on earlier version of EP93XX
* PATA driver by Lennert Buytenhek and Alessandro Zummo.
* Read/Write timings, resource management and other improvements
* from driver by Joao Ramos and Bartlomiej Zolnierkiewicz.
* DMA engine support based on spi-ep93xx.c by Mika Westerberg.
*
* Original copyrights:
*
* Support for Cirrus Logic's EP93xx (EP9312, EP9315) CPUs
* PATA host controller driver.
*
* Copyright (c) 2009, Bartlomiej Zolnierkiewicz
*
* Heavily based on the ep93xx-ide.c driver:
*
* Copyright (c) 2009, Joao Ramos <joao.ramos@inov.pt>
* INESC Inovacao (INOV)
*
* EP93XX PATA controller driver.
* Copyright (C) 2007 Lennert Buytenhek <buytenh@wantstofly.org>
*
* An ATA driver for the Cirrus Logic EP93xx PATA controller.
*
* Based on an earlier version by Alessandro Zummo, which is:
* Copyright (C) 2006 Tower Technologies
*/
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/blkdev.h>
#include <scsi/scsi_host.h>
#include <linux/ata.h>
#include <linux/libata.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/ktime.h>
#include <linux/platform_data/dma-ep93xx.h>
#include <linux/soc/cirrus/ep93xx.h>
#define DRV_NAME "ep93xx-ide"
#define DRV_VERSION "1.0"
enum {
/* IDE Control Register */
IDECTRL = 0x00,
IDECTRL_CS0N = (1 << 0),
IDECTRL_CS1N = (1 << 1),
IDECTRL_DIORN = (1 << 5),
IDECTRL_DIOWN = (1 << 6),
IDECTRL_INTRQ = (1 << 9),
IDECTRL_IORDY = (1 << 10),
/*
* the device IDE register to be accessed is selected through
* IDECTRL register's specific bitfields 'DA', 'CS1N' and 'CS0N':
* b4 b3 b2 b1 b0
* A2 A1 A0 CS1N CS0N
* the values filled in this structure allows the value to be directly
* ORed to the IDECTRL register, hence giving directly the A[2:0] and
* CS1N/CS0N values for each IDE register.
* The values correspond to the transformation:
* ((real IDE address) << 2) | CS1N value << 1 | CS0N value
*/
IDECTRL_ADDR_CMD = 0 + 2, /* CS1 */
IDECTRL_ADDR_DATA = (ATA_REG_DATA << 2) + 2,
IDECTRL_ADDR_ERROR = (ATA_REG_ERR << 2) + 2,
IDECTRL_ADDR_FEATURE = (ATA_REG_FEATURE << 2) + 2,
IDECTRL_ADDR_NSECT = (ATA_REG_NSECT << 2) + 2,
IDECTRL_ADDR_LBAL = (ATA_REG_LBAL << 2) + 2,
IDECTRL_ADDR_LBAM = (ATA_REG_LBAM << 2) + 2,
IDECTRL_ADDR_LBAH = (ATA_REG_LBAH << 2) + 2,
IDECTRL_ADDR_DEVICE = (ATA_REG_DEVICE << 2) + 2,
IDECTRL_ADDR_STATUS = (ATA_REG_STATUS << 2) + 2,
IDECTRL_ADDR_COMMAND = (ATA_REG_CMD << 2) + 2,
IDECTRL_ADDR_ALTSTATUS = (0x06 << 2) + 1, /* CS0 */
IDECTRL_ADDR_CTL = (0x06 << 2) + 1, /* CS0 */
/* IDE Configuration Register */
IDECFG = 0x04,
IDECFG_IDEEN = (1 << 0),
IDECFG_PIO = (1 << 1),
IDECFG_MDMA = (1 << 2),
IDECFG_UDMA = (1 << 3),
IDECFG_MODE_SHIFT = 4,
IDECFG_MODE_MASK = (0xf << 4),
IDECFG_WST_SHIFT = 8,
IDECFG_WST_MASK = (0x3 << 8),
/* MDMA Operation Register */
IDEMDMAOP = 0x08,
/* UDMA Operation Register */
IDEUDMAOP = 0x0c,
IDEUDMAOP_UEN = (1 << 0),
IDEUDMAOP_RWOP = (1 << 1),
/* PIO/MDMA/UDMA Data Registers */
IDEDATAOUT = 0x10,
IDEDATAIN = 0x14,
IDEMDMADATAOUT = 0x18,
IDEMDMADATAIN = 0x1c,
IDEUDMADATAOUT = 0x20,
IDEUDMADATAIN = 0x24,
/* UDMA Status Register */
IDEUDMASTS = 0x28,
IDEUDMASTS_DMAIDE = (1 << 16),
IDEUDMASTS_INTIDE = (1 << 17),
IDEUDMASTS_SBUSY = (1 << 18),
IDEUDMASTS_NDO = (1 << 24),
IDEUDMASTS_NDI = (1 << 25),
IDEUDMASTS_N4X = (1 << 26),
/* UDMA Debug Status Register */
IDEUDMADEBUG = 0x2c,
};
struct ep93xx_pata_data {
const struct platform_device *pdev;
void __iomem *ide_base;
struct ata_timing t;
bool iordy;
unsigned long udma_in_phys;
unsigned long udma_out_phys;
struct dma_chan *dma_rx_channel;
struct ep93xx_dma_data dma_rx_data;
struct dma_chan *dma_tx_channel;
struct ep93xx_dma_data dma_tx_data;
};
static