From patchwork Mon Jan 24 12:47:47 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Macpaul Lin X-Patchwork-Id: 80151 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 34C5E1007D1 for ; Mon, 24 Jan 2011 23:47:26 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 9B6D5280A4; Mon, 24 Jan 2011 13:47:24 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id hRMs+3bO9sHo; Mon, 24 Jan 2011 13:47:24 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 984B1280A8; Mon, 24 Jan 2011 13:47:19 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 0A3C628087 for ; Mon, 24 Jan 2011 13:47:16 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Aq3zl2bY2waw for ; Mon, 24 Jan 2011 13:47:10 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from ATCPCS06.andestech.com (59-124-160-117.HINET-IP.hinet.net [59.124.160.117]) by theia.denx.de (Postfix) with ESMTP id CDFC92808B for ; Mon, 24 Jan 2011 13:47:08 +0100 (CET) Received: from app01.andestech.com ([10.0.4.31]) by ATCPCS06.andestech.com with Microsoft SMTPSVC(6.0.3790.4675); Mon, 24 Jan 2011 20:47:52 +0800 From: Macpaul Lin To: u-boot@lists.denx.de, ratbert@faraday-tech.com, wd@denx.de Date: Mon, 24 Jan 2011 20:47:47 +0800 Message-Id: <1295873267-32570-2-git-send-email-macpaul@andestech.com> X-Mailer: git-send-email 1.7.3.5 In-Reply-To: <1295873267-32570-1-git-send-email-macpaul@andestech.com> References: <1295873267-32570-1-git-send-email-macpaul@andestech.com> X-OriginalArrivalTime: 24 Jan 2011 12:47:52.0774 (UTC) FILETIME=[EA386660:01CBBBC4] Cc: Macpaul Lin Subject: [U-Boot] [PATCH 2/2] ftide020: add faraday ide ahb controller from Linux kernel X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.9 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de 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 --- 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 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 + * Macpaul Lin + * Kuo-Wei Chou + * + * 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 +#include +#include +#include +#include +#include + +#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 + * Macpaul Lin + * Kuo-Wei Chou + * + * 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 */