]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
Blackfin: add driver for on-chip ATAPI controller
authorSonic Zhang <Sonic.Zhang@analog.com>
Thu, 27 Nov 2008 03:16:45 +0000 (22:16 -0500)
committerMike Frysinger <vapier@gentoo.org>
Mon, 2 Feb 2009 17:27:14 +0000 (12:27 -0500)
This is a port of the Linux Blackfin on-chip ATAPI driver to U-Boot.

Signed-off-by: Sonic Zhang <Sonic.Zhang@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
drivers/block/Makefile
drivers/block/pata_bfin.c [new file with mode: 0644]
drivers/block/pata_bfin.h [new file with mode: 0644]
include/asm-blackfin/mach-common/bits/pata.h [new file with mode: 0644]

index 642582b08819dd6629a6290b5f248d11d032eeba..59388d9d452fc8e393c1f5c70c4162bed1be4b9a 100644 (file)
@@ -29,6 +29,7 @@ COBJS-$(CONFIG_SCSI_AHCI) += ahci.o
 COBJS-$(CONFIG_ATA_PIIX) += ata_piix.o
 COBJS-$(CONFIG_FSL_SATA) += fsl_sata.o
 COBJS-$(CONFIG_LIBATA) += libata.o
+COBJS-$(CONFIG_PATA_BFIN) += pata_bfin.o
 COBJS-$(CONFIG_SATA_SIL3114) += sata_sil3114.o
 COBJS-$(CONFIG_IDE_SIL680) += sil680.o
 COBJS-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o
