Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / u-boot / drivers / block / pata_bfin.c
diff --git a/qemu/roms/u-boot/drivers/block/pata_bfin.c b/qemu/roms/u-boot/drivers/block/pata_bfin.c
new file mode 100644 (file)
index 0000000..b7fd1cd
--- /dev/null
@@ -0,0 +1,1204 @@
+/*
+ * 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/clock.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/portmux.h>
+#include <asm/mach-common/bits/pata.h>
+#include <ata.h>
+#include <sata.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)
+{
+       const unsigned short pins[] = {
+               P_ATAPI_RESET, P_ATAPI_DIOR, P_ATAPI_DIOW, P_ATAPI_CS0,
+               P_ATAPI_CS1, P_ATAPI_DMACK, P_ATAPI_DMARQ, P_ATAPI_INTRQ,
+               P_ATAPI_IORDY, P_ATAPI_D0A, P_ATAPI_D1A, P_ATAPI_D2A,
+               P_ATAPI_D3A, P_ATAPI_D4A, P_ATAPI_D5A, P_ATAPI_D6A,
+               P_ATAPI_D7A, P_ATAPI_D8A, P_ATAPI_D9A, P_ATAPI_D10A,
+               P_ATAPI_D11A, P_ATAPI_D12A, P_ATAPI_D13A, P_ATAPI_D14A,
+               P_ATAPI_D15A, P_ATAPI_A0A, P_ATAPI_A1A, P_ATAPI_A2A, 0,
+       };
+
+       peripheral_request_list(pins, "pata_bfin");
+
+       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%lx\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].log2blksz =
+               LOG2(sata_dev_desc[ap->port_no].blksz);
+       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, lbaint_t 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, lbaint_t 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;
+}