Merge branch 'master' of git://www.denx.de/git/u-boot-mpc85xx
diff --git a/CHANGELOG b/CHANGELOG
index 278bb33..d5eae56 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,133 @@
+commit fd0b1fe3c388a77e8fe00cdd930ca317a91198d4
+Author: Dave Liu <r63238@freescale.com>
+Date:	Wed Mar 26 22:55:32 2008 +0800
+
+    drivers: add the support for Freescale SATA controller
+
+    Add the Freescale on-chip SATA controller driver to u-boot,
+    The SATA controller is used on the 837x and 8315 targets,
+    The driver can be used to load kernel, fs and dtb.
+
+    The features list:
+    - 1.5/3 Gbps link speed
+    - LBA48, LBA28 support
+    - DMA and FPDMA support
+    - Two ports support
+
+    Signed-off-by: Dave Liu <daveliu@freescale.com>
+
+commit bede87f4c87c3ccd868cc60ebf792e0560c6d024
+Author: Dave Liu <r63238@freescale.com>
+Date:	Wed Mar 26 22:54:44 2008 +0800
+
+    ata: add the readme for SATA command line
+
+    Signed-off-by: Dave Liu <daveliu@freescale.com>
+
+commit cd54081cd479e542fc399b8a40651ff11a1ad849
+Author: Dave Liu <r63238@freescale.com>
+Date:	Wed Mar 26 22:53:24 2008 +0800
+
+    ata: enable the sata initialize on boot up
+
+    Signed-off-by: Dave Liu <daveliu@freescale.com>
+
+commit 69386383c5c2b323c66495b0b0cef6a9714d83bf
+Author: Dave Liu <r63238@freescale.com>
+Date:	Wed Mar 26 22:52:36 2008 +0800
+
+    ata: add the fis struct for SATA
+
+    Signed-off-by: Dave Liu <daveliu@freescale.com>
+
+commit ffc664e80dfb2e17de0df5ad39e91a02e9c361bc
+Author: Dave Liu <r63238@freescale.com>
+Date:	Wed Mar 26 22:51:44 2008 +0800
+
+    ata: add the libata support
+
+    add simple libata support in u-boot
+
+    Signed-off-by: Dave Liu <daveliu@freescale.com>
+
+commit 8e9bb43429e50df55fa41932cbe65841ff579220
+Author: Dave Liu <r63238@freescale.com>
+Date:	Wed Mar 26 22:50:45 2008 +0800
+
+    ata: make the ata_piix driver using new SATA framework
+
+    original ata_piix driver is using IDE framework, not real
+    SATA framework. For now, the ata_piix driver is only used
+    by x86 sc520_cdp board. This patch makes the ata_piix driver
+    use the new SATA framework, so
+
+    - remove the duplicated command stuff
+    - remove the CONFIG_CMD_IDE define in the sc520_cdp.h
+    - add the CONFIG_CMD_SATA define to sc520_cdp.h
+
+    Signed-off-by: Dave Liu <daveliu@freescale.com>
+
+commit c7057b529c3c3cb9c0ac9060686a4068f1491bbe
+Author: Dave Liu <r63238@freescale.com>
+Date:	Wed Mar 26 22:49:44 2008 +0800
+
+    ata: add the support for SATA framework
+
+    - add the SATA framework
+    - add the SATA command line
+
+    Signed-off-by: Dave Liu <daveliu@freescale.com>
+
+commit 83c7f470a4ce94f33600f11ae85ce4dcf00aa90c
+Author: Dave Liu <r63238@freescale.com>
+Date:	Wed Mar 26 22:48:18 2008 +0800
+
+    ata: merge the header of ata_piix driver
+
+    move the sata.h from include/ to drivers/block/ata_piix.h
+
+    Signed-off-by: Dave Liu <daveliu@freescale.com>
+
+commit 9eef62804d9695425b24c87b46a61a7fa74afee0
+Author: Dave Liu <r63238@freescale.com>
+Date:	Wed Mar 26 22:47:06 2008 +0800
+
+    ata: merge the ata_piix driver
+
+    move the cmd_sata.c from common/ to drivers/ata_piix.c,
+    the cmd_sata.c have some part of ata_piix controller drivers.
+    consolidate the driver to have better framework.
+
+    Signed-off-by: Dave Liu <daveliu@freescale.com>
+
+commit 5b5eb9ca5b778f763bcf332697b35cc1e747626e
+Author: Wolfgang Denk <wd@denx.de>
+Date:	Wed Mar 26 15:38:47 2008 +0100
+
+    Coding style cleanup.
+
+    Signed-off-by: Wolfgang Denk <wd@denx.de>
+
+commit da8808df7a9cef5a3d2ee286ef9ebf9de1780660
+Author: Joakim Tjernlund <Joakim.Tjernlund@transmode.se>
+Date:	Wed Mar 26 13:02:13 2008 +0100
+
+    Add CFG_RTC_DS1337_NOOSC to turn off OSC output
+
+    The default settings for RTC DS1337 keeps the OSC
+    output, 32,768 Hz, on. This add CFG_RTC_DS1337_NOOSC to
+    turn it off.
+
+    Signed-off-by: Joakim Tjernlund <Joakim.Tjernlund@transmode.se>
+
+commit 438a4c11260b4ea9805039b0b4f92f9df5306b02
+Author: Wolfgang Denk <wd@denx.de>
+Date:	Wed Mar 26 11:48:46 2008 +0100
+
+    Cleanup coding style, update CHANGELOG
+
+    Signed-off-by: Wolfgang Denk <wd@denx.de>
+
 commit 218ca724c08ca8a649f0917cf201cf23d4b33f39
 Author: Wolfgang Denk <wd@denx.de>
 Date:	Wed Mar 26 10:40:12 2008 +0100
diff --git a/README b/README
index b3423e3..5cbe7c1 100644
--- a/README
+++ b/README
@@ -78,7 +78,7 @@
 available for FTP download from the ftp://ftp.denx.de/pub/u-boot/
 directory.
 
-Pre-build (and tested) images are available from
+Pre-built (and tested) images are available from
 ftp://ftp.denx.de/pub/u-boot/images/
 
 
diff --git a/common/Makefile b/common/Makefile
index 382dd01..0d67337 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -88,7 +88,7 @@
 COBJS-$(CONFIG_CMD_PORTIO) += cmd_portio.o
 COBJS-$(CONFIG_CMD_REGINFO) += cmd_reginfo.o
 COBJS-$(CONFIG_CMD_REISER) += cmd_reiser.o
-COBJS-y += cmd_sata.o
+COBJS-$(CONFIG_CMD_SATA) += cmd_sata.o
 COBJS-$(CONFIG_CMD_SCSI) += cmd_scsi.o
 COBJS-$(CONFIG_CMD_SETEXPR) += cmd_setexpr.o
 COBJS-$(CONFIG_CMD_SPI) += cmd_spi.o
diff --git a/common/cmd_sata.c b/common/cmd_sata.c
index bd4c11f..79c2495 100644
--- a/common/cmd_sata.c
+++ b/common/cmd_sata.c
@@ -1,8 +1,11 @@
 /*
+ * Copyright (C) 2000-2005, DENX Software Engineering
+ *		Wolfgang Denk <wd@denx.de>
  * Copyright (C) Procsys. All rights reserved.
- * Author: Mushtaq Khan <mushtaq_k@procsys.com>
+ *		Mushtaq Khan <mushtaq_k@procsys.com>
  *			<mushtaqk_921@yahoo.co.in>
- *
+ * Copyright (C) 2008 Freescale Semiconductor, Inc.
+ *		Dave Liu <daveliu@freescale.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -11,702 +14,180 @@
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  * MA 02111-1307 USA
- *
- * with the reference to libata in kernel 2.4.32
- *
  */
 
-/*
- * File contains SATA read-write and other utility functions.
- */
 #include <common.h>
-#include <asm/io.h>
-#include <pci.h>
 #include <command.h>
-#include <config.h>
-#include <ide.h>
-#include <ata.h>
-
-#ifdef CFG_SATA_SUPPORTED
-/*For debug prints set macro DEBUG_SATA to 1 */
-#define DEBUG_SATA 0
-/*Macro for SATA library specific declarations */
-#define SATA_DECL
+#include <part.h>
 #include <sata.h>
-#undef SATA_DECL
-
-static u8 __inline__
-sata_inb (unsigned long ioaddr)
-{
-	return inb (ioaddr);
-}
-
-static void __inline__
-sata_outb (unsigned char val, unsigned long ioaddr)
-{
-	outb (val, ioaddr);
-}
-
-static void
-output_data (struct sata_ioports *ioaddr, ulong * sect_buf, int words)
-{
-	outsw (ioaddr->data_addr, sect_buf, words << 1);
-}
-
-static int
-input_data (struct sata_ioports *ioaddr, ulong * sect_buf, int words)
-{
-	insw (ioaddr->data_addr, sect_buf, words << 1);
-	return 0;
-}
-
-static void
-sata_cpy (unsigned char *dst, unsigned char *src, unsigned int len)
-{
-	unsigned char *end, *last;
-
-	last = dst;
-	end = src + len - 1;
-
-	/* reserve space for '\0' */
-	if (len < 2)
-		goto OUT;
-
-	/* skip leading white space */
-	while ((*src) && (src < end) && (*src == ' '))
-		++src;
-
-	/* copy string, omitting trailing white space */
-	while ((*src) && (src < end)) {
-		*dst++ = *src;
-		if (*src++ != ' ')
-			last = dst;
-	}
-      OUT:
-	*last = '\0';
-}
-
-int
-sata_bus_softreset (int num)
-{
-	u8 dev = 0, status = 0, i;
-
-	port[num].dev_mask = 0;
-
-	for (i = 0; i < CFG_SATA_DEVS_PER_BUS; i++) {
-		if (!(sata_devchk (&port[num].ioaddr, i))) {
-			PRINTF ("dev_chk failed for dev#%d\n", i);
-		} else {
-			port[num].dev_mask |= (1 << i);
-			PRINTF ("dev_chk passed for dev#%d\n", i);
-		}
-	}
-
-	if (!(port[num].dev_mask)) {
-		printf ("no devices on port%d\n", num);
-		return 1;
-	}
-
-	dev_select (&port[num].ioaddr, dev);
-
-	port[num].ctl_reg = 0x08;	/*Default value of control reg */
-	sata_outb (port[num].ctl_reg, port[num].ioaddr.ctl_addr);
-	udelay (10);
-	sata_outb (port[num].ctl_reg | ATA_SRST, port[num].ioaddr.ctl_addr);
-	udelay (10);
-	sata_outb (port[num].ctl_reg, port[num].ioaddr.ctl_addr);
-
-	/* 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.
-	 */
-	msleep (150);
-	status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 300);
-	while ((status & ATA_BUSY)) {
-		msleep (100);
-		status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 3);
-	}
-
-	if (status & ATA_BUSY)
-		printf ("ata%u is slow to respond,plz be patient\n", port);
-
-	while ((status & ATA_BUSY)) {
-		msleep (100);
-		status = sata_chk_status (&port[num].ioaddr);
-	}
-
-	if (status & ATA_BUSY) {
-		printf ("ata%u failed to respond : ", port);
-		printf ("bus reset failed\n");
-		return 1;
-	}
-	return 0;
-}
-
-void
-sata_identify (int num, int dev)
-{
-	u8 cmd = 0, status = 0, devno = num * CFG_SATA_DEVS_PER_BUS + dev;
-	u16 iobuf[ATA_SECT_SIZE];
-	u64 n_sectors = 0;
-	u8 mask = 0;
-
-	memset (iobuf, 0, sizeof (iobuf));
-	hd_driveid_t *iop = (hd_driveid_t *) iobuf;
-
-	if (dev == 0)
-		mask = 0x01;
-	else
-		mask = 0x02;
-
-	if (!(port[num].dev_mask & mask)) {
-		printf ("dev%d is not present on port#%d\n", dev, num);
-		return;
-	}
-
-	printf ("port=%d dev=%d\n", num, dev);
-
-	dev_select (&port[num].ioaddr, dev);
-
-	status = 0;
-	cmd = ATA_CMD_IDENT;	/*Device Identify Command */
-	sata_outb (cmd, port[num].ioaddr.command_addr);
-	sata_inb (port[num].ioaddr.altstatus_addr);
-	udelay (10);
-
-	status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 1000);
-	if (status & ATA_ERR) {
-		printf ("\ndevice not responding\n");
-		port[num].dev_mask &= ~mask;
-		return;
-	}
-
-	input_data (&port[num].ioaddr, (ulong *) iobuf, ATA_SECTORWORDS);
-
-	PRINTF ("\nata%u: dev %u cfg 49:%04x 82:%04x 83:%04x 84:%04x85:%04x"
-		"86:%04x" "87:%04x 88:%04x\n", num, dev, iobuf[49],
-		iobuf[82], iobuf[83], iobuf[84], iobuf[85], iobuf[86],
-		iobuf[87], iobuf[88]);
-
-	/* 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", num);
-	}
-	ata_dump_id (iobuf);
-
-	if (ata_id_has_lba48 (iobuf)) {
-		n_sectors = ata_id_u64 (iobuf, 100);
-	} else {
-		n_sectors = ata_id_u32 (iobuf, 60);
-	}
-	PRINTF ("no. of sectors %u\n", ata_id_u64 (iobuf, 100));
-	PRINTF ("no. of sectors %u\n", ata_id_u32 (iobuf, 60));
-
-	if (n_sectors == 0) {
-		port[num].dev_mask &= ~mask;
-		return;
-	}
-
-	sata_cpy (sata_dev_desc[devno].revision, iop->fw_rev,
-		  sizeof (sata_dev_desc[devno].revision));
-	sata_cpy (sata_dev_desc[devno].vendor, iop->model,
-		  sizeof (sata_dev_desc[devno].vendor));
-	sata_cpy (sata_dev_desc[devno].product, iop->serial_no,
-		  sizeof (sata_dev_desc[devno].product));
-	strswab (sata_dev_desc[devno].revision);
-	strswab (sata_dev_desc[devno].vendor);
-
-	if ((iop->config & 0x0080) == 0x0080) {
-		sata_dev_desc[devno].removable = 1;
-	} else {
-		sata_dev_desc[devno].removable = 0;
-	}
-
-	sata_dev_desc[devno].lba = iop->lba_capacity;
-	PRINTF ("lba=0x%x", sata_dev_desc[devno].lba);
-
-#ifdef CONFIG_LBA48
-	if (iop->command_set_2 & 0x0400) {
-		sata_dev_desc[devno].lba48 = 1;
-		lba = (unsigned long long) iop->lba48_capacity[0] |
-		    ((unsigned long long) iop->lba48_capacity[1] << 16) |
-		    ((unsigned long long) iop->lba48_capacity[2] << 32) |
-		    ((unsigned long long) iop->lba48_capacity[3] << 48);
-	} else {
-		sata_dev_desc[devno].lba48 = 0;
-	}
-#endif
-
-	/* assuming HD */
-	sata_dev_desc[devno].type = DEV_TYPE_HARDDISK;
-	sata_dev_desc[devno].blksz = ATA_BLOCKSIZE;
-	sata_dev_desc[devno].lun = 0;	/* just to fill something in... */
-}
-
-void
-set_Feature_cmd (int num, int dev)
-{
-	u8 mask = 0x00, status = 0;
-
-	if (dev == 0)
-		mask = 0x01;
-	else
-		mask = 0x02;
-
-	if (!(port[num].dev_mask & mask)) {
-		PRINTF ("dev%d is not present on port#%d\n", dev, num);
-		return;
-	}
-
-	dev_select (&port[num].ioaddr, dev);
-
-	sata_outb (SETFEATURES_XFER, port[num].ioaddr.feature_addr);
-	sata_outb (XFER_PIO_4, port[num].ioaddr.nsect_addr);
-	sata_outb (0, port[num].ioaddr.lbal_addr);
-	sata_outb (0, port[num].ioaddr.lbam_addr);
-	sata_outb (0, port[num].ioaddr.lbah_addr);
-
-	sata_outb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr);
-	sata_outb (ATA_CMD_SETF, port[num].ioaddr.command_addr);
-
-	udelay (50);
-	msleep (150);
-
-	status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 5000);
-	if ((status & (ATA_STAT_BUSY | ATA_STAT_ERR))) {
-		printf ("Error  : status 0x%02x\n", status);
-		port[num].dev_mask &= ~mask;
-	}
-}
-
-void
-sata_port (struct sata_ioports *ioport)
-{
-	ioport->data_addr = ioport->cmd_addr + ATA_REG_DATA;
-	ioport->error_addr = ioport->cmd_addr + ATA_REG_ERR;
-	ioport->feature_addr = ioport->cmd_addr + ATA_REG_FEATURE;
-	ioport->nsect_addr = ioport->cmd_addr + ATA_REG_NSECT;
-	ioport->lbal_addr = ioport->cmd_addr + ATA_REG_LBAL;
-	ioport->lbam_addr = ioport->cmd_addr + ATA_REG_LBAM;
-	ioport->lbah_addr = ioport->cmd_addr + ATA_REG_LBAH;
-	ioport->device_addr = ioport->cmd_addr + ATA_REG_DEVICE;
-	ioport->status_addr = ioport->cmd_addr + ATA_REG_STATUS;
-	ioport->command_addr = ioport->cmd_addr + ATA_REG_CMD;
-}
-
-int
-sata_devchk (struct sata_ioports *ioaddr, int dev)
-{
-	u8 nsect, lbal;
-
-	dev_select (ioaddr, dev);
-
-	sata_outb (0x55, ioaddr->nsect_addr);
-	sata_outb (0xaa, ioaddr->lbal_addr);
 
-	sata_outb (0xaa, ioaddr->nsect_addr);
-	sata_outb (0x55, ioaddr->lbal_addr);
+int curr_device = -1;
+block_dev_desc_t sata_dev_desc[CFG_SATA_MAX_DEVICE];
 
-	sata_outb (0x55, ioaddr->nsect_addr);
-	sata_outb (0xaa, ioaddr->lbal_addr);
-
-	nsect = sata_inb (ioaddr->nsect_addr);
-	lbal = sata_inb (ioaddr->lbal_addr);
-
-	if ((nsect == 0x55) && (lbal == 0xaa))
-		return 1;	/* we found a device */
-	else
-		return 0;	/* nothing found */
-}
-
-void
-dev_select (struct sata_ioports *ioaddr, int dev)
-{
-	u8 tmp = 0;
-
-	if (dev == 0)
-		tmp = ATA_DEVICE_OBS;
-	else
-		tmp = ATA_DEVICE_OBS | ATA_DEV1;
-
-	sata_outb (tmp, ioaddr->device_addr);
-	sata_inb (ioaddr->altstatus_addr);
-	udelay (5);
-}
-
-u8
-sata_busy_wait (struct sata_ioports *ioaddr, int bits, unsigned int max)
+int sata_initialize(void)
 {
-	u8 status;
-
-	do {
-		udelay (1000);
-		status = sata_chk_status (ioaddr);
-		max--;
-	} while ((status & bits) && (max > 0));
-
-	return status;
-}
-
-u8
-sata_chk_status (struct sata_ioports * ioaddr)
-{
-	return sata_inb (ioaddr->status_addr);
-}
-
-void
-msleep (int count)
-{
+	int rc;
 	int i;
 
-	for (i = 0; i < count; i++)
-		udelay (1000);
-}
-
-ulong
-sata_read (int device, ulong blknr,lbaint_t blkcnt, void * buff)
-{
-	ulong n = 0, *buffer = (ulong *)buff;
-	u8 dev = 0, num = 0, mask = 0, status = 0;
-
-#ifdef CONFIG_LBA48
-	unsigned char lba48 = 0;
-
-	if (blknr & 0x0000fffff0000000) {
-		if (!sata_dev_desc[devno].lba48) {
-			printf ("Drive doesn't support 48-bit addressing\n");
-			return 0;
-		}
-		/* more than 28 bits used, use 48bit mode */
-		lba48 = 1;
-	}
-#endif
-	/*Port Number */
-	num = device / CFG_SATA_DEVS_PER_BUS;
-	/*dev on the port */
-	if (device >= CFG_SATA_DEVS_PER_BUS)
-		dev = device - CFG_SATA_DEVS_PER_BUS;
-	else
-		dev = device;
-
-	if (dev == 0)
-		mask = 0x01;
-	else
-		mask = 0x02;
-
-	if (!(port[num].dev_mask & mask)) {
-		printf ("dev%d is not present on port#%d\n", dev, num);
-		return 0;
-	}
-
-	/* Select device */
-	dev_select (&port[num].ioaddr, dev);
-
-	status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500);
-	if (status & ATA_BUSY) {
-		printf ("ata%u failed to respond\n", port[num].port_no);
-		return n;
-	}
-	while (blkcnt-- > 0) {
-		status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500);
-		if (status & ATA_BUSY) {
-			printf ("ata%u failed to respond\n", 0);
-			return n;
-		}
-#ifdef CONFIG_LBA48
-		if (lba48) {
-			/* write high bits */
-			sata_outb (0, port[num].ioaddr.nsect_addr);
-			sata_outb ((blknr >> 24) & 0xFF,
-				   port[num].ioaddr.lbal_addr);
-			sata_outb ((blknr >> 32) & 0xFF,
-				   port[num].ioaddr.lbam_addr);
-			sata_outb ((blknr >> 40) & 0xFF,
-				   port[num].ioaddr.lbah_addr);
-		}
-#endif
-		sata_outb (1, port[num].ioaddr.nsect_addr);
-		sata_outb (((blknr) >> 0) & 0xFF,
-			   port[num].ioaddr.lbal_addr);
-		sata_outb ((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr);
-		sata_outb ((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr);
-
-#ifdef CONFIG_LBA48
-		if (lba48) {
-			sata_outb (ATA_LBA, port[num].ioaddr.device_addr);
-			sata_outb (ATA_CMD_READ_EXT,
-				   port[num].ioaddr.command_addr);
-		} else
-#endif
-		{
-			sata_outb (ATA_LBA | ((blknr >> 24) & 0xF),
-				   port[num].ioaddr.device_addr);
-			sata_outb (ATA_CMD_READ,
-				   port[num].ioaddr.command_addr);
-		}
-
-		msleep (50);
-		/*may take up to 4 sec */
-		status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 4000);
-
-		if ((status & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR))
-		    != ATA_STAT_DRQ) {
-			u8 err = 0;
-
-			printf ("Error no DRQ dev %d blk %ld: sts 0x%02x\n",
-				device, (ulong) blknr, status);
-			err = sata_inb (port[num].ioaddr.error_addr);
-			printf ("Error reg = 0x%x\n", err);
-			return (n);
-		}
-		input_data (&port[num].ioaddr, buffer, ATA_SECTORWORDS);
-		sata_inb (port[num].ioaddr.altstatus_addr);
-		udelay (50);
-
-		++n;
-		++blknr;
-		buffer += ATA_SECTORWORDS;
-	}
-	return n;
-}
-
-ulong
-sata_write (int device, ulong blknr,lbaint_t blkcnt, void * buff)
-{
-	ulong n = 0, *buffer = (ulong *)buff;
-	unsigned char status = 0, num = 0, dev = 0, mask = 0;
-
-#ifdef CONFIG_LBA48
-	unsigned char lba48 = 0;
-
-	if (blknr & 0x0000fffff0000000) {
-		if (!sata_dev_desc[devno].lba48) {
-			printf ("Drive doesn't support 48-bit addressing\n");
-			return 0;
-		}
-		/* more than 28 bits used, use 48bit mode */
-		lba48 = 1;
-	}
-#endif
-	/*Port Number */
-	num = device / CFG_SATA_DEVS_PER_BUS;
-	/*dev on the Port */
-	if (device >= CFG_SATA_DEVS_PER_BUS)
-		dev = device - CFG_SATA_DEVS_PER_BUS;
-	else
-		dev = device;
+	for (i = 0; i < CFG_SATA_MAX_DEVICE; i++) {
+		memset(&sata_dev_desc[i], 0, sizeof(struct block_dev_desc));
+		sata_dev_desc[i].if_type = IF_TYPE_SATA;
+		sata_dev_desc[i].dev = i;
+		sata_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
+		sata_dev_desc[i].type = DEV_TYPE_HARDDISK;
+		sata_dev_desc[i].lba = 0;
+		sata_dev_desc[i].blksz = 512;
+		sata_dev_desc[i].block_read = sata_read;
+		sata_dev_desc[i].block_write = sata_write;
 
-	if (dev == 0)
-		mask = 0x01;
-	else
-		mask = 0x02;
-
-	/* Select device */
-	dev_select (&port[num].ioaddr, dev);
-
-	status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500);
-	if (status & ATA_BUSY) {
-		printf ("ata%u failed to respond\n", port[num].port_no);
-		return n;
+		rc = init_sata(i);
+		rc = scan_sata(i);
+		if ((sata_dev_desc[i].lba > 0) && (sata_dev_desc[i].blksz > 0))
+			init_part(&sata_dev_desc[i]);
 	}
-
-	while (blkcnt-- > 0) {
-		status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500);
-		if (status & ATA_BUSY) {
-			printf ("ata%u failed to respond\n",
-				port[num].port_no);
-			return n;
-		}
-#ifdef CONFIG_LBA48
-		if (lba48) {
-			/* write high bits */
-			sata_outb (0, port[num].ioaddr.nsect_addr);
-			sata_outb ((blknr >> 24) & 0xFF,
-				   port[num].ioaddr.lbal_addr);
-			sata_outb ((blknr >> 32) & 0xFF,
-				   port[num].ioaddr.lbam_addr);
-			sata_outb ((blknr >> 40) & 0xFF,
-				   port[num].ioaddr.lbah_addr);
-		}
-#endif
-		sata_outb (1, port[num].ioaddr.nsect_addr);
-		sata_outb ((blknr >> 0) & 0xFF, port[num].ioaddr.lbal_addr);
-		sata_outb ((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr);
-		sata_outb ((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr);
-#ifdef CONFIG_LBA48
-		if (lba48) {
-			sata_outb (ATA_LBA, port[num].ioaddr.device_addr);
-			sata_outb (ATA_CMD_WRITE_EXT,
-				   port[num].ioaddr.command_addr);
-		} else
-#endif
-		{
-			sata_outb (ATA_LBA | ((blknr >> 24) & 0xF),
-				   port[num].ioaddr.device_addr);
-			sata_outb (ATA_CMD_WRITE,
-				   port[num].ioaddr.command_addr);
-		}
-
-		msleep (50);
-		/*may take up to 4 sec */
-		status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 4000);
-		if ((status & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR))
-		    != ATA_STAT_DRQ) {
-			printf ("Error no DRQ dev %d blk %ld: sts 0x%02x\n",
-				device, (ulong) blknr, status);
-			return (n);
-		}
-
-		output_data (&port[num].ioaddr, buffer, ATA_SECTORWORDS);
-		sata_inb (port[num].ioaddr.altstatus_addr);
-		udelay (50);
-
-		++n;
-		++blknr;
-		buffer += ATA_SECTORWORDS;
-	}
-	return n;
+	curr_device = 0;
+	return rc;
 }
 
