]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
Merge branch 'master' of git://www.denx.de/git/u-boot-mpc85xx
authorWolfgang Denk <wd@denx.de>
Wed, 26 Mar 2008 23:16:34 +0000 (00:16 +0100)
committerWolfgang Denk <wd@denx.de>
Wed, 26 Mar 2008 23:16:34 +0000 (00:16 +0100)
24 files changed:
CHANGELOG
README
common/Makefile
common/cmd_sata.c
common/usb_storage.c
disk/part.c
disk/part_dos.c
disk/part_iso.c
disk/part_mac.c
doc/README.sata [new file with mode: 0644]
drivers/block/Makefile
drivers/block/ata_piix.c
drivers/block/ata_piix.h [new file with mode: 0644]
drivers/block/fsl_sata.c [new file with mode: 0644]
drivers/block/fsl_sata.h [new file with mode: 0644]
drivers/block/libata.c [new file with mode: 0644]
drivers/i2c/fsl_i2c.c
include/configs/sc520_cdp.h
include/fis.h [new file with mode: 0644]
include/libata.h [new file with mode: 0644]
include/part.h
include/sata.h
include/usb.h
lib_ppc/board.c

index 278bb33a2ef0680c8dc7d5daaf5e86113c39dfdc..d5eae562ac3b53fb89e2ebfb2907cb7f3d6a74c1 100644 (file)
--- 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 b3423e318e3d33adce18f80302aac2314f04efec..5cbe7c1e80daabeee8c43247db7041b999919025 100644 (file)
--- a/README
+++ b/README
@@ -78,7 +78,7 @@ any version you might be interested in. Ofifcial releases are also
 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/
 
 
index 382dd018001b76d8203664f4f5f5893d3743093d..0d67337d2695be5071d8a8f19af83407c96263bf 100644 (file)
@@ -88,7 +88,7 @@ COBJS-y += cmd_pcmcia.o
 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
index bd4c11fd9b7bb1717f53b7adea7d06dde6276f18..79c2495d664eff4b0bfbbb3407aa65fff44b4fa7 100644 (file)
@@ -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
  *
  * 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);
+int curr_device = -1;
+block_dev_desc_t sata_dev_desc[CFG_SATA_MAX_DEVICE];
 
-#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 sata_initialize(void)
 {
+       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;
-       }
+       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;
 
-       /* 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", 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;
+       curr_device = 0;
+       return rc;
 }
 
-ulong
-sata_write (int device, ulong blknr,lbaint_t blkcnt, void * buff)
+block_dev_desc_t *sata_get_dev(int dev)
 {
-       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;
+       return (dev < CFG_SATA_MAX_DEVICE) ? &sata_dev_desc[dev] : NULL;
 }
 
-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]);
-}
-
-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);
+
+                       printf("\nSATA read: device %d block # %ld, count %ld ... ",
+                               curr_device, blk, cnt);
+
+                       n = sata_read(curr_device, blk, cnt, (u32 *)addr);
 
-                       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);
                        /* 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");
index 81d2f92100eb54686f9a3f030ca7f851b4ff8fc5..d263b6c0d0ea61c31cf5d3cb2dd1fc586cfde724 100644 (file)
@@ -196,12 +196,12 @@ int usb_stor_info(void)
                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;
 }
 
 /*********************************************************************************
index 56b9427c260b5cd61c097b6128492056626ee76f..3c71208a12bb0e05cbb9e3e112bc83e114ceaa69 100644 (file)
@@ -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 @@ static const struct block_drvr block_drvr[] = {
 #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 @@ block_dev_desc_t *get_dev(char* ifname, int dev)
 #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 @@ void dev_print (block_dev_desc_t *dev_desc)
                        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 @@ void dev_print (block_dev_desc_t *dev_desc)
 #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 @@ static void print_part_header (const char *type, block_dev_desc_t * dev_desc)
        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");
index 4707f803dc182897a76289897894b30346f2f338..4d778ec5b24b69fad5ae6a4829e8bb4f58ce1cbd 100644 (file)
@@ -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 @@ static int get_partition_info_extended (block_dev_desc_t *dev_desc, int ext_part
                        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;
index 06dd75eff6d81047e136ba539c632c1ea35b173b..489463079392be2dc964e08c2f9677435bea074f 100644 (file)
@@ -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 @@ int get_partition_info_iso_verb(block_dev_desc_t * dev_desc, int part_num, disk_
        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;
index d303a73f297814e426adbd4f3beaafdcb285741d..1922fe53a9ce86d0688b0e5247c80e6fd9129497 100644 (file)
@@ -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 (file)
index 0000000..168dc7f
--- /dev/null
@@ -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
index e069969e680d32c0bbfe705997c84247e2f1a1ae..dca3547919e6fe9227bc347d483927f9b5aa475f 100644 (file)
@@ -27,6 +27,8 @@ LIB   := $(obj)libblock.a
 
 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
index 42456d7be334dab74d67df839d3c1c040cc1cee2..441a4dcd8d652f1aface989268f72bacaf39360c 100644 (file)
  */
 
 #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 @@ sata_bus_probe (int port_no)
 }
 
 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 @@ init_sata (void)
                                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 (file)
