]> git.sur5r.net Git - u-boot/blobdiff - drivers/ata/ahci.c
sf: Add support for gd25q32b gigadevice flash
[u-boot] / drivers / ata / ahci.c
index 2cc604b3f48246ded00c7cdb7f03fadc74212d32..c35912bd3341f97423d6bde0ab7ed71b95ed592b 100644 (file)
@@ -1,11 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright (C) Freescale Semiconductor, Inc. 2006.
  * Author: Jason Jin<Jason.jin@freescale.com>
  *         Zhang Wei<wei.zhang@freescale.com>
  *
- * SPDX-License-Identifier:    GPL-2.0+
- *
  * with the reference on libata and ahci drvier in kernel
+ *
+ * This driver provides a SCSI interface to SATA.
  */
 #include <common.h>
 
 #include <asm/io.h>
 #include <malloc.h>
 #include <memalign.h>
+#include <pci.h>
 #include <scsi.h>
 #include <libata.h>
 #include <linux/ctype.h>
 #include <ahci.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
 
-static int ata_io_flush(u8 port);
+static int ata_io_flush(struct ahci_uc_priv *uc_priv, u8 port);
 
-struct ahci_probe_ent *probe_ent = NULL;
-u16 *ataid[AHCI_MAX_PORTS];
+#ifndef CONFIG_DM_SCSI
+struct ahci_uc_priv *probe_ent = NULL;
+#endif
 
 #define writel_with_flush(a,b) do { writel(a,b); readl(b); } while (0)
 
@@ -109,11 +114,11 @@ static int waiting_for_cmd_completed(void __iomem *offset,
        return (i < timeout_msec) ? 0 : -1;
 }
 
-int __weak ahci_link_up(struct ahci_probe_ent *probe_ent, u8 port)
+int __weak ahci_link_up(struct ahci_uc_priv *uc_priv, u8 port)
 {
        u32 tmp;
        int j = 0;
-       void __iomem *port_mmio = probe_ent->port[port].port_mmio;
+       void __iomem *port_mmio = uc_priv->port[port].port_mmio;
 
        /*
         * Bring up SATA link.
@@ -166,19 +171,19 @@ int ahci_reset(void __iomem *base)
        return 0;
 }
 
-static int ahci_host_init(struct ahci_probe_ent *probe_ent)
+static int ahci_host_init(struct ahci_uc_priv *uc_priv)
 {
 #if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI)
 # ifdef CONFIG_DM_PCI
-       struct udevice *dev = probe_ent->dev;
+       struct udevice *dev = uc_priv->dev;
        struct pci_child_platdata *pplat = dev_get_parent_platdata(dev);
 # else
-       pci_dev_t pdev = probe_ent->dev;
+       pci_dev_t pdev = uc_priv->dev;
        unsigned short vendor;
 # endif
        u16 tmp16;
 #endif
-       void __iomem *mmio = probe_ent->mmio_base;
+       void __iomem *mmio = uc_priv->mmio_base;
        u32 tmp, cap_save, cmd;
        int i, j, ret;
        void __iomem *port_mmio;
@@ -190,7 +195,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
        cap_save &= ((1 << 28) | (1 << 17));
        cap_save |= (1 << 27);  /* Staggered Spin-up. Not needed. */
 
-       ret = ahci_reset(probe_ent->mmio_base);
+       ret = ahci_reset(uc_priv->mmio_base);
        if (ret)
                return ret;
 
@@ -217,23 +222,23 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
        }
 # endif
 #endif
-       probe_ent->cap = readl(mmio + HOST_CAP);
-       probe_ent->port_map = readl(mmio + HOST_PORTS_IMPL);
-       port_map = probe_ent->port_map;
-       probe_ent->n_ports = (probe_ent->cap & 0x1f) + 1;
+       uc_priv->cap = readl(mmio + HOST_CAP);
+       uc_priv->port_map = readl(mmio + HOST_PORTS_IMPL);
+       port_map = uc_priv->port_map;
+       uc_priv->n_ports = (uc_priv->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);
+             uc_priv->cap, uc_priv->port_map, uc_priv->n_ports);
 