-block_dev_desc_t *sata_get_dev (int dev);
-
-block_dev_desc_t *
-sata_get_dev (int dev)
+block_dev_desc_t *sata_get_dev(int dev)
 {
-	return ((block_dev_desc_t *) & sata_dev_desc[dev]);
+	return (dev < CFG_SATA_MAX_DEVICE) ? &sata_dev_desc[dev] : NULL;
 }
 
-int
-do_sata (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+int do_sata(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 {
+	int rc = 0;
 
 	switch (argc) {
 	case 0:
 	case 1:
-		printf ("Usage:\n%s\n", cmdtp->usage);
+		printf("Usage:\n%s\n", cmdtp->usage);
 		return 1;
 	case 2:
-		if (strncmp (argv[1], "init", 4) == 0) {
-			int rcode = 0;
-
-			rcode = init_sata ();
-			if (rcode)
-				printf ("Sata initialization Failed\n");
-			return rcode;
-		} else if (strncmp (argv[1], "inf", 3) == 0) {
+		if (strncmp(argv[1],"inf", 3) == 0) {
 			int i;
-
-			putc ('\n');
-			for (i = 0; i < CFG_SATA_MAXDEVICES; ++i) {
-				/*List only known devices */
-				if (sata_dev_desc[i].type ==
-				    DEV_TYPE_UNKNOWN)
+			putc('\n');
+			for (i = 0; i < CFG_SATA_MAX_DEVICE; ++i) {
+				if (sata_dev_desc[i].type == DEV_TYPE_UNKNOWN)
 					continue;
-				printf ("sata dev %d: ", i);
-				dev_print (&sata_dev_desc[i]);
+				printf ("SATA device %d: ", i);
+				dev_print(&sata_dev_desc[i]);
 			}
 			return 0;
+		} else if (strncmp(argv[1],"dev", 3) == 0) {
+			if ((curr_device < 0) || (curr_device >= CFG_SATA_MAX_DEVICE)) {
+				puts("\nno SATA devices available\n");
+				return 1;
+			}
+			printf("\nSATA device %d: ", curr_device);
+			dev_print(&sata_dev_desc[curr_device]);
+			return 0;
+		} else if (strncmp(argv[1],"part",4) == 0) {
+			int dev, ok;
+
+			for (ok = 0, dev = 0; dev < CFG_SATA_MAX_DEVICE; ++dev) {
+				if (sata_dev_desc[dev].part_type != PART_TYPE_UNKNOWN) {
+					++ok;
+					if (dev)
+						putc ('\n');
+					print_part(&sata_dev_desc[dev]);
+				}
+			}
+			if (!ok) {
+				puts("\nno SATA devices available\n");
+				rc ++;
+			}
+			return rc;
 		}
-		printf ("Usage:\n%s\n", cmdtp->usage);
+		printf("Usage:\n%s\n", cmdtp->usage);
 		return 1;
 	case 3:
-		if (strcmp (argv[1], "dev") == 0) {
-			int dev = (int) simple_strtoul (argv[2], NULL, 10);
+		if (strncmp(argv[1], "dev", 3) == 0) {
+			int dev = (int)simple_strtoul(argv[2], NULL, 10);
 
-			if (dev >= CFG_SATA_MAXDEVICES) {
-				printf ("\nSata dev %d not available\n",
-					dev);
+			printf("\nSATA device %d: ", dev);
+			if (dev >= CFG_SATA_MAX_DEVICE) {
+				puts ("unknown device\n");
 				return 1;
 			}
-			printf ("\nSATA dev %d: ", dev);
-			dev_print (&sata_dev_desc[dev]);
+			dev_print(&sata_dev_desc[dev]);
+
 			if (sata_dev_desc[dev].type == DEV_TYPE_UNKNOWN)
 				return 1;
-			curr_dev = dev;
+
+			curr_device = dev;
+
+			puts("... is now current device\n");
+
 			return 0;
-		} else if (strcmp (argv[1], "part") == 0) {
-			int dev = (int) simple_strtoul (argv[2], NULL, 10);
+		} else if (strncmp(argv[1], "part", 4) == 0) {
+			int dev = (int)simple_strtoul(argv[2], NULL, 10);
 
-			if (dev >= CFG_SATA_MAXDEVICES) {
-				printf ("\nSata dev %d not available\n",
-					dev);
-				return 1;
-			}
-			PRINTF ("\nSATA dev %d: ", dev);
-			if (sata_dev_desc[dev].part_type !=
-			    PART_TYPE_UNKNOWN) {
-				print_part (&sata_dev_desc[dev]);
+			if (sata_dev_desc[dev].part_type != PART_TYPE_UNKNOWN) {
+				print_part(&sata_dev_desc[dev]);
 			} else {
-				printf ("\nSata dev %d partition type "
-					"unknown\n", dev);
-				return 1;
+				printf("\nSATA device %d not available\n", dev);
+				rc = 1;
 			}
-			return 0;
+			return rc;
 		}
 		printf ("Usage:\n%s\n", cmdtp->usage);
 		return 1;
-	default:
-		if (argc < 5) {
-			printf ("Usage:\n%s\n", cmdtp->usage);
-			return 1;
-		}
-		if (strcmp (argv[1], "read") == 0) {
-			ulong addr = simple_strtoul (argv[2], NULL, 16);
-			ulong cnt = simple_strtoul (argv[4], NULL, 16);
+
+	default: /* at least 4 args */
+		if (strcmp(argv[1], "read") == 0) {
+			ulong addr = simple_strtoul(argv[2], NULL, 16);
+			ulong cnt = simple_strtoul(argv[4], NULL, 16);
 			ulong n;
-			lbaint_t blk = simple_strtoul (argv[3], NULL, 16);
+			lbaint_t blk = simple_strtoul(argv[3], NULL, 16);
 
-			memset ((int *) addr, 0, cnt * 512);
-			printf ("\nSATA read: dev %d blk # %ld,"
-				"count %ld ... ", curr_dev, blk, cnt);
-			n = sata_read (curr_dev, blk, cnt, (ulong *) addr);
+			printf("\nSATA read: device %d block # %ld, count %ld ... ",
+				curr_device, blk, cnt);
+
+			n = sata_read(curr_device, blk, cnt, (u32 *)addr);
+
 			/* flush cache after read */
-			flush_cache (addr, cnt * 512);
-			printf ("%ld blocks read: %s\n", n,
-				(n == cnt) ? "OK" : "ERR");
-			if (n == cnt)
-				return 1;
-			else
-				return 0;
-		} else if (strcmp (argv[1], "write") == 0) {
-			ulong addr = simple_strtoul (argv[2], NULL, 16);
-			ulong cnt = simple_strtoul (argv[4], NULL, 16);
+			flush_cache(addr, cnt * sata_dev_desc[curr_device].blksz);
+
+			printf("%ld blocks read: %s\n",
+				n, (n==cnt) ? "OK" : "ERROR");
+			return (n == cnt) ? 0 : 1;
+		} else if (strcmp(argv[1], "write") == 0) {
+			ulong addr = simple_strtoul(argv[2], NULL, 16);
+			ulong cnt = simple_strtoul(argv[4], NULL, 16);
 			ulong n;
-			lbaint_t blk = simple_strtoul (argv[3], NULL, 16);
 
-			printf ("\nSata write: dev %d blk # %ld,"
-				"count %ld ... ", curr_dev, blk, cnt);
-			n = sata_write (curr_dev, blk, cnt, (ulong *) addr);
-			printf ("%ld blocks written: %s\n", n,
-				(n == cnt) ? "OK" : "ERR");
-			if (n == cnt)
-				return 1;
-			else
-				return 0;
+			lbaint_t blk = simple_strtoul(argv[3], NULL, 16);
+
+			printf("\nSATA write: device %d block # %ld, count %ld ... ",
+				curr_device, blk, cnt);
+
+			n = sata_write(curr_device, blk, cnt, (u32 *)addr);
+
+			printf("%ld blocks written: %s\n",
+				n, (n == cnt) ? "OK" : "ERROR");
+			return (n == cnt) ? 0 : 1;
 		} else {
-			printf ("Usage:\n%s\n", cmdtp->usage);
-			return 1;
+			printf("Usage:\n%s\n", cmdtp->usage);
+			rc = 1;
 		}
-	}			/*End OF SWITCH */
-}
 
-U_BOOT_CMD (sata, 5, 1, do_sata,
-	    "sata init\n"
-	    "sata info\n"
-	    "sata part device\n"
-	    "sata dev device\n"
-	    "sata read  addr blk# cnt\n"
-	    "sata write  addr blk# cnt\n", "cmd for init,rw and dev-info\n");
+		return rc;
+	}
+}
 
-#endif
+U_BOOT_CMD(
+	sata, 5, 1, do_sata,
+	"sata	- SATA sub system\n",
+	"sata info - show available SATA devices\n"
+	"sata device [dev] - show or set current device\n"
+	"sata part [dev] - print partition table\n"
+	"sata read addr blk# cnt\n"
+	"sata write addr blk# cnt\n");
diff --git a/common/usb_storage.c b/common/usb_storage.c
index 81d2f92..d263b6c 100644
--- a/common/usb_storage.c
+++ b/common/usb_storage.c
@@ -196,12 +196,12 @@
 		for (i = 0; i < usb_max_devs; i++) {
 			printf ("  Device %d: ", i);
 			dev_print(&usb_dev_desc[i]);
-			return 0;
 		}
-	} else {
-		printf("No storage devices, perhaps not 'usb start'ed..?\n");
-		return 1;
+		return 0;
 	}
+	
+	printf("No storage devices, perhaps not 'usb start'ed..?\n");
+	return 1;
 }
 
 /*********************************************************************************
diff --git a/disk/part.c b/disk/part.c
index 56b9427..3c71208 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -35,6 +35,7 @@
 #endif
 
 #if (defined(CONFIG_CMD_IDE) || \
+     defined(CONFIG_CMD_SATA) || \
      defined(CONFIG_CMD_SCSI) || \
      defined(CONFIG_CMD_USB) || \
      defined(CONFIG_MMC) || \
@@ -49,6 +50,9 @@
 #if defined(CONFIG_CMD_IDE)
 	{ .name = "ide", .get_dev = ide_get_dev, },
 #endif
+#if defined(CONFIG_CMD_SATA)
+	{.name = "sata", .get_dev = sata_get_dev, },
+#endif
 #if defined(CONFIG_CMD_SCSI)
 	{ .name = "scsi", .get_dev = scsi_get_dev, },
 #endif
@@ -87,6 +91,7 @@
 #endif
 
 #if (defined(CONFIG_CMD_IDE) || \
+     defined(CONFIG_CMD_SATA) || \
      defined(CONFIG_CMD_SCSI) || \
      defined(CONFIG_CMD_USB) || \
      defined(CONFIG_MMC) || \
@@ -116,6 +121,12 @@
 			dev_desc->vendor,
 			dev_desc->revision,
 			dev_desc->product);
+	}
+	if (dev_desc->if_type==IF_TYPE_SATA) {
+		printf ("Model: %s Firm: %s Ser#: %s\n",
+			dev_desc->vendor,
+			dev_desc->revision,
+			dev_desc->product);
 	} else {
 		printf ("Vendor: %s Prod.: %s Rev: %s\n",
 			dev_desc->vendor,
@@ -177,6 +188,7 @@
 #endif
 
 #if (defined(CONFIG_CMD_IDE) || \
+     defined(CONFIG_CMD_SATA) || \
      defined(CONFIG_CMD_SCSI) || \
      defined(CONFIG_CMD_USB) || \
      defined(CONFIG_MMC)		|| \
@@ -271,6 +283,8 @@
 	switch (dev_desc->if_type) {
 		case IF_TYPE_IDE:  	puts ("IDE");
 					break;
+		case IF_TYPE_SATA:	puts ("SATA");
+					break;
 		case IF_TYPE_SCSI: 	puts ("SCSI");
 					break;
 		case IF_TYPE_ATAPI:	puts ("ATAPI");
diff --git a/disk/part_dos.c b/disk/part_dos.c
index 4707f80..4d778ec 100644
--- a/disk/part_dos.c
+++ b/disk/part_dos.c
@@ -36,6 +36,7 @@
 #include "part_dos.h"
 
 #if (defined(CONFIG_CMD_IDE) || \
+     defined(CONFIG_CMD_SATA) || \
      defined(CONFIG_CMD_SCSI) || \
      defined(CONFIG_CMD_USB) || \
      defined(CONFIG_MMC) || \
@@ -194,6 +195,7 @@
 			info->size  = le32_to_int (pt->size4);
 			switch(dev_desc->if_type) {
 				case IF_TYPE_IDE:
+				case IF_TYPE_SATA:
 				case IF_TYPE_ATAPI:
 					sprintf ((char *)info->name, "hd%c%d\n", 'a' + dev_desc->dev, part_num);
 					break;
diff --git a/disk/part_iso.c b/disk/part_iso.c
index 06dd75e..4894630 100644
--- a/disk/part_iso.c
+++ b/disk/part_iso.c
@@ -27,6 +27,7 @@
 
 #if (defined(CONFIG_CMD_IDE) || \
      defined(CONFIG_CMD_SCSI) || \
+     defined(CONFIG_CMD_SATA) || \
      defined(CONFIG_CMD_USB) || \
      defined(CONFIG_MMC) || \
      defined(CONFIG_SYSTEMACE) ) && defined(CONFIG_ISO_PARTITION)
@@ -157,6 +158,7 @@
 	sprintf ((char *)info->type, "U-Boot");
 	switch(dev_desc->if_type) {
 		case IF_TYPE_IDE:
+		case IF_TYPE_SATA:
 		case IF_TYPE_ATAPI:
 			sprintf ((char *)info->name, "hd%c%d\n", 'a' + dev_desc->dev, part_num);
 			break;
diff --git a/disk/part_mac.c b/disk/part_mac.c
index d303a73..1922fe5 100644
--- a/disk/part_mac.c
+++ b/disk/part_mac.c
@@ -36,6 +36,7 @@
 
 #if (defined(CONFIG_CMD_IDE) || \
      defined(CONFIG_CMD_SCSI) || \
+     defined(CONFIG_CMD_SATA) || \
      defined(CONFIG_CMD_USB) || \
      defined(CONFIG_MMC) || \
      defined(CONFIG_SYSTEMACE) ) && defined(CONFIG_MAC_PARTITION)
diff --git a/doc/README.sata b/doc/README.sata
new file mode 100644
index 0000000..168dc7f
--- /dev/null
+++ b/doc/README.sata
@@ -0,0 +1,68 @@
+1. SATA usage in U-boot
+
+	Two ways to operate the hard disk
+
+	* Raw read/write block from/to SATA hard disk;
+	* ext2load read file from ext2 filesytem in hard disk
+
+1.0 How to know the information of SATA hard disk?
+
+	=> sata info
+
+SATA device 0: Model: ST3320620AS Firm: 3.AAD Ser#:		4QF01ZTN
+	    Type: Hard Disk
+	    Supports 48-bit addressing
+	    Capacity: 305245.3 MB = 298.0 GB (625142448 x 512)
+
+1.1 How to save the kernel, filesystem, dtb to SATA hard disk with raw?
+
+	Notes: 0x1000 sectors = 2 MBytes
+
+	wirte kernel
+	=> tftp 40000 /tftpboot/uImage.837x
+	=> sata write 40000 0 2000
+
+	write ramdisk
+	=> tftp 40000 /tftpboot/ramdisk.837x
+	=> sata write 40000 2000 8000
+
+	write dtb
+	=> tftp 40000 /tftpboot/mpc837xemds.dtb
+	=> sata write 40000 a000 1000
+
+1.2 How to read the kernel, filesystem, dtb from SATA hard disk with raw?
+
+	load kernel
+	=> sata read 200000 0 2000
+
+	load ramdisk
+	=> sata read 1000000 2000 8000
+
+	load dtb
+	=> sata read 2000000 a000 1000
+
+	boot
+	=> bootm 200000 1000000 2000000
+
+1.3 How to load image from ext2 filesystem in U-boot?
+
+	U-boot doesn't support ext2 write to hard disk, so
+	you have to write the image to hard disk under Linux env,
+	before you load image from ext2 filesystem.
+
+	=> ext2ls sata 0:1 /
+	<DIR>	    4096 .
+	<DIR>	    4096 ..
+	<DIR>	   16384 lost+found
+		 1352023 uImage.837x
+		 3646377 ramdisk.837x
+		   12288 mpc837xemds.dtb
+		      12 hello.txt
+
+	=> ext2load sata 0:1 200000 /uImage.837x
+
+	=> ext2load sata 0:1 1000000 /ramdisk.837x
+
+	=> ext2load sata 0:1 2000000 /mpc837xemds.dtb
+
+	=> bootm 200000 1000000 2000000
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index e069969..dca3547 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -27,6 +27,8 @@
 
 COBJS-y += ahci.o
 COBJS-y += ata_piix.o
+COBJS-$(CONFIG_FSL_SATA) += fsl_sata.o
+COBJS-$(CONFIG_LIBATA) += libata.o
 COBJS-y += sil680.o
 COBJS-y += sym53c8xx.o
 COBJS-y += systemace.o
diff --git a/drivers/block/ata_piix.c b/drivers/block/ata_piix.c
index 42456d7..441a4dc 100644
--- a/drivers/block/ata_piix.c
+++ b/drivers/block/ata_piix.c
@@ -26,20 +26,25 @@
  */
 
 #include <common.h>
+#include <asm/io.h>
 #include <pci.h>
 #include <command.h>
 #include <config.h>
 #include <asm/byteorder.h>
+#include <part.h>
 #include <ide.h>
 #include <ata.h>
 
 #ifdef CFG_ATA_PIIX		/*ata_piix driver */
 
+extern block_dev_desc_t sata_dev_desc[CFG_SATA_MAX_DEVICE];
+extern int curr_device;
+
 #define DEBUG_SATA 0		/*For debug prints set DEBUG_SATA to 1 */
 
+#define SATA_DECL
 #define DRV_DECL		/*For file specific declarations */
-#include <sata.h>
-#undef DRV_DECL
+#include "ata_piix.h"
 
 /*Macros realted to PCI*/
 #define PCI_SATA_BUS	0x00
@@ -142,19 +147,15 @@
 }
 
 int
-init_sata (void)
+init_sata (int dev)
 {
+	static int done = 0;
 	u8 i, rv = 0;
 
-	for (i = 0; i < CFG_SATA_MAXDEVICES; i++) {
-		sata_dev_desc[i].type = DEV_TYPE_UNKNOWN;
-		sata_dev_desc[i].if_type = IF_TYPE_IDE;
-		sata_dev_desc[i].dev = i;
-		sata_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
-		sata_dev_desc[i].blksz = 0;
-		sata_dev_desc[i].lba = 0;
-		sata_dev_desc[i].block_read = sata_read;
-	}
+	if (!done)
+		done = 1;
+	else
+		return 0;
 
 	rv = pci_sata_init ();
 	if (rv == 1) {
@@ -205,12 +206,555 @@
 				dev_print (&sata_dev_desc[devno]);
 				/* initialize partition type */
 				init_part (&sata_dev_desc[devno]);
-				if (curr_dev < 0)
-					curr_dev =
+				if (curr_device < 0)
+					curr_device =
 					    i * CFG_SATA_DEVS_PER_BUS + j;
 			}
 		}
 	}
 	return 0;
 }
+
+static u8 __inline__
+sata_inb (unsigned long ioaddr)
+{
+	return inb (ioaddr);
+}
+
+static void __inline__
+sata_outb (unsigned char val, unsigned long ioaddr)
+{
+	outb (val, ioaddr);
+}
+
+static void
+output_data (struct sata_ioports *ioaddr, ulong * sect_buf, int words)
+{
+	outsw (ioaddr->data_addr, sect_buf, words << 1);
+}
+
+static int
+input_data (struct sata_ioports *ioaddr, ulong * sect_buf, int words)
+{
+	insw (ioaddr->data_addr, sect_buf, words << 1);
+	return 0;
+}
+
+static void
+sata_cpy (unsigned char *dst, unsigned char *src, unsigned int len)
+{
+	unsigned char *end, *last;
+
+	last = dst;
+	end = src + len - 1;
+
+	/* reserve space for '\0' */
+	if (len < 2)
+		goto OUT;
+
+	/* skip leading white space */
+	while ((*src) && (src < end) && (*src == ' '))
+		++src;
+
+	/* copy string, omitting trailing white space */
+	while ((*src) && (src < end)) {
+		*dst++ = *src;
+		if (*src++ != ' ')
+			last = dst;
+	}
+      OUT:
+	*last = '\0';
+}
+
+int
+sata_bus_softreset (int num)
+{
+	u8 dev = 0, status = 0, i;
+
+	port[num].dev_mask = 0;
+
+	for (i = 0; i < CFG_SATA_DEVS_PER_BUS; i++) {
+		if (!(sata_devchk (&port[num].ioaddr, i))) {
+			PRINTF ("dev_chk failed for dev#%d\n", i);
+		} else {
+			port[num].dev_mask |= (1 << i);
+			PRINTF ("dev_chk passed for dev#%d\n", i);
+		}
+	}
+
+	if (!(port[num].dev_mask)) {
+		printf ("no devices on port%d\n", num);
+		return 1;
+	}
+
+	dev_select (&port[num].ioaddr, dev);
+
+	port[num].ctl_reg = 0x08;	/*Default value of control reg */
+	sata_outb (port[num].ctl_reg, port[num].ioaddr.ctl_addr);
+	udelay (10);
+	sata_outb (port[num].ctl_reg | ATA_SRST, port[num].ioaddr.ctl_addr);
+	udelay (10);
+	sata_outb (port[num].ctl_reg, port[num].ioaddr.ctl_addr);
+
+	/* 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.
+	 */
+	msleep (150);
+	status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 300);
+	while ((status & ATA_BUSY)) {
+		msleep (100);
+		status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 3);
+	}
+
+	if (status & ATA_BUSY)
+		printf ("ata%u is slow to respond,plz be patient\n", port);
+
+	while ((status & ATA_BUSY)) {
+		msleep (100);
+		status = sata_chk_status (&port[num].ioaddr);
+	}
+
+	if (status & ATA_BUSY) {
+		printf ("ata%u failed to respond : ", port);
+		printf ("bus reset failed\n");
+		return 1;
+	}
+	return 0;
+}
+
+void
+sata_identify (int num, int dev)
+{
+	u8 cmd = 0, status = 0, devno = num * CFG_SATA_DEVS_PER_BUS + dev;
+	u16 iobuf[ATA_SECT_SIZE];
+	u64 n_sectors = 0;
+	u8 mask = 0;
+
+	memset (iobuf, 0, sizeof (iobuf));
+	hd_driveid_t *iop = (hd_driveid_t *) iobuf;
+
+	if (dev == 0)
+		mask = 0x01;
+	else
+		mask = 0x02;
+
+	if (!(port[num].dev_mask & mask)) {
+		printf ("dev%d is not present on port#%d\n", dev, num);
+		return;
+	}
+
+	printf ("port=%d dev=%d\n", num, dev);
+
+	dev_select (&port[num].ioaddr, dev);
+
+	status = 0;
+	cmd = ATA_CMD_IDENT;	/*Device Identify Command */
+	sata_outb (cmd, port[num].ioaddr.command_addr);
+	sata_inb (port[num].ioaddr.altstatus_addr);
+	udelay (10);
+
+	status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 1000);
+	if (status & ATA_ERR) {
+		printf ("\ndevice not responding\n");
+		port[num].dev_mask &= ~mask;
+		return;
+	}
+
+	input_data (&port[num].ioaddr, (ulong *) iobuf, ATA_SECTORWORDS);
+
+	PRINTF ("\nata%u: dev %u cfg 49:%04x 82:%04x 83:%04x 84:%04x85:%04x"
+		"86:%04x" "87:%04x 88:%04x\n", num, dev, iobuf[49],
+		iobuf[82], iobuf[83], iobuf[84], iobuf[85], iobuf[86],
+		iobuf[87], iobuf[88]);
+
+	/* 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", num);
+	}
+	ata_dump_id (iobuf);
+
+	if (ata_id_has_lba48 (iobuf)) {
+		n_sectors = ata_id_u64 (iobuf, 100);
+	} else {
+		n_sectors = ata_id_u32 (iobuf, 60);
+	}
+	PRINTF ("no. of sectors %u\n", ata_id_u64 (iobuf, 100));
+	PRINTF ("no. of sectors %u\n", ata_id_u32 (iobuf, 60));
+
+	if (n_sectors == 0) {
+		port[num].dev_mask &= ~mask;
+		return;
+	}
+
+	sata_cpy (sata_dev_desc[devno].revision, iop->fw_rev,
+		  sizeof (sata_dev_desc[devno].revision));
+	sata_cpy (sata_dev_desc[devno].vendor, iop->model,
+		  sizeof (sata_dev_desc[devno].vendor));
+	sata_cpy (sata_dev_desc[devno].product, iop->serial_no,
+		  sizeof (sata_dev_desc[devno].product));
+	strswab (sata_dev_desc[devno].revision);
+	strswab (sata_dev_desc[devno].vendor);
+
+	if ((iop->config & 0x0080) == 0x0080) {
+		sata_dev_desc[devno].removable = 1;
+	} else {
+		sata_dev_desc[devno].removable = 0;
+	}
+
+	sata_dev_desc[devno].lba = iop->lba_capacity;
+	PRINTF ("lba=0x%x", sata_dev_desc[devno].lba);
+
+#ifdef CONFIG_LBA48
+	if (iop->command_set_2 & 0x0400) {
+		sata_dev_desc[devno].lba48 = 1;
+		lba = (unsigned long long) iop->lba48_capacity[0] |
+		    ((unsigned long long) iop->lba48_capacity[1] << 16) |
+		    ((unsigned long long) iop->lba48_capacity[2] << 32) |
+		    ((unsigned long long) iop->lba48_capacity[3] << 48);
+	} else {
+		sata_dev_desc[devno].lba48 = 0;
+	}
+#endif
+
+	/* assuming HD */
+	sata_dev_desc[devno].type = DEV_TYPE_HARDDISK;
+	sata_dev_desc[devno].blksz = ATA_BLOCKSIZE;
+	sata_dev_desc[devno].lun = 0;	/* just to fill something in... */
+}
+
+void
+set_Feature_cmd (int num, int dev)
+{
+	u8 mask = 0x00, status = 0;
+
+	if (dev == 0)
+		mask = 0x01;
+	else
+		mask = 0x02;
+
+	if (!(port[num].dev_mask & mask)) {
+		PRINTF ("dev%d is not present on port#%d\n", dev, num);
+		return;
+	}
+
+	dev_select (&port[num].ioaddr, dev);
+
+	sata_outb (SETFEATURES_XFER, port[num].ioaddr.feature_addr);
+	sata_outb (XFER_PIO_4, port[num].ioaddr.nsect_addr);
+	sata_outb (0, port[num].ioaddr.lbal_addr);
+	sata_outb (0, port[num].ioaddr.lbam_addr);
+	sata_outb (0, port[num].ioaddr.lbah_addr);
+
+	sata_outb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr);
+	sata_outb (ATA_CMD_SETF, port[num].ioaddr.command_addr);
+
+	udelay (50);
+	msleep (150);
+
+	status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 5000);
+	if ((status & (ATA_STAT_BUSY | ATA_STAT_ERR))) {
+		printf ("Error  : status 0x%02x\n", status);
+		port[num].dev_mask &= ~mask;
+	}
+}
+
+void
+sata_port (struct sata_ioports *ioport)
+{
+	ioport->data_addr = ioport->cmd_addr + ATA_REG_DATA;
+	ioport->error_addr = ioport->cmd_addr + ATA_REG_ERR;
+	ioport->feature_addr = ioport->cmd_addr + ATA_REG_FEATURE;
+	ioport->nsect_addr = ioport->cmd_addr + ATA_REG_NSECT;
+	ioport->lbal_addr = ioport->cmd_addr + ATA_REG_LBAL;
+	ioport->lbam_addr = ioport->cmd_addr + ATA_REG_LBAM;
+	ioport->lbah_addr = ioport->cmd_addr + ATA_REG_LBAH;
+	ioport->device_addr = ioport->cmd_addr + ATA_REG_DEVICE;
+	ioport->status_addr = ioport->cmd_addr + ATA_REG_STATUS;
+	ioport->command_addr = ioport->cmd_addr + ATA_REG_CMD;
+}
+
+int
+sata_devchk (struct sata_ioports *ioaddr, int dev)
+{
+	u8 nsect, lbal;
+
+	dev_select (ioaddr, dev);
+
+	sata_outb (0x55, ioaddr->nsect_addr);
+	sata_outb (0xaa, ioaddr->lbal_addr);
+
+	sata_outb (0xaa, ioaddr->nsect_addr);
+	sata_outb (0x55, ioaddr->lbal_addr);
+
+	sata_outb (0x55, ioaddr->nsect_addr);
+	sata_outb (0xaa, ioaddr->lbal_addr);
+
+	nsect = sata_inb (ioaddr->nsect_addr);
+	lbal = sata_inb (ioaddr->lbal_addr);
+
+	if ((nsect == 0x55) && (lbal == 0xaa))
+		return 1;	/* we found a device */
+	else
+		return 0;	/* nothing found */
+}
+
+void
+dev_select (struct sata_ioports *ioaddr, int dev)
+{
+	u8 tmp = 0;
+
+	if (dev == 0)
+		tmp = ATA_DEVICE_OBS;
+	else
+		tmp = ATA_DEVICE_OBS | ATA_DEV1;
+
+	sata_outb (tmp, ioaddr->device_addr);
+	sata_inb (ioaddr->altstatus_addr);
+	udelay (5);
+}
+
+u8
+sata_busy_wait (struct sata_ioports *ioaddr, int bits, unsigned int max)
+{
+	u8 status;
+
+	do {
+		udelay (1000);
+		status = sata_chk_status (ioaddr);
+		max--;
+	} while ((status & bits) && (max > 0));
+
+	return status;
+}
+
+u8
+sata_chk_status (struct sata_ioports * ioaddr)
+{
+	return sata_inb (ioaddr->status_addr);
+}
+
+void
+msleep (int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		udelay (1000);
+}
+
+ulong
+sata_read (int device, ulong blknr,lbaint_t blkcnt, void * buff)
+{
+	ulong n = 0, *buffer = (ulong *)buff;
+	u8 dev = 0, num = 0, mask = 0, status = 0;
+
+#ifdef CONFIG_LBA48
+	unsigned char lba48 = 0;
+
+	if (blknr & 0x0000fffff0000000) {
+		if (!sata_dev_desc[devno].lba48) {
+			printf ("Drive doesn't support 48-bit addressing\n");
+			return 0;
+		}
+		/* more than 28 bits used, use 48bit mode */
+		lba48 = 1;
+	}
+#endif
+	/*Port Number */
+	num = device / CFG_SATA_DEVS_PER_BUS;
+	/*dev on the port */
+	if (device >= CFG_SATA_DEVS_PER_BUS)
+		dev = device - CFG_SATA_DEVS_PER_BUS;
+	else
+		dev = device;
+
+	if (dev == 0)
+		mask = 0x01;
+	else
+		mask = 0x02;
+
+	if (!(port[num].dev_mask & mask)) {
+		printf ("dev%d is not present on port#%d\n", dev, num);
+		return 0;
+	}
+
+	/* Select device */
+	dev_select (&port[num].ioaddr, dev);
+
+	status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500);
+	if (status & ATA_BUSY) {
+		printf ("ata%u failed to respond\n", port[num].port_no);
+		return n;
+	}
+	while (blkcnt-- > 0) {
+		status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500);
+		if (status & ATA_BUSY) {
+			printf ("ata%u failed to respond\n", 0);
+			return n;
+		}
+#ifdef CONFIG_LBA48
+		if (lba48) {
+			/* write high bits */
+			sata_outb (0, port[num].ioaddr.nsect_addr);
+			sata_outb ((blknr >> 24) & 0xFF,
+				   port[num].ioaddr.lbal_addr);
+			sata_outb ((blknr >> 32) & 0xFF,
+				   port[num].ioaddr.lbam_addr);
+			sata_outb ((blknr >> 40) & 0xFF,
+				   port[num].ioaddr.lbah_addr);
+		}
+#endif
+		sata_outb (1, port[num].ioaddr.nsect_addr);
+		sata_outb (((blknr) >> 0) & 0xFF,
+			   port[num].ioaddr.lbal_addr);
+		sata_outb ((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr);
+		sata_outb ((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr);
+
+#ifdef CONFIG_LBA48
+		if (lba48) {
+			sata_outb (ATA_LBA, port[num].ioaddr.device_addr);
+			sata_outb (ATA_CMD_READ_EXT,
+				   port[num].ioaddr.command_addr);
+		} else
+#endif
+		{
+			sata_outb (ATA_LBA | ((blknr >> 24) & 0xF),
+				   port[num].ioaddr.device_addr);
+			sata_outb (ATA_CMD_READ,
+				   port[num].ioaddr.command_addr);
+		}
+
+		msleep (50);
+		/*may take up to 4 sec */
+		status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 4000);
+
+		if ((status & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR))
+		    != ATA_STAT_DRQ) {
+			u8 err = 0;
+
+			printf ("Error no DRQ dev %d blk %ld: sts 0x%02x\n",
+				device, (ulong) blknr, status);
+			err = sata_inb (port[num].ioaddr.error_addr);
+			printf ("Error reg = 0x%x\n", err);
+			return (n);
+		}
+		input_data (&port[num].ioaddr, buffer, ATA_SECTORWORDS);
+		sata_inb (port[num].ioaddr.altstatus_addr);
+		udelay (50);
+
+		++n;
+		++blknr;
+		buffer += ATA_SECTORWORDS;
+	}
+	return n;
+}
+
+ulong
+sata_write (int device, ulong blknr,lbaint_t blkcnt, void * buff)
+{
+	ulong n = 0, *buffer = (ulong *)buff;
+	unsigned char status = 0, num = 0, dev = 0, mask = 0;
+
+#ifdef CONFIG_LBA48
+	unsigned char lba48 = 0;
+
+	if (blknr & 0x0000fffff0000000) {
+		if (!sata_dev_desc[devno].lba48) {
+			printf ("Drive doesn't support 48-bit addressing\n");
+			return 0;
+		}
+		/* more than 28 bits used, use 48bit mode */
+		lba48 = 1;
+	}
+#endif
+	/*Port Number */
+	num = device / CFG_SATA_DEVS_PER_BUS;
+	/*dev on the Port */
+	if (device >= CFG_SATA_DEVS_PER_BUS)
+		dev = device - CFG_SATA_DEVS_PER_BUS;
+	else
+		dev = device;
+
+	if (dev == 0)
+		mask = 0x01;
+	else
+		mask = 0x02;
+
+	/* Select device */
+	dev_select (&port[num].ioaddr, dev);
+
+	status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500);
+	if (status & ATA_BUSY) {
+		printf ("ata%u failed to respond\n", port[num].port_no);
+		return n;
+	}
+
+	while (blkcnt-- > 0) {
+		status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500);
+		if (status & ATA_BUSY) {
+			printf ("ata%u failed to respond\n",
+				port[num].port_no);
+			return n;
+		}
+#ifdef CONFIG_LBA48
+		if (lba48) {
+			/* write high bits */
+			sata_outb (0, port[num].ioaddr.nsect_addr);
+			sata_outb ((blknr >> 24) & 0xFF,
+				   port[num].ioaddr.lbal_addr);
+			sata_outb ((blknr >> 32) & 0xFF,
+				   port[num].ioaddr.lbam_addr);
+			sata_outb ((blknr >> 40) & 0xFF,
+				   port[num].ioaddr.lbah_addr);
+		}
+#endif
+		sata_outb (1, port[num].ioaddr.nsect_addr);
+		sata_outb ((blknr >> 0) & 0xFF, port[num].ioaddr.lbal_addr);
+		sata_outb ((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr);
+		sata_outb ((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr);
+#ifdef CONFIG_LBA48
+		if (lba48) {
+			sata_outb (ATA_LBA, port[num].ioaddr.device_addr);
+			sata_outb (ATA_CMD_WRITE_EXT,
+				   port[num].ioaddr.command_addr);
+		} else
+#endif
+		{
+			sata_outb (ATA_LBA | ((blknr >> 24) & 0xF),
+				   port[num].ioaddr.device_addr);
+			sata_outb (ATA_CMD_WRITE,
+				   port[num].ioaddr.command_addr);
+		}
+
+		msleep (50);
+		/*may take up to 4 sec */
+		status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 4000);
+		if ((status & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR))
+		    != ATA_STAT_DRQ) {
+			printf ("Error no DRQ dev %d blk %ld: sts 0x%02x\n",
+				device, (ulong) blknr, status);
+			return (n);
+		}
+
+		output_data (&port[num].ioaddr, buffer, ATA_SECTORWORDS);
+		sata_inb (port[num].ioaddr.altstatus_addr);
+		udelay (50);
+
+		++n;
+		++blknr;
+		buffer += ATA_SECTORWORDS;
+	}
+	return n;
+}
+
+int scan_sata(int dev)
+{
+	return 0;
+}
+
 #endif
