summaryrefslogtreecommitdiffstats
path: root/u-boot/drivers/block
diff options
context:
space:
mode:
authorH. Nikolaus Schaller <hns@goldelico.com>2012-03-26 20:55:28 +0200
committerH. Nikolaus Schaller <hns@goldelico.com>2012-03-26 20:55:28 +0200
commit92988a21ad4c4c9504295ccb580c9f806134471b (patch)
tree5effc9f14170112450de05c67dafbe8d5034d595 /u-boot/drivers/block
parentca2b506783b676c95762c54ea24dcfdaae1947c9 (diff)
downloadbootable_bootloader_goldelico_gta04-92988a21ad4c4c9504295ccb580c9f806134471b.zip
bootable_bootloader_goldelico_gta04-92988a21ad4c4c9504295ccb580c9f806134471b.tar.gz
bootable_bootloader_goldelico_gta04-92988a21ad4c4c9504295ccb580c9f806134471b.tar.bz2
added boot script files to repository
Diffstat (limited to 'u-boot/drivers/block')
-rw-r--r--u-boot/drivers/block/Makefile58
-rw-r--r--u-boot/drivers/block/ahci.c695
-rw-r--r--u-boot/drivers/block/ata_piix.c756
-rw-r--r--u-boot/drivers/block/ata_piix.h81
-rw-r--r--u-boot/drivers/block/fsl_sata.c942
-rw-r--r--u-boot/drivers/block/fsl_sata.h332
-rw-r--r--u-boot/drivers/block/libata.c158
-rw-r--r--u-boot/drivers/block/mg_disk.c582
-rw-r--r--u-boot/drivers/block/mg_disk_prv.h144
-rw-r--r--u-boot/drivers/block/mvsata_ide.c164
-rw-r--r--u-boot/drivers/block/mxc_ata.c146
-rw-r--r--u-boot/drivers/block/pata_bfin.c1200
-rw-r--r--u-boot/drivers/block/pata_bfin.h173
-rw-r--r--u-boot/drivers/block/sata_dwc.c2110
-rw-r--r--u-boot/drivers/block/sata_dwc.h477
-rw-r--r--u-boot/drivers/block/sata_sil3114.c839
-rw-r--r--u-boot/drivers/block/sata_sil3114.h147
-rw-r--r--u-boot/drivers/block/sil680.c107
-rw-r--r--u-boot/drivers/block/sym53c8xx.c870
-rw-r--r--u-boot/drivers/block/systemace.c255
20 files changed, 10236 insertions, 0 deletions
diff --git a/u-boot/drivers/block/Makefile b/u-boot/drivers/block/Makefile
new file mode 100644
index 0000000..aa7dc87
--- /dev/null
+++ b/u-boot/drivers/block/Makefile
@@ -0,0 +1,58 @@
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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 $(TOPDIR)/config.mk
+
+LIB := $(obj)libblock.o
+
+COBJS-$(CONFIG_SCSI_AHCI) += ahci.o
+COBJS-$(CONFIG_ATA_PIIX) += ata_piix.o
+COBJS-$(CONFIG_FSL_SATA) += fsl_sata.o
+COBJS-$(CONFIG_LIBATA) += libata.o
+COBJS-$(CONFIG_CMD_MG_DISK) += mg_disk.o
+COBJS-$(CONFIG_MVSATA_IDE) += mvsata_ide.o
+COBJS-$(CONFIG_MX51_PATA) += mxc_ata.o
+COBJS-$(CONFIG_PATA_BFIN) += pata_bfin.o
+COBJS-$(CONFIG_SATA_DWC) += sata_dwc.o
+COBJS-$(CONFIG_SATA_SIL3114) += sata_sil3114.o
+COBJS-$(CONFIG_IDE_SIL680) += sil680.o
+COBJS-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o
+COBJS-$(CONFIG_SYSTEMACE) += systemace.o
+
+COBJS := $(COBJS-y)
+SRCS := $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+
+all: $(LIB)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/u-boot/drivers/block/ahci.c b/u-boot/drivers/block/ahci.c
new file mode 100644
index 0000000..a3ca2dc
--- /dev/null
+++ b/u-boot/drivers/block/ahci.c
@@ -0,0 +1,695 @@
+/*
+ * Copyright (C) Freescale Semiconductor, Inc. 2006.
+ * Author: Jason Jin<Jason.jin@freescale.com>
+ * Zhang Wei<wei.zhang@freescale.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ *
+ * with the reference on libata and ahci drvier in kernel
+ *
+ */
+#include <common.h>
+
+#include <command.h>
+#include <pci.h>
+#include <asm/processor.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <scsi.h>
+#include <ata.h>
+#include <linux/ctype.h>
+#include <ahci.h>
+
+struct ahci_probe_ent *probe_ent = NULL;
+hd_driveid_t *ataid[AHCI_MAX_PORTS];
+
+#define writel_with_flush(a,b) do { writel(a,b); readl(b); } while (0)
+
+
+static inline u32 ahci_port_base(u32 base, u32 port)
+{
+ return base + 0x100 + (port * 0x80);
+}
+
+
+static void ahci_setup_port(struct ahci_ioports *port, unsigned long base,
+ unsigned int port_idx)
+{
+ base = ahci_port_base(base, port_idx);
+
+ port->cmd_addr = base;
+ port->scr_addr = base + PORT_SCR;
+}
+
+
+#define msleep(a) udelay(a * 1000)
+#define ssleep(a) msleep(a * 1000)
+
+static int waiting_for_cmd_completed(volatile u8 *offset,
+ int timeout_msec,
+ u32 sign)
+{
+ int i;
+ u32 status;
+
+ for (i = 0; ((status = readl(offset)) & sign) && i < timeout_msec; i++)
+ msleep(1);
+
+ return (i < timeout_msec) ? 0 : -1;
+}
+
+
+static int ahci_host_init(struct ahci_probe_ent *probe_ent)
+{
+ pci_dev_t pdev = probe_ent->dev;
+ volatile u8 *mmio = (volatile u8 *)probe_ent->mmio_base;
+ u32 tmp, cap_save;
+ u16 tmp16;
+ int i, j;
+ volatile u8 *port_mmio;
+ unsigned short vendor;
+
+ cap_save = readl(mmio + HOST_CAP);
+ cap_save &= ((1 << 28) | (1 << 17));
+ cap_save |= (1 << 27);
+
+ /* global controller reset */
+ tmp = readl(mmio + HOST_CTL);
+ if ((tmp & HOST_RESET) == 0)
+ writel_with_flush(tmp | HOST_RESET, mmio + HOST_CTL);
+
+ /* reset must complete within 1 second, or
+ * the hardware should be considered fried.
+ */
+ ssleep(1);
+
+ tmp = readl(mmio + HOST_CTL);
+ if (tmp & HOST_RESET) {
+ debug("controller reset failed (0x%x)\n", tmp);
+ return -1;
+ }
+
+ writel_with_flush(HOST_AHCI_EN, mmio + HOST_CTL);
+ writel(cap_save, mmio + HOST_CAP);
+ writel_with_flush(0xf, mmio + HOST_PORTS_IMPL);
+
+ pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor);
+
+ if (vendor == PCI_VENDOR_ID_INTEL) {
+ u16 tmp16;
+ pci_read_config_word(pdev, 0x92, &tmp16);
+ tmp16 |= 0xf;
+ pci_write_config_word(pdev, 0x92, tmp16);
+ }
+
+ probe_ent->cap = readl(mmio + HOST_CAP);
+ probe_ent->port_map = readl(mmio + HOST_PORTS_IMPL);
+ probe_ent->n_ports = (probe_ent->cap & 0x1f) + 1;
+
+ debug("cap 0x%x port_map 0x%x n_ports %d\n",
+ probe_ent->cap, probe_ent->port_map, probe_ent->n_ports);
+
+ for (i = 0; i < probe_ent->n_ports; i++) {
+ probe_ent->port[i].port_mmio = ahci_port_base((u32) mmio, i);
+ port_mmio = (u8 *) probe_ent->port[i].port_mmio;
+ ahci_setup_port(&probe_ent->port[i], (unsigned long)mmio, i);
+
+ /* make sure port is not active */
+ tmp = readl(port_mmio + PORT_CMD);
+ if (tmp & (PORT_CMD_LIST_ON | PORT_CMD_FIS_ON |
+ PORT_CMD_FIS_RX | PORT_CMD_START)) {
+ tmp &= ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON |
+ PORT_CMD_FIS_RX | PORT_CMD_START);
+ writel_with_flush(tmp, port_mmio + PORT_CMD);
+
+ /* spec says 500 msecs for each bit, so
+ * this is slightly incorrect.
+ */
+ msleep(500);
+ }
+
+ writel(PORT_CMD_SPIN_UP, port_mmio + PORT_CMD);
+
+ j = 0;
+ while (j < 100) {
+ msleep(10);
+ tmp = readl(port_mmio + PORT_SCR_STAT);
+ if ((tmp & 0xf) == 0x3)
+ break;
+ j++;
+ }
+
+ tmp = readl(port_mmio + PORT_SCR_ERR);
+ debug("PORT_SCR_ERR 0x%x\n", tmp);
+ writel(tmp, port_mmio + PORT_SCR_ERR);
+
+ /* ack any pending irq events for this port */
+ tmp = readl(port_mmio + PORT_IRQ_STAT);
+ debug("PORT_IRQ_STAT 0x%x\n", tmp);
+ if (tmp)
+ writel(tmp, port_mmio + PORT_IRQ_STAT);
+
+ writel(1 << i, mmio + HOST_IRQ_STAT);
+
+ /* set irq mask (enables interrupts) */
+ writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
+
+ /*register linkup ports */
+ tmp = readl(port_mmio + PORT_SCR_STAT);
+ debug("Port %d status: 0x%x\n", i, tmp);
+ if ((tmp & 0xf) == 0x03)
+ probe_ent->link_port_map |= (0x01 << i);
+ }
+
+ tmp = readl(mmio + HOST_CTL);
+ debug("HOST_CTL 0x%x\n", tmp);
+ writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
+ tmp = readl(mmio + HOST_CTL);
+ debug("HOST_CTL 0x%x\n", tmp);
+
+ pci_read_config_word(pdev, PCI_COMMAND, &tmp16);
+ tmp |= PCI_COMMAND_MASTER;
+ pci_write_config_word(pdev, PCI_COMMAND, tmp16);
+
+ return 0;
+}
+
+
+static void ahci_print_info(struct ahci_probe_ent *probe_ent)
+{
+ pci_dev_t pdev = probe_ent->dev;
+ volatile u8 *mmio = (volatile u8 *)probe_ent->mmio_base;
+ u32 vers, cap, impl, speed;
+ const char *speed_s;
+ u16 cc;
+ const char *scc_s;
+
+ vers = readl(mmio + HOST_VERSION);
+ cap = probe_ent->cap;
+ impl = probe_ent->port_map;
+
+ speed = (cap >> 20) & 0xf;
+ if (speed == 1)
+ speed_s = "1.5";
+ else if (speed == 2)
+ speed_s = "3";
+ else
+ speed_s = "?";
+
+ pci_read_config_word(pdev, 0x0a, &cc);
+ if (cc == 0x0101)
+ scc_s = "IDE";
+ else if (cc == 0x0106)
+ scc_s = "SATA";
+ else if (cc == 0x0104)
+ scc_s = "RAID";
+ else
+ scc_s = "unknown";
+
+ printf("AHCI %02x%02x.%02x%02x "
+ "%u slots %u ports %s Gbps 0x%x impl %s mode\n",
+ (vers >> 24) & 0xff,
+ (vers >> 16) & 0xff,
+ (vers >> 8) & 0xff,
+ vers & 0xff,
+ ((cap >> 8) & 0x1f) + 1, (cap & 0x1f) + 1, speed_s, impl, scc_s);
+
+ printf("flags: "
+ "%s%s%s%s%s%s"
+ "%s%s%s%s%s%s%s\n",
+ cap & (1 << 31) ? "64bit " : "",
+ cap & (1 << 30) ? "ncq " : "",
+ cap & (1 << 28) ? "ilck " : "",
+ cap & (1 << 27) ? "stag " : "",
+ cap & (1 << 26) ? "pm " : "",
+ cap & (1 << 25) ? "led " : "",
+ cap & (1 << 24) ? "clo " : "",
+ cap & (1 << 19) ? "nz " : "",
+ cap & (1 << 18) ? "only " : "",
+ cap & (1 << 17) ? "pmp " : "",
+ cap & (1 << 15) ? "pio " : "",
+ cap & (1 << 14) ? "slum " : "",
+ cap & (1 << 13) ? "part " : "");
+}
+
+static int ahci_init_one(pci_dev_t pdev)
+{
+ u16 vendor;
+ int rc;
+
+ memset((void *)ataid, 0, sizeof(hd_driveid_t *) * AHCI_MAX_PORTS);
+
+ probe_ent = malloc(sizeof(struct ahci_probe_ent));
+ memset(probe_ent, 0, sizeof(struct ahci_probe_ent));
+ probe_ent->dev = pdev;
+
+ probe_ent->host_flags = ATA_FLAG_SATA
+ | ATA_FLAG_NO_LEGACY
+ | ATA_FLAG_MMIO
+ | ATA_FLAG_PIO_DMA
+ | ATA_FLAG_NO_ATAPI;
+ probe_ent->pio_mask = 0x1f;
+ probe_ent->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */
+
+ probe_ent->mmio_base = (u32)pci_map_bar(pdev, AHCI_PCI_BAR,
+ PCI_REGION_MEM);
+
+ /* Take from kernel:
+ * JMicron-specific fixup:
+ * make sure we're in AHCI mode
+ */
+ pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor);
+ if (vendor == 0x197b)
+ pci_write_config_byte(pdev, 0x41, 0xa1);
+
+ /* initialize adapter */
+ rc = ahci_host_init(probe_ent);
+ if (rc)
+ goto err_out;
+
+ ahci_print_info(probe_ent);
+
+ return 0;
+
+ err_out:
+ return rc;
+}
+
+
+#define MAX_DATA_BYTE_COUNT (4*1024*1024)
+
+static int ahci_fill_sg(u8 port, unsigned char *buf, int buf_len)
+{
+ struct ahci_ioports *pp = &(probe_ent->port[port]);
+ struct ahci_sg *ahci_sg = pp->cmd_tbl_sg;
+ u32 sg_count;
+ int i;
+
+ sg_count = ((buf_len - 1) / MAX_DATA_BYTE_COUNT) + 1;
+ if (sg_count > AHCI_MAX_SG) {
+ printf("Error:Too much sg!\n");
+ return -1;
+ }
+
+ for (i = 0; i < sg_count; i++) {
+ ahci_sg->addr =
+ cpu_to_le32((u32) buf + i * MAX_DATA_BYTE_COUNT);
+ ahci_sg->addr_hi = 0;
+ ahci_sg->flags_size = cpu_to_le32(0x3fffff &
+ (buf_len < MAX_DATA_BYTE_COUNT
+ ? (buf_len - 1)
+ : (MAX_DATA_BYTE_COUNT - 1)));
+ ahci_sg++;
+ buf_len -= MAX_DATA_BYTE_COUNT;
+ }
+
+ return sg_count;
+}
+
+
+static void ahci_fill_cmd_slot(struct ahci_ioports *pp, u32 opts)
+{
+ pp->cmd_slot->opts = cpu_to_le32(opts);
+ pp->cmd_slot->status = 0;
+ pp->cmd_slot->tbl_addr = cpu_to_le32(pp->cmd_tbl & 0xffffffff);
+ pp->cmd_slot->tbl_addr_hi = 0;
+}
+
+
+static void ahci_set_feature(u8 port)
+{
+ struct ahci_ioports *pp = &(probe_ent->port[port]);
+ volatile u8 *port_mmio = (volatile u8 *)pp->port_mmio;
+ u32 cmd_fis_len = 5; /* five dwords */
+ u8 fis[20];
+
+ /*set feature */
+ memset(fis, 0, 20);
+ fis[0] = 0x27;
+ fis[1] = 1 << 7;
+ fis[2] = ATA_CMD_SETF;
+ fis[3] = SETFEATURES_XFER;
+ fis[12] = __ilog2(probe_ent->udma_mask + 1) + 0x40 - 0x01;
+
+ memcpy((unsigned char *)pp->cmd_tbl, fis, 20);
+ ahci_fill_cmd_slot(pp, cmd_fis_len);
+ writel(1, port_mmio + PORT_CMD_ISSUE);
+ readl(port_mmio + PORT_CMD_ISSUE);
+
+ if (waiting_for_cmd_completed(port_mmio + PORT_CMD_ISSUE, 150, 0x1)) {
+ printf("set feature error!\n");
+ }
+}
+
+
+static int ahci_port_start(u8 port)
+{
+ struct ahci_ioports *pp = &(probe_ent->port[port]);
+ volatile u8 *port_mmio = (volatile u8 *)pp->port_mmio;
+ u32 port_status;
+ u32 mem;
+
+ debug("Enter start port: %d\n", port);
+ port_status = readl(port_mmio + PORT_SCR_STAT);
+ debug("Port %d status: %x\n", port, port_status);
+ if ((port_status & 0xf) != 0x03) {
+ printf("No Link on this port!\n");
+ return -1;
+ }
+
+ mem = (u32) malloc(AHCI_PORT_PRIV_DMA_SZ + 2048);
+ if (!mem) {
+ free(pp);
+ printf("No mem for table!\n");
+ return -ENOMEM;
+ }
+
+ mem = (mem + 0x800) & (~0x7ff); /* Aligned to 2048-bytes */
+ memset((u8 *) mem, 0, AHCI_PORT_PRIV_DMA_SZ);
+
+ /*
+ * First item in chunk of DMA memory: 32-slot command table,
+ * 32 bytes each in size
+ */
+ pp->cmd_slot = (struct ahci_cmd_hdr *)mem;
+ debug("cmd_slot = 0x%x\n", pp->cmd_slot);
+ mem += (AHCI_CMD_SLOT_SZ + 224);
+
+ /*
+ * Second item: Received-FIS area
+ */
+ pp->rx_fis = mem;
+ mem += AHCI_RX_FIS_SZ;
+
+ /*
+ * Third item: data area for storing a single command
+ * and its scatter-gather table
+ */
+ pp->cmd_tbl = mem;
+ debug("cmd_tbl_dma = 0x%x\n", pp->cmd_tbl);
+
+ mem += AHCI_CMD_TBL_HDR;
+ pp->cmd_tbl_sg = (struct ahci_sg *)mem;
+
+ writel_with_flush((u32) pp->cmd_slot, port_mmio + PORT_LST_ADDR);
+
+ writel_with_flush(pp->rx_fis, port_mmio + PORT_FIS_ADDR);
+
+ writel_with_flush(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX |
+ PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP |
+ PORT_CMD_START, port_mmio + PORT_CMD);
+
+ debug("Exit start port %d\n", port);
+
+ return 0;
+}
+
+
+static int get_ahci_device_data(u8 port, u8 *fis, int fis_len, u8 *buf,
+ int buf_len)
+{
+
+ struct ahci_ioports *pp = &(probe_ent->port[port]);
+ volatile u8 *port_mmio = (volatile u8 *)pp->port_mmio;
+ u32 opts;
+ u32 port_status;
+ int sg_count;
+
+ debug("Enter get_ahci_device_data: for port %d\n", port);
+
+ if (port > probe_ent->n_ports) {
+ printf("Invaild port number %d\n", port);
+ return -1;
+ }
+
+ port_status = readl(port_mmio + PORT_SCR_STAT);
+ if ((port_status & 0xf) != 0x03) {
+ debug("No Link on port %d!\n", port);
+ return -1;
+ }
+
+ memcpy((unsigned char *)pp->cmd_tbl, fis, fis_len);
+
+ sg_count = ahci_fill_sg(port, buf, buf_len);
+ opts = (fis_len >> 2) | (sg_count << 16);
+ ahci_fill_cmd_slot(pp, opts);
+
+ writel_with_flush(1, port_mmio + PORT_CMD_ISSUE);
+
+ if (waiting_for_cmd_completed(port_mmio + PORT_CMD_ISSUE, 150, 0x1)) {
+ printf("timeout exit!\n");
+ return -1;
+ }
+ debug("get_ahci_device_data: %d byte transferred.\n",
+ pp->cmd_slot->status);
+
+ return 0;
+}
+
+
+static char *ata_id_strcpy(u16 *target, u16 *src, int len)
+{
+ int i;
+ for (i = 0; i < len / 2; i++)
+ target[i] = le16_to_cpu(src[i]);
+ return (char *)target;
+}
+
+
+static void dump_ataid(hd_driveid_t *ataid)
+{
+ debug("(49)ataid->capability = 0x%x\n", ataid->capability);
+ debug("(53)ataid->field_valid =0x%x\n", ataid->field_valid);
+ debug("(63)ataid->dma_mword = 0x%x\n", ataid->dma_mword);
+ debug("(64)ataid->eide_pio_modes = 0x%x\n", ataid->eide_pio_modes);
+ debug("(75)ataid->queue_depth = 0x%x\n", ataid->queue_depth);
+ debug("(80)ataid->major_rev_num = 0x%x\n", ataid->major_rev_num);
+ debug("(81)ataid->minor_rev_num = 0x%x\n", ataid->minor_rev_num);
+ debug("(82)ataid->command_set_1 = 0x%x\n", ataid->command_set_1);
+ debug("(83)ataid->command_set_2 = 0x%x\n", ataid->command_set_2);
+ debug("(84)ataid->cfsse = 0x%x\n", ataid->cfsse);
+ debug("(85)ataid->cfs_enable_1 = 0x%x\n", ataid->cfs_enable_1);
+ debug("(86)ataid->cfs_enable_2 = 0x%x\n", ataid->cfs_enable_2);
+ debug("(87)ataid->csf_default = 0x%x\n", ataid->csf_default);
+ debug("(88)ataid->dma_ultra = 0x%x\n", ataid->dma_ultra);
+ debug("(93)ataid->hw_config = 0x%x\n", ataid->hw_config);
+}
+
+
+/*
+ * SCSI INQUIRY command operation.
+ */
+static int ata_scsiop_inquiry(ccb *pccb)
+{
+ u8 hdr[] = {
+ 0,
+ 0,
+ 0x5, /* claim SPC-3 version compatibility */
+ 2,
+ 95 - 4,
+ };
+ u8 fis[20];
+ u8 *tmpid;
+ u8 port;
+
+ /* Clean ccb data buffer */
+ memset(pccb->pdata, 0, pccb->datalen);
+
+ memcpy(pccb->pdata, hdr, sizeof(hdr));
+
+ if (pccb->datalen <= 35)
+ return 0;
+
+ memset(fis, 0, 20);
+ /* Construct the FIS */
+ fis[0] = 0x27; /* Host to device FIS. */
+ fis[1] = 1 << 7; /* Command FIS. */
+ fis[2] = ATA_CMD_IDENT; /* Command byte. */
+
+ /* Read id from sata */
+ port = pccb->target;
+ if (!(tmpid = malloc(sizeof(hd_driveid_t))))
+ return -ENOMEM;
+
+ if (get_ahci_device_data(port, (u8 *) & fis, 20,
+ tmpid, sizeof(hd_driveid_t))) {
+ debug("scsi_ahci: SCSI inquiry command failure.\n");
+ return -EIO;
+ }
+
+ if (ataid[port])
+ free(ataid[port]);
+ ataid[port] = (hd_driveid_t *) tmpid;
+
+ memcpy(&pccb->pdata[8], "ATA ", 8);
+ ata_id_strcpy((u16 *) &pccb->pdata[16], (u16 *)ataid[port]->model, 16);
+ ata_id_strcpy((u16 *) &pccb->pdata[32], (u16 *)ataid[port]->fw_rev, 4);
+
+ dump_ataid(ataid[port]);
+ return 0;
+}
+
+
+/*
+ * SCSI READ10 command operation.
+ */
+static int ata_scsiop_read10(ccb * pccb)
+{
+ u64 lba = 0;
+ u32 len = 0;
+ u8 fis[20];
+
+ lba = (((u64) pccb->cmd[2]) << 24) | (((u64) pccb->cmd[3]) << 16)
+ | (((u64) pccb->cmd[4]) << 8) | ((u64) pccb->cmd[5]);
+ len = (((u32) pccb->cmd[7]) << 8) | ((u32) pccb->cmd[8]);
+
+ /* For 10-byte and 16-byte SCSI R/W commands, transfer
+ * length 0 means transfer 0 block of data.
+ * However, for ATA R/W commands, sector count 0 means
+ * 256 or 65536 sectors, not 0 sectors as in SCSI.
+ *
+ * WARNING: one or two older ATA drives treat 0 as 0...
+ */
+ if (!len)
+ return 0;
+ memset(fis, 0, 20);
+
+ /* Construct the FIS */
+ fis[0] = 0x27; /* Host to device FIS. */
+ fis[1] = 1 << 7; /* Command FIS. */
+ fis[2] = ATA_CMD_RD_DMA; /* Command byte. */
+
+ /* LBA address, only support LBA28 in this driver */
+ fis[4] = pccb->cmd[5];
+ fis[5] = pccb->cmd[4];
+ fis[6] = pccb->cmd[3];
+ fis[7] = (pccb->cmd[2] & 0x0f) | 0xe0;
+
+ /* Sector Count */
+ fis[12] = pccb->cmd[8];
+ fis[13] = pccb->cmd[7];
+
+ /* Read from ahci */
+ if (get_ahci_device_data(pccb->target, (u8 *) & fis, 20,
+ pccb->pdata, pccb->datalen)) {
+ debug("scsi_ahci: SCSI READ10 command failure.\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+
+/*
+ * SCSI READ CAPACITY10 command operation.
+ */
+static int ata_scsiop_read_capacity10(ccb *pccb)
+{
+ u32 cap;
+
+ if (!ataid[pccb->target]) {
+ printf("scsi_ahci: SCSI READ CAPACITY10 command failure. "
+ "\tNo ATA info!\n"
+ "\tPlease run SCSI commmand INQUIRY firstly!\n");
+ return -EPERM;
+ }
+
+ cap = le32_to_cpu(ataid[pccb->target]->lba_capacity);
+ memcpy(pccb->pdata, &cap, sizeof(cap));
+
+ pccb->pdata[4] = pccb->pdata[5] = 0;
+ pccb->pdata[6] = 512 >> 8;
+ pccb->pdata[7] = 512 & 0xff;
+
+ return 0;
+}
+
+
+/*
+ * SCSI TEST UNIT READY command operation.
+ */
+static int ata_scsiop_test_unit_ready(ccb *pccb)
+{
+ return (ataid[pccb->target]) ? 0 : -EPERM;
+}
+
+
+int scsi_exec(ccb *pccb)
+{
+ int ret;
+
+ switch (pccb->cmd[0]) {
+ case SCSI_READ10:
+ ret = ata_scsiop_read10(pccb);
+ break;
+ case SCSI_RD_CAPAC:
+ ret = ata_scsiop_read_capacity10(pccb);
+ break;
+ case SCSI_TST_U_RDY:
+ ret = ata_scsiop_test_unit_ready(pccb);
+ break;
+ case SCSI_INQUIRY:
+ ret = ata_scsiop_inquiry(pccb);
+ break;
+ default:
+ printf("Unsupport SCSI command 0x%02x\n", pccb->cmd[0]);
+ return FALSE;
+ }
+
+ if (ret) {
+ debug("SCSI command 0x%02x ret errno %d\n", pccb->cmd[0], ret);
+ return FALSE;
+ }
+ return TRUE;
+
+}
+
+
+void scsi_low_level_init(int busdevfunc)
+{
+ int i;
+ u32 linkmap;
+
+ ahci_init_one(busdevfunc);
+
+ linkmap = probe_ent->link_port_map;
+
+ for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) {
+ if (((linkmap >> i) & 0x01)) {
+ if (ahci_port_start((u8) i)) {
+ printf("Can not start port %d\n", i);
+ continue;
+ }
+ ahci_set_feature((u8) i);
+ }
+ }
+}
+
+
+void scsi_bus_reset(void)
+{
+ /*Not implement*/
+}
+
+
+void scsi_print_error(ccb * pccb)
+{
+ /*The ahci error info can be read in the ahci driver*/
+}
diff --git a/u-boot/drivers/block/ata_piix.c b/u-boot/drivers/block/ata_piix.c
new file mode 100644
index 0000000..c81d11a
--- /dev/null
+++ b/u-boot/drivers/block/ata_piix.c
@@ -0,0 +1,756 @@
+/*
+ * Copyright (C) Procsys. All rights reserved.
+ * Author: Mushtaq Khan <mushtaq_k@procsys.com>
+ * <mushtaqk_921@yahoo.co.in>
+ *
+ * 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
+ *
+ * with the reference to ata_piix driver in kernel 2.4.32
+ */
+
+/*
+ * This file contains SATA controller and SATA drive initialization functions
+ */
+
+#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>
+
+extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE];
+extern int sata_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 "ata_piix.h"
+
+/*Macros realted to PCI*/
+#define PCI_SATA_BUS 0x00
+#define PCI_SATA_DEV 0x1f
+#define PCI_SATA_FUNC 0x02
+
+#define PCI_SATA_BASE1 0x10
+#define PCI_SATA_BASE2 0x14
+#define PCI_SATA_BASE3 0x18
+#define PCI_SATA_BASE4 0x1c
+#define PCI_SATA_BASE5 0x20
+#define PCI_PMR 0x90
+#define PCI_PI 0x09
+#define PCI_PCS 0x92
+#define PCI_DMA_CTL 0x48
+
+#define PORT_PRESENT (1<<0)
+#define PORT_ENABLED (1<<4)
+
+u32 bdf;
+u32 iobase1 = 0; /*Primary cmd block */
+u32 iobase2 = 0; /*Primary ctl block */
+u32 iobase3 = 0; /*Sec cmd block */
+u32 iobase4 = 0; /*sec ctl block */
+u32 iobase5 = 0; /*BMDMA*/
+int
+pci_sata_init (void)
+{
+ u32 bus = PCI_SATA_BUS;
+ u32 dev = PCI_SATA_DEV;
+ u32 fun = PCI_SATA_FUNC;
+ u16 cmd = 0;
+ u8 lat = 0, pcibios_max_latency = 0xff;
+ u8 pmr; /*Port mapping reg */
+ u8 pi; /*Prgming Interface reg */
+
+ bdf = PCI_BDF (bus, dev, fun);
+ pci_read_config_dword (bdf, PCI_SATA_BASE1, &iobase1);
+ pci_read_config_dword (bdf, PCI_SATA_BASE2, &iobase2);
+ pci_read_config_dword (bdf, PCI_SATA_BASE3, &iobase3);
+ pci_read_config_dword (bdf, PCI_SATA_BASE4, &iobase4);
+ pci_read_config_dword (bdf, PCI_SATA_BASE5, &iobase5);
+
+ if ((iobase1 == 0xFFFFFFFF) || (iobase2 == 0xFFFFFFFF) ||
+ (iobase3 == 0xFFFFFFFF) || (iobase4 == 0xFFFFFFFF) ||
+ (iobase5 == 0xFFFFFFFF)) {
+ printf ("error no base addr for SATA controller\n");
+ return 1;
+ /*ERROR*/}
+
+ iobase1 &= 0xFFFFFFFE;
+ iobase2 &= 0xFFFFFFFE;
+ iobase3 &= 0xFFFFFFFE;
+ iobase4 &= 0xFFFFFFFE;
+ iobase5 &= 0xFFFFFFFE;
+
+ /*check for mode */
+ pci_read_config_byte (bdf, PCI_PMR, &pmr);
+ if (pmr > 1) {
+ printf ("combined mode not supported\n");
+ return 1;
+ }
+
+ pci_read_config_byte (bdf, PCI_PI, &pi);
+ if ((pi & 0x05) != 0x05) {
+ printf ("Sata is in Legacy mode\n");
+ return 1;
+ } else {
+ printf ("sata is in Native mode\n");
+ }
+
+ /*MASTER CFG AND IO CFG */
+ pci_read_config_word (bdf, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_IO;
+ pci_write_config_word (bdf, PCI_COMMAND, cmd);
+ pci_read_config_byte (dev, PCI_LATENCY_TIMER, &lat);
+
+ if (lat < 16)
+ lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+ else if (lat > pcibios_max_latency)
+ lat = pcibios_max_latency;
+ pci_write_config_byte (dev, PCI_LATENCY_TIMER, lat);
+
+ return 0;
+}
+
+int
+sata_bus_probe (int port_no)
+{
+ int orig_mask, mask;
+ u16 pcs;
+
+ mask = (PORT_PRESENT << port_no);
+ pci_read_config_word (bdf, PCI_PCS, &pcs);
+ orig_mask = (int) pcs & 0xff;
+ if ((orig_mask & mask) != mask)
+ return 0;
+ else
+ return 1;
+}
+
+int
+init_sata (int dev)
+{
+ static int done = 0;
+ u8 i, rv = 0;
+
+ if (!done)
+ done = 1;
+ else
+ return 0;
+
+ rv = pci_sata_init ();
+ if (rv == 1) {
+ printf ("pci initialization failed\n");
+ return 1;
+ }
+
+ port[0].port_no = 0;
+ port[0].ioaddr.cmd_addr = iobase1;
+ port[0].ioaddr.altstatus_addr = port[0].ioaddr.ctl_addr =
+ iobase2 | ATA_PCI_CTL_OFS;
+ port[0].ioaddr.bmdma_addr = iobase5;
+
+ port[1].port_no = 1;
+ port[1].ioaddr.cmd_addr = iobase3;
+ port[1].ioaddr.altstatus_addr = port[1].ioaddr.ctl_addr =
+ iobase4 | ATA_PCI_CTL_OFS;
+ port[1].ioaddr.bmdma_addr = iobase5 + 0x8;
+
+ for (i = 0; i < CONFIG_SYS_SATA_MAXBUS; i++)
+ sata_port (&port[i].ioaddr);
+
+ for (i = 0; i < CONFIG_SYS_SATA_MAXBUS; i++) {
+ if (!(sata_bus_probe (i))) {
+ port[i].port_state = 0;
+ printf ("SATA#%d port is not present \n", i);
+ } else {
+ printf ("SATA#%d port is present\n", i);
+ if (sata_bus_softreset (i)) {
+ port[i].port_state = 0;
+ } else {
+ port[i].port_state = 1;
+ }
+ }
+ }
+
+ for (i = 0; i < CONFIG_SYS_SATA_MAXBUS; i++) {
+ u8 j, devno;
+
+ if (port[i].port_state == 0)
+ continue;
+ for (j = 0; j < CONFIG_SYS_SATA_DEVS_PER_BUS; j++) {
+ sata_identify (i, j);
+ set_Feature_cmd (i, j);
+ devno = i * CONFIG_SYS_SATA_DEVS_PER_BUS + j;
+ if ((sata_dev_desc[devno].lba > 0) &&
+ (sata_dev_desc[devno].blksz > 0)) {
+ dev_print (&sata_dev_desc[devno]);
+ /* initialize partition type */
+ init_part (&sata_dev_desc[devno]);
+ if (sata_curr_device < 0)
+ sata_curr_device =
+ i * CONFIG_SYS_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 < CONFIG_SYS_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", num);
+
+ while ((status & ATA_BUSY)) {
+ msleep (100);
+ status = sata_chk_status (&port[num].ioaddr);
+ }
+
+ if (status & ATA_BUSY) {
+ printf ("ata%u failed to respond : ", num);
+ printf ("bus reset failed\n");
+ return 1;
+ }
+ return 0;
+}
+
+void
+sata_identify (int num, int dev)
+{
+ u8 cmd = 0, status = 0, devno = num * CONFIG_SYS_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 ((unsigned char *)sata_dev_desc[devno].revision, iop->fw_rev,
+ sizeof (sata_dev_desc[devno].revision));
+ sata_cpy ((unsigned char *)sata_dev_desc[devno].vendor, iop->model,
+ sizeof (sata_dev_desc[devno].vendor));
+ sata_cpy ((unsigned char *)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 / CONFIG_SYS_SATA_DEVS_PER_BUS;
+ /*dev on the port */
+ if (device >= CONFIG_SYS_SATA_DEVS_PER_BUS)
+ dev = device - CONFIG_SYS_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 / CONFIG_SYS_SATA_DEVS_PER_BUS;
+ /*dev on the Port */
+ if (device >= CONFIG_SYS_SATA_DEVS_PER_BUS)
+ dev = device - CONFIG_SYS_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;
+}
diff --git a/u-boot/drivers/block/ata_piix.h b/u-boot/drivers/block/ata_piix.h
new file mode 100644
index 0000000..9157cf8
--- /dev/null
+++ b/u-boot/drivers/block/ata_piix.h
@@ -0,0 +1,81 @@
+#ifndef __ATA_PIIX_H__
+#define __ATA_PIIX_H__
+
+#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 */
+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[CONFIG_SYS_SATA_MAXBUS];
+#endif
+
+#endif /* __ATA_PIIX_H__ */
diff --git a/u-boot/drivers/block/fsl_sata.c b/u-boot/drivers/block/fsl_sata.c
new file mode 100644
index 0000000..4b97a0e
--- /dev/null
+++ b/u-boot/drivers/block/fsl_sata.c
@@ -0,0 +1,942 @@
+/*
+ * Copyright (C) 2008,2010 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 <asm/processor.h>
+#include <asm/fsl_serdes.h>
+#include <malloc.h>
+#include <libata.h>
+#include <fis.h>
+#include "fsl_sata.h"
+
+extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE];
+
+#ifndef CONFIG_SYS_SATA1_FLAGS
+ #define CONFIG_SYS_SATA1_FLAGS FLAGS_DMA
+#endif
+#ifndef CONFIG_SYS_SATA2_FLAGS
+ #define CONFIG_SYS_SATA2_FLAGS FLAGS_DMA
+#endif
+
+static struct fsl_sata_info fsl_sata_info[] = {
+#ifdef CONFIG_SATA1
+ {CONFIG_SYS_SATA1, CONFIG_SYS_SATA1_FLAGS},
+#else
+ {0, 0},
+#endif
+#ifdef CONFIG_SATA2
+ {CONFIG_SYS_SATA2, CONFIG_SYS_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 sata_fis_d2h *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 > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) {
+ printf("the sata index %d is out of ranges\n\r", dev);
+ return -1;
+ }
+
+#ifdef CONFIG_MPC85xx
+ if ((dev == 0) && (!is_serdes_configured(SATA1))) {
+ printf("SATA%d [dev = %d] is not enabled\n", dev+1, dev);
+ return -1;
+ }
+ if ((dev == 1) && (!is_serdes_configured(SATA2))) {
+ printf("SATA%d [dev = %d] is not enabled\n", dev+1, dev);
+ return -1;
+ }
+#endif
+
+ /* 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);
+
+#if defined(CONFIG_FSL_SATA_V2) && defined(CONFIG_FSL_SATA_ERRATUM_A001)
+ /*
+ * For P1022/1013 Rev1.0 silicon, after power on SATA host
+ * controller is configured in legacy mode instead of the
+ * expected enterprise mode. software needs to clear bit[28]
+ * of HControl register to change to enterprise mode from
+ * legacy mode.
+ */
+ {
+ u32 svr = get_svr();
+ if (IS_SVR_REV(svr, 1, 0) &&
+ ((SVR_SOC_VER(svr) == SVR_P1022) ||
+ (SVR_SOC_VER(svr) == SVR_P1022_E) ||
+ (SVR_SOC_VER(svr) == SVR_P1013) ||
+ (SVR_SOC_VER(svr) == SVR_P1013_E))) {
+ out_le32(&reg->hstatus, 0x20000000);
+ out_le32(&reg->hcontrol, 0x00000100);
+ }
+ }
+#endif
+
+ /* 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);
+
+ /* Wait PHY RDY signal changed for 500ms */
+ ata_wait_register(&reg->hstatus, HSTATUS_PHY_RDY,
+ HSTATUS_PHY_RDY, 500);
+
+ /* 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;
+ }
+
+ /* Wait for signature updated, which is 1st D2H */
+ ata_wait_register(&reg->hstatus, HSTATUS_SIGNATURE,
+ HSTATUS_SIGNATURE, 10000);
+
+ 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 sata_fis_h2d *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 sata_fis_d2h *)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 sata_fis_h2d *cfis,
+ int tag, u8 *buffer, u32 len)
+{
+ return 0;
+}
+
+static int fsl_sata_exec_cmd(struct fsl_sata *sata, struct sata_fis_h2d *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=%d\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, *cfis = &h2d;
+
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
+
+ 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, *cfis = &h2d;
+ u8 udma_cap;
+
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
+
+ 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, *cfis = &h2d;
+ u32 block;
+
+ block = start;
+
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
+
+ cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+ cfis->pm_port_c = 0x80; /* is command */
+ cfis->command = (is_write) ? ATA_CMD_WRITE : ATA_CMD_READ;
+ 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, *cfis = &h2d;
+
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
+
+ cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+ cfis->pm_port_c = 0x80; /* is command */
+ cfis->command = ATA_CMD_FLUSH;
+
+ 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, *cfis = &h2d;
+ u64 block;
+
+ block = (u64)start;
+
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
+
+ cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+ cfis->pm_port_c = 0x80; /* is command */
+
+ cfis->command = (is_write) ? ATA_CMD_WRITE_EXT
+ : ATA_CMD_READ_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, *cfis = &h2d;
+ 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;
+
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
+
+ cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+ cfis->pm_port_c = 0x80; /* is command */
+
+ cfis->command = (is_write) ? ATA_CMD_FPDMA_WRITE
+ : ATA_CMD_FPDMA_READ;
+
+ 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, *cfis = &h2d;
+
+ memset(cfis, 0, sizeof(struct sata_fis_h2d));
+
+ cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+ cfis->pm_port_c = 0x80; /* is command */
+ cfis->command = ATA_CMD_FLUSH_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/u-boot/drivers/block/fsl_sata.h b/u-boot/drivers/block/fsl_sata.h
new file mode 100644
index 0000000..576efaf
--- /dev/null
+++ b/u-boot/drivers/block/fsl_sata.h
@@ -0,0 +1,332 @@
+/*
+ * 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 */
+#ifdef CONFIG_FSL_SATA_V2
+#define PRD_ENTRY_DATA_SNOOP 0x10000000 /* Data snoop enable */
+#else
+#define PRD_ENTRY_DATA_SNOOP 0x00400000 /* Data snoop enable */
+#endif
+#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
+
+/*
+ * 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/u-boot/drivers/block/libata.c b/u-boot/drivers/block/libata.c
new file mode 100644
index 0000000..65b0203
--- /dev/null
+++ b/u-boot/drivers/block/libata.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2008 Freescale Semiconductor, Inc.
+ * Dave Liu <daveliu@freescale.com>
+ * port from the libata of linux kernel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <libata.h>
+
+u64 ata_id_n_sectors(u16 *id)
+{
+ if (ata_id_has_lba(id)) {
+ if (ata_id_has_lba48(id))
+ return ata_id_u64(id, ATA_ID_LBA48_SECTORS);
+ else
+ return ata_id_u32(id, ATA_ID_LBA_SECTORS);
+ } else {
+ return 0;
+ }
+}
+
+u32 ata_dev_classify(u32 sig)
+{
+ u8 lbam, lbah;
+
+ lbam = (sig >> 16) & 0xff;
+ lbah = (sig >> 24) & 0xff;
+
+ if (((lbam == 0) && (lbah == 0)) ||
+ ((lbam == 0x3c) && (lbah == 0xc3)))
+ return ATA_DEV_ATA;
+
+ if ((lbam == 0x14) && (lbah == 0xeb))
+ return ATA_DEV_ATAPI;
+
+ if ((lbam == 0x69) && (lbah == 0x96))
+ return ATA_DEV_PMP;
+
+ return ATA_DEV_UNKNOWN;
+}
+
+static void ata_id_string(const u16 *id, unsigned char *s,
+ unsigned int ofs, unsigned int len)
+{
+ unsigned int c;
+
+ while (len > 0) {
+ c = id[ofs] >> 8;
+ *s = c;
+ s++;
+
+ c = id[ofs] & 0xff;
+ *s = c;
+ s++;
+
+ ofs++;
+ len -= 2;
+ }
+}
+
+void ata_id_c_string(const u16 *id, unsigned char *s,
+ unsigned int ofs, unsigned int len)
+{
+ unsigned char *p;
+
+ ata_id_string(id, s, ofs, len - 1);
+
+ p = s + strnlen((char *)s, len - 1);
+ while (p > s && p[-1] == ' ')
+ p--;
+ *p = '\0';
+}
+
+void ata_dump_id(u16 *id)
+{
+ unsigned char serial[ATA_ID_SERNO_LEN + 1];
+ unsigned char firmware[ATA_ID_FW_REV_LEN + 1];
+ unsigned char product[ATA_ID_PROD_LEN + 1];
+ u64 n_sectors;
+
+ /* Serial number */
+ ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial));
+ printf("S/N: %s\n\r", serial);
+
+ /* Firmware version */
+ ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware));
+ printf("Firmware version: %s\n\r", firmware);
+
+ /* Product model */
+ ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product));
+ printf("Product model number: %s\n\r", product);
+
+ /* Total sectors of device */
+ n_sectors = ata_id_n_sectors(id);
+ printf("Capablity: %lld sectors\n\r", n_sectors);
+
+ printf ("id[49]: capabilities = 0x%04x\n"
+ "id[53]: field valid = 0x%04x\n"
+ "id[63]: mwdma = 0x%04x\n"
+ "id[64]: pio = 0x%04x\n"
+ "id[75]: queue depth = 0x%04x\n",
+ id[49],
+ id[53],
+ id[63],
+ id[64],
+ id[75]);
+
+ printf ("id[76]: sata capablity = 0x%04x\n"
+ "id[78]: sata features supported = 0x%04x\n"
+ "id[79]: sata features enable = 0x%04x\n",
+ id[76],
+ id[78],
+ id[79]);
+
+ printf ("id[80]: major version = 0x%04x\n"
+ "id[81]: minor version = 0x%04x\n"
+ "id[82]: command set supported 1 = 0x%04x\n"
+ "id[83]: command set supported 2 = 0x%04x\n"
+ "id[84]: command set extension = 0x%04x\n",
+ id[80],
+ id[81],
+ id[82],
+ id[83],
+ id[84]);
+ printf ("id[85]: command set enable 1 = 0x%04x\n"
+ "id[86]: command set enable 2 = 0x%04x\n"
+ "id[87]: command set default = 0x%04x\n"
+ "id[88]: udma = 0x%04x\n"
+ "id[93]: hardware reset result = 0x%04x\n",
+ id[85],
+ id[86],
+ id[87],
+ id[88],
+ id[93]);
+}
+
+void ata_swap_buf_le16(u16 *buf, unsigned int buf_words)
+{
+ unsigned int i;
+
+ for (i = 0; i < buf_words; i++)
+ buf[i] = le16_to_cpu(buf[i]);
+}
diff --git a/u-boot/drivers/block/mg_disk.c b/u-boot/drivers/block/mg_disk.c
new file mode 100644
index 0000000..b74307a
--- /dev/null
+++ b/u-boot/drivers/block/mg_disk.c
@@ -0,0 +1,582 @@
+/*
+ * (C) Copyright 2009 mGine co.
+ * unsik Kim <donari75@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 <malloc.h>
+#include <part.h>
+#include <ata.h>
+#include <asm/io.h>
+#include "mg_disk_prv.h"
+
+#ifndef CONFIG_MG_DISK_RES
+#define CONFIG_MG_DISK_RES 0
+#endif
+
+#define MG_RES_SEC ((CONFIG_MG_DISK_RES) << 1)
+
+static struct mg_host host;
+
+static inline u32 mg_base(void)
+{
+ return host.drv_data->base;
+}
+
+static block_dev_desc_t mg_disk_dev = {
+ .if_type = IF_TYPE_ATAPI,
+ .part_type = PART_TYPE_UNKNOWN,
+ .type = DEV_TYPE_HARDDISK,
+ .blksz = MG_SECTOR_SIZE,
+ .priv = &host };
+
+static void mg_dump_status (const char *msg, unsigned int stat, unsigned err)
+{
+ char *name = MG_DEV_NAME;
+
+ printf("%s: %s: status=0x%02x { ", name, msg, stat & 0xff);
+ if (stat & MG_REG_STATUS_BIT_BUSY)
+ printf("Busy ");
+ if (stat & MG_REG_STATUS_BIT_READY)
+ printf("DriveReady ");
+ if (stat & MG_REG_STATUS_BIT_WRITE_FAULT)
+ printf("WriteFault ");
+ if (stat & MG_REG_STATUS_BIT_SEEK_DONE)
+ printf("SeekComplete ");
+ if (stat & MG_REG_STATUS_BIT_DATA_REQ)
+ printf("DataRequest ");
+ if (stat & MG_REG_STATUS_BIT_CORRECTED_ERROR)
+ printf("CorrectedError ");
+ if (stat & MG_REG_STATUS_BIT_ERROR)
+ printf("Error ");
+ printf("}\n");
+
+ if ((stat & MG_REG_STATUS_BIT_ERROR)) {
+ printf("%s: %s: error=0x%02x { ", name, msg, err & 0xff);
+ if (err & MG_REG_ERR_BBK)
+ printf("BadSector ");
+ if (err & MG_REG_ERR_UNC)
+ printf("UncorrectableError ");
+ if (err & MG_REG_ERR_IDNF)
+ printf("SectorIdNotFound ");
+ if (err & MG_REG_ERR_ABRT)
+ printf("DriveStatusError ");
+ if (err & MG_REG_ERR_AMNF)
+ printf("AddrMarkNotFound ");
+ printf("}\n");
+ }
+}
+
+static unsigned int mg_wait (u32 expect, u32 msec)
+{
+ u8 status;
+ u32 from, cur, err;
+
+ err = MG_ERR_NONE;
+ reset_timer();
+ from = get_timer(0);
+
+ status = readb(mg_base() + MG_REG_STATUS);
+ do {
+ cur = get_timer(from);
+ if (status & MG_REG_STATUS_BIT_BUSY) {
+ if (expect == MG_REG_STATUS_BIT_BUSY)
+ break;
+ } else {
+ /* Check the error condition! */
+ if (status & MG_REG_STATUS_BIT_ERROR) {
+ err = readb(mg_base() + MG_REG_ERROR);
+ mg_dump_status("mg_wait", status, err);
+ break;
+ }
+
+ if (expect == MG_STAT_READY)
+ if (MG_READY_OK(status))
+ break;
+
+ if (expect == MG_REG_STATUS_BIT_DATA_REQ)
+ if (status & MG_REG_STATUS_BIT_DATA_REQ)
+ break;
+ }
+ status = readb(mg_base() + MG_REG_STATUS);
+ } while (cur < msec);
+
+ if (cur >= msec)
+ err = MG_ERR_TIMEOUT;
+
+ return err;
+}
+
+static int mg_get_disk_id (void)
+{
+ u16 id[(MG_SECTOR_SIZE / sizeof(u16))];
+ hd_driveid_t *iop = (hd_driveid_t *)id;
+ u32 i, err, res;
+
+ writeb(MG_CMD_ID, mg_base() + MG_REG_COMMAND);
+ err = mg_wait(MG_REG_STATUS_BIT_DATA_REQ, 3000);
+ if (err)
+ return err;
+
+ for(i = 0; i < (MG_SECTOR_SIZE / sizeof(u16)); i++)
+ id[i] = readw(mg_base() + MG_BUFF_OFFSET + i * 2);
+
+ writeb(MG_CMD_RD_CONF, mg_base() + MG_REG_COMMAND);
+ err = mg_wait(MG_STAT_READY, 3000);
+ if (err)
+ return err;
+
+ ata_swap_buf_le16(id, MG_SECTOR_SIZE / sizeof(u16));
+
+ if((iop->field_valid & 1) == 0)
+ return MG_ERR_TRANSLATION;
+
+ ata_id_c_string(id, (unsigned char *)mg_disk_dev.revision,
+ ATA_ID_FW_REV, sizeof(mg_disk_dev.revision));
+ ata_id_c_string(id, (unsigned char *)mg_disk_dev.vendor,
+ ATA_ID_PROD, sizeof(mg_disk_dev.vendor));
+ ata_id_c_string(id, (unsigned char *)mg_disk_dev.product,
+ ATA_ID_SERNO, sizeof(mg_disk_dev.product));
+
+#ifdef __BIG_ENDIAN
+ iop->lba_capacity = (iop->lba_capacity << 16) |
+ (iop->lba_capacity >> 16);
+#endif /* __BIG_ENDIAN */
+
+ if (MG_RES_SEC) {
+ MG_DBG("MG_RES_SEC=%d\n", MG_RES_SEC);
+ iop->cyls = (iop->lba_capacity - MG_RES_SEC) /
+ iop->sectors / iop->heads;
+ res = iop->lba_capacity -
+ iop->cyls * iop->heads * iop->sectors;
+ iop->lba_capacity -= res;
+ printf("mg_disk: %d sectors reserved\n", res);
+ }
+
+ mg_disk_dev.lba = iop->lba_capacity;
+ return MG_ERR_NONE;
+}
+
+static int mg_disk_reset (void)
+{
+ struct mg_drv_data *prv_data = host.drv_data;
+ s32 err;
+ u8 init_status;
+
+ /* hdd rst low */
+ prv_data->mg_hdrst_pin(0);
+ err = mg_wait(MG_REG_STATUS_BIT_BUSY, 300);
+ if(err)
+ return err;
+
+ /* hdd rst high */
+ prv_data->mg_hdrst_pin(1);
+ err = mg_wait(MG_STAT_READY, 3000);
+ if(err)
+ return err;
+
+ /* soft reset on */
+ writeb(MG_REG_CTRL_RESET | MG_REG_CTRL_INTR_DISABLE,
+ mg_base() + MG_REG_DRV_CTRL);
+ err = mg_wait(MG_REG_STATUS_BIT_BUSY, 3000);
+ if(err)
+ return err;
+
+ /* soft reset off */
+ writeb(MG_REG_CTRL_INTR_DISABLE, mg_base() + MG_REG_DRV_CTRL);
+ err = mg_wait(MG_STAT_READY, 3000);
+ if(err)
+ return err;
+
+ init_status = readb(mg_base() + MG_REG_STATUS) & 0xf;
+
+ if (init_status == 0xf)
+ return MG_ERR_INIT_STAT;
+
+ return err;
+}
+
+
+static unsigned int mg_out(unsigned int sect_num,
+ unsigned int sect_cnt,
+ unsigned int cmd)
+{
+ u32 err = MG_ERR_NONE;
+
+ err = mg_wait(MG_STAT_READY, 3000);
+ if (err)
+ return err;
+
+ writeb((u8)sect_cnt, mg_base() + MG_REG_SECT_CNT);
+ writeb((u8)sect_num, mg_base() + MG_REG_SECT_NUM);
+ writeb((u8)(sect_num >> 8), mg_base() + MG_REG_CYL_LOW);
+ writeb((u8)(sect_num >> 16), mg_base() + MG_REG_CYL_HIGH);
+ writeb((u8)((sect_num >> 24) | MG_REG_HEAD_LBA_MODE),
+ mg_base() + MG_REG_DRV_HEAD);
+ writeb(cmd, mg_base() + MG_REG_COMMAND);
+
+ return err;
+}
+
+static unsigned int mg_do_read_sects(void *buff, u32 sect_num, u32 sect_cnt)
+{
+ u32 i, j, err;
+ u8 *buff_ptr = buff;
+ union mg_uniwb uniwb;
+
+ err = mg_out(sect_num, sect_cnt, MG_CMD_RD);
+ if (err)
+ return err;
+
+ for (i = 0; i < sect_cnt; i++) {
+ err = mg_wait(MG_REG_STATUS_BIT_DATA_REQ, 3000);
+ if (err)
+ return err;
+
+ if ((u32)buff_ptr & 1) {
+ for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) {
+ uniwb.w = readw(mg_base() + MG_BUFF_OFFSET
+ + (j << 1));
+ *buff_ptr++ = uniwb.b[0];
+ *buff_ptr++ = uniwb.b[1];
+ }
+ } else {
+ for(j = 0; j < MG_SECTOR_SIZE >> 1; j++) {
+ *(u16 *)buff_ptr = readw(mg_base() +
+ MG_BUFF_OFFSET + (j << 1));
+ buff_ptr += 2;
+ }
+ }
+ writeb(MG_CMD_RD_CONF, mg_base() + MG_REG_COMMAND);
+
+ MG_DBG("%u (0x%8.8x) sector read", sect_num + i,
+ (sect_num + i) * MG_SECTOR_SIZE);
+ }
+
+ return err;
+}
+
+unsigned int mg_disk_read_sects(void *buff, u32 sect_num, u32 sect_cnt)
+{
+ u32 quotient, residue, i, err;
+ u8 *buff_ptr = buff;
+
+ quotient = sect_cnt >> 8;
+ residue = sect_cnt % 256;
+
+ for (i = 0; i < quotient; i++) {
+ MG_DBG("sect num : %u buff : 0x%8.8x", sect_num, (u32)buff_ptr);
+ err = mg_do_read_sects(buff_ptr, sect_num, 256);
+ if (err)
+ return err;
+ sect_num += 256;
+ buff_ptr += 256 * MG_SECTOR_SIZE;
+ }
+
+ if (residue) {
+ MG_DBG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr);
+ err = mg_do_read_sects(buff_ptr, sect_num, residue);
+ }
+
+ return err;
+}
+
+unsigned long mg_block_read (int dev, unsigned long start,
+ lbaint_t blkcnt, void *buffer)
+{
+ start += MG_RES_SEC;
+ if (! mg_disk_read_sects(buffer, start, blkcnt))
+ return blkcnt;
+ else
+ return 0;
+}
+
+unsigned int mg_disk_read (u32 addr, u8 *buff, u32 len)
+{
+ u8 *sect_buff, *buff_ptr = buff;
+ u32 cur_addr, next_sec_addr, end_addr, cnt, sect_num;
+ u32 err = MG_ERR_NONE;
+
+ /* TODO : sanity chk */
+ cnt = 0;
+ cur_addr = addr;
+ end_addr = addr + len;
+
+ sect_buff = malloc(MG_SECTOR_SIZE);
+
+ if (cur_addr & MG_SECTOR_SIZE_MASK) {
+ next_sec_addr = (cur_addr + MG_SECTOR_SIZE) &
+ ~MG_SECTOR_SIZE_MASK;
+ sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
+ err = mg_disk_read_sects(sect_buff, sect_num, 1);
+ if (err)
+ goto mg_read_exit;
+
+ if (end_addr < next_sec_addr) {
+ memcpy(buff_ptr,
+ sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK),
+ end_addr - cur_addr);
+ MG_DBG("copies %u byte from sector offset 0x%8.8x",
+ end_addr - cur_addr, cur_addr);
+ cur_addr = end_addr;
+ } else {
+ memcpy(buff_ptr,
+ sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK),
+ next_sec_addr - cur_addr);
+ MG_DBG("copies %u byte from sector offset 0x%8.8x",
+ next_sec_addr - cur_addr, cur_addr);
+ buff_ptr += (next_sec_addr - cur_addr);
+ cur_addr = next_sec_addr;
+ }
+ }
+
+ if (cur_addr < end_addr) {
+ sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
+ cnt = ((end_addr & ~MG_SECTOR_SIZE_MASK) - cur_addr) >>
+ MG_SECTOR_SIZE_SHIFT;
+
+ if (cnt)
+ err = mg_disk_read_sects(buff_ptr, sect_num, cnt);
+ if (err)
+ goto mg_read_exit;
+
+ buff_ptr += cnt * MG_SECTOR_SIZE;
+ cur_addr += cnt * MG_SECTOR_SIZE;
+
+ if (cur_addr < end_addr) {
+ sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
+ err = mg_disk_read_sects(sect_buff, sect_num, 1);
+ if (err)
+ goto mg_read_exit;
+ memcpy(buff_ptr, sect_buff, end_addr - cur_addr);
+ MG_DBG("copies %u byte", end_addr - cur_addr);
+ }
+ }
+
+mg_read_exit:
+ free(sect_buff);
+
+ return err;
+}
+static int mg_do_write_sects(void *buff, u32 sect_num, u32 sect_cnt)
+{
+ u32 i, j, err;
+ u8 *buff_ptr = buff;
+ union mg_uniwb uniwb;
+
+ err = mg_out(sect_num, sect_cnt, MG_CMD_WR);
+ if (err)
+ return err;
+
+ for (i = 0; i < sect_cnt; i++) {
+ err = mg_wait(MG_REG_STATUS_BIT_DATA_REQ, 3000);
+ if (err)
+ return err;
+
+ if ((u32)buff_ptr & 1) {
+ uniwb.b[0] = *buff_ptr++;
+ uniwb.b[1] = *buff_ptr++;
+ writew(uniwb.w, mg_base() + MG_BUFF_OFFSET + (j << 1));
+ } else {
+ for(j = 0; j < MG_SECTOR_SIZE >> 1; j++) {
+ writew(*(u16 *)buff_ptr,
+ mg_base() + MG_BUFF_OFFSET +
+ (j << 1));
+ buff_ptr += 2;
+ }
+ }
+ writeb(MG_CMD_WR_CONF, mg_base() + MG_REG_COMMAND);
+
+ MG_DBG("%u (0x%8.8x) sector write",
+ sect_num + i, (sect_num + i) * MG_SECTOR_SIZE);
+ }
+
+ return err;
+}
+
+unsigned int mg_disk_write_sects(void *buff, u32 sect_num, u32 sect_cnt)
+{
+ u32 quotient, residue, i;
+ u32 err = MG_ERR_NONE;
+ u8 *buff_ptr = buff;
+
+ quotient = sect_cnt >> 8;
+ residue = sect_cnt % 256;
+
+ for (i = 0; i < quotient; i++) {
+ MG_DBG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr);
+ err = mg_do_write_sects(buff_ptr, sect_num, 256);
+ if (err)
+ return err;
+ sect_num += 256;
+ buff_ptr += 256 * MG_SECTOR_SIZE;
+ }
+
+ if (residue) {
+ MG_DBG("sect num : %u buff : %8.8x", sect_num, (u32)buff_ptr);
+ err = mg_do_write_sects(buff_ptr, sect_num, residue);
+ }
+
+ return err;
+}
+
+unsigned long mg_block_write (int dev, unsigned long start,
+ lbaint_t blkcnt, const void *buffer)
+{
+ start += MG_RES_SEC;
+ if (!mg_disk_write_sects((void *)buffer, start, blkcnt))
+ return blkcnt;
+ else
+ return 0;
+}
+
+unsigned int mg_disk_write(u32 addr, u8 *buff, u32 len)
+{
+ u8 *sect_buff, *buff_ptr = buff;
+ u32 cur_addr, next_sec_addr, end_addr, cnt, sect_num;
+ u32 err = MG_ERR_NONE;
+
+ /* TODO : sanity chk */
+ cnt = 0;
+ cur_addr = addr;
+ end_addr = addr + len;
+
+ sect_buff = malloc(MG_SECTOR_SIZE);
+
+ if (cur_addr & MG_SECTOR_SIZE_MASK) {
+
+ next_sec_addr = (cur_addr + MG_SECTOR_SIZE) &
+ ~MG_SECTOR_SIZE_MASK;
+ sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
+ err = mg_disk_read_sects(sect_buff, sect_num, 1);
+ if (err)
+ goto mg_write_exit;
+
+ if (end_addr < next_sec_addr) {
+ memcpy(sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK),
+ buff_ptr, end_addr - cur_addr);
+ MG_DBG("copies %u byte to sector offset 0x%8.8x",
+ end_addr - cur_addr, cur_addr);
+ cur_addr = end_addr;
+ } else {
+ memcpy(sect_buff + (cur_addr & MG_SECTOR_SIZE_MASK),
+ buff_ptr, next_sec_addr - cur_addr);
+ MG_DBG("copies %u byte to sector offset 0x%8.8x",
+ next_sec_addr - cur_addr, cur_addr);
+ buff_ptr += (next_sec_addr - cur_addr);
+ cur_addr = next_sec_addr;
+ }
+
+ err = mg_disk_write_sects(sect_buff, sect_num, 1);
+ if (err)
+ goto mg_write_exit;
+ }
+
+ if (cur_addr < end_addr) {
+
+ sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
+ cnt = ((end_addr & ~MG_SECTOR_SIZE_MASK) - cur_addr) >>
+ MG_SECTOR_SIZE_SHIFT;
+
+ if (cnt)
+ err = mg_disk_write_sects(buff_ptr, sect_num, cnt);
+ if (err)
+ goto mg_write_exit;
+
+ buff_ptr += cnt * MG_SECTOR_SIZE;
+ cur_addr += cnt * MG_SECTOR_SIZE;
+
+ if (cur_addr < end_addr) {
+ sect_num = cur_addr >> MG_SECTOR_SIZE_SHIFT;
+ err = mg_disk_read_sects(sect_buff, sect_num, 1);
+ if (err)
+ goto mg_write_exit;
+ memcpy(sect_buff, buff_ptr, end_addr - cur_addr);
+ MG_DBG("copies %u byte", end_addr - cur_addr);
+ err = mg_disk_write_sects(sect_buff, sect_num, 1);
+ }
+
+ }
+
+mg_write_exit:
+ free(sect_buff);
+
+ return err;
+}
+
+block_dev_desc_t *mg_disk_get_dev(int dev)
+{
+ return ((block_dev_desc_t *) & mg_disk_dev);
+}
+
+/* must override this function */
+struct mg_drv_data * __attribute__((weak)) mg_get_drv_data (void)
+{
+ puts ("### WARNING ### port mg_get_drv_data function\n");
+ return NULL;
+}
+
+unsigned int mg_disk_init (void)
+{
+ struct mg_drv_data *prv_data;
+ u32 err = MG_ERR_NONE;
+
+ prv_data = mg_get_drv_data();
+ if (! prv_data) {
+ printf("%s:%d fail (no driver_data)\n", __func__, __LINE__);
+ err = MG_ERR_NO_DRV_DATA;
+ return err;
+ }
+
+ ((struct mg_host *)mg_disk_dev.priv)->drv_data = prv_data;
+
+ /* init ctrl pin */
+ if (prv_data->mg_ctrl_pin_init)
+ prv_data->mg_ctrl_pin_init();
+
+ if (! prv_data->mg_hdrst_pin) {
+ err = MG_ERR_CTRL_RST;
+ return err;
+ }
+
+ /* disk reset */
+ err = mg_disk_reset();
+ if (err) {
+ printf("%s:%d fail (err code : %d)\n", __func__, __LINE__, err);
+ return err;
+ }
+
+ /* get disk id */
+ err = mg_get_disk_id();
+ if (err) {
+ printf("%s:%d fail (err code : %d)\n", __func__, __LINE__, err);
+ return err;
+ }
+
+ mg_disk_dev.block_read = mg_block_read;
+ mg_disk_dev.block_write = mg_block_write;
+
+ init_part(&mg_disk_dev);
+
+ dev_print(&mg_disk_dev);
+
+ return err;
+}
diff --git a/u-boot/drivers/block/mg_disk_prv.h b/u-boot/drivers/block/mg_disk_prv.h
new file mode 100644
index 0000000..43e90ea
--- /dev/null
+++ b/u-boot/drivers/block/mg_disk_prv.h
@@ -0,0 +1,144 @@
+/*
+ * (C) Copyright 2009 mGine co.
+ * unsik Kim <donari75@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 __MG_DISK_PRV_H__
+#define __MG_DISK_PRV_H__
+
+#include <mg_disk.h>
+
+/* name for block device */
+#define MG_DISK_NAME "mgd"
+/* name for platform device */
+#define MG_DEV_NAME "mg_disk"
+
+#define MG_DISK_MAJ 240
+#define MG_DISK_MAX_PART 16
+#define MG_SECTOR_SIZE 512
+#define MG_SECTOR_SIZE_MASK (512 - 1)
+#define MG_SECTOR_SIZE_SHIFT (9)
+#define MG_MAX_SECTS 256
+
+/* Register offsets */
+#define MG_BUFF_OFFSET 0x8000
+#define MG_STORAGE_BUFFER_SIZE 0x200
+#define MG_REG_OFFSET 0xC000
+#define MG_REG_FEATURE (MG_REG_OFFSET + 2) /* write case */
+#define MG_REG_ERROR (MG_REG_OFFSET + 2) /* read case */
+#define MG_REG_SECT_CNT (MG_REG_OFFSET + 4)
+#define MG_REG_SECT_NUM (MG_REG_OFFSET + 6)
+#define MG_REG_CYL_LOW (MG_REG_OFFSET + 8)
+#define MG_REG_CYL_HIGH (MG_REG_OFFSET + 0xA)
+#define MG_REG_DRV_HEAD (MG_REG_OFFSET + 0xC)
+#define MG_REG_COMMAND (MG_REG_OFFSET + 0xE) /* write case */
+#define MG_REG_STATUS (MG_REG_OFFSET + 0xE) /* read case */
+#define MG_REG_DRV_CTRL (MG_REG_OFFSET + 0x10)
+#define MG_REG_BURST_CTRL (MG_REG_OFFSET + 0x12)
+
+/* "Drive Select/Head Register" bit values */
+#define MG_REG_HEAD_MUST_BE_ON 0xA0 /* These 2 bits are always on */
+#define MG_REG_HEAD_DRIVE_MASTER (0x00 | MG_REG_HEAD_MUST_BE_ON)
+#define MG_REG_HEAD_DRIVE_SLAVE (0x10 | MG_REG_HEAD_MUST_BE_ON)
+#define MG_REG_HEAD_LBA_MODE (0x40 | MG_REG_HEAD_MUST_BE_ON)
+
+
+/* "Device Control Register" bit values */
+#define MG_REG_CTRL_INTR_ENABLE 0x0
+#define MG_REG_CTRL_INTR_DISABLE (0x1 << 1)
+#define MG_REG_CTRL_RESET (0x1 << 2)
+#define MG_REG_CTRL_INTR_POLA_ACTIVE_HIGH 0x0
+#define MG_REG_CTRL_INTR_POLA_ACTIVE_LOW (0x1 << 4)
+#define MG_REG_CTRL_DPD_POLA_ACTIVE_LOW 0x0
+#define MG_REG_CTRL_DPD_POLA_ACTIVE_HIGH (0x1 << 5)
+#define MG_REG_CTRL_DPD_DISABLE 0x0
+#define MG_REG_CTRL_DPD_ENABLE (0x1 << 6)
+
+/* Status register bit */
+ /* error bit in status register */
+#define MG_REG_STATUS_BIT_ERROR 0x01
+ /* corrected error in status register */
+#define MG_REG_STATUS_BIT_CORRECTED_ERROR 0x04
+ /* data request bit in status register */
+#define MG_REG_STATUS_BIT_DATA_REQ 0x08
+ /* DSC - Drive Seek Complete */
+#define MG_REG_STATUS_BIT_SEEK_DONE 0x10
+ /* DWF - Drive Write Fault */
+#define MG_REG_STATUS_BIT_WRITE_FAULT 0x20
+#define MG_REG_STATUS_BIT_READY 0x40
+#define MG_REG_STATUS_BIT_BUSY 0x80
+
+/* handy status */
+#define MG_STAT_READY (MG_REG_STATUS_BIT_READY | MG_REG_STATUS_BIT_SEEK_DONE)
+#define MG_READY_OK(s) (((s) & (MG_STAT_READY | \
+ (MG_REG_STATUS_BIT_BUSY | \
+ MG_REG_STATUS_BIT_WRITE_FAULT | \
+ MG_REG_STATUS_BIT_ERROR))) == MG_STAT_READY)
+
+/* Error register */
+#define MG_REG_ERR_AMNF 0x01
+#define MG_REG_ERR_ABRT 0x04
+#define MG_REG_ERR_IDNF 0x10
+#define MG_REG_ERR_UNC 0x40
+#define MG_REG_ERR_BBK 0x80
+
+/* error code for others */
+#define MG_ERR_NONE 0
+#define MG_ERR_TIMEOUT 0x100
+#define MG_ERR_INIT_STAT 0x101
+#define MG_ERR_TRANSLATION 0x102
+#define MG_ERR_CTRL_RST 0x103
+#define MG_ERR_NO_DRV_DATA 0x104
+
+#define MG_MAX_ERRORS 16 /* Max read/write errors/sector */
+#define MG_RESET_FREQ 4 /* Reset controller every 4th retry */
+
+/* command */
+#define MG_CMD_RD 0x20
+#define MG_CMD_WR 0x30
+#define MG_CMD_SLEEP 0x99
+#define MG_CMD_WAKEUP 0xC3
+#define MG_CMD_ID 0xEC
+#define MG_CMD_WR_CONF 0x3C
+#define MG_CMD_RD_CONF 0x40
+
+union mg_uniwb{
+ u16 w;
+ u8 b[2];
+};
+
+/* main structure for mflash driver */
+struct mg_host {
+ struct mg_drv_data *drv_data;
+ /* for future use */
+};
+
+/*
+ * Debugging macro and defines
+ */
+#undef DO_MG_DEBUG
+#ifdef DO_MG_DEBUG
+# define MG_DBG(fmt, args...) printf("%s:%d "fmt"\n", __func__, __LINE__,##args)
+#else /* CONFIG_MG_DEBUG */
+# define MG_DBG(fmt, args...) do { } while(0)
+#endif /* CONFIG_MG_DEBUG */
+
+#endif
diff --git a/u-boot/drivers/block/mvsata_ide.c b/u-boot/drivers/block/mvsata_ide.c
new file mode 100644
index 0000000..3d6993a
--- /dev/null
+++ b/u-boot/drivers/block/mvsata_ide.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2010 Albert ARIBAUD <albert.aribaud@free.fr>
+ *
+ * Written-by: Albert ARIBAUD <albert.aribaud@free.fr>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#if defined(CONFIG_ORION5X)
+#include <asm/arch/orion5x.h>
+#elif defined(CONFIG_KIRKWOOD)
+#include <asm/arch/kirkwood.h>
+#endif
+
+/* SATA port registers */
+struct mvsata_port_registers {
+ u32 reserved1[192];
+ /* offset 0x300 : ATA Interface registers */
+ u32 sstatus;
+ u32 serror;
+ u32 scontrol;
+ u32 ltmode;
+ u32 phymode3;
+ u32 phymode4;
+ u32 reserved2[5];
+ u32 phymode1;
+ u32 phymode2;
+ u32 bist_cr;
+ u32 bist_dw1;
+ u32 bist_dw2;
+ u32 serrorintrmask;
+};
+
+/*
+ * Sanity checks:
+ * - to compile at all, we need CONFIG_SYS_ATA_BASE_ADDR.
+ * - for ide_preinit to make sense, we need at least one of
+ * CONFIG_SYS_ATA_IDE0_OFFSET or CONFIG_SYS_ATA_IDE0_OFFSET;
+ * - for inde_preinit to be called, we need CONFIG_IDE_PREINIT.
+ * Fail with an explanation message if these conditions are not met.
+ * This is particularly important for CONFIG_IDE_PREINIT, because
+ * its lack would not cause a build error.
+ */
+
+#if !defined(CONFIG_SYS_ATA_BASE_ADDR)
+#error CONFIG_SYS_ATA_BASE_ADDR must be defined
+#elif !defined(CONFIG_SYS_ATA_IDE0_OFFSET) \
+ && !defined(CONFIG_SYS_ATA_IDE1_OFFSET)
+#error CONFIG_SYS_ATA_IDE0_OFFSET or CONFIG_SYS_ATA_IDE1_OFFSET \
+ must be defined
+#elif !defined(CONFIG_IDE_PREINIT)
+#error CONFIG_IDE_PREINIT must be defined
+#endif
+
+/*
+ * Masks and values for SControl DETection and Interface Power Management,
+ * and for SStatus DETection.
+ */
+
+#define MVSATA_SCONTROL_DET_MASK 0x0000000F
+#define MVSATA_SCONTROL_DET_NONE 0x00000000
+#define MVSATA_SCONTROL_DET_INIT 0x00000001
+#define MVSATA_SCONTROL_IPM_MASK 0x00000F00
+#define MVSATA_SCONTROL_IPM_NO_LP_ALLOWED 0x00000300
+#define MVSATA_SCONTROL_MASK \
+ (MVSATA_SCONTROL_DET_MASK|MVSATA_SCONTROL_IPM_MASK)
+#define MVSATA_PORT_INIT \
+ (MVSATA_SCONTROL_DET_INIT|MVSATA_SCONTROL_IPM_NO_LP_ALLOWED)
+#define MVSATA_PORT_USE \
+ (MVSATA_SCONTROL_DET_NONE|MVSATA_SCONTROL_IPM_NO_LP_ALLOWED)
+#define MVSATA_SSTATUS_DET_MASK 0x0000000F
+#define MVSATA_SSTATUS_DET_DEVCOMM 0x00000003
+
+/*
+ * Status codes to return to client callers. Currently, callers ignore
+ * exact value and only care for zero or nonzero, so no need to make this
+ * public, it is only #define'd for clarity.
+ * If/when standard negative codes are implemented in U-boot, then these
+ * #defines should be moved to, or replaced by ones from, the common list
+ * of status codes.
+ */
+
+#define MVSATA_STATUS_OK 0
+#define MVSATA_STATUS_TIMEOUT -1
+
+/*
+ * Initialize one MVSATAHC port: set SControl's IPM to "always active"
+ * and DET to "reset", then wait for SStatus's DET to become "device and
+ * comm ok" (or time out after 50 us if no device), then set SControl's
+ * DET back to "no action".
+ */
+
+static int mvsata_ide_initialize_port(struct mvsata_port_registers *port)
+{
+ u32 control;
+ u32 status;
+ u32 timeleft = 10000; /* wait at most 10 ms for SATA reset to complete */
+
+ /* Set control IPM to 3 (no low power) and DET to 1 (initialize) */
+ control = readl(&port->scontrol);
+ control = (control & ~MVSATA_SCONTROL_MASK) | MVSATA_PORT_INIT;
+ writel(control, &port->scontrol);
+ /* Toggle control DET back to 0 (normal operation) */
+ control = (control & ~MVSATA_SCONTROL_MASK) | MVSATA_PORT_USE;
+ writel(control, &port->scontrol);
+ /* wait for status DET to become 3 (device and communication OK) */
+ while (--timeleft) {
+ status = readl(&port->sstatus) & MVSATA_SSTATUS_DET_MASK;
+ if (status == MVSATA_SSTATUS_DET_DEVCOMM)
+ break;
+ udelay(1);
+ }
+ /* return success or time-out error depending on time left */
+ if (!timeleft)
+ return MVSATA_STATUS_TIMEOUT;
+ return MVSATA_STATUS_OK;
+}
+
+/*
+ * ide_preinit() will be called by ide_init in cmd_ide.c and will
+ * reset the MVSTATHC ports needed by the board.
+ */
+
+int ide_preinit(void)
+{
+ int status;
+ /* Enable ATA port 0 (could be SATA port 0 or 1) if declared */
+#if defined(CONFIG_SYS_ATA_IDE0_OFFSET)
+ status = mvsata_ide_initialize_port(
+ (struct mvsata_port_registers *)
+ (CONFIG_SYS_ATA_BASE_ADDR + CONFIG_SYS_ATA_IDE0_OFFSET));
+ if (status)
+ return status;
+#endif
+ /* Enable ATA port 1 (could be SATA port 0 or 1) if declared */
+#if defined(CONFIG_SYS_ATA_IDE1_OFFSET)
+ status = mvsata_ide_initialize_port(
+ (struct mvsata_port_registers *)
+ (CONFIG_SYS_ATA_BASE_ADDR + CONFIG_SYS_ATA_IDE1_OFFSET));
+ if (status)
+ return status;
+#endif
+ /* return success if all ports initializations succeeded */
+ return MVSATA_STATUS_OK;
+}
diff --git a/u-boot/drivers/block/mxc_ata.c b/u-boot/drivers/block/mxc_ata.c
new file mode 100644
index 0000000..f22f4f4
--- /dev/null
+++ b/u-boot/drivers/block/mxc_ata.c
@@ -0,0 +1,146 @@
+/*
+ * Freescale iMX51 ATA driver
+ *
+ * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on code by:
+ * Mahesh Mahadevan <mahesh.mahadevan@freescale.com>
+ *
+ * Based on code from original FSL ATA driver, which is
+ * part of eCos, the Embedded Configurable Operating System.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+ *
+ * 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 <config.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <ide.h>
+
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/clock.h>
+
+/* MXC ATA register offsets */
+struct mxc_ata_config_regs {
+ u8 time_off; /* 0x00 */
+ u8 time_on;
+ u8 time_1;
+ u8 time_2w;
+ u8 time_2r;
+ u8 time_ax;
+ u8 time_pio_rdx;
+ u8 time_4;
+ u8 time_9;
+ u8 time_m;
+ u8 time_jn;
+ u8 time_d;
+ u8 time_k;
+ u8 time_ack;
+ u8 time_env;
+ u8 time_udma_rdx;
+ u8 time_zah; /* 0x10 */
+ u8 time_mlix;
+ u8 time_dvh;
+ u8 time_dzfs;
+ u8 time_dvs;
+ u8 time_cvh;
+ u8 time_ss;
+ u8 time_cyc;
+ u32 fifo_data_32; /* 0x18 */
+ u32 fifo_data_16;
+ u32 fifo_fill;
+ u32 ata_control;
+ u32 interrupt_pending;
+ u32 interrupt_enable;
+ u32 interrupt_clear;
+ u32 fifo_alarm;
+};
+
+struct mxc_data_hdd_regs {
+ u32 drive_data; /* 0xa0 */
+ u32 drive_features;
+ u32 drive_sector_count;
+ u32 drive_sector_num;
+ u32 drive_cyl_low;
+ u32 drive_cyl_high;
+ u32 drive_dev_head;
+ u32 command;
+ u32 status;
+ u32 alt_status;
+};
+
+/* PIO timing table */
+#define NR_PIO_SPECS 5
+static uint16_t pio_t1[NR_PIO_SPECS] = { 70, 50, 30, 30, 25 };
+static uint16_t pio_t2_8[NR_PIO_SPECS] = { 290, 290, 290, 80, 70 };
+static uint16_t pio_t4[NR_PIO_SPECS] = { 30, 20, 15, 10, 10 };
+static uint16_t pio_t9[NR_PIO_SPECS] = { 20, 15, 10, 10, 10 };
+static uint16_t pio_tA[NR_PIO_SPECS] = { 50, 50, 50, 50, 50 };
+
+#define REG2OFF(reg) ((((uint32_t)reg) & 0x3) * 8)
+static void set_ata_bus_timing(unsigned char mode)
+{
+ uint32_t val;
+ uint32_t T = 1000000000 / mxc_get_clock(MXC_IPG_CLK);
+
+ struct mxc_ata_config_regs *ata_regs;
+ ata_regs = (struct mxc_ata_config_regs *)CONFIG_SYS_ATA_BASE_ADDR;
+
+ if (mode >= NR_PIO_SPECS)
+ return;
+
+ /* Write TIME_OFF/ON/1/2W */
+ val = (3 << REG2OFF(&ata_regs->time_off)) |
+ (3 << REG2OFF(&ata_regs->time_on)) |
+ (((pio_t1[mode] + T) / T) << REG2OFF(&ata_regs->time_1)) |
+ (((pio_t2_8[mode] + T) / T) << REG2OFF(&ata_regs->time_2w));
+ writel(val, &ata_regs->time_off);
+
+ /* Write TIME_2R/AX/RDX/4 */
+ val = (((pio_t2_8[mode] + T) / T) << REG2OFF(&ata_regs->time_2r)) |
+ (((pio_tA[mode] + T) / T + 2) << REG2OFF(&ata_regs->time_ax)) |
+ (1 << REG2OFF(&ata_regs->time_pio_rdx)) |
+ (((pio_t4[mode] + T) / T) << REG2OFF(&ata_regs->time_4));
+ writel(val, &ata_regs->time_2r);
+
+ /* Write TIME_9 ; the rest of timing registers is irrelevant for PIO */
+ val = (((pio_t9[mode] + T) / T) << REG2OFF(&ata_regs->time_9));
+ writel(val, &ata_regs->time_9);
+}
+
+int ide_preinit(void)
+{
+ struct mxc_ata_config_regs *ata_regs;
+ ata_regs = (struct mxc_ata_config_regs *)CONFIG_SYS_ATA_BASE_ADDR;
+
+ /* 46.3.3.4 @ FSL iMX51 manual */
+ /* FIFO normal op., drive reset */
+ writel(0x80, &ata_regs->ata_control);
+ /* FIFO normal op., drive not reset */
+ writel(0xc0, &ata_regs->ata_control);
+
+ /* Configure the PIO timing */
+ set_ata_bus_timing(CONFIG_MXC_ATA_PIO_MODE);
+
+ /* 46.3.3.4 @ FSL iMX51 manual */
+ /* Drive not reset, IORDY handshake */
+ writel(0x41, &ata_regs->ata_control);
+
+ return 0;
+}
diff --git a/u-boot/drivers/block/pata_bfin.c b/u-boot/drivers/block/pata_bfin.c
new file mode 100644
index 0000000..847c032
--- /dev/null
+++ b/u-boot/drivers/block/pata_bfin.c
@@ -0,0 +1,1200 @@
+/*
+ * Driver for Blackfin on-chip ATAPI controller.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (c) 2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/portmux.h>
+#include <asm/mach-common/bits/pata.h>
+#include <ata.h>
+#include <libata.h>
+#include "pata_bfin.h"
+
+static struct ata_port port[CONFIG_SYS_SATA_MAX_DEVICE];
+
+/**
+ * PIO Mode - Frequency compatibility
+ */
+/* mode: 0 1 2 3 4 */
+static const u32 pio_fsclk[] =
+{ 33333333, 33333333, 33333333, 33333333, 33333333 };
+
+/**
+ * MDMA Mode - Frequency compatibility
+ */
+/* mode: 0 1 2 */
+static const u32 mdma_fsclk[] = { 33333333, 33333333, 33333333 };
+
+/**
+ * UDMA Mode - Frequency compatibility
+ *
+ * UDMA5 - 100 MB/s - SCLK = 133 MHz
+ * UDMA4 - 66 MB/s - SCLK >= 80 MHz
+ * UDMA3 - 44.4 MB/s - SCLK >= 50 MHz
+ * UDMA2 - 33 MB/s - SCLK >= 40 MHz
+ */
+/* mode: 0 1 2 3 4 5 */
+static const u32 udma_fsclk[] =
+{ 33333333, 33333333, 40000000, 50000000, 80000000, 133333333 };
+
+/**
+ * Register transfer timing table
+ */
+/* mode: 0 1 2 3 4 */
+/* Cycle Time */
+static const u32 reg_t0min[] = { 600, 383, 330, 180, 120 };
+/* DIOR/DIOW to end cycle */
+static const u32 reg_t2min[] = { 290, 290, 290, 70, 25 };
+/* DIOR/DIOW asserted pulse width */
+static const u32 reg_teocmin[] = { 290, 290, 290, 80, 70 };
+
+/**
+ * PIO timing table
+ */
+/* mode: 0 1 2 3 4 */
+/* Cycle Time */
+static const u32 pio_t0min[] = { 600, 383, 240, 180, 120 };
+/* Address valid to DIOR/DIORW */
+static const u32 pio_t1min[] = { 70, 50, 30, 30, 25 };
+/* DIOR/DIOW to end cycle */
+static const u32 pio_t2min[] = { 165, 125, 100, 80, 70 };
+/* DIOR/DIOW asserted pulse width */
+static const u32 pio_teocmin[] = { 165, 125, 100, 70, 25 };
+/* DIOW data hold */
+static const u32 pio_t4min[] = { 30, 20, 15, 10, 10 };
+
+/* ******************************************************************
+ * Multiword DMA timing table
+ * ******************************************************************
+ */
+/* mode: 0 1 2 */
+/* Cycle Time */
+static const u32 mdma_t0min[] = { 480, 150, 120 };
+/* DIOR/DIOW asserted pulse width */
+static const u32 mdma_tdmin[] = { 215, 80, 70 };
+/* DMACK to read data released */
+static const u32 mdma_thmin[] = { 20, 15, 10 };
+/* DIOR/DIOW to DMACK hold */
+static const u32 mdma_tjmin[] = { 20, 5, 5 };
+/* DIOR negated pulse width */
+static const u32 mdma_tkrmin[] = { 50, 50, 25 };
+/* DIOR negated pulse width */
+static const u32 mdma_tkwmin[] = { 215, 50, 25 };
+/* CS[1:0] valid to DIOR/DIOW */
+static const u32 mdma_tmmin[] = { 50, 30, 25 };
+/* DMACK to read data released */
+static const u32 mdma_tzmax[] = { 20, 25, 25 };
+
+/**
+ * Ultra DMA timing table
+ */
+/* mode: 0 1 2 3 4 5 */
+static const u32 udma_tcycmin[] = { 112, 73, 54, 39, 25, 17 };
+static const u32 udma_tdvsmin[] = { 70, 48, 31, 20, 7, 5 };
+static const u32 udma_tenvmax[] = { 70, 70, 70, 55, 55, 50 };
+static const u32 udma_trpmin[] = { 160, 125, 100, 100, 100, 85 };
+static const u32 udma_tmin[] = { 5, 5, 5, 5, 3, 3 };
+
+
+static const u32 udma_tmlimin = 20;
+static const u32 udma_tzahmin = 20;
+static const u32 udma_tenvmin = 20;
+static const u32 udma_tackmin = 20;
+static const u32 udma_tssmin = 50;
+
+static void msleep(int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ udelay(1000);
+}
+
+/**
+ *
+ * Function: num_clocks_min
+ *
+ * Description:
+ * calculate number of SCLK cycles to meet minimum timing
+ */
+static unsigned short num_clocks_min(unsigned long tmin,
+ unsigned long fsclk)
+{
+ unsigned long tmp ;
+ unsigned short result;
+
+ tmp = tmin * (fsclk/1000/1000) / 1000;
+ result = (unsigned short)tmp;
+ if ((tmp*1000*1000) < (tmin*(fsclk/1000)))
+ result++;
+
+ return result;
+}
+
+/**
+ * bfin_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @pio_mode: mode
+ *
+ * Set PIO mode for device.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void bfin_set_piomode(struct ata_port *ap, int pio_mode)
+{
+ int mode = pio_mode - XFER_PIO_0;
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned int fsclk = get_sclk();
+ unsigned short teoc_reg, t2_reg, teoc_pio;
+ unsigned short t4_reg, t2_pio, t1_reg;
+ unsigned short n0, n6, t6min = 5;
+
+ /* the most restrictive timing value is t6 and tc, the DIOW - data hold
+ * If one SCLK pulse is longer than this minimum value then register
+ * transfers cannot be supported at this frequency.
+ */
+ n6 = num_clocks_min(t6min, fsclk);
+ if (mode >= 0 && mode <= 4 && n6 >= 1) {
+ debug("set piomode: mode=%d, fsclk=%ud\n", mode, fsclk);
+ /* calculate the timing values for register transfers. */
+ while (mode > 0 && pio_fsclk[mode] > fsclk)
+ mode--;
+
+ /* DIOR/DIOW to end cycle time */
+ t2_reg = num_clocks_min(reg_t2min[mode], fsclk);
+ /* DIOR/DIOW asserted pulse width */
+ teoc_reg = num_clocks_min(reg_teocmin[mode], fsclk);
+ /* Cycle Time */
+ n0 = num_clocks_min(reg_t0min[mode], fsclk);
+
+ /* increase t2 until we meed the minimum cycle length */
+ if (t2_reg + teoc_reg < n0)
+ t2_reg = n0 - teoc_reg;
+
+ /* calculate the timing values for pio transfers. */
+
+ /* DIOR/DIOW to end cycle time */
+ t2_pio = num_clocks_min(pio_t2min[mode], fsclk);
+ /* DIOR/DIOW asserted pulse width */
+ teoc_pio = num_clocks_min(pio_teocmin[mode], fsclk);
+ /* Cycle Time */
+ n0 = num_clocks_min(pio_t0min[mode], fsclk);
+
+ /* increase t2 until we meed the minimum cycle length */
+ if (t2_pio + teoc_pio < n0)
+ t2_pio = n0 - teoc_pio;
+
+ /* Address valid to DIOR/DIORW */
+ t1_reg = num_clocks_min(pio_t1min[mode], fsclk);
+
+ /* DIOW data hold */
+ t4_reg = num_clocks_min(pio_t4min[mode], fsclk);
+
+ ATAPI_SET_REG_TIM_0(base, (teoc_reg<<8 | t2_reg));
+ ATAPI_SET_PIO_TIM_0(base, (t4_reg<<12 | t2_pio<<4 | t1_reg));
+ ATAPI_SET_PIO_TIM_1(base, teoc_pio);
+ if (mode > 2) {
+ ATAPI_SET_CONTROL(base,
+ ATAPI_GET_CONTROL(base) | IORDY_EN);
+ } else {
+ ATAPI_SET_CONTROL(base,
+ ATAPI_GET_CONTROL(base) & ~IORDY_EN);
+ }
+
+ /* Disable host ATAPI PIO interrupts */
+ ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base)
+ & ~(PIO_DONE_MASK | HOST_TERM_XFER_MASK));
+ SSYNC();
+ }
+}
+
+/**
+ *
+ * Function: wait_complete
+ *
+ * Description: Waits the interrupt from device
+ *
+ */
+static inline void wait_complete(void __iomem *base, unsigned short mask)
+{
+ unsigned short status;
+ unsigned int i = 0;
+
+ for (i = 0; i < PATA_BFIN_WAIT_TIMEOUT; i++) {
+ status = ATAPI_GET_INT_STATUS(base) & mask;
+ if (status)
+ break;
+ }
+
+ ATAPI_SET_INT_STATUS(base, mask);
+}
+
+/**
+ *
+ * Function: write_atapi_register
+ *
+ * Description: Writes to ATA Device Resgister
+ *
+ */
+
+static void write_atapi_register(void __iomem *base,
+ unsigned long ata_reg, unsigned short value)
+{
+ /* Program the ATA_DEV_TXBUF register with write data (to be
+ * written into the device).
+ */
+ ATAPI_SET_DEV_TXBUF(base, value);
+
+ /* Program the ATA_DEV_ADDR register with address of the
+ * device register (0x01 to 0x0F).
+ */
+ ATAPI_SET_DEV_ADDR(base, ata_reg);
+
+ /* Program the ATA_CTRL register with dir set to write (1)
+ */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR));
+
+ /* ensure PIO DMA is not set */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+ /* and start the transfer */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+ /* Wait for the interrupt to indicate the end of the transfer.
+ * (We need to wait on and clear rhe ATA_DEV_INT interrupt status)
+ */
+ wait_complete(base, PIO_DONE_INT);
+}
+
+/**
+ *
+ * Function: read_atapi_register
+ *
+ *Description: Reads from ATA Device Resgister
+ *
+ */
+
+static unsigned short read_atapi_register(void __iomem *base,
+ unsigned long ata_reg)
+{
+ /* Program the ATA_DEV_ADDR register with address of the
+ * device register (0x01 to 0x0F).
+ */
+ ATAPI_SET_DEV_ADDR(base, ata_reg);
+
+ /* Program the ATA_CTRL register with dir set to read (0) and
+ */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR));
+
+ /* ensure PIO DMA is not set */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+ /* and start the transfer */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+ /* Wait for the interrupt to indicate the end of the transfer.
+ * (PIO_DONE interrupt is set and it doesn't seem to matter
+ * that we don't clear it)
+ */
+ wait_complete(base, PIO_DONE_INT);
+
+ /* Read the ATA_DEV_RXBUF register with write data (to be
+ * written into the device).
+ */
+ return ATAPI_GET_DEV_RXBUF(base);
+}
+
+/**
+ *
+ * Function: write_atapi_register_data
+ *
+ * Description: Writes to ATA Device Resgister
+ *
+ */
+
+static void write_atapi_data(void __iomem *base,
+ int len, unsigned short *buf)
+{
+ int i;
+
+ /* Set transfer length to 1 */
+ ATAPI_SET_XFER_LEN(base, 1);
+
+ /* Program the ATA_DEV_ADDR register with address of the
+ * ATA_REG_DATA
+ */
+ ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA);
+
+ /* Program the ATA_CTRL register with dir set to write (1)
+ */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR));
+
+ /* ensure PIO DMA is not set */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+ for (i = 0; i < len; i++) {
+ /* Program the ATA_DEV_TXBUF register with write data (to be
+ * written into the device).
+ */
+ ATAPI_SET_DEV_TXBUF(base, buf[i]);
+
+ /* and start the transfer */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+ /* Wait for the interrupt to indicate the end of the transfer.
+ * (We need to wait on and clear rhe ATA_DEV_INT
+ * interrupt status)
+ */
+ wait_complete(base, PIO_DONE_INT);
+ }
+}
+
+/**
+ *
+ * Function: read_atapi_register_data
+ *
+ * Description: Reads from ATA Device Resgister
+ *
+ */
+
+static void read_atapi_data(void __iomem *base,
+ int len, unsigned short *buf)
+{
+ int i;
+
+ /* Set transfer length to 1 */
+ ATAPI_SET_XFER_LEN(base, 1);
+
+ /* Program the ATA_DEV_ADDR register with address of the
+ * ATA_REG_DATA
+ */
+ ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA);
+
+ /* Program the ATA_CTRL register with dir set to read (0) and
+ */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR));
+
+ /* ensure PIO DMA is not set */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+ for (i = 0; i < len; i++) {
+ /* and start the transfer */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+ /* Wait for the interrupt to indicate the end of the transfer.
+ * (PIO_DONE interrupt is set and it doesn't seem to matter
+ * that we don't clear it)
+ */
+ wait_complete(base, PIO_DONE_INT);
+
+ /* Read the ATA_DEV_RXBUF register with write data (to be
+ * written into the device).
+ */
+ buf[i] = ATAPI_GET_DEV_RXBUF(base);
+ }
+}
+
+/**
+ * bfin_check_status - Read device status reg & clear interrupt
+ * @ap: port where the device is
+ *
+ * Note: Original code is ata_check_status().
+ */
+
+static u8 bfin_check_status(struct ata_port *ap)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ return read_atapi_register(base, ATA_REG_STATUS);
+}
+
+/**
+ * bfin_check_altstatus - Read device alternate status reg
+ * @ap: port where the device is
+ */
+
+static u8 bfin_check_altstatus(struct ata_port *ap)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ return read_atapi_register(base, ATA_REG_ALTSTATUS);
+}
+
+/**
+ * bfin_ata_busy_wait - Wait for a port status register
+ * @ap: Port to wait for.
+ * @bits: bits that must be clear
+ * @max: number of 10uS waits to perform
+ *
+ * Waits up to max*10 microseconds for the selected bits in the port's
+ * status register to be cleared.
+ * Returns final value of status register.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static inline u8 bfin_ata_busy_wait(struct ata_port *ap, unsigned int bits,
+ unsigned int max, u8 usealtstatus)
+{
+ u8 status;
+
+ do {
+ udelay(10);
+ if (usealtstatus)
+ status = bfin_check_altstatus(ap);
+ else
+ status = bfin_check_status(ap);
+ max--;
+ } while (status != 0xff && (status & bits) && (max > 0));
+
+ return status;
+}
+
+/**
+ * bfin_ata_busy_sleep - sleep until BSY clears, or timeout
+ * @ap: port containing status register to be polled
+ * @tmout_pat: impatience timeout in msecs
+ * @tmout: overall timeout in msecs
+ *
+ * Sleep until ATA Status register bit BSY clears,
+ * or a timeout occurs.
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+static int bfin_ata_busy_sleep(struct ata_port *ap,
+ long tmout_pat, unsigned long tmout)
+{
+ u8 status;
+
+ status = bfin_ata_busy_wait(ap, ATA_BUSY, 300, 0);
+ while (status != 0xff && (status & ATA_BUSY) && tmout_pat > 0) {
+ msleep(50);
+ tmout_pat -= 50;
+ status = bfin_ata_busy_wait(ap, ATA_BUSY, 3, 0);
+ }
+
+ if (status != 0xff && (status & ATA_BUSY))
+ printf("port is slow to respond, please be patient "
+ "(Status 0x%x)\n", status);
+
+ while (status != 0xff && (status & ATA_BUSY) && tmout_pat > 0) {
+ msleep(50);
+ tmout_pat -= 50;
+ status = bfin_check_status(ap);
+ }
+
+ if (status == 0xff)
+ return -ENODEV;
+
+ if (status & ATA_BUSY) {
+ printf("port failed to respond "
+ "(%lu secs, Status 0x%x)\n",
+ DIV_ROUND_UP(tmout, 1000), status);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+/**
+ * bfin_dev_select - Select device 0/1 on ATA bus
+ * @ap: ATA channel to manipulate
+ * @device: ATA device (numbered from zero) to select
+ *
+ * Note: Original code is ata_sff_dev_select().
+ */
+
+static void bfin_dev_select(struct ata_port *ap, unsigned int device)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ u8 tmp;
+
+
+ if (device == 0)
+ tmp = ATA_DEVICE_OBS;
+ else
+ tmp = ATA_DEVICE_OBS | ATA_DEV1;
+
+ write_atapi_register(base, ATA_REG_DEVICE, tmp);
+ udelay(1);
+}
+
+/**
+ * bfin_devchk - PATA device presence detection
+ * @ap: ATA channel to examine
+ * @device: Device to examine (starting at zero)
+ *
+ * Note: Original code is ata_devchk().
+ */
+
+static unsigned int bfin_devchk(struct ata_port *ap,
+ unsigned int device)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ u8 nsect, lbal;
+
+ bfin_dev_select(ap, device);
+
+ write_atapi_register(base, ATA_REG_NSECT, 0x55);
+ write_atapi_register(base, ATA_REG_LBAL, 0xaa);
+
+ write_atapi_register(base, ATA_REG_NSECT, 0xaa);
+ write_atapi_register(base, ATA_REG_LBAL, 0x55);
+
+ write_atapi_register(base, ATA_REG_NSECT, 0x55);
+ write_atapi_register(base, ATA_REG_LBAL, 0xaa);
+
+ nsect = read_atapi_register(base, ATA_REG_NSECT);
+ lbal = read_atapi_register(base, ATA_REG_LBAL);
+
+ if ((nsect == 0x55) && (lbal == 0xaa))
+ return 1; /* we found a device */
+
+ return 0; /* nothing found */
+}
+
+/**
+ * bfin_bus_post_reset - PATA device post reset
+ *
+ * Note: Original code is ata_bus_post_reset().
+ */
+
+static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned int dev0 = devmask & (1 << 0);
+ unsigned int dev1 = devmask & (1 << 1);
+ long deadline;
+
+ /* if device 0 was found in ata_devchk, wait for its
+ * BSY bit to clear
+ */
+ if (dev0)
+ bfin_ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+ /* if device 1 was found in ata_devchk, wait for
+ * register access, then wait for BSY to clear
+ */
+ deadline = ATA_TMOUT_BOOT;
+ while (dev1) {
+ u8 nsect, lbal;
+
+ bfin_dev_select(ap, 1);
+ nsect = read_atapi_register(base, ATA_REG_NSECT);
+ lbal = read_atapi_register(base, ATA_REG_LBAL);
+ if ((nsect == 1) && (lbal == 1))
+ break;
+ if (deadline <= 0) {
+ dev1 = 0;
+ break;
+ }
+ msleep(50); /* give drive a breather */
+ deadline -= 50;
+ }
+ if (dev1)
+ bfin_ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+ /* is all this really necessary? */
+ bfin_dev_select(ap, 0);
+ if (dev1)
+ bfin_dev_select(ap, 1);
+ if (dev0)
+ bfin_dev_select(ap, 0);
+}
+
+/**
+ * bfin_bus_softreset - PATA device software reset
+ *
+ * Note: Original code is ata_bus_softreset().
+ */
+
+static unsigned int bfin_bus_softreset(struct ata_port *ap,
+ unsigned int devmask)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ /* software reset. causes dev0 to be selected */
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl_reg);
+ udelay(20);
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl_reg | ATA_SRST);
+ udelay(20);
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl_reg);
+
+ /* spec mandates ">= 2ms" before checking status.
+ * We wait 150ms, because that was the magic delay used for
+ * ATAPI devices in Hale Landis's ATADRVR, for the period of time
+ * between when the ATA command register is written, and then
+ * status is checked. Because waiting for "a while" before
+ * checking status is fine, post SRST, we perform this magic
+ * delay here as well.
+ *
+ * Old drivers/ide uses the 2mS rule and then waits for ready
+ */
+ msleep(150);
+
+ /* Before we perform post reset processing we want to see if
+ * the bus shows 0xFF because the odd clown forgets the D7
+ * pulldown resistor.
+ */
+ if (bfin_check_status(ap) == 0xFF)
+ return 0;
+
+ bfin_bus_post_reset(ap, devmask);
+
+ return 0;
+}
+
+/**
+ * bfin_softreset - reset host port via ATA SRST
+ * @ap: port to reset
+ *
+ * Note: Original code is ata_sff_softreset().
+ */
+
+static int bfin_softreset(struct ata_port *ap)
+{
+ unsigned int err_mask;
+
+ ap->dev_mask = 0;
+
+ /* determine if device 0/1 are present.
+ * only one device is supported on one port by now.
+ */
+ if (bfin_devchk(ap, 0))
+ ap->dev_mask |= (1 << 0);
+ else if (bfin_devchk(ap, 1))
+ ap->dev_mask |= (1 << 1);
+ else
+ return -ENODEV;
+
+ /* select device 0 again */
+ bfin_dev_select(ap, 0);
+
+ /* issue bus reset */
+ err_mask = bfin_bus_softreset(ap, ap->dev_mask);
+ if (err_mask) {
+ printf("SRST failed (err_mask=0x%x)\n",
+ err_mask);
+ ap->dev_mask = 0;
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * bfin_irq_clear - Clear ATAPI interrupt.
+ * @ap: Port associated with this ATA transaction.
+ *
+ * Note: Original code is ata_sff_irq_clear().
+ */
+
+static void bfin_irq_clear(struct ata_port *ap)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ ATAPI_SET_INT_STATUS(base, ATAPI_GET_INT_STATUS(base)|ATAPI_DEV_INT
+ | MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT
+ | MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT);
+}
+
+static u8 bfin_wait_for_irq(struct ata_port *ap, unsigned int max)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ do {
+ if (ATAPI_GET_INT_STATUS(base) & (ATAPI_DEV_INT
+ | MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT
+ | MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT)) {
+ break;
+ }
+ udelay(1000);
+ max--;
+ } while ((max > 0));
+
+ return max == 0;
+}
+
+/**
+ * bfin_ata_reset_port - initialize BFIN ATAPI port.
+ */
+
+static int bfin_ata_reset_port(struct ata_port *ap)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ int count;
+ unsigned short status;
+
+ /* Disable all ATAPI interrupts */
+ ATAPI_SET_INT_MASK(base, 0);
+ SSYNC();
+
+ /* Assert the RESET signal 25us*/
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | DEV_RST);
+ udelay(30);
+
+ /* Negate the RESET signal for 2ms*/
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) & ~DEV_RST);
+ msleep(2);
+
+ /* Wait on Busy flag to clear */
+ count = 10000000;
+ do {
+ status = read_atapi_register(base, ATA_REG_STATUS);
+ } while (--count && (status & ATA_BUSY));
+
+ /* Enable only ATAPI Device interrupt */
+ ATAPI_SET_INT_MASK(base, 1);
+ SSYNC();
+
+ return !count;
+}
+
+/**
+ *
+ * Function: bfin_config_atapi_gpio
+ *
+ * Description: Configures the ATAPI pins for use
+ *
+ */
+static int bfin_config_atapi_gpio(struct ata_port *ap)
+{
+ const unsigned short pins[] = {
+ P_ATAPI_RESET, P_ATAPI_DIOR, P_ATAPI_DIOW, P_ATAPI_CS0,
+ P_ATAPI_CS1, P_ATAPI_DMACK, P_ATAPI_DMARQ, P_ATAPI_INTRQ,
+ P_ATAPI_IORDY, P_ATAPI_D0A, P_ATAPI_D1A, P_ATAPI_D2A,
+ P_ATAPI_D3A, P_ATAPI_D4A, P_ATAPI_D5A, P_ATAPI_D6A,
+ P_ATAPI_D7A, P_ATAPI_D8A, P_ATAPI_D9A, P_ATAPI_D10A,
+ P_ATAPI_D11A, P_ATAPI_D12A, P_ATAPI_D13A, P_ATAPI_D14A,
+ P_ATAPI_D15A, P_ATAPI_A0A, P_ATAPI_A1A, P_ATAPI_A2A, 0,
+ };
+
+ peripheral_request_list(pins, "pata_bfin");
+
+ return 0;
+}
+
+/**
+ * bfin_atapi_probe - attach a bfin atapi interface
+ * @pdev: platform device
+ *
+ * Register a bfin atapi interface.
+ *
+ *
+ * Platform devices are expected to contain 2 resources per port:
+ *
+ * - I/O Base (IORESOURCE_IO)
+ * - IRQ (IORESOURCE_IRQ)
+ *
+ */
+static int bfin_ata_probe_port(struct ata_port *ap)
+{
+ if (bfin_config_atapi_gpio(ap)) {
+ printf("Requesting Peripherals faild\n");
+ return -EFAULT;
+ }
+
+ if (bfin_ata_reset_port(ap)) {
+ printf("Fail to reset ATAPI device\n");
+ return -EFAULT;
+ }
+
+ if (ap->ata_mode >= XFER_PIO_0 && ap->ata_mode <= XFER_PIO_4)
+ bfin_set_piomode(ap, ap->ata_mode);
+ else {
+ printf("Given ATA data transfer mode is not supported.\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+#define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2)
+
+static void bfin_ata_identify(struct ata_port *ap, int dev)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ u8 status = 0;
+ static u16 iobuf[ATA_SECTOR_WORDS];
+ u64 n_sectors = 0;
+ hd_driveid_t *iop = (hd_driveid_t *)iobuf;
+
+ memset(iobuf, 0, sizeof(iobuf));
+
+ if (!(ap->dev_mask & (1 << dev)))
+ return;
+
+ debug("port=%d dev=%d\n", ap->port_no, dev);
+
+ bfin_dev_select(ap, dev);
+
+ status = 0;
+ /* Device Identify Command */
+ write_atapi_register(base, ATA_REG_CMD, ATA_CMD_ID_ATA);
+ bfin_check_altstatus(ap);
+ udelay(10);
+
+ status = bfin_ata_busy_wait(ap, ATA_BUSY, 1000, 0);
+ if (status & ATA_ERR) {
+ printf("\ndevice not responding\n");
+ ap->dev_mask &= ~(1 << dev);
+ return;
+ }
+
+ read_atapi_data(base, ATA_SECTOR_WORDS, iobuf);
+
+ ata_swap_buf_le16(iobuf, ATA_SECTOR_WORDS);
+
+ /* we require LBA and DMA support (bits 8 & 9 of word 49) */
+ if (!ata_id_has_dma(iobuf) || !ata_id_has_lba(iobuf))
+ printf("ata%u: no dma/lba\n", ap->port_no);
+
+#ifdef DEBUG
+ ata_dump_id(iobuf);
+#endif
+
+ n_sectors = ata_id_n_sectors(iobuf);
+
+ if (n_sectors == 0) {
+ ap->dev_mask &= ~(1 << dev);
+ return;
+ }
+
+ ata_id_c_string(iobuf, (unsigned char *)sata_dev_desc[ap->port_no].revision,
+ ATA_ID_FW_REV, sizeof(sata_dev_desc[ap->port_no].revision));
+ ata_id_c_string(iobuf, (unsigned char *)sata_dev_desc[ap->port_no].vendor,
+ ATA_ID_PROD, sizeof(sata_dev_desc[ap->port_no].vendor));
+ ata_id_c_string(iobuf, (unsigned char *)sata_dev_desc[ap->port_no].product,
+ ATA_ID_SERNO, sizeof(sata_dev_desc[ap->port_no].product));
+
+ if ((iop->config & 0x0080) == 0x0080)
+ sata_dev_desc[ap->port_no].removable = 1;
+ else
+ sata_dev_desc[ap->port_no].removable = 0;
+
+ sata_dev_desc[ap->port_no].lba = (u32) n_sectors;
+ debug("lba=0x%x\n", sata_dev_desc[ap->port_no].lba);
+
+#ifdef CONFIG_LBA48
+ if (iop->command_set_2 & 0x0400)
+ sata_dev_desc[ap->port_no].lba48 = 1;
+ else
+ sata_dev_desc[ap->port_no].lba48 = 0;
+#endif
+
+ /* assuming HD */
+ sata_dev_desc[ap->port_no].type = DEV_TYPE_HARDDISK;
+ sata_dev_desc[ap->port_no].blksz = ATA_SECT_SIZE;
+ sata_dev_desc[ap->port_no].lun = 0; /* just to fill something in... */
+
+ printf("PATA device#%d %s is found on ata port#%d.\n",
+ ap->port_no%PATA_DEV_NUM_PER_PORT,
+ sata_dev_desc[ap->port_no].vendor,
+ ap->port_no/PATA_DEV_NUM_PER_PORT);
+}
+
+static void bfin_ata_set_Feature_cmd(struct ata_port *ap, int dev)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ u8 status = 0;
+
+ if (!(ap->dev_mask & (1 << dev)))
+ return;
+
+ bfin_dev_select(ap, dev);
+
+ write_atapi_register(base, ATA_REG_FEATURE, SETFEATURES_XFER);
+ write_atapi_register(base, ATA_REG_NSECT, ap->ata_mode);
+ write_atapi_register(base, ATA_REG_LBAL, 0);
+ write_atapi_register(base, ATA_REG_LBAM, 0);
+ write_atapi_register(base, ATA_REG_LBAH, 0);
+
+ write_atapi_register(base, ATA_REG_DEVICE, ATA_DEVICE_OBS);
+ write_atapi_register(base, ATA_REG_CMD, ATA_CMD_SET_FEATURES);
+
+ udelay(50);
+ msleep(150);
+
+ status = bfin_ata_busy_wait(ap, ATA_BUSY, 5000, 0);
+ if ((status & (ATA_BUSY | ATA_ERR))) {
+ printf("Error : status 0x%02x\n", status);
+ ap->dev_mask &= ~(1 << dev);
+ }
+}
+
+int scan_sata(int dev)
+{
+ /* dev is the index of each ata device in the system. one PATA port
+ * contains 2 devices. one element in scan_done array indicates one
+ * PATA port. device connected to one PATA port is selected by
+ * bfin_dev_select() before access.
+ */
+ struct ata_port *ap = &port[dev];
+ static int scan_done[(CONFIG_SYS_SATA_MAX_DEVICE+1)/PATA_DEV_NUM_PER_PORT];
+
+ if (scan_done[dev/PATA_DEV_NUM_PER_PORT])
+ return 0;
+
+ /* Check for attached device */
+ if (!bfin_ata_probe_port(ap)) {
+ if (bfin_softreset(ap)) {
+ /* soft reset failed, try a hard one */
+ bfin_ata_reset_port(ap);
+ if (bfin_softreset(ap))
+ scan_done[dev/PATA_DEV_NUM_PER_PORT] = 1;
+ } else {
+ scan_done[dev/PATA_DEV_NUM_PER_PORT] = 1;
+ }
+ }
+ if (scan_done[dev/PATA_DEV_NUM_PER_PORT]) {
+ /* Probe device and set xfer mode */
+ bfin_ata_identify(ap, dev%PATA_DEV_NUM_PER_PORT);
+ bfin_ata_set_Feature_cmd(ap, dev%PATA_DEV_NUM_PER_PORT);
+ init_part(&sata_dev_desc[dev]);
+ return 0;
+ }
+
+ printf("PATA device#%d is not present on ATA port#%d.\n",
+ ap->port_no%PATA_DEV_NUM_PER_PORT,
+ ap->port_no/PATA_DEV_NUM_PER_PORT);
+
+ return -1;
+}
+
+int init_sata(int dev)
+{
+ struct ata_port *ap = &port[dev];
+ static u8 init_done;
+ int res = 1;
+
+ if (init_done)
+ return res;
+
+ init_done = 1;
+
+ switch (dev/PATA_DEV_NUM_PER_PORT) {
+ case 0:
+ ap->ioaddr.ctl_addr = ATAPI_CONTROL;
+ ap->ata_mode = CONFIG_BFIN_ATA_MODE;
+ break;
+ default:
+ printf("Tried to scan unknown port %d.\n", dev);
+ return res;
+ }
+
+ if (ap->ata_mode < XFER_PIO_0 || ap->ata_mode > XFER_PIO_4) {
+ ap->ata_mode = XFER_PIO_4;
+ printf("DMA mode is not supported. Set to PIO mode 4.\n");
+ }
+
+ ap->port_no = dev;
+ ap->ctl_reg = 0x8; /*Default value of control reg */
+
+ res = 0;
+ return res;
+}
+
+/* Read up to 255 sectors
+ *
+ * Returns sectors read
+*/
+static u8 do_one_read(struct ata_port *ap, u64 blknr, u8 blkcnt, u16 *buffer,
+ uchar lba48)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ u8 sr = 0;
+ u8 status;
+ u16 err = 0;
+
+ if (!(bfin_check_status(ap) & ATA_DRDY)) {
+ printf("Device ata%d not ready\n", ap->port_no);
+ return 0;
+ }
+
+ /* Set up transfer */
+#ifdef CONFIG_LBA48
+ if (lba48) {
+ /* write high bits */
+ write_atapi_register(base, ATA_REG_NSECT, 0);
+ write_atapi_register(base, ATA_REG_LBAL, (blknr >> 24) & 0xFF);
+ write_atapi_register(base, ATA_REG_LBAM, (blknr >> 32) & 0xFF);
+ write_atapi_register(base, ATA_REG_LBAH, (blknr >> 40) & 0xFF);
+ }
+#endif
+ write_atapi_register(base, ATA_REG_NSECT, blkcnt);
+ write_atapi_register(base, ATA_REG_LBAL, (blknr >> 0) & 0xFF);
+ write_atapi_register(base, ATA_REG_LBAM, (blknr >> 8) & 0xFF);
+ write_atapi_register(base, ATA_REG_LBAH, (blknr >> 16) & 0xFF);
+
+#ifdef CONFIG_LBA48
+ if (lba48) {
+ write_atapi_register(base, ATA_REG_DEVICE, ATA_LBA);
+ write_atapi_register(base, ATA_REG_CMD, ATA_CMD_PIO_READ_EXT);
+ } else
+#endif
+ {
+ write_atapi_register(base, ATA_REG_DEVICE, ATA_LBA | ((blknr >> 24) & 0xF));
+ write_atapi_register(base, ATA_REG_CMD, ATA_CMD_PIO_READ);
+ }
+ status = bfin_ata_busy_wait(ap, ATA_BUSY, 500000, 1);
+
+ if (status & (ATA_BUSY | ATA_ERR)) {
+ printf("Device %d not responding status 0x%x.\n", ap->port_no, status);
+ err = read_atapi_register(base, ATA_REG_ERR);
+ printf("Error reg = 0x%x\n", err);
+ return sr;
+ }
+
+ while (blkcnt--) {
+ if (bfin_wait_for_irq(ap, 500)) {
+ printf("ata%u irq failed\n", ap->port_no);
+ return sr;
+ }
+
+ status = bfin_check_status(ap);
+ if (status & ATA_ERR) {
+ err = read_atapi_register(base, ATA_REG_ERR);
+ printf("ata%u error %d\n", ap->port_no, err);
+ return sr;
+ }
+ bfin_irq_clear(ap);
+
+ /* Read one sector */
+ read_atapi_data(base, ATA_SECTOR_WORDS, buffer);
+ buffer += ATA_SECTOR_WORDS;
+ sr++;
+ }
+
+ return sr;
+}
+
+ulong sata_read(int dev, ulong block, ulong blkcnt, void *buff)
+{
+ struct ata_port *ap = &port[dev];
+ ulong n = 0, sread;
+ u16 *buffer = (u16 *) buff;
+ u8 status = 0;
+ u64 blknr = (u64) block;
+ unsigned char lba48 = 0;
+
+#ifdef CONFIG_LBA48
+ if (blknr > 0xfffffff) {
+ if (!sata_dev_desc[dev].lba48) {
+ printf("Drive doesn't support 48-bit addressing\n");
+ return 0;
+ }
+ /* more than 28 bits used, use 48bit mode */
+ lba48 = 1;
+ }
+#endif
+ bfin_dev_select(ap, dev%PATA_DEV_NUM_PER_PORT);
+
+ while (blkcnt > 0) {
+
+ if (blkcnt > 255)
+ sread = 255;
+ else
+ sread = blkcnt;
+
+ status = do_one_read(ap, blknr, sread, buffer, lba48);
+ if (status != sread) {
+ printf("Read failed\n");
+ return n;
+ }
+
+ blkcnt -= sread;
+ blknr += sread;
+ n += sread;
+ buffer += sread * ATA_SECTOR_WORDS;
+ }
+ return n;
+}
+
+ulong sata_write(int dev, ulong block, ulong blkcnt, const void *buff)
+{
+ struct ata_port *ap = &port[dev];
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ ulong n = 0;
+ u16 *buffer = (u16 *) buff;
+ unsigned char status = 0;
+ u64 blknr = (u64) block;
+#ifdef CONFIG_LBA48
+ unsigned char lba48 = 0;
+
+ if (blknr > 0xfffffff) {
+ if (!sata_dev_desc[dev].lba48) {
+ printf("Drive doesn't support 48-bit addressing\n");
+ return 0;
+ }
+ /* more than 28 bits used, use 48bit mode */
+ lba48 = 1;
+ }
+#endif
+
+ bfin_dev_select(ap, dev%PATA_DEV_NUM_PER_PORT);
+
+ while (blkcnt-- > 0) {
+ status = bfin_ata_busy_wait(ap, ATA_BUSY, 50000, 0);
+ if (status & ATA_BUSY) {
+ printf("ata%u failed to respond\n", ap->port_no);
+ return n;
+ }
+#ifdef CONFIG_LBA48
+ if (lba48) {
+ /* write high bits */
+ write_atapi_register(base, ATA_REG_NSECT, 0);
+ write_atapi_register(base, ATA_REG_LBAL,
+ (blknr >> 24) & 0xFF);
+ write_atapi_register(base, ATA_REG_LBAM,
+ (blknr >> 32) & 0xFF);
+ write_atapi_register(base, ATA_REG_LBAH,
+ (blknr >> 40) & 0xFF);
+ }
+#endif
+ write_atapi_register(base, ATA_REG_NSECT, 1);
+ write_atapi_register(base, ATA_REG_LBAL, (blknr >> 0) & 0xFF);
+ write_atapi_register(base, ATA_REG_LBAM, (blknr >> 8) & 0xFF);
+ write_atapi_register(base, ATA_REG_LBAH, (blknr >> 16) & 0xFF);
+#ifdef CONFIG_LBA48
+ if (lba48) {
+ write_atapi_register(base, ATA_REG_DEVICE, ATA_LBA);
+ write_atapi_register(base, ATA_REG_CMD,
+ ATA_CMD_PIO_WRITE_EXT);
+ } else
+#endif
+ {
+ write_atapi_register(base, ATA_REG_DEVICE,
+ ATA_LBA | ((blknr >> 24) & 0xF));
+ write_atapi_register(base, ATA_REG_CMD,
+ ATA_CMD_PIO_WRITE);
+ }
+
+ /*may take up to 5 sec */
+ status = bfin_ata_busy_wait(ap, ATA_BUSY, 50000, 0);
+ if ((status & (ATA_DRQ | ATA_BUSY | ATA_ERR)) != ATA_DRQ) {
+ printf("Error no DRQ dev %d blk %ld: sts 0x%02x\n",
+ ap->port_no, (ulong) blknr, status);
+ return n;
+ }
+
+ write_atapi_data(base, ATA_SECTOR_WORDS, buffer);
+ bfin_check_altstatus(ap);
+ udelay(1);
+
+ ++n;
+ ++blknr;
+ buffer += ATA_SECTOR_WORDS;
+ }
+ return n;
+}
diff --git a/u-boot/drivers/block/pata_bfin.h b/u-boot/drivers/block/pata_bfin.h
new file mode 100644
index 0000000..2b3425b
--- /dev/null
+++ b/u-boot/drivers/block/pata_bfin.h
@@ -0,0 +1,173 @@
+/*
+ * Driver for Blackfin on-chip ATAPI controller.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (c) 2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef PATA_BFIN_H
+#define PATA_BFIN_H
+
+#include <asm/blackfin_local.h>
+
+struct ata_ioports {
+ unsigned long cmd_addr;
+ unsigned long data_addr;
+ unsigned long error_addr;
+ unsigned long feature_addr;
+ unsigned long nsect_addr;
+ unsigned long lbal_addr;
+ unsigned long lbam_addr;
+ unsigned long lbah_addr;
+ unsigned long device_addr;
+ unsigned long status_addr;
+ unsigned long command_addr;
+ unsigned long altstatus_addr;
+ unsigned long ctl_addr;
+ unsigned long bmdma_addr;
+ unsigned long scr_addr;
+};
+
+struct ata_port {
+ unsigned int port_no; /* primary=0, secondary=1 */
+ struct ata_ioports ioaddr; /* ATA cmd/ctl/dma reg blks */
+ unsigned long flag;
+ unsigned int ata_mode;
+ unsigned char ctl_reg;
+ unsigned char last_ctl;
+ unsigned char dev_mask;
+};
+
+extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE];
+
+#define DRV_NAME "pata-bfin"
+#define DRV_VERSION "0.9"
+#define __iomem
+
+#define ATA_REG_CTRL 0x0E
+#define ATA_REG_ALTSTATUS ATA_REG_CTRL
+#define ATA_TMOUT_BOOT 30000
+#define ATA_TMOUT_BOOT_QUICK 7000
+
+#define PATA_BFIN_WAIT_TIMEOUT 10000
+#define PATA_DEV_NUM_PER_PORT 2
+
+/* These are the offset of the controller's registers */
+#define ATAPI_OFFSET_CONTROL 0x00
+#define ATAPI_OFFSET_STATUS 0x04
+#define ATAPI_OFFSET_DEV_ADDR 0x08
+#define ATAPI_OFFSET_DEV_TXBUF 0x0c
+#define ATAPI_OFFSET_DEV_RXBUF 0x10
+#define ATAPI_OFFSET_INT_MASK 0x14
+#define ATAPI_OFFSET_INT_STATUS 0x18
+#define ATAPI_OFFSET_XFER_LEN 0x1c
+#define ATAPI_OFFSET_LINE_STATUS 0x20
+#define ATAPI_OFFSET_SM_STATE 0x24
+#define ATAPI_OFFSET_TERMINATE 0x28
+#define ATAPI_OFFSET_PIO_TFRCNT 0x2c
+#define ATAPI_OFFSET_DMA_TFRCNT 0x30
+#define ATAPI_OFFSET_UMAIN_TFRCNT 0x34
+#define ATAPI_OFFSET_UDMAOUT_TFRCNT 0x38
+#define ATAPI_OFFSET_REG_TIM_0 0x40
+#define ATAPI_OFFSET_PIO_TIM_0 0x44
+#define ATAPI_OFFSET_PIO_TIM_1 0x48
+#define ATAPI_OFFSET_MULTI_TIM_0 0x50
+#define ATAPI_OFFSET_MULTI_TIM_1 0x54
+#define ATAPI_OFFSET_MULTI_TIM_2 0x58
+#define ATAPI_OFFSET_ULTRA_TIM_0 0x60
+#define ATAPI_OFFSET_ULTRA_TIM_1 0x64
+#define ATAPI_OFFSET_ULTRA_TIM_2 0x68
+#define ATAPI_OFFSET_ULTRA_TIM_3 0x6c
+
+
+#define ATAPI_GET_CONTROL(base)\
+ bfin_read16(base + ATAPI_OFFSET_CONTROL)
+#define ATAPI_SET_CONTROL(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_CONTROL, val)
+#define ATAPI_GET_STATUS(base)\
+ bfin_read16(base + ATAPI_OFFSET_STATUS)
+#define ATAPI_GET_DEV_ADDR(base)\
+ bfin_read16(base + ATAPI_OFFSET_DEV_ADDR)
+#define ATAPI_SET_DEV_ADDR(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_DEV_ADDR, val)
+#define ATAPI_GET_DEV_TXBUF(base)\
+ bfin_read16(base + ATAPI_OFFSET_DEV_TXBUF)
+#define ATAPI_SET_DEV_TXBUF(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_DEV_TXBUF, val)
+#define ATAPI_GET_DEV_RXBUF(base)\
+ bfin_read16(base + ATAPI_OFFSET_DEV_RXBUF)
+#define ATAPI_SET_DEV_RXBUF(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_DEV_RXBUF, val)
+#define ATAPI_GET_INT_MASK(base)\
+ bfin_read16(base + ATAPI_OFFSET_INT_MASK)
+#define ATAPI_SET_INT_MASK(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_INT_MASK, val)
+#define ATAPI_GET_INT_STATUS(base)\
+ bfin_read16(base + ATAPI_OFFSET_INT_STATUS)
+#define ATAPI_SET_INT_STATUS(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_INT_STATUS, val)
+#define ATAPI_GET_XFER_LEN(base)\
+ bfin_read16(base + ATAPI_OFFSET_XFER_LEN)
+#define ATAPI_SET_XFER_LEN(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_XFER_LEN, val)
+#define ATAPI_GET_LINE_STATUS(base)\
+ bfin_read16(base + ATAPI_OFFSET_LINE_STATUS)
+#define ATAPI_GET_SM_STATE(base)\
+ bfin_read16(base + ATAPI_OFFSET_SM_STATE)
+#define ATAPI_GET_TERMINATE(base)\
+ bfin_read16(base + ATAPI_OFFSET_TERMINATE)
+#define ATAPI_SET_TERMINATE(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_TERMINATE, val)
+#define ATAPI_GET_PIO_TFRCNT(base)\
+ bfin_read16(base + ATAPI_OFFSET_PIO_TFRCNT)
+#define ATAPI_GET_DMA_TFRCNT(base)\
+ bfin_read16(base + ATAPI_OFFSET_DMA_TFRCNT)
+#define ATAPI_GET_UMAIN_TFRCNT(base)\
+ bfin_read16(base + ATAPI_OFFSET_UMAIN_TFRCNT)
+#define ATAPI_GET_UDMAOUT_TFRCNT(base)\
+ bfin_read16(base + ATAPI_OFFSET_UDMAOUT_TFRCNT)
+#define ATAPI_GET_REG_TIM_0(base)\
+ bfin_read16(base + ATAPI_OFFSET_REG_TIM_0)
+#define ATAPI_SET_REG_TIM_0(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_REG_TIM_0, val)
+#define ATAPI_GET_PIO_TIM_0(base)\
+ bfin_read16(base + ATAPI_OFFSET_PIO_TIM_0)
+#define ATAPI_SET_PIO_TIM_0(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_PIO_TIM_0, val)
+#define ATAPI_GET_PIO_TIM_1(base)\
+ bfin_read16(base + ATAPI_OFFSET_PIO_TIM_1)
+#define ATAPI_SET_PIO_TIM_1(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_PIO_TIM_1, val)
+#define ATAPI_GET_MULTI_TIM_0(base)\
+ bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_0)
+#define ATAPI_SET_MULTI_TIM_0(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_0, val)
+#define ATAPI_GET_MULTI_TIM_1(base)\
+ bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_1)
+#define ATAPI_SET_MULTI_TIM_1(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_1, val)
+#define ATAPI_GET_MULTI_TIM_2(base)\
+ bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_2)
+#define ATAPI_SET_MULTI_TIM_2(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_2, val)
+#define ATAPI_GET_ULTRA_TIM_0(base)\
+ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_0)
+#define ATAPI_SET_ULTRA_TIM_0(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_0, val)
+#define ATAPI_GET_ULTRA_TIM_1(base)\
+ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_1)
+#define ATAPI_SET_ULTRA_TIM_1(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_1, val)
+#define ATAPI_GET_ULTRA_TIM_2(base)\
+ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_2)
+#define ATAPI_SET_ULTRA_TIM_2(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_2, val)
+#define ATAPI_GET_ULTRA_TIM_3(base)\
+ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_3)
+#define ATAPI_SET_ULTRA_TIM_3(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_3, val)
+
+#endif
diff --git a/u-boot/drivers/block/sata_dwc.c b/u-boot/drivers/block/sata_dwc.c
new file mode 100644
index 0000000..b2b3804
--- /dev/null
+++ b/u-boot/drivers/block/sata_dwc.c
@@ -0,0 +1,2110 @@
+/*
+ * sata_dwc.c
+ *
+ * Synopsys DesignWare Cores (DWC) SATA host driver
+ *
+ * Author: Mark Miesfeld <mmiesfeld@amcc.com>
+ *
+ * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese <sr@denx.de>
+ * Copyright 2008 DENX Software Engineering
+ *
+ * Based on versions provided by AMCC and Synopsys which are:
+ * Copyright 2006 Applied Micro Circuits Corporation
+ * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED
+ *
+ * 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.
+ *
+ */
+/*
+ * SATA support based on the chip canyonlands.
+ *
+ * 04-17-2009
+ * The local version of this driver for the canyonlands board
+ * does not use interrupts but polls the chip instead.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <pci.h>
+#include <asm/processor.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <ata.h>
+#include <linux/ctype.h>
+
+#include "sata_dwc.h"
+
+#define DMA_NUM_CHANS 1
+#define DMA_NUM_CHAN_REGS 8
+
+#define AHB_DMA_BRST_DFLT 16
+
+struct dmareg {
+ u32 low;
+ u32 high;
+};
+
+struct dma_chan_regs {
+ struct dmareg sar;
+ struct dmareg dar;
+ struct dmareg llp;
+ struct dmareg ctl;
+ struct dmareg sstat;
+ struct dmareg dstat;
+ struct dmareg sstatar;
+ struct dmareg dstatar;
+ struct dmareg cfg;
+ struct dmareg sgr;
+ struct dmareg dsr;
+};
+
+struct dma_interrupt_regs {
+ struct dmareg tfr;
+ struct dmareg block;
+ struct dmareg srctran;
+ struct dmareg dsttran;
+ struct dmareg error;
+};
+
+struct ahb_dma_regs {
+ struct dma_chan_regs chan_regs[DMA_NUM_CHAN_REGS];
+ struct dma_interrupt_regs interrupt_raw;
+ struct dma_interrupt_regs interrupt_status;
+ struct dma_interrupt_regs interrupt_mask;
+ struct dma_interrupt_regs interrupt_clear;
+ struct dmareg statusInt;
+ struct dmareg rq_srcreg;
+ struct dmareg rq_dstreg;
+ struct dmareg rq_sgl_srcreg;
+ struct dmareg rq_sgl_dstreg;
+ struct dmareg rq_lst_srcreg;
+ struct dmareg rq_lst_dstreg;
+ struct dmareg dma_cfg;
+ struct dmareg dma_chan_en;
+ struct dmareg dma_id;
+ struct dmareg dma_test;
+ struct dmareg res1;
+ struct dmareg res2;
+ /* DMA Comp Params
+ * Param 6 = dma_param[0], Param 5 = dma_param[1],
+ * Param 4 = dma_param[2] ...
+ */
+ struct dmareg dma_params[6];
+};
+
+#define DMA_EN 0x00000001
+#define DMA_DI 0x00000000
+#define DMA_CHANNEL(ch) (0x00000001 << (ch))
+#define DMA_ENABLE_CHAN(ch) ((0x00000001 << (ch)) | \
+ ((0x000000001 << (ch)) << 8))
+#define DMA_DISABLE_CHAN(ch) (0x00000000 | \
+ ((0x000000001 << (ch)) << 8))
+
+#define SATA_DWC_MAX_PORTS 1
+#define SATA_DWC_SCR_OFFSET 0x24
+#define SATA_DWC_REG_OFFSET 0x64
+
+struct sata_dwc_regs {
+ u32 fptagr;
+ u32 fpbor;
+ u32 fptcr;
+ u32 dmacr;
+ u32 dbtsr;
+ u32 intpr;
+ u32 intmr;
+ u32 errmr;
+ u32 llcr;
+ u32 phycr;
+ u32 physr;
+ u32 rxbistpd;
+ u32 rxbistpd1;
+ u32 rxbistpd2;
+ u32 txbistpd;
+ u32 txbistpd1;
+ u32 txbistpd2;
+ u32 bistcr;
+ u32 bistfctr;
+ u32 bistsr;
+ u32 bistdecr;
+ u32 res[15];
+ u32 testr;
+ u32 versionr;
+ u32 idr;
+ u32 unimpl[192];
+ u32 dmadr[256];
+};
+
+#define SATA_DWC_TXFIFO_DEPTH 0x01FF
+#define SATA_DWC_RXFIFO_DEPTH 0x01FF
+
+#define SATA_DWC_DBTSR_MWR(size) ((size / 4) & SATA_DWC_TXFIFO_DEPTH)
+#define SATA_DWC_DBTSR_MRD(size) (((size / 4) & \
+ SATA_DWC_RXFIFO_DEPTH) << 16)
+#define SATA_DWC_INTPR_DMAT 0x00000001
+#define SATA_DWC_INTPR_NEWFP 0x00000002
+#define SATA_DWC_INTPR_PMABRT 0x00000004
+#define SATA_DWC_INTPR_ERR 0x00000008
+#define SATA_DWC_INTPR_NEWBIST 0x00000010
+#define SATA_DWC_INTPR_IPF 0x10000000
+#define SATA_DWC_INTMR_DMATM 0x00000001
+#define SATA_DWC_INTMR_NEWFPM 0x00000002
+#define SATA_DWC_INTMR_PMABRTM 0x00000004
+#define SATA_DWC_INTMR_ERRM 0x00000008
+#define SATA_DWC_INTMR_NEWBISTM 0x00000010
+
+#define SATA_DWC_DMACR_TMOD_TXCHEN 0x00000004
+#define SATA_DWC_DMACR_TXRXCH_CLEAR SATA_DWC_DMACR_TMOD_TXCHEN
+
+#define SATA_DWC_QCMD_MAX 32
+
+#define SATA_DWC_SERROR_ERR_BITS 0x0FFF0F03
+
+#define HSDEVP_FROM_AP(ap) (struct sata_dwc_device_port*) \
+ (ap)->private_data
+
+struct sata_dwc_device {
+ struct device *dev;
+ struct ata_probe_ent *pe;
+ struct ata_host *host;
+ u8 *reg_base;
+ struct sata_dwc_regs *sata_dwc_regs;
+ int irq_dma;
+};
+
+struct sata_dwc_device_port {
+ struct sata_dwc_device *hsdev;
+ int cmd_issued[SATA_DWC_QCMD_MAX];
+ u32 dma_chan[SATA_DWC_QCMD_MAX];
+ int dma_pending[SATA_DWC_QCMD_MAX];
+};
+
+enum {
+ SATA_DWC_CMD_ISSUED_NOT = 0,
+ SATA_DWC_CMD_ISSUED_PEND = 1,
+ SATA_DWC_CMD_ISSUED_EXEC = 2,
+ SATA_DWC_CMD_ISSUED_NODATA = 3,
+
+ SATA_DWC_DMA_PENDING_NONE = 0,
+ SATA_DWC_DMA_PENDING_TX = 1,
+ SATA_DWC_DMA_PENDING_RX = 2,
+};
+
+#define msleep(a) udelay(a * 1000)
+#define ssleep(a) msleep(a * 1000)
+
+static int ata_probe_timeout = (ATA_TMOUT_INTERNAL / 100);
+
+enum sata_dev_state {
+ SATA_INIT = 0,
+ SATA_READY = 1,
+ SATA_NODEVICE = 2,
+ SATA_ERROR = 3,
+};
+enum sata_dev_state dev_state = SATA_INIT;
+
+static struct ahb_dma_regs *sata_dma_regs = 0;
+static struct ata_host *phost;
+static struct ata_port ap;
+static struct ata_port *pap = &ap;
+static struct ata_device ata_device;
+static struct sata_dwc_device_port dwc_devp;
+
+static void *scr_addr_sstatus;
+static u32 temp_n_block = 0;
+
+static unsigned ata_exec_internal(struct ata_device *dev,
+ struct ata_taskfile *tf, const u8 *cdb,
+ int dma_dir, unsigned int buflen,
+ unsigned long timeout);
+static unsigned int ata_dev_set_feature(struct ata_device *dev,
+ u8 enable,u8 feature);
+static unsigned int ata_dev_init_params(struct ata_device *dev,
+ u16 heads, u16 sectors);
+static u8 ata_irq_on(struct ata_port *ap);
+static struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap,
+ unsigned int tag);
+static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
+ u8 status, int in_wq);
+static void ata_tf_to_host(struct ata_port *ap,
+ const struct ata_taskfile *tf);
+static void ata_exec_command(struct ata_port *ap,
+ const struct ata_taskfile *tf);
+static unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc);
+static u8 ata_check_altstatus(struct ata_port *ap);
+static u8 ata_check_status(struct ata_port *ap);
+static void ata_dev_select(struct ata_port *ap, unsigned int device,
+ unsigned int wait, unsigned int can_sleep);
+static void ata_qc_issue(struct ata_queued_cmd *qc);
+static void ata_tf_load(struct ata_port *ap,
+ const struct ata_taskfile *tf);
+static int ata_dev_read_sectors(unsigned char* pdata,
+ unsigned long datalen, u32 block, u32 n_block);
+static int ata_dev_write_sectors(unsigned char* pdata,
+ unsigned long datalen , u32 block, u32 n_block);
+static void ata_std_dev_select(struct ata_port *ap, unsigned int device);
+static void ata_qc_complete(struct ata_queued_cmd *qc);
+static void __ata_qc_complete(struct ata_queued_cmd *qc);
+static void fill_result_tf(struct ata_queued_cmd *qc);
+static void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
+static void ata_mmio_data_xfer(struct ata_device *dev,
+ unsigned char *buf,
+ unsigned int buflen,int do_write);
+static void ata_pio_task(struct ata_port *arg_ap);
+static void __ata_port_freeze(struct ata_port *ap);
+static int ata_port_freeze(struct ata_port *ap);
+static void ata_qc_free(struct ata_queued_cmd *qc);
+static void ata_pio_sectors(struct ata_queued_cmd *qc);
+static void ata_pio_sector(struct ata_queued_cmd *qc);
+static void ata_pio_queue_task(struct ata_port *ap,
+ void *data,unsigned long delay);
+static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq);
+static int sata_dwc_softreset(struct ata_port *ap);
+static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
+ unsigned int flags, u16 *id);
+static int check_sata_dev_state(void);
+
+extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE];
+
+static const struct ata_port_info sata_dwc_port_info[] = {
+ {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING |
+ ATA_FLAG_SRST | ATA_FLAG_NCQ,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ },
+};
+
+int init_sata(int dev)
+{
+ struct sata_dwc_device hsdev;
+ struct ata_host host;
+ struct ata_port_info pi = sata_dwc_port_info[0];
+ struct ata_link *link;
+ struct sata_dwc_device_port hsdevp = dwc_devp;
+ u8 *base = 0;
+ u8 *sata_dma_regs_addr = 0;
+ u8 status;
+ unsigned long base_addr = 0;
+ int chan = 0;
+ int rc;
+ int i;
+
+ phost = &host;
+
+ base = (u8*)SATA_BASE_ADDR;
+
+ hsdev.sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET);
+
+ host.n_ports = SATA_DWC_MAX_PORTS;
+
+ for (i = 0; i < SATA_DWC_MAX_PORTS; i++) {
+ ap.pflags |= ATA_PFLAG_INITIALIZING;
+ ap.flags = ATA_FLAG_DISABLED;
+ ap.print_id = -1;
+ ap.ctl = ATA_DEVCTL_OBS;
+ ap.host = &host;
+ ap.last_ctl = 0xFF;
+
+ link = &ap.link;
+ link->ap = &ap;
+ link->pmp = 0;
+ link->active_tag = ATA_TAG_POISON;
+ link->hw_sata_spd_limit = 0;
+
+ ap.port_no = i;
+ host.ports[i] = &ap;
+ }
+
+ ap.pio_mask = pi.pio_mask;
+ ap.mwdma_mask = pi.mwdma_mask;
+ ap.udma_mask = pi.udma_mask;
+ ap.flags |= pi.flags;
+ ap.link.flags |= pi.link_flags;
+
+ host.ports[0]->ioaddr.cmd_addr = base;
+ host.ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET;
+ scr_addr_sstatus = base + SATA_DWC_SCR_OFFSET;
+
+ base_addr = (unsigned long)base;
+
+ host.ports[0]->ioaddr.cmd_addr = (void *)base_addr + 0x00;
+ host.ports[0]->ioaddr.data_addr = (void *)base_addr + 0x00;
+
+ host.ports[0]->ioaddr.error_addr = (void *)base_addr + 0x04;
+ host.ports[0]->ioaddr.feature_addr = (void *)base_addr + 0x04;
+
+ host.ports[0]->ioaddr.nsect_addr = (void *)base_addr + 0x08;
+
+ host.ports[0]->ioaddr.lbal_addr = (void *)base_addr + 0x0c;
+ host.ports[0]->ioaddr.lbam_addr = (void *)base_addr + 0x10;
+ host.ports[0]->ioaddr.lbah_addr = (void *)base_addr + 0x14;
+
+ host.ports[0]->ioaddr.device_addr = (void *)base_addr + 0x18;
+ host.ports[0]->ioaddr.command_addr = (void *)base_addr + 0x1c;
+ host.ports[0]->ioaddr.status_addr = (void *)base_addr + 0x1c;
+
+ host.ports[0]->ioaddr.altstatus_addr = (void *)base_addr + 0x20;
+ host.ports[0]->ioaddr.ctl_addr = (void *)base_addr + 0x20;
+
+ sata_dma_regs_addr = (u8*)SATA_DMA_REG_ADDR;
+ sata_dma_regs = (void *__iomem)sata_dma_regs_addr;
+
+ status = ata_check_altstatus(&ap);
+
+ if (status == 0x7f) {
+ printf("Hard Disk not found.\n");
+ dev_state = SATA_NODEVICE;
+ rc = FALSE;
+ return rc;
+ }
+
+ printf("Waiting for device...");
+ i = 0;
+ while (1) {
+ udelay(10000);
+
+ status = ata_check_altstatus(&ap);
+
+ if ((status & ATA_BUSY) == 0) {
+ printf("\n");
+ break;
+ }
+
+ i++;
+ if (i > (ATA_RESET_TIME * 100)) {
+ printf("** TimeOUT **\n");
+
+ dev_state = SATA_NODEVICE;
+ rc = FALSE;
+ return rc;
+ }
+ if ((i >= 100) && ((i % 100) == 0))
+ printf(".");
+ }
+
+ rc = sata_dwc_softreset(&ap);
+
+ if (rc) {
+ printf("sata_dwc : error. soft reset failed\n");
+ return rc;
+ }
+
+ for (chan = 0; chan < DMA_NUM_CHANS; chan++) {
+ out_le32(&(sata_dma_regs->interrupt_mask.error.low),
+ DMA_DISABLE_CHAN(chan));
+
+ out_le32(&(sata_dma_regs->interrupt_mask.tfr.low),
+ DMA_DISABLE_CHAN(chan));
+ }
+
+ out_le32(&(sata_dma_regs->dma_cfg.low), DMA_DI);
+
+ out_le32(&hsdev.sata_dwc_regs->intmr,
+ SATA_DWC_INTMR_ERRM |
+ SATA_DWC_INTMR_PMABRTM);
+
+ /* Unmask the error bits that should trigger
+ * an error interrupt by setting the error mask register.
+ */
+ out_le32(&hsdev.sata_dwc_regs->errmr, SATA_DWC_SERROR_ERR_BITS);
+
+ hsdev.host = ap.host;
+ memset(&hsdevp, 0, sizeof(hsdevp));
+ hsdevp.hsdev = &hsdev;
+
+ for (i = 0; i < SATA_DWC_QCMD_MAX; i++)
+ hsdevp.cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT;
+
+ out_le32((void __iomem *)scr_addr_sstatus + 4,
+ in_le32((void __iomem *)scr_addr_sstatus + 4));
+
+ rc = 0;
+ return rc;
+}
+
+static u8 ata_check_altstatus(struct ata_port *ap)
+{
+ u8 val = 0;
+ val = readb(ap->ioaddr.altstatus_addr);
+ return val;
+}
+
+static int sata_dwc_softreset(struct ata_port *ap)
+{
+ u8 nsect,lbal = 0;
+ u8 tmp = 0;
+ u32 serror = 0;
+ u8 status = 0;
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ serror = in_le32((void *)ap->ioaddr.scr_addr + (SCR_ERROR * 4));
+
+ writeb(0x55, ioaddr->nsect_addr);
+ writeb(0xaa, ioaddr->lbal_addr);
+ writeb(0xaa, ioaddr->nsect_addr);
+ writeb(0x55, ioaddr->lbal_addr);
+ writeb(0x55, ioaddr->nsect_addr);
+ writeb(0xaa, ioaddr->lbal_addr);
+
+ nsect = readb(ioaddr->nsect_addr);
+ lbal = readb(ioaddr->lbal_addr);
+
+ if ((nsect == 0x55) && (lbal == 0xaa)) {
+ printf("Device found\n");
+ } else {
+ printf("No device found\n");
+ dev_state = SATA_NODEVICE;
+ return FALSE;
+ }
+
+ tmp = ATA_DEVICE_OBS;
+ writeb(tmp, ioaddr->device_addr);
+ writeb(ap->ctl, ioaddr->ctl_addr);
+
+ udelay(200);
+
+ writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
+
+ udelay(200);
+ writeb(ap->ctl, ioaddr->ctl_addr);
+
+ msleep(150);
+ status = ata_check_status(ap);
+
+ msleep(50);
+ ata_check_status(ap);
+
+ while (1) {
+ u8 status = ata_check_status(ap);
+
+ if (!(status & ATA_BUSY))
+ break;
+
+ printf("Hard Disk status is BUSY.\n");
+ msleep(50);
+ }
+
+ tmp = ATA_DEVICE_OBS;
+ writeb(tmp, ioaddr->device_addr);
+
+ nsect = readb(ioaddr->nsect_addr);
+ lbal = readb(ioaddr->lbal_addr);
+
+ return 0;
+}
+
+static u8 ata_check_status(struct ata_port *ap)
+{
+ u8 val = 0;
+ val = readb(ap->ioaddr.status_addr);
+ return val;
+}
+
+static int ata_id_has_hipm(const u16 *id)
+{
+ u16 val = id[76];
+
+ if (val == 0 || val == 0xffff)
+ return -1;
+
+ return val & (1 << 9);
+}
+
+static int ata_id_has_dipm(const u16 *id)
+{
+ u16 val = id[78];
+
+ if (val == 0 || val == 0xffff)
+ return -1;
+
+ return val & (1 << 3);
+}
+
+int scan_sata(int dev)
+{
+ int i;
+ int rc;
+ u8 status;
+ const u16 *id;
+ struct ata_device *ata_dev = &ata_device;
+ unsigned long pio_mask, mwdma_mask, udma_mask;
+ unsigned long xfer_mask;
+ char revbuf[7];
+ u16 iobuf[ATA_SECTOR_WORDS];
+
+ memset(iobuf, 0, sizeof(iobuf));
+
+ if (dev_state == SATA_NODEVICE)
+ return 1;
+
+ printf("Waiting for device...");
+ i = 0;
+ while (1) {
+ udelay(10000);
+
+ status = ata_check_altstatus(&ap);
+
+ if ((status & ATA_BUSY) == 0) {
+ printf("\n");
+ break;
+ }
+
+ i++;
+ if (i > (ATA_RESET_TIME * 100)) {
+ printf("** TimeOUT **\n");
+
+ dev_state = SATA_NODEVICE;
+ return 1;
+ }
+ if ((i >= 100) && ((i % 100) == 0))
+ printf(".");
+ }
+
+ udelay(1000);
+
+ rc = ata_dev_read_id(ata_dev, &ata_dev->class,
+ ATA_READID_POSTRESET,ata_dev->id);
+ if (rc) {
+ printf("sata_dwc : error. failed sata scan\n");
+ return 1;
+ }
+
+ /* SATA drives indicate we have a bridge. We don't know which
+ * end of the link the bridge is which is a problem
+ */
+ if (ata_id_is_sata(ata_dev->id))
+ ap.cbl = ATA_CBL_SATA;
+
+ id = ata_dev->id;
+
+ ata_dev->flags &= ~ATA_DFLAG_CFG_MASK;
+ ata_dev->max_sectors = 0;
+ ata_dev->cdb_len = 0;
+ ata_dev->n_sectors = 0;
+ ata_dev->cylinders = 0;
+ ata_dev->heads = 0;
+ ata_dev->sectors = 0;
+
+ if (id[ATA_ID_FIELD_VALID] & (1 << 1)) {
+ pio_mask = id[ATA_ID_PIO_MODES] & 0x03;
+ pio_mask <<= 3;
+ pio_mask |= 0x7;
+ } else {
+ /* If word 64 isn't valid then Word 51 high byte holds
+ * the PIO timing number for the maximum. Turn it into
+ * a mask.
+ */
+ u8 mode = (id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF;
+ if (mode < 5) {
+ pio_mask = (2 << mode) - 1;
+ } else {
+ pio_mask = 1;
+ }
+ }
+
+ mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07;
+
+ if (ata_id_is_cfa(id)) {
+ int pio = id[163] & 0x7;
+ int dma = (id[163] >> 3) & 7;
+
+ if (pio)
+ pio_mask |= (1 << 5);
+ if (pio > 1)
+ pio_mask |= (1 << 6);
+ if (dma)
+ mwdma_mask |= (1 << 3);
+ if (dma > 1)
+ mwdma_mask |= (1 << 4);
+ }
+
+ udma_mask = 0;
+ if (id[ATA_ID_FIELD_VALID] & (1 << 2))
+ udma_mask = id[ATA_ID_UDMA_MODES] & 0xff;
+
+ xfer_mask = ((pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO) |
+ ((mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA) |
+ ((udma_mask << ATA_SHIFT_UDMA) & ATA_MASK_UDMA);
+
+ if (ata_dev->class == ATA_DEV_ATA) {
+ if (ata_id_is_cfa(id)) {
+ if (id[162] & 1)
+ printf("supports DRM functions and may "
+ "not be fully accessable.\n");
+ sprintf(revbuf, "%s", "CFA");
+ } else {
+ if (ata_id_has_tpm(id))
+ printf("supports DRM functions and may "
+ "not be fully accessable.\n");
+ }
+
+ ata_dev->n_sectors = ata_id_n_sectors((u16*)id);
+
+ if (ata_dev->id[59] & 0x100)
+ ata_dev->multi_count = ata_dev->id[59] & 0xff;
+
+ if (ata_id_has_lba(id)) {
+ const char *lba_desc;
+ char ncq_desc[20];
+
+ lba_desc = "LBA";
+ ata_dev->flags |= ATA_DFLAG_LBA;
+ if (ata_id_has_lba48(id)) {
+ ata_dev->flags |= ATA_DFLAG_LBA48;
+ lba_desc = "LBA48";
+
+ if (ata_dev->n_sectors >= (1UL << 28) &&
+ ata_id_has_flush_ext(id))
+ ata_dev->flags |= ATA_DFLAG_FLUSH_EXT;
+ }
+ if (!ata_id_has_ncq(ata_dev->id))
+ ncq_desc[0] = '\0';
+
+ if (ata_dev->horkage & ATA_HORKAGE_NONCQ)
+ sprintf(ncq_desc, "%s", "NCQ (not used)");
+
+ if (ap.flags & ATA_FLAG_NCQ)
+ ata_dev->flags |= ATA_DFLAG_NCQ;
+ }
+ ata_dev->cdb_len = 16;
+ }
+ ata_dev->max_sectors = ATA_MAX_SECTORS;
+ if (ata_dev->flags & ATA_DFLAG_LBA48)
+ ata_dev->max_sectors = ATA_MAX_SECTORS_LBA48;
+
+ if (!(ata_dev->horkage & ATA_HORKAGE_IPM)) {
+ if (ata_id_has_hipm(ata_dev->id))
+ ata_dev->flags |= ATA_DFLAG_HIPM;
+ if (ata_id_has_dipm(ata_dev->id))
+ ata_dev->flags |= ATA_DFLAG_DIPM;
+ }
+
+ if ((ap.cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ata_dev->id))) {
+ ata_dev->udma_mask &= ATA_UDMA5;
+ ata_dev->max_sectors = ATA_MAX_SECTORS;
+ }
+
+ if (ata_dev->horkage & ATA_HORKAGE_DIAGNOSTIC) {
+ printf("Drive reports diagnostics failure."
+ "This may indicate a drive\n");
+ printf("fault or invalid emulation."
+ "Contact drive vendor for information.\n");
+ }
+
+ rc = check_sata_dev_state();
+
+ ata_id_c_string(ata_dev->id,
+ (unsigned char *)sata_dev_desc[dev].revision,
+ ATA_ID_FW_REV, sizeof(sata_dev_desc[dev].revision));
+ ata_id_c_string(ata_dev->id,
+ (unsigned char *)sata_dev_desc[dev].vendor,
+ ATA_ID_PROD, sizeof(sata_dev_desc[dev].vendor));
+ ata_id_c_string(ata_dev->id,
+ (unsigned char *)sata_dev_desc[dev].product,
+ ATA_ID_SERNO, sizeof(sata_dev_desc[dev].product));
+
+ sata_dev_desc[dev].lba = (u32) ata_dev->n_sectors;
+
+#ifdef CONFIG_LBA48
+ if (ata_dev->id[83] & (1 << 10)) {
+ sata_dev_desc[dev].lba48 = 1;
+ } else {
+ sata_dev_desc[dev].lba48 = 0;
+ }
+#endif
+
+ return 0;
+}
+
+static u8 ata_busy_wait(struct ata_port *ap,
+ unsigned int bits,unsigned int max)
+{
+ u8 status;
+
+ do {
+ udelay(10);
+ status = ata_check_status(ap);
+ max--;
+ } while (status != 0xff && (status & bits) && (max > 0));
+
+ return status;
+}
+
+static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
+ unsigned int flags, u16 *id)
+{
+ struct ata_port *ap = pap;
+ unsigned int class = *p_class;
+ struct ata_taskfile tf;
+ unsigned int err_mask = 0;
+ const char *reason;
+ int may_fallback = 1, tried_spinup = 0;
+ u8 status;
+ int rc;
+
+ status = ata_busy_wait(ap, ATA_BUSY, 30000);
+ if (status & ATA_BUSY) {
+ printf("BSY = 0 check. timeout.\n");
+ rc = FALSE;
+ return rc;
+ }
+
+ ata_dev_select(ap, dev->devno, 1, 1);
+
+retry:
+ memset(&tf, 0, sizeof(tf));
+ ap->print_id = 1;
+ ap->flags &= ~ATA_FLAG_DISABLED;
+ tf.ctl = ap->ctl;
+ tf.device = ATA_DEVICE_OBS;
+ tf.command = ATA_CMD_ID_ATA;
+ tf.protocol = ATA_PROT_PIO;
+
+ /* Some devices choke if TF registers contain garbage. Make
+ * sure those are properly initialized.
+ */
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+
+ /* Device presence detection is unreliable on some
+ * controllers. Always poll IDENTIFY if available.
+ */
+ tf.flags |= ATA_TFLAG_POLLING;
+
+ temp_n_block = 1;
+
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
+ sizeof(id[0]) * ATA_ID_WORDS, 0);
+
+ if (err_mask) {
+ if (err_mask & AC_ERR_NODEV_HINT) {
+ printf("NODEV after polling detection\n");
+ return -ENOENT;
+ }
+
+ if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) {
+ /* Device or controller might have reported
+ * the wrong device class. Give a shot at the
+ * other IDENTIFY if the current one is
+ * aborted by the device.
+ */
+ if (may_fallback) {
+ may_fallback = 0;
+
+ if (class == ATA_DEV_ATA) {
+ class = ATA_DEV_ATAPI;
+ } else {
+ class = ATA_DEV_ATA;
+ }
+ goto retry;
+ }
+ /* Control reaches here iff the device aborted
+ * both flavors of IDENTIFYs which happens
+ * sometimes with phantom devices.
+ */
+ printf("both IDENTIFYs aborted, assuming NODEV\n");
+ return -ENOENT;
+ }
+ rc = -EIO;
+ reason = "I/O error";
+ goto err_out;
+ }
+
+ /* Falling back doesn't make sense if ID data was read
+ * successfully at least once.
+ */
+ may_fallback = 0;
+
+ unsigned int id_cnt;
+
+ for (id_cnt = 0; id_cnt < ATA_ID_WORDS; id_cnt++)
+ id[id_cnt] = le16_to_cpu(id[id_cnt]);
+
+
+ rc = -EINVAL;
+ reason = "device reports invalid type";
+
+ if (class == ATA_DEV_ATA) {
+ if (!ata_id_is_ata(id) && !ata_id_is_cfa(id))
+ goto err_out;
+ } else {
+ if (ata_id_is_ata(id))
+ goto err_out;
+ }
+ if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) {
+ tried_spinup = 1;
+ /*
+ * Drive powered-up in standby mode, and requires a specific
+ * SET_FEATURES spin-up subcommand before it will accept
+ * anything other than the original IDENTIFY command.
+ */
+ err_mask = ata_dev_set_feature(dev, SETFEATURES_SPINUP, 0);
+ if (err_mask && id[2] != 0x738c) {
+ rc = -EIO;
+ reason = "SPINUP failed";
+ goto err_out;
+ }
+ /*
+ * If the drive initially returned incomplete IDENTIFY info,
+ * we now must reissue the IDENTIFY command.
+ */
+ if (id[2] == 0x37c8)
+ goto retry;
+ }
+
+ if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) {
+ /*
+ * The exact sequence expected by certain pre-ATA4 drives is:
+ * SRST RESET
+ * IDENTIFY (optional in early ATA)
+ * INITIALIZE DEVICE PARAMETERS (later IDE and ATA)
+ * anything else..
+ * Some drives were very specific about that exact sequence.
+ *
+ * Note that ATA4 says lba is mandatory so the second check
+ * shoud never trigger.
+ */
+ if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) {
+ err_mask = ata_dev_init_params(dev, id[3], id[6]);
+ if (err_mask) {
+ rc = -EIO;
+ reason = "INIT_DEV_PARAMS failed";
+ goto err_out;
+ }
+
+ /* current CHS translation info (id[53-58]) might be
+ * changed. reread the identify device info.
+ */
+ flags &= ~ATA_READID_POSTRESET;
+ goto retry;
+ }
+ }
+
+ *p_class = class;
+ return 0;
+
+err_out:
+ return rc;
+}
+
+static u8 ata_wait_idle(struct ata_port *ap)
+{
+ u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+ return status;
+}
+
+static void ata_dev_select(struct ata_port *ap, unsigned int device,
+ unsigned int wait, unsigned int can_sleep)
+{
+ if (wait)
+ ata_wait_idle(ap);
+
+ ata_std_dev_select(ap, device);
+
+ if (wait)
+ ata_wait_idle(ap);
+}
+
+static void ata_std_dev_select(struct ata_port *ap, unsigned int device)
+{
+ u8 tmp;
+
+ if (device == 0) {
+ tmp = ATA_DEVICE_OBS;
+ } else {
+ tmp = ATA_DEVICE_OBS | ATA_DEV1;
+ }
+
+ writeb(tmp, ap->ioaddr.device_addr);
+
+ readb(ap->ioaddr.altstatus_addr);
+
+ udelay(1);
+}
+
+static int waiting_for_reg_state(volatile u8 *offset,
+ int timeout_msec,
+ u32 sign)
+{
+ int i;
+ u32 status;
+
+ for (i = 0; i < timeout_msec; i++) {
+ status = readl(offset);
+ if ((status & sign) != 0)
+ break;
+ msleep(1);
+ }
+
+ return (i < timeout_msec) ? 0 : -1;
+}
+
+static void ata_qc_reinit(struct ata_queued_cmd *qc)
+{
+ qc->dma_dir = DMA_NONE;
+ qc->flags = 0;
+ qc->nbytes = qc->extrabytes = qc->curbytes = 0;
+ qc->n_elem = 0;
+ qc->err_mask = 0;
+ qc->sect_size = ATA_SECT_SIZE;
+ qc->nbytes = ATA_SECT_SIZE * temp_n_block;
+
+ memset(&qc->tf, 0, sizeof(qc->tf));
+ qc->tf.ctl = 0;
+ qc->tf.device = ATA_DEVICE_OBS;
+
+ qc->result_tf.command = ATA_DRDY;
+ qc->result_tf.feature = 0;
+}
+
+struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap,
+ unsigned int tag)
+{
+ if (tag < ATA_MAX_QUEUE)
+ return &ap->qcmd[tag];
+ return NULL;
+}
+
+static void __ata_port_freeze(struct ata_port *ap)
+{
+ printf("set port freeze.\n");
+ ap->pflags |= ATA_PFLAG_FROZEN;
+}
+
+static int ata_port_freeze(struct ata_port *ap)
+{
+ __ata_port_freeze(ap);
+ return 0;
+}
+
+unsigned ata_exec_internal(struct ata_device *dev,
+ struct ata_taskfile *tf, const u8 *cdb,
+ int dma_dir, unsigned int buflen,
+ unsigned long timeout)
+{
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = pap;
+ struct ata_queued_cmd *qc;
+ unsigned int tag, preempted_tag;
+ u32 preempted_sactive, preempted_qc_active;
+ int preempted_nr_active_links;
+ unsigned int err_mask;
+ int rc = 0;
+ u8 status;
+
+ status = ata_busy_wait(ap, ATA_BUSY, 300000);
+ if (status & ATA_BUSY) {
+ printf("BSY = 0 check. timeout.\n");
+ rc = FALSE;
+ return rc;
+ }
+
+ if (ap->pflags & ATA_PFLAG_FROZEN)
+ return AC_ERR_SYSTEM;
+
+ tag = ATA_TAG_INTERNAL;
+
+ if (test_and_set_bit(tag, &ap->qc_allocated)) {
+ rc = FALSE;
+ return rc;
+ }
+
+ qc = __ata_qc_from_tag(ap, tag);
+ qc->tag = tag;
+ qc->ap = ap;
+ qc->dev = dev;
+
+ ata_qc_reinit(qc);
+
+ preempted_tag = link->active_tag;
+ preempted_sactive = link->sactive;
+ preempted_qc_active = ap->qc_active;
+ preempted_nr_active_links = ap->nr_active_links;
+ link->active_tag = ATA_TAG_POISON;
+ link->sactive = 0;
+ ap->qc_active = 0;
+ ap->nr_active_links = 0;
+
+ qc->tf = *tf;
+ if (cdb)
+ memcpy(qc->cdb, cdb, ATAPI_CDB_LEN);
+ qc->flags |= ATA_QCFLAG_RESULT_TF;
+ qc->dma_dir = dma_dir;
+ qc->private_data = 0;
+
+ ata_qc_issue(qc);
+
+ if (!timeout)
+ timeout = ata_probe_timeout * 1000 / HZ;
+
+ status = ata_busy_wait(ap, ATA_BUSY, 30000);
+ if (status & ATA_BUSY) {
+ printf("BSY = 0 check. timeout.\n");
+ printf("altstatus = 0x%x.\n", status);
+ qc->err_mask |= AC_ERR_OTHER;
+ return qc->err_mask;
+ }
+
+ if (waiting_for_reg_state(ap->ioaddr.altstatus_addr, 1000, 0x8)) {
+ u8 status = 0;
+ u8 errorStatus = 0;
+
+ status = readb(ap->ioaddr.altstatus_addr);
+ if ((status & 0x01) != 0) {
+ errorStatus = readb(ap->ioaddr.feature_addr);
+ if (errorStatus == 0x04 &&
+ qc->tf.command == ATA_CMD_PIO_READ_EXT){
+ printf("Hard Disk doesn't support LBA48\n");
+ dev_state = SATA_ERROR;
+ qc->err_mask |= AC_ERR_OTHER;
+ return qc->err_mask;
+ }
+ }
+ qc->err_mask |= AC_ERR_OTHER;
+ return qc->err_mask;
+ }
+
+ status = ata_busy_wait(ap, ATA_BUSY, 10);
+ if (status & ATA_BUSY) {
+ printf("BSY = 0 check. timeout.\n");
+ qc->err_mask |= AC_ERR_OTHER;
+ return qc->err_mask;
+ }
+
+ ata_pio_task(ap);
+
+ if (!rc) {
+ if (qc->flags & ATA_QCFLAG_ACTIVE) {
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ ata_port_freeze(ap);
+ }
+ }
+
+ if (qc->flags & ATA_QCFLAG_FAILED) {
+ if (qc->result_tf.command & (ATA_ERR | ATA_DF))
+ qc->err_mask |= AC_ERR_DEV;
+
+ if (!qc->err_mask)
+ qc->err_mask |= AC_ERR_OTHER;
+
+ if (qc->err_mask & ~AC_ERR_OTHER)
+ qc->err_mask &= ~AC_ERR_OTHER;
+ }
+
+ *tf = qc->result_tf;
+ err_mask = qc->err_mask;
+ ata_qc_free(qc);
+ link->active_tag = preempted_tag;
+ link->sactive = preempted_sactive;
+ ap->qc_active = preempted_qc_active;
+ ap->nr_active_links = preempted_nr_active_links;
+
+ if (ap->flags & ATA_FLAG_DISABLED) {
+ err_mask |= AC_ERR_SYSTEM;
+ ap->flags &= ~ATA_FLAG_DISABLED;
+ }
+
+ return err_mask;
+}
+
+static void ata_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_link *link = qc->dev->link;
+ u8 prot = qc->tf.protocol;
+
+ if (ata_is_ncq(prot)) {
+ if (!link->sactive)
+ ap->nr_active_links++;
+ link->sactive |= 1 << qc->tag;
+ } else {
+ ap->nr_active_links++;
+ link->active_tag = qc->tag;
+ }
+
+ qc->flags |= ATA_QCFLAG_ACTIVE;
+ ap->qc_active |= 1 << qc->tag;
+
+ if (qc->dev->flags & ATA_DFLAG_SLEEPING) {
+ msleep(1);
+ return;
+ }
+
+ qc->err_mask |= ata_qc_issue_prot(qc);
+ if (qc->err_mask)
+ goto err;
+
+ return;
+err:
+ ata_qc_complete(qc);
+}
+
+static unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ if (ap->flags & ATA_FLAG_PIO_POLLING) {
+ switch (qc->tf.protocol) {
+ case ATA_PROT_PIO:
+ case ATA_PROT_NODATA:
+ case ATAPI_PROT_PIO:
+ case ATAPI_PROT_NODATA:
+ qc->tf.flags |= ATA_TFLAG_POLLING;
+ break;
+ default:
+ break;
+ }
+ }
+
+ ata_dev_select(ap, qc->dev->devno, 1, 0);
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_PIO:
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ qc->tf.ctl |= ATA_NIEN;
+
+ ata_tf_to_host(ap, &qc->tf);
+
+ ap->hsm_task_state = HSM_ST;
+
+ if (qc->tf.flags & ATA_TFLAG_POLLING)
+ ata_pio_queue_task(ap, qc, 0);
+
+ break;
+
+ default:
+ return AC_ERR_SYSTEM;
+ }
+
+ return 0;
+}
+
+static void ata_tf_to_host(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ ata_tf_load(ap, tf);
+ ata_exec_command(ap, tf);
+}
+
+static void ata_tf_load(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+ if (tf->ctl != ap->last_ctl) {
+ if (ioaddr->ctl_addr)
+ writeb(tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+ writeb(tf->hob_feature, ioaddr->feature_addr);
+ writeb(tf->hob_nsect, ioaddr->nsect_addr);
+ writeb(tf->hob_lbal, ioaddr->lbal_addr);
+ writeb(tf->hob_lbam, ioaddr->lbam_addr);
+ writeb(tf->hob_lbah, ioaddr->lbah_addr);
+ }
+
+ if (is_addr) {
+ writeb(tf->feature, ioaddr->feature_addr);
+ writeb(tf->nsect, ioaddr->nsect_addr);
+ writeb(tf->lbal, ioaddr->lbal_addr);
+ writeb(tf->lbam, ioaddr->lbam_addr);
+ writeb(tf->lbah, ioaddr->lbah_addr);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE)
+ writeb(tf->device, ioaddr->device_addr);
+
+ ata_wait_idle(ap);
+}
+
+static void ata_exec_command(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ writeb(tf->command, ap->ioaddr.command_addr);
+
+ readb(ap->ioaddr.altstatus_addr);
+
+ udelay(1);
+}
+
+static void ata_pio_queue_task(struct ata_port *ap,
+ void *data,unsigned long delay)
+{
+ ap->port_task_data = data;
+}
+
+static unsigned int ac_err_mask(u8 status)
+{
+ if (status & (ATA_BUSY | ATA_DRQ))
+ return AC_ERR_HSM;
+ if (status & (ATA_ERR | ATA_DF))
+ return AC_ERR_DEV;
+ return 0;
+}
+
+static unsigned int __ac_err_mask(u8 status)
+{
+ unsigned int mask = ac_err_mask(status);
+ if (mask == 0)
+ return AC_ERR_OTHER;
+ return mask;
+}
+
+static void ata_pio_task(struct ata_port *arg_ap)
+{
+ struct ata_port *ap = arg_ap;
+ struct ata_queued_cmd *qc = ap->port_task_data;
+ u8 status;
+ int poll_next;
+
+fsm_start:
+ /*
+ * This is purely heuristic. This is a fast path.
+ * Sometimes when we enter, BSY will be cleared in
+ * a chk-status or two. If not, the drive is probably seeking
+ * or something. Snooze for a couple msecs, then
+ * chk-status again. If still busy, queue delayed work.
+ */
+ status = ata_busy_wait(ap, ATA_BUSY, 5);
+ if (status & ATA_BUSY) {
+ msleep(2);
+ status = ata_busy_wait(ap, ATA_BUSY, 10);
+ if (status & ATA_BUSY) {
+ ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE);
+ return;
+ }
+ }
+
+ poll_next = ata_hsm_move(ap, qc, status, 1);
+
+ /* another command or interrupt handler
+ * may be running at this point.
+ */
+ if (poll_next)
+ goto fsm_start;
+}
+
+static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
+ u8 status, int in_wq)
+{
+ int poll_next;
+
+fsm_start:
+ switch (ap->hsm_task_state) {
+ case HSM_ST_FIRST:
+ poll_next = (qc->tf.flags & ATA_TFLAG_POLLING);
+
+ if ((status & ATA_DRQ) == 0) {
+ if (status & (ATA_ERR | ATA_DF)) {
+ qc->err_mask |= AC_ERR_DEV;
+ } else {
+ qc->err_mask |= AC_ERR_HSM;
+ }
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
+
+ /* Device should not ask for data transfer (DRQ=1)
+ * when it finds something wrong.
+ * We ignore DRQ here and stop the HSM by
+ * changing hsm_task_state to HSM_ST_ERR and
+ * let the EH abort the command or reset the device.
+ */
+ if (status & (ATA_ERR | ATA_DF)) {
+ if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) {
+ printf("DRQ=1 with device error, "
+ "dev_stat 0x%X\n", status);
+ qc->err_mask |= AC_ERR_HSM;
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
+ }
+
+ if (qc->tf.protocol == ATA_PROT_PIO) {
+ /* PIO data out protocol.
+ * send first data block.
+ */
+ /* ata_pio_sectors() might change the state
+ * to HSM_ST_LAST. so, the state is changed here
+ * before ata_pio_sectors().
+ */
+ ap->hsm_task_state = HSM_ST;
+ ata_pio_sectors(qc);
+ } else {
+ printf("protocol is not ATA_PROT_PIO \n");
+ }
+ break;
+
+ case HSM_ST:
+ if ((status & ATA_DRQ) == 0) {
+ if (status & (ATA_ERR | ATA_DF)) {
+ qc->err_mask |= AC_ERR_DEV;
+ } else {
+ /* HSM violation. Let EH handle this.
+ * Phantom devices also trigger this
+ * condition. Mark hint.
+ */
+ qc->err_mask |= AC_ERR_HSM | AC_ERR_NODEV_HINT;
+ }
+
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
+ /* For PIO reads, some devices may ask for
+ * data transfer (DRQ=1) alone with ERR=1.
+ * We respect DRQ here and transfer one
+ * block of junk data before changing the
+ * hsm_task_state to HSM_ST_ERR.
+ *
+ * For PIO writes, ERR=1 DRQ=1 doesn't make
+ * sense since the data block has been
+ * transferred to the device.
+ */
+ if (status & (ATA_ERR | ATA_DF)) {
+ qc->err_mask |= AC_ERR_DEV;
+
+ if (!(qc->tf.flags & ATA_TFLAG_WRITE)) {
+ ata_pio_sectors(qc);
+ status = ata_wait_idle(ap);
+ }
+
+ if (status & (ATA_BUSY | ATA_DRQ))
+ qc->err_mask |= AC_ERR_HSM;
+
+ /* ata_pio_sectors() might change the
+ * state to HSM_ST_LAST. so, the state
+ * is changed after ata_pio_sectors().
+ */
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
+
+ ata_pio_sectors(qc);
+ if (ap->hsm_task_state == HSM_ST_LAST &&
+ (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
+ status = ata_wait_idle(ap);
+ goto fsm_start;
+ }
+
+ poll_next = 1;
+ break;
+
+ case HSM_ST_LAST:
+ if (!ata_ok(status)) {
+ qc->err_mask |= __ac_err_mask(status);
+ ap->hsm_task_state = HSM_ST_ERR;
+ goto fsm_start;
+ }
+
+ ap->hsm_task_state = HSM_ST_IDLE;
+
+ ata_hsm_qc_complete(qc, in_wq);
+
+ poll_next = 0;
+ break;
+
+ case HSM_ST_ERR:
+ /* make sure qc->err_mask is available to
+ * know what's wrong and recover
+ */
+ ap->hsm_task_state = HSM_ST_IDLE;
+
+ ata_hsm_qc_complete(qc, in_wq);
+
+ poll_next = 0;
+ break;
+ default:
+ poll_next = 0;
+ }
+
+ return poll_next;
+}
+
+static void ata_pio_sectors(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap;
+ ap = pap;
+ qc->pdata = ap->pdata;
+
+ ata_pio_sector(qc);
+
+ readb(qc->ap->ioaddr.altstatus_addr);
+ udelay(1);
+}
+
+static void ata_pio_sector(struct ata_queued_cmd *qc)
+{
+ int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
+ struct ata_port *ap = qc->ap;
+ unsigned int offset;
+ unsigned char *buf;
+ char temp_data_buf[512];
+
+ if (qc->curbytes == qc->nbytes - qc->sect_size)
+ ap->hsm_task_state = HSM_ST_LAST;
+
+ offset = qc->curbytes;
+
+ switch (qc->tf.command) {
+ case ATA_CMD_ID_ATA:
+ buf = (unsigned char *)&ata_device.id[0];
+ break;
+ case ATA_CMD_PIO_READ_EXT:
+ case ATA_CMD_PIO_READ:
+ case ATA_CMD_PIO_WRITE_EXT:
+ case ATA_CMD_PIO_WRITE:
+ buf = qc->pdata + offset;
+ break;
+ default:
+ buf = (unsigned char *)&temp_data_buf[0];
+ }
+
+ ata_mmio_data_xfer(qc->dev, buf, qc->sect_size, do_write);
+
+ qc->curbytes += qc->sect_size;
+
+}
+
+static void ata_mmio_data_xfer(struct ata_device *dev, unsigned char *buf,
+ unsigned int buflen, int do_write)
+{
+ struct ata_port *ap = pap;
+ void __iomem *data_addr = ap->ioaddr.data_addr;
+ unsigned int words = buflen >> 1;
+ u16 *buf16 = (u16 *)buf;
+ unsigned int i = 0;
+
+ udelay(100);
+ if (do_write) {
+ for (i = 0; i < words; i++)
+ writew(le16_to_cpu(buf16[i]), data_addr);
+ } else {
+ for (i = 0; i < words; i++)
+ buf16[i] = cpu_to_le16(readw(data_addr));
+ }
+
+ if (buflen & 0x01) {
+ __le16 align_buf[1] = { 0 };
+ unsigned char *trailing_buf = buf + buflen - 1;
+
+ if (do_write) {
+ memcpy(align_buf, trailing_buf, 1);
+ writew(le16_to_cpu(align_buf[0]), data_addr);
+ } else {
+ align_buf[0] = cpu_to_le16(readw(data_addr));
+ memcpy(trailing_buf, align_buf, 1);
+ }
+ }
+}
+
+static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
+{
+ struct ata_port *ap = qc->ap;
+
+ if (in_wq) {
+ /* EH might have kicked in while host lock is
+ * released.
+ */
+ qc = &ap->qcmd[qc->tag];
+ if (qc) {
+ if (!(qc->err_mask & AC_ERR_HSM)) {
+ ata_irq_on(ap);
+ ata_qc_complete(qc);
+ } else {
+ ata_port_freeze(ap);
+ }
+ }
+ } else {
+ if (!(qc->err_mask & AC_ERR_HSM)) {
+ ata_qc_complete(qc);
+ } else {
+ ata_port_freeze(ap);
+ }
+ }
+}
+
+static u8 ata_irq_on(struct ata_port *ap)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ u8 tmp;
+
+ ap->ctl &= ~ATA_NIEN;
+ ap->last_ctl = ap->ctl;
+
+ if (ioaddr->ctl_addr)
+ writeb(ap->ctl, ioaddr->ctl_addr);
+
+ tmp = ata_wait_idle(ap);
+
+ return tmp;
+}
+
+static unsigned int ata_tag_internal(unsigned int tag)
+{
+ return tag == ATA_MAX_QUEUE - 1;
+}
+
+static void ata_qc_complete(struct ata_queued_cmd *qc)
+{
+ struct ata_device *dev = qc->dev;
+ if (qc->err_mask)
+ qc->flags |= ATA_QCFLAG_FAILED;
+
+ if (qc->flags & ATA_QCFLAG_FAILED) {
+ if (!ata_tag_internal(qc->tag)) {
+ fill_result_tf(qc);
+ return;
+ }
+ }
+ if (qc->flags & ATA_QCFLAG_RESULT_TF)
+ fill_result_tf(qc);
+
+ /* Some commands need post-processing after successful
+ * completion.
+ */
+ switch (qc->tf.command) {
+ case ATA_CMD_SET_FEATURES:
+ if (qc->tf.feature != SETFEATURES_WC_ON &&
+ qc->tf.feature != SETFEATURES_WC_OFF)
+ break;
+ case ATA_CMD_INIT_DEV_PARAMS:
+ case ATA_CMD_SET_MULTI:
+ break;
+
+ case ATA_CMD_SLEEP:
+ dev->flags |= ATA_DFLAG_SLEEPING;
+ break;
+ }
+
+ __ata_qc_complete(qc);
+}
+
+static void fill_result_tf(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ qc->result_tf.flags = qc->tf.flags;
+ ata_tf_read(ap, &qc->result_tf);
+}
+
+static void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ tf->command = ata_check_status(ap);
+ tf->feature = readb(ioaddr->error_addr);
+ tf->nsect = readb(ioaddr->nsect_addr);
+ tf->lbal = readb(ioaddr->lbal_addr);
+ tf->lbam = readb(ioaddr->lbam_addr);
+ tf->lbah = readb(ioaddr->lbah_addr);
+ tf->device = readb(ioaddr->device_addr);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ if (ioaddr->ctl_addr) {
+ writeb(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
+
+ tf->hob_feature = readb(ioaddr->error_addr);
+ tf->hob_nsect = readb(ioaddr->nsect_addr);
+ tf->hob_lbal = readb(ioaddr->lbal_addr);
+ tf->hob_lbam = readb(ioaddr->lbam_addr);
+ tf->hob_lbah = readb(ioaddr->lbah_addr);
+
+ writeb(tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
+ } else {
+ printf("sata_dwc warnning register read.\n");
+ }
+ }
+}
+
+static void __ata_qc_complete(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_link *link = qc->dev->link;
+
+ link->active_tag = ATA_TAG_POISON;
+ ap->nr_active_links--;
+
+ if (qc->flags & ATA_QCFLAG_CLEAR_EXCL && ap->excl_link == link)
+ ap->excl_link = NULL;
+
+ qc->flags &= ~ATA_QCFLAG_ACTIVE;
+ ap->qc_active &= ~(1 << qc->tag);
+}
+
+static void ata_qc_free(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ unsigned int tag;
+ qc->flags = 0;
+ tag = qc->tag;
+ if (tag < ATA_MAX_QUEUE) {
+ qc->tag = ATA_TAG_POISON;
+ clear_bit(tag, &ap->qc_allocated);
+ }
+}
+
+static int check_sata_dev_state(void)
+{
+ unsigned long datalen;
+ unsigned char *pdata;
+ int ret = 0;
+ int i = 0;
+ char temp_data_buf[512];
+
+ while (1) {
+ udelay(10000);
+
+ pdata = (unsigned char*)&temp_data_buf[0];
+ datalen = 512;
+
+ ret = ata_dev_read_sectors(pdata, datalen, 0, 1);
+
+ if (ret == TRUE)
+ break;
+
+ i++;
+ if (i > (ATA_RESET_TIME * 100)) {
+ printf("** TimeOUT **\n");
+ dev_state = SATA_NODEVICE;
+ return FALSE;
+ }
+
+ if ((i >= 100) && ((i % 100) == 0))
+ printf(".");
+ }
+
+ dev_state = SATA_READY;
+
+ return TRUE;
+}
+
+static unsigned int ata_dev_set_feature(struct ata_device *dev,
+ u8 enable, u8 feature)
+{
+ struct ata_taskfile tf;
+ struct ata_port *ap;
+ ap = pap;
+ unsigned int err_mask;
+
+ memset(&tf, 0, sizeof(tf));
+ tf.ctl = ap->ctl;
+
+ tf.device = ATA_DEVICE_OBS;
+ tf.command = ATA_CMD_SET_FEATURES;
+ tf.feature = enable;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.protocol = ATA_PROT_NODATA;
+ tf.nsect = feature;
+
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0);
+
+ return err_mask;
+}
+
+static unsigned int ata_dev_init_params(struct ata_device *dev,
+ u16 heads, u16 sectors)
+{
+ struct ata_taskfile tf;
+ struct ata_port *ap;
+ ap = pap;
+ unsigned int err_mask;
+
+ if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16)
+ return AC_ERR_INVALID;
+
+ memset(&tf, 0, sizeof(tf));
+ tf.ctl = ap->ctl;
+ tf.device = ATA_DEVICE_OBS;
+ tf.command = ATA_CMD_INIT_DEV_PARAMS;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.protocol = ATA_PROT_NODATA;
+ tf.nsect = sectors;
+ tf.device |= (heads - 1) & 0x0f;
+
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0);
+
+ if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED))
+ err_mask = 0;
+
+ return err_mask;
+}
+
+#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48)
+#define SATA_MAX_READ_BLK 0xFF
+#else
+#define SATA_MAX_READ_BLK 0xFFFF
+#endif
+
+ulong sata_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer)
+{
+ ulong start,blks, buf_addr;
+ unsigned short smallblks;
+ unsigned long datalen;
+ unsigned char *pdata;
+ device &= 0xff;
+
+ u32 block = 0;
+ u32 n_block = 0;
+
+ if (dev_state != SATA_READY)
+ return 0;
+
+ buf_addr = (unsigned long)buffer;
+ start = blknr;
+ blks = blkcnt;
+ do {
+ pdata = (unsigned char *)buf_addr;
+ if (blks > SATA_MAX_READ_BLK) {
+ datalen = sata_dev_desc[device].blksz * SATA_MAX_READ_BLK;
+ smallblks = SATA_MAX_READ_BLK;
+
+ block = (u32)start;
+ n_block = (u32)smallblks;
+
+ start += SATA_MAX_READ_BLK;
+ blks -= SATA_MAX_READ_BLK;
+ } else {
+ datalen = sata_dev_desc[device].blksz * SATA_MAX_READ_BLK;
+ datalen = sata_dev_desc[device].blksz * blks;
+ smallblks = (unsigned short)blks;
+
+ block = (u32)start;
+ n_block = (u32)smallblks;
+
+ start += blks;
+ blks = 0;
+ }
+
+ if (ata_dev_read_sectors(pdata, datalen, block, n_block) != TRUE) {
+ printf("sata_dwc : Hard disk read error.\n");
+ blkcnt -= blks;
+ break;
+ }
+ buf_addr += datalen;
+ } while (blks != 0);
+
+ return (blkcnt);
+}
+
+static int ata_dev_read_sectors(unsigned char *pdata, unsigned long datalen,
+ u32 block, u32 n_block)
+{
+ struct ata_port *ap = pap;
+ struct ata_device *dev = &ata_device;
+ struct ata_taskfile tf;
+ unsigned int class = ATA_DEV_ATA;
+ unsigned int err_mask = 0;
+ const char *reason;
+ int may_fallback = 1;
+ int rc;
+
+ if (dev_state == SATA_ERROR)
+ return FALSE;
+
+ ata_dev_select(ap, dev->devno, 1, 1);
+
+retry:
+ memset(&tf, 0, sizeof(tf));
+ tf.ctl = ap->ctl;
+ ap->print_id = 1;
+ ap->flags &= ~ATA_FLAG_DISABLED;
+
+ ap->pdata = pdata;
+
+ tf.device = ATA_DEVICE_OBS;
+
+ temp_n_block = n_block;
+
+#ifdef CONFIG_LBA48
+ tf.command = ATA_CMD_PIO_READ_EXT;
+ tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
+
+ tf.hob_feature = 31;
+ tf.feature = 31;
+ tf.hob_nsect = (n_block >> 8) & 0xff;
+ tf.nsect = n_block & 0xff;
+
+ tf.hob_lbah = 0x0;
+ tf.hob_lbam = 0x0;
+ tf.hob_lbal = (block >> 24) & 0xff;
+ tf.lbah = (block >> 16) & 0xff;
+ tf.lbam = (block >> 8) & 0xff;
+ tf.lbal = block & 0xff;
+
+ tf.device = 1 << 6;
+ if (tf.flags & ATA_TFLAG_FUA)
+ tf.device |= 1 << 7;
+#else
+ tf.command = ATA_CMD_PIO_READ;
+ tf.flags |= ATA_TFLAG_LBA ;
+
+ tf.feature = 31;
+ tf.nsect = n_block & 0xff;
+
+ tf.lbah = (block >> 16) & 0xff;
+ tf.lbam = (block >> 8) & 0xff;
+ tf.lbal = block & 0xff;
+
+ tf.device = (block >> 24) & 0xf;
+
+ tf.device |= 1 << 6;
+ if (tf.flags & ATA_TFLAG_FUA)
+ tf.device |= 1 << 7;
+
+#endif
+
+ tf.protocol = ATA_PROT_PIO;
+
+ /* Some devices choke if TF registers contain garbage. Make
+ * sure those are properly initialized.
+ */
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.flags |= ATA_TFLAG_POLLING;
+
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, 0, 0);
+
+ if (err_mask) {
+ if (err_mask & AC_ERR_NODEV_HINT) {
+ printf("READ_SECTORS NODEV after polling detection\n");
+ return -ENOENT;
+ }
+
+ if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) {
+ /* Device or controller might have reported
+ * the wrong device class. Give a shot at the
+ * other IDENTIFY if the current one is
+ * aborted by the device.
+ */
+ if (may_fallback) {
+ may_fallback = 0;
+
+ if (class == ATA_DEV_ATA) {
+ class = ATA_DEV_ATAPI;
+ } else {
+ class = ATA_DEV_ATA;
+ }
+ goto retry;
+ }
+ /* Control reaches here iff the device aborted
+ * both flavors of IDENTIFYs which happens
+ * sometimes with phantom devices.
+ */
+ printf("both IDENTIFYs aborted, assuming NODEV\n");
+ return -ENOENT;
+ }
+
+ rc = -EIO;
+ reason = "I/O error";
+ goto err_out;
+ }
+
+ /* Falling back doesn't make sense if ID data was read
+ * successfully at least once.
+ */
+ may_fallback = 0;
+
+ rc = -EINVAL;
+ reason = "device reports invalid type";
+
+ return TRUE;
+
+err_out:
+ printf("failed to READ SECTORS (%s, err_mask=0x%x)\n", reason, err_mask);
+ return FALSE;
+}
+
+#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48)
+#define SATA_MAX_WRITE_BLK 0xFF
+#else
+#define SATA_MAX_WRITE_BLK 0xFFFF
+#endif
+
+ulong sata_write(int device, ulong blknr, lbaint_t blkcnt, void *buffer)
+{
+ ulong start,blks, buf_addr;
+ unsigned short smallblks;
+ unsigned long datalen;
+ unsigned char *pdata;
+ device &= 0xff;
+
+
+ u32 block = 0;
+ u32 n_block = 0;
+
+ if (dev_state != SATA_READY)
+ return 0;
+
+ buf_addr = (unsigned long)buffer;
+ start = blknr;
+ blks = blkcnt;
+ do {
+ pdata = (unsigned char *)buf_addr;
+ if (blks > SATA_MAX_WRITE_BLK) {
+ datalen = sata_dev_desc[device].blksz * SATA_MAX_WRITE_BLK;
+ smallblks = SATA_MAX_WRITE_BLK;
+
+ block = (u32)start;
+ n_block = (u32)smallblks;
+
+ start += SATA_MAX_WRITE_BLK;
+ blks -= SATA_MAX_WRITE_BLK;
+ } else {
+ datalen = sata_dev_desc[device].blksz * blks;
+ smallblks = (unsigned short)blks;
+
+ block = (u32)start;
+ n_block = (u32)smallblks;
+
+ start += blks;
+ blks = 0;
+ }
+
+ if (ata_dev_write_sectors(pdata, datalen, block, n_block) != TRUE) {
+ printf("sata_dwc : Hard disk read error.\n");
+ blkcnt -= blks;
+ break;
+ }
+ buf_addr += datalen;
+ } while (blks != 0);
+
+ return (blkcnt);
+}
+
+static int ata_dev_write_sectors(unsigned char* pdata, unsigned long datalen,
+ u32 block, u32 n_block)
+{
+ struct ata_port *ap = pap;
+ struct ata_device *dev = &ata_device;
+ struct ata_taskfile tf;
+ unsigned int class = ATA_DEV_ATA;
+ unsigned int err_mask = 0;
+ const char *reason;
+ int may_fallback = 1;
+ int rc;
+
+ if (dev_state == SATA_ERROR)
+ return FALSE;
+
+ ata_dev_select(ap, dev->devno, 1, 1);
+
+retry:
+ memset(&tf, 0, sizeof(tf));
+ tf.ctl = ap->ctl;
+ ap->print_id = 1;
+ ap->flags &= ~ATA_FLAG_DISABLED;
+
+ ap->pdata = pdata;
+
+ tf.device = ATA_DEVICE_OBS;
+
+ temp_n_block = n_block;
+
+
+#ifdef CONFIG_LBA48
+ tf.command = ATA_CMD_PIO_WRITE_EXT;
+ tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48 | ATA_TFLAG_WRITE;
+
+ tf.hob_feature = 31;
+ tf.feature = 31;
+ tf.hob_nsect = (n_block >> 8) & 0xff;
+ tf.nsect = n_block & 0xff;
+
+ tf.hob_lbah = 0x0;
+ tf.hob_lbam = 0x0;
+ tf.hob_lbal = (block >> 24) & 0xff;
+ tf.lbah = (block >> 16) & 0xff;
+ tf.lbam = (block >> 8) & 0xff;
+ tf.lbal = block & 0xff;
+
+ tf.device = 1 << 6;
+ if (tf.flags & ATA_TFLAG_FUA)
+ tf.device |= 1 << 7;
+#else
+ tf.command = ATA_CMD_PIO_WRITE;
+ tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_WRITE;
+
+ tf.feature = 31;
+ tf.nsect = n_block & 0xff;
+
+ tf.lbah = (block >> 16) & 0xff;
+ tf.lbam = (block >> 8) & 0xff;
+ tf.lbal = block & 0xff;
+
+ tf.device = (block >> 24) & 0xf;
+
+ tf.device |= 1 << 6;
+ if (tf.flags & ATA_TFLAG_FUA)
+ tf.device |= 1 << 7;
+
+#endif
+
+ tf.protocol = ATA_PROT_PIO;
+
+ /* Some devices choke if TF registers contain garbage. Make
+ * sure those are properly initialized.
+ */
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.flags |= ATA_TFLAG_POLLING;
+
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, 0, 0);
+
+ if (err_mask) {
+ if (err_mask & AC_ERR_NODEV_HINT) {
+ printf("READ_SECTORS NODEV after polling detection\n");
+ return -ENOENT;
+ }
+
+ if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) {
+ /* Device or controller might have reported
+ * the wrong device class. Give a shot at the
+ * other IDENTIFY if the current one is
+ * aborted by the device.
+ */
+ if (may_fallback) {
+ may_fallback = 0;
+
+ if (class == ATA_DEV_ATA) {
+ class = ATA_DEV_ATAPI;
+ } else {
+ class = ATA_DEV_ATA;
+ }
+ goto retry;
+ }
+ /* Control reaches here iff the device aborted
+ * both flavors of IDENTIFYs which happens
+ * sometimes with phantom devices.
+ */
+ printf("both IDENTIFYs aborted, assuming NODEV\n");
+ return -ENOENT;
+ }
+
+ rc = -EIO;
+ reason = "I/O error";
+ goto err_out;
+ }
+
+ /* Falling back doesn't make sense if ID data was read
+ * successfully at least once.
+ */
+ may_fallback = 0;
+
+ rc = -EINVAL;
+ reason = "device reports invalid type";
+
+ return TRUE;
+
+err_out:
+ printf("failed to WRITE SECTORS (%s, err_mask=0x%x)\n", reason, err_mask);
+ return FALSE;
+}
diff --git a/u-boot/drivers/block/sata_dwc.h b/u-boot/drivers/block/sata_dwc.h
new file mode 100644
index 0000000..204d644
--- /dev/null
+++ b/u-boot/drivers/block/sata_dwc.h
@@ -0,0 +1,477 @@
+/*
+ * sata_dwc.h
+ *
+ * Synopsys DesignWare Cores (DWC) SATA host driver
+ *
+ * Author: Mark Miesfeld <mmiesfeld@amcc.com>
+ *
+ * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese <sr@denx.de>
+ * Copyright 2008 DENX Software Engineering
+ *
+ * Based on versions provided by AMCC and Synopsys which are:
+ * Copyright 2006 Applied Micro Circuits Corporation
+ * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED
+ *
+ * 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.
+ *
+ */
+/*
+ * SATA support based on the chip canyonlands.
+ *
+ * 04-17-2009
+ * The local version of this driver for the canyonlands board
+ * does not use interrupts but polls the chip instead.
+ */
+
+
+#ifndef _SATA_DWC_H_
+#define _SATA_DWC_H_
+
+#define __U_BOOT__
+
+#define HZ 100
+#define READ 0
+#define WRITE 1
+
+enum {
+ ATA_READID_POSTRESET = (1 << 0),
+
+ ATA_DNXFER_PIO = 0,
+ ATA_DNXFER_DMA = 1,
+ ATA_DNXFER_40C = 2,
+ ATA_DNXFER_FORCE_PIO = 3,
+ ATA_DNXFER_FORCE_PIO0 = 4,
+
+ ATA_DNXFER_QUIET = (1 << 31),
+};
+
+enum hsm_task_states {
+ HSM_ST_IDLE,
+ HSM_ST_FIRST,
+ HSM_ST,
+ HSM_ST_LAST,
+ HSM_ST_ERR,
+};
+
+#define ATA_SHORT_PAUSE ((HZ >> 6) + 1)
+
+struct ata_queued_cmd {
+ struct ata_port *ap;
+ struct ata_device *dev;
+
+ struct ata_taskfile tf;
+ u8 cdb[ATAPI_CDB_LEN];
+ unsigned long flags;
+ unsigned int tag;
+ unsigned int n_elem;
+
+ int dma_dir;
+ unsigned int sect_size;
+
+ unsigned int nbytes;
+ unsigned int extrabytes;
+ unsigned int curbytes;
+
+ unsigned int err_mask;
+ struct ata_taskfile result_tf;
+
+ void *private_data;
+#ifndef __U_BOOT__
+ void *lldd_task;
+#endif
+ unsigned char *pdata;
+};
+
+typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc);
+
+#define ATA_TAG_POISON 0xfafbfcfdU
+
+enum {
+ LIBATA_MAX_PRD = ATA_MAX_PRD / 2,
+ LIBATA_DUMB_MAX_PRD = ATA_MAX_PRD / 4,
+ ATA_MAX_PORTS = 8,
+ ATA_DEF_QUEUE = 1,
+ ATA_MAX_QUEUE = 32,
+ ATA_TAG_INTERNAL = ATA_MAX_QUEUE - 1,
+ ATA_MAX_BUS = 2,
+ ATA_DEF_BUSY_WAIT = 10000,
+
+ ATAPI_MAX_DRAIN = 16 << 10,
+
+ ATA_SHT_EMULATED = 1,
+ ATA_SHT_CMD_PER_LUN = 1,
+ ATA_SHT_THIS_ID = -1,
+ ATA_SHT_USE_CLUSTERING = 1,
+
+ ATA_DFLAG_LBA = (1 << 0),
+ ATA_DFLAG_LBA48 = (1 << 1),
+ ATA_DFLAG_CDB_INTR = (1 << 2),
+ ATA_DFLAG_NCQ = (1 << 3),
+ ATA_DFLAG_FLUSH_EXT = (1 << 4),
+ ATA_DFLAG_ACPI_PENDING = (1 << 5),
+ ATA_DFLAG_ACPI_FAILED = (1 << 6),
+ ATA_DFLAG_AN = (1 << 7),
+ ATA_DFLAG_HIPM = (1 << 8),
+ ATA_DFLAG_DIPM = (1 << 9),
+ ATA_DFLAG_DMADIR = (1 << 10),
+ ATA_DFLAG_CFG_MASK = (1 << 12) - 1,
+
+ ATA_DFLAG_PIO = (1 << 12),
+ ATA_DFLAG_NCQ_OFF = (1 << 13),
+ ATA_DFLAG_SPUNDOWN = (1 << 14),
+ ATA_DFLAG_SLEEPING = (1 << 15),
+ ATA_DFLAG_DUBIOUS_XFER = (1 << 16),
+ ATA_DFLAG_INIT_MASK = (1 << 24) - 1,
+
+ ATA_DFLAG_DETACH = (1 << 24),
+ ATA_DFLAG_DETACHED = (1 << 25),
+
+ ATA_LFLAG_HRST_TO_RESUME = (1 << 0),
+ ATA_LFLAG_SKIP_D2H_BSY = (1 << 1),
+ ATA_LFLAG_NO_SRST = (1 << 2),
+ ATA_LFLAG_ASSUME_ATA = (1 << 3),
+ ATA_LFLAG_ASSUME_SEMB = (1 << 4),
+ ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB,
+ ATA_LFLAG_NO_RETRY = (1 << 5),
+ ATA_LFLAG_DISABLED = (1 << 6),
+
+ ATA_FLAG_SLAVE_POSS = (1 << 0),
+ ATA_FLAG_SATA = (1 << 1),
+ ATA_FLAG_NO_LEGACY = (1 << 2),
+ ATA_FLAG_MMIO = (1 << 3),
+ ATA_FLAG_SRST = (1 << 4),
+ ATA_FLAG_SATA_RESET = (1 << 5),
+ ATA_FLAG_NO_ATAPI = (1 << 6),
+ ATA_FLAG_PIO_DMA = (1 << 7),
+ ATA_FLAG_PIO_LBA48 = (1 << 8),
+ ATA_FLAG_PIO_POLLING = (1 << 9),
+ ATA_FLAG_NCQ = (1 << 10),
+ ATA_FLAG_DEBUGMSG = (1 << 13),
+ ATA_FLAG_IGN_SIMPLEX = (1 << 15),
+ ATA_FLAG_NO_IORDY = (1 << 16),
+ ATA_FLAG_ACPI_SATA = (1 << 17),
+ ATA_FLAG_AN = (1 << 18),
+ ATA_FLAG_PMP = (1 << 19),
+ ATA_FLAG_IPM = (1 << 20),
+
+ ATA_FLAG_DISABLED = (1 << 23),
+
+ ATA_PFLAG_EH_PENDING = (1 << 0),
+ ATA_PFLAG_EH_IN_PROGRESS = (1 << 1),
+ ATA_PFLAG_FROZEN = (1 << 2),
+ ATA_PFLAG_RECOVERED = (1 << 3),
+ ATA_PFLAG_LOADING = (1 << 4),
+ ATA_PFLAG_UNLOADING = (1 << 5),
+ ATA_PFLAG_SCSI_HOTPLUG = (1 << 6),
+ ATA_PFLAG_INITIALIZING = (1 << 7),
+ ATA_PFLAG_RESETTING = (1 << 8),
+ ATA_PFLAG_SUSPENDED = (1 << 17),
+ ATA_PFLAG_PM_PENDING = (1 << 18),
+
+ ATA_QCFLAG_ACTIVE = (1 << 0),
+ ATA_QCFLAG_DMAMAP = (1 << 1),
+ ATA_QCFLAG_IO = (1 << 3),
+ ATA_QCFLAG_RESULT_TF = (1 << 4),
+ ATA_QCFLAG_CLEAR_EXCL = (1 << 5),
+ ATA_QCFLAG_QUIET = (1 << 6),
+
+ ATA_QCFLAG_FAILED = (1 << 16),
+ ATA_QCFLAG_SENSE_VALID = (1 << 17),
+ ATA_QCFLAG_EH_SCHEDULED = (1 << 18),
+
+ ATA_HOST_SIMPLEX = (1 << 0),
+ ATA_HOST_STARTED = (1 << 1),
+
+ ATA_TMOUT_BOOT = 30 * 100,
+ ATA_TMOUT_BOOT_QUICK = 7 * 100,
+ ATA_TMOUT_INTERNAL = 30 * 100,
+ ATA_TMOUT_INTERNAL_QUICK = 5 * 100,
+
+ /* FIXME: GoVault needs 2s but we can't afford that without
+ * parallel probing. 800ms is enough for iVDR disk
+ * HHD424020F7SV00. Increase to 2secs when parallel probing
+ * is in place.
+ */
+ ATA_TMOUT_FF_WAIT = 4 * 100 / 5,
+
+ BUS_UNKNOWN = 0,
+ BUS_DMA = 1,
+ BUS_IDLE = 2,
+ BUS_NOINTR = 3,
+ BUS_NODATA = 4,
+ BUS_TIMER = 5,
+ BUS_PIO = 6,
+ BUS_EDD = 7,
+ BUS_IDENTIFY = 8,
+ BUS_PACKET = 9,
+
+ PORT_UNKNOWN = 0,
+ PORT_ENABLED = 1,
+ PORT_DISABLED = 2,
+
+ /* encoding various smaller bitmaps into a single
+ * unsigned long bitmap
+ */
+ ATA_NR_PIO_MODES = 7,
+ ATA_NR_MWDMA_MODES = 5,
+ ATA_NR_UDMA_MODES = 8,
+
+ ATA_SHIFT_PIO = 0,
+ ATA_SHIFT_MWDMA = ATA_SHIFT_PIO + ATA_NR_PIO_MODES,
+ ATA_SHIFT_UDMA = ATA_SHIFT_MWDMA + ATA_NR_MWDMA_MODES,
+
+ ATA_DMA_PAD_SZ = 4,
+
+ ATA_ERING_SIZE = 32,
+
+ ATA_DEFER_LINK = 1,
+ ATA_DEFER_PORT = 2,
+
+ ATA_EH_DESC_LEN = 80,
+
+ ATA_EH_REVALIDATE = (1 << 0),
+ ATA_EH_SOFTRESET = (1 << 1),
+ ATA_EH_HARDRESET = (1 << 2),
+ ATA_EH_ENABLE_LINK = (1 << 3),
+ ATA_EH_LPM = (1 << 4),
+
+ ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
+ ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE,
+
+ ATA_EHI_HOTPLUGGED = (1 << 0),
+ ATA_EHI_RESUME_LINK = (1 << 1),
+ ATA_EHI_NO_AUTOPSY = (1 << 2),
+ ATA_EHI_QUIET = (1 << 3),
+
+ ATA_EHI_DID_SOFTRESET = (1 << 16),
+ ATA_EHI_DID_HARDRESET = (1 << 17),
+ ATA_EHI_PRINTINFO = (1 << 18),
+ ATA_EHI_SETMODE = (1 << 19),
+ ATA_EHI_POST_SETMODE = (1 << 20),
+
+ ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET,
+ ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK,
+
+ ATA_EH_MAX_TRIES = 5,
+
+ ATA_PROBE_MAX_TRIES = 3,
+ ATA_EH_DEV_TRIES = 3,
+ ATA_EH_PMP_TRIES = 5,
+ ATA_EH_PMP_LINK_TRIES = 3,
+
+ SATA_PMP_SCR_TIMEOUT = 250,
+
+ /* Horkage types. May be set by libata or controller on drives
+ (some horkage may be drive/controller pair dependant */
+
+ ATA_HORKAGE_DIAGNOSTIC = (1 << 0),
+ ATA_HORKAGE_NODMA = (1 << 1),
+ ATA_HORKAGE_NONCQ = (1 << 2),
+ ATA_HORKAGE_MAX_SEC_128 = (1 << 3),
+ ATA_HORKAGE_BROKEN_HPA = (1 << 4),
+ ATA_HORKAGE_SKIP_PM = (1 << 5),
+ ATA_HORKAGE_HPA_SIZE = (1 << 6),
+ ATA_HORKAGE_IPM = (1 << 7),
+ ATA_HORKAGE_IVB = (1 << 8),
+ ATA_HORKAGE_STUCK_ERR = (1 << 9),
+
+ ATA_DMA_MASK_ATA = (1 << 0),
+ ATA_DMA_MASK_ATAPI = (1 << 1),
+ ATA_DMA_MASK_CFA = (1 << 2),
+
+ ATAPI_READ = 0,
+ ATAPI_WRITE = 1,
+ ATAPI_READ_CD = 2,
+ ATAPI_PASS_THRU = 3,
+ ATAPI_MISC = 4,
+};
+
+enum ata_completion_errors {
+ AC_ERR_DEV = (1 << 0),
+ AC_ERR_HSM = (1 << 1),
+ AC_ERR_TIMEOUT = (1 << 2),
+ AC_ERR_MEDIA = (1 << 3),
+ AC_ERR_ATA_BUS = (1 << 4),
+ AC_ERR_HOST_BUS = (1 << 5),
+ AC_ERR_SYSTEM = (1 << 6),
+ AC_ERR_INVALID = (1 << 7),
+ AC_ERR_OTHER = (1 << 8),
+ AC_ERR_NODEV_HINT = (1 << 9),
+ AC_ERR_NCQ = (1 << 10),
+};
+
+enum ata_xfer_mask {
+ ATA_MASK_PIO = ((1LU << ATA_NR_PIO_MODES) - 1) << ATA_SHIFT_PIO,
+ ATA_MASK_MWDMA = ((1LU << ATA_NR_MWDMA_MODES) - 1) << ATA_SHIFT_MWDMA,
+ ATA_MASK_UDMA = ((1LU << ATA_NR_UDMA_MODES) - 1) << ATA_SHIFT_UDMA,
+};
+
+struct ata_port_info {
+#ifndef __U_BOOT__
+ struct scsi_host_template *sht;
+#endif
+ unsigned long flags;
+ unsigned long link_flags;
+ unsigned long pio_mask;
+ unsigned long mwdma_mask;
+ unsigned long udma_mask;
+#ifndef __U_BOOT__
+ const struct ata_port_operations *port_ops;
+ void *private_data;
+#endif
+};
+
+struct ata_ioports {
+ void __iomem *cmd_addr;
+ void __iomem *data_addr;
+ void __iomem *error_addr;
+ void __iomem *feature_addr;
+ void __iomem *nsect_addr;
+ void __iomem *lbal_addr;
+ void __iomem *lbam_addr;
+ void __iomem *lbah_addr;
+ void __iomem *device_addr;
+ void __iomem *status_addr;
+ void __iomem *command_addr;
+ void __iomem *altstatus_addr;
+ void __iomem *ctl_addr;
+#ifndef __U_BOOT__
+ void __iomem *bmdma_addr;
+#endif
+ void __iomem *scr_addr;
+};
+
+struct ata_host {
+#ifndef __U_BOOT__
+ void __iomem * const *iomap;
+ void *private_data;
+ const struct ata_port_operations *ops;
+ unsigned long flags;
+ struct ata_port *simplex_claimed;
+#endif
+ unsigned int n_ports;
+ struct ata_port *ports[0];
+};
+
+#ifndef __U_BOOT__
+struct ata_port_stats {
+ unsigned long unhandled_irq;
+ unsigned long idle_irq;
+ unsigned long rw_reqbuf;
+};
+#endif
+
+struct ata_device {
+ struct ata_link *link;
+ unsigned int devno;
+ unsigned long flags;
+ unsigned int horkage;
+#ifndef __U_BOOT__
+ struct scsi_device *sdev;
+#ifdef CONFIG_ATA_ACPI
+ acpi_handle acpi_handle;
+ union acpi_object *gtf_cache;
+#endif
+#endif
+ u64 n_sectors;
+ unsigned int class;
+
+ union {
+ u16 id[ATA_ID_WORDS];
+ u32 gscr[SATA_PMP_GSCR_DWORDS];
+ };
+#ifndef __U_BOOT__
+ u8 pio_mode;
+ u8 dma_mode;
+ u8 xfer_mode;
+ unsigned int xfer_shift;
+#endif
+ unsigned int multi_count;
+ unsigned int max_sectors;
+ unsigned int cdb_len;
+#ifndef __U_BOOT__
+ unsigned long pio_mask;
+ unsigned long mwdma_mask;
+#endif
+ unsigned long udma_mask;
+ u16 cylinders;
+ u16 heads;
+ u16 sectors;
+#ifndef __U_BOOT__
+ int spdn_cnt;
+#endif
+};
+
+enum dma_data_direction {
+ DMA_BIDIRECTIONAL = 0,
+ DMA_TO_DEVICE = 1,
+ DMA_FROM_DEVICE = 2,
+ DMA_NONE = 3,
+};
+
+struct ata_link {
+ struct ata_port *ap;
+ int pmp;
+ unsigned int active_tag;
+ u32 sactive;
+ unsigned int flags;
+ unsigned int hw_sata_spd_limit;
+#ifndef __U_BOOT__
+ unsigned int sata_spd_limit;
+ unsigned int sata_spd;
+ struct ata_device device[2];
+#endif
+};
+
+struct ata_port {
+ unsigned long flags;
+ unsigned int pflags;
+ unsigned int print_id;
+ unsigned int port_no;
+
+ struct ata_ioports ioaddr;
+
+ u8 ctl;
+ u8 last_ctl;
+ unsigned int pio_mask;
+ unsigned int mwdma_mask;
+ unsigned int udma_mask;
+ unsigned int cbl;
+
+ struct ata_queued_cmd qcmd[ATA_MAX_QUEUE];
+ unsigned long qc_allocated;
+ unsigned int qc_active;
+ int nr_active_links;
+
+ struct ata_link link;
+#ifndef __U_BOOT__
+ int nr_pmp_links;
+ struct ata_link *pmp_link;
+#endif
+ struct ata_link *excl_link;
+ int nr_pmp_links;
+#ifndef __U_BOOT__
+ struct ata_port_stats stats;
+ struct device *dev;
+ u32 msg_enable;
+#endif
+ struct ata_host *host;
+ void *port_task_data;
+
+ unsigned int hsm_task_state;
+ void *private_data;
+ unsigned char *pdata;
+};
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#endif
diff --git a/u-boot/drivers/block/sata_sil3114.c b/u-boot/drivers/block/sata_sil3114.c
new file mode 100644
index 0000000..62cc99d
--- /dev/null
+++ b/u-boot/drivers/block/sata_sil3114.c
@@ -0,0 +1,839 @@
+/*
+ * Copyright (C) Excito Elektronik i Skåne AB, All rights reserved.
+ * Author: Tor Krill <tor@excito.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
+ *
+ * This is a driver for Silicon Image sil3114 sata chip modelled on
+ * the ata_piix driver
+ */
+
+#include <common.h>
+#include <pci.h>
+#include <command.h>
+#include <config.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <ide.h>
+#include <libata.h>
+#include "sata_sil3114.h"
+
+/* Convert sectorsize to wordsize */
+#define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2)
+
+/* Forwards */
+u8 sil3114_spin_up (int num);
+u8 sil3114_spin_down (int num);
+static int sata_bus_softreset (int num);
+static void sata_identify (int num, int dev);
+static u8 check_power_mode (int num);
+static void sata_port (struct sata_ioports *ioport);
+static void set_Feature_cmd (int num, int dev);
+static u8 sata_busy_wait (struct sata_ioports *ioaddr, int bits,
+ unsigned int max, u8 usealtstatus);
+static u8 sata_chk_status (struct sata_ioports *ioaddr, u8 usealtstatus);
+static void msleep (int count);
+
+static u32 iobase[6] = { 0, 0, 0, 0, 0, 0}; /* PCI BAR registers for device */
+extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE];
+
+static struct sata_port port[CONFIG_SYS_SATA_MAX_DEVICE];
+
+static void output_data (struct sata_ioports *ioaddr, u16 * sect_buf, int words)
+{
+ while (words--) {
+ __raw_writew (*sect_buf++, (void *)ioaddr->data_addr);
+ }
+}
+
+static int input_data (struct sata_ioports *ioaddr, u16 * sect_buf, int words)
+{
+ while (words--) {
+ *sect_buf++ = __raw_readw ((void *)ioaddr->data_addr);
+ }
+ return 0;
+}
+
+static int sata_bus_softreset (int num)
+{
+ u8 status = 0;
+
+ port[num].dev_mask = 1;
+
+ port[num].ctl_reg = 0x08; /*Default value of control reg */
+ writeb (port[num].ctl_reg, port[num].ioaddr.ctl_addr);
+ udelay (10);
+ writeb (port[num].ctl_reg | ATA_SRST, port[num].ioaddr.ctl_addr);
+ udelay (10);
+ writeb (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, 0);
+ while ((status & ATA_BUSY)) {
+ msleep (100);
+ status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 3, 0);
+ }
+
+ if (status & ATA_BUSY) {
+ printf ("ata%u is slow to respond,plz be patient\n", num);
+ }
+
+ while ((status & ATA_BUSY)) {
+ msleep (100);
+ status = sata_chk_status (&port[num].ioaddr, 0);
+ }
+
+ if (status & ATA_BUSY) {
+ printf ("ata%u failed to respond : ", num);
+ printf ("bus reset failed\n");
+ port[num].dev_mask = 0;
+ return 1;
+ }
+ return 0;
+}
+
+static void sata_identify (int num, int dev)
+{
+ u8 cmd = 0, status = 0, devno = num;
+ u16 iobuf[ATA_SECTOR_WORDS];
+ u64 n_sectors = 0;
+
+ memset (iobuf, 0, sizeof (iobuf));
+
+ if (!(port[num].dev_mask & 0x01)) {
+ printf ("dev%d is not present on port#%d\n", dev, num);
+ return;
+ }
+
+ debug ("port=%d dev=%d\n", num, dev);
+
+ status = 0;
+ cmd = ATA_CMD_ID_ATA; /*Device Identify Command */
+ writeb (cmd, port[num].ioaddr.command_addr);
+ readb (port[num].ioaddr.altstatus_addr);
+ udelay (10);
+
+ status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 1000, 0);
+ if (status & ATA_ERR) {
+ printf ("\ndevice not responding\n");
+ port[num].dev_mask &= ~0x01;
+ return;
+ }
+
+ input_data (&port[num].ioaddr, iobuf, ATA_SECTOR_WORDS);
+
+ ata_swap_buf_le16 (iobuf, ATA_SECTOR_WORDS);
+
+ debug ("Specific config: %x\n", iobuf[2]);
+
+ /* we require LBA and DMA support (bits 8 & 9 of word 49) */
+ if (!ata_id_has_dma (iobuf) || !ata_id_has_lba (iobuf)) {
+ debug ("ata%u: no dma/lba\n", num);
+ }
+#ifdef DEBUG
+ ata_dump_id (iobuf);
+#endif
+ n_sectors = ata_id_n_sectors (iobuf);
+
+ if (n_sectors == 0) {
+ port[num].dev_mask &= ~0x01;
+ return;
+ }
+ ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].revision,
+ ATA_ID_FW_REV, sizeof (sata_dev_desc[devno].revision));
+ ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].vendor,
+ ATA_ID_PROD, sizeof (sata_dev_desc[devno].vendor));
+ ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].product,
+ ATA_ID_SERNO, sizeof (sata_dev_desc[devno].product));
+
+ /* TODO - atm we asume harddisk ie not removable */
+ sata_dev_desc[devno].removable = 0;
+
+ sata_dev_desc[devno].lba = (u32) n_sectors;
+ debug ("lba=0x%x\n", sata_dev_desc[devno].lba);
+
+#ifdef CONFIG_LBA48
+ if (iobuf[83] & (1 << 10)) {
+ sata_dev_desc[devno].lba48 = 1;
+ } else {
+ sata_dev_desc[devno].lba48 = 0;
+ }
+#endif
+
+ /* assuming HD */
+ sata_dev_desc[devno].type = DEV_TYPE_HARDDISK;
+ sata_dev_desc[devno].blksz = ATA_SECT_SIZE;
+ sata_dev_desc[devno].lun = 0; /* just to fill something in... */
+}
+
+static void set_Feature_cmd (int num, int dev)
+{
+ u8 status = 0;
+
+ if (!(port[num].dev_mask & 0x01)) {
+ debug ("dev%d is not present on port#%d\n", dev, num);
+ return;
+ }
+
+ writeb (SETFEATURES_XFER, port[num].ioaddr.feature_addr);
+ writeb (XFER_PIO_4, port[num].ioaddr.nsect_addr);
+ writeb (0, port[num].ioaddr.lbal_addr);
+ writeb (0, port[num].ioaddr.lbam_addr);
+ writeb (0, port[num].ioaddr.lbah_addr);
+
+ writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr);
+ writeb (ATA_CMD_SET_FEATURES, port[num].ioaddr.command_addr);
+
+ udelay (50);
+ msleep (150);
+
+ status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 5000, 0);
+ if ((status & (ATA_BUSY | ATA_ERR))) {
+ printf ("Error : status 0x%02x\n", status);
+ port[num].dev_mask &= ~0x01;
+ }
+}
+
+u8 sil3114_spin_down (int num)
+{
+ u8 status = 0;
+
+ debug ("Spin down disk\n");
+
+ if (!(port[num].dev_mask & 0x01)) {
+ debug ("Device ata%d is not present\n", num);
+ return 1;
+ }
+
+ if ((status = check_power_mode (num)) == 0x00) {
+ debug ("Already in standby\n");
+ return 0;
+ }
+
+ if (status == 0x01) {
+ printf ("Failed to check power mode on ata%d\n", num);
+ return 1;
+ }
+
+ if (!((status = sata_chk_status (&port[num].ioaddr, 0)) & ATA_DRDY)) {
+ printf ("Device ata%d not ready\n", num);
+ return 1;
+ }
+
+ writeb (0x00, port[num].ioaddr.feature_addr);
+
+ writeb (0x00, port[num].ioaddr.nsect_addr);
+ writeb (0x00, port[num].ioaddr.lbal_addr);
+ writeb (0x00, port[num].ioaddr.lbam_addr);
+ writeb (0x00, port[num].ioaddr.lbah_addr);
+
+ writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr);
+ writeb (ATA_CMD_STANDBY, port[num].ioaddr.command_addr);
+
+ status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 30000, 0);
+ if ((status & (ATA_BUSY | ATA_ERR))) {
+ printf ("Error waiting for disk spin down: status 0x%02x\n",
+ status);
+ port[num].dev_mask &= ~0x01;
+ return 1;
+ }
+ return 0;
+}
+
+u8 sil3114_spin_up (int num)
+{
+ u8 status = 0;
+
+ debug ("Spin up disk\n");
+
+ if (!(port[num].dev_mask & 0x01)) {
+ debug ("Device ata%d is not present\n", num);
+ return 1;
+ }
+
+ if ((status = check_power_mode (num)) != 0x00) {
+ if (status == 0x01) {
+ printf ("Failed to check power mode on ata%d\n", num);
+ return 1;
+ } else {
+ /* should be up and running already */
+ return 0;
+ }
+ }
+
+ if (!((status = sata_chk_status (&port[num].ioaddr, 0)) & ATA_DRDY)) {
+ printf ("Device ata%d not ready\n", num);
+ return 1;
+ }
+
+ debug ("Stautus of device check: %d\n", status);
+
+ writeb (0x00, port[num].ioaddr.feature_addr);
+
+ writeb (0x00, port[num].ioaddr.nsect_addr);
+ writeb (0x00, port[num].ioaddr.lbal_addr);
+ writeb (0x00, port[num].ioaddr.lbam_addr);
+ writeb (0x00, port[num].ioaddr.lbah_addr);
+
+ writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr);
+ writeb (ATA_CMD_IDLE, port[num].ioaddr.command_addr);
+
+ status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 30000, 0);
+ if ((status & (ATA_BUSY | ATA_ERR))) {
+ printf ("Error waiting for disk spin up: status 0x%02x\n",
+ status);
+ port[num].dev_mask &= ~0x01;
+ return 1;
+ }
+
+ /* Wait for disk to enter Active state */
+ do {
+ msleep (10);
+ status = check_power_mode (num);
+ } while ((status == 0x00) || (status == 0x80));
+
+ if (status == 0x01) {
+ printf ("Falied waiting for disk to spin up\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Return value is not the usual here
+ * 0x00 - Device stand by
+ * 0x01 - Operation failed
+ * 0x80 - Device idle
+ * 0xff - Device active
+*/
+static u8 check_power_mode (int num)
+{
+ u8 status = 0;
+ u8 res = 0;
+ if (!(port[num].dev_mask & 0x01)) {
+ debug ("Device ata%d is not present\n", num);
+ return 1;
+ }
+
+ if (!(sata_chk_status (&port[num].ioaddr, 0) & ATA_DRDY)) {
+ printf ("Device ata%d not ready\n", num);
+ return 1;
+ }
+
+ writeb (0, port[num].ioaddr.feature_addr);
+ writeb (0, port[num].ioaddr.nsect_addr);
+ writeb (0, port[num].ioaddr.lbal_addr);
+ writeb (0, port[num].ioaddr.lbam_addr);
+ writeb (0, port[num].ioaddr.lbah_addr);
+
+ writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr);
+ writeb (ATA_CMD_CHK_POWER, port[num].ioaddr.command_addr);
+
+ status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 5000, 0);
+ if ((status & (ATA_BUSY | ATA_ERR))) {
+ printf
+ ("Error waiting for check power mode complete : status 0x%02x\n",
+ status);
+ port[num].dev_mask &= ~0x01;
+ return 1;
+ }
+ res = readb (port[num].ioaddr.nsect_addr);
+ debug ("Check powermode: %d\n", res);
+ return res;
+
+}
+
+static 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;
+}
+
+static u8 wait_for_irq (int num, unsigned int max)
+{
+
+ u32 port = iobase[5];
+ switch (num) {
+ case 0:
+ port += VND_TF_CNST_CH0;
+ break;
+ case 1:
+ port += VND_TF_CNST_CH1;
+ break;
+ case 2:
+ port += VND_TF_CNST_CH2;
+ break;
+ case 3:
+ port += VND_TF_CNST_CH3;
+ break;
+ default:
+ return 1;
+ }
+
+ do {
+ if (readl (port) & VND_TF_CNST_INTST) {
+ break;
+ }
+ udelay (1000);
+ max--;
+ } while ((max > 0));
+
+ return (max == 0);
+}
+
+static u8 sata_busy_wait (struct sata_ioports *ioaddr, int bits,
+ unsigned int max, u8 usealtstatus)
+{
+ u8 status;
+
+ do {
+ if (!((status = sata_chk_status (ioaddr, usealtstatus)) & bits)) {
+ break;
+ }
+ udelay (1000);
+ max--;
+ } while ((status & bits) && (max > 0));
+
+ return status;
+}
+
+static u8 sata_chk_status (struct sata_ioports *ioaddr, u8 usealtstatus)
+{
+ if (!usealtstatus) {
+ return readb (ioaddr->status_addr);
+ } else {
+ return readb (ioaddr->altstatus_addr);
+ }
+}
+
+static void msleep (int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ udelay (1000);
+}
+
+/* Read up to 255 sectors
+ *
+ * Returns sectors read
+*/
+static u8 do_one_read (int device, ulong block, u8 blkcnt, u16 * buff,
+ uchar lba48)
+{
+
+ u8 sr = 0;
+ u8 status;
+ u64 blknr = (u64) block;
+
+ if (!(sata_chk_status (&port[device].ioaddr, 0) & ATA_DRDY)) {
+ printf ("Device ata%d not ready\n", device);
+ return 0;
+ }
+
+ /* Set up transfer */
+#ifdef CONFIG_LBA48
+ if (lba48) {
+ /* write high bits */
+ writeb (0, port[device].ioaddr.nsect_addr);
+ writeb ((blknr >> 24) & 0xFF, port[device].ioaddr.lbal_addr);
+ writeb ((blknr >> 32) & 0xFF, port[device].ioaddr.lbam_addr);
+ writeb ((blknr >> 40) & 0xFF, port[device].ioaddr.lbah_addr);
+ }
+#endif
+ writeb (blkcnt, port[device].ioaddr.nsect_addr);
+ writeb (((blknr) >> 0) & 0xFF, port[device].ioaddr.lbal_addr);
+ writeb ((blknr >> 8) & 0xFF, port[device].ioaddr.lbam_addr);
+ writeb ((blknr >> 16) & 0xFF, port[device].ioaddr.lbah_addr);
+
+#ifdef CONFIG_LBA48
+ if (lba48) {
+ writeb (ATA_LBA, port[device].ioaddr.device_addr);
+ writeb (ATA_CMD_PIO_READ_EXT, port[device].ioaddr.command_addr);
+ } else
+#endif
+ {
+ writeb (ATA_LBA | ((blknr >> 24) & 0xF),
+ port[device].ioaddr.device_addr);
+ writeb (ATA_CMD_PIO_READ, port[device].ioaddr.command_addr);
+ }
+
+ status = sata_busy_wait (&port[device].ioaddr, ATA_BUSY, 10000, 1);
+
+ if (status & ATA_BUSY) {
+ u8 err = 0;
+
+ printf ("Device %d not responding status %d\n", device, status);
+ err = readb (port[device].ioaddr.error_addr);
+ printf ("Error reg = 0x%x\n", err);
+
+ return (sr);
+ }
+ while (blkcnt--) {
+
+ if (wait_for_irq (device, 500)) {
+ printf ("ata%u irq failed\n", device);
+ return sr;
+ }
+
+ status = sata_chk_status (&port[device].ioaddr, 0);
+ if (status & ATA_ERR) {
+ printf ("ata%u error %d\n", device,
+ readb (port[device].ioaddr.error_addr));
+ return sr;
+ }
+ /* Read one sector */
+ input_data (&port[device].ioaddr, buff, ATA_SECTOR_WORDS);
+ buff += ATA_SECTOR_WORDS;
+ sr++;
+
+ }
+ return sr;
+}
+
+ulong sata_read (int device, ulong block, lbaint_t blkcnt, void *buff)
+{
+ ulong n = 0, sread;
+ u16 *buffer = (u16 *) buff;
+ u8 status = 0;
+ u64 blknr = (u64) block;
+ unsigned char lba48 = 0;
+
+#ifdef CONFIG_LBA48
+ if (blknr > 0xfffffff) {
+ if (!sata_dev_desc[device].lba48) {
+ printf ("Drive doesn't support 48-bit addressing\n");
+ return 0;
+ }
+ /* more than 28 bits used, use 48bit mode */
+ lba48 = 1;
+ }
+#endif
+
+ while (blkcnt > 0) {
+
+ if (blkcnt > 255) {
+ sread = 255;
+ } else {
+ sread = blkcnt;
+ }
+
+ status = do_one_read (device, blknr, sread, buffer, lba48);
+ if (status != sread) {
+ printf ("Read failed\n");
+ return n;
+ }
+
+ blkcnt -= sread;
+ blknr += sread;
+ n += sread;
+ buffer += sread * ATA_SECTOR_WORDS;
+ }
+ return n;
+}
+
+ulong sata_write (int device, ulong block, lbaint_t blkcnt, const void *buff)
+{
+ ulong n = 0;
+ u16 *buffer = (u16 *) buff;
+ unsigned char status = 0, num = 0;
+ u64 blknr = (u64) block;
+#ifdef CONFIG_LBA48
+ unsigned char lba48 = 0;
+
+ if (blknr > 0xfffffff) {
+ if (!sata_dev_desc[device].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;
+
+ while (blkcnt-- > 0) {
+ status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500, 0);
+ 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 */
+ writeb (0, port[num].ioaddr.nsect_addr);
+ writeb ((blknr >> 24) & 0xFF,
+ port[num].ioaddr.lbal_addr);
+ writeb ((blknr >> 32) & 0xFF,
+ port[num].ioaddr.lbam_addr);
+ writeb ((blknr >> 40) & 0xFF,
+ port[num].ioaddr.lbah_addr);
+ }
+#endif
+ writeb (1, port[num].ioaddr.nsect_addr);
+ writeb ((blknr >> 0) & 0xFF, port[num].ioaddr.lbal_addr);
+ writeb ((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr);
+ writeb ((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr);
+#ifdef CONFIG_LBA48
+ if (lba48) {
+ writeb (ATA_LBA, port[num].ioaddr.device_addr);
+ writeb (ATA_CMD_PIO_WRITE_EXT, port[num].ioaddr.command_addr);
+ } else
+#endif
+ {
+ writeb (ATA_LBA | ((blknr >> 24) & 0xF),
+ port[num].ioaddr.device_addr);
+ writeb (ATA_CMD_PIO_WRITE, port[num].ioaddr.command_addr);
+ }
+
+ msleep (50);
+ /*may take up to 4 sec */
+ status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 4000, 0);
+ if ((status & (ATA_DRQ | ATA_BUSY | ATA_ERR)) != ATA_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_SECTOR_WORDS);
+ readb (port[num].ioaddr.altstatus_addr);
+ udelay (50);
+
+ ++n;
+ ++blknr;
+ buffer += ATA_SECTOR_WORDS;
+ }
+ return n;
+}
+
+/* Driver implementation */
+static u8 sil_get_device_cache_line (pci_dev_t pdev)
+{
+ u8 cache_line = 0;
+ pci_read_config_byte (pdev, PCI_CACHE_LINE_SIZE, &cache_line);
+ return cache_line;
+}
+
+int init_sata (int dev)
+{
+ static u8 init_done = 0;
+ static int res = 1;
+ pci_dev_t devno;
+ u8 cls = 0;
+ u16 cmd = 0;
+ u32 sconf = 0;
+
+ if (init_done) {
+ return res;
+ }
+
+ init_done = 1;
+
+ if ((devno = pci_find_device (SIL_VEND_ID, SIL3114_DEVICE_ID, 0)) == -1) {
+ res = 1;
+ return res;
+ }
+
+ /* Read out all BARs, even though we only use MMIO from BAR5 */
+ pci_read_config_dword (devno, PCI_BASE_ADDRESS_0, &iobase[0]);
+ pci_read_config_dword (devno, PCI_BASE_ADDRESS_1, &iobase[1]);
+ pci_read_config_dword (devno, PCI_BASE_ADDRESS_2, &iobase[2]);
+ pci_read_config_dword (devno, PCI_BASE_ADDRESS_3, &iobase[3]);
+ pci_read_config_dword (devno, PCI_BASE_ADDRESS_4, &iobase[4]);
+ pci_read_config_dword (devno, PCI_BASE_ADDRESS_5, &iobase[5]);
+
+ if ((iobase[0] == 0xFFFFFFFF) || (iobase[1] == 0xFFFFFFFF) ||
+ (iobase[2] == 0xFFFFFFFF) || (iobase[3] == 0xFFFFFFFF) ||
+ (iobase[4] == 0xFFFFFFFF) || (iobase[5] == 0xFFFFFFFF)) {
+ printf ("Error no base addr for SATA controller\n");
+ res = 1;
+ return res;
+ }
+
+ /* mask off unused bits */
+ iobase[0] &= 0xfffffffc;
+ iobase[1] &= 0xfffffff8;
+ iobase[2] &= 0xfffffffc;
+ iobase[3] &= 0xfffffff8;
+ iobase[4] &= 0xfffffff0;
+ iobase[5] &= 0xfffffc00;
+
+ /* from sata_sil in Linux kernel */
+ cls = sil_get_device_cache_line (devno);
+ if (cls) {
+ cls >>= 3;
+ cls++; /* cls = (line_size/8)+1 */
+ writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH0);
+ writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH1);
+ writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH2);
+ writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH3);
+ } else {
+ printf ("Cache line not set. Driver may not function\n");
+ }
+
+ /* Enable operation */
+ pci_read_config_word (devno, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+ pci_write_config_word (devno, PCI_COMMAND, cmd);
+
+ /* Disable interrupt usage */
+ pci_read_config_dword (devno, VND_SYSCONFSTAT, &sconf);
+ sconf |= (VND_SYSCONFSTAT_CHN_0_INTBLOCK | VND_SYSCONFSTAT_CHN_1_INTBLOCK);
+ pci_write_config_dword (devno, VND_SYSCONFSTAT, sconf);
+
+ res = 0;
+ return res;
+}
+
+/* Check if device is connected to port */
+int sata_bus_probe (int portno)
+{
+ u32 port = iobase[5];
+ u32 val;
+ switch (portno) {
+ case 0:
+ port += VND_SSTATUS_CH0;
+ break;
+ case 1:
+ port += VND_SSTATUS_CH1;
+ break;
+ case 2:
+ port += VND_SSTATUS_CH2;
+ break;
+ case 3:
+ port += VND_SSTATUS_CH3;
+ break;
+ default:
+ return 0;
+ }
+ val = readl (port);
+ if ((val & SATA_DET_PRES) == SATA_DET_PRES) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int sata_phy_reset (int portno)
+{
+ u32 port = iobase[5];
+ u32 val;
+ switch (portno) {
+ case 0:
+ port += VND_SCONTROL_CH0;
+ break;
+ case 1:
+ port += VND_SCONTROL_CH1;
+ break;
+ case 2:
+ port += VND_SCONTROL_CH2;
+ break;
+ case 3:
+ port += VND_SCONTROL_CH3;
+ break;
+ default:
+ return 0;
+ }
+ val = readl (port);
+ writel (val | SATA_SC_DET_RST, port);
+ msleep (150);
+ writel (val & ~SATA_SC_DET_RST, port);
+ return 0;
+}
+
+int scan_sata (int dev)
+{
+ /* A bit brain dead, but the code has a legacy */
+ switch (dev) {
+ case 0:
+ port[0].port_no = 0;
+ port[0].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH0;
+ port[0].ioaddr.altstatus_addr = port[0].ioaddr.ctl_addr =
+ (iobase[5] + VND_TF2_CH0) | ATA_PCI_CTL_OFS;
+ port[0].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH0;
+ break;
+ case 1:
+ port[1].port_no = 0;
+ port[1].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH1;
+ port[1].ioaddr.altstatus_addr = port[1].ioaddr.ctl_addr =
+ (iobase[5] + VND_TF2_CH1) | ATA_PCI_CTL_OFS;
+ port[1].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH1;
+ break;
+ case 2:
+ port[2].port_no = 0;
+ port[2].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH2;
+ port[2].ioaddr.altstatus_addr = port[2].ioaddr.ctl_addr =
+ (iobase[5] + VND_TF2_CH2) | ATA_PCI_CTL_OFS;
+ port[2].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH2;
+ break;
+ case 3:
+ port[3].port_no = 0;
+ port[3].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH3;
+ port[3].ioaddr.altstatus_addr = port[3].ioaddr.ctl_addr =
+ (iobase[5] + VND_TF2_CH3) | ATA_PCI_CTL_OFS;
+ port[3].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH3;
+ break;
+ default:
+ printf ("Tried to scan unknown port: ata%d\n", dev);
+ return 1;
+ }
+
+ /* Initialize other registers */
+ sata_port (&port[dev].ioaddr);
+
+ /* Check for attached device */
+ if (!sata_bus_probe (dev)) {
+ port[dev].port_state = 0;
+ debug ("SATA#%d port is not present\n", dev);
+ } else {
+ debug ("SATA#%d port is present\n", dev);
+ if (sata_bus_softreset (dev)) {
+ /* soft reset failed, try a hard one */
+ sata_phy_reset (dev);
+ if (sata_bus_softreset (dev)) {
+ port[dev].port_state = 0;
+ } else {
+ port[dev].port_state = 1;
+ }
+ } else {
+ port[dev].port_state = 1;
+ }
+ }
+ if (port[dev].port_state == 1) {
+ /* Probe device and set xfer mode */
+ sata_identify (dev, 0);
+ set_Feature_cmd (dev, 0);
+ }
+
+ return 0;
+}
diff --git a/u-boot/drivers/block/sata_sil3114.h b/u-boot/drivers/block/sata_sil3114.h
new file mode 100644
index 0000000..8f2301a
--- /dev/null
+++ b/u-boot/drivers/block/sata_sil3114.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) Excito Elektronik i Skåne AB, All rights reserved.
+ * Author: Tor Krill <tor@excito.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 SATA_SIL3114_H
+#define SATA_SIL3114_H
+
+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;
+};
+
+/* Missing ata defines */
+#define ATA_CMD_STANDBY 0xE2
+#define ATA_CMD_STANDBYNOW1 0xE0
+#define ATA_CMD_IDLE 0xE3
+#define ATA_CMD_IDLEIMMEDIATE 0xE1
+
+/* Defines for SIL3114 chip */
+
+/* PCI defines */
+#define SIL_VEND_ID 0x1095
+#define SIL3114_DEVICE_ID 0x3114
+
+/* some vendor specific registers */
+#define VND_SYSCONFSTAT 0x88 /* System Configuration Status and Command */
+#define VND_SYSCONFSTAT_CHN_0_INTBLOCK (1<<22)
+#define VND_SYSCONFSTAT_CHN_1_INTBLOCK (1<<23)
+#define VND_SYSCONFSTAT_CHN_2_INTBLOCK (1<<24)
+#define VND_SYSCONFSTAT_CHN_3_INTBLOCK (1<<25)
+
+/* internal registers mapped by BAR5 */
+/* SATA Control*/
+#define VND_SCONTROL_CH0 0x100
+#define VND_SCONTROL_CH1 0x180
+#define VND_SCONTROL_CH2 0x300
+#define VND_SCONTROL_CH3 0x380
+
+#define SATA_SC_IPM_T2P (1<<16)
+#define SATA_SC_IPM_T2S (2<<16)
+#define SATA_SC_SPD_1_5 (1<<4)
+#define SATA_SC_SPD_3_0 (2<<4)
+#define SATA_SC_DET_RST (1) /* ATA Reset sequence */
+#define SATA_SC_DET_PDIS (4) /* PHY Disable */
+
+/* SATA Status */
+#define VND_SSTATUS_CH0 0x104
+#define VND_SSTATUS_CH1 0x184
+#define VND_SSTATUS_CH2 0x304
+#define VND_SSTATUS_CH3 0x384
+
+#define SATA_SS_IPM_ACTIVE (1<<8)
+#define SATA_SS_IPM_PARTIAL (2<<8)
+#define SATA_SS_IPM_SLUMBER (6<<8)
+#define SATA_SS_SPD_1_5 (1<<4)
+#define SATA_SS_SPD_3_0 (2<<4)
+#define SATA_DET_P_NOPHY (1) /* Device presence but no PHY connection established */
+#define SATA_DET_PRES (3) /* Device presence and active PHY */
+#define SATA_DET_OFFLINE (4) /* Device offline or in loopback mode */
+
+/* Task file registers in BAR5 mapping */
+#define VND_TF0_CH0 0x80
+#define VND_TF0_CH1 0xc0
+#define VND_TF0_CH2 0x280
+#define VND_TF0_CH3 0x2c0
+#define VND_TF1_CH0 0x88
+#define VND_TF1_CH1 0xc8
+#define VND_TF1_CH2 0x288
+#define VND_TF1_CH3 0x2c8
+#define VND_TF2_CH0 0x88
+#define VND_TF2_CH1 0xc8
+#define VND_TF2_CH2 0x288
+#define VND_TF2_CH3 0x2c8
+
+#define VND_BMDMA_CH0 0x00
+#define VND_BMDMA_CH1 0x08
+#define VND_BMDMA_CH2 0x200
+#define VND_BMDMA_CH3 0x208
+#define VND_BMDMA2_CH0 0x10
+#define VND_BMDMA2_CH1 0x18
+#define VND_BMDMA2_CH2 0x210
+#define VND_BMDMA2_CH3 0x218
+
+/* FIFO control */
+#define VND_FIFOCFG_CH0 0x40
+#define VND_FIFOCFG_CH1 0x44
+#define VND_FIFOCFG_CH2 0x240
+#define VND_FIFOCFG_CH3 0x244
+
+/* Task File configuration and status */
+#define VND_TF_CNST_CH0 0xa0
+#define VND_TF_CNST_CH1 0xe0
+#define VND_TF_CNST_CH2 0x2a0
+#define VND_TF_CNST_CH3 0x2e0
+
+#define VND_TF_CNST_BFCMD (1<<1)
+#define VND_TF_CNST_CHNRST (1<<2)
+#define VND_TF_CNST_VDMA (1<<10)
+#define VND_TF_CNST_INTST (1<<11)
+#define VND_TF_CNST_WDTO (1<<12)
+#define VND_TF_CNST_WDEN (1<<13)
+#define VND_TF_CNST_WDIEN (1<<14)
+
+/* for testing */
+#define VND_SSDR 0x04c /* System Software Data Register */
+#define VND_FMACS 0x050 /* Flash Memory Address control and status */
+
+#endif
diff --git a/u-boot/drivers/block/sil680.c b/u-boot/drivers/block/sil680.c
new file mode 100644
index 0000000..e21fb9b
--- /dev/null
+++ b/u-boot/drivers/block/sil680.c
@@ -0,0 +1,107 @@
+/*
+ * (C) Copyright 2007
+ * Gary Jennejohn, DENX Software Engineering, garyj@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ *
+ */
+/* sil680.c - ide support functions for the Sil0680A controller */
+
+/*
+ * The following parameters must be defined in the configuration file
+ * of the target board:
+ *
+ * #define CONFIG_IDE_SIL680
+ *
+ * #define CONFIG_PCI_PNP
+ * NOTE it may also be necessary to define this if the default of 8 is
+ * incorrect for the target board (e.g. the sequoia board requires 0).
+ * #define CONFIG_SYS_PCI_CACHE_LINE_SIZE 0
+ *
+ * #define CONFIG_CMD_IDE
+ * #undef CONFIG_IDE_8xx_DIRECT
+ * #undef CONFIG_IDE_LED
+ * #undef CONFIG_IDE_RESET
+ * #define CONFIG_IDE_PREINIT
+ * #define CONFIG_SYS_IDE_MAXBUS 2 - modify to suit
+ * #define CONFIG_SYS_IDE_MAXDEVICE (CONFIG_SYS_IDE_MAXBUS*2) - modify to suit
+ * #define CONFIG_SYS_ATA_BASE_ADDR 0
+ * #define CONFIG_SYS_ATA_IDE0_OFFSET 0
+ * #define CONFIG_SYS_ATA_IDE1_OFFSET 0
+ * #define CONFIG_SYS_ATA_DATA_OFFSET 0
+ * #define CONFIG_SYS_ATA_REG_OFFSET 0
+ * #define CONFIG_SYS_ATA_ALT_OFFSET 0x0004
+ *
+ * The mapping for PCI IO-space.
+ * NOTE this is the value for the sequoia board. Modify to suit.
+ * #define CONFIG_SYS_PCI0_IO_SPACE 0xE8000000
+ */
+
+#include <common.h>
+#include <ata.h>
+#include <ide.h>
+#include <pci.h>
+
+extern ulong ide_bus_offset[CONFIG_SYS_IDE_MAXBUS];
+
+int ide_preinit (void)
+{
+ int status;
+ pci_dev_t devbusfn;
+ int l;
+
+ status = 1;
+ for (l = 0; l < CONFIG_SYS_IDE_MAXBUS; l++) {
+ ide_bus_offset[l] = -ATA_STATUS;
+ }
+ devbusfn = pci_find_device (0x1095, 0x0680, 0);
+ if (devbusfn != -1) {
+ status = 0;
+
+ pci_read_config_dword (devbusfn, PCI_BASE_ADDRESS_0,
+ (u32 *) &ide_bus_offset[0]);
+ ide_bus_offset[0] &= 0xfffffff8;
+ ide_bus_offset[0] += CONFIG_SYS_PCI0_IO_SPACE;
+ pci_read_config_dword (devbusfn, PCI_BASE_ADDRESS_2,
+ (u32 *) &ide_bus_offset[1]);
+ ide_bus_offset[1] &= 0xfffffff8;
+ ide_bus_offset[1] += CONFIG_SYS_PCI0_IO_SPACE;
+ /* init various things - taken from the Linux driver */
+ /* set PIO mode */
+ pci_write_config_byte(devbusfn, 0x80, 0x00);
+ pci_write_config_byte(devbusfn, 0x84, 0x00);
+ /* IDE0 */
+ pci_write_config_byte(devbusfn, 0xA1, 0x02);
+ pci_write_config_word(devbusfn, 0xA2, 0x328A);
+ pci_write_config_dword(devbusfn, 0xA4, 0x62DD62DD);
+ pci_write_config_dword(devbusfn, 0xA8, 0x43924392);
+ pci_write_config_dword(devbusfn, 0xAC, 0x40094009);
+ /* IDE1 */
+ pci_write_config_byte(devbusfn, 0xB1, 0x02);
+ pci_write_config_word(devbusfn, 0xB2, 0x328A);
+ pci_write_config_dword(devbusfn, 0xB4, 0x62DD62DD);
+ pci_write_config_dword(devbusfn, 0xB8, 0x43924392);
+ pci_write_config_dword(devbusfn, 0xBC, 0x40094009);
+ }
+ return (status);
+}
+
+void ide_set_reset (int flag) {
+ return;
+}
diff --git a/u-boot/drivers/block/sym53c8xx.c b/u-boot/drivers/block/sym53c8xx.c
new file mode 100644
index 0000000..8094b41
--- /dev/null
+++ b/u-boot/drivers/block/sym53c8xx.c
@@ -0,0 +1,870 @@
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland, d.peter@mpl.ch.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ * partly derived from
+ * linux/drivers/scsi/sym53c8xx.c
+ *
+ */
+
+/*
+ * SCSI support based on the chip sym53C810.
+ *
+ * 09-19-2001 Andreas Heppel, Sysgo RTS GmbH <aheppel@sysgo.de>
+ * The local version of this driver for the BAB750 board does not
+ * use interrupts but polls the chip instead (see the call of
+ * 'handle_scsi_int()' in 'scsi_issue()'.
+ */
+
+#include <common.h>
+
+#include <command.h>
+#include <pci.h>
+#include <asm/processor.h>
+#include <sym53c8xx.h>
+#include <scsi.h>
+
+#undef SYM53C8XX_DEBUG
+
+#ifdef SYM53C8XX_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+#if defined(CONFIG_CMD_SCSI) && defined(CONFIG_SCSI_SYM53C8XX)
+
+#undef SCSI_SINGLE_STEP
+/*
+ * Single Step is only used for debug purposes
+ */
+#ifdef SCSI_SINGLE_STEP
+static unsigned long start_script_select;
+static unsigned long start_script_msgout;
+static unsigned long start_script_msgin;
+static unsigned long start_script_msg_ext;
+static unsigned long start_script_cmd;
+static unsigned long start_script_data_in;
+static unsigned long start_script_data_out;
+static unsigned long start_script_status;
+static unsigned long start_script_complete;
+static unsigned long start_script_error;
+static unsigned long start_script_reselection;
+static unsigned int len_script_select;
+static unsigned int len_script_msgout;
+static unsigned int len_script_msgin;
+static unsigned int len_script_msg_ext;
+static unsigned int len_script_cmd;
+static unsigned int len_script_data_in;
+static unsigned int len_script_data_out;
+static unsigned int len_script_status;
+static unsigned int len_script_complete;
+static unsigned int len_script_error;
+static unsigned int len_script_reselection;
+#endif
+
+
+static unsigned short scsi_int_mask; /* shadow register for SCSI related interrupts */
+static unsigned char script_int_mask; /* shadow register for SCRIPT related interrupts */
+static unsigned long script_select[8]; /* script for selection */
+static unsigned long script_msgout[8]; /* script for message out phase (NOT USED) */
+static unsigned long script_msgin[14]; /* script for message in phase */
+static unsigned long script_msg_ext[32]; /* script for message in phase when more than 1 byte message */
+static unsigned long script_cmd[18]; /* script for command phase */
+static unsigned long script_data_in[8]; /* script for data in phase */
+static unsigned long script_data_out[8]; /* script for data out phase */
+static unsigned long script_status[6]; /* script for status phase */
+static unsigned long script_complete[10]; /* script for complete */
+static unsigned long script_reselection[4]; /* script for reselection (NOT USED) */
+static unsigned long script_error[2]; /* script for error handling */
+
+static unsigned long int_stat[3]; /* interrupt status */
+static unsigned long scsi_mem_addr; /* base memory address =SCSI_MEM_ADDRESS; */
+
+#define bus_to_phys(a) pci_mem_to_phys(busdevfunc, (unsigned long) (a))
+#define phys_to_bus(a) pci_phys_to_mem(busdevfunc, (unsigned long) (a))
+
+#define SCSI_MAX_RETRY 3 /* number of retries in scsi_issue() */
+
+#define SCSI_MAX_RETRY_NOT_READY 10 /* number of retries when device is not ready */
+#define SCSI_NOT_READY_TIME_OUT 500 /* timeout per retry when not ready */
+
+/*********************************************************************************
+ * forward declerations
+ */
+
+void scsi_chip_init(void);
+void handle_scsi_int(void);
+
+
+/********************************************************************************
+ * reports SCSI errors to the user
+ */
+void scsi_print_error (ccb * pccb)
+{
+ int i;
+
+ printf ("SCSI Error: Target %d LUN %d Command %02X\n", pccb->target,
+ pccb->lun, pccb->cmd[0]);
+ printf (" CCB: ");
+ for (i = 0; i < pccb->cmdlen; i++)
+ printf ("%02X ", pccb->cmd[i]);
+ printf ("(len=%d)\n", pccb->cmdlen);
+ printf (" Cntrl: ");
+ switch (pccb->contr_stat) {
+ case SIR_COMPLETE:
+ printf ("Complete (no Error)\n");
+ break;
+ case SIR_SEL_ATN_NO_MSG_OUT:
+ printf ("Selected with ATN no MSG out phase\n");
+ break;
+ case SIR_CMD_OUT_ILL_PH:
+ printf ("Command out illegal phase\n");
+ break;
+ case SIR_MSG_RECEIVED:
+ printf ("MSG received Error\n");
+ break;
+ case SIR_DATA_IN_ERR:
+ printf ("Data in Error\n");
+ break;
+ case SIR_DATA_OUT_ERR:
+ printf ("Data out Error\n");
+ break;
+ case SIR_SCRIPT_ERROR:
+ printf ("Script Error\n");
+ break;
+ case SIR_MSG_OUT_NO_CMD:
+ printf ("MSG out no Command phase\n");
+ break;
+ case SIR_MSG_OVER7:
+ printf ("MSG in over 7 bytes\n");
+ break;
+ case INT_ON_FY:
+ printf ("Interrupt on fly\n");
+ break;
+ case SCSI_SEL_TIME_OUT:
+ printf ("SCSI Selection Timeout\n");
+ break;
+ case SCSI_HNS_TIME_OUT:
+ printf ("SCSI Handshake Timeout\n");
+ break;
+ case SCSI_MA_TIME_OUT:
+ printf ("SCSI Phase Error\n");
+ break;
+ case SCSI_UNEXP_DIS:
+ printf ("SCSI unexpected disconnect\n");
+ break;
+ default:
+ printf ("unknown status %lx\n", pccb->contr_stat);
+ break;
+ }
+ printf (" Sense: SK %x (", pccb->sense_buf[2] & 0x0f);
+ switch (pccb->sense_buf[2] & 0xf) {
+ case SENSE_NO_SENSE:
+ printf ("No Sense)");
+ break;
+ case SENSE_RECOVERED_ERROR:
+ printf ("Recovered Error)");
+ break;
+ case SENSE_NOT_READY:
+ printf ("Not Ready)");
+ break;
+ case SENSE_MEDIUM_ERROR:
+ printf ("Medium Error)");
+ break;
+ case SENSE_HARDWARE_ERROR:
+ printf ("Hardware Error)");
+ break;
+ case SENSE_ILLEGAL_REQUEST:
+ printf ("Illegal request)");
+ break;
+ case SENSE_UNIT_ATTENTION:
+ printf ("Unit Attention)");
+ break;
+ case SENSE_DATA_PROTECT:
+ printf ("Data Protect)");
+ break;
+ case SENSE_BLANK_CHECK:
+ printf ("Blank check)");
+ break;
+ case SENSE_VENDOR_SPECIFIC:
+ printf ("Vendor specific)");
+ break;
+ case SENSE_COPY_ABORTED:
+ printf ("Copy aborted)");
+ break;
+ case SENSE_ABORTED_COMMAND:
+ printf ("Aborted Command)");
+ break;
+ case SENSE_VOLUME_OVERFLOW:
+ printf ("Volume overflow)");
+ break;
+ case SENSE_MISCOMPARE:
+ printf ("Misscompare\n");
+ break;
+ default:
+ printf ("Illegal Sensecode\n");
+ break;
+ }
+ printf (" ASC %x ASCQ %x\n", pccb->sense_buf[12],
+ pccb->sense_buf[13]);
+ printf (" Status: ");
+ switch (pccb->status) {
+ case S_GOOD:
+ printf ("Good\n");
+ break;
+ case S_CHECK_COND:
+ printf ("Check condition\n");
+ break;
+ case S_COND_MET:
+ printf ("Condition Met\n");
+ break;
+ case S_BUSY:
+ printf ("Busy\n");
+ break;
+ case S_INT:
+ printf ("Intermediate\n");
+ break;
+ case S_INT_COND_MET:
+ printf ("Intermediate condition met\n");
+ break;
+ case S_CONFLICT:
+ printf ("Reservation conflict\n");
+ break;
+ case S_TERMINATED:
+ printf ("Command terminated\n");
+ break;
+ case S_QUEUE_FULL:
+ printf ("Task set full\n");
+ break;
+ default:
+ printf ("unknown: %02X\n", pccb->status);
+ break;
+ }
+
+}
+
+
+/******************************************************************************
+ * sets-up the SCSI controller
+ * the base memory address is retrived via the pci_read_config_dword
+ */
+void scsi_low_level_init(int busdevfunc)
+{
+ unsigned int cmd;
+ unsigned int addr;
+ unsigned char vec;
+
+ pci_read_config_byte(busdevfunc, PCI_INTERRUPT_LINE, &vec);
+ pci_read_config_dword(busdevfunc, PCI_BASE_ADDRESS_1, &addr);
+
+ addr = bus_to_phys(addr & ~0xf);
+
+ /*
+ * Enable bus mastering in case this has not been done, yet.
+ */
+ pci_read_config_dword(busdevfunc, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MASTER;
+ pci_write_config_dword(busdevfunc, PCI_COMMAND, cmd);
+
+ scsi_mem_addr = addr;
+
+ scsi_chip_init();
+ scsi_bus_reset();
+}
+
+
+/************************************************************************************
+ * Low level Part of SCSI Driver
+ */
+
+/*
+ * big-endian -> little endian conversion for the script
+ */
+unsigned long swap_script(unsigned long val)
+{
+ unsigned long tmp;
+ tmp = ((val>>24)&0xff) | ((val>>8)&0xff00) | ((val<<8)&0xff0000) | ((val<<24)&0xff000000);
+ return tmp;
+}
+
+
+void scsi_write_byte(ulong offset,unsigned char val)
+{
+ out8(scsi_mem_addr+offset,val);
+}
+
+
+unsigned char scsi_read_byte(ulong offset)
+{
+ return(in8(scsi_mem_addr+offset));
+}
+
+
+/********************************************************************************
+ * interrupt handler
+ */
+void handle_scsi_int(void)
+{
+ unsigned char stat,stat1,stat2;
+ unsigned short sstat;
+ int i;
+#ifdef SCSI_SINGLE_STEP
+ unsigned long tt;
+#endif
+ stat=scsi_read_byte(ISTAT);
+ if((stat & DIP)==DIP) { /* DMA Interrupt pending */
+ stat1=scsi_read_byte(DSTAT);
+#ifdef SCSI_SINGLE_STEP
+ if((stat1 & SSI)==SSI) {
+ tt=in32r(scsi_mem_addr+DSP);
+ if(((tt)>=start_script_select) && ((tt)<start_script_select+len_script_select)) {
+ printf("select %d\n",(tt-start_script_select)>>2);
+ goto end_single;
+ }
+ if(((tt)>=start_script_msgout) && ((tt)<start_script_msgout+len_script_msgout)) {
+ printf("msgout %d\n",(tt-start_script_msgout)>>2);
+ goto end_single;
+ }
+ if(((tt)>=start_script_msgin) && ((tt)<start_script_msgin+len_script_msgin)) {
+ printf("msgin %d\n",(tt-start_script_msgin)>>2);
+ goto end_single;
+ }
+ if(((tt)>=start_script_msg_ext) && ((tt)<start_script_msg_ext+len_script_msg_ext)) {
+ printf("msgin_ext %d\n",(tt-start_script_msg_ext)>>2);
+ goto end_single;
+ }
+ if(((tt)>=start_script_cmd) && ((tt)<start_script_cmd+len_script_cmd)) {
+ printf("cmd %d\n",(tt-start_script_cmd)>>2);
+ goto end_single;
+ }
+ if(((tt)>=start_script_data_in) && ((tt)<start_script_data_in+len_script_data_in)) {
+ printf("data_in %d\n",(tt-start_script_data_in)>>2);
+ goto end_single;
+ }
+ if(((tt)>=start_script_data_out) && ((tt)<start_script_data_out+len_script_data_out)) {
+ printf("data_out %d\n",(tt-start_script_data_out)>>2);
+ goto end_single;
+ }
+ if(((tt)>=start_script_status) && ((tt)<start_script_status+len_script_status)) {
+ printf("status %d\n",(tt-start_script_status)>>2);
+ goto end_single;
+ }
+ if(((tt)>=start_script_complete) && ((tt)<start_script_complete+len_script_complete)) {
+ printf("complete %d\n",(tt-start_script_complete)>>2);
+ goto end_single;
+ }
+ if(((tt)>=start_script_error) && ((tt)<start_script_error+len_script_error)) {
+ printf("error %d\n",(tt-start_script_error)>>2);
+ goto end_single;
+ }
+ if(((tt)>=start_script_reselection) && ((tt)<start_script_reselection+len_script_reselection)) {
+ printf("reselection %d\n",(tt-start_script_reselection)>>2);
+ goto end_single;
+ }
+ printf("sc: %lx\n",tt);
+end_single:
+ stat2=scsi_read_byte(DCNTL);
+ stat2|=STD;
+ scsi_write_byte(DCNTL,stat2);
+ }
+#endif
+ if((stat1 & SIR)==SIR) /* script interrupt */
+ {
+ int_stat[0]=in32(scsi_mem_addr+DSPS);
+ }
+ if((stat1 & DFE)==0) { /* fifo not epmty */
+ scsi_write_byte(CTEST3,CLF); /* Clear DMA FIFO */
+ stat2=scsi_read_byte(STEST3);
+ scsi_write_byte(STEST3,(stat2 | CSF)); /* Clear SCSI FIFO */
+ }
+ }
+ if((stat & SIP)==SIP) { /* scsi interrupt */
+ sstat = (unsigned short)scsi_read_byte(SIST+1);
+ sstat <<=8;
+ sstat |= (unsigned short)scsi_read_byte(SIST);
+ for(i=0;i<3;i++) {
+ if(int_stat[i]==0)
+ break; /* found an empty int status */
+ }
+ int_stat[i]=SCSI_INT_STATE | sstat;
+ stat1=scsi_read_byte(DSTAT);
+ if((stat1 & DFE)==0) { /* fifo not epmty */
+ scsi_write_byte(CTEST3,CLF); /* Clear DMA FIFO */
+ stat2=scsi_read_byte(STEST3);
+ scsi_write_byte(STEST3,(stat2 | CSF)); /* Clear SCSI FIFO */
+ }
+ }
+ if((stat & INTF)==INTF) { /* interrupt on Fly */
+ scsi_write_byte(ISTAT,stat); /* clear it */
+ for(i=0;i<3;i++) {
+ if(int_stat[i]==0)
+ break; /* found an empty int status */
+ }
+ int_stat[i]=INT_ON_FY;
+ }
+}
+
+void scsi_bus_reset(void)
+{
+ unsigned char t;
+ int i;
+ int end = CONFIG_SYS_SCSI_SPIN_UP_TIME*1000;
+
+ t=scsi_read_byte(SCNTL1);
+ scsi_write_byte(SCNTL1,(t | CRST));
+ udelay(50);
+ scsi_write_byte(SCNTL1,t);
+
+ puts("waiting for devices to spin up");
+ for(i=0;i<end;i++) {
+ udelay(1000); /* give the devices time to spin up */
+ if (i % 1000 == 0)
+ putc('.');
+ }
+ putc('\n');
+ scsi_chip_init(); /* reinit the chip ...*/
+
+}
+
+void scsi_int_enable(void)
+{
+ scsi_write_byte(SIEN,(unsigned char)scsi_int_mask);
+ scsi_write_byte(SIEN+1,(unsigned char)(scsi_int_mask>>8));
+ scsi_write_byte(DIEN,script_int_mask);
+}
+
+void scsi_write_dsp(unsigned long start)
+{
+ unsigned long val;
+#ifdef SCSI_SINGLE_STEP
+ unsigned char t;
+#endif
+ val = start;
+ out32r(scsi_mem_addr + DSP,start);
+#ifdef SCSI_SINGLE_STEP
+ t=scsi_read_byte(DCNTL);
+ t|=STD;
+ scsi_write_byte(DCNTL,t);
+#endif
+}
+
+/* only used for debug purposes */
+void scsi_print_script(void)
+{
+ printf("script_select @ 0x%08lX\n",(unsigned long)&script_select[0]);
+ printf("script_msgout @ 0x%08lX\n",(unsigned long)&script_msgout[0]);
+ printf("script_msgin @ 0x%08lX\n",(unsigned long)&script_msgin[0]);
+ printf("script_msgext @ 0x%08lX\n",(unsigned long)&script_msg_ext[0]);
+ printf("script_cmd @ 0x%08lX\n",(unsigned long)&script_cmd[0]);
+ printf("script_data_in @ 0x%08lX\n",(unsigned long)&script_data_in[0]);
+ printf("script_data_out @ 0x%08lX\n",(unsigned long)&script_data_out[0]);
+ printf("script_status @ 0x%08lX\n",(unsigned long)&script_status[0]);
+ printf("script_complete @ 0x%08lX\n",(unsigned long)&script_complete[0]);
+ printf("script_error @ 0x%08lX\n",(unsigned long)&script_error[0]);
+}
+
+
+void scsi_set_script(ccb *pccb)
+{
+ int busdevfunc = pccb->priv;
+ int i;
+ i=0;
+ script_select[i++]=swap_script(SCR_REG_REG(GPREG, SCR_AND, 0xfe));
+ script_select[i++]=0; /* LED ON */
+ script_select[i++]=swap_script(SCR_CLR(SCR_TRG)); /* select initiator mode */
+ script_select[i++]=0;
+ /* script_select[i++]=swap_script(SCR_SEL_ABS_ATN | pccb->target << 16); */
+ script_select[i++]=swap_script(SCR_SEL_ABS | pccb->target << 16);
+ script_select[i++]=swap_script(phys_to_bus(&script_cmd[4])); /* error handling */
+ script_select[i++]=swap_script(SCR_JUMP); /* next section */
+ /* script_select[i++]=swap_script((unsigned long)&script_msgout[0]); */ /* message out */
+ script_select[i++]=swap_script(phys_to_bus(&script_cmd[0])); /* command out */
+
+#ifdef SCSI_SINGLE_STEP
+ start_script_select=(unsigned long)&script_select[0];
+ len_script_select=i*4;
+#endif
+
+ i=0;
+ script_msgout[i++]=swap_script(SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)));
+ script_msgout[i++]=SIR_SEL_ATN_NO_MSG_OUT;
+ script_msgout[i++]=swap_script( SCR_MOVE_ABS(1) ^ SCR_MSG_OUT);
+ script_msgout[i++]=swap_script(phys_to_bus(&pccb->msgout[0]));
+ script_msgout[i++]=swap_script(SCR_JUMP ^ IFTRUE (WHEN (SCR_COMMAND))); /* if Command phase */
+ script_msgout[i++]=swap_script(phys_to_bus(&script_cmd[0])); /* switch to command */
+ script_msgout[i++]=swap_script(SCR_INT); /* interrupt if not */
+ script_msgout[i++]=SIR_MSG_OUT_NO_CMD;
+
+#ifdef SCSI_SINGLE_STEP
+ start_script_msgout=(unsigned long)&script_msgout[0];
+ len_script_msgout=i*4;
+#endif
+ i=0;
+ script_cmd[i++]=swap_script(SCR_MOVE_ABS(pccb->cmdlen) ^ SCR_COMMAND);
+ script_cmd[i++]=swap_script(phys_to_bus(&pccb->cmd[0]));
+ script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN))); /* message in ? */
+ script_cmd[i++]=swap_script(phys_to_bus(&script_msgin[0]));
+ script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (IF (SCR_DATA_OUT))); /* data out ? */
+ script_cmd[i++]=swap_script(phys_to_bus(&script_data_out[0]));
+ script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (IF (SCR_DATA_IN))); /* data in ? */
+ script_cmd[i++]=swap_script(phys_to_bus(&script_data_in[0]));
+ script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (IF (SCR_STATUS))); /* status ? */
+ script_cmd[i++]=swap_script(phys_to_bus(&script_status[0]));
+ script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND))); /* command ? */
+ script_cmd[i++]=swap_script(phys_to_bus(&script_cmd[0]));
+ script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT))); /* message out ? */
+ script_cmd[i++]=swap_script(phys_to_bus(&script_msgout[0]));
+ script_cmd[i++]=swap_script(SCR_JUMP ^ IFTRUE (IF (SCR_MSG_IN))); /* just for error handling message in ? */
+ script_cmd[i++]=swap_script(phys_to_bus(&script_msgin[0]));
+ script_cmd[i++]=swap_script(SCR_INT); /* interrupt if not */
+ script_cmd[i++]=SIR_CMD_OUT_ILL_PH;
+#ifdef SCSI_SINGLE_STEP
+ start_script_cmd=(unsigned long)&script_cmd[0];
+ len_script_cmd=i*4;
+#endif
+ i=0;
+ script_data_out[i++]=swap_script(SCR_MOVE_ABS(pccb->datalen)^ SCR_DATA_OUT); /* move */
+ script_data_out[i++]=swap_script(phys_to_bus(pccb->pdata)); /* pointer to buffer */
+ script_data_out[i++]=swap_script(SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)));
+ script_data_out[i++]=swap_script(phys_to_bus(&script_status[0]));
+ script_data_out[i++]=swap_script(SCR_INT);
+ script_data_out[i++]=SIR_DATA_OUT_ERR;
+
+#ifdef SCSI_SINGLE_STEP
+ start_script_data_out=(unsigned long)&script_data_out[0];
+ len_script_data_out=i*4;
+#endif
+ i=0;
+ script_data_in[i++]=swap_script(SCR_MOVE_ABS(pccb->datalen)^ SCR_DATA_IN); /* move */
+ script_data_in[i++]=swap_script(phys_to_bus(pccb->pdata)); /* pointer to buffer */
+ script_data_in[i++]=swap_script(SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)));
+ script_data_in[i++]=swap_script(phys_to_bus(&script_status[0]));
+ script_data_in[i++]=swap_script(SCR_INT);
+ script_data_in[i++]=SIR_DATA_IN_ERR;
+#ifdef SCSI_SINGLE_STEP
+ start_script_data_in=(unsigned long)&script_data_in[0];
+ len_script_data_in=i*4;
+#endif
+ i=0;
+ script_msgin[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN);
+ script_msgin[i++]=swap_script(phys_to_bus(&pccb->msgin[0]));
+ script_msgin[i++]=swap_script(SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)));
+ script_msgin[i++]=swap_script(phys_to_bus(&script_complete[0]));
+ script_msgin[i++]=swap_script(SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)));
+ script_msgin[i++]=swap_script(phys_to_bus(&script_complete[0]));
+ script_msgin[i++]=swap_script(SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)));
+ script_msgin[i++]=swap_script(phys_to_bus(&script_complete[0]));
+ script_msgin[i++]=swap_script(SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)));
+ script_msgin[i++]=swap_script(phys_to_bus(&script_complete[0]));
+ script_msgin[i++]=swap_script(SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)));
+ script_msgin[i++]=swap_script(phys_to_bus(&script_msg_ext[0]));
+ script_msgin[i++]=swap_script(SCR_INT);
+ script_msgin[i++]=SIR_MSG_RECEIVED;
+#ifdef SCSI_SINGLE_STEP
+ start_script_msgin=(unsigned long)&script_msgin[0];
+ len_script_msgin=i*4;
+#endif
+ i=0;
+ script_msg_ext[i++]=swap_script(SCR_CLR (SCR_ACK)); /* clear ACK */
+ script_msg_ext[i++]=0;
+ script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* assuming this is the msg length */
+ script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[1]));
+ script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN)));
+ script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */
+ script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* next */
+ script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[2]));
+ script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN)));
+ script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */
+ script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* next */
+ script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[3]));
+ script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN)));
+ script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */
+ script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* next */
+ script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[4]));
+ script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN)));
+ script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */
+ script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* next */
+ script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[5]));
+ script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN)));
+ script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */
+ script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* next */
+ script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[6]));
+ script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN)));
+ script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */
+ script_msg_ext[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_MSG_IN); /* next */
+ script_msg_ext[i++]=swap_script(phys_to_bus(&pccb->msgin[7]));
+ script_msg_ext[i++]=swap_script(SCR_JUMP ^ IFFALSE (IF (SCR_MSG_IN)));
+ script_msg_ext[i++]=swap_script(phys_to_bus(&script_complete[0])); /* no more bytes */
+ script_msg_ext[i++]=swap_script(SCR_INT);
+ script_msg_ext[i++]=SIR_MSG_OVER7;
+#ifdef SCSI_SINGLE_STEP
+ start_script_msg_ext=(unsigned long)&script_msg_ext[0];
+ len_script_msg_ext=i*4;
+#endif
+ i=0;
+ script_status[i++]=swap_script(SCR_MOVE_ABS (1) ^ SCR_STATUS);
+ script_status[i++]=swap_script(phys_to_bus(&pccb->status));
+ script_status[i++]=swap_script(SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)));
+ script_status[i++]=swap_script(phys_to_bus(&script_msgin[0]));
+ script_status[i++]=swap_script(SCR_INT);
+ script_status[i++]=SIR_STATUS_ILL_PH;
+#ifdef SCSI_SINGLE_STEP
+ start_script_status=(unsigned long)&script_status[0];
+ len_script_status=i*4;
+#endif
+ i=0;
+ script_complete[i++]=swap_script(SCR_REG_REG (SCNTL2, SCR_AND, 0x7f));
+ script_complete[i++]=0;
+ script_complete[i++]=swap_script(SCR_CLR (SCR_ACK|SCR_ATN));
+ script_complete[i++]=0;
+ script_complete[i++]=swap_script(SCR_WAIT_DISC);
+ script_complete[i++]=0;
+ script_complete[i++]=swap_script(SCR_REG_REG(GPREG, SCR_OR, 0x01));
+ script_complete[i++]=0; /* LED OFF */
+ script_complete[i++]=swap_script(SCR_INT);
+ script_complete[i++]=SIR_COMPLETE;
+#ifdef SCSI_SINGLE_STEP
+ start_script_complete=(unsigned long)&script_complete[0];
+ len_script_complete=i*4;
+#endif
+ i=0;
+ script_error[i++]=swap_script(SCR_INT); /* interrupt if error */
+ script_error[i++]=SIR_SCRIPT_ERROR;
+#ifdef SCSI_SINGLE_STEP
+ start_script_error=(unsigned long)&script_error[0];
+ len_script_error=i*4;
+#endif
+ i=0;
+ script_reselection[i++]=swap_script(SCR_CLR (SCR_TRG)); /* target status */
+ script_reselection[i++]=0;
+ script_reselection[i++]=swap_script(SCR_WAIT_RESEL);
+ script_reselection[i++]=swap_script(phys_to_bus(&script_select[0])); /* len = 4 */
+#ifdef SCSI_SINGLE_STEP
+ start_script_reselection=(unsigned long)&script_reselection[0];
+ len_script_reselection=i*4;
+#endif
+}
+
+
+void scsi_issue(ccb *pccb)
+{
+ int busdevfunc = pccb->priv;
+ int i;
+ unsigned short sstat;
+ int retrycnt; /* retry counter */
+ for(i=0;i<3;i++)
+ int_stat[i]=0; /* delete all int status */
+ /* struct pccb must be set-up correctly */
+ retrycnt=0;
+ PRINTF("ID %d issue cmd %02X\n",pccb->target,pccb->cmd[0]);
+ pccb->trans_bytes=0; /* no bytes transfered yet */
+ scsi_set_script(pccb); /* fill in SCRIPT */
+ scsi_int_mask=STO | UDC | MA; /* | CMP; / * Interrupts which are enabled */
+ script_int_mask=0xff; /* enable all Ints */
+ scsi_int_enable();
+ scsi_write_dsp(phys_to_bus(&script_select[0])); /* start script */
+ /* now we have to wait for IRQs */
+retry:
+ /*
+ * This version of the driver is _not_ interrupt driven,
+ * but polls the chip's interrupt registers (ISTAT, DSTAT).
+ */
+ while(int_stat[0]==0)
+ handle_scsi_int();
+
+ if(int_stat[0]==SIR_COMPLETE) {
+ if(pccb->msgin[0]==M_DISCONNECT) {
+ PRINTF("Wait for reselection\n");
+ for(i=0;i<3;i++)
+ int_stat[i]=0; /* delete all int status */
+ scsi_write_dsp(phys_to_bus(&script_reselection[0])); /* start reselection script */
+ goto retry;
+ }
+ pccb->contr_stat=SIR_COMPLETE;
+ return;
+ }
+ if((int_stat[0] & SCSI_INT_STATE)==SCSI_INT_STATE) { /* scsi interrupt */
+ sstat=(unsigned short)int_stat[0];
+ if((sstat & STO)==STO) { /* selection timeout */
+ pccb->contr_stat=SCSI_SEL_TIME_OUT;
+ scsi_write_byte(GPREG,0x01);
+ PRINTF("ID: %X Selection Timeout\n",pccb->target);
+ return;
+ }
+ if((sstat & UDC)==UDC) { /* unexpected disconnect */
+ pccb->contr_stat=SCSI_UNEXP_DIS;
+ scsi_write_byte(GPREG,0x01);
+ PRINTF("ID: %X Unexpected Disconnect\n",pccb->target);
+ return;
+ }
+ if((sstat & RSL)==RSL) { /* reselection */
+ pccb->contr_stat=SCSI_UNEXP_DIS;
+ scsi_write_byte(GPREG,0x01);
+ PRINTF("ID: %X Unexpected Disconnect\n",pccb->target);
+ return;
+ }
+ if(((sstat & MA)==MA)||((sstat & HTH)==HTH)) { /* phase missmatch */
+ if(retrycnt<SCSI_MAX_RETRY) {
+ pccb->trans_bytes=pccb->datalen -
+ ((unsigned long)scsi_read_byte(DBC) |
+ ((unsigned long)scsi_read_byte(DBC+1)<<8) |
+ ((unsigned long)scsi_read_byte(DBC+2)<<16));
+ for(i=0;i<3;i++)
+ int_stat[i]=0; /* delete all int status */
+ retrycnt++;
+ PRINTF("ID: %X Phase Missmatch Retry %d Phase %02X transfered %lx\n",
+ pccb->target,retrycnt,scsi_read_byte(SBCL),pccb->trans_bytes);
+ scsi_write_dsp(phys_to_bus(&script_cmd[4])); /* start retry script */
+ goto retry;
+ }
+ if((sstat & MA)==MA)
+ pccb->contr_stat=SCSI_MA_TIME_OUT;
+ else
+ pccb->contr_stat=SCSI_HNS_TIME_OUT;
+ PRINTF("Phase Missmatch stat %lx\n",pccb->contr_stat);
+ return;
+ } /* no phase int */
+/* if((sstat & CMP)==CMP) {
+ pccb->contr_stat=SIR_COMPLETE;
+ return;
+ }
+*/
+ PRINTF("SCSI INT %lX\n",int_stat[0]);
+ pccb->contr_stat=int_stat[0];
+ return;
+ } /* end scsi int */
+ PRINTF("SCRIPT INT %lX phase %02X\n",int_stat[0],scsi_read_byte(SBCL));
+ pccb->contr_stat=int_stat[0];
+ return;
+}
+
+int scsi_exec(ccb *pccb)
+{
+ unsigned char tmpcmd[16],tmpstat;
+ int i,retrycnt,t;
+ unsigned long transbytes,datalen;
+ unsigned char *tmpptr;
+ retrycnt=0;
+retry:
+ scsi_issue(pccb);
+ if(pccb->contr_stat!=SIR_COMPLETE)
+ return FALSE;
+ if(pccb->status==S_GOOD)
+ return TRUE;
+ if(pccb->status==S_CHECK_COND) { /* check condition */
+ for(i=0;i<16;i++)
+ tmpcmd[i]=pccb->cmd[i];
+ pccb->cmd[0]=SCSI_REQ_SENSE;
+ pccb->cmd[1]=pccb->lun<<5;
+ pccb->cmd[2]=0;
+ pccb->cmd[3]=0;
+ pccb->cmd[4]=14;
+ pccb->cmd[5]=0;
+ pccb->cmdlen=6;
+ pccb->msgout[0]=SCSI_IDENTIFY;
+ transbytes=pccb->trans_bytes;
+ tmpptr=pccb->pdata;
+ pccb->pdata = &pccb->sense_buf[0];
+ datalen=pccb->datalen;
+ pccb->datalen=14;
+ tmpstat=pccb->status;
+ scsi_issue(pccb);
+ for(i=0;i<16;i++)
+ pccb->cmd[i]=tmpcmd[i];
+ pccb->trans_bytes=transbytes;
+ pccb->pdata=tmpptr;
+ pccb->datalen=datalen;
+ pccb->status=tmpstat;
+ PRINTF("Request_sense sense key %x ASC %x ASCQ %x\n",pccb->sense_buf[2]&0x0f,
+ pccb->sense_buf[12],pccb->sense_buf[13]);
+ switch(pccb->sense_buf[2]&0xf) {
+ case SENSE_NO_SENSE:
+ case SENSE_RECOVERED_ERROR:
+ /* seems to be ok */
+ return TRUE;
+ break;
+ case SENSE_NOT_READY:
+ if((pccb->sense_buf[12]!=0x04)||(pccb->sense_buf[13]!=0x01)) {
+ /* if device is not in process of becoming ready */
+ return FALSE;
+ break;
+ } /* else fall through */
+ case SENSE_UNIT_ATTENTION:
+ if(retrycnt<SCSI_MAX_RETRY_NOT_READY) {
+ PRINTF("Target %d not ready, retry %d\n",pccb->target,retrycnt);
+ for(t=0;t<SCSI_NOT_READY_TIME_OUT;t++)
+ udelay(1000); /* 1sec wait */
+ retrycnt++;
+ goto retry;
+ }
+ PRINTF("Target %d not ready, %d retried\n",pccb->target,retrycnt);
+ return FALSE;
+ default:
+ return FALSE;
+ }
+ }
+ PRINTF("Status = %X\n",pccb->status);
+ return FALSE;
+}
+
+
+void scsi_chip_init(void)
+{
+ /* first we issue a soft reset */
+ scsi_write_byte(ISTAT,SRST);
+ udelay(1000);
+ scsi_write_byte(ISTAT,0);
+ /* setup chip */
+ scsi_write_byte(SCNTL0,0xC0); /* full arbitration no start, no message, parity disabled, master */
+ scsi_write_byte(SCNTL1,0x00);
+ scsi_write_byte(SCNTL2,0x00);
+#ifndef CONFIG_SYS_SCSI_SYM53C8XX_CCF /* config value for none 40 MHz clocks */
+ scsi_write_byte(SCNTL3,0x13); /* synchronous clock 40/4=10MHz, asynchronous 40MHz */
+#else
+ scsi_write_byte(SCNTL3,CONFIG_SYS_SCSI_SYM53C8XX_CCF); /* config value for none 40 MHz clocks */
+#endif
+ scsi_write_byte(SCID,0x47); /* ID=7, enable reselection */
+ scsi_write_byte(SXFER,0x00); /* synchronous transfer period 10MHz, asynchronous */
+ scsi_write_byte(SDID,0x00); /* targed SCSI ID = 0 */
+ scsi_int_mask=0x0000; /* no Interrupt is enabled */
+ script_int_mask=0x00;
+ scsi_int_enable();
+ scsi_write_byte(GPREG,0x01); /* GPIO0 is LED (off) */
+ scsi_write_byte(GPCNTL,0x0E); /* GPIO0 is Output */
+ scsi_write_byte(STIME0,0x08); /* handshake timer disabled, selection timeout 512msec */
+ scsi_write_byte(RESPID,0x80); /* repond only to the own ID (reselection) */
+ scsi_write_byte(STEST1,0x00); /* not isolated, SCLK is used */
+ scsi_write_byte(STEST2,0x00); /* no Lowlevel Mode? */
+ scsi_write_byte(STEST3,0x80); /* enable tolerANT */
+ scsi_write_byte(CTEST3,0x04); /* clear FIFO */
+ scsi_write_byte(CTEST4,0x00);
+ scsi_write_byte(CTEST5,0x00);
+#ifdef SCSI_SINGLE_STEP
+/* scsi_write_byte(DCNTL,IRQM | SSM); */
+ scsi_write_byte(DCNTL,IRQD | SSM);
+ scsi_write_byte(DMODE,MAN);
+#else
+/* scsi_write_byte(DCNTL,IRQM); */
+ scsi_write_byte(DCNTL,IRQD);
+ scsi_write_byte(DMODE,0x00);
+#endif
+}
+#endif
diff --git a/u-boot/drivers/block/systemace.c b/u-boot/drivers/block/systemace.c
new file mode 100644
index 0000000..e8dff0a
--- /dev/null
+++ b/u-boot/drivers/block/systemace.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2004 Picture Elements, Inc.
+ * Stephen Williams (XXXXXXXXXXXXXXXX)
+ *
+ * This source code is free software; you can redistribute it
+ * and/or modify it in source code form 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
+ */
+
+/*
+ * The Xilinx SystemACE chip support is activated by defining
+ * CONFIG_SYSTEMACE to turn on support, and CONFIG_SYS_SYSTEMACE_BASE
+ * to set the base address of the device. This code currently
+ * assumes that the chip is connected via a byte-wide bus.
+ *
+ * The CONFIG_SYSTEMACE also adds to fat support the device class
+ * "ace" that allows the user to execute "fatls ace 0" and the
+ * like. This works by making the systemace_get_dev function
+ * available to cmd_fat.c:get_dev and filling in a block device
+ * description that has all the bits needed for FAT support to
+ * read sectors.
+ *
+ * According to Xilinx technical support, before accessing the
+ * SystemACE CF you need to set the following control bits:
+ * FORCECFGMODE : 1
+ * CFGMODE : 0
+ * CFGSTART : 0
+ */
+
+#include <common.h>
+#include <command.h>
+#include <systemace.h>
+#include <part.h>
+#include <asm/io.h>
+
+/*
+ * The ace_readw and writew functions read/write 16bit words, but the
+ * offset value is the BYTE offset as most used in the Xilinx
+ * datasheet for the SystemACE chip. The CONFIG_SYS_SYSTEMACE_BASE is defined
+ * to be the base address for the chip, usually in the local
+ * peripheral bus.
+ */
+#if (CONFIG_SYS_SYSTEMACE_WIDTH == 8)
+#if !defined(__BIG_ENDIAN)
+#define ace_readw(off) ((readb(CONFIG_SYS_SYSTEMACE_BASE+off)<<8) | \
+ (readb(CONFIG_SYS_SYSTEMACE_BASE+off+1)))
+#define ace_writew(val, off) {writeb(val>>8, CONFIG_SYS_SYSTEMACE_BASE+off); \
+ writeb(val, CONFIG_SYS_SYSTEMACE_BASE+off+1);}
+#else
+#define ace_readw(off) ((readb(CONFIG_SYS_SYSTEMACE_BASE+off)) | \
+ (readb(CONFIG_SYS_SYSTEMACE_BASE+off+1)<<8))
+#define ace_writew(val, off) {writeb(val, CONFIG_SYS_SYSTEMACE_BASE+off); \
+ writeb(val>>8, CONFIG_SYS_SYSTEMACE_BASE+off+1);}
+#endif
+#else
+#define ace_readw(off) (in16(CONFIG_SYS_SYSTEMACE_BASE+off))
+#define ace_writew(val, off) (out16(CONFIG_SYS_SYSTEMACE_BASE+off,val))
+#endif
+
+/* */
+
+static unsigned long systemace_read(int dev, unsigned long start,
+ unsigned long blkcnt, void *buffer);
+
+static block_dev_desc_t systemace_dev = { 0 };
+
+static int get_cf_lock(void)
+{
+ int retry = 10;
+
+ /* CONTROLREG = LOCKREG */
+ unsigned val = ace_readw(0x18);
+ val |= 0x0002;
+ ace_writew((val & 0xffff), 0x18);
+
+ /* Wait for MPULOCK in STATUSREG[15:0] */
+ while (!(ace_readw(0x04) & 0x0002)) {
+
+ if (retry < 0)
+ return -1;
+
+ udelay(100000);
+ retry -= 1;
+ }
+
+ return 0;
+}
+
+static void release_cf_lock(void)
+{
+ unsigned val = ace_readw(0x18);
+ val &= ~(0x0002);
+ ace_writew((val & 0xffff), 0x18);
+}
+
+block_dev_desc_t *systemace_get_dev(int dev)
+{
+ /* The first time through this, the systemace_dev object is
+ not yet initialized. In that case, fill it in. */
+ if (systemace_dev.blksz == 0) {
+ systemace_dev.if_type = IF_TYPE_UNKNOWN;
+ systemace_dev.dev = 0;
+ systemace_dev.part_type = PART_TYPE_UNKNOWN;
+ systemace_dev.type = DEV_TYPE_HARDDISK;
+ systemace_dev.blksz = 512;
+ systemace_dev.removable = 1;
+ systemace_dev.block_read = systemace_read;
+
+ /*
+ * Ensure the correct bus mode (8/16 bits) gets enabled
+ */
+ ace_writew(CONFIG_SYS_SYSTEMACE_WIDTH == 8 ? 0 : 0x0001, 0);
+
+ init_part(&systemace_dev);
+
+ }
+
+ return &systemace_dev;
+}
+
+/*
+ * This function is called (by dereferencing the block_read pointer in
+ * the dev_desc) to read blocks of data. The return value is the
+ * number of blocks read. A zero return indicates an error.
+ */
+static unsigned long systemace_read(int dev, unsigned long start,
+ unsigned long blkcnt, void *buffer)
+{
+ int retry;
+ unsigned blk_countdown;
+ unsigned char *dp = buffer;
+ unsigned val;
+
+ if (get_cf_lock() < 0) {
+ unsigned status = ace_readw(0x04);
+
+ /* If CFDETECT is false, card is missing. */
+ if (!(status & 0x0010)) {
+ printf("** CompactFlash card not present. **\n");
+ return 0;
+ }
+
+ printf("**** ACE locked away from me (STATUSREG=%04x)\n",
+ status);
+ return 0;
+ }
+#ifdef DEBUG_SYSTEMACE
+ printf("... systemace read %lu sectors at %lu\n", blkcnt, start);
+#endif
+
+ retry = 2000;
+ for (;;) {
+ val = ace_readw(0x04);
+
+ /* If CFDETECT is false, card is missing. */
+ if (!(val & 0x0010)) {
+ printf("**** ACE CompactFlash not found.\n");
+ release_cf_lock();
+ return 0;
+ }
+
+ /* If RDYFORCMD, then we are ready to go. */
+ if (val & 0x0100)
+ break;
+
+ if (retry < 0) {
+ printf("**** SystemACE not ready.\n");
+ release_cf_lock();
+ return 0;
+ }
+
+ udelay(1000);
+ retry -= 1;
+ }
+
+ /* The SystemACE can only transfer 256 sectors at a time, so
+ limit the current chunk of sectors. The blk_countdown
+ variable is the number of sectors left to transfer. */
+
+ blk_countdown = blkcnt;
+ while (blk_countdown > 0) {
+ unsigned trans = blk_countdown;
+
+ if (trans > 256)
+ trans = 256;
+
+#ifdef DEBUG_SYSTEMACE
+ printf("... transfer %lu sector in a chunk\n", trans);
+#endif
+ /* Write LBA block address */
+ ace_writew((start >> 0) & 0xffff, 0x10);
+ ace_writew((start >> 16) & 0x0fff, 0x12);
+
+ /* NOTE: in the Write Sector count below, a count of 0
+ causes a transfer of 256, so &0xff gives the right
+ value for whatever transfer count we want. */
+
+ /* Write sector count | ReadMemCardData. */
+ ace_writew((trans & 0xff) | 0x0300, 0x14);
+
+/*
+ * For FPGA configuration via SystemACE is reset unacceptable
+ * CFGDONE bit in STATUSREG is not set to 1.
+ */
+#ifndef SYSTEMACE_CONFIG_FPGA
+ /* Reset the configruation controller */
+ val = ace_readw(0x18);
+ val |= 0x0080;
+ ace_writew(val, 0x18);
+#endif
+
+ retry = trans * 16;
+ while (retry > 0) {
+ int idx;
+
+ /* Wait for buffer to become ready. */
+ while (!(ace_readw(0x04) & 0x0020)) {
+ udelay(100);
+ }
+
+ /* Read 16 words of 2bytes from the sector buffer. */
+ for (idx = 0; idx < 16; idx += 1) {
+ unsigned short val = ace_readw(0x40);
+ *dp++ = val & 0xff;
+ *dp++ = (val >> 8) & 0xff;
+ }
+
+ retry -= 1;
+ }
+
+ /* Clear the configruation controller reset */
+ val = ace_readw(0x18);
+ val &= ~0x0080;
+ ace_writew(val, 0x18);
+
+ /* Count the blocks we transfer this time. */
+ start += trans;
+ blk_countdown -= trans;
+ }
+
+ release_cf_lock();
+
+ return blkcnt;
+}