summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSonic Zhang <Sonic.Zhang@analog.com>2008-11-26 22:16:45 -0500
committerMike Frysinger <vapier@gentoo.org>2009-02-02 12:27:14 -0500
commit8a6b272596d43de0db4943eac7af58c3534c4026 (patch)
tree9cd5498465898a78b0bec75fc8d4091b81cd1192
parentbe9d8c780e6831cb84b7d4590ceae03dca8fc10b (diff)
Blackfin: add driver for on-chip ATAPI controller
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>
-rw-r--r--drivers/block/Makefile1
-rw-r--r--drivers/block/pata_bfin.c1201
-rw-r--r--drivers/block/pata_bfin.h173
-rw-r--r--include/asm-blackfin/mach-common/bits/pata.h220
4 files changed, 1595 insertions, 0 deletions
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 642582b088..59388d9d45 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -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
index 0000000000..f16dabeba7
--- /dev/null
+++ b/drivers/block/pata_bfin.c
@@ -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
index 0000000000..2b3425bc95
--- /dev/null
+++ b/drivers/block/pata_bfin.h
@@ -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
index 0000000000..9b61824f18
--- /dev/null
+++ b/include/asm-blackfin/mach-common/bits/pata.h
@@ -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__ */