diff --git a/drivers/block/ata_piix.h b/drivers/block/ata_piix.h
new file mode 100644
index 0000000..ed2e4d5
--- /dev/null
+++ b/drivers/block/ata_piix.h
@@ -0,0 +1,90 @@
+
+#if (DEBUG_SATA)
+#define PRINTF(fmt,args...)	printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+struct sata_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 sata_port {
+	unsigned char port_no;		/* primary=0, secondary=1	*/
+	struct sata_ioports ioaddr;	/* ATA cmd/ctl/dma reg blks	*/
+	unsigned char ctl_reg;
+	unsigned char last_ctl;
+	unsigned char port_state;	/* 1-port is available and	*/
+					/* 0-port is not available	*/
+	unsigned char dev_mask;
+};
+
+/***********SATA LIBRARY SPECIFIC DEFINITIONS AND DECLARATIONS**************/
+#ifdef SATA_DECL		/*SATA library specific declarations */
+#define ata_id_has_lba48(id)    ((id)[83] & (1 << 10))
+#define ata_id_has_lba(id)      ((id)[49] & (1 << 9))
+#define ata_id_has_dma(id)      ((id)[49] & (1 << 8))
+#define ata_id_u32(id,n)        \
+	(((u32) (id)[(n) + 1] << 16) | ((u32) (id)[(n)]))
+#define ata_id_u64(id,n)        \
+	(((u64) (id)[(n) + 3] << 48) | \
+	((u64) (id)[(n) + 2] << 32) | \
+	((u64) (id)[(n) + 1] << 16) | \
+	((u64) (id)[(n) + 0]) )
+#endif
+
+#ifdef SATA_DECL		/*SATA library specific declarations */
+static inline void
+ata_dump_id (u16 * id)
+{
+	PRINTF ("49==0x%04x  "
+		"53==0x%04x  "
+		"63==0x%04x  "
+		"64==0x%04x  "
+		"75==0x%04x  \n", id[49], id[53], id[63], id[64], id[75]);
+	PRINTF ("80==0x%04x  "
+		"81==0x%04x  "
+		"82==0x%04x  "
+		"83==0x%04x  "
+		"84==0x%04x  \n", id[80], id[81], id[82], id[83], id[84]);
+	PRINTF ("88==0x%04x  " "93==0x%04x\n", id[88], id[93]);
+}
+#endif
+
+#ifdef SATA_DECL		/*SATA library specific declarations */
+int sata_bus_softreset (int num);
+void sata_identify (int num, int dev);
+void sata_port (struct sata_ioports *ioport);
+void set_Feature_cmd (int num, int dev);
+int sata_devchk (struct sata_ioports *ioaddr, int dev);
+void dev_select (struct sata_ioports *ioaddr, int dev);
+u8 sata_busy_wait (struct sata_ioports *ioaddr, int bits, unsigned int max);
+u8 sata_chk_status (struct sata_ioports *ioaddr);
+ulong sata_read (int device, ulong blknr,lbaint_t blkcnt, void * buffer);
+ulong sata_write (int device,ulong blknr, lbaint_t blkcnt, void * buffer);
+void msleep (int count);
+#endif
+
+/************DRIVER SPECIFIC DEFINITIONS AND DECLARATIONS**************/
+
+#ifdef DRV_DECL			/*Driver specific declaration */
+int init_sata (int dev);
+#endif
+
+#ifdef DRV_DECL			/*Defines Driver Specific variables */
+struct sata_port port[CFG_SATA_MAXBUS];
+#endif
diff --git a/drivers/block/fsl_sata.c b/drivers/block/fsl_sata.c
new file mode 100644
index 0000000..7436c4d
--- /dev/null
+++ b/drivers/block/fsl_sata.c
@@ -0,0 +1,916 @@
+/*
+ * Copyright (C) 2008 Freescale Semiconductor, Inc.
+ *		Dave Liu <daveliu@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <libata.h>
+#include <fis.h>
+#include "fsl_sata.h"
+
+extern block_dev_desc_t sata_dev_desc[CFG_SATA_MAX_DEVICE];
+
+#ifndef CFG_SATA1_FLAGS
+	#define CFG_SATA1_FLAGS	FLAGS_DMA
+#endif
+#ifndef CFG_SATA2_FLAGS
+	#define CFG_SATA2_FLAGS	FLAGS_DMA
+#endif
+
+static struct fsl_sata_info fsl_sata_info[] = {
+#ifdef CONFIG_SATA1
+	{CFG_SATA1, CFG_SATA1_FLAGS},
+#else
+	{0, 0},
+#endif
+#ifdef CONFIG_SATA2
+	{CFG_SATA2, CFG_SATA2_FLAGS},
+#else
+	{0, 0},
+#endif
+};
+
+static inline void mdelay(unsigned long msec)
+{
+	unsigned long i;
+	for (i = 0; i < msec; i++)
+		udelay(1000);
+}
+
+static inline void sdelay(unsigned long sec)
+{
+	unsigned long i;
+	for (i = 0; i < sec; i++)
+		mdelay(1000);
+}
+
+void dprint_buffer(unsigned char *buf, int len)
+{
+	int i, j;
+
+	i = 0;
+	j = 0;
+	printf("\n\r");
+
+	for (i = 0; i < len; i++) {
+		printf("%02x ", *buf++);
+		j++;
+		if (j == 16) {
+			printf("\n\r");
+			j = 0;
+		}
+	}
+	printf("\n\r");
+}
+
+static void fsl_sata_dump_sfis(struct sfis *s)
+{
+	printf("Status FIS dump:\n\r");
+	printf("fis_type:		%02x\n\r", s->fis_type);
+	printf("pm_port_i:		%02x\n\r", s->pm_port_i);
+	printf("status:			%02x\n\r", s->status);
+	printf("error:			%02x\n\r", s->error);
+	printf("lba_low:		%02x\n\r", s->lba_low);
+	printf("lba_mid:		%02x\n\r", s->lba_mid);
+	printf("lba_high:		%02x\n\r", s->lba_high);
+	printf("device:			%02x\n\r", s->device);
+	printf("lba_low_exp:		%02x\n\r", s->lba_low_exp);
+	printf("lba_mid_exp:		%02x\n\r", s->lba_mid_exp);
+	printf("lba_high_exp:		%02x\n\r", s->lba_high_exp);
+	printf("res1:			%02x\n\r", s->res1);
+	printf("sector_count:		%02x\n\r", s->sector_count);
+	printf("sector_count_exp:	%02x\n\r", s->sector_count_exp);
+}
+
+static int ata_wait_register(volatile unsigned *addr, u32 mask,
+			 u32 val, u32 timeout_msec)
+{
+	int i;
+	u32 temp;
+
+	for (i = 0; (((temp = in_le32(addr)) & mask) != val)
+			 && i < timeout_msec; i++)
+		mdelay(1);
+	return (i < timeout_msec) ? 0 : -1;
+}
+
+int init_sata(int dev)
+{
+	u32 length, align;
+	cmd_hdr_tbl_t *cmd_hdr;
+	u32 cda;
+	u32 val32;
+	fsl_sata_reg_t *reg;
+	u32 sig;
+	int i;
+	fsl_sata_t *sata;
+
+	if (dev < 0 || dev > (CFG_SATA_MAX_DEVICE - 1)) {
+		printf("the sata index %d is out of ranges\n\r", dev);
+		return -1;
+	}
+
+	/* Allocate SATA device driver struct */
+	sata = (fsl_sata_t *)malloc(sizeof(fsl_sata_t));
+	if (!sata) {
+		printf("alloc the sata device struct failed\n\r");
+		return -1;
+	}
+	/* Zero all of the device driver struct */
+	memset((void *)sata, 0, sizeof(fsl_sata_t));
+
+	/* Save the private struct to block device struct */
+	sata_dev_desc[dev].priv = (void *)sata;
+
+	sprintf(sata->name, "SATA%d", dev);
+
+	/* Set the controller register base address to device struct */
+	reg = (fsl_sata_reg_t *)(fsl_sata_info[dev].sata_reg_base);
+	sata->reg_base = reg;
+
+	/* Allocate the command header table, 4 bytes aligned */
+	length = sizeof(struct cmd_hdr_tbl);
+	align = SATA_HC_CMD_HDR_TBL_ALIGN;
+	sata->cmd_hdr_tbl_offset = (void *)malloc(length + align);
+	if (!sata) {
+		printf("alloc the command header failed\n\r");
+		return -1;
+	}
+
+	cmd_hdr = (cmd_hdr_tbl_t *)(((u32)sata->cmd_hdr_tbl_offset + align)
+						& ~(align - 1));
+	sata->cmd_hdr = cmd_hdr;
+
+	/* Zero all of the command header table */
+	memset((void *)sata->cmd_hdr_tbl_offset, 0, length + align);
+
+	/* Allocate command descriptor for all command */
+	length = sizeof(struct cmd_desc) * SATA_HC_MAX_CMD;
+	align = SATA_HC_CMD_DESC_ALIGN;
+	sata->cmd_desc_offset = (void *)malloc(length + align);
+	if (!sata->cmd_desc_offset) {
+		printf("alloc the command descriptor failed\n\r");
+		return -1;
+	}
+	sata->cmd_desc = (cmd_desc_t *)(((u32)sata->cmd_desc_offset + align)
+						& ~(align - 1));
+	/* Zero all of command descriptor */
+	memset((void *)sata->cmd_desc_offset, 0, length + align);
+
+	/* Link the command descriptor to command header */
+	for (i = 0; i < SATA_HC_MAX_CMD; i++) {
+		cda = ((u32)sata->cmd_desc + SATA_HC_CMD_DESC_SIZE * i)
+					 & ~(CMD_HDR_CDA_ALIGN - 1);
+		cmd_hdr->cmd_slot[i].cda = cpu_to_le32(cda);
+	}
+
+	/* To have safe state, force the controller offline */
+	val32 = in_le32(&reg->hcontrol);
+	val32 &= ~HCONTROL_ONOFF;
+	val32 |= HCONTROL_FORCE_OFFLINE;
+	out_le32(&reg->hcontrol, val32);
+
+	/* Wait the controller offline */
+	ata_wait_register(&reg->hstatus, HSTATUS_ONOFF, 0, 1000);
+
+	/* Set the command header base address to CHBA register to tell DMA */
+	out_le32(&reg->chba, (u32)cmd_hdr & ~0x3);
+
+	/* Snoop for the command header */
+	val32 = in_le32(&reg->hcontrol);
+	val32 |= HCONTROL_HDR_SNOOP;
+	out_le32(&reg->hcontrol, val32);
+
+	/* Disable all of interrupts */
+	val32 = in_le32(&reg->hcontrol);
+	val32 &= ~HCONTROL_INT_EN_ALL;
+	out_le32(&reg->hcontrol, val32);
+
+	/* Clear all of interrupts */
+	val32 = in_le32(&reg->hstatus);
+	out_le32(&reg->hstatus, val32);
+
+	/* Set the ICC, no interrupt coalescing */
+	out_le32(&reg->icc, 0x01000000);
+
+	/* No PM attatched, the SATA device direct connect */
+	out_le32(&reg->cqpmp, 0);
+
+	/* Clear SError register */
+	val32 = in_le32(&reg->serror);
+	out_le32(&reg->serror, val32);
+
+	/* Clear CER register */
+	val32 = in_le32(&reg->cer);
+	out_le32(&reg->cer, val32);
+
+	/* Clear DER register */
+	val32 = in_le32(&reg->der);
+	out_le32(&reg->der, val32);
+
+	/* No device detection or initialization action requested */
+	out_le32(&reg->scontrol, 0x00000300);
+
+	/* Configure the transport layer, default value */
+	out_le32(&reg->transcfg, 0x08000016);
+
+	/* Configure the link layer, default value */
+	out_le32(&reg->linkcfg, 0x0000ff34);
+
+	/* Bring the controller online */
+	val32 = in_le32(&reg->hcontrol);
+	val32 |= HCONTROL_ONOFF;
+	out_le32(&reg->hcontrol, val32);
+
+	mdelay(100);
+
+	/* print sata device name */
+	if (!dev)
+		printf("%s ", sata->name);
+	else
+		printf("       %s ", sata->name);
+
+	/* Check PHYRDY */
+	val32 = in_le32(&reg->hstatus);
+	if (val32 & HSTATUS_PHY_RDY) {
+		sata->link = 1;
+	} else {
+		sata->link = 0;
+		printf("(No RDY)\n\r");
+		return -1;
+	}
+
+	if (val32 & HSTATUS_SIGNATURE) {
+		sig = in_le32(&reg->sig);
+		debug("Signature updated, the sig =%08x\n\r", sig);
+		sata->ata_device_type = ata_dev_classify(sig);
+	}
+
+	/* Check the speed */
+	val32 = in_le32(&reg->sstatus);
+	if ((val32 & SSTATUS_SPD_MASK) == SSTATUS_SPD_GEN1)
+		printf("(1.5 Gbps)\n\r");
+	else if ((val32 & SSTATUS_SPD_MASK) == SSTATUS_SPD_GEN2)
+		printf("(3 Gbps)\n\r");
+
+	return 0;
+}
+
+/* Hardware reset, like Power-on and COMRESET */
+void fsl_sata_hardware_reset(u32 reg_base)
+{
+	fsl_sata_reg_t *reg = (fsl_sata_reg_t *)reg_base;
+	u32 scontrol;
+
+	/* Disable the SATA interface and put PHY offline */
+	scontrol = in_le32(&reg->scontrol);
+	scontrol = (scontrol & 0x0f0) | 0x304;
+	out_le32(&reg->scontrol, scontrol);
+
+	/* No speed strict */
+	scontrol = in_le32(&reg->scontrol);
+	scontrol = scontrol & ~0x0f0;
+	out_le32(&reg->scontrol, scontrol);
+
+	/* Issue PHY wake/reset, Hardware_reset_asserted */
+	scontrol = in_le32(&reg->scontrol);
+	scontrol = (scontrol & 0x0f0) | 0x301;
+	out_le32(&reg->scontrol, scontrol);
+
+	mdelay(100);
+
+	/* Resume PHY, COMRESET negated, the device initialize hardware
+	 * and execute diagnostics, send good status-signature to host,
+	 * which is D2H register FIS, and then the device enter idle state.
+	 */
+	scontrol = in_le32(&reg->scontrol);
+	scontrol = (scontrol & 0x0f0) | 0x300;
+	out_le32(&reg->scontrol, scontrol);
+
+	mdelay(100);
+	return;
+}
+
+static void fsl_sata_dump_regs(fsl_sata_reg_t *reg)
+{
+	printf("\n\rSATA:           %08x\n\r", (u32)reg);
+	printf("CQR:            %08x\n\r", in_le32(&reg->cqr));
+	printf("CAR:            %08x\n\r", in_le32(&reg->car));
+	printf("CCR:            %08x\n\r", in_le32(&reg->ccr));
+	printf("CER:            %08x\n\r", in_le32(&reg->cer));
+	printf("CQR:            %08x\n\r", in_le32(&reg->cqr));
+	printf("DER:            %08x\n\r", in_le32(&reg->der));
+	printf("CHBA:           %08x\n\r", in_le32(&reg->chba));
+	printf("HStatus:        %08x\n\r", in_le32(&reg->hstatus));
+	printf("HControl:       %08x\n\r", in_le32(&reg->hcontrol));
+	printf("CQPMP:          %08x\n\r", in_le32(&reg->cqpmp));
+	printf("SIG:            %08x\n\r", in_le32(&reg->sig));
+	printf("ICC:            %08x\n\r", in_le32(&reg->icc));
+	printf("SStatus:        %08x\n\r", in_le32(&reg->sstatus));
+	printf("SError:         %08x\n\r", in_le32(&reg->serror));
+	printf("SControl:       %08x\n\r", in_le32(&reg->scontrol));
+	printf("SNotification:  %08x\n\r", in_le32(&reg->snotification));
+	printf("TransCfg:       %08x\n\r", in_le32(&reg->transcfg));
+	printf("TransStatus:    %08x\n\r", in_le32(&reg->transstatus));
+	printf("LinkCfg:        %08x\n\r", in_le32(&reg->linkcfg));
+	printf("LinkCfg1:       %08x\n\r", in_le32(&reg->linkcfg1));
+	printf("LinkCfg2:       %08x\n\r", in_le32(&reg->linkcfg2));
+	printf("LinkStatus:     %08x\n\r", in_le32(&reg->linkstatus));
+	printf("LinkStatus1:    %08x\n\r", in_le32(&reg->linkstatus1));
+	printf("PhyCtrlCfg:     %08x\n\r", in_le32(&reg->phyctrlcfg));
+	printf("SYSPR:          %08x\n\r", in_be32(&reg->syspr));
+}
+
+static int fsl_ata_exec_ata_cmd(struct fsl_sata *sata, struct cfis *cfis,
+				int is_ncq, int tag, u8 *buffer, u32 len)
+{
+	cmd_hdr_entry_t *cmd_hdr;
+	cmd_desc_t *cmd_desc;
+	sata_fis_h2d_t *h2d;
+	prd_entry_t *prde;
+	u32 ext_c_ddc;
+	u32 prde_count;
+	u32 val32;
+	u32 ttl;
+	fsl_sata_reg_t *reg = sata->reg_base;
+	int i;
+
+	/* Check xfer length */
+	if (len > SATA_HC_MAX_XFER_LEN) {
+		printf("max transfer length is 64MB\n\r");
+		return 0;
+	}
+
+	/* Setup the command descriptor */
+	cmd_desc = sata->cmd_desc + tag;
+
+	/* Get the pointer cfis of command descriptor */
+	h2d = (sata_fis_h2d_t *)cmd_desc->cfis;
+
+	/* Zero the cfis of command descriptor */
+	memset((void *)h2d, 0, SATA_HC_CMD_DESC_CFIS_SIZE);
+
+	/* Copy the cfis from user to command descriptor */
+	h2d->fis_type = cfis->fis_type;
+	h2d->pm_port_c = cfis->pm_port_c;
+	h2d->command = cfis->command;
+
+	h2d->features = cfis->features;
+	h2d->features_exp = cfis->features_exp;
+
+	h2d->lba_low = cfis->lba_low;
+	h2d->lba_mid = cfis->lba_mid;
+	h2d->lba_high = cfis->lba_high;
+	h2d->lba_low_exp = cfis->lba_low_exp;
+	h2d->lba_mid_exp = cfis->lba_mid_exp;
+	h2d->lba_high_exp = cfis->lba_high_exp;
+
+	if (!is_ncq) {
+		h2d->sector_count = cfis->sector_count;
+		h2d->sector_count_exp = cfis->sector_count_exp;
+	} else { /* NCQ */
+		h2d->sector_count = (u8)(tag << 3);
+	}
+
+	h2d->device = cfis->device;
+	h2d->control = cfis->control;
+
+	/* Setup the PRD table */
+	prde = (prd_entry_t *)cmd_desc->prdt;
+	memset((void *)prde, 0, sizeof(struct prdt));
+
+	prde_count = 0;
+	ttl = len;
+	for (i = 0; i < SATA_HC_MAX_PRD_DIRECT; i++) {
+		if (!len)
+			break;
+		prde->dba = cpu_to_le32((u32)buffer & ~0x3);
+		debug("dba = %08x\n\r", (u32)buffer);
+
+		if (len < PRD_ENTRY_MAX_XFER_SZ) {
+			ext_c_ddc = PRD_ENTRY_DATA_SNOOP | len;
+			debug("ext_c_ddc1 = %08x, len = %08x\n\r", ext_c_ddc, len);
+			prde->ext_c_ddc = cpu_to_le32(ext_c_ddc);
+			prde_count++;
+			prde++;
+			break;
+		} else {
+			ext_c_ddc = PRD_ENTRY_DATA_SNOOP; /* 4M bytes */
+			debug("ext_c_ddc2 = %08x, len = %08x\n\r", ext_c_ddc, len);
+			prde->ext_c_ddc = cpu_to_le32(ext_c_ddc);
+			buffer += PRD_ENTRY_MAX_XFER_SZ;
+			len -= PRD_ENTRY_MAX_XFER_SZ;
+			prde_count++;
+			prde++;
+		}
+	}
+
+	/* Setup the command slot of cmd hdr */
+	cmd_hdr = (cmd_hdr_entry_t *)&sata->cmd_hdr->cmd_slot[tag];
+
+	cmd_hdr->cda = cpu_to_le32((u32)cmd_desc & ~0x3);
+
+	val32 = prde_count << CMD_HDR_PRD_ENTRY_SHIFT;
+	val32 |= sizeof(sata_fis_h2d_t);
+	cmd_hdr->prde_fis_len = cpu_to_le32(val32);
+
+	cmd_hdr->ttl = cpu_to_le32(ttl);
+
+	if (!is_ncq) {
+		val32 = CMD_HDR_ATTR_RES | CMD_HDR_ATTR_SNOOP;
+	} else {
+		val32 = CMD_HDR_ATTR_RES | CMD_HDR_ATTR_SNOOP | CMD_HDR_ATTR_FPDMA;
+	}
+
+	tag &= CMD_HDR_ATTR_TAG;
+	val32 |= tag;
+
+	debug("attribute = %08x\n\r", val32);
+	cmd_hdr->attribute = cpu_to_le32(val32);
+
+	/* Make sure cmd desc and cmd slot valid before commmand issue */
+	sync();
+
+	/* PMP*/
+	val32 = (u32)(h2d->pm_port_c & 0x0f);
+	out_le32(&reg->cqpmp, val32);
+
+	/* Wait no active */
+	if (ata_wait_register(&reg->car, (1 << tag), 0, 10000))
+		printf("Wait no active time out\n\r");
+
+	/* Issue command */
+	if (!(in_le32(&reg->cqr) & (1 << tag))) {
+		val32 = 1 << tag;
+		out_le32(&reg->cqr, val32);
+	}
+
+	/* Wait command completed for 10s */
+	if (ata_wait_register(&reg->ccr, (1 << tag), (1 << tag), 10000)) {
+		if (!is_ncq)
+			printf("Non-NCQ command time out\n\r");
+		else
+			printf("NCQ command time out\n\r");
+	}
+
+	val32 = in_le32(&reg->cer);
+
+	if (val32) {
+		u32 der;
+		fsl_sata_dump_sfis((struct sfis *)cmd_desc->sfis);
+		printf("CE at device\n\r");
+		fsl_sata_dump_regs(reg);
+		der = in_le32(&reg->der);
+		out_le32(&reg->cer, val32);
+		out_le32(&reg->der, der);
+	}
+
+	/* Clear complete flags */
+	val32 = in_le32(&reg->ccr);
+	out_le32(&reg->ccr, val32);
+
+	return len;
+}
+
+static int fsl_ata_exec_reset_cmd(struct fsl_sata *sata, struct cfis *cfis,
+				 int tag, u8 *buffer, u32 len)
+{
+	return 0;
+}
+
+static int fsl_sata_exec_cmd(struct fsl_sata *sata, struct cfis *cfis,
+		 enum cmd_type command_type, int tag, u8 *buffer, u32 len)
+{
+	int rc;
+
+	if (tag > SATA_HC_MAX_CMD || tag < 0) {
+		printf("tag is out of range, tag=\n\r", tag);
+		return -1;
+	}
+
+	switch (command_type) {
+	case CMD_ATA:
+		rc = fsl_ata_exec_ata_cmd(sata, cfis, 0, tag, buffer, len);
+		return rc;
+	case CMD_RESET:
+		rc = fsl_ata_exec_reset_cmd(sata, cfis, tag, buffer, len);
+		return rc;
+	case CMD_NCQ:
+		rc = fsl_ata_exec_ata_cmd(sata, cfis, 1, tag, buffer, len);
+		return rc;
+	case CMD_ATAPI:
+	case CMD_VENDOR_BIST:
+	case CMD_BIST:
+		printf("not support now\n\r");
+		return -1;
+	default:
+		break;
+	}
+
+	return -1;
+}
+
+static void fsl_sata_identify(int dev, u16 *id)
+{
+	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
+	struct sata_fis_h2d h2d;
+	struct cfis *cfis;
+
+	cfis = (struct cfis *)&h2d;
+	memset((void *)cfis, 0, sizeof(struct cfis));
+
+	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+	cfis->pm_port_c = 0x80; /* is command */
+	cfis->command = ATA_CMD_ID_ATA;
+
+	fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, (u8 *)id, ATA_ID_WORDS * 2);
+	ata_swap_buf_le16(id, ATA_ID_WORDS);
+}
+
+static void fsl_sata_xfer_mode(int dev, u16 *id)
+{
+	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
+
+	sata->pio = id[ATA_ID_PIO_MODES];
+	sata->mwdma = id[ATA_ID_MWDMA_MODES];
+	sata->udma = id[ATA_ID_UDMA_MODES];
+	debug("pio %04x, mwdma %04x, udma %04x\n\r", sata->pio, sata->mwdma, sata->udma);
+}
+
+static void fsl_sata_set_features(int dev)
+{
+	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
+	struct sata_fis_h2d h2d;
+	struct cfis *cfis;
+	u8 udma_cap;
+
+	cfis = (struct cfis *)&h2d;
+	memset((void *)cfis, 0, sizeof(struct cfis));
+
+	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+	cfis->pm_port_c = 0x80; /* is command */
+	cfis->command = ATA_CMD_SET_FEATURES;
+	cfis->features = SETFEATURES_XFER;
+
+	/* First check the device capablity */
+	udma_cap = (u8)(sata->udma & 0xff);
+	debug("udma_cap %02x\n\r", udma_cap);
+
+	if (udma_cap == ATA_UDMA6)
+		cfis->sector_count = XFER_UDMA_6;
+	if (udma_cap == ATA_UDMA5)
+		cfis->sector_count = XFER_UDMA_5;
+	if (udma_cap == ATA_UDMA4)
+		cfis->sector_count = XFER_UDMA_4;
+	if (udma_cap == ATA_UDMA3)
+		cfis->sector_count = XFER_UDMA_3;
+
+	fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0);
+}
+
+static u32 fsl_sata_rw_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write)
+{
+	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
+	struct sata_fis_h2d h2d;
+	struct cfis *cfis;
+	u32 block;
+
+	block = start;
+	cfis = (struct cfis *)&h2d;
+
+	memset((void *)cfis, 0, sizeof(struct cfis));
+
+	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+	cfis->pm_port_c = 0x80; /* is command */
+	cfis->command = (is_write) ? ATA_CMD_WRITE_DMA : ATA_CMD_READ_DMA;
+	cfis->device = ATA_LBA;
+
+	cfis->device |= (block >> 24) & 0xf;
+	cfis->lba_high = (block >> 16) & 0xff;
+	cfis->lba_mid = (block >> 8) & 0xff;
+	cfis->lba_low = block & 0xff;
+	cfis->sector_count = (u8)(blkcnt & 0xff);
+
+	fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, buffer, ATA_SECT_SIZE * blkcnt);
+	return blkcnt;
+}
+
+void fsl_sata_flush_cache(int dev)
+{
+	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
+	struct sata_fis_h2d h2d;
+	struct cfis *cfis;
+
+	cfis = (struct cfis *)&h2d;
+
+	memset((void *)cfis, 0, sizeof(struct cfis));
+
+	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+	cfis->pm_port_c = 0x80; /* is command */
+	cfis->command = ATA_CMD_FLUSH_CACHE;
+
+	fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0);
+}
+
+static u32 fsl_sata_rw_cmd_ext(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write)
+{
+	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
+	struct sata_fis_h2d h2d;
+	struct cfis *cfis;
+	u64 block;
+
+	block = (u64)start;
+	cfis = (struct cfis *)&h2d;
+
+	memset((void *)cfis, 0, sizeof(struct cfis));
+
+	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+	cfis->pm_port_c = 0x80; /* is command */
+
+	cfis->command = (is_write) ? ATA_CMD_WRITE_DMA_EXT
+				 : ATA_CMD_READ_DMA_EXT;
+
+	cfis->lba_high_exp = (block >> 40) & 0xff;
+	cfis->lba_mid_exp = (block >> 32) & 0xff;
+	cfis->lba_low_exp = (block >> 24) & 0xff;
+	cfis->lba_high = (block >> 16) & 0xff;
+	cfis->lba_mid = (block >> 8) & 0xff;
+	cfis->lba_low = block & 0xff;
+	cfis->device = ATA_LBA;
+	cfis->sector_count_exp = (blkcnt >> 8) & 0xff;
+	cfis->sector_count = blkcnt & 0xff;
+
+	fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, buffer, ATA_SECT_SIZE * blkcnt);
+	return blkcnt;
+}
+
+u32 fsl_sata_rw_ncq_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write)
+{
+	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
+	struct sata_fis_h2d h2d;
+	struct cfis *cfis;
+	int ncq_channel;
+	u64 block;
+
+	if (sata_dev_desc[dev].lba48 != 1) {
+		printf("execute FPDMA command on non-LBA48 hard disk\n\r");
+		return -1;
+	}
+
+	block = (u64)start;
+	cfis = (struct cfis *)&h2d;
+
+	memset((void *)cfis, 0, sizeof(struct cfis));
+
+	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+	cfis->pm_port_c = 0x80; /* is command */
+
+	cfis->command = (is_write) ? ATA_CMD_WRITE_FPDMA_QUEUED
+				 : ATA_CMD_READ_FPDMA_QUEUED;
+
+	cfis->lba_high_exp = (block >> 40) & 0xff;
+	cfis->lba_mid_exp = (block >> 32) & 0xff;
+	cfis->lba_low_exp = (block >> 24) & 0xff;
+	cfis->lba_high = (block >> 16) & 0xff;
+	cfis->lba_mid = (block >> 8) & 0xff;
+	cfis->lba_low = block & 0xff;
+
+	cfis->device = ATA_LBA;
+	cfis->features_exp = (blkcnt >> 8) & 0xff;
+	cfis->features = blkcnt & 0xff;
+
+	if (sata->queue_depth >= SATA_HC_MAX_CMD)
+		ncq_channel = SATA_HC_MAX_CMD - 1;
+	else
+		ncq_channel = sata->queue_depth - 1;
+
+	/* Use the latest queue */
+	fsl_sata_exec_cmd(sata, cfis, CMD_NCQ, ncq_channel, buffer, ATA_SECT_SIZE * blkcnt);
+	return blkcnt;
+}
+
+void fsl_sata_flush_cache_ext(int dev)
+{
+	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
+	struct sata_fis_h2d h2d;
+	struct cfis *cfis;
+
+	cfis = (struct cfis *)&h2d;
+
+	memset((void *)cfis, 0, sizeof(struct cfis));
+
+	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+	cfis->pm_port_c = 0x80; /* is command */
+	cfis->command = ATA_CMD_FLUSH_CACHE_EXT;
+
+	fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0);
+}
+
+/* Software reset, set SRST of the Device Control register */
+void fsl_sata_software_reset(int dev)
+{
+	return;
+}
+
+static void fsl_sata_init_wcache(int dev, u16 *id)
+{
+	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
+
+	if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id))
+		sata->wcache = 1;
+	if (ata_id_has_flush(id))
+		sata->flush = 1;
+	if (ata_id_has_flush_ext(id))
+		sata->flush_ext = 1;
+}
+
+static int fsl_sata_get_wcache(int dev)
+{
+	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
+	return sata->wcache;
+}
+
+static int fsl_sata_get_flush(int dev)
+{
+	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
+	return sata->flush;
+}
+
+static int fsl_sata_get_flush_ext(int dev)
+{
+	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
+	return sata->flush_ext;
+}
+
+u32 ata_low_level_rw_lba48(int dev, u32 blknr, u32 blkcnt, void *buffer, int is_write)
+{
+	u32 start, blks;
+	u8 *addr;
+	int max_blks;
+
+	start = blknr;
+	blks = blkcnt;
+	addr = (u8 *)buffer;
+
+	max_blks = ATA_MAX_SECTORS_LBA48;
+	do {
+		if (blks > max_blks) {
+			if (fsl_sata_info[dev].flags != FLAGS_FPDMA)
+				fsl_sata_rw_cmd_ext(dev, start, max_blks, addr, is_write);
+			else
+				fsl_sata_rw_ncq_cmd(dev, start, max_blks, addr, is_write);
+			start += max_blks;
+			blks -= max_blks;
+			addr += ATA_SECT_SIZE * max_blks;
+		} else {
+			if (fsl_sata_info[dev].flags != FLAGS_FPDMA)
+				fsl_sata_rw_cmd_ext(dev, start, blks, addr, is_write);
+			else
+				fsl_sata_rw_ncq_cmd(dev, start, blks, addr, is_write);
+			start += blks;
+			blks = 0;
+			addr += ATA_SECT_SIZE * blks;
+		}
+	} while (blks != 0);
+
+	return blkcnt;
+}
+
+u32 ata_low_level_rw_lba28(int dev, u32 blknr, u32 blkcnt, void *buffer, int is_write)
+{
+	u32 start, blks;
+	u8 *addr;
+	int max_blks;
+
+	start = blknr;
+	blks = blkcnt;
+	addr = (u8 *)buffer;
+
+	max_blks = ATA_MAX_SECTORS;
+	do {
+		if (blks > max_blks) {
+			fsl_sata_rw_cmd(dev, start, max_blks, addr, is_write);
+			start += max_blks;
+			blks -= max_blks;
+			addr += ATA_SECT_SIZE * max_blks;
+		} else {
+			fsl_sata_rw_cmd(dev, start, blks, addr, is_write);
+			start += blks;
+			blks = 0;
+			addr += ATA_SECT_SIZE * blks;
+		}
+	} while (blks != 0);
+
+	return blkcnt;
+}
+
+/*
+ * SATA interface between low level driver and command layer
+ */
+ulong sata_read(int dev, u32 blknr, u32 blkcnt, void *buffer)
+{
+	u32 rc;
+
+	if (sata_dev_desc[dev].lba48)
+		rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, READ_CMD);
+	else
+		rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, buffer, READ_CMD);
+	return rc;
+}
+
+ulong sata_write(int dev, u32 blknr, u32 blkcnt, void *buffer)
+{
+	u32 rc;
+
+	if (sata_dev_desc[dev].lba48) {
+		rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, WRITE_CMD);
+		if (fsl_sata_get_wcache(dev) && fsl_sata_get_flush_ext(dev))
+			fsl_sata_flush_cache_ext(dev);
+	} else {
+		rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, buffer, WRITE_CMD);
+		if (fsl_sata_get_wcache(dev) && fsl_sata_get_flush(dev))
+			fsl_sata_flush_cache(dev);
+	}
+	return rc;
+}
+
+int scan_sata(int dev)
+{
+	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
+	unsigned char serial[ATA_ID_SERNO_LEN + 1];
+	unsigned char firmware[ATA_ID_FW_REV_LEN + 1];
+	unsigned char product[ATA_ID_PROD_LEN + 1];
+	u16 *id;
+	u64 n_sectors;
+
+	/* if no detected link */
+	if (!sata->link)
+		return -1;
+
+	id = (u16 *)malloc(ATA_ID_WORDS * 2);
+	if (!id) {
+		printf("id malloc failed\n\r");
+		return -1;
+	}
+
+	/* Identify device to get information */
+	fsl_sata_identify(dev, id);
+
+	/* Serial number */
+	ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial));
+	memcpy(sata_dev_desc[dev].product, serial, sizeof(serial));
+
+	/* Firmware version */
+	ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware));
+	memcpy(sata_dev_desc[dev].revision, firmware, sizeof(firmware));
+
+	/* Product model */
+	ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product));
+	memcpy(sata_dev_desc[dev].vendor, product, sizeof(product));
+
+	/* Totoal sectors */
+	n_sectors = ata_id_n_sectors(id);
+	sata_dev_desc[dev].lba = (u32)n_sectors;
+
+	/* Check if support LBA48 */
+	if (ata_id_has_lba48(id)) {
+		sata_dev_desc[dev].lba48 = 1;
+		debug("Device support LBA48\n\r");
+	}
+
+	/* Get the NCQ queue depth from device */
+	sata->queue_depth = ata_id_queue_depth(id);
+
+	/* Get the xfer mode from device */
+	fsl_sata_xfer_mode(dev, id);
+
+	/* Get the write cache status from device */
+	fsl_sata_init_wcache(dev, id);
+
+	/* Set the xfer mode to highest speed */
+	fsl_sata_set_features(dev);
+#ifdef DEBUG
+	fsl_sata_identify(dev, id);
+	ata_dump_id(id);
+#endif
+	free((void *)id);
+	return 0;
+}
diff --git a/drivers/block/fsl_sata.h b/drivers/block/fsl_sata.h
new file mode 100644
index 0000000..874c0dc
--- /dev/null
+++ b/drivers/block/fsl_sata.h
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2007-2008 Freescale Semiconductor, Inc.
+ *		Dave Liu <daveliu@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __FSL_SATA_H__
+#define __FSL_SATA_H__
+
+#define SATA_HC_MAX_NUM		4 /* Max host controller numbers */
+#define SATA_HC_MAX_CMD		16 /* Max command queue depth per host controller */
+#define SATA_HC_MAX_PORT	16 /* Max port number per host controller */
+
+/*
+* SATA Host Controller Registers
+*/
+typedef struct fsl_sata_reg {
+	/* SATA command registers */
+	u32 cqr;		/* Command queue register */
+	u8 res1[0x4];
+	u32 car;		/* Command active register */
+	u8 res2[0x4];
+	u32 ccr;		/* Command completed register */
+	u8 res3[0x4];
+	u32 cer;		/* Command error register */
+	u8 res4[0x4];
+	u32 der;		/* Device error register */
+	u32 chba;		/* Command header base address */
+	u32 hstatus;		/* Host status register */
+	u32 hcontrol;		/* Host control register */
+	u32 cqpmp;		/* Port number queue register */
+	u32 sig;		/* Signature register */
+	u32 icc;		/* Interrupt coalescing control register */
+	u8 res5[0xc4];
+
+	/* SATA supperset registers */
+	u32 sstatus;		/* SATA interface status register */
+	u32 serror;		/* SATA interface error register */
+	u32 scontrol;		/* SATA interface control register */
+	u32 snotification;	/* SATA interface notification register */
+	u8 res6[0x30];
+
+	/* SATA control status registers */
+	u32 transcfg;		/* Transport layer configuration */
+	u32 transstatus;	/* Transport layer status */
+	u32 linkcfg;		/* Link layer configuration */
+	u32 linkcfg1;		/* Link layer configuration1 */
+	u32 linkcfg2;		/* Link layer configuration2 */
+	u32 linkstatus;		/* Link layer status */
+	u32 linkstatus1;	/* Link layer status1 */
+	u32 phyctrlcfg;		/* PHY control configuration */
+	u8 res7[0x2b0];
+
+	/* SATA system control registers */
+	u32 syspr;		/* System priority register - big endian */
+	u8 res8[0xbec];
+} __attribute__ ((packed)) fsl_sata_reg_t;
+
+/* HStatus register
+*/
+#define HSTATUS_ONOFF			0x80000000 /* Online/offline status */
+#define HSTATUS_FORCE_OFFLINE		0x40000000 /* In process going offline */
+#define HSTATUS_BIST_ERR		0x20000000
+
+/* Fatal error */
+#define HSTATUS_MASTER_ERR		0x00004000
+#define HSTATUS_DATA_UNDERRUN		0x00002000
+#define HSTATUS_DATA_OVERRUN		0x00001000
+#define HSTATUS_CRC_ERR_TX		0x00000800
+#define HSTATUS_CRC_ERR_RX		0x00000400
+#define HSTATUS_FIFO_OVERFLOW_TX	0x00000200
+#define HSTATUS_FIFO_OVERFLOW_RX	0x00000100
+#define HSTATUS_FATAL_ERR_ALL		(HSTATUS_MASTER_ERR | \
+					HSTATUS_DATA_UNDERRUN | \
+					HSTATUS_DATA_OVERRUN | \
+					HSTATUS_CRC_ERR_TX | \
+					HSTATUS_CRC_ERR_RX | \
+					HSTATUS_FIFO_OVERFLOW_TX | \
+					HSTATUS_FIFO_OVERFLOW_RX)
+/* Interrupt status */
+#define HSTATUS_FATAL_ERR		0x00000020
+#define HSTATUS_PHY_RDY			0x00000010
+#define HSTATUS_SIGNATURE		0x00000008
+#define HSTATUS_SNOTIFY			0x00000004
+#define HSTATUS_DEVICE_ERR		0x00000002
+#define HSTATUS_CMD_COMPLETE		0x00000001
+
+/* HControl register
+*/
+#define HCONTROL_ONOFF			0x80000000 /* Online or offline request */
+#define HCONTROL_FORCE_OFFLINE		0x40000000 /* Force offline request */
+#define HCONTROL_HDR_SNOOP		0x00000400 /* Command header snoop */
+#define HCONTROL_PMP_ATTACHED		0x00000200 /* Port multiplier attached */
+
+/* Interrupt enable */
+#define HCONTROL_FATAL_ERR		0x00000020
+#define HCONTROL_PHY_RDY		0x00000010
+#define HCONTROL_SIGNATURE		0x00000008
+#define HCONTROL_SNOTIFY		0x00000004
+#define HCONTROL_DEVICE_ERR		0x00000002
+#define HCONTROL_CMD_COMPLETE		0x00000001
+
+#define HCONTROL_INT_EN_ALL		(HCONTROL_FATAL_ERR | \
+					HCONTROL_PHY_RDY | \
+					HCONTROL_SIGNATURE | \
+					HCONTROL_SNOTIFY | \
+					HCONTROL_DEVICE_ERR | \
+					HCONTROL_CMD_COMPLETE)
+
+/* SStatus register
+*/
+#define SSTATUS_IPM_MASK		0x00000780
+#define SSTATUS_IPM_NOPRESENT		0x00000000
+#define SSTATUS_IPM_ACTIVE		0x00000080
+#define SSTATUS_IPM_PATIAL		0x00000100
+#define SSTATUS_IPM_SLUMBER		0x00000300
+
+#define SSTATUS_SPD_MASK		0x000000f0
+#define SSTATUS_SPD_GEN1		0x00000010
+#define SSTATUS_SPD_GEN2		0x00000020
+
+#define SSTATUS_DET_MASK		0x0000000f
+#define SSTATUS_DET_NODEVICE		0x00000000
+#define SSTATUS_DET_DISCONNECT		0x00000001
+#define SSTATUS_DET_CONNECT		0x00000003
+#define SSTATUS_DET_PHY_OFFLINE		0x00000004
+
+/* SControl register
+*/
+#define SCONTROL_SPM_MASK		0x0000f000
+#define SCONTROL_SPM_GO_PARTIAL		0x00001000
+#define SCONTROL_SPM_GO_SLUMBER		0x00002000
+#define SCONTROL_SPM_GO_ACTIVE		0x00004000
+
+#define SCONTROL_IPM_MASK		0x00000f00
+#define SCONTROL_IPM_NO_RESTRICT	0x00000000
+#define SCONTROL_IPM_PARTIAL		0x00000100
+#define SCONTROL_IPM_SLUMBER		0x00000200
+#define SCONTROL_IPM_PART_SLUM		0x00000300
+
+#define SCONTROL_SPD_MASK		0x000000f0
+#define SCONTROL_SPD_NO_RESTRICT	0x00000000
+#define SCONTROL_SPD_GEN1		0x00000010
+#define SCONTROL_SPD_GEN2		0x00000020
+
+#define SCONTROL_DET_MASK		0x0000000f
+#define SCONTROL_DET_HRESET		0x00000001
+#define SCONTROL_DET_DISABLE		0x00000004
+
+/* TransCfg register
+*/
+#define TRANSCFG_DFIS_SIZE_SHIFT	16
+#define TRANSCFG_RX_WATER_MARK_MASK	0x0000001f
+
+/* PhyCtrlCfg register
+*/
+#define PHYCTRLCFG_FPRFTI_MASK		0x00000018
+#define PHYCTRLCFG_LOOPBACK_MASK	0x0000000e
+
+/*
+* Command Header Entry
+*/
+typedef struct cmd_hdr_entry {
+	u32 cda;		/* Command Descriptor Address, 4 bytes aligned */
+	u32 prde_fis_len;	/* Number of PRD entries and FIS length */
+	u32 ttl;		/* Total transfer length */
+	u32 attribute;		/* the attribute of command */
+} __attribute__ ((packed)) cmd_hdr_entry_t;
+
+#define SATA_HC_CMD_HDR_ENTRY_SIZE	sizeof(struct cmd_hdr_entry)
+
+/* cda
+*/
+#define CMD_HDR_CDA_ALIGN	4
+
+/* prde_fis_len
+*/
+#define CMD_HDR_PRD_ENTRY_SHIFT	16
+#define CMD_HDR_PRD_ENTRY_MASK	0x003f0000
+#define CMD_HDR_FIS_LEN_SHIFT	2
+
+/* attribute
+*/
+#define CMD_HDR_ATTR_RES	0x00000800 /* Reserved bit, should be 1 */
+#define CMD_HDR_ATTR_VBIST	0x00000400 /* Vendor BIST */
+#define CMD_HDR_ATTR_SNOOP	0x00000200 /* Snoop enable for all descriptor */
+#define CMD_HDR_ATTR_FPDMA	0x00000100 /* FPDMA queued command */
+#define CMD_HDR_ATTR_RESET	0x00000080 /* Reset - a SRST or device reset */
+#define CMD_HDR_ATTR_BIST	0x00000040 /* BIST - require the host to enter BIST mode */
+#define CMD_HDR_ATTR_ATAPI	0x00000020 /* ATAPI command */
+#define CMD_HDR_ATTR_TAG	0x0000001f /* TAG mask */
+
+/* command type
+*/
+enum cmd_type {
+	CMD_VENDOR_BIST,
+	CMD_BIST,
+	CMD_RESET,	/* SRST or device reset */
+	CMD_ATAPI,
+	CMD_NCQ,
+	CMD_ATA,	/* None of all above */
+};
+
+/*
+* Command Header Table
+*/
+typedef struct cmd_hdr_tbl {
+	cmd_hdr_entry_t cmd_slot[SATA_HC_MAX_CMD];
+} __attribute__ ((packed)) cmd_hdr_tbl_t;
+
+#define SATA_HC_CMD_HDR_TBL_SIZE	sizeof(struct cmd_hdr_tbl)
+#define SATA_HC_CMD_HDR_TBL_ALIGN	4
+
+/*
+* PRD entry - Physical Region Descriptor entry
+*/
+typedef struct prd_entry {
+	u32 dba;	/* Data base address, 4 bytes aligned */
+	u32 res1;
+	u32 res2;
+	u32 ext_c_ddc;	/* Indirect PRD flags, snoop and data word count */
+} __attribute__ ((packed)) prd_entry_t;
+
+#define SATA_HC_CMD_DESC_PRD_SIZE	sizeof(struct prd_entry)
+
+/* dba
+*/
+#define PRD_ENTRY_DBA_ALIGN	4
+
+/* ext_c_ddc
+*/
+#define PRD_ENTRY_EXT		0x80000000 /* extension flag or called indirect descriptor flag */
+#define PRD_ENTRY_DATA_SNOOP	0x00400000 /* Snoop enable for all data associated with the PRD entry */
+#define PRD_ENTRY_LEN_MASK	0x003fffff /* Data word count */
+
+#define PRD_ENTRY_MAX_XFER_SZ	(PRD_ENTRY_LEN_MASK + 1)
+
+/*
+ * This SATA host controller supports a max of 16 direct PRD entries, but if use
+ * chained indirect PRD entries, then the contollers supports upto a max of 63
+ * entries including direct and indirect PRD entries.
+ * The PRDT is an array of 63 PRD entries contigiously, but the PRD entries#15
+ * will be setup as an indirect descriptor, pointing to it's next (contigious)
+ * PRD entries#16.
+ */
+#define SATA_HC_MAX_PRD		63 /* Max PRD entry numbers per command */
+#define SATA_HC_MAX_PRD_DIRECT	16 /* Direct PRDT entries */
+#define SATA_HC_MAX_PRD_USABLE	(SATA_HC_MAX_PRD - 1)
+#define SATA_HC_MAX_XFER_LEN	0x4000000
+
+/*
+* PRDT - Physical Region Descriptor Table
+*/
+typedef struct prdt {
+	prd_entry_t prdt[SATA_HC_MAX_PRD];
+} __attribute__ ((packed)) prdt_t;
+
+/*
+* Command Descriptor
+*/
+#define SATA_HC_CMD_DESC_CFIS_SIZE	32 /* bytes */
+#define SATA_HC_CMD_DESC_SFIS_SIZE	32 /* bytes */
+#define SATA_HC_CMD_DESC_ACMD_SIZE	16 /* bytes */
+#define SATA_HC_CMD_DESC_RES		16 /* bytes */
+
+typedef struct cmd_desc {
+	u8 cfis[SATA_HC_CMD_DESC_CFIS_SIZE];
+	u8 sfis[SATA_HC_CMD_DESC_SFIS_SIZE];
+	u8 acmd[SATA_HC_CMD_DESC_ACMD_SIZE];
+	u8 res[SATA_HC_CMD_DESC_RES];
+	prd_entry_t prdt[SATA_HC_MAX_PRD];
+} __attribute__ ((packed)) cmd_desc_t;
+
+#define SATA_HC_CMD_DESC_SIZE		sizeof(struct cmd_desc)
+#define SATA_HC_CMD_DESC_ALIGN		4
+
+/*
+* CFIS - Command FIS, which is H2D register FIS, the struct defination
+* of Non-Queued command is different than NCQ command. see them is sata2.h
+*/
+typedef struct cfis {
+	u8 fis_type;
+	u8 pm_port_c;
+	u8 command;
+	u8 features;
+	u8 lba_low;
+	u8 lba_mid;
+	u8 lba_high;
+	u8 device;
+	u8 lba_low_exp;
+	u8 lba_mid_exp;
+	u8 lba_high_exp;
+	u8 features_exp;
+	u8 sector_count;
+	u8 sector_count_exp;
+	u8 res1;
+	u8 control;
+	u8 res2[4];
+} __attribute__ ((packed)) cfis_t;
+
+/*
+* SFIS - Status FIS, which is D2H register FIS.
+*/
+typedef struct sfis {
+	u8 fis_type;
+	u8 pm_port_i;
+	u8 status;
+	u8 error;
+	u8 lba_low;
+	u8 lba_mid;
+	u8 lba_high;
+	u8 device;
+	u8 lba_low_exp;
+	u8 lba_mid_exp;
+	u8 lba_high_exp;
+	u8 res1;
+	u8 sector_count;
+	u8 sector_count_exp;
+	u8 res2[2];
+	u8 res3[4];
+} __attribute__ ((packed)) sfis_t;
+
+/*
+ * SATA device driver info
+ */
+typedef struct fsl_sata_info {
+	u32	sata_reg_base;
+	u32	flags;
+} fsl_sata_info_t;
+
+#define FLAGS_DMA	0x00000000
+#define FLAGS_FPDMA	0x00000001
+
+/*
+ * SATA device driver struct
+ */
+typedef struct fsl_sata {
+	char		name[12];
+	fsl_sata_reg_t	*reg_base;		/* the base address of controller register */
+	void		*cmd_hdr_tbl_offset;	/* alloc address of command header table */
+	cmd_hdr_tbl_t	*cmd_hdr;		/* aligned address of command header table */
+	void		*cmd_desc_offset;	/* alloc address of command descriptor */
+	cmd_desc_t	*cmd_desc;		/* aligned address of command descriptor */
+	int		link;			/* PHY link status */
+	/* device attribute */
+	int		ata_device_type;	/* device type */
+	int		lba48;
+	int		queue_depth;		/* Max NCQ queue depth */
+	u16		pio;
+	u16		mwdma;
+	u16		udma;
+	int		wcache;
+	int		flush;
+	int		flush_ext;
+} fsl_sata_t;
+
+#define READ_CMD	0
+#define WRITE_CMD	1
+
+#endif /* __FSL_SATA_H__ */
diff --git a/drivers/block/libata.c b/drivers/block/libata.c
new file mode 100644
index 0000000..bbe16a2
--- /dev/null
+++ b/drivers/block/libata.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2008 Freescale Semiconductor, Inc.
+ *		Dave Liu <daveliu@freescale.com>
+ *		port from the libata of linux kernel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <libata.h>
+
+u64 ata_id_n_sectors(u16 *id)
+{
+	if (ata_id_has_lba(id)) {
+		if (ata_id_has_lba48(id))
+			return ata_id_u64(id, ATA_ID_LBA48_SECTORS);
+		else
+			return ata_id_u32(id, ATA_ID_LBA_SECTORS);
+	} else {
+		return 0;
+	}
+}
+
+u32 ata_dev_classify(u32 sig)
+{
+	u8 lbam, lbah;
+
+	lbam = (sig >> 16) & 0xff;
+	lbah = (sig >> 24) & 0xff;
+
+	if (((lbam == 0) && (lbah == 0)) ||
+		((lbam == 0x3c) && (lbah == 0xc3)))
+		return ATA_DEV_ATA;
+
+	if ((lbam == 0x14) && (lbah == 0xeb))
+		return ATA_DEV_ATAPI;
+
+	if ((lbam == 0x69) && (lbah == 0x96))
+		return ATA_DEV_PMP;
+
+	return ATA_DEV_UNKNOWN;
+}
+
+static void ata_id_string(const u16 *id, unsigned char *s,
+			 unsigned int ofs, unsigned int len)
+{
+	unsigned int c;
+
+	while (len > 0) {
+		c = id[ofs] >> 8;
+		*s = c;
+		s++;
+
+		c = id[ofs] & 0xff;
+		*s = c;
+		s++;
+
+		ofs++;
+		len -= 2;
+	}
+}
+
+void ata_id_c_string(const u16 *id, unsigned char *s,
+			 unsigned int ofs, unsigned int len)
+{
+	unsigned char *p;
+
+	ata_id_string(id, s, ofs, len - 1);
+
+	p = s + strnlen((char *)s, len - 1);
+	while (p > s && p[-1] == ' ')
+		p--;
+	*p = '\0';
+}
+
+void ata_dump_id(u16 *id)
+{
+	unsigned char serial[ATA_ID_SERNO_LEN + 1];
+	unsigned char firmware[ATA_ID_FW_REV_LEN + 1];
+	unsigned char product[ATA_ID_PROD_LEN + 1];
+	u64 n_sectors;
+
+	/* Serial number */
+	ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial));
+	printf("S/N: %s\n\r", serial);
+
+	/* Firmware version */
+	ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware));
+	printf("Firmware version: %s\n\r", firmware);
+
+	/* Product model */
+	ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product));
+	printf("Product model number: %s\n\r", product);
+
+	/* Total sectors of device  */
+	n_sectors = ata_id_n_sectors(id);
+	printf("Capablity: %d sectors\n\r", n_sectors);
+
+	printf ("id[49]: capabilities ==0x%04x\n"
+		"id[53]: field valid ==0x%04x\n"
+		"id[63]: mwdma ==0x%04x\n"
+		"id[64]: pio ==0x%04x\n"
+		"id[75]: queue depth ==0x%04x\n",
+		id[49],
+		id[53],
+		id[63],
+		id[64],
+		id[75]);
+
+	printf ("id[76]: sata capablity ==0x%04x\n"
+		"id[78]: sata features supported ==0x%04x\n"
+		"id[79]: sata features enable ==0x%04x\n",
+		id[76],
+		id[78],
+		id[79]);
+
+	printf ("id[80]: major version ==0x%04x\n"
+		"id[81]: minor version ==0x%04x\n"
+		"id[82]: command set supported 1 ==0x%04x\n"
+		"id[83]: command set supported 2 ==0x%04x\n"
+		"id[84]: command set extension ==0x%04x\n",
+		id[80],
+		id[81],
+		id[82],
+		id[83],
+		id[84]);
+	printf ("id[85]: command set enable 1 ==0x%04x\n"
+		"id[86]: command set enable 2 ==0x%04x\n"
+		"id[87]: command set default ==0x%04x\n"
+		"id[88]: udma ==0x%04x\n"
+		"id[93]: hardware reset result ==0x%04x\n",
+		id[85],
+		id[86],
+		id[87],
+		id[88],
+		id[93]);
+}
+
+void ata_swap_buf_le16(u16 *buf, unsigned int buf_words)
+{
+	unsigned int i;
+
+	for (i = 0; i < buf_words; i++)
+		buf[i] = le16_to_cpu(buf[i]);
+}
diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c
index 22485ea..dde0571 100644
--- a/drivers/i2c/fsl_i2c.c
+++ b/drivers/i2c/fsl_i2c.c
@@ -32,6 +32,8 @@
 #define I2C_READ_BIT  1
 #define I2C_WRITE_BIT 0
 