-       if (probe_ent->n_ports > CONFIG_SYS_SCSI_MAX_SCSI_ID)
-               probe_ent->n_ports = CONFIG_SYS_SCSI_MAX_SCSI_ID;
+       if (uc_priv->n_ports > CONFIG_SYS_SCSI_MAX_SCSI_ID)
+               uc_priv->n_ports = CONFIG_SYS_SCSI_MAX_SCSI_ID;
 
-       for (i = 0; i < probe_ent->n_ports; i++) {
+       for (i = 0; i < uc_priv->n_ports; i++) {
                if (!(port_map & (1 << i)))
                        continue;
-               probe_ent->port[i].port_mmio = ahci_port_base(mmio, i);
-               port_mmio = (u8 *) probe_ent->port[i].port_mmio;
-               ahci_setup_port(&probe_ent->port[i], mmio, i);
+               uc_priv->port[i].port_mmio = ahci_port_base(mmio, i);
+               port_mmio = (u8 *)uc_priv->port[i].port_mmio;
+               ahci_setup_port(&uc_priv->port[i], mmio, i);
 
                /* make sure port is not active */
                tmp = readl(port_mmio + PORT_CMD);
@@ -262,7 +267,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
                writel_with_flush(cmd, port_mmio + PORT_CMD);
 
                /* Bring up SATA link. */
-               ret = ahci_link_up(probe_ent, i);
+               ret = ahci_link_up(uc_priv, i);
                if (ret) {
                        printf("SATA link %d timeout.\n", i);
                        continue;
@@ -319,7 +324,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
                tmp = readl(port_mmio + PORT_SCR_STAT);
                debug("SATA port %d status: 0x%x\n", i, tmp);
                if ((tmp & PORT_SCR_STAT_DET_MASK) == PORT_SCR_STAT_DET_PHYRDY)
-                       probe_ent->link_port_map |= (0x01 << i);
+                       uc_priv->link_port_map |= (0x01 << i);
        }
 
        tmp = readl(mmio + HOST_CTL);
@@ -344,25 +349,25 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)
 }
 
 
-static void ahci_print_info(struct ahci_probe_ent *probe_ent)
+static void ahci_print_info(struct ahci_uc_priv *uc_priv)
 {
 #if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI)
 # if defined(CONFIG_DM_PCI)
-       struct udevice *dev = probe_ent->dev;
+       struct udevice *dev = uc_priv->dev;
 # else
-       pci_dev_t pdev = probe_ent->dev;
+       pci_dev_t pdev = uc_priv->dev;
 # endif
        u16 cc;
 #endif
-       void __iomem *mmio = probe_ent->mmio_base;
+       void __iomem *mmio = uc_priv->mmio_base;
        u32 vers, cap, cap2, impl, speed;
        const char *speed_s;
        const char *scc_s;
 
        vers = readl(mmio + HOST_VERSION);
-       cap = probe_ent->cap;
+       cap = uc_priv->cap;
        cap2 = readl(mmio + HOST_CAP2);
-       impl = probe_ent->port_map;
+       impl = uc_priv->port_map;
 
        speed = (cap >> 20) & 0xf;
        if (speed == 1)
@@ -425,11 +430,11 @@ static void ahci_print_info(struct ahci_probe_ent *probe_ent)
               cap2 & (1 << 0) ? "boh " : "");
 }
 
-#ifndef CONFIG_SCSI_AHCI_PLAT
+#if defined(CONFIG_DM_SCSI) || !defined(CONFIG_SCSI_AHCI_PLAT)
 # if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI)
-static int ahci_init_one(struct udevice *dev)
+static int ahci_init_one(struct ahci_uc_priv *uc_priv, struct udevice *dev)
 # else