index 0000000..ed2e4d5
--- /dev/null
@@ -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 (file)
index 0000000..7436c4d
--- /dev/null
@@ -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 (file)
index 0000000..874c0dc
--- /dev/null
@@ -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 (file)
index 0000000..bbe16a2
--- /dev/null
@@ -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]);
+}
index 22485ea916f4a958d31892192c277a48e29a05ae..dde057124e9bfb7b18cf24c79011a1a11b521d4c 100644 (file)
@@ -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"))) = CFG_SPD_BUS
 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 @@ i2c_init(int speed, int slaveadd)
 
        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_num(unsigned int bus)
 
 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_num(void)
 
 unsigned int i2c_get_bus_speed(void)
 {
-       return 0;
+       return i2c_bus_speed[i2c_bus_num];
 }
+
 #endif /* CONFIG_HARD_I2C */
 #endif /* CONFIG_FSL_I2C */
index 8491d97ae421607a70736e694d5f7ff876be6f44..4df461dd96113b71060b6a336a3450cff6ba58d5 100644 (file)
@@ -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
 
 #define CONFIG_PCNET_79C975
 #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
  ************************************************************/
diff --git a/include/fis.h b/include/fis.h
new file mode 100644 (file)
index 0000000..2040b50
--- /dev/null
@@ -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 (file)
index 0000000..aedba74
--- /dev/null
@@ -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__ */
index 8407aa05d26b350789e16052f8b25964d65f9383..b22a637dd2ca9fd75b6c885a5b286336c6b4c051 100644 (file)
@@ -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 @@ typedef struct block_dev_desc {
 #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 @@ typedef struct block_dev_desc {
                                       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 @@ typedef struct block_dev_desc {
 #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 @@ typedef struct disk_partition {
 /* 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);
index 165b471b289ab011ac162d16f65ba3d7737d3278..b4b702903e2c6b854dc659ebf8948ad3206dfd0a 100644 (file)
@@ -1,108 +1,6 @@
+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);
 
-#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
-
-#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);
index 4e1539fa8820684b7c38e2cf00c283d7b6eeb07d..5a6ffddec805fbef68069bdcf73a3886a611bf53 100644 (file)
@@ -195,7 +195,7 @@ void usb_event_poll(void);
 #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
 
index 3ab22f809ed6b934917762b90eff7213bec81604..30383027c78d33d310c9468340ec635d7c4aed4a 100644 (file)
@@ -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 @@ void board_init_r (gd_t *id, ulong dest_addr)
 #endif
 #endif
 
+#if defined(CONFIG_CMD_SATA)
+       puts ("SATA:  ");
+       sata_initialize ();
+#endif
+
 #ifdef CONFIG_LAST_STAGE_INIT
        WATCHDOG_RESET ();
        /*