+DECLARE_GLOBAL_DATA_PTR;
+
 /* Initialize the bus pointer to whatever one the SPD EEPROM is on.
  * Default is bus 0.  This is necessary because the DDR initialization
  * runs from ROM, and we can't switch buses because we can't modify
@@ -43,24 +45,111 @@
 static unsigned int i2c_bus_num __attribute__ ((section ("data"))) = 0;
 #endif
 
-static volatile struct fsl_i2c *i2c_dev[2] = {
+static unsigned int i2c_bus_speed[2] = {CFG_I2C_SPEED, CFG_I2C_SPEED};
+
+static const struct fsl_i2c *i2c_dev[2] = {
 	(struct fsl_i2c *) (CFG_IMMR + CFG_I2C_OFFSET),
 #ifdef CFG_I2C2_OFFSET
 	(struct fsl_i2c *) (CFG_IMMR + CFG_I2C2_OFFSET)
 #endif
 };
 
+/* I2C speed map for a DFSR value of 1 */
+
+/*
+ * Map I2C frequency dividers to FDR and DFSR values
+ *
+ * This structure is used to define the elements of a table that maps I2C
+ * frequency divider (I2C clock rate divided by I2C bus speed) to a value to be
+ * programmed into the Frequency Divider Ratio (FDR) and Digital Filter
+ * Sampling Rate (DFSR) registers.
+ *
+ * The actual table should be defined in the board file, and it must be called
+ * fsl_i2c_speed_map[].
+ *
+ * The last entry of the table must have a value of {-1, X}, where X is same
+ * FDR/DFSR values as the second-to-last entry.  This guarantees that any
+ * search through the array will always find a match.
+ *
+ * The values of the divider must be in increasing numerical order, i.e.
+ * fsl_i2c_speed_map[x+1].divider > fsl_i2c_speed_map[x].divider.
+ *
+ * For this table, the values are based on a value of 1 for the DFSR
+ * register.  See the application note AN2919 "Determining the I2C Frequency
+ * Divider Ratio for SCL"
+ */
+static const struct {
+	unsigned short divider;
+	u8 dfsr;
+	u8 fdr;
+} fsl_i2c_speed_map[] = {
+	{160, 1, 32}, {192, 1, 33}, {224, 1, 34}, {256, 1, 35},
+	{288, 1, 0}, {320, 1, 1}, {352, 6, 1}, {384, 1, 2}, {416, 6, 2},
+	{448, 1, 38}, {480, 1, 3}, {512, 1, 39}, {544, 11, 3}, {576, 1, 4},
+	{608, 22, 3}, {640, 1, 5}, {672, 32, 3}, {704, 11, 5}, {736, 43, 3},
+	{768, 1, 6}, {800, 54, 3}, {832, 11, 6}, {896, 1, 42}, {960, 1, 7},
+	{1024, 1, 43}, {1088, 22, 7}, {1152, 1, 8}, {1216, 43, 7}, {1280, 1, 9},
+	{1408, 22, 9}, {1536, 1, 10}, {1664, 22, 10}, {1792, 1, 46},
+	{1920, 1, 11}, {2048, 1, 47}, {2176, 43, 11}, {2304, 1, 12},
+	{2560, 1, 13}, {2816, 43, 13}, {3072, 1, 14}, {3328, 43, 14},
+	{3584, 1, 50}, {3840, 1, 15}, {4096, 1, 51}, {4608, 1, 16},
+	{5120, 1, 17}, {6144, 1, 18}, {7168, 1, 54}, {7680, 1, 19},
+	{8192, 1, 55}, {9216, 1, 20}, {10240, 1, 21}, {12288, 1, 22},
+	{14336, 1, 58}, {15360, 1, 23}, {16384, 1, 59}, {18432, 1, 24},
+	{20480, 1, 25}, {24576, 1, 26}, {28672, 1, 62}, {30720, 1, 27},
+	{32768, 1, 63}, {36864, 1, 28}, {40960, 1, 29}, {49152, 1, 30},
+	{61440, 1, 31}, {-1, 1, 31}
+};
+
+/**
+ * Set the I2C bus speed for a given I2C device
+ *
+ * @param dev: the I2C device
+ * @i2c_clk: I2C bus clock frequency
+ * @speed: the desired speed of the bus
+ *
+ * The I2C device must be stopped before calling this function.
+ *
+ * The return value is the actual bus speed that is set.
+ */
+static unsigned int set_i2c_bus_speed(const struct fsl_i2c *dev,
+	unsigned int i2c_clk, unsigned int speed)
+{
+	unsigned short divider = min(i2c_clk / speed, (unsigned short) -1);
+	unsigned int i;
+	u8 fdr, dfsr;
+
+	/*
+	 * We want to choose an FDR/DFSR that generates an I2C bus speed that
+	 * is equal to or lower than the requested speed.  That means that we
+	 * want the first divider that is equal to or greater than the
+	 * calculated divider.
+	 */
+
+	for (i = 0; i < ARRAY_SIZE(fsl_i2c_speed_map); i++)
+		if (fsl_i2c_speed_map[i].divider >= divider) {
+			dfsr = fsl_i2c_speed_map[i].dfsr;
+			fdr = fsl_i2c_speed_map[i].fdr;
+			speed = i2c_clk / fsl_i2c_speed_map[i].divider;
+			break;
+		}
+
+	writeb(fdr, &dev->fdr);			/* set bus speed */
+	writeb(dfsr, &dev->dfsrr);		/* set default filter */
+
+	return speed;
+}
+
 void
 i2c_init(int speed, int slaveadd)
 {
-	volatile struct fsl_i2c *dev;
+	struct fsl_i2c *dev;
 
 	dev = (struct fsl_i2c *) (CFG_IMMR + CFG_I2C_OFFSET);
 
 	writeb(0, &dev->cr);			/* stop I2C controller */
 	udelay(5);				/* let it shutdown in peace */
-	writeb(0x3F, &dev->fdr);		/* set bus speed */
-	writeb(0x3F, &dev->dfsrr);		/* set default filter */
+	i2c_bus_speed[0] = set_i2c_bus_speed(dev, gd->i2c1_clk, speed);
 	writeb(slaveadd << 1, &dev->adr);	/* write slave address */
 	writeb(0x0, &dev->sr);			/* clear status register */
 	writeb(I2C_CR_MEN, &dev->cr);		/* start I2C controller */
@@ -70,12 +159,11 @@
 
 	writeb(0, &dev->cr);			/* stop I2C controller */
 	udelay(5);				/* let it shutdown in peace */
-	writeb(0x3F, &dev->fdr);		/* set bus speed */
-	writeb(0x3F, &dev->dfsrr);		/* set default filter */
+	i2c_bus_speed[1] = set_i2c_bus_speed(dev, gd->i2c2_clk, speed);
 	writeb(slaveadd << 1, &dev->adr);	/* write slave address */
 	writeb(0x0, &dev->sr);			/* clear status register */
 	writeb(I2C_CR_MEN, &dev->cr);		/* start I2C controller */
-#endif	/* CFG_I2C2_OFFSET */
+#endif
 }
 
 static __inline__ int