-static int ahci_init_one(pci_dev_t dev)
+static int ahci_init_one(struct ahci_uc_priv *uc_priv, pci_dev_t dev)
 # endif
 {
 #if !defined(CONFIG_DM_SCSI)
@@ -437,26 +442,19 @@ static int ahci_init_one(pci_dev_t dev)
 #endif
        int rc;
 
-       probe_ent = malloc(sizeof(struct ahci_probe_ent));
-       if (!probe_ent) {
-               printf("%s: No memory for probe_ent\n", __func__);
-               return -ENOMEM;
-       }
-
-       memset(probe_ent, 0, sizeof(struct ahci_probe_ent));
-       probe_ent->dev = dev;
+       uc_priv->dev = dev;
 
-       probe_ent->host_flags = ATA_FLAG_SATA
+       uc_priv->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 */
+       uc_priv->pio_mask = 0x1f;
+       uc_priv->udma_mask = 0x7f;      /*Fixme,assume to support UDMA6 */
 
 #if !defined(CONFIG_DM_SCSI)
 #ifdef CONFIG_DM_PCI
-       probe_ent->mmio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_5,
+       uc_priv->mmio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_5,
                                              PCI_REGION_MEM);
 
        /* Take from kernel:
@@ -467,7 +465,7 @@ static int ahci_init_one(pci_dev_t dev)
        if (vendor == 0x197b)
                dm_pci_write_config8(dev, 0x41, 0xa1);
 #else
-       probe_ent->mmio_base = pci_map_bar(dev, PCI_BASE_ADDRESS_5,
+       uc_priv->mmio_base = pci_map_bar(dev, PCI_BASE_ADDRESS_5,
                                           PCI_REGION_MEM);
 
        /* Take from kernel:
@@ -480,16 +478,16 @@ static int ahci_init_one(pci_dev_t dev)
 #endif
 #else
        struct scsi_platdata *plat = dev_get_uclass_platdata(dev);
-       probe_ent->mmio_base = (void *)plat->base;
+       uc_priv->mmio_base = (void *)plat->base;
 #endif
 
-       debug("ahci mmio_base=0x%p\n", probe_ent->mmio_base);
+       debug("ahci mmio_base=0x%p\n", uc_priv->mmio_base);
        /* initialize adapter */
-       rc = ahci_host_init(probe_ent);
+       rc = ahci_host_init(uc_priv);
        if (rc)
                goto err_out;
 
-       ahci_print_info(probe_ent);
+       ahci_print_info(uc_priv);
 
        return 0;
 
@@ -500,9 +498,10 @@ static int ahci_init_one(pci_dev_t dev)
 
 #define MAX_DATA_BYTE_COUNT  (4*1024*1024)
 
-static int ahci_fill_sg(u8 port, unsigned char *buf, int buf_len)
+static int ahci_fill_sg(struct ahci_uc_priv *uc_priv, u8 port,
+                       unsigned char *buf, int buf_len)
 {
-       struct ahci_ioports *pp = &(probe_ent->port[port]);
+       struct ahci_ioports *pp = &(uc_priv->port[port]);
        struct ahci_sg *ahci_sg = pp->cmd_tbl_sg;
        u32 sg_count;
        int i;
@@ -555,9 +554,9 @@ static int wait_spinup(void __iomem *port_mmio)
        return -ETIMEDOUT;
 }
 
-static int ahci_port_start(u8 port)
+static int ahci_port_start(struct ahci_uc_priv *uc_priv, u8 port)
 {
-       struct ahci_ioports *pp = &(probe_ent->port[port]);
+       struct ahci_ioports *pp = &(uc_priv->port[port]);
        void __iomem *port_mmio = pp->port_mmio;
        u32 port_status;
        void __iomem *mem;
@@ -630,11 +629,11 @@ static int ahci_port_start(u8 port)
 }
 
 
