Patchwork [U-Boot,2/2] ftide020: add faraday ide ahb controller from Linux kernel

login
register
mail settings
Submitter Macpaul Lin
Date Jan. 24, 2011, 12:47 p.m.
Message ID <1295873267-32570-2-git-send-email-macpaul@andestech.com>
Download mbox | patch
Permalink /patch/80151/
State Superseded
Headers show

Comments

Macpaul Lin - Jan. 24, 2011, 12:47 p.m.
Faraday's ftide020_s is an IDE-AHB controller for SoC design.
This patch ported the u-boot driver (PIO) of ftide020 ATA (IDE) driver
from Linux kernel. IDE commands include read, info, and other functions
has been implemented.

Because this IDE controller support AHB interface only which is differ
from other most IDE controller supports PCI interface. Some registers
access is required during CMD/DATA I/O. Hence a configuration
"CONFIG_IDE_AHB" is required to be defined according to the feature in
cmd_ide.c.

Signed-off-by: Macpaul Lin <macpaul@andestech.com>
---
 drivers/block/Makefile   |    1 +
 drivers/block/ftide020.c |  380 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/block/ftide020.h |  265 ++++++++++++++++++++++++++++++++
 3 files changed, 646 insertions(+), 0 deletions(-)
 create mode 100644 drivers/block/ftide020.c
 create mode 100644 drivers/block/ftide020.h
Wolfgang Denk - April 11, 2011, 8:30 p.m.
Dear Macpaul Lin,

In message <1295873267-32570-2-git-send-email-macpaul@andestech.com> you wrote:
> Faraday's ftide020_s is an IDE-AHB controller for SoC design.
> This patch ported the u-boot driver (PIO) of ftide020 ATA (IDE) driver
> from Linux kernel. IDE commands include read, info, and other functions
> has been implemented.

When copying code from Linux, you must give exact reference from which
file and which exact version (commit ID) the code was taken rom;
please see bullet # 4 at
http://www.denx.de/wiki/view/U-Boot/Patches#Attributing_Code_Copyrights_Sign

...
> +extern ulong ide_bus_offset[CONFIG_SYS_IDE_MAXBUS];

See before - please move to header file.

...
> +			tcyc = (u8) (((UDMA_ACCESS_TIMING[UDMA_TCYC][mode] * sysclk) + 9990) / 10000);
> +			tcvs = (u8) (((UDMA_ACCESS_TIMING[UDMA_TCVS][mode] * sysclk) + 9990) / 10000);
> +			tmli = (u8) (((UDMA_ACCESS_TIMING[UDMA_TMLI][mode] * sysclk) + 9990) / 10000);
> +			tenv = (u8) (((UDMA_ACCESS_TIMING[UDMA_TENV][mode] * sysclk) + 9990) / 10000);
> +			trp  = (u8) (((UDMA_ACCESS_TIMING[UDMA_TRP][mode]  * sysclk) + 9990) / 10000);
> +			tack = (u8) (((UDMA_ACCESS_TIMING[UDMA_TACK][mode] * sysclk) + 9990) / 10000);

Lines too long, please fix globally.

...
> +/* set device: (CF4) */
> +#define IDE_SET_OPCODE		(0x2740 << 2) 		/* [15:2], 0x9d00 */

please, no space before tabs. Please fix globally.


Best regards,

Wolfgang Denk

Patch

diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index e27175b..e3f46b8 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -28,6 +28,7 @@  LIB	:= $(obj)libblock.o
 COBJS-$(CONFIG_SCSI_AHCI) += ahci.o
 COBJS-$(CONFIG_ATA_PIIX) += ata_piix.o
 COBJS-$(CONFIG_FSL_SATA) += fsl_sata.o
+COBJS-$(CONFIG_IDE_FTIDE020) += ftide020.o
 COBJS-$(CONFIG_LIBATA) += libata.o
 COBJS-$(CONFIG_CMD_MG_DISK) += mg_disk.o
 COBJS-$(CONFIG_MVSATA_IDE) += mvsata_ide.o