@@ -279,7 +367,14 @@
 
 int i2c_set_bus_speed(unsigned int speed)
 {
-	return -1;
+	unsigned int i2c_clk = (i2c_bus_num == 1) ? gd->i2c2_clk : gd->i2c1_clk;
+
+	writeb(0, &i2c_dev[i2c_bus_num]->cr);		/* stop controller */
+	i2c_bus_speed[i2c_bus_num] =
+		set_i2c_bus_speed(i2c_dev[i2c_bus_num], i2c_clk, speed);
+	writeb(I2C_CR_MEN, &i2c_dev[i2c_bus_num]->cr);	/* start controller */
+
+	return 0;
 }
 
 unsigned int i2c_get_bus_num(void)
@@ -289,7 +384,8 @@
 
 unsigned int i2c_get_bus_speed(void)
 {
-	return 0;
+	return i2c_bus_speed[i2c_bus_num];
 }
+
 #endif /* CONFIG_HARD_I2C */
 #endif /* CONFIG_FSL_I2C */
diff --git a/include/configs/sc520_cdp.h b/include/configs/sc520_cdp.h
index 8491d97..4df461d 100644
--- a/include/configs/sc520_cdp.h
+++ b/include/configs/sc520_cdp.h
@@ -81,8 +81,8 @@
 #include <config_cmd_default.h>
 
 #define CONFIG_CMD_PCI