diff --git a/drivers/block/pata_bfin.c b/drivers/block/pata_bfin.c
new file mode 100644 (file)
index 0000000..f16dabe
--- /dev/null
@@ -0,0 +1,1201 @@
+/*
+ * Driver for Blackfin on-chip ATAPI controller.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (c) 2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/mach-common/bits/pata.h>
+#include <ata.h>
+#include <libata.h>
+#include "pata_bfin.h"
+
+static struct ata_port port[CONFIG_SYS_SATA_MAX_DEVICE];
+
+/**
+ * PIO Mode - Frequency compatibility
+ */
+/* mode: 0         1         2         3         4 */
+static const u32 pio_fsclk[] =
+{ 33333333, 33333333, 33333333, 33333333, 33333333 };
+
+/**
+ * MDMA Mode - Frequency compatibility
+ */
+/*               mode:      0         1         2        */
+static const u32 mdma_fsclk[] = { 33333333, 33333333, 33333333 };
+
+/**
+ * UDMA Mode - Frequency compatibility
+ *
+ * UDMA5 - 100 MB/s   - SCLK  = 133 MHz
+ * UDMA4 - 66 MB/s    - SCLK >=  80 MHz
+ * UDMA3 - 44.4 MB/s  - SCLK >=  50 MHz
+ * UDMA2 - 33 MB/s    - SCLK >=  40 MHz
+ */
+/* mode: 0         1         2         3         4          5 */
+static const u32 udma_fsclk[] =
+{ 33333333, 33333333, 40000000, 50000000, 80000000, 133333333 };
+
+/**
+ * Register transfer timing table
+ */
+/*               mode:       0    1    2    3    4    */
+/* Cycle Time                     */
+static const u32 reg_t0min[]   = { 600, 383, 330, 180, 120 };
+/* DIOR/DIOW to end cycle         */
+static const u32 reg_t2min[]   = { 290, 290, 290, 70,  25  };
+/* DIOR/DIOW asserted pulse width */
+static const u32 reg_teocmin[] = { 290, 290, 290, 80,  70  };
+
+/**
+ * PIO timing table
+ */
+/*               mode:       0    1    2    3    4    */
+/* Cycle Time                     */
+static const u32 pio_t0min[]   = { 600, 383, 240, 180, 120 };
+/* Address valid to DIOR/DIORW    */
+static const u32 pio_t1min[]   = { 70,  50,  30,  30,  25  };
+/* DIOR/DIOW to end cycle         */
+static const u32 pio_t2min[]   = { 165, 125, 100, 80,  70  };
+/* DIOR/DIOW asserted pulse width */
+static const u32 pio_teocmin[] = { 165, 125, 100, 70,  25  };
+/* DIOW data hold                 */
+static const u32 pio_t4min[]   = { 30,  20,  15,  10,  10  };
+
+/* ******************************************************************
+ * Multiword DMA timing table
+ * ******************************************************************
+ */
+/*               mode:       0   1    2        */
+/* Cycle Time                     */
+static const u32 mdma_t0min[]  = { 480, 150, 120 };
+/* DIOR/DIOW asserted pulse width */
+static const u32 mdma_tdmin[]  = { 215, 80,  70  };
+/* DMACK to read data released    */
+static const u32 mdma_thmin[]  = { 20,  15,  10  };
+/* DIOR/DIOW to DMACK hold        */
+static const u32 mdma_tjmin[]  = { 20,  5,   5   };
+/* DIOR negated pulse width       */
+static const u32 mdma_tkrmin[] = { 50,  50,  25  };
+/* DIOR negated pulse width       */
+static const u32 mdma_tkwmin[] = { 215, 50,  25  };
+/* CS[1:0] valid to DIOR/DIOW     */
+static const u32 mdma_tmmin[]  = { 50,  30,  25  };
+/* DMACK to read data released    */
+static const u32 mdma_tzmax[]  = { 20,  25,  25  };
+
+/**
+ * Ultra DMA timing table
+ */
+/*               mode:         0    1    2    3    4    5       */
+static const u32 udma_tcycmin[]  = { 112, 73,  54,  39,  25,  17 };
+static const u32 udma_tdvsmin[]  = { 70,  48,  31,  20,  7,   5  };
+static const u32 udma_tenvmax[]  = { 70,  70,  70,  55,  55,  50 };
+static const u32 udma_trpmin[]   = { 160, 125, 100, 100, 100, 85 };
+static const u32 udma_tmin[]     = { 5,   5,   5,   5,   3,   3  };
+
+
+static const u32 udma_tmlimin = 20;
+static const u32 udma_tzahmin = 20;
+static const u32 udma_tenvmin = 20;
+static const u32 udma_tackmin = 20;
+static const u32 udma_tssmin = 50;
+
+static void msleep(int count)
+{
+       int i;
+
+       for (i = 0; i < count; i++)
+               udelay(1000);
+}
+
+/**
+ *
+ *     Function:       num_clocks_min
+ *
+ *     Description:
+ *     calculate number of SCLK cycles to meet minimum timing
+ */
+static unsigned short num_clocks_min(unsigned long tmin,
+                               unsigned long fsclk)
+{
+       unsigned long tmp ;
+       unsigned short result;
+
+       tmp = tmin * (fsclk/1000/1000) / 1000;
+       result = (unsigned short)tmp;
+       if ((tmp*1000*1000) < (tmin*(fsclk/1000)))
+               result++;
+
+       return result;
+}
+
+/**
+ *     bfin_set_piomode - Initialize host controller PATA PIO timings
+ *     @ap: Port whose timings we are configuring
+ *     @pio_mode: mode
+ *
+ *     Set PIO mode for device.
+ *
+ *     LOCKING:
+ *     None (inherited from caller).
+ */
+
+static void bfin_set_piomode(struct ata_port *ap, int pio_mode)
+{
+       int mode = pio_mode - XFER_PIO_0;
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       unsigned int fsclk = get_sclk();
+       unsigned short teoc_reg, t2_reg, teoc_pio;
+       unsigned short t4_reg, t2_pio, t1_reg;
+       unsigned short n0, n6, t6min = 5;
+
+       /* the most restrictive timing value is t6 and tc, the DIOW - data hold
+       * If one SCLK pulse is longer than this minimum value then register
+       * transfers cannot be supported at this frequency.
+       */
+       n6 = num_clocks_min(t6min, fsclk);
+       if (mode >= 0 && mode <= 4 && n6 >= 1) {
+               debug("set piomode: mode=%d, fsclk=%ud\n", mode, fsclk);
+               /* calculate the timing values for register transfers. */
+               while (mode > 0 && pio_fsclk[mode] > fsclk)
+                       mode--;
+
+               /* DIOR/DIOW to end cycle time */
+               t2_reg = num_clocks_min(reg_t2min[mode], fsclk);
+               /* DIOR/DIOW asserted pulse width */
+               teoc_reg = num_clocks_min(reg_teocmin[mode], fsclk);
+               /* Cycle Time */
+               n0  = num_clocks_min(reg_t0min[mode], fsclk);
+
+               /* increase t2 until we meed the minimum cycle length */
+               if (t2_reg + teoc_reg < n0)
+                       t2_reg = n0 - teoc_reg;
+
+               /* calculate the timing values for pio transfers. */
+
+               /* DIOR/DIOW to end cycle time */
+               t2_pio = num_clocks_min(pio_t2min[mode], fsclk);
+               /* DIOR/DIOW asserted pulse width */
+               teoc_pio = num_clocks_min(pio_teocmin[mode], fsclk);
+               /* Cycle Time */
+               n0  = num_clocks_min(pio_t0min[mode], fsclk);
+
+               /* increase t2 until we meed the minimum cycle length */
+               if (t2_pio + teoc_pio < n0)
+                       t2_pio = n0 - teoc_pio;
+
+               /* Address valid to DIOR/DIORW */
+               t1_reg = num_clocks_min(pio_t1min[mode], fsclk);
+
+               /* DIOW data hold */
+               t4_reg = num_clocks_min(pio_t4min[mode], fsclk);
+
+               ATAPI_SET_REG_TIM_0(base, (teoc_reg<<8 | t2_reg));
+               ATAPI_SET_PIO_TIM_0(base, (t4_reg<<12 | t2_pio<<4 | t1_reg));
+               ATAPI_SET_PIO_TIM_1(base, teoc_pio);
+               if (mode > 2) {
+                       ATAPI_SET_CONTROL(base,
+                               ATAPI_GET_CONTROL(base) | IORDY_EN);
+               } else {
+                       ATAPI_SET_CONTROL(base,
+                               ATAPI_GET_CONTROL(base) & ~IORDY_EN);
+               }
+
+               /* Disable host ATAPI PIO interrupts */
+               ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base)
+                       & ~(PIO_DONE_MASK | HOST_TERM_XFER_MASK));
+               SSYNC();
+       }
+}
+
+/**
+ *
+ *    Function:       wait_complete
+ *
+ *    Description:    Waits the interrupt from device
+ *
+ */
+static inline void wait_complete(void __iomem *base, unsigned short mask)
+{
+       unsigned short status;
+       unsigned int i = 0;
+
+       for (i = 0; i < PATA_BFIN_WAIT_TIMEOUT; i++) {
+               status = ATAPI_GET_INT_STATUS(base) & mask;
+               if (status)
+                       break;
+       }
+
+       ATAPI_SET_INT_STATUS(base, mask);
+}
+
+/**
+ *
+ *    Function:       write_atapi_register
+ *
+ *    Description:    Writes to ATA Device Resgister
+ *
+ */
+
+static void write_atapi_register(void __iomem *base,
+               unsigned long ata_reg, unsigned short value)
+{
+       /* Program the ATA_DEV_TXBUF register with write data (to be
+        * written into the device).
+        */
+       ATAPI_SET_DEV_TXBUF(base, value);
+
+       /* Program the ATA_DEV_ADDR register with address of the
+        * device register (0x01 to 0x0F).
+        */
+       ATAPI_SET_DEV_ADDR(base, ata_reg);
+
+       /* Program the ATA_CTRL register with dir set to write (1)
+        */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR));
+
+       /* ensure PIO DMA is not set */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+       /* and start the transfer */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+       /* Wait for the interrupt to indicate the end of the transfer.
+        * (We need to wait on and clear rhe ATA_DEV_INT interrupt status)
+        */
+       wait_complete(base, PIO_DONE_INT);
+}
+
+/**
+ *
+ *     Function:       read_atapi_register
+ *
+ *Description:    Reads from ATA Device Resgister
+ *
+ */
+
+static unsigned short read_atapi_register(void __iomem *base,
+               unsigned long ata_reg)
+{
+       /* Program the ATA_DEV_ADDR register with address of the
+        * device register (0x01 to 0x0F).
+        */
+       ATAPI_SET_DEV_ADDR(base, ata_reg);
+
+       /* Program the ATA_CTRL register with dir set to read (0) and
+        */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR));
+
+       /* ensure PIO DMA is not set */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+       /* and start the transfer */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+       /* Wait for the interrupt to indicate the end of the transfer.
+        * (PIO_DONE interrupt is set and it doesn't seem to matter
+        * that we don't clear it)
+        */
+       wait_complete(base, PIO_DONE_INT);
+
+       /* Read the ATA_DEV_RXBUF register with write data (to be
+        * written into the device).
+        */
+       return ATAPI_GET_DEV_RXBUF(base);
+}
+
+/**
+ *
+ *    Function:       write_atapi_register_data
+ *
+ *    Description:    Writes to ATA Device Resgister
+ *
+ */
+
+static void write_atapi_data(void __iomem *base,
+               int len, unsigned short *buf)
+{
+       int i;
+
+       /* Set transfer length to 1 */
+       ATAPI_SET_XFER_LEN(base, 1);
+
+       /* Program the ATA_DEV_ADDR register with address of the
+        * ATA_REG_DATA
+        */
+       ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA);
+
+       /* Program the ATA_CTRL register with dir set to write (1)
+        */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR));
+
+       /* ensure PIO DMA is not set */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+       for (i = 0; i < len; i++) {
+               /* Program the ATA_DEV_TXBUF register with write data (to be
+                * written into the device).
+                */
+               ATAPI_SET_DEV_TXBUF(base, buf[i]);
+
+               /* and start the transfer */
+               ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+               /* Wait for the interrupt to indicate the end of the transfer.
+                * (We need to wait on and clear rhe ATA_DEV_INT
+                * interrupt status)
+                */
+               wait_complete(base, PIO_DONE_INT);
+       }
+}
+
+/**
+ *
+ *     Function:       read_atapi_register_data
+ *
+ *     Description:    Reads from ATA Device Resgister
+ *
+ */
+
+static void read_atapi_data(void __iomem *base,
+               int len, unsigned short *buf)
+{
+       int i;
+
+       /* Set transfer length to 1 */
+       ATAPI_SET_XFER_LEN(base, 1);
+
+       /* Program the ATA_DEV_ADDR register with address of the
+        * ATA_REG_DATA
+        */
+       ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA);
+
+       /* Program the ATA_CTRL register with dir set to read (0) and
+        */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR));
+
+       /* ensure PIO DMA is not set */
+       ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+       for (i = 0; i < len; i++) {
+               /* and start the transfer */
+               ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+               /* Wait for the interrupt to indicate the end of the transfer.
+                * (PIO_DONE interrupt is set and it doesn't seem to matter
+                * that we don't clear it)
+                */
+               wait_complete(base, PIO_DONE_INT);
+
+               /* Read the ATA_DEV_RXBUF register with write data (to be
+                * written into the device).
+                */
+               buf[i] = ATAPI_GET_DEV_RXBUF(base);
+       }
+}
+
+/**
+ *     bfin_check_status - Read device status reg & clear interrupt
+ *     @ap: port where the device is
+ *
+ *     Note: Original code is ata_check_status().
+ */
+
+static u8 bfin_check_status(struct ata_port *ap)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       return read_atapi_register(base, ATA_REG_STATUS);
+}
+
+/**
+ *     bfin_check_altstatus - Read device alternate status reg
+ *     @ap: port where the device is
+ */
+
+static u8 bfin_check_altstatus(struct ata_port *ap)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       return read_atapi_register(base, ATA_REG_ALTSTATUS);
+}
+
+/**
+ *      bfin_ata_busy_wait - Wait for a port status register
+ *      @ap: Port to wait for.
+ *      @bits: bits that must be clear
+ *      @max: number of 10uS waits to perform
+ *
+ *      Waits up to max*10 microseconds for the selected bits in the port's
+ *      status register to be cleared.
+ *      Returns final value of status register.
+ *
+ *      LOCKING:
+ *      Inherited from caller.
+ */
+static inline u8 bfin_ata_busy_wait(struct ata_port *ap, unsigned int bits,
+                               unsigned int max, u8 usealtstatus)
+{
+       u8 status;
+
+       do {
+               udelay(10);
+               if (usealtstatus)
+                       status = bfin_check_altstatus(ap);
+               else
+                       status = bfin_check_status(ap);
+               max--;
+       } while (status != 0xff && (status & bits) && (max > 0));
+
+       return status;
+}
+
+/**
+ *     bfin_ata_busy_sleep - sleep until BSY clears, or timeout
+ *     @ap: port containing status register to be polled
+ *     @tmout_pat: impatience timeout in msecs
+ *     @tmout: overall timeout in msecs
+ *
+ *     Sleep until ATA Status register bit BSY clears,
+ *     or a timeout occurs.
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+static int bfin_ata_busy_sleep(struct ata_port *ap,
+                      long tmout_pat, unsigned long tmout)
+{
+       u8 status;
+
+       status = bfin_ata_busy_wait(ap, ATA_BUSY, 300, 0);
+       while (status != 0xff && (status & ATA_BUSY) && tmout_pat > 0) {
+               msleep(50);
+               tmout_pat -= 50;
+               status = bfin_ata_busy_wait(ap, ATA_BUSY, 3, 0);
+       }
+
+       if (status != 0xff && (status & ATA_BUSY))
+               printf("port is slow to respond, please be patient "
+                               "(Status 0x%x)\n", status);
+
+       while (status != 0xff && (status & ATA_BUSY) && tmout_pat > 0) {
+               msleep(50);
+               tmout_pat -= 50;
+               status = bfin_check_status(ap);
+       }
+
+       if (status == 0xff)
+               return -ENODEV;
+
+       if (status & ATA_BUSY) {
+               printf("port failed to respond "
+                               "(%lu secs, Status 0x%x)\n",
+                               DIV_ROUND_UP(tmout, 1000), status);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+/**
+ *     bfin_dev_select - Select device 0/1 on ATA bus
+ *     @ap: ATA channel to manipulate
+ *     @device: ATA device (numbered from zero) to select
+ *
+ *     Note: Original code is ata_sff_dev_select().
+ */
+
+static void bfin_dev_select(struct ata_port *ap, unsigned int device)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       u8 tmp;
+
+
+       if (device == 0)
+               tmp = ATA_DEVICE_OBS;
+       else
+               tmp = ATA_DEVICE_OBS | ATA_DEV1;
+
+       write_atapi_register(base, ATA_REG_DEVICE, tmp);
+       udelay(1);
+}
+
+/**
+ *     bfin_devchk - PATA device presence detection
+ *     @ap: ATA channel to examine
+ *     @device: Device to examine (starting at zero)
+ *
+ *     Note: Original code is ata_devchk().
+ */
+
+static unsigned int bfin_devchk(struct ata_port *ap,
+                               unsigned int device)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       u8 nsect, lbal;
+
+       bfin_dev_select(ap, device);
+
+       write_atapi_register(base, ATA_REG_NSECT, 0x55);
+       write_atapi_register(base, ATA_REG_LBAL, 0xaa);
+
+       write_atapi_register(base, ATA_REG_NSECT, 0xaa);
+       write_atapi_register(base, ATA_REG_LBAL, 0x55);
+
+       write_atapi_register(base, ATA_REG_NSECT, 0x55);
+       write_atapi_register(base, ATA_REG_LBAL, 0xaa);
+
+       nsect = read_atapi_register(base, ATA_REG_NSECT);
+       lbal = read_atapi_register(base, ATA_REG_LBAL);
+
+       if ((nsect == 0x55) && (lbal == 0xaa))
+               return 1;       /* we found a device */
+
+       return 0;               /* nothing found */
+}
+
+/**
+ *     bfin_bus_post_reset - PATA device post reset
+ *
+ *     Note: Original code is ata_bus_post_reset().
+ */
+
+static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       unsigned int dev0 = devmask & (1 << 0);
+       unsigned int dev1 = devmask & (1 << 1);
+       long deadline;
+
+       /* if device 0 was found in ata_devchk, wait for its
+        * BSY bit to clear
+        */
+       if (dev0)
+               bfin_ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+       /* if device 1 was found in ata_devchk, wait for
+        * register access, then wait for BSY to clear
+        */
+       deadline = ATA_TMOUT_BOOT;
+       while (dev1) {
+               u8 nsect, lbal;
+
+               bfin_dev_select(ap, 1);
+               nsect = read_atapi_register(base, ATA_REG_NSECT);
+               lbal = read_atapi_register(base, ATA_REG_LBAL);
+               if ((nsect == 1) && (lbal == 1))
+                       break;
+               if (deadline <= 0) {
+                       dev1 = 0;
+                       break;
+               }
+               msleep(50);     /* give drive a breather */
+               deadline -= 50;
+       }
+       if (dev1)
+               bfin_ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+       /* is all this really necessary? */
+       bfin_dev_select(ap, 0);
+       if (dev1)
+               bfin_dev_select(ap, 1);
+       if (dev0)
+               bfin_dev_select(ap, 0);
+}
+
+/**
+ *     bfin_bus_softreset - PATA device software reset
+ *
+ *     Note: Original code is ata_bus_softreset().
+ */
+
+static unsigned int bfin_bus_softreset(struct ata_port *ap,
+                                      unsigned int devmask)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+       /* software reset.  causes dev0 to be selected */
+       write_atapi_register(base, ATA_REG_CTRL, ap->ctl_reg);
+       udelay(20);
+       write_atapi_register(base, ATA_REG_CTRL, ap->ctl_reg | ATA_SRST);
+       udelay(20);
+       write_atapi_register(base, ATA_REG_CTRL, ap->ctl_reg);
+
+       /* spec mandates ">= 2ms" before checking status.
+        * We wait 150ms, because that was the magic delay used for
+        * ATAPI devices in Hale Landis's ATADRVR, for the period of time
+        * between when the ATA command register is written, and then
+        * status is checked.  Because waiting for "a while" before
+        * checking status is fine, post SRST, we perform this magic
+        * delay here as well.
+        *
+        * Old drivers/ide uses the 2mS rule and then waits for ready
+        */
+       msleep(150);
+
+       /* Before we perform post reset processing we want to see if
+        * the bus shows 0xFF because the odd clown forgets the D7
+        * pulldown resistor.
+        */
+       if (bfin_check_status(ap) == 0xFF)
+               return 0;
+
+       bfin_bus_post_reset(ap, devmask);
+
+       return 0;
+}
+
+/**
+ *     bfin_softreset - reset host port via ATA SRST
+ *     @ap: port to reset
+ *
+ *     Note: Original code is ata_sff_softreset().
+ */
+
+static int bfin_softreset(struct ata_port *ap)
+{
+       unsigned int err_mask;
+
+       ap->dev_mask = 0;
+
+       /* determine if device 0/1 are present.
+        * only one device is supported on one port by now.
+       */
+       if (bfin_devchk(ap, 0))
+               ap->dev_mask |= (1 << 0);
+       else if (bfin_devchk(ap, 1))
+               ap->dev_mask |= (1 << 1);
+       else
+               return -ENODEV;
+
+       /* select device 0 again */
+       bfin_dev_select(ap, 0);
+
+       /* issue bus reset */
+       err_mask = bfin_bus_softreset(ap, ap->dev_mask);
+       if (err_mask) {
+               printf("SRST failed (err_mask=0x%x)\n",
+                               err_mask);
+               ap->dev_mask = 0;
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/**
+ *     bfin_irq_clear - Clear ATAPI interrupt.
+ *     @ap: Port associated with this ATA transaction.
+ *
+ *     Note: Original code is ata_sff_irq_clear().
+ */
+
+static void bfin_irq_clear(struct ata_port *ap)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+       ATAPI_SET_INT_STATUS(base, ATAPI_GET_INT_STATUS(base)|ATAPI_DEV_INT
+               | MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT
+               | MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT);
+}
+
+static u8 bfin_wait_for_irq(struct ata_port *ap, unsigned int max)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+       do {
+               if (ATAPI_GET_INT_STATUS(base) & (ATAPI_DEV_INT
+               | MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT
+               | MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT)) {
+                       break;
+               }
+               udelay(1000);
+               max--;
+       } while ((max > 0));
+
+       return max == 0;
+}
+
+/**
+ *     bfin_ata_reset_port - initialize BFIN ATAPI port.
+ */
+
+static int bfin_ata_reset_port(struct ata_port *ap)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       int count;
+       unsigned short status;
+
+       /* Disable all ATAPI interrupts */
+       ATAPI_SET_INT_MASK(base, 0);
+       SSYNC();
+
+       /* Assert the RESET signal 25us*/
+       ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | DEV_RST);
+       udelay(30);
+
+       /* Negate the RESET signal for 2ms*/
+       ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) & ~DEV_RST);
+       msleep(2);
+
+       /* Wait on Busy flag to clear */
+       count = 10000000;
+       do {
+               status = read_atapi_register(base, ATA_REG_STATUS);
+       } while (--count && (status & ATA_BUSY));
+
+       /* Enable only ATAPI Device interrupt */
+       ATAPI_SET_INT_MASK(base, 1);
+       SSYNC();
+
+       return !count;
+}
+
+/**
+ *
+ *     Function:       bfin_config_atapi_gpio
+ *
+ *     Description:    Configures the ATAPI pins for use
+ *
+ */
+static int bfin_config_atapi_gpio(struct ata_port *ap)
+{
+       bfin_write_PORTH_FER(bfin_read_PORTH_FER() | 0x4);
+       bfin_write_PORTH_MUX(bfin_read_PORTH_MUX() & ~0x30);
+       bfin_write_PORTH_DIR_SET(0x4);
+
+       bfin_write_PORTJ_FER(0x7f8);
+       bfin_write_PORTJ_MUX(bfin_read_PORTI_MUX() & ~0x3fffc0);
+       bfin_write_PORTJ_DIR_SET(0x5f8);
+       bfin_write_PORTJ_DIR_CLEAR(0x200);
+       bfin_write_PORTJ_INEN(0x200);
+
+       bfin_write_PINT2_ASSIGN(0x0707);
+       bfin_write_PINT2_MASK_SET(0x200);
+       SSYNC();
+
+       return 0;
+}
+
+/**
+ *     bfin_atapi_probe        -       attach a bfin atapi interface
+ *     @pdev: platform device
+ *
+ *     Register a bfin atapi interface.
+ *
+ *
+ *     Platform devices are expected to contain 2 resources per port:
+ *
+ *             - I/O Base (IORESOURCE_IO)
+ *             - IRQ      (IORESOURCE_IRQ)
+ *
+ */
+static int bfin_ata_probe_port(struct ata_port *ap)
+{
+       if (bfin_config_atapi_gpio(ap)) {
+               printf("Requesting Peripherals faild\n");
+               return -EFAULT;
+       }
+
+       if (bfin_ata_reset_port(ap)) {
+               printf("Fail to reset ATAPI device\n");
+               return -EFAULT;
+       }
+
+       if (ap->ata_mode >= XFER_PIO_0 && ap->ata_mode <= XFER_PIO_4)
+               bfin_set_piomode(ap, ap->ata_mode);
+       else {
+               printf("Given ATA data transfer mode is not supported.\n");
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+#define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2)
+
+static void bfin_ata_identify(struct ata_port *ap, int dev)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       u8 status = 0;
+       static u16 iobuf[ATA_SECTOR_WORDS];
+       u64 n_sectors = 0;
+       hd_driveid_t *iop = (hd_driveid_t *)iobuf;
+
+       memset(iobuf, 0, sizeof(iobuf));
+
+       if (!(ap->dev_mask & (1 << dev)))
+               return;
+
+       debug("port=%d dev=%d\n", ap->port_no, dev);
+
+       bfin_dev_select(ap, dev);
+
+       status = 0;
+       /* Device Identify Command */
+       write_atapi_register(base, ATA_REG_CMD, ATA_CMD_ID_ATA);
+       bfin_check_altstatus(ap);
+       udelay(10);
+
+       status = bfin_ata_busy_wait(ap, ATA_BUSY, 1000, 0);
+       if (status & ATA_ERR) {
+               printf("\ndevice not responding\n");
+               ap->dev_mask &= ~(1 << dev);
+               return;
+       }
+
+       read_atapi_data(base, ATA_SECTOR_WORDS, iobuf);
+
+       ata_swap_buf_le16(iobuf, ATA_SECTOR_WORDS);
+
+       /* we require LBA and DMA support (bits 8 & 9 of word 49) */
+       if (!ata_id_has_dma(iobuf) || !ata_id_has_lba(iobuf))
+               printf("ata%u: no dma/lba\n", ap->port_no);
+
+#ifdef DEBUG
+       ata_dump_id(iobuf);
+#endif
+
+       n_sectors = ata_id_n_sectors(iobuf);
+
+       if (n_sectors == 0) {
+               ap->dev_mask &= ~(1 << dev);
+               return;
+       }
+
+       ata_id_c_string(iobuf, (unsigned char *)sata_dev_desc[ap->port_no].revision,
+                        ATA_ID_FW_REV, sizeof(sata_dev_desc[ap->port_no].revision));
+       ata_id_c_string(iobuf, (unsigned char *)sata_dev_desc[ap->port_no].vendor,
+                        ATA_ID_PROD, sizeof(sata_dev_desc[ap->port_no].vendor));
+       ata_id_c_string(iobuf, (unsigned char *)sata_dev_desc[ap->port_no].product,
+                        ATA_ID_SERNO, sizeof(sata_dev_desc[ap->port_no].product));
+
+       if ((iop->config & 0x0080) == 0x0080)
+               sata_dev_desc[ap->port_no].removable = 1;
+       else
+               sata_dev_desc[ap->port_no].removable = 0;
+
+       sata_dev_desc[ap->port_no].lba = (u32) n_sectors;
+       debug("lba=0x%x\n", sata_dev_desc[ap->port_no].lba);
+
+#ifdef CONFIG_LBA48
+       if (iop->command_set_2 & 0x0400)
+               sata_dev_desc[ap->port_no].lba48 = 1;
+       else
+               sata_dev_desc[ap->port_no].lba48 = 0;
+#endif
+
+       /* assuming HD */
+       sata_dev_desc[ap->port_no].type = DEV_TYPE_HARDDISK;
+       sata_dev_desc[ap->port_no].blksz = ATA_SECT_SIZE;
+       sata_dev_desc[ap->port_no].lun = 0;     /* just to fill something in... */
+
+       printf("PATA device#%d %s is found on ata port#%d.\n",
+               ap->port_no%PATA_DEV_NUM_PER_PORT,
+               sata_dev_desc[ap->port_no].vendor,
+               ap->port_no/PATA_DEV_NUM_PER_PORT);
+}
+
+static void bfin_ata_set_Feature_cmd(struct ata_port *ap, int dev)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       u8 status = 0;
+
+       if (!(ap->dev_mask & (1 << dev)))
+               return;
+
+       bfin_dev_select(ap, dev);
+
+       write_atapi_register(base, ATA_REG_FEATURE, SETFEATURES_XFER);
+       write_atapi_register(base, ATA_REG_NSECT, ap->ata_mode);
+       write_atapi_register(base, ATA_REG_LBAL, 0);
+       write_atapi_register(base, ATA_REG_LBAM, 0);
+       write_atapi_register(base, ATA_REG_LBAH, 0);
+
+       write_atapi_register(base, ATA_REG_DEVICE, ATA_DEVICE_OBS);
+       write_atapi_register(base, ATA_REG_CMD, ATA_CMD_SET_FEATURES);
+
+       udelay(50);
+       msleep(150);
+
+       status = bfin_ata_busy_wait(ap, ATA_BUSY, 5000, 0);
+       if ((status & (ATA_BUSY | ATA_ERR))) {
+               printf("Error  : status 0x%02x\n", status);
+               ap->dev_mask &= ~(1 << dev);
+       }
+}
+
+int scan_sata(int dev)
+{
+       /* dev is the index of each ata device in the system. one PATA port
+        * contains 2 devices. one element in scan_done array indicates one
+        * PATA port. device connected to one PATA port is selected by
+        * bfin_dev_select() before access.
+        */
+       struct ata_port *ap = &port[dev];
+       static int scan_done[(CONFIG_SYS_SATA_MAX_DEVICE+1)/PATA_DEV_NUM_PER_PORT];
+
+       if (scan_done[dev/PATA_DEV_NUM_PER_PORT])
+               return 0;
+
+       /* Check for attached device */
+       if (!bfin_ata_probe_port(ap)) {
+               if (bfin_softreset(ap)) {
+                       /* soft reset failed, try a hard one */
+                       bfin_ata_reset_port(ap);
+                       if (bfin_softreset(ap))
+                               scan_done[dev/PATA_DEV_NUM_PER_PORT] = 1;
+               } else {
+                       scan_done[dev/PATA_DEV_NUM_PER_PORT] = 1;
+               }
+       }
+       if (scan_done[dev/PATA_DEV_NUM_PER_PORT]) {
+               /* Probe device and set xfer mode */
+               bfin_ata_identify(ap, dev%PATA_DEV_NUM_PER_PORT);
+               bfin_ata_set_Feature_cmd(ap, dev%PATA_DEV_NUM_PER_PORT);
+               init_part(&sata_dev_desc[dev]);
+               return 0;
+       }
+
+       printf("PATA device#%d is not present on ATA port#%d.\n",
+               ap->port_no%PATA_DEV_NUM_PER_PORT,
+               ap->port_no/PATA_DEV_NUM_PER_PORT);
+
+       return -1;
+}
+
+int init_sata(int dev)
+{
+       struct ata_port *ap = &port[dev];
+       static u8 init_done;
+       int res = 1;
+
+       if (init_done)
+               return res;
+
+       init_done = 1;
+
+       switch (dev/PATA_DEV_NUM_PER_PORT) {
+       case 0:
+               ap->ioaddr.ctl_addr = ATAPI_CONTROL;
+               ap->ata_mode = CONFIG_BFIN_ATA_MODE;
+               break;
+       default:
+               printf("Tried to scan unknown port %d.\n", dev);
+               return res;
+       }
+
+       if (ap->ata_mode < XFER_PIO_0 || ap->ata_mode > XFER_PIO_4) {
+               ap->ata_mode = XFER_PIO_4;
+               printf("DMA mode is not supported. Set to PIO mode 4.\n");
+       }
+
+       ap->port_no = dev;
+       ap->ctl_reg = 0x8;      /*Default value of control reg */
+
+       res = 0;
+       return res;
+}
+
+/* Read up to 255 sectors
+ *
+ * Returns sectors read
+*/
+static u8 do_one_read(struct ata_port *ap, u64 blknr, u8 blkcnt, u16 *buffer,
+                       uchar lba48)
+{
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       u8 sr = 0;
+       u8 status;
+       u16 err = 0;
+
+       if (!(bfin_check_status(ap) & ATA_DRDY)) {
+               printf("Device ata%d not ready\n", ap->port_no);
+               return 0;
+       }
+
+       /* Set up transfer */
+#ifdef CONFIG_LBA48
+       if (lba48) {
+               /* write high bits */
+               write_atapi_register(base, ATA_REG_NSECT, 0);
+               write_atapi_register(base, ATA_REG_LBAL, (blknr >> 24) & 0xFF);
+               write_atapi_register(base, ATA_REG_LBAM, (blknr >> 32) & 0xFF);
+               write_atapi_register(base, ATA_REG_LBAH, (blknr >> 40) & 0xFF);
+       }
+#endif
+       write_atapi_register(base, ATA_REG_NSECT, blkcnt);
+       write_atapi_register(base, ATA_REG_LBAL, (blknr >> 0) & 0xFF);
+       write_atapi_register(base, ATA_REG_LBAM, (blknr >> 8) & 0xFF);
+       write_atapi_register(base, ATA_REG_LBAH, (blknr >> 16) & 0xFF);
+
+#ifdef CONFIG_LBA48
+       if (lba48) {
+               write_atapi_register(base, ATA_REG_DEVICE, ATA_LBA);
+               write_atapi_register(base, ATA_REG_CMD, ATA_CMD_PIO_READ_EXT);
+       } else
+#endif
+       {
+               write_atapi_register(base, ATA_REG_DEVICE, ATA_LBA | ((blknr >> 24) & 0xF));
+               write_atapi_register(base, ATA_REG_CMD, ATA_CMD_PIO_READ);
+       }
+       status = bfin_ata_busy_wait(ap, ATA_BUSY, 500000, 1);
+
+       if (status & (ATA_BUSY | ATA_ERR)) {
+               printf("Device %d not responding status 0x%x.\n", ap->port_no, status);
+               err = read_atapi_register(base, ATA_REG_ERR);
+               printf("Error reg = 0x%x\n", err);
+               return sr;
+       }
+
+       while (blkcnt--) {
+               if (bfin_wait_for_irq(ap, 500)) {
+                       printf("ata%u irq failed\n", ap->port_no);
+                       return sr;
+               }
+
+               status = bfin_check_status(ap);
+               if (status & ATA_ERR) {
+                       err = read_atapi_register(base, ATA_REG_ERR);
+                       printf("ata%u error %d\n", ap->port_no, err);
+                       return sr;
+               }
+               bfin_irq_clear(ap);
+
+               /* Read one sector */
+               read_atapi_data(base, ATA_SECTOR_WORDS, buffer);
+               buffer += ATA_SECTOR_WORDS;
+               sr++;
+       }
+
+       return sr;
+}
+
+ulong sata_read(int dev, ulong block, ulong blkcnt, void *buff)
+{
+       struct ata_port *ap = &port[dev];
+       ulong n = 0, sread;
+       u16 *buffer = (u16 *) buff;
+       u8 status = 0;
+       u64 blknr = (u64) block;
+       unsigned char lba48 = 0;
+
+#ifdef CONFIG_LBA48
+       if (blknr > 0xfffffff) {
+               if (!sata_dev_desc[dev].lba48) {
+                       printf("Drive doesn't support 48-bit addressing\n");
+                       return 0;
+               }
+               /* more than 28 bits used, use 48bit mode */
+               lba48 = 1;
+       }
+#endif
+       bfin_dev_select(ap, dev%PATA_DEV_NUM_PER_PORT);
+
+       while (blkcnt > 0) {
+
+               if (blkcnt > 255)
+                       sread = 255;
+               else
+                       sread = blkcnt;
+
+               status = do_one_read(ap, blknr, sread, buffer, lba48);
+               if (status != sread) {
+                       printf("Read failed\n");
+                       return n;
+               }
+
+               blkcnt -= sread;
+               blknr += sread;
+               n += sread;
+               buffer += sread * ATA_SECTOR_WORDS;
+       }
+       return n;
+}
+
+ulong sata_write(int dev, ulong block, ulong blkcnt, const void *buff)
+{
+       struct ata_port *ap = &port[dev];
+       void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+       ulong n = 0;
+       u16 *buffer = (u16 *) buff;
+       unsigned char status = 0;
+       u64 blknr = (u64) block;
+#ifdef CONFIG_LBA48
+       unsigned char lba48 = 0;
+
+       if (blknr > 0xfffffff) {
+               if (!sata_dev_desc[dev].lba48) {
+                       printf("Drive doesn't support 48-bit addressing\n");
+                       return 0;
+               }
+               /* more than 28 bits used, use 48bit mode */
+               lba48 = 1;
+       }
+#endif
+
+       bfin_dev_select(ap, dev%PATA_DEV_NUM_PER_PORT);
+
+       while (blkcnt-- > 0) {
+               status = bfin_ata_busy_wait(ap, ATA_BUSY, 50000, 0);
+               if (status & ATA_BUSY) {
+                       printf("ata%u failed to respond\n", ap->port_no);
+                       return n;
+               }
+#ifdef CONFIG_LBA48
+               if (lba48) {
+                       /* write high bits */
+                       write_atapi_register(base, ATA_REG_NSECT, 0);
+                       write_atapi_register(base, ATA_REG_LBAL,
+                               (blknr >> 24) & 0xFF);
+                       write_atapi_register(base, ATA_REG_LBAM,
+                               (blknr >> 32) & 0xFF);
+                       write_atapi_register(base, ATA_REG_LBAH,
+                               (blknr >> 40) & 0xFF);
+               }
+#endif
+               write_atapi_register(base, ATA_REG_NSECT, 1);
+               write_atapi_register(base, ATA_REG_LBAL, (blknr >> 0) & 0xFF);
+               write_atapi_register(base, ATA_REG_LBAM, (blknr >> 8) & 0xFF);
+               write_atapi_register(base, ATA_REG_LBAH, (blknr >> 16) & 0xFF);
+#ifdef CONFIG_LBA48
+               if (lba48) {
+                       write_atapi_register(base, ATA_REG_DEVICE, ATA_LBA);
+                       write_atapi_register(base, ATA_REG_CMD,
+                               ATA_CMD_PIO_WRITE_EXT);
+               } else
+#endif
+               {
+                       write_atapi_register(base, ATA_REG_DEVICE,
+                               ATA_LBA | ((blknr >> 24) & 0xF));
+                       write_atapi_register(base, ATA_REG_CMD,
+                               ATA_CMD_PIO_WRITE);
+               }
+
+               /*may take up to 5 sec */
+               status = bfin_ata_busy_wait(ap, ATA_BUSY, 50000, 0);
+               if ((status & (ATA_DRQ | ATA_BUSY | ATA_ERR)) != ATA_DRQ) {
+                       printf("Error no DRQ dev %d blk %ld: sts 0x%02x\n",
+                               ap->port_no, (ulong) blknr, status);
+                       return n;
+               }
+
+               write_atapi_data(base, ATA_SECTOR_WORDS, buffer);
+               bfin_check_altstatus(ap);
+               udelay(1);
+
+               ++n;
+               ++blknr;
+               buffer += ATA_SECTOR_WORDS;
+       }
+       return n;
+}
diff --git a/drivers/block/pata_bfin.h b/drivers/block/pata_bfin.h
new file mode 100644 (file)
index 0000000..2b3425b
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Driver for Blackfin on-chip ATAPI controller.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (c) 2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef PATA_BFIN_H
+#define PATA_BFIN_H
+
+#include <asm/blackfin_local.h>
+
+struct ata_ioports {
+       unsigned long cmd_addr;
+       unsigned long data_addr;
+       unsigned long error_addr;
+       unsigned long feature_addr;
+       unsigned long nsect_addr;
+       unsigned long lbal_addr;
+       unsigned long lbam_addr;
+       unsigned long lbah_addr;
+       unsigned long device_addr;
+       unsigned long status_addr;
+       unsigned long command_addr;
+       unsigned long altstatus_addr;
+       unsigned long ctl_addr;
+       unsigned long bmdma_addr;
+       unsigned long scr_addr;
+};
+
+struct ata_port {
+       unsigned int port_no;           /* primary=0, secondary=1       */
+       struct ata_ioports ioaddr;      /* ATA cmd/ctl/dma reg blks     */
+       unsigned long flag;
+       unsigned int ata_mode;
+       unsigned char ctl_reg;
+       unsigned char last_ctl;
+       unsigned char dev_mask;
+};
+
+extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE];
+
+#define DRV_NAME               "pata-bfin"
+#define DRV_VERSION            "0.9"
+#define __iomem
+
+#define ATA_REG_CTRL           0x0E
+#define ATA_REG_ALTSTATUS      ATA_REG_CTRL
+#define ATA_TMOUT_BOOT         30000
+#define ATA_TMOUT_BOOT_QUICK   7000
+
+#define PATA_BFIN_WAIT_TIMEOUT         10000
+#define PATA_DEV_NUM_PER_PORT  2
+
+/* These are the offset of the controller's registers */
+#define ATAPI_OFFSET_CONTROL           0x00
+#define ATAPI_OFFSET_STATUS            0x04
+#define ATAPI_OFFSET_DEV_ADDR          0x08
+#define ATAPI_OFFSET_DEV_TXBUF         0x0c
+#define ATAPI_OFFSET_DEV_RXBUF         0x10
+#define ATAPI_OFFSET_INT_MASK          0x14
+#define ATAPI_OFFSET_INT_STATUS                0x18
+#define ATAPI_OFFSET_XFER_LEN          0x1c
+#define ATAPI_OFFSET_LINE_STATUS       0x20
+#define ATAPI_OFFSET_SM_STATE          0x24
+#define ATAPI_OFFSET_TERMINATE         0x28
+#define ATAPI_OFFSET_PIO_TFRCNT                0x2c
+#define ATAPI_OFFSET_DMA_TFRCNT                0x30
+#define ATAPI_OFFSET_UMAIN_TFRCNT      0x34
+#define ATAPI_OFFSET_UDMAOUT_TFRCNT    0x38
+#define ATAPI_OFFSET_REG_TIM_0         0x40
+#define ATAPI_OFFSET_PIO_TIM_0         0x44
+#define ATAPI_OFFSET_PIO_TIM_1         0x48
+#define ATAPI_OFFSET_MULTI_TIM_0       0x50
+#define ATAPI_OFFSET_MULTI_TIM_1       0x54
+#define ATAPI_OFFSET_MULTI_TIM_2       0x58
+#define ATAPI_OFFSET_ULTRA_TIM_0       0x60
+#define ATAPI_OFFSET_ULTRA_TIM_1       0x64
+#define ATAPI_OFFSET_ULTRA_TIM_2       0x68
+#define ATAPI_OFFSET_ULTRA_TIM_3       0x6c
+
+
+#define ATAPI_GET_CONTROL(base)\
+       bfin_read16(base + ATAPI_OFFSET_CONTROL)
+#define ATAPI_SET_CONTROL(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_CONTROL, val)
+#define ATAPI_GET_STATUS(base)\
+       bfin_read16(base + ATAPI_OFFSET_STATUS)
+#define ATAPI_GET_DEV_ADDR(base)\
+       bfin_read16(base + ATAPI_OFFSET_DEV_ADDR)
+#define ATAPI_SET_DEV_ADDR(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_DEV_ADDR, val)
+#define ATAPI_GET_DEV_TXBUF(base)\
+       bfin_read16(base + ATAPI_OFFSET_DEV_TXBUF)
+#define ATAPI_SET_DEV_TXBUF(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_DEV_TXBUF, val)
+#define ATAPI_GET_DEV_RXBUF(base)\
+       bfin_read16(base + ATAPI_OFFSET_DEV_RXBUF)
+#define ATAPI_SET_DEV_RXBUF(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_DEV_RXBUF, val)
+#define ATAPI_GET_INT_MASK(base)\
+       bfin_read16(base + ATAPI_OFFSET_INT_MASK)
+#define ATAPI_SET_INT_MASK(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_INT_MASK, val)
+#define ATAPI_GET_INT_STATUS(base)\
+       bfin_read16(base + ATAPI_OFFSET_INT_STATUS)
+#define ATAPI_SET_INT_STATUS(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_INT_STATUS, val)
+#define ATAPI_GET_XFER_LEN(base)\
+       bfin_read16(base + ATAPI_OFFSET_XFER_LEN)
+#define ATAPI_SET_XFER_LEN(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_XFER_LEN, val)
+#define ATAPI_GET_LINE_STATUS(base)\
+       bfin_read16(base + ATAPI_OFFSET_LINE_STATUS)
+#define ATAPI_GET_SM_STATE(base)\
+       bfin_read16(base + ATAPI_OFFSET_SM_STATE)
+#define ATAPI_GET_TERMINATE(base)\
+       bfin_read16(base + ATAPI_OFFSET_TERMINATE)
+#define ATAPI_SET_TERMINATE(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_TERMINATE, val)
+#define ATAPI_GET_PIO_TFRCNT(base)\
+       bfin_read16(base + ATAPI_OFFSET_PIO_TFRCNT)
+#define ATAPI_GET_DMA_TFRCNT(base)\
+       bfin_read16(base + ATAPI_OFFSET_DMA_TFRCNT)
+#define ATAPI_GET_UMAIN_TFRCNT(base)\
+       bfin_read16(base + ATAPI_OFFSET_UMAIN_TFRCNT)
+#define ATAPI_GET_UDMAOUT_TFRCNT(base)\
+       bfin_read16(base + ATAPI_OFFSET_UDMAOUT_TFRCNT)
+#define ATAPI_GET_REG_TIM_0(base)\
+       bfin_read16(base + ATAPI_OFFSET_REG_TIM_0)
+#define ATAPI_SET_REG_TIM_0(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_REG_TIM_0, val)
+#define ATAPI_GET_PIO_TIM_0(base)\
+       bfin_read16(base + ATAPI_OFFSET_PIO_TIM_0)
+#define ATAPI_SET_PIO_TIM_0(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_PIO_TIM_0, val)
+#define ATAPI_GET_PIO_TIM_1(base)\
+       bfin_read16(base + ATAPI_OFFSET_PIO_TIM_1)
+#define ATAPI_SET_PIO_TIM_1(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_PIO_TIM_1, val)
+#define ATAPI_GET_MULTI_TIM_0(base)\
+       bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_0)
+#define ATAPI_SET_MULTI_TIM_0(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_0, val)
+#define ATAPI_GET_MULTI_TIM_1(base)\
+       bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_1)
+#define ATAPI_SET_MULTI_TIM_1(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_1, val)
+#define ATAPI_GET_MULTI_TIM_2(base)\
+       bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_2)
+#define ATAPI_SET_MULTI_TIM_2(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_2, val)
+#define ATAPI_GET_ULTRA_TIM_0(base)\
+       bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_0)
+#define ATAPI_SET_ULTRA_TIM_0(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_0, val)
+#define ATAPI_GET_ULTRA_TIM_1(base)\
+       bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_1)
+#define ATAPI_SET_ULTRA_TIM_1(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_1, val)
+#define ATAPI_GET_ULTRA_TIM_2(base)\
+       bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_2)
+#define ATAPI_SET_ULTRA_TIM_2(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_2, val)
+#define ATAPI_GET_ULTRA_TIM_3(base)\
+       bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_3)
+#define ATAPI_SET_ULTRA_TIM_3(base, val)\
+       bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_3, val)
+
+#endif
diff --git a/include/asm-blackfin/mach-common/bits/pata.h b/include/asm-blackfin/mach-common/bits/pata.h
new file mode 100644 (file)
index 0000000..9b61824
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * ATAPI Masks
+ */
+
+#ifndef __BFIN_PERIPHERAL_PATA__
+#define __BFIN_PERIPHERAL_PATA__
+
+/* Bit masks for ATAPI_CONTROL */
+#define                 PIO_START  0x1        /* Start PIO/Reg Op */
+#define               MULTI_START  0x2        /* Start Multi-DMA Op */
+#define               ULTRA_START  0x4        /* Start Ultra-DMA Op */
+#define                  XFER_DIR  0x8        /* Transfer Direction */
+#define                  IORDY_EN  0x10       /* IORDY Enable */
+#define                FIFO_FLUSH  0x20       /* Flush FIFOs */
+#define                  SOFT_RST  0x40       /* Soft Reset */
+#define                   DEV_RST  0x80       /* Device Reset */
+#define                TFRCNT_RST  0x100      /* Trans Count Reset */
+#define               END_ON_TERM  0x200      /* End/Terminate Select */
+#define               PIO_USE_DMA  0x400      /* PIO-DMA Enable */
+#define          UDMAIN_FIFO_THRS  0xf000     /* Ultra DMA-IN FIFO Threshold */
+
+/* Bit masks for ATAPI_STATUS */
+#define               PIO_XFER_ON  0x1        /* PIO transfer in progress */
+#define             MULTI_XFER_ON  0x2        /* Multi-word DMA transfer in progress */
+#define             ULTRA_XFER_ON  0x4        /* Ultra DMA transfer in progress */
+#define               ULTRA_IN_FL  0xf0       /* Ultra DMA Input FIFO Level */
+
+/* Bit masks for ATAPI_DEV_ADDR */
+#define                  DEV_ADDR  0x1f       /* Device Address */
+
+/* Bit masks for ATAPI_INT_MASK */
+#define        ATAPI_DEV_INT_MASK  0x1        /* Device interrupt mask */
+#define             PIO_DONE_MASK  0x2        /* PIO transfer done interrupt mask */
+#define           MULTI_DONE_MASK  0x4        /* Multi-DMA transfer done interrupt mask */
+#define          UDMAIN_DONE_MASK  0x8        /* Ultra-DMA in transfer done interrupt mask */
+#define         UDMAOUT_DONE_MASK  0x10       /* Ultra-DMA out transfer done interrupt mask */
+#define       HOST_TERM_XFER_MASK  0x20       /* Host terminate current transfer interrupt mask */
+#define           MULTI_TERM_MASK  0x40       /* Device terminate Multi-DMA transfer interrupt mask */
+#define          UDMAIN_TERM_MASK  0x80       /* Device terminate Ultra-DMA-in transfer interrupt mask */
+#define         UDMAOUT_TERM_MASK  0x100      /* Device terminate Ultra-DMA-out transfer interrupt mask */
+
+/* Bit masks for ATAPI_INT_STATUS */
+#define             ATAPI_DEV_INT  0x1        /* Device interrupt status */
+#define              PIO_DONE_INT  0x2        /* PIO transfer done interrupt status */
+#define            MULTI_DONE_INT  0x4        /* Multi-DMA transfer done interrupt status */
+#define           UDMAIN_DONE_INT  0x8        /* Ultra-DMA in transfer done interrupt status */
+#define          UDMAOUT_DONE_INT  0x10       /* Ultra-DMA out transfer done interrupt status */
+#define        HOST_TERM_XFER_INT  0x20       /* Host terminate current transfer interrupt status */
+#define            MULTI_TERM_INT  0x40       /* Device terminate Multi-DMA transfer interrupt status */
+#define           UDMAIN_TERM_INT  0x80       /* Device terminate Ultra-DMA-in transfer interrupt status */
+#define          UDMAOUT_TERM_INT  0x100      /* Device terminate Ultra-DMA-out transfer interrupt status */
+
+/* Bit masks for ATAPI_LINE_STATUS */
+#define                ATAPI_INTR  0x1        /* Device interrupt to host line status */
+#define                ATAPI_DASP  0x2        /* Device dasp to host line status */
+#define                ATAPI_CS0N  0x4        /* ATAPI chip select 0 line status */
+#define                ATAPI_CS1N  0x8        /* ATAPI chip select 1 line status */
+#define                ATAPI_ADDR  0x70       /* ATAPI address line status */
+#define              ATAPI_DMAREQ  0x80       /* ATAPI DMA request line status */
+#define             ATAPI_DMAACKN  0x100      /* ATAPI DMA acknowledge line status */
+#define               ATAPI_DIOWN  0x200      /* ATAPI write line status */
+#define               ATAPI_DIORN  0x400      /* ATAPI read line status */
+#define               ATAPI_IORDY  0x800      /* ATAPI IORDY line status */
+
+/* Bit masks for ATAPI_SM_STATE */
+#define                PIO_CSTATE  0xf        /* PIO mode state machine current state */
+#define                DMA_CSTATE  0xf0       /* DMA mode state machine current state */
+#define             UDMAIN_CSTATE  0xf00      /* Ultra DMA-In mode state machine current state */
+#define            UDMAOUT_CSTATE  0xf000     /* ATAPI IORDY line status */
+
+/* Bit masks for ATAPI_TERMINATE */
+#define           ATAPI_HOST_TERM  0x1        /* Host terminationation */
+
+/* Bit masks for ATAPI_REG_TIM_0 */
+#define                    T2_REG  0xff       /* End of cycle time for register access transfers */
+#define                  TEOC_REG  0xff00     /* Selects DIOR/DIOW pulsewidth */
+
+/* Bit masks for ATAPI_PIO_TIM_0 */
+#define                    T1_REG  0xf        /* Time from address valid to DIOR/DIOW */
+#define                T2_REG_PIO  0xff0      /* DIOR/DIOW pulsewidth */
+#define                    T4_REG  0xf000     /* DIOW data hold */
+
+/* Bit masks for ATAPI_PIO_TIM_1 */
+#define              TEOC_REG_PIO  0xff       /* End of cycle time for PIO access transfers. */
+
+/* Bit masks for ATAPI_MULTI_TIM_0 */
+#define                        TD  0xff       /* DIOR/DIOW asserted pulsewidth */
+#define                        TM  0xff00     /* Time from address valid to DIOR/DIOW */
+
+/* Bit masks for ATAPI_MULTI_TIM_1 */
+#define                       TKW  0xff       /* Selects DIOW negated pulsewidth */
+#define                       TKR  0xff00     /* Selects DIOR negated pulsewidth */
+
+/* Bit masks for ATAPI_MULTI_TIM_2 */
+#define                        TH  0xff       /* Selects DIOW data hold */
+#define                      TEOC  0xff00     /* Selects end of cycle for DMA */
+
+/* Bit masks for ATAPI_ULTRA_TIM_0 */
+#define                      TACK  0xff       /* Selects setup and hold times for TACK */
+#define                      TENV  0xff00     /* Selects envelope time */
+
+/* Bit masks for ATAPI_ULTRA_TIM_1 */
+#define                      TDVS  0xff       /* Selects data valid setup time */
+#define                 TCYC_TDVS  0xff00     /* Selects cycle time - TDVS time */
+
+/* Bit masks for ATAPI_ULTRA_TIM_2 */
+#define                       TSS  0xff       /* Selects time from STROBE edge to negation of DMARQ or assertion of STOP */
+#define                      TMLI  0xff00     /* Selects interlock time */
+
+/* Bit masks for ATAPI_ULTRA_TIM_3 */
+#define                      TZAH  0xff       /* Selects minimum delay required for output */
+#define               READY_PAUSE  0xff00     /* Selects ready to pause */
+
+/* Bit masks for ATAPI_CONTROL */
+#define                 PIO_START  0x1        /* Start PIO/Reg Op */
+#define               MULTI_START  0x2        /* Start Multi-DMA Op */
+#define               ULTRA_START  0x4        /* Start Ultra-DMA Op */
+#define                  XFER_DIR  0x8        /* Transfer Direction */
+#define                  IORDY_EN  0x10       /* IORDY Enable */
+#define                FIFO_FLUSH  0x20       /* Flush FIFOs */
+#define                  SOFT_RST  0x40       /* Soft Reset */
+#define                   DEV_RST  0x80       /* Device Reset */
+#define                TFRCNT_RST  0x100      /* Trans Count Reset */
+#define               END_ON_TERM  0x200      /* End/Terminate Select */
+#define               PIO_USE_DMA  0x400      /* PIO-DMA Enable */
+#define          UDMAIN_FIFO_THRS  0xf000     /* Ultra DMA-IN FIFO Threshold */
+
+/* Bit masks for ATAPI_STATUS */
+#define               PIO_XFER_ON  0x1        /* PIO transfer in progress */
+#define             MULTI_XFER_ON  0x2        /* Multi-word DMA transfer in progress */
+#define             ULTRA_XFER_ON  0x4        /* Ultra DMA transfer in progress */
+#define               ULTRA_IN_FL  0xf0       /* Ultra DMA Input FIFO Level */
+
+/* Bit masks for ATAPI_DEV_ADDR */
+#define                  DEV_ADDR  0x1f       /* Device Address */
+
+/* Bit masks for ATAPI_INT_MASK */
+#define        ATAPI_DEV_INT_MASK  0x1        /* Device interrupt mask */
+#define             PIO_DONE_MASK  0x2        /* PIO transfer done interrupt mask */
+#define           MULTI_DONE_MASK  0x4        /* Multi-DMA transfer done interrupt mask */
+#define          UDMAIN_DONE_MASK  0x8        /* Ultra-DMA in transfer done interrupt mask */
+#define         UDMAOUT_DONE_MASK  0x10       /* Ultra-DMA out transfer done interrupt mask */
+#define       HOST_TERM_XFER_MASK  0x20       /* Host terminate current transfer interrupt mask */
+#define           MULTI_TERM_MASK  0x40       /* Device terminate Multi-DMA transfer interrupt mask */
+#define          UDMAIN_TERM_MASK  0x80       /* Device terminate Ultra-DMA-in transfer interrupt mask */
+#define         UDMAOUT_TERM_MASK  0x100      /* Device terminate Ultra-DMA-out transfer interrupt mask */
+
+/* Bit masks for ATAPI_INT_STATUS */
+#define             ATAPI_DEV_INT  0x1        /* Device interrupt status */
+#define              PIO_DONE_INT  0x2        /* PIO transfer done interrupt status */
+#define            MULTI_DONE_INT  0x4        /* Multi-DMA transfer done interrupt status */
+#define           UDMAIN_DONE_INT  0x8        /* Ultra-DMA in transfer done interrupt status */
+#define          UDMAOUT_DONE_INT  0x10       /* Ultra-DMA out transfer done interrupt status */
+#define        HOST_TERM_XFER_INT  0x20       /* Host terminate current transfer interrupt status */
+#define            MULTI_TERM_INT  0x40       /* Device terminate Multi-DMA transfer interrupt status */
+#define           UDMAIN_TERM_INT  0x80       /* Device terminate Ultra-DMA-in transfer interrupt status */
+#define          UDMAOUT_TERM_INT  0x100      /* Device terminate Ultra-DMA-out transfer interrupt status */
+
+/* Bit masks for ATAPI_LINE_STATUS */
+#define                ATAPI_INTR  0x1        /* Device interrupt to host line status */
+#define                ATAPI_DASP  0x2        /* Device dasp to host line status */
+#define                ATAPI_CS0N  0x4        /* ATAPI chip select 0 line status */
+#define                ATAPI_CS1N  0x8        /* ATAPI chip select 1 line status */
+#define                ATAPI_ADDR  0x70       /* ATAPI address line status */
+#define              ATAPI_DMAREQ  0x80       /* ATAPI DMA request line status */
+#define             ATAPI_DMAACKN  0x100      /* ATAPI DMA acknowledge line status */
+#define               ATAPI_DIOWN  0x200      /* ATAPI write line status */
+#define               ATAPI_DIORN  0x400      /* ATAPI read line status */
+#define               ATAPI_IORDY  0x800      /* ATAPI IORDY line status */
+
+/* Bit masks for ATAPI_SM_STATE */
+#define                PIO_CSTATE  0xf        /* PIO mode state machine current state */
+#define                DMA_CSTATE  0xf0       /* DMA mode state machine current state */
+#define             UDMAIN_CSTATE  0xf00      /* Ultra DMA-In mode state machine current state */
+#define            UDMAOUT_CSTATE  0xf000     /* ATAPI IORDY line status */
+
+/* Bit masks for ATAPI_TERMINATE */
+#define           ATAPI_HOST_TERM  0x1        /* Host terminationation */
+
+/* Bit masks for ATAPI_REG_TIM_0 */
+#define                    T2_REG  0xff       /* End of cycle time for register access transfers */
+#define                  TEOC_REG  0xff00     /* Selects DIOR/DIOW pulsewidth */
+
+/* Bit masks for ATAPI_PIO_TIM_0 */
+#define                    T1_REG  0xf        /* Time from address valid to DIOR/DIOW */
+#define                T2_REG_PIO  0xff0      /* DIOR/DIOW pulsewidth */
+#define                    T4_REG  0xf000     /* DIOW data hold */
+
+/* Bit masks for ATAPI_PIO_TIM_1 */
+#define              TEOC_REG_PIO  0xff       /* End of cycle time for PIO access transfers. */
+
+/* Bit masks for ATAPI_MULTI_TIM_0 */
+#define                        TD  0xff       /* DIOR/DIOW asserted pulsewidth */
+#define                        TM  0xff00     /* Time from address valid to DIOR/DIOW */
+
+/* Bit masks for ATAPI_MULTI_TIM_1 */
+#define                       TKW  0xff       /* Selects DIOW negated pulsewidth */
+#define                       TKR  0xff00     /* Selects DIOR negated pulsewidth */
+
+/* Bit masks for ATAPI_MULTI_TIM_2 */
+#define                        TH  0xff       /* Selects DIOW data hold */
+#define                      TEOC  0xff00     /* Selects end of cycle for DMA */
+
+/* Bit masks for ATAPI_ULTRA_TIM_0 */
+#define                      TACK  0xff       /* Selects setup and hold times for TACK */
+#define                      TENV  0xff00     /* Selects envelope time */
+
+/* Bit masks for ATAPI_ULTRA_TIM_1 */
+#define                      TDVS  0xff       /* Selects data valid setup time */
+#define                 TCYC_TDVS  0xff00     /* Selects cycle time - TDVS time */
+
+/* Bit masks for ATAPI_ULTRA_TIM_2 */
+#define                       TSS  0xff       /* Selects time from STROBE edge to negation of DMARQ or assertion of STOP */
+#define                      TMLI  0xff00     /* Selects interlock time */
+
+/* Bit masks for ATAPI_ULTRA_TIM_3 */
+#define                      TZAH  0xff       /* Selects minimum delay required for output */
+#define               READY_PAUSE  0xff00     /* Selects ready to pause */
+
+#endif /* __BFIN_PERIPHERAL_PATA__ */