diff --git a/drivers/block/ftide020.c b/drivers/block/ftide020.c
new file mode 100644
index 0000000..eef8c08
--- /dev/null
+++ b/drivers/block/ftide020.c
@@ -0,0 +1,380 @@ 
+/*
+ * [origin: Linux kernel drivers/ide/ftide020.c]
+ * Faraday FTIDE020 ATA Controller (AHB)
+ *
+ * (C) Copyright 2011 Andes Technology
+ * Greentime Hu <greentime@andestech.com>
+ * Macpaul Lin <macpaul@andestech.com>
+ * Kuo-Wei Chou <kwchou@andestech.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+/* ftide020.c - ide support functions for the FTIDE020_S controller */
+
+#include <config.h>
+#include <common.h>
+#include <ata.h>
+#include <ide.h>
+#include <asm/io.h>
+#include <api_public.h>
+
+#include "ftide020.h"
+
+#define FTIDE_IP_NAME		"FTIDE020_S"
+#define FTIDE_DRIVER_VERSION	"1.0.1"
+
+#ifndef TRUE
+#define TRUE	1
+#endif
+
+#ifndef FALSE
+#define FALSE	0
+#endif
+
+/* DEBUG */
+#ifdef FTIDE_DEBUG
+	#define P_DEBUG(fmt, args...)	printf(FTIDE_IP_NAME ":" fmt, ## args)
+#else
+	#define P_DEBUG(a...)
+#endif
+
+/* base address */
+#define FTIDE_BASE	CONFIG_SYS_ATA_BASE_ADDR
+
+/*
+ * data address - The CMD and DATA use the same FIFO in FTIDE020_S
+ *   FTIDE_DATA = CONFIG_SYS_ATA_BASE_ADDR + CONFIG_SYS_ATA_DATA_OFFSET
+ *		= &ftide020->rw_fifo
+ */
+#define FTIDE_DATA	(&ftide020->rw_fifo)
+
+/* command and data I/O macros */
+/* 0x0 - DATA FIFO */
+#define WRITE_DATA(x)	outl((x), &ftide020->rw_fifo)	/* 0x00 */
+#define READ_DATA()	inl(&ftide020->rw_fifo)		/* 0x00 */
+/* 0x04 - R: Status Reg, W: CMD_FIFO */
+#define WRITE_CMD(x)	outl((x), &ftide020->cmd_fifo)	/* 0x04 */
+#define READ_STATUS()	inl(&ftide020->cmd_fifo)	/* 0x04 */
+
+#define mdelay(n) ({unsigned long msec = (n); while (msec--) udelay(1000); })
+
+void ftide_set_device(int cx8, int dev)
+{
+	static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
+
+	WRITE_CMD(SET_DEV_CMD | IDE_SET_CX8(cx8) | dev);
+}
+
+unsigned char ide_read_register(int dev, unsigned int port)
+{
+	static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
+
+	ftide_set_device(0, dev);
+	WRITE_CMD(READ_REG_CMD | IDE_REG_CS_READ(CONFIG_IDE_REG_CS) |
+		IDE_REG_DA_WRITE(port));
+
+	return READ_DATA() & 0xff;
+}
+
+void ide_write_register(int dev, unsigned int port, unsigned char val)
+{
+	static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
+
+	ftide_set_device(0, dev);
+	WRITE_CMD(WRITE_REG_CMD | IDE_REG_CS_WRITE(CONFIG_IDE_REG_CS) |
+		IDE_REG_DA_WRITE(port) | val);
+}
+
+void ide_write_data(int dev, ulong *sect_buf, int words)
+{
+	static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
+
+	ftide_set_device(0, dev);
+	WRITE_CMD(WRITE_DATA_CMD | ((words << 2) - 1));
+
+	/* block write */
+	outsl(FTIDE_DATA, sect_buf, words);
+}
+
+void ide_read_data(int dev, ulong *sect_buf, int words)
+{
+	static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
+
+	ftide_set_device(0, dev);
+	WRITE_CMD(READ_DATA_CMD | ((words << 2) - 1));
+
+	/* block read */
+	insl(FTIDE_DATA, sect_buf, words);
+}
+
+void ftide_dfifo_ready(ulong *time)
+{
+	static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
+
+	while (!(READ_STATUS() & STATUS_RFE)) {
+		if (*time-- == 0)
+			break;
+
+		udelay(100);
+	}
+}
+
+extern ulong ide_bus_offset[CONFIG_SYS_IDE_MAXBUS];
+
+/* Reset_IDE_controller */
+static void reset_ide_controller(void)
+{
+	static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
+	unsigned int val;
+
+	val = inl(&ftide020->cr);
+
+	val |= CONTROL_RST;
+	outl(val, &ftide020->cr);
+
+	/* wait until reset OK, this is poor HW design */
+	mdelay(50);
+	val &= ~(CONTROL_RST);
+	outl(val, &ftide020->cr);
+
+	mdelay(50);
+	val |= CONTROL_SRST;
+	outl(val, &ftide020->cr);
+
+	/* wait until reset OK, this is poor HW design */
+	mdelay(50);
+	val &= ~(CONTROL_SRST);
+	outl(val, &ftide020->cr);
+
+	/* IORDY enable for PIO, for 2 device */
+	val |= (CONTROL_IRE0 | CONTROL_IRE1);
+	outl(val, &ftide020->cr);
+}
+
+/* IDE clock frequence */
+uint ftide_clock_freq(void)
+{
+	/*
+	 * todo: To aquire dynamic system frequency is dependend on the power
+	 * management unit which the ftide020 is connected to. In current,
+	 * there are only few PMU supports in u-boot.
+	 * So this function is wait for future enhancement.
+	 */
+	return 100;
+}
+
+/* Calculate Timing Registers */
+static unsigned int timing_cal(u16 t0, u16 t1, u16 t2, u16 t4)
+{
+	unsigned int val, ahb_ns = 8;
+	u8 TEOC, T1, T2, T4;
+
+	T1 = (u8) (t1 / ahb_ns);
+	if ((T1 * ahb_ns) == t1)
+		T1--;
+
+	T2 = (u8) (t2 / ahb_ns);
+	if ((T2 * ahb_ns) == t2)
+		T2--;
+
+	T4 = (u8) (t4 / ahb_ns);
+	if ((T4 * ahb_ns) == t4)
+		T4--;
+
+	TEOC = (u8) (t0 / ahb_ns);
+	if ((TEOC * ahb_ns) == t0)
+		TEOC--;
+
+	TEOC = ((TEOC > (T1 + T2 + T4)) ? (TEOC - (T1 + T2 + T4)) : 0);
+
+	/*
+	 * Here the fields in data timing registers in PIO mode
+	 * is accessed the same way as command timing registers.
+	 */
+	val =	DT_REG_PIO_T1(T1)	|
+		DT_REG_PIO_T2(T2)	|
+		DT_REG_PIO_T4(T4)	|
+		DT_REG_PIO_TEOC(TEOC);
+
+	return val;
+}
+
+/* Set Timing Register */
+static unsigned int set_mode_timing(u8 dev, u8 id, u8 mode)
+{
+	static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
+	u16 t0, t1, t2, t4;
+	u8 tcyc, tcvs, tmli, tenv, tack, trp;
+	unsigned int val, sysclk = 8;
+
+	if (id >= TATOL_TIMING)
+		return FALSE;
+
+	sysclk = ftide_clock_freq();
+	switch (id) {
+	case CMD_TIMING:
+		if (mode < REG_MODE) {
+			t0 = REG_ACCESS_TIMING[REG_T0][mode];
+			t1 = REG_ACCESS_TIMING[REG_T1][mode];
+			t2 = REG_ACCESS_TIMING[REG_T2][mode];
+			t4 = REG_ACCESS_TIMING[REG_T4][mode];
+
+			val = timing_cal(t0, t1, t2, t4);
+			outl(val, (dev ? &ftide020->ctrd1 : &ftide020->ctrd0));
+			return TRUE;
+		} else
+			return FALSE;
+	case PIO_TIMING:
+		if (mode < PIO_MODE) {
+			t0 = PIO_ACCESS_TIMING[PIO_T0][mode];
+			t1 = PIO_ACCESS_TIMING[PIO_T1][mode];
+			t2 = PIO_ACCESS_TIMING[PIO_T2][mode];
+			t4 = PIO_ACCESS_TIMING[PIO_T4][mode];
+
+			val = timing_cal(t0, t1, t2, t4);
+
+			outl(val, (dev ? &ftide020->dtrd1 : &ftide020->dtrd0));
+			return TRUE;
+		} else
+			return FALSE;
+	case DMA_TIMING:
+		if (mode < UDMA_MODE) {
+			/*
+			 * 0.999 is ceiling
+			 * for tcyc, tcvs, tmli, tenv, trp, tack
+			 */
+			tcyc = (u8) (((UDMA_ACCESS_TIMING[UDMA_TCYC][mode] * sysclk) + 9990) / 10000);
+			tcvs = (u8) (((UDMA_ACCESS_TIMING[UDMA_TCVS][mode] * sysclk) + 9990) / 10000);
+			tmli = (u8) (((UDMA_ACCESS_TIMING[UDMA_TMLI][mode] * sysclk) + 9990) / 10000);
+			tenv = (u8) (((UDMA_ACCESS_TIMING[UDMA_TENV][mode] * sysclk) + 9990) / 10000);
+			trp  = (u8) (((UDMA_ACCESS_TIMING[UDMA_TRP][mode]  * sysclk) + 9990) / 10000);
+			tack = (u8) (((UDMA_ACCESS_TIMING[UDMA_TACK][mode] * sysclk) + 9990) / 10000);
+
+			val  =	DT_REG_UDMA_TENV((tenv > 0) ? (tenv - 1) : 0) |
+				DT_REG_UDMA_TMLI((tmli > 0) ? (tmli - 1) : 0) |
+				DT_REG_UDMA_TCYC((tcyc > 0) ? (tcyc - 1) : 0) |
+				DT_REG_UDMA_TACK((tack > 0) ? (tack - 1) : 0) |
+				DT_REG_UDMA_TCVS((tcvs > 0) ? (tcvs - 1) : 0) |
+				DT_REG_UDMA_TRP((trp > 0) ? (trp - 1) : 0);
+
+			outl(val, (dev ? &ftide020->dtrd1 : &ftide020->dtrd0));
+			return TRUE;
+		} else
+			return FALSE;
+	default:
+		return FALSE;
+	}
+}
+
+static void ftide_read_hwrev(void)
+{
+	static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
+	unsigned int rev;
+
+	rev = inl(&ftide020->revision);
+}
+
+static int ftide_controller_probe(void)
+{
+	static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
+	unsigned int bak;
+
+	bak = inl(&ftide020->ctrd1);
+
+	/* probing by using shorter setup time */
+	outl(CONFIG_CTRD1_PROBE_T1, &ftide020->ctrd1);
+	if ((inl(&ftide020->ctrd1) & 0xff) != CONFIG_CTRD1_PROBE_T1) {
+		outl(bak, &ftide020->ctrd1);
+		return 0;
+	}
+
+	/* probing by using longer setup time */
+	outl(CONFIG_CTRD1_PROBE_T2, &ftide020->ctrd1);
+	if ((inl(&ftide020->ctrd1) & 0xff) != CONFIG_CTRD1_PROBE_T2) {
+		outl(bak, &ftide020->ctrd1);
+		return 0;
+	}
+
+	outl(bak, &ftide020->ctrd1);
+
+	return 1;
+}
+
+/* ide_preinit() was migrated from linux driver ide_probe_for_ftide() */
+int ide_preinit(void)
+{
+	static struct ftide020_s *ftide020 = (struct ftide020_s *) FTIDE_BASE;
+	int status;
+	unsigned int val;
+	int i;
+
+	status = 1;
+	for (i = 0; i < CONFIG_SYS_IDE_MAXBUS; i++)
+		ide_bus_offset[i] = -ATA_STATUS;
+
+	/* auto-detect IDE controller */
+	if (ftide_controller_probe()) {
+		printf("Faraday %s driver version %s\n", FTIDE_IP_NAME,
+		FTIDE_DRIVER_VERSION);
+	} else {
+		printf("Faraday ATA controller not found.\n");
+		return API_ENODEV;
+	}
+
+	/* check HW IP revision */
+	ftide_read_hwrev();
+
+	/* set FIFO threshold */
+	outl(((WRITE_FIFO - RX_THRESH) << 16) | RX_THRESH, &ftide020->dmatirr);
+
+	/* set Device_0 PIO_0 timing */
+	set_mode_timing(0, CMD_TIMING, REG_MODE0);
+	set_mode_timing(0, PIO_TIMING, PIO_MODE0);
+
+	/* set Device_1 PIO_0 timing */
+	set_mode_timing(1, CMD_TIMING, REG_MODE0);
+	set_mode_timing(1, PIO_TIMING, PIO_MODE0);
+
+	/* from E-bios */
+	/* little endian */
+	outl(0x0, &ftide020->cr);
+	mdelay(10);
+
+	outl(0x0fff0fff, &ftide020->ahbtr);
+	mdelay(10);
+
+	/* Enable controller Interrupt */
+	val = inl(&ftide020->cr);
+
+	/* Enable: IDE IRQ, IDE Terminate ERROR IRQ, AHB Timeout error IRQ */
+	val |= (CONTROL_IIE | CONTROL_TERIE | CONTROL_AERIE);
+	outl(val, &ftide020->cr);
+
+	status = 0;
+
+	return status;
+}
+
+void ide_set_reset(int flag)
+{
+	debug("ide_set_reset()\n");
+	reset_ide_controller();
+	return;
+}
diff --git a/drivers/block/ftide020.h b/drivers/block/ftide020.h
new file mode 100644
index 0000000..f3eefec
--- /dev/null
+++ b/drivers/block/ftide020.h
@@ -0,0 +1,265 @@ 
+/*
+ * Faraday FTIDE020_s ATA Controller (AHB)
+ *
+ * (C) Copyright 2011 Andes Technology
+ * Greentime Hu <greentime@andestech.com>
+ * Macpaul Lin <macpaul@andestech.com>
+ * Kuo-Wei Chou <kwchou@andestech.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#ifndef __FTIDE020_H
+#define __FTIDE020_H
+
+/* ftide020.h - ide support functions for the FTIDE020_S controller */
+
+/* ATA controller register offset */
+struct ftide020_s {
+	unsigned int	rw_fifo;	/* 0x00 - READ/WRITE FIFO	*/
+	unsigned int	cmd_fifo;	/* 0x04 - R: Status Reg, W: CMD_FIFO */
+	unsigned int	cr;		/* 0x08 - Control Reg		*/
+	unsigned int	dmatirr;	/* 0x0c - DMA Threshold/Interrupt Reg */
+	unsigned int	ctrd0;		/* 0x10 - Command Timing Reg Device 0 */
+	unsigned int	dtrd0;		/* 0x14 - Data Timing Reg Device 0 */
+	unsigned int	ctrd1;		/* 0x18 - Command Timing Reg Device 1 */
+	unsigned int	dtrd1;		/* 0x1c - Data Timing Reg Device 1 */
+	unsigned int	ahbtr;		/* 0x20 - AHB Timeout Reg	*/
+	unsigned int	RESVD0;		/* 0x24 */
+	unsigned int	RESVD1;		/* 0x28 */
+	unsigned int	RESVD2;		/* 0x2c */
+	unsigned int	f_cfifo;	/* 0x30 - Feature Info of CMD_FIFO */
+	unsigned int	f_wfifo;	/* 0x34 - Feature Info of WRITE_FIFO */
+	unsigned int	f_rfifo;	/* 0x3c - Feature Info of READ_FIFO */
+	unsigned int	revision;	/* 0x38 - Revision No. of FTIDE020_S */
+};
+
+/* reference parameters */
+#define CONFIG_IDE_REG_CS	0x2	/* ref: ATA spec chaper 10, table 42 */
+#define CONFIG_CTRD1_PROBE_T1	0x2
+#define CONFIG_CTRD1_PROBE_T2	0x5
+
+/* status register - 0x04 */
+#define STATUS_CSEL		(1 << 0)	/* CSEL			*/
+#define STATUS_CS(x)		(((x) >> 1) & 0x3)	/* CS#[1:0]	*/
+#define STATUS_DMACK		(1 << 3)	/* DMACK#		*/
+#define STATUS_DMARQ		(1 << 4)	/* DMA req		*/
+#define STATUS_INTRQ		(1 << 5)	/* INT req		*/
+#define STATUS_DIOR		(1 << 6)	/* DIOR			*/
+#define STATUS_IORDY		(1 << 7)	/* I/O ready		*/
+#define STATUS_DIOW		(1 << 8)	/* DIOW#		*/
+#define STATUS_PDIAG		(1 << 9)	/* PDIAG		*/
+#define STATUS_DASP		(1 << 10)	/* DASP#		*/
+#define STATUS_DEV		(1 << 11)	/* selected device	*/
+#define STATUS_PIO		(1 << 12)	/* PIO in progress	*/
+#define STATUS_DMA		(1 << 13)	/* DMA in progress	*/
+#define STATUS_WFE		(1 << 14)	/* write fifo full	*/
+#define STATUS_RFE		(1 << 15)	/* read fifo empty	*/
+#define STATUS_COUNTER(x)	(((x) >> 16) & 0x3fff)	/* data tx counter */
+#define STATUS_ERR		(1 << 30)	/* trasfer terminated	*/
+#define STATUS_AER		(1 << 31)	/* AHB timeout indicate	*/
+
+/* Control register - 0x08 */
+#define CONTROL_TYPE_PIO	0x0
+#define CONTROL_TYPE_UDMA	0x1
+
+/* Device 0 */
+#define CONTROL_TYP0(x)		(((x) & 0x7) << 0)
+#define CONTROL_IRE0		(1 << 3)	/* Device 0 - enable IORDY for PIO */
+#define CONTROL_RESVD_DW0	(1 << 4)	/* Reserved - DW0 ?		*/
+#define CONTROL_E0		(1 << 5)	/* Device 0 - E0: 1: Big Endian	*/
+#define CONTROL_RESVD_WP0	(1 << 6)	/* Reserved - WP0 ?		*/
+#define CONTROL_RESVD_SE0	(1 << 7)	/* Reserved - SE0 ?		*/
+#define CONTROL_RESVD_ECC0	(1 << 8)	/* Reserved - ECC0 ?		*/
+
+#define CONTROL_RAEIE		(1 << 9)	/* IRQ - read fifo almost full	*/
+#define CONTROL_RNEIE		(1 << 10)	/* IRQ - read fifo not empty	*/
+#define CONTROL_WAFIE		(1 << 11)	/* IRQ - write fifo almost empty*/
+#define CONTROL_WNFIE		(1 << 12)	/* IRQ - write fifo not full	*/
+#define CONTROL_RESVD_FIRQ	(1 << 13)	/* RESERVED - FIRQ ?		*/
+#define CONTROL_AERIE		(1 << 14)	/* IRQ - AHB timeout error	*/
+#define CONTROL_IIE		(1 << 15)	/* IDE IRQ enable		*/
+
+/* Device 1 */
+#define CONTROL_TYP1(x)		(((x) & 0x7) << 16)
+#define CONTROL_IRE1		(1 << 19)	/* Device 1 - enable IORDY for PIO */
+#define CONTROL_RESVD_DW1	(1 << 20)	/* Reserved - DW1 ?		*/
+#define CONTROL_E1		(1 << 21)	/* Device 1 - E1: 1: Big Endian	*/
+#define CONTROL_RESVD_WP1	(1 << 22)	/* Reserved - WP1 ?		*/
+#define CONTROL_RESVD_SE1	(1 << 23)	/* Reserved - SE1 ?		*/
+#define CONTROL_RESVD_ECC1	(1 << 24)	/* Reserved - ECC1 ?		*/
+
+#define CONTROL_DRE		(1 << 25)	/* DMA receive enable		*/
+#define CONTROL_DTE		(1 << 26)	/* DMA transmit enable		*/
+#define CONTRIL_RESVD		(1 << 27)
+#define CONTROL_TERIE		(1 << 28)	/* transfer terminate error IRQ	*/
+#define CONTROL_T		(1 << 29)	/* terminate current operation	*/
+#define CONTROL_SRST		(1 << 30)	/* IDE soft reset		*/
+#define CONTROL_RST		(1 << 31)	/* IDE hardware reset		*/
+
+/* IRQ register - 0x0c */
+#define IRQ_RXTHRESH(x)		(((x) & 0x3ff) << 0)	/* Read FIFO threshold		*/
+#define IRQ_RFAEIRQ		(1 << 10)	/* Read FIFO almost full intr req	*/
+#define IRQ_RFNEIRQ		(1 << 11)	/* Read FIFO not empty intr req		*/
+#define IRQ_WFAFIRQ		(1 << 12)	/* Write FIFO almost empty intr req	*/
+#define IRQ_WFNFIRQ		(1 << 13)	/* Write FIFO not full intr req		*/
+#define IRQ_RESVD_FIRQ		(1 << 14)	/* Reserved - FIRQ ?			*/
+#define IRQ_IIRQ		(1 << 15)	/* IDE device interrupt request		*/
+#define IRQ_TXTHRESH(x)		(((x) & 0x3ff) << 16)	/* Write FIFO thershold		*/
+#define IRQ_TERMERR 		(1 << 28)	/* Transfer termination indication	*/
+#define IRQ_AHBERR 		(1 << 29)	/* AHB Timeout indication		*/
+
+/* Command Timing Register 0-1: ctrd (0x10, 0x18) */
+#define CT_REG_T1(x)		(((x) & 0xff) << 0)	/* the setup time of addressed	*/
+#define CT_REG_T2(x)		(((x) & 0xff) << 8)	/* the pluse width of DIOR/DIOW	*/
+#define CT_REG_T4(x)		(((x) & 0xff) << 16)	/* data hold time		*/
+#define CT_REG_TEOC(x)		(((x) & 0xff) << 24)	/* the time to the end of a cycle */
+
+/* Data Timing Register 0-1: dtrd (0x14, 0x1c) */
+#define DT_REG_PIO_T1(x)	(((x) & 0xff) << 0)	/* the setup time of addressed	*/
+#define DT_REG_PIO_T2(x)	(((x) & 0xff) << 8)	/* the pluse width of DIOR/DIOW	*/
+#define DT_REG_PIO_T4(x)	(((x) & 0xff) << 16)	/* data hold time		*/
+#define DT_REG_PIO_TEOC(x)	(((x) & 0xff) << 24)	/* the time to the end of a cycle */
+
+#define DT_REG_UDMA_TENV(x)	(((x) & 0xf) << 0)	/* the envelope time		*/
+#define DT_REG_UDMA_TMLI(x)	(((x) & 0xf) << 4)	/* interlock time		*/
+#define DT_REG_UDMA_TCYC(x)	(((x) & 0xff) << 8)	/* cycle time - data time	*/
+#define DT_REG_UDMA_TACK(x)	(((x) & 0xf) << 16)	/* the setup and hold time of DMACK */
+#define DT_REG_UDMA_TCVS(x)	(((x) & 0xf) << 20)	/* the setup tim eof CRC	*/
+#define DT_REG_UDMA_TRP(x)	(((x) & 0xff) << 24)	/* the time to ready to pause	*/
+
+/* ftide020_s command formats */
+/* read: IDE Register (CF1) */
+#define IDE_REG_OPCODE_READ	(1 << 13)		/* 0x2000 */
+#define IDE_REG_CS_READ(x)	(((x) & 0x3) << 11)
+#define IDE_REG_DA_READ(x)	(((x) & 0x7) << 8)
+#define IDE_REG_CMD_READ(x)	0x0			/* fixed value */
+
+/* write: IDE Register (CF2) */
+#define IDE_REG_OPCODE_WRITE	(0x5 << 13)		/* 0xA000 */
+#define IDE_REG_CS_WRITE(x)	(((x) & 0x3) << 11)
+#define IDE_REG_DA_WRITE(x)	(((x) & 0x7) << 8)
+#define IDE_REG_CMD_WRITE(x)	(((x) & 0xff) << 0)i	/* Actual ATA command or data */
+
+/* read/write data: PIO/UDMA (CF3) */
+#define IDE_DATA_WRITE		(1 << 15)		/* read: 0, write: 1 */
+#define IDE_DATA_OPCODE		(0x2 << 13)		/* device data access opcode */
+#define IDE_DATA_COUNTER(x)	(((x) & 0x1fff) << 0)	/* Number of transfers minus 1 */
+
+/* set device: (CF4) */
+#define IDE_SET_OPCODE		(0x2740 << 2) 		/* [15:2], 0x9d00 */
+/* CF3 counter value: 0: Tx in bytes, 1: in blocks (each block is 8 bytes) */
+#define IDE_SET_CX8(x)		(((x) & 0x1) << 1)
+#define IDE_SET_DEV(x)		(((x) & 0x1) << 0)	/* 0: Master, 1: Slave */
+
+/*
+ * IDE command bit definition
+ * This section is designed for minor hardware revision compatibility.
+ */
+#define READ_REG_CMD		IDE_REG_OPCODE_READ			/* 0x2000 */
+#define WRITE_REG_CMD		IDE_REG_OPCODE_WRITE			/* 0xA000 */
+#define READ_DATA_CMD		IDE_DATA_OPCODE				/* 0x4000 */
+#define WRITE_DATA_CMD		(IDE_DATA_OPCODE | IDE_DATA_WRITE)	/* 0xC000 */
+#define SET_DEV_CMD		IDE_SET_OPCODE				/* 0x9D00 */
+
+#define TATOL_TIMING		3
+#define CMD_TIMING		0
+#define PIO_TIMING		1
+#define DMA_TIMING		2
+
+/* Timing Parameters */
+/* Register Access Timing Parameters */
+#define REG_PARAMETER		4
+#define REG_T0			0
+#define REG_T1			1
+#define REG_T2			2
+#define REG_T4			3
+
+#define REG_MODE		5
+#define REG_MODE0		0
+#define REG_MODE1		1
+#define REG_MODE2		2
+#define REG_MODE3		3
+#define REG_MODE4		4
+
+/* PIO Access Timing Parameters */
+#define PIO_PARAMETER		4
+#define PIO_T0			0
+#define PIO_T1			1
+#define PIO_T2			2
+#define PIO_T4			3
+
+#define PIO_MODE		5
+#define PIO_MODE0		0
+#define PIO_MODE1		1
+#define PIO_MODE2		2
+#define PIO_MODE3		3
+#define PIO_MODE4		4
+
+/* UDMA Access Timing Parameters */
+#define UDMA_PARAMETER		6
+#define UDMA_TCYC		0
+#define UDMA_TCVS		1
+#define UDMA_TMLI		2
+#define UDMA_TENV		3
+#define UDMA_TRP		4
+#define UDMA_TACK		5
+
+#define UDMA_MODE 		7
+#define UDMA_MODE0		0
+#define UDMA_MODE1		1
+#define UDMA_MODE2		2
+#define UDMA_MODE3		3
+#define UDMA_MODE4		4
+#define UDMA_MODE5		5
+#define UDMA_MODE6		6
+
+/*
+ * RX_THRESH:
+ * hardware limitation: max = 8, should support 1,4,8,16,32,64,128,256
+ */
+#define RX_THRESH		8
+#define WRITE_FIFO		32	/* Hardwired value */
+
+/* Time Table */
+unsigned int REG_ACCESS_TIMING[REG_PARAMETER][REG_MODE] = {
+	{600,	383,	330,	180,	120},
+	{70,	50,	30,	30,	25},
+	{290,	290,	290,	80,	70},
+	{30,	20,	15,	10,	10},
+};
+
+unsigned int PIO_ACCESS_TIMING[PIO_PARAMETER][PIO_MODE] = {
+	{600,	383,	240,	180,	120},
+	{70,	50,	30,	30,	25},
+	{165,	125,	100,	80,	70},
+	{30,	20,	15,	10,	10},
+};
+
+unsigned int UDMA_ACCESS_TIMING[UDMA_PARAMETER][UDMA_MODE] = {
+	{1120,	730,	540,	390,	250,	168,	130}, /* 10X */
+	{700,	480,	310,	200,	67,	100,	100}, /* 10X */
+	{200,	200,	200,	200,	200,	200,	200}, /* 10X */
+	{200,	200,	200,	200,	200,	200,	200}, /* 10X */
+	{1600,	1250,	1000,	1000,	1000,	850,	850}, /* 10X */
+	{200,	200,	200,	200,	200,	200,	200}, /* 10X */
+};
+
+#endif /* __FTIDE020_H */