+#define CONFIG_CMD_SATA
 #define CONFIG_CMD_JFFS2
-#define CONFIG_CMD_IDE
 #define CONFIG_CMD_NET
 #define CONFIG_CMD_EEPROM
 
@@ -173,37 +173,14 @@
 #define PCNET_HAS_PROM         1
 
 /************************************************************
- * IDE/ATA stuff
- ************************************************************/
-#define CFG_IDE_MAXBUS		1   /* max. 2 IDE busses	*/
-#define CFG_IDE_MAXDEVICE	(CFG_IDE_MAXBUS*2) /* max. 2 drives per IDE bus */
-
-#define CFG_ATA_IDE0_OFFSET	0x01F0	/* ide0 offste */
-/*#define CFG_ATA_IDE1_OFFSET	0x0170	/###* ide1 offset */
-#define CFG_ATA_DATA_OFFSET	0	/* data reg offset	*/
-#define CFG_ATA_REG_OFFSET	0	/* reg offset */
-#define CFG_ATA_ALT_OFFSET	0x200	/* alternate register offset */
-#define CFG_ATA_BASE_ADDR       0
-
-#undef	CONFIG_IDE_LED			/* no led for ide supported	*/
-#undef  CONFIG_IDE_RESET		/* reset for ide unsupported...	*/
-#undef  CONFIG_IDE_RESET_ROUTINE	/* no special reset function */
-
-/************************************************************
 *SATA/Native Stuff
 ************************************************************/