-static int ahci_device_data_io(u8 port, u8 *fis, int fis_len, u8 *buf,
-                               int buf_len, u8 is_write)
+static int ahci_device_data_io(struct ahci_uc_priv *uc_priv, u8 port, u8 *fis,
+                              int fis_len, u8 *buf, int buf_len, u8 is_write)
 {
 
-       struct ahci_ioports *pp = &(probe_ent->port[port]);
+       struct ahci_ioports *pp = &(uc_priv->port[port]);
        void __iomem *port_mmio = pp->port_mmio;
        u32 opts;
        u32 port_status;
@@ -642,7 +641,7 @@ static int ahci_device_data_io(u8 port, u8 *fis, int fis_len, u8 *buf,
 
        debug("Enter %s: for port %d\n", __func__, port);
 
-       if (port > probe_ent->n_ports) {
+       if (port > uc_priv->n_ports) {
                printf("Invalid port number %d\n", port);
                return -1;
        }
@@ -655,7 +654,7 @@ static int ahci_device_data_io(u8 port, u8 *fis, int fis_len, u8 *buf,
 
        memcpy((unsigned char *)pp->cmd_tbl, fis, fis_len);
 
-       sg_count = ahci_fill_sg(port, buf, buf_len);
+       sg_count = ahci_fill_sg(uc_priv, port, buf, buf_len);
        opts = (fis_len >> 2) | (sg_count << 16) | (is_write << 6);
        ahci_fill_cmd_slot(pp, opts);
 
@@ -689,7 +688,8 @@ static char *ata_id_strcpy(u16 *target, u16 *src, int len)
 /*
  * SCSI INQUIRY command operation.
  */
-static int ata_scsiop_inquiry(struct scsi_cmd *pccb)
+static int ata_scsiop_inquiry(struct ahci_uc_priv *uc_priv,
+                             struct scsi_cmd *pccb)
 {
        static const u8 hdr[] = {
                0,
@@ -720,21 +720,21 @@ static int ata_scsiop_inquiry(struct scsi_cmd *pccb)
        /* Read id from sata */
        port = pccb->target;
 
-       if (ahci_device_data_io(port, (u8 *) &fis, sizeof(fis), (u8 *)tmpid,
-                               ATA_ID_WORDS * 2, 0)) {
+       if (ahci_device_data_io(uc_priv, port, (u8 *)&fis, sizeof(fis),
+                               (u8 *)tmpid, ATA_ID_WORDS * 2, 0)) {
                debug("scsi_ahci: SCSI inquiry command failure.\n");
                return -EIO;
        }
 
-       if (!ataid[port]) {
-               ataid[port] = malloc(ATA_ID_WORDS * 2);
-               if (!ataid[port]) {
+       if (!uc_priv->ataid[port]) {
+               uc_priv->ataid[port] = malloc(ATA_ID_WORDS * 2);
+               if (!uc_priv->ataid[port]) {
                        printf("%s: No memory for ataid[port]\n", __func__);
                        return -ENOMEM;
                }
        }
 
-       idbuf = ataid[port];
+       idbuf = uc_priv->ataid[port];
 
        memcpy(idbuf, tmpid, ATA_ID_WORDS * 2);
        ata_swap_buf_le16(idbuf, ATA_ID_WORDS);
@@ -753,7 +753,8 @@ static int ata_scsiop_inquiry(struct scsi_cmd *pccb)
 /*
  * SCSI READ10/WRITE10 command operation.
  */
-static int ata_scsiop_read_write(struct scsi_cmd *pccb, u8 is_write)
+static int ata_scsiop_read_write(struct ahci_uc_priv *uc_priv,
+                                struct scsi_cmd *pccb, u8 is_write)
 {
        lbaint_t lba = 0;
        u16 blocks = 0;
@@ -833,8 +834,8 @@ static int ata_scsiop_read_write(struct scsi_cmd *pccb, u8 is_write)
                fis[13] = (now_blocks >> 8) & 0xff;
 
                /* Read/Write from ahci */
-               if (ahci_device_data_io(pccb->target, (u8 *) &fis, sizeof(fis),
-                                       user_buffer, transfer_size,
+               if (ahci_device_data_io(uc_priv, pccb->target, (u8 *)&fis,
+                                       sizeof(fis), user_buffer, transfer_size,
                                        is_write)) {
                        debug("scsi_ahci: SCSI %s10 command failure.\n",
                              is_write ? "WRITE" : "READ");
@@ -848,7 +849,7 @@ static int ata_scsiop_read_write(struct scsi_cmd *pccb, u8 is_write)
                 * usually, one extra flush when the rare writes do happen.
                 */
                if (is_write) {
-                       if (-EIO == ata_io_flush(pccb->target))
+                       if (-EIO == ata_io_flush(uc_priv, pccb->target))
                                return -EIO;
                }
                user_buffer += transfer_size;
@@ -864,20 +865,21 @@ static int ata_scsiop_read_write(struct scsi_cmd *pccb, u8 is_write)
 /*
  * SCSI READ CAPACITY10 command operation.
  */
-static int ata_scsiop_read_capacity10(struct scsi_cmd *pccb)
+static int ata_scsiop_read_capacity10(struct ahci_uc_priv *uc_priv,
+                                     struct scsi_cmd *pccb)
 {
        u32 cap;
        u64 cap64;
        u32 block_size;
 
-       if (!ataid[pccb->target]) {
+       if (!uc_priv->ataid[pccb->target]) {
                printf("scsi_ahci: SCSI READ CAPACITY10 command failure. "
                       "\tNo ATA info!\n"
                       "\tPlease run SCSI command INQUIRY first!\n");
                return -EPERM;
        }
 
-       cap64 = ata_id_n_sectors(ataid[pccb->target]);
+       cap64 = ata_id_n_sectors(uc_priv->ataid[pccb->target]);
        if (cap64 > 0x100000000ULL)
                cap64 = 0xffffffff;
 
@@ -894,19 +896,20 @@ static int ata_scsiop_read_capacity10(struct scsi_cmd *pccb)
 /*
  * SCSI READ CAPACITY16 command operation.
  */
-static int ata_scsiop_read_capacity16(struct scsi_cmd *pccb)
+static int ata_scsiop_read_capacity16(struct ahci_uc_priv *uc_priv,
+                                     struct scsi_cmd *pccb)
 {
        u64 cap;
        u64 block_size;
 
-       if (!ataid[pccb->target]) {
+       if (!uc_priv->ataid[pccb->target]) {
                printf("scsi_ahci: SCSI READ CAPACITY16 command failure. "
                       "\tNo ATA info!\n"
                       "\tPlease run SCSI command INQUIRY first!\n");
                return -EPERM;
        }
 
-       cap = ata_id_n_sectors(ataid[pccb->target]);
+       cap = ata_id_n_sectors(uc_priv->ataid[pccb->target]);
        cap = cpu_to_be64(cap);
        memcpy(pccb->pdata, &cap, sizeof(cap));
 
@@ -920,59 +923,87 @@ static int ata_scsiop_read_capacity16(struct scsi_cmd *pccb)
 /*
  * SCSI TEST UNIT READY command operation.
  */
-static int ata_scsiop_test_unit_ready(struct scsi_cmd *pccb)
+static int ata_scsiop_test_unit_ready(struct ahci_uc_priv *uc_priv,
+                                     struct scsi_cmd *pccb)
 {
-       return (ataid[pccb->target]) ? 0 : -EPERM;
+       return (uc_priv->ataid[pccb->target]) ? 0 : -EPERM;
 }
 
 
-int scsi_exec(struct scsi_cmd *pccb)
+static int ahci_scsi_exec(struct udevice *dev, struct scsi_cmd *pccb)
 {
+       struct ahci_uc_priv *uc_priv;
+#ifdef CONFIG_DM_SCSI
+       uc_priv = dev_get_uclass_priv(dev->parent);
+#else
+       uc_priv = probe_ent;
+#endif
        int ret;
 
        switch (pccb->cmd[0]) {
        case SCSI_READ16:
        case SCSI_READ10:
-               ret = ata_scsiop_read_write(pccb, 0);
+               ret = ata_scsiop_read_write(uc_priv, pccb, 0);
                break;
        case SCSI_WRITE10:
-               ret = ata_scsiop_read_write(pccb, 1);
+               ret = ata_scsiop_read_write(uc_priv, pccb, 1);
                break;
        case SCSI_RD_CAPAC10:
-               ret = ata_scsiop_read_capacity10(pccb);
+               ret = ata_scsiop_read_capacity10(uc_priv, pccb);
                break;
        case SCSI_RD_CAPAC16:
-               ret = ata_scsiop_read_capacity16(pccb);
+               ret = ata_scsiop_read_capacity16(uc_priv, pccb);
                break;
        case SCSI_TST_U_RDY:
-               ret = ata_scsiop_test_unit_ready(pccb);
+               ret = ata_scsiop_test_unit_ready(uc_priv, pccb);
                break;
        case SCSI_INQUIRY:
-               ret = ata_scsiop_inquiry(pccb);
+               ret = ata_scsiop_inquiry(uc_priv, pccb);
                break;
        default:
                printf("Unsupport SCSI command 0x%02x\n", pccb->cmd[0]);
-               return false;
+               return -ENOTSUPP;
        }
 
        if (ret) {
                debug("SCSI command 0x%02x ret errno %d\n", pccb->cmd[0], ret);
-               return false;
+               return ret;
        }
-       return true;
+       return 0;
 
 }
 
-#if defined(CONFIG_DM_SCSI)
-void scsi_low_level_init(int busdevfunc, struct udevice *dev)
-#else
-void scsi_low_level_init(int busdevfunc)
-#endif
+static int ahci_start_ports(struct ahci_uc_priv *uc_priv)
 {
-       int i;
        u32 linkmap;
+       int i;
+
+       linkmap = uc_priv->link_port_map;
+
+       for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) {
+               if (((linkmap >> i) & 0x01)) {
+                       if (ahci_port_start(uc_priv, (u8) i)) {
+                               printf("Can not start port %d\n", i);
+                               continue;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+#ifndef CONFIG_DM_SCSI
+void scsi_low_level_init(int busdevfunc)
+{
+       struct ahci_uc_priv *uc_priv;
 
 #ifndef CONFIG_SCSI_AHCI_PLAT
+       probe_ent = calloc(1, sizeof(struct ahci_uc_priv));
+       if (!probe_ent) {
+               printf("%s: No memory for uc_priv\n", __func__);
+               return;
+       }
+       uc_priv = probe_ent;
 # if defined(CONFIG_DM_PCI)
        struct udevice *dev;
        int ret;
@@ -980,76 +1011,94 @@ void scsi_low_level_init(int busdevfunc)
        ret = dm_pci_bus_find_bdf(busdevfunc, &dev);
        if (ret)
                return;
-       ahci_init_one(dev);
-# elif defined(CONFIG_DM_SCSI)
-       ahci_init_one(dev);
+       ahci_init_one(uc_priv, dev);
 # else
-       ahci_init_one(busdevfunc);
+       ahci_init_one(uc_priv, busdevfunc);
 # endif
+#else
+       uc_priv = probe_ent;
 #endif
 
-       linkmap = probe_ent->link_port_map;
+       ahci_start_ports(uc_priv);
+}
+#endif
 
-       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;
-                       }
-               }
-       }
+#ifndef CONFIG_SCSI_AHCI_PLAT
+# if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI)
+int ahci_init_one_dm(struct udevice *dev)
+{
+       struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+
+       return ahci_init_one(uc_priv, dev);
 }
+#endif
+#endif
 
-#ifdef CONFIG_SCSI_AHCI_PLAT
-int ahci_init(void __iomem *base)
+int ahci_start_ports_dm(struct udevice *dev)
 {
-       int i, rc = 0;
-       u32 linkmap;
+       struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev);
 
-       probe_ent = malloc(sizeof(struct ahci_probe_ent));
-       if (!probe_ent) {
-               printf("%s: No memory for probe_ent\n", __func__);
-               return -ENOMEM;
-       }
+       return ahci_start_ports(uc_priv);
+}
 
-       memset(probe_ent, 0, sizeof(struct ahci_probe_ent));
+#ifdef CONFIG_SCSI_AHCI_PLAT
+static int ahci_init_common(struct ahci_uc_priv *uc_priv, void __iomem *base)
+{
+       int rc;
 
-       probe_ent->host_flags = ATA_FLAG_SATA
+       uc_priv->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 */
+       uc_priv->pio_mask = 0x1f;
+       uc_priv->udma_mask = 0x7f;      /*Fixme,assume to support UDMA6 */
 
-       probe_ent->mmio_base = base;
+       uc_priv->mmio_base = base;
 
        /* initialize adapter */
-       rc = ahci_host_init(probe_ent);
+       rc = ahci_host_init(uc_priv);
        if (rc)
                goto err_out;
 
-       ahci_print_info(probe_ent);
+       ahci_print_info(uc_priv);
 
-       linkmap = probe_ent->link_port_map;
+       rc = ahci_start_ports(uc_priv);
 
-       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;
-                       }
-               }
-       }
 err_out:
        return rc;
 }
 
+#ifndef CONFIG_DM_SCSI
+int ahci_init(void __iomem *base)
+{
+       struct ahci_uc_priv *uc_priv;
+
+       probe_ent = malloc(sizeof(struct ahci_uc_priv));
+       if (!probe_ent) {
+               printf("%s: No memory for uc_priv\n", __func__);
+               return -ENOMEM;
+       }
+
+       uc_priv = probe_ent;
+       memset(uc_priv, 0, sizeof(struct ahci_uc_priv));
+
+       return ahci_init_common(uc_priv, base);
+}
+#endif
+
+int ahci_init_dm(struct udevice *dev, void __iomem *base)
+{
+       struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+
+       return ahci_init_common(uc_priv, base);
+}
+
 void __weak scsi_init(void)
 {
 }
 
-#endif
+#endif /* CONFIG_SCSI_AHCI_PLAT */
 
 /*
  * In the general case of generic rotating media it makes sense to have a
@@ -1060,10 +1109,10 @@ void __weak scsi_init(void)
  * is the last write is difficult. Because writing to the disk in u-boot is
  * very rare, this flush command will be invoked after every block write.
  */
-static int ata_io_flush(u8 port)
+static int ata_io_flush(struct ahci_uc_priv *uc_priv, u8 port)
 {
        u8 fis[20];
-       struct ahci_ioports *pp = &(probe_ent->port[port]);
+       struct ahci_ioports *pp = &(uc_priv->port[port]);
        void __iomem *port_mmio = pp->port_mmio;
        u32 cmd_fis_len = 5;    /* five dwords */
 
@@ -1087,8 +1136,85 @@ static int ata_io_flush(u8 port)
        return 0;
 }
 
+static int ahci_scsi_bus_reset(struct udevice *dev)
+{
+       /* Not implemented */
+
+       return 0;
+}
 
-__weak void scsi_bus_reset(void)
+#ifdef CONFIG_DM_SCSI
+int ahci_bind_scsi(struct udevice *ahci_dev, struct udevice **devp)
 {
-       /*Not implement*/
+       struct udevice *dev;
+       int ret;
+
+       ret = device_bind_driver(ahci_dev, "ahci_scsi", "ahci_scsi", &dev);
+       if (ret)
+               return ret;
+       *devp = dev;
+
+       return 0;
 }
+
+int ahci_probe_scsi(struct udevice *ahci_dev, ulong base)
+{
+       struct ahci_uc_priv *uc_priv;
+       struct scsi_platdata *uc_plat;
+       struct udevice *dev;
+       int ret;
+
+       device_find_first_child(ahci_dev, &dev);
+       if (!dev)
+               return -ENODEV;
+       uc_plat = dev_get_uclass_platdata(dev);
+       uc_plat->base = base;
+       uc_plat->max_lun = 1;
+       uc_plat->max_id = 2;
+
+       uc_priv = dev_get_uclass_priv(ahci_dev);
+       ret = ahci_init_one(uc_priv, dev);
+       if (ret)
+               return ret;
+       ret = ahci_start_ports(uc_priv);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+#ifdef CONFIG_DM_PCI
+int ahci_probe_scsi_pci(struct udevice *ahci_dev)
+{
+       ulong base;
+
+       base = (ulong)dm_pci_map_bar(ahci_dev, PCI_BASE_ADDRESS_5,
+                                    PCI_REGION_MEM);
+
+       return ahci_probe_scsi(ahci_dev, base);
+}
+#endif
+
+struct scsi_ops scsi_ops = {
+       .exec           = ahci_scsi_exec,
+       .bus_reset      = ahci_scsi_bus_reset,
+};
+
+U_BOOT_DRIVER(ahci_scsi) = {
+       .name           = "ahci_scsi",
+       .id             = UCLASS_SCSI,
+       .ops            = &scsi_ops,
+};
+#else
+int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb)
+{
+       return ahci_scsi_exec(dev, pccb);
+}
+
+__weak int scsi_bus_reset(struct udevice *dev)
+{
+       return ahci_scsi_bus_reset(dev);
+
+       return 0;
+}
+#endif