From: Macpaul Lin Date: Sun, 1 May 2011 21:28:56 +0000 (+0000) Subject: ftide020: add faraday ide ahb controller X-Git-Tag: v2011.06-rc1~36 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=4bed7265f2ce2e986ab11f0c9382a5ac2899d630;p=oweals%2Fu-boot.git ftide020: add faraday ide ahb controller Faraday's ftide020_s is an IDE-AHB controller for SoC design. This patch add the u-boot driver (PIO) of ftide020 ATA (IDE) driver. 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 --- diff --git a/drivers/block/Makefile b/drivers/block/Makefile index aa7dc877cd..2efe981dc9 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 0000000000..2eef3e939a --- /dev/null +++ b/drivers/block/ftide020.c @@ -0,0 +1,367 @@ +/* + * 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" + +/* 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 0; + + 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 1; + } else + return 0; + 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 1; + } else + return 0; + 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 1; + } else + return 0; + default: + return 0; + } +} + +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_4 timing */ + set_mode_timing(0, CMD_TIMING, REG_MODE4); + set_mode_timing(0, PIO_TIMING, PIO_MODE4); + + /* set Device_1 PIO_4 timing */ + set_mode_timing(1, CMD_TIMING, REG_MODE4); + set_mode_timing(1, PIO_TIMING, PIO_MODE4); + + /* 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 0000000000..29d3de9662 --- /dev/null +++ b/drivers/block/ftide020.h @@ -0,0 +1,283 @@ +/* + * 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) /* enable IORDY for PIO */ +#define CONTROL_RESVD_DW0 (1 << 4) /* Reserved - DW0 ? */ +#define CONTROL_E0 (1 << 5) /* 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) /* enable IORDY for PIO */ +#define CONTROL_RESVD_DW1 (1 << 20) /* Reserved - DW1 ? */ +#define CONTROL_E1 (1 << 21) /* 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 int 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) /* setup time of addressed */ +#define CT_REG_T2(x) (((x) & 0xff) << 8) /* pluse width of DIOR/DIOW */ +#define CT_REG_T4(x) (((x) & 0xff) << 16) /* data hold time */ +#define CT_REG_TEOC(x) (((x) & 0xff) << 24) /* time to the end of a cycle */ + +/* Data Timing Register 0-1: dtrd (0x14, 0x1c) */ +/* + * PIO mode: + * b(0:7) DT_REG_PIO_T1: the setup time of addressed + * b(8:15) DT_REG_PIO_T2: the pluse width of DIOR/DIOW + * b(16:23) DT_REG_PIO_T4: data hold time + * b(24:31) DT_REG_PIO_TEOC: the time to the end of a cycle + */ +#define DT_REG_PIO_T1(x) (((x) & 0xff) << 0) +#define DT_REG_PIO_T2(x) (((x) & 0xff) << 8) +#define DT_REG_PIO_T4(x) (((x) & 0xff) << 16) +#define DT_REG_PIO_TEOC(x) (((x) & 0xff) << 24) + +/* + * UDMA mode: + * b(0:3) DT_REG_UDMA_TENV: the envelope time + * b(4:7) DT_REG_UDMA_TMLI: interlock time + * b(8:15) DT_REG_UDMA_TCYC: cycle time - data time + * b(16:19) DT_REG_UDMA_TACK: setup and hold time of DMACK + * b(23:30) DT_REG_UDMA_TCVS: setup time of CRC + * b(24:31) DT_REG_UDMA_TRP: time to ready to pause + */ +#define DT_REG_UDMA_TENV(x) (((x) & 0xf) << 0) +#define DT_REG_UDMA_TMLI(x) (((x) & 0xf) << 4) +#define DT_REG_UDMA_TCYC(x) (((x) & 0xff) << 8) +#define DT_REG_UDMA_TACK(x) (((x) & 0xf) << 16) +#define DT_REG_UDMA_TCVS(x) (((x) & 0xf) << 20) +#define DT_REG_UDMA_TRP(x) (((x) & 0xff) << 24) + +/* 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) +/* b(0:7) IDE_REG_CMD_WRITE(x): Actual ATA command or data */ +#define IDE_REG_CMD_WRITE(x) (((x) & 0xff) << 0) + +/* 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 */ +/* b(0:12) IDE_DATA_COUNTER(x): Number of transfers minus 1 */ +#define IDE_DATA_COUNTER(x) (((x) & 0x1fff) << 0) + +/* 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 */