-#define CFG_SATA_SUPPORTED      1
 #define CFG_SATA_MAXBUS         2       /*Max Sata buses supported */
 #define CFG_SATA_DEVS_PER_BUS   2      /*Max no. of devices per bus/port */
-#define CFG_SATA_MAXDEVICES     (CFG_SATA_MAXBUS* CFG_SATA_DEVS_PER_BUS)
+#define CFG_SATA_MAX_DEVICE     (CFG_SATA_MAXBUS* CFG_SATA_DEVS_PER_BUS)
 #define CFG_ATA_PIIX            1       /*Supports ata_piix driver */
 
 /************************************************************
- * ATAPI support (experimental)
- ************************************************************/
-#define CONFIG_ATAPI			/* enable ATAPI Support */
-
-/************************************************************
  * DISK Partition support
  ************************************************************/
 #define CONFIG_DOS_PARTITION
diff --git a/include/fis.h b/include/fis.h
new file mode 100644
index 0000000..2040b50
--- /dev/null
+++ b/include/fis.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2008 Freescale Semiconductor, Inc.
+ *		Dave Liu <daveliu@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#ifndef __FIS_H__
+#define __FIS_H__
+/*
+* Register - Host to Device FIS
+*/
+typedef struct sata_fis_h2d {
+	u8 fis_type;
+	u8 pm_port_c;
+	u8 command;
+	u8 features;
+	u8 lba_low;
+	u8 lba_mid;
+	u8 lba_high;
+	u8 device;
+	u8 lba_low_exp;
+	u8 lba_mid_exp;
+	u8 lba_high_exp;
+	u8 features_exp;
+	u8 sector_count;
+	u8 sector_count_exp;
+	u8 res1;
+	u8 control;
+	u8 res2[4];
+} __attribute__ ((packed)) sata_fis_h2d_t;
+
+/*
+* Register - Host to Device FIS for read/write FPDMA queued
+*/
+typedef struct sata_fis_h2d_ncq {
+	u8 fis_type;
+	u8 pm_port_c;
+	u8 command;
+	u8 sector_count_low;
+	u8 lba_low;
+	u8 lba_mid;
+	u8 lba_high;
+	u8 device;
+	u8 lba_low_exp;
+	u8 lba_mid_exp;
+	u8 lba_high_exp;
+	u8 sector_count_high;
+	u8 tag;
+	u8 res1;
+	u8 res2;
+	u8 control;
+	u8 res3[4];
+} __attribute__ ((packed)) sata_fis_h2d_ncq_t;
+
+/*
+* Register - Device to Host FIS
+*/
+typedef struct sata_fis_d2h {
+	u8 fis_type;
+	u8 pm_port_i;
+	u8 status;
+	u8 error;
+	u8 lba_low;
+	u8 lba_mid;
+	u8 lba_high;
+	u8 device;
+	u8 lba_low_exp;
+	u8 lba_mid_exp;
+	u8 lba_high_exp;
+	u8 res1;
+	u8 sector_count;
+	u8 sector_count_exp;
+	u8 res2[2];
+	u8 res3[4];
+} __attribute__ ((packed)) sata_fis_d2h_t;
+
+/*
+* DMA Setup - Device to Host or Host to Device FIS
+*/
+typedef struct sata_fis_dma_setup {
+	u8 fis_type;
+	u8 pm_port_dir_int_act;
+	u8 res1;
+	u8 res2;
+	u32 dma_buffer_id_low;
+	u32 dma_buffer_id_high;
+	u32 res3;
+	u32 dma_buffer_offset;
+	u32 dma_transfer_count;
+	u32 res4;
+} __attribute__ ((packed)) sata_fis_dma_setup_t;
+
+/*
+* PIO Setup - Device to Host FIS
+*/
+typedef struct sata_fis_pio_setup {
+	u8 fis_type;
+	u8 pm_port_dir_int;
+	u8 status;
+	u8 error;
+	u8 lba_low;
+	u8 lba_mid;
+	u8 lba_high;
+	u8 res1;
+	u8 lba_low_exp;
+	u8 lba_mid_exp;
+	u8 lba_high_exp;
+	u8 res2;
+	u8 sector_count;
+	u8 sector_count_exp;
+	u8 res3;
+	u8 e_status;
+	u16 transfer_count;
+	u16 res4;
+} __attribute__ ((packed)) sata_fis_pio_setup_t;
+
+/*
+* Data - Host to Device or Device to Host FIS
+*/
+typedef struct sata_fis_data {
+	u8 fis_type;
+	u8 pm_port;
+	u8 res1;
+	u8 res2;
+	u32 data[2048];
+} __attribute__ ((packed)) sata_fis_data_t;
+
+/* fis_type - SATA FIS type
+ */
+enum sata_fis_type {
+	SATA_FIS_TYPE_REGISTER_H2D		= 0x27,
+	SATA_FIS_TYPE_REGISTER_D2H		= 0x34,
+	SATA_FIS_TYPE_DMA_ACT_D2H		= 0x39,
+	SATA_FIS_TYPE_DMA_SETUP_BI		= 0x41,
+	SATA_FIS_TYPE_DATA_BI			= 0x46,
+	SATA_FIS_TYPE_BIST_ACT_BI		= 0x58,
+	SATA_FIS_TYPE_PIO_SETUP_D2H		= 0x5F,
+	SATA_FIS_TYPE_SET_DEVICE_BITS_D2H	= 0xA1,
+};
+
+#endif	/* __FIS_H__ */
diff --git a/include/libata.h b/include/libata.h
new file mode 100644
index 0000000..aedba74
--- /dev/null
+++ b/include/libata.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2008 Freescale Semiconductor, Inc.
+ *		Dave Liu <daveliu@freescale.com>
+ *		port from libata of linux kernel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#ifndef __LIBATA_H__
+#define __LIBATA_H__
+
+#include <common.h>
+
+/* command
+ */
+enum ata_cmd {
+	/* non-NCQ command */
+	ATA_CMD_DEV_RESET		= 0x08, /* ATAPI device reset */
+	ATA_CMD_FLUSH_CACHE		= 0xE7,
+	ATA_CMD_FLUSH_CACHE_EXT		= 0xEA,
+	ATA_CMD_ID_ATA			= 0xEC,
+	ATA_CMD_ID_ATAPI		= 0xA1,
+	ATA_CMD_READ_DMA		= 0xC8,
+	ATA_CMD_READ_DMA_EXT		= 0x25,
+	ATA_CMD_WRITE_DMA		= 0xCA,
+	ATA_CMD_WRITE_DMA_EXT		= 0x35,
+	ATA_CMD_PIO_READ		= 0x20,
+	ATA_CMD_PIO_READ_EXT		= 0x24,
+	ATA_CMD_PIO_WRITE		= 0x30,
+	ATA_CMD_PIO_WRITE_EXT		= 0x34,
+	ATA_CMD_SET_FEATURES		= 0xEF,
+
+	/* NCQ command */
+	ATA_CMD_READ_FPDMA_QUEUED	= 0x60,
+	ATA_CMD_WRITE_FPDMA_QUEUED	= 0x61,
+};
+
+/* SETFEATURES stuff
+ */
+enum ata_set_features {
+	/* SETFEATURES stuff */
+	SETFEATURES_XFER	= 0x03,
+	XFER_UDMA_7		= 0x47,
+	XFER_UDMA_6		= 0x46,
+	XFER_UDMA_5		= 0x45,
+	XFER_UDMA_4		= 0x44,
+	XFER_UDMA_3		= 0x43,
+	XFER_UDMA_2		= 0x42,
+	XFER_UDMA_1		= 0x41,
+	XFER_UDMA_0		= 0x40,
+	XFER_MW_DMA_4		= 0x24, /* CFA only */
+	XFER_MW_DMA_3		= 0x23, /* CFA only */
+	XFER_MW_DMA_2		= 0x22,
+	XFER_MW_DMA_1		= 0x21,
+	XFER_MW_DMA_0		= 0x20,
+	XFER_PIO_6		= 0x0E, /* CFA only */
+	XFER_PIO_5		= 0x0D, /* CFA only */
+	XFER_PIO_4		= 0x0C,
+	XFER_PIO_3		= 0x0B,
+	XFER_PIO_2		= 0x0A,
+	XFER_PIO_1		= 0x09,
+	XFER_PIO_0		= 0x08,
+	XFER_PIO_SLOW		= 0x00,
+
+	SETFEATURES_WC_ON	= 0x02, /* Enable write cache */
+	SETFEATURES_WC_OFF	= 0x82, /* Disable write cache */
+
+	SETFEATURES_SPINUP	= 0x07, /* Spin-up drive */
+};
+
+enum ata_protocol {
+	ATA_PROT_UNKNOWN,	/* unknown */
+	ATA_PROT_NODATA,	/* no data */
+	ATA_PROT_PIO,		/* PIO data xfer */
+	ATA_PROT_DMA,		/* DMA */
+	ATA_PROT_NCQ,		/* NCQ */
+	ATA_PROT_ATAPI,		/* packet command, PIO data xfer */
+	ATA_PROT_ATAPI_NODATA,	/* packet command, no data */
+	ATA_PROT_ATAPI_DMA,	/* packet command, DMA */
+};
+
+enum ata_dev_typed {
+	ATA_DEV_ATA,		/* ATA device */
+	ATA_DEV_ATAPI,		/* ATAPI device */
+	ATA_DEV_PMP,		/* Port Multiplier Port */
+	ATA_DEV_UNKNOWN,	/* unknown */
+};
+
+enum {
+	ATA_SECT_SIZE		= 512,
+	ATA_MAX_SECTORS_128	= 128,
+	ATA_MAX_SECTORS		= 256,
+	ATA_MAX_SECTORS_LBA48	= 65535,
+
+	/* bits in ATA command block registers */
+	ATA_HOB			= (1 << 7),	/* LBA48 selector */
+	ATA_NIEN		= (1 << 1),	/* disable-irq flag */
+	ATA_LBA			= (1 << 6),	/* LBA28 selector */
+	ATA_DEV1		= (1 << 4),	/* Select Device 1 (slave) */
+	ATA_BUSY		= (1 << 7),	/* BSY status bit */
+	ATA_DRDY		= (1 << 6),	/* device ready */
+	ATA_DF			= (1 << 5),	/* device fault */
+	ATA_DRQ			= (1 << 3),	/* data request i/o */
+	ATA_ERR			= (1 << 0),	/* have an error */
+	ATA_SRST		= (1 << 2),	/* software reset */
+	ATA_ICRC		= (1 << 7),	/* interface CRC error */
+	ATA_UNC			= (1 << 6),	/* uncorrectable media error */
+	ATA_IDNF		= (1 << 4),	/* ID not found */
+	ATA_ABORTED		= (1 << 2),	/* command aborted */
+
+	ATA_ID_WORDS		= 256,
+	ATA_ID_SERNO		= 10,
+	ATA_ID_FW_REV		= 23,
+	ATA_ID_PROD		= 27,
+	ATA_ID_FIELD_VALID	= 53,
+	ATA_ID_LBA_SECTORS	= 60,
+	ATA_ID_MWDMA_MODES	= 63,
+	ATA_ID_PIO_MODES	= 64,
+	ATA_ID_QUEUE_DEPTH	= 75,
+	ATA_ID_SATA_CAP		= 76,
+	ATA_ID_SATA_FEATURES	= 78,
+	ATA_ID_SATA_FEATURES_EN	= 79,
+	ATA_ID_MAJOR_VER	= 80,
+	ATA_ID_MINOR_VER	= 81,
+	ATA_ID_UDMA_MODES	= 88,
+	ATA_ID_LBA48_SECTORS	= 100,
+
+	ATA_ID_SERNO_LEN	= 20,
+	ATA_ID_FW_REV_LEN	= 8,
+	ATA_ID_PROD_LEN		= 40,
+
+	ATA_PIO3		= (1 << 0),
+	ATA_PIO4		= ATA_PIO3 | (1 << 1),
+
+	ATA_UDMA0		= (1 << 0),
+	ATA_UDMA1		= ATA_UDMA0 | (1 << 1),
+	ATA_UDMA2		= ATA_UDMA1 | (1 << 2),
+	ATA_UDMA3		= ATA_UDMA2 | (1 << 3),
+	ATA_UDMA4		= ATA_UDMA3 | (1 << 4),
+	ATA_UDMA5		= ATA_UDMA4 | (1 << 5),
+	ATA_UDMA6		= ATA_UDMA5 | (1 << 6),
+	ATA_UDMA7		= ATA_UDMA6 | (1 << 7),
+};
+
+#define ata_id_is_ata(id)		(((id)[0] & (1 << 15)) == 0)
+#define ata_id_wcache_enabled(id)	((id)[85] & (1 << 5))
+#define ata_id_has_fua(id)		((id)[84] & (1 << 6))
+#define ata_id_has_flush(id)		((id)[83] & (1 << 12))
+#define ata_id_has_flush_ext(id)	((id)[83] & (1 << 13))
+#define ata_id_has_lba48(id)		((id)[83] & (1 << 10))
+#define ata_id_has_wcache(id)		((id)[82] & (1 << 5))
+#define ata_id_has_lba(id)		((id)[49] & (1 << 9))
+#define ata_id_has_dma(id)		((id)[49] & (1 << 8))
+#define ata_id_has_ncq(id)		((id)[76] & (1 << 8))
+#define ata_id_queue_depth(id)		(((id)[75] & 0x1f) + 1)
+
+#define ata_id_u32(id,n)	\
+	(((u32) (id)[(n) + 1] << 16) | ((u32) (id)[(n)]))
+#define ata_id_u64(id,n)	\
+	( ((u64) (id)[(n) + 3] << 48) | \
+	  ((u64) (id)[(n) + 2] << 32) | \
+	  ((u64) (id)[(n) + 1] << 16) | \
+	  ((u64) (id)[(n) + 0]) )
+
+
+static inline unsigned int ata_id_major_version(const u16 *id)
+{
+	unsigned int mver;
+
+	if (id[ATA_ID_MAJOR_VER] == 0xFFFF)
+		return 0;
+
+	for (mver = 14; mver >= 1; mver--)
+		if (id[ATA_ID_MAJOR_VER] & (1 << mver))
+			break;
+	return mver;
+}
+
+static inline int ata_id_is_sata(const u16 *id)
+{
+	return ata_id_major_version(id) >= 5 && id[93] == 0;
+}
+
+u64 ata_id_n_sectors(u16 *id);
+u32 ata_dev_classify(u32 sig);
+void ata_id_c_string(const u16 *id, unsigned char *s,
+			 unsigned int ofs, unsigned int len);
+void ata_dump_id(u16 *id);
+void ata_swap_buf_le16(u16 *buf, unsigned int buf_words);
+
+#endif /* __LIBATA_H__ */
diff --git a/include/part.h b/include/part.h
index 8407aa0..b22a637 100644
--- a/include/part.h
+++ b/include/part.h
@@ -27,8 +27,8 @@
 
 typedef struct block_dev_desc {
 	int		if_type;	/* type of the interface */
-	int	        dev;	  	/* device number */
-	unsigned char	part_type;  	/* partition type */
+	int		dev;		/* device number */
+	unsigned char	part_type;	/* partition type */
 	unsigned char	target;		/* target SCSI ID */
 	unsigned char	lun;		/* target LUN */
 	unsigned char	type;		/* device type */
@@ -36,9 +36,9 @@
 #ifdef CONFIG_LBA48
 	unsigned char	lba48;		/* device can use 48bit addr (ATA/ATAPI v7) */
 #endif
-	lbaint_t		lba;	  	/* number of blocks */
+	lbaint_t		lba;		/* number of blocks */
 	unsigned long	blksz;		/* block size */
-	char		vendor [40+1]; 	/* IDE model, SCSI Vendor */
+	char		vendor [40+1];	/* IDE model, SCSI Vendor */
 	char		product[20+1];	/* IDE Serial no, SCSI product */
 	char		revision[8+1];	/* firmware revision */
 	unsigned long	(*block_read)(int dev,
@@ -49,6 +49,7 @@
 				       unsigned long start,
 				       lbaint_t blkcnt,
 				       const void *buffer);
+	void		*priv;		/* driver private struct pointer */
 }block_dev_desc_t;
 
 /* Interface types: */
@@ -60,6 +61,7 @@
 #define IF_TYPE_DOC		5
 #define IF_TYPE_MMC		6
 #define IF_TYPE_SD		7
+#define IF_TYPE_SATA		8
 
 /* Part types */
 #define PART_TYPE_UNKNOWN	0x00
@@ -92,6 +94,7 @@
 /* Misc _get_dev functions */
 block_dev_desc_t* get_dev(char* ifname, int dev);
 block_dev_desc_t* ide_get_dev(int dev);
+block_dev_desc_t* sata_get_dev(int dev);
 block_dev_desc_t* scsi_get_dev(int dev);
 block_dev_desc_t* usb_stor_get_dev(int dev);
 block_dev_desc_t* mmc_get_dev(int dev);
diff --git a/include/sata.h b/include/sata.h
index 165b471..b4b7029 100644
--- a/include/sata.h
+++ b/include/sata.h
@@ -1,108 +1,6 @@
-
-#if (DEBUG_SATA)
-#define PRINTF(fmt,args...)	printf (fmt ,##args)
-#else
-#define PRINTF(fmt,args...)
-#endif
-
-struct sata_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 sata_port {
-	unsigned char port_no;		/* primary=0, secondary=1	*/
-	struct sata_ioports ioaddr;	/* ATA cmd/ctl/dma reg blks	*/
-	unsigned char ctl_reg;
-	unsigned char last_ctl;
-	unsigned char port_state;	/* 1-port is available and	*/
-					/* 0-port is not available	*/
-	unsigned char dev_mask;
-};
-
-/***********SATA LIBRARY SPECIFIC DEFINITIONS AND DECLARATIONS**************/
-#ifdef SATA_DECL		/*SATA library specific declarations */
-#define ata_id_has_lba48(id)    ((id)[83] & (1 << 10))
-#define ata_id_has_lba(id)      ((id)[49] & (1 << 9))
-#define ata_id_has_dma(id)      ((id)[49] & (1 << 8))
-#define ata_id_u32(id,n)        \
-	(((u32) (id)[(n) + 1] << 16) | ((u32) (id)[(n)]))
-#define ata_id_u64(id,n)        \
-	(((u64) (id)[(n) + 3] << 48) | \
-	((u64) (id)[(n) + 2] << 32) | \
-	((u64) (id)[(n) + 1] << 16) | \
-	((u64) (id)[(n) + 0]) )
-#endif
-
-#ifdef SATA_DECL		/*SATA library specific declarations */
-static inline void
-ata_dump_id (u16 * id)
-{
-	PRINTF ("49==0x%04x  "
-		"53==0x%04x  "
-		"63==0x%04x  "
-		"64==0x%04x  "
-		"75==0x%04x  \n", id[49], id[53], id[63], id[64], id[75]);
-	PRINTF ("80==0x%04x  "
-		"81==0x%04x  "
-		"82==0x%04x  "
-		"83==0x%04x  "
-		"84==0x%04x  \n", id[80], id[81], id[82], id[83], id[84]);
-	PRINTF ("88==0x%04x  " "93==0x%04x\n", id[88], id[93]);
-}
-#endif
-
-#ifdef SATA_DECL		/*SATA library specific declarations */
-int sata_bus_softreset (int num);
-void sata_identify (int num, int dev);
-void sata_port (struct sata_ioports *ioport);
-void set_Feature_cmd (int num, int dev);
-int sata_devchk (struct sata_ioports *ioaddr, int dev);
-void dev_select (struct sata_ioports *ioaddr, int dev);
-u8 sata_busy_wait (struct sata_ioports *ioaddr, int bits, unsigned int max);
-u8 sata_chk_status (struct sata_ioports *ioaddr);
-ulong sata_read (int device, ulong blknr,lbaint_t blkcnt, void * buffer);
-ulong sata_write (int device,ulong blknr, lbaint_t blkcnt, void * buffer);
-void msleep (int count);
-#else
-extern int sata_bus_softreset (int num);
-extern void sata_identify (int num, int dev);
-extern void sata_port (struct sata_ioports *ioport);
-extern void set_Feature_cmd (int num, int dev);
-extern ulong sata_read (int device, ulong blknr,
-			lbaint_t blkcnt, void * buffer);
-extern ulong sata_write (int device, ulong blknr,
-			lbaint_t blkcnt, void * buffer);
-extern void msleep (int count);
-#endif
-
-/************DRIVER SPECIFIC DEFINITIONS AND DECLARATIONS**************/
-
-#ifdef DRV_DECL			/*Driver specific declaration */
-int init_sata (void);
-#else
-extern int init_sata (void);
-#endif
+int init_sata(int dev);
+int scan_sata(int dev);
+ulong sata_read(int dev, ulong blknr, ulong blkcnt, void *buffer);
+ulong sata_write(int dev, ulong blknr, ulong blkcnt, const void *buffer);
 
-#ifdef DRV_DECL			/*Defines Driver Specific variables */
-struct sata_port port[CFG_SATA_MAXBUS];
-block_dev_desc_t sata_dev_desc[CFG_SATA_MAXDEVICES];
-int curr_dev = -1;
-#else
-extern struct sata_port port[CFG_SATA_MAXBUS];
-extern block_dev_desc_t sata_dev_desc[CFG_SATA_MAXDEVICES];
-extern int curr_dev;
-#endif
+int sata_initialize(void);
diff --git a/include/usb.h b/include/usb.h
index 4e1539f..5a6ffdd 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -195,7 +195,7 @@
 #define USB_MAX_STOR_DEV 5
 block_dev_desc_t *usb_stor_get_dev(int index);
 int usb_stor_scan(int mode);
-void usb_stor_info(void);
+int usb_stor_info(void);
 
 #endif
 
diff --git a/lib_ppc/board.c b/lib_ppc/board.c
index 3ab22f8..3038302 100644
--- a/lib_ppc/board.c
+++ b/lib_ppc/board.c
@@ -38,6 +38,9 @@
 #if defined(CONFIG_CMD_IDE)
 #include <ide.h>
 #endif
+#if defined(CONFIG_CMD_SATA)
+#include <sata.h>
+#endif
 #if defined(CONFIG_CMD_SCSI)
 #include <scsi.h>
 #endif
@@ -1104,6 +1107,11 @@
 #endif
 #endif
 
+#if defined(CONFIG_CMD_SATA)
+	puts ("SATA:  ");
+	sata_initialize ();
+#endif
+
 #ifdef CONFIG_LAST_STAGE_INIT
 	WATCHDOG_RESET ();
 	/*