瀏覽代碼

add ls2k sata ssd driver

bigmagic 4 年之前
父節點
當前提交
68689c7c43

+ 35 - 0
bsp/ls2kdev/.config

@@ -385,6 +385,8 @@ CONFIG_RT_LWIP_USING_PING=y
 # CONFIG_PKG_USING_AGILE_JSMN is not set
 # CONFIG_PKG_USING_PDULIB is not set
 # CONFIG_PKG_USING_BTSTACK is not set
+# CONFIG_PKG_USING_LORAWAN_ED_STACK is not set
+# CONFIG_PKG_USING_WAYZ_IOTKIT is not set
 
 #
 # security packages
@@ -410,6 +412,9 @@ CONFIG_RT_LWIP_USING_PING=y
 # CONFIG_PKG_USING_STEMWIN is not set
 # CONFIG_PKG_USING_WAVPLAYER is not set
 # CONFIG_PKG_USING_TJPGD is not set
+# CONFIG_PKG_USING_HELIX is not set
+# CONFIG_PKG_USING_AZUREGUIX is not set
+# CONFIG_PKG_USING_TOUCHGFX2RTT is not set
 
 #
 # tools packages
@@ -424,6 +429,7 @@ CONFIG_RT_LWIP_USING_PING=y
 # CONFIG_PKG_USING_ADBD is not set
 # CONFIG_PKG_USING_COREMARK is not set
 # CONFIG_PKG_USING_DHRYSTONE is not set
+# CONFIG_PKG_USING_MEMORYPERF is not set
 # CONFIG_PKG_USING_NR_MICRO_SHELL is not set
 # CONFIG_PKG_USING_CHINESE_FONT_LIBRARY is not set
 # CONFIG_PKG_USING_LUNAR_CALENDAR is not set
@@ -431,6 +437,10 @@ CONFIG_RT_LWIP_USING_PING=y
 # CONFIG_PKG_USING_GPS_RMC is not set
 # CONFIG_PKG_USING_URLENCODE is not set
 # CONFIG_PKG_USING_UMCN is not set
+# CONFIG_PKG_USING_LWRB2RTT is not set
+# CONFIG_PKG_USING_CPU_USAGE is not set
+# CONFIG_PKG_USING_GBK2UTF8 is not set
+# CONFIG_PKG_USING_VCONSOLE is not set
 
 #
 # system packages
@@ -462,8 +472,18 @@ CONFIG_PKG_LWEXT4_VER="latest"
 # CONFIG_PKG_USING_RAMDISK is not set
 # CONFIG_PKG_USING_MININI is not set
 # CONFIG_PKG_USING_QBOOT is not set
+
+#
+# Micrium: Micrium software products porting for RT-Thread
+#
 # CONFIG_PKG_USING_UCOSIII_WRAPPER is not set
+# CONFIG_PKG_USING_UCOSII_WRAPPER is not set
+# CONFIG_PKG_USING_UC_CRC is not set
+# CONFIG_PKG_USING_UC_CLK is not set
+# CONFIG_PKG_USING_UC_COMMON is not set
+# CONFIG_PKG_USING_UC_MODBUS is not set
 # CONFIG_PKG_USING_PPOOL is not set
+# CONFIG_PKG_USING_OPENAMP is not set
 
 #
 # peripheral libraries and drivers
@@ -517,6 +537,13 @@ CONFIG_PKG_LWEXT4_VER="latest"
 # CONFIG_PKG_USING_LD3320 is not set
 # CONFIG_PKG_USING_WK2124 is not set
 # CONFIG_PKG_USING_LY68L6400 is not set
+# CONFIG_PKG_USING_DM9051 is not set
+# CONFIG_PKG_USING_SSD1306 is not set
+# CONFIG_PKG_USING_QKEY is not set
+# CONFIG_PKG_USING_RS485 is not set
+# CONFIG_PKG_USING_NES is not set
+# CONFIG_PKG_USING_VIRTUAL_SENSOR is not set
+# CONFIG_PKG_USING_VDEVICE is not set
 
 #
 # miscellaneous packages
@@ -526,6 +553,7 @@ CONFIG_PKG_LWEXT4_VER="latest"
 # CONFIG_PKG_USING_FASTLZ is not set
 # CONFIG_PKG_USING_MINILZO is not set
 # CONFIG_PKG_USING_QUICKLZ is not set
+# CONFIG_PKG_USING_LZMA is not set
 # CONFIG_PKG_USING_MULTIBUTTON is not set
 # CONFIG_PKG_USING_FLEXIBLE_BUTTON is not set
 # CONFIG_PKG_USING_CANFESTIVAL is not set
@@ -546,6 +574,7 @@ CONFIG_PKG_LWEXT4_VER="latest"
 # CONFIG_PKG_USING_PERIPHERAL_SAMPLES is not set
 # CONFIG_PKG_USING_HELLO is not set
 # CONFIG_PKG_USING_VI is not set
+# CONFIG_PKG_USING_KI is not set
 # CONFIG_PKG_USING_NNOM is not set
 # CONFIG_PKG_USING_LIBANN is not set
 # CONFIG_PKG_USING_ELAPACK is not set
@@ -554,8 +583,14 @@ CONFIG_PKG_LWEXT4_VER="latest"
 # CONFIG_PKG_USING_ULAPACK is not set
 # CONFIG_PKG_USING_UKAL is not set
 # CONFIG_PKG_USING_CRCLIB is not set
+
+#
+# games: games run on RT-Thread console
+#
 # CONFIG_PKG_USING_THREES is not set
 # CONFIG_PKG_USING_2048 is not set
+# CONFIG_PKG_USING_SNAKE is not set
+# CONFIG_PKG_USING_TETRIS is not set
 # CONFIG_PKG_USING_LWGPS is not set
 # CONFIG_PKG_USING_TENSORFLOWLITEMICRO is not set
 CONFIG_SOC_LS2K1000=y

+ 39 - 0
bsp/ls2kdev/applications/mnt.c

@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-29     bigmagic    first version
+ */
+#include <rthw.h>
+#include <rtthread.h>
+#include <dfs.h>
+#include <dfs_fs.h>
+#include <dfs_file.h>
+#include <ext4.h>
+#include <ext4_debug.h>
+#include <blk_device.h>
+#include <stdint.h>
+#include <pci.h>
+
+int mount_ssd(void)
+{
+    struct blk_device *blkdev = (struct blk_device *)rt_device_find("dwc_ahsata_blk");
+
+    if(blkdev == RT_NULL)
+    {
+        rt_kprintf("dwc_ahsata_blk not found!\n");
+        return;
+    }
+    
+    //ext4_dmask_set(0xFFFFFFFF);
+    blk_device_init(blkdev);
+    dfs_mount("dwc_ahsata_blk","/","ext",0,(void *)1);
+    dfs_mount("dwc_ahsata_blk","/boot","ext",0,(void *)0);
+
+    return 0;
+}
+
+INIT_ENV_EXPORT(mount_ssd);

+ 14 - 0
bsp/ls2kdev/drivers/ata/SConscript

@@ -0,0 +1,14 @@
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c')
+
+CPPPATH = [cwd]
+
+if GetDepend('RT_USING_DFS_ELMFAT') == False:
+    SrcRemove(src, 'dwc_ahsata.c')
+    SrcRemove(src, 'libata.c')
+
+group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH)
+
+Return('group')

+ 281 - 0
bsp/ls2kdev/drivers/ata/ahci.h

@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-08-19     lizhirui     porting to ls2k
+ */
+
+#ifndef _AHCI_H_
+#define _AHCI_H_
+
+#define AHCI_PCI_BAR 0x24
+#define AHCI_MAX_SG 56 /* hardware max is 64K */
+#define AHCI_CMD_SLOT_SZ 32
+#define AHCI_MAX_CMD_SLOT 32
+#define AHCI_RX_FIS_SZ 256
+#define AHCI_CMD_TBL_HDR 0x80
+#define AHCI_CMD_TBL_CDB 0x40
+#define AHCI_CMD_TBL_SZ AHCI_CMD_TBL_HDR + (AHCI_MAX_SG * 16)
+#define AHCI_PORT_PRIV_DMA_SZ (AHCI_CMD_SLOT_SZ * AHCI_MAX_CMD_SLOT + \
+                               AHCI_CMD_TBL_SZ + AHCI_RX_FIS_SZ)
+#define AHCI_CMD_ATAPI (1 << 5)
+#define AHCI_CMD_WRITE (1 << 6)
+#define AHCI_CMD_PREFETCH (1 << 7)
+#define AHCI_CMD_RESET (1 << 8)
+#define AHCI_CMD_CLR_BUSY (1 << 10)
+
+#define RX_FIS_D2H_REG 0x40 /* offset of D2H Register FIS data */
+
+/* Global controller registers */
+#define HOST_CAP 0x00        /* host capabilities */
+#define HOST_CTL 0x04        /* global host control */
+#define HOST_IRQ_STAT 0x08   /* interrupt status */
+#define HOST_PORTS_IMPL 0x0c /* bitmap of implemented ports */
+#define HOST_VERSION 0x10    /* AHCI spec. version compliancy */
+#define HOST_CAP2 0x24       /* host capabilities, extended */
+
+/* HOST_CTL bits */
+#define HOST_RESET (1 << 0)    /* reset controller; self-clear */
+#define HOST_IRQ_EN (1 << 1)   /* global IRQ enable */
+#define HOST_AHCI_EN (1 << 31) /* AHCI enabled */
+
+/* Registers for each SATA port */
+#define PORT_LST_ADDR 0x00    /* command list DMA addr */
+#define PORT_LST_ADDR_HI 0x04 /* command list DMA addr hi */
+#define PORT_FIS_ADDR 0x08    /* FIS rx buf addr */
+#define PORT_FIS_ADDR_HI 0x0c /* FIS rx buf addr hi */
+#define PORT_IRQ_STAT 0x10    /* interrupt status */
+#define PORT_IRQ_MASK 0x14    /* interrupt enable/disable mask */
+#define PORT_CMD 0x18         /* port command */
+#define PORT_TFDATA 0x20      /* taskfile data */
+#define PORT_SIG 0x24         /* device TF signature */
+#define PORT_CMD_ISSUE 0x38   /* command issue */
+#define PORT_SCR 0x28         /* SATA phy register block */
+#define PORT_SCR_STAT 0x28    /* SATA phy register: SStatus */
+#define PORT_SCR_CTL 0x2c     /* SATA phy register: SControl */
+#define PORT_SCR_ERR 0x30     /* SATA phy register: SError */
+#define PORT_SCR_ACT 0x34     /* SATA phy register: SActive */
+
+#ifdef CONFIG_SUNXI_AHCI
+#define PORT_P0DMACR 0x70 /* SUNXI specific "DMA register" */
+#endif
+
+/* PORT_IRQ_{STAT,MASK} bits */
+#define PORT_IRQ_COLD_PRES (1 << 31)     /* cold presence detect */
+#define PORT_IRQ_TF_ERR (1 << 30)        /* task file error */
+#define PORT_IRQ_HBUS_ERR (1 << 29)      /* host bus fatal error */
+#define PORT_IRQ_HBUS_DATA_ERR (1 << 28) /* host bus data error */
+#define PORT_IRQ_IF_ERR (1 << 27)        /* interface fatal error */
+#define PORT_IRQ_IF_NONFATAL (1 << 26)   /* interface non-fatal error */
+#define PORT_IRQ_OVERFLOW (1 << 24)      /* xfer exhausted available S/G */
+#define PORT_IRQ_BAD_PMP (1 << 23)       /* incorrect port multiplier */
+
+#define PORT_IRQ_PHYRDY (1 << 22)     /* PhyRdy changed */
+#define PORT_IRQ_DEV_ILCK (1 << 7)    /* device interlock */
+#define PORT_IRQ_CONNECT (1 << 6)     /* port connect change status */
+#define PORT_IRQ_SG_DONE (1 << 5)     /* descriptor processed */
+#define PORT_IRQ_UNK_FIS (1 << 4)     /* unknown FIS rx'd */
+#define PORT_IRQ_SDB_FIS (1 << 3)     /* Set Device Bits FIS rx'd */
+#define PORT_IRQ_DMAS_FIS (1 << 2)    /* DMA Setup FIS rx'd */
+#define PORT_IRQ_PIOS_FIS (1 << 1)    /* PIO Setup FIS rx'd */
+#define PORT_IRQ_D2H_REG_FIS (1 << 0) /* D2H Register FIS rx'd */
+
+#define PORT_IRQ_FATAL PORT_IRQ_TF_ERR | PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR | PORT_IRQ_IF_ERR
+
+#define DEF_PORT_IRQ PORT_IRQ_FATAL | PORT_IRQ_PHYRDY | PORT_IRQ_CONNECT | PORT_IRQ_SG_DONE | PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS
+
+/* PORT_SCR_STAT bits */
+#define PORT_SCR_STAT_DET_MASK 0x3
+#define PORT_SCR_STAT_DET_COMINIT 0x1
+#define PORT_SCR_STAT_DET_PHYRDY 0x3
+
+/* PORT_CMD bits */
+#define PORT_CMD_ATAPI (1 << 24)   /* Device is ATAPI */
+#define PORT_CMD_LIST_ON (1 << 15) /* cmd list DMA engine running */
+#define PORT_CMD_FIS_ON (1 << 14)  /* FIS DMA engine running */
+#define PORT_CMD_FIS_RX (1 << 4)   /* Enable FIS receive DMA engine */
+#define PORT_CMD_CLO (1 << 3)      /* Command list override */
+#define PORT_CMD_POWER_ON (1 << 2) /* Power up device */
+#define PORT_CMD_SPIN_UP (1 << 1)  /* Spin up device */
+#define PORT_CMD_START (1 << 0)    /* Enable port DMA engine */
+
+#define PORT_CMD_ICC_ACTIVE (0x1 << 28)  /* Put i/f in active state */
+#define PORT_CMD_ICC_PARTIAL (0x2 << 28) /* Put i/f in partial state */
+#define PORT_CMD_ICC_SLUMBER (0x6 << 28) /* Put i/f in slumber state */
+
+#define AHCI_MAX_PORTS 32
+
+#define ATA_FLAG_SATA (1 << 3)
+#define ATA_FLAG_NO_LEGACY (1 << 4)  /* no legacy mode check */
+#define ATA_FLAG_MMIO (1 << 6)       /* use MMIO, not PIO */
+#define ATA_FLAG_SATA_RESET (1 << 7) /* (obsolete) use COMRESET */
+#define ATA_FLAG_PIO_DMA (1 << 8)    /* PIO cmds via DMA */
+#define ATA_FLAG_NO_ATAPI (1 << 11)  /* No ATAPI support */
+
+struct ahci_cmd_hdr
+{
+    u32 opts;
+    u32 status;
+    u64 tbl_addr;
+    //u32 tbl_addr_hi;
+    u32 reserved[4];
+};
+
+struct ahci_sg
+{
+    u64 addr;
+    //u32 addr_hi;
+    u32 reserved;
+    u32 flags_size;
+};
+
+struct ahci_ioports
+{
+    void __iomem *port_mmio;
+    struct ahci_cmd_hdr *cmd_slot;
+    struct ahci_sg *cmd_tbl_sg;
+    ulong cmd_tbl;
+    u32 rx_fis;
+};
+
+/**
+ * struct ahci_uc_priv - information about an AHCI controller
+ *
+ * When driver model is used, this is accessible using dev_get_uclass_priv(dev)
+ * where dev is the controller (although at present it sometimes stands alone).
+ */
+struct ahci_uc_priv
+{
+    struct rt_device parent;
+    struct ahci_ioports port[AHCI_MAX_PORTS];
+    u16 *ataid[AHCI_MAX_PORTS];
+    u32 n_ports;
+    u32 hard_port_no;
+    u32 host_flags;
+    u32 host_set_flags;
+    void *mmio_base;
+    u32 pio_mask;
+    u32 udma_mask;
+    u32 flags;
+    u32 cap;           /* cache of HOST_CAP register */
+    u32 port_map;      /* cache of HOST_PORTS_IMPL reg */
+    u32 link_port_map; /*linkup port map*/
+};
+
+struct ahci_ops
+{
+    /**
+     * reset() - reset the controller
+     *
+     * @dev:    Controller to reset
+     * @return 0 if OK, -ve on error
+     */
+    int (*reset)(struct rt_device *dev);
+
+    /**
+     * port_status() - get the status of a SATA port
+     *
+     * @dev:    Controller to reset
+     * @port:    Port number to check (0 for first)
+     * @return 0 if detected, -ENXIO if nothing on port, other -ve on error
+     */
+    int (*port_status)(struct rt_device *dev, int port);
+
+    /**
+     * scan() - scan SATA ports
+     *
+     * @dev:    Controller to scan
+     * @return 0 if OK, -ve on error
+     */
+    int (*scan)(struct rt_device *dev);
+};
+
+#define ahci_get_ops(dev) ((struct ahci_ops *)(dev)->driver->ops)
+
+/**
+ * sata_reset() - reset the controller
+ *
+ * @dev:    Controller to reset
+ * @return 0 if OK, -ve on error
+ */
+int sata_reset(struct rt_device *dev);
+
+/**
+ * sata_port_status() - get the status of a SATA port
+ *
+ * @dev:    Controller to reset
+ * @port:    Port number to check (0 for first)
+ * @return 0 if detected, -ENXIO if nothin on port, other -ve on error
+ */
+int sata_dm_port_status(struct rt_device *dev, int port);
+
+/**
+ * sata_scan() - scan SATA ports
+ *
+ * @dev:    Controller to scan
+ * @return 0 if OK, -ve on error
+ */
+int sata_scan(struct rt_device *dev);
+
+int ahci_init(void __iomem *base);
+int ahci_reset(void __iomem *base);
+
+/**
+ * ahci_init_one_dm() - set up a single AHCI port
+ *
+ * @dev: Controller to init
+ */
+int ahci_init_one_dm(struct rt_device *dev);
+
+/**
+ * ahci_start_ports_dm() - start all AHCI ports for a controller
+ *
+ * @dev: Controller containing ports to start
+ */
+int ahci_start_ports_dm(struct rt_device *dev);
+
+/**
+ * ahci_init_dm() - init AHCI for a controller, finding all ports
+ *
+ * @dev: Device to init
+ */
+int ahci_init_dm(struct rt_device *dev, void __iomem *base);
+
+/**
+ * ahci_bind_scsi() - bind a new SCSI bus as a child
+ *
+ * Note that the SCSI bus device will itself bind block devices
+ *
+ * @ahci_dev: AHCI parent device
+ * @devp: Returns new SCSI bus device
+ * @return 0 if OK, -ve on error
+ */
+int ahci_bind_scsi(struct rt_device *ahci_dev, struct rt_device **devp);
+
+/**
+ * ahci_probe_scsi() - probe and scan the attached SCSI bus
+ *
+ * Note that the SCSI device will itself bind block devices for any storage
+ * devices it finds.
+ *
+ * @ahci_dev: AHCI parent device
+ * @base: Base address of AHCI port
+ * @return 0 if OK, -ve on error
+ */
+int ahci_probe_scsi(struct rt_device *ahci_dev, ulong base);
+
+/**
+ * ahci_probe_scsi_pci() - probe and scan the attached SCSI bus on PCI
+ *
+ * Note that the SCSI device will itself bind block devices for any storage
+ * devices it finds.
+ *
+ * @ahci_dev: AHCI parent device
+ * @return 0 if OK, -ve on error
+ */
+int ahci_probe_scsi_pci(struct rt_device *ahci_dev);
+
+#endif

+ 20 - 0
bsp/ls2kdev/drivers/ata/ata_debug.h

@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-08-19     lizhirui     first version
+ */
+
+#ifndef __ATA_DEBUG_H__
+#define __ATA_DEBUG_H__
+//#define ATA_DEBUG
+#include <rtthread.h>
+#ifdef ATA_DEBUG
+#define debug rt_kprintf
+#else
+#define debug(...)
+#endif
+#endif

+ 101 - 0
bsp/ls2kdev/drivers/ata/ata_interface.h

@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-08-19     lizhirui     first version
+ */
+
+#ifndef __ATA_INTERFACE_H__
+#define __ATA_INTERFACE_H__
+
+typedef rt_uint8_t u8;
+typedef rt_uint16_t u16;
+typedef rt_uint32_t u32;
+typedef rt_uint64_t u64;
+typedef rt_uint64_t ulong;
+
+typedef rt_int8_t s8;
+typedef rt_int16_t s16;
+typedef rt_int32_t s32;
+typedef rt_int64_t s64;
+
+typedef rt_size_t lbaint_t;
+
+#define __iomem
+#define mdelay rt_thread_mdelay
+#define udelay(...) rt_thread_mdelay(1)
+
+#define cpu_to_le32
+#define cpu_to_le16
+#define le32_to_cpu
+#define le16_to_cpu
+
+#define flush_cache(...)
+#define invalidate_dcache_range(...)
+
+#define ARCH_DMA_MINALIGN 1024
+
+#define CONFIG_IS_ENABLED
+#define AHCI 1
+
+#define VADDR_TO_PHY(vaddr) (((u64)vaddr) - KSEG0BASE)
+#define LOW_PHY(vaddr) ((u32)VADDR_TO_PHY(vaddr))
+#define HIGH_PHY(vaddr) ((u32)((VADDR_TO_PHY(vaddr)) >> 32))
+
+#define ALIGN_1(x, a) __ALIGN_MASK((x), (typeof(x))(a)-1)
+#define ALIGN_DOWN(x, a) ALIGN_1((x) - ((a)-1), (a))
+#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
+#define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a)))
+#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a)-1)) == 0)
+
+#define ROUND(a, b) (((a) + (b)-1) & ~((b)-1))
+
+#define PAD_COUNT(s, pad) (((s)-1) / (pad) + 1)
+#define PAD_SIZE(s, pad) (PAD_COUNT(s, pad) * pad)
+#define ALLOC_ALIGN_BUFFER_PAD(type, name, size, align, pad)                         \
+    char __##name[ROUND(PAD_SIZE((size) * sizeof(type), pad), align) + (align - 1)]; \
+                                                                                     \
+    type *name = (type *)ALIGN_1((rt_ubase_t)__##name, align)
+#define ALLOC_ALIGN_BUFFER(type, name, size, align) \
+    ALLOC_ALIGN_BUFFER_PAD(type, name, size, align, 1)
+#define ALLOC_CACHE_ALIGN_BUFFER_PAD(type, name, size, pad) \
+    ALLOC_ALIGN_BUFFER_PAD(type, name, size, ARCH_DMA_MINALIGN, pad)
+#define ALLOC_CACHE_ALIGN_BUFFER(type, name, size) \
+    ALLOC_ALIGN_BUFFER(type, name, size, ARCH_DMA_MINALIGN)
+
+static inline u32 readl(void *addr)
+{
+    return *((u32 *)addr);
+}
+
+static inline void writel(u32 data, void *addr)
+{
+    *((u32 *)addr) = data;
+}
+
+static inline int ffs(int word)
+{
+    int r;
+
+    if (word == 0)
+    {
+        return 0;
+    }
+
+    word &= (-word);
+
+    __asm__("clz %0, %1"
+            : "=r"(r)
+            : "r"(word));
+    return 32 - r;
+}
+
+static inline void setbits_le32(u32 *addr, u32 value)
+{
+    *addr = value;
+}
+
+#endif

+ 127 - 0
bsp/ls2kdev/drivers/ata/blk_device.c

@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-08-19     lizhirui     first version
+ */
+
+#include <rtthread.h>
+#include <rtdef.h>
+#include <dfs.h>
+#include <dfs_fs.h>
+#include <dfs_file.h>
+#include <ext4.h>
+#include <ext4_debug.h>
+#include <blk_device.h>
+#include <stdint.h>
+
+static struct blk_device *blkdev;
+static rt_uint32_t disk_sector_size;
+
+static int blockdev_open(struct ext4_blockdev *bdev)
+{
+    int r;
+    uint32_t size;
+    rt_device_t device = (rt_device_t)blkdev;
+    struct rt_device_blk_geometry geometry;
+
+    RT_ASSERT(device);
+
+    r = rt_device_open((rt_device_t)blkdev, RT_DEVICE_OFLAG_RDWR);
+
+    if (r != RT_EOK)
+    {
+        return r;
+    }
+
+    r = rt_device_control(device, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry);
+
+    if (RT_EOK == r)
+    {
+        bdev->part_offset = 0;
+        bdev->part_size = geometry.sector_count * geometry.bytes_per_sector;
+        disk_sector_size = geometry.bytes_per_sector;
+        bdev->bdif->ph_bcnt = bdev->part_size / bdev->bdif->ph_bsize;
+    }
+
+    return r;
+}
+
+static int blockdev_bread(struct ext4_blockdev *bdev, void *buf, uint64_t blk_id,
+                          uint32_t blk_cnt)
+{
+    int result;
+    rt_device_t device = (rt_device_t)blkdev;
+    struct blk_device *blk = (struct blk_device *)device;
+    RT_ASSERT(device);
+
+    result = rt_device_read(device, blk_id * (bdev->bdif->ph_bsize / disk_sector_size),
+                            buf, blk_cnt * (bdev->bdif->ph_bsize / disk_sector_size));
+
+    if ((blk_cnt * (bdev->bdif->ph_bsize / disk_sector_size)) == result)
+    {
+        result = 0;
+    }
+    else
+    {
+        result = -EIO;
+    }
+
+    return result;
+}
+
+static int blockdev_bwrite(struct ext4_blockdev *bdev, const void *buf,
+                           uint64_t blk_id, uint32_t blk_cnt)
+{
+    int result;
+    rt_device_t device = (rt_device_t)blkdev;
+
+    RT_ASSERT(device);
+
+    result = rt_device_write(device, blk_id * (bdev->bdif->ph_bsize / disk_sector_size),
+                             buf, blk_cnt * (bdev->bdif->ph_bsize / disk_sector_size));
+
+    if ((blk_cnt * (bdev->bdif->ph_bsize / disk_sector_size)) == result)
+    {
+        result = 0;
+    }
+    else
+    {
+        result = -EIO;
+    }
+
+    return result;
+}
+
+static int blockdev_close(struct ext4_blockdev *bdev)
+{
+    return rt_device_close((rt_device_t)blkdev);
+}
+
+static int blockdev_lock(struct ext4_blockdev *bdev)
+{
+    return 0;
+}
+
+static int blockdev_unlock(struct ext4_blockdev *bdev)
+{
+    return 0;
+}
+
+EXT4_BLOCKDEV_STATIC_INSTANCE(bdev, 4096, 0, blockdev_open,
+                              blockdev_bread, blockdev_bwrite, blockdev_close,
+                              blockdev_lock, blockdev_unlock);
+
+void blk_device_init(struct blk_device *blk_devices)
+{
+    blkdev = blk_devices;
+
+    if (ext4_mbr_scan(&bdev, &(blkdev->ext4_partition)) != EOK)
+    {
+        rt_kprintf("MBR scan failed!\n");
+        return;
+    }
+}

+ 48 - 0
bsp/ls2kdev/drivers/ata/blk_device.h

@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-08-19     lizhirui     first version
+ */
+
+#ifndef __BLK_DEVICE_H__
+#define __BLK_DEVICE_H__
+
+#include <rtconfig.h>
+#include <ext4_mbr.h>
+
+#define DEV_TYPE_UNKNOWN 0xff  /* not connected */
+#define DEV_TYPE_HARDDISK 0x00 /* harddisk */
+#define DEV_TYPE_TAPE 0x01     /* Tape */
+#define DEV_TYPE_CDROM 0x05    /* CD-ROM */
+#define DEV_TYPE_OPDISK 0x07   /* optical disk */
+
+struct blk_device
+{
+    struct rt_device parent;
+    struct ahci_uc_priv *ahci_device;
+
+    rt_uint8_t target;
+    rt_uint8_t lun;
+    rt_uint8_t type;
+
+#ifdef RT_USING_DFS_LWEXT4
+    struct ext4_mbr_bdevs ext4_partition;
+#endif
+
+    rt_bool_t lba48;
+    rt_uint64_t lba;
+    rt_uint64_t blksz;
+    rt_int32_t log2blksz;
+
+    char product[21];
+    char revision[9];
+    char vendor[41];
+};
+
+void blk_device_init(struct blk_device *blk_devices);
+
+#endif

+ 1234 - 0
bsp/ls2kdev/drivers/ata/dwc_ahsata.c

@@ -0,0 +1,1234 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-08-19     lizhirui     porting to ls2k
+ */
+
+#include <rtthread.h>
+#include <rtdef.h>
+#include <mips_addrspace.h>
+#include <ata_interface.h>
+#include <ahci.h>
+#include <dwc_ahsata.h>
+#include <fis.h>
+#include <libata.h>
+#include <ata_debug.h>
+#include <blk_device.h>
+#include "dwc_ahsata_priv.h"
+
+struct sata_port_regs
+{
+    u32 clb;
+    u32 clbu;
+    u32 fb;
+    u32 fbu;
+    u32 is;
+    u32 ie;
+    u32 cmd;
+    u32 res1[1];
+    u32 tfd;
+    u32 sig;
+    u32 ssts;
+    u32 sctl;
+    u32 serr;
+    u32 sact;
+    u32 ci;
+    u32 sntf;
+    u32 res2[1];
+    u32 dmacr;
+    u32 res3[1];
+    u32 phycr;
+    u32 physr;
+};
+
+struct sata_host_regs
+{
+    u32 cap;
+    u32 ghc;
+    u32 is;
+    u32 pi;
+    u32 vs;
+    u32 ccc_ctl;
+    u32 ccc_ports;
+    u32 res1[2];
+    u32 cap2;
+    u32 res2[30];
+    u32 bistafr;
+    u32 bistcr;
+    u32 bistfctr;
+    u32 bistsr;
+    u32 bistdecr;
+    u32 res3[2];
+    u32 oobr;
+    u32 res4[8];
+    u32 timer1ms;
+    u32 res5[1];
+    u32 gparam1r;
+    u32 gparam2r;
+    u32 pparamr;
+    u32 testr;
+    u32 versionr;
+    u32 idr;
+};
+
+#define MAX_DATA_BYTES_PER_SG (4 * 1024 * 1024)
+#define MAX_BYTES_PER_TRANS (AHCI_MAX_SG * MAX_DATA_BYTES_PER_SG)
+
+#define writel_with_flush(a, b) \
+    do                          \
+    {                           \
+        writel(a, b);           \
+        readl(b);               \
+    } while (0)
+
+static inline void __iomem *ahci_port_base(void __iomem *base, u32 port)
+{
+    return base + 0x100 + (port * 0x80);
+}
+
+static int waiting_for_cmd_completed(u8 *offset, int timeout_msec, u32 sign)
+{
+    int i;
+    u32 status;
+
+    for (i = 0; ((status = readl(offset)) & sign) && i < timeout_msec; i++)
+    {
+        mdelay(1);
+    }
+
+    return (i < timeout_msec) ? 0 : -1;
+}
+
+static int ahci_setup_oobr(struct ahci_uc_priv *uc_priv, int clk)
+{
+    struct sata_host_regs *host_mmio = uc_priv->mmio_base;
+
+    writel(SATA_HOST_OOBR_WE, &host_mmio->oobr);
+    writel(0x02060b14, &host_mmio->oobr);
+
+    return 0;
+}
+
+int ahci_host_init(struct ahci_uc_priv *uc_priv)
+{
+    u32 tmp, cap_save, num_ports;
+    int i, j, timeout = 1000;
+    struct sata_port_regs *port_mmio = NULL;
+    struct sata_host_regs *host_mmio = uc_priv->mmio_base;
+
+    //prepare to enable staggered spin-up
+    cap_save = readl(&host_mmio->cap);
+    cap_save |= SATA_HOST_CAP_SSS;
+
+    /* global controller reset */
+    tmp = readl(&host_mmio->ghc);
+
+    //ahsata controller reset
+    if ((tmp & SATA_HOST_GHC_HR) == 0)
+    {
+        writel_with_flush(tmp | SATA_HOST_GHC_HR, &host_mmio->ghc);
+    }
+
+    //wait for reset finishing
+    while ((readl(&host_mmio->ghc) & SATA_HOST_GHC_HR) && --timeout)
+        ;
+
+    //reset timeout
+    if (timeout <= 0)
+    {
+        debug("controller reset failed (0x%x)\n", tmp);
+        return -1;
+    }
+
+    /* Set timer 1ms @ 100MHz*/
+    writel(100000000 / 1000, &host_mmio->timer1ms);
+
+    ahci_setup_oobr(uc_priv, 0);
+
+    //enable ahci
+    writel_with_flush(SATA_HOST_GHC_AE, &host_mmio->ghc);
+
+    //enable staggered spin-up
+    writel(cap_save, &host_mmio->cap);
+
+    //get sata port number
+    num_ports = (cap_save & SATA_HOST_CAP_NP_MASK) + 1;
+
+    //initialize pi register to set correct port number
+    writel_with_flush((1 << num_ports) - 1, &host_mmio->pi);
+
+    /*
+     * Determine which Ports are implemented by the DWC_ahsata,
+     * by reading the PI register. This bit map value aids the
+     * software to determine how many Ports are available and
+     * which Port registers need to be initialized.
+     */
+    uc_priv->cap = readl(&host_mmio->cap);
+    uc_priv->port_map = readl(&host_mmio->pi);
+
+    /* Determine how many command slots the HBA supports */
+    uc_priv->n_ports = (uc_priv->cap & SATA_HOST_CAP_NP_MASK) + 1;
+
+    debug("cap 0x%x  port_map 0x%x  n_ports %d\n",
+          uc_priv->cap, uc_priv->port_map, uc_priv->n_ports);
+
+    for (i = 0; i < uc_priv->n_ports; i++)
+    {
+        uc_priv->port[i].port_mmio = ahci_port_base(host_mmio, i);
+        port_mmio = uc_priv->port[i].port_mmio;
+
+        /* Ensure that the DWC_ahsata is in idle state */
+        tmp = readl(&port_mmio->cmd);
+
+        /*
+         * When P#CMD.ST, P#CMD.CR, P#CMD.FRE and P#CMD.FR
+         * are all cleared, the Port is in an idle state.
+         */
+        if (tmp & (SATA_PORT_CMD_CR | SATA_PORT_CMD_FR |
+                   SATA_PORT_CMD_FRE | SATA_PORT_CMD_ST))
+        {
+
+            /*
+             * System software places a Port into the idle state by
+             * clearing P#CMD.ST and waiting for P#CMD.CR to return
+             * 0 when read.
+             */
+            tmp &= ~SATA_PORT_CMD_ST;
+            writel_with_flush(tmp, &port_mmio->cmd);
+
+            /*
+             * spec says 500 msecs for each bit, so
+             * this is slightly incorrect.
+             */
+            mdelay(500);
+
+            timeout = 1000;
+            while ((readl(&port_mmio->cmd) & SATA_PORT_CMD_CR) && --timeout)
+                ;
+
+            if (timeout <= 0)
+            {
+                debug("port reset failed (0x%x)\n", tmp);
+                return -1;
+            }
+        }
+
+        /* Spin-up device */
+        tmp = readl(&port_mmio->cmd);
+        writel((tmp | SATA_PORT_CMD_SUD), &port_mmio->cmd);
+
+        /* Wait for spin-up to finish */
+        timeout = 1000;
+        while (!(readl(&port_mmio->cmd) | SATA_PORT_CMD_SUD) && --timeout)
+            ;
+
+        if (timeout <= 0)
+        {
+            debug("Spin-Up can't finish!\n");
+            return -1;
+        }
+
+        for (j = 0; j < 100; ++j)
+        {
+            mdelay(10);
+            tmp = readl(&port_mmio->ssts);
+            if (((tmp & SATA_PORT_SSTS_DET_MASK) == 0x3) ||
+                ((tmp & SATA_PORT_SSTS_DET_MASK) == 0x1))
+            {
+                break;
+            }
+        }
+
+        /* Wait for COMINIT bit 26 (DIAG_X) in SERR */
+        timeout = 1000;
+        while (!(readl(&port_mmio->serr) & SATA_PORT_SERR_DIAG_X) && --timeout)
+            ;
+
+        if (timeout <= 0)
+        {
+            debug("Can't find DIAG_X set!\n");
+            return -1;
+        }
+
+        /*
+         * For each implemented Port, clear the P#SERR
+         * register, by writing ones to each implemented\
+         * bit location.
+         */
+        tmp = readl(&port_mmio->serr);
+        debug("P#SERR 0x%x\n",
+              tmp);
+        writel(tmp, &port_mmio->serr);
+
+        /* Ack any pending irq events for this port */
+        tmp = readl(&host_mmio->is);
+        debug("IS 0x%x\n", tmp);
+        if (tmp)
+        {
+            writel(tmp, &host_mmio->is);
+        }
+
+        writel(1 << i, &host_mmio->is);
+
+        /* set irq mask (enables interrupts) */
+        writel(DEF_PORT_IRQ, &port_mmio->ie);
+
+        /* register linkup ports */
+        tmp = readl(&port_mmio->ssts);
+        debug("Port %d status: 0x%x\n", i, tmp);
+        if ((tmp & SATA_PORT_SSTS_DET_MASK) == 0x03)
+        {
+            uc_priv->link_port_map |= (0x01 << i);
+        }
+    }
+
+    tmp = readl(&host_mmio->ghc);
+    debug("GHC 0x%x\n", tmp);
+    //Interrupt Enable
+    writel(tmp | SATA_HOST_GHC_IE, &host_mmio->ghc);
+    tmp = readl(&host_mmio->ghc);
+    debug("GHC 0x%x\n", tmp);
+
+    return 0;
+}
+
+int rt_hw_ahci_host_init()
+{
+    struct ahci_uc_priv *ahci_device;
+    ahci_device = (struct ahci_uc_priv *)rt_device_create(RT_Device_Class_Miscellaneous, sizeof(struct ahci_uc_priv) - sizeof(struct rt_device));
+
+    ahci_device->mmio_base = (void *)DWCAHSATA_BASE;
+    ahci_device->parent.init = NULL;
+    ahci_device->parent.open = NULL;
+    ahci_device->parent.close = NULL;
+    ahci_device->parent.read = NULL;
+    ahci_device->parent.write = NULL;
+    ahci_device->parent.control = NULL;
+
+    if (rt_device_register((rt_device_t)ahci_device, "dwc_ahsata_ahci", 0) != RT_EOK)
+    {
+        rt_kprintf("dwc_ahsata_ahci device register failed!\n");
+        return -RT_ERROR;
+    }
+
+    if (dwc_ahsata_probe((rt_device_t)ahci_device) != 0)
+    {
+        rt_kprintf("ahci probe failed!\n");
+        return -RT_ERROR;
+    }
+
+    if (dwc_ahsata_scan((rt_device_t)ahci_device) != 0)
+    {
+        rt_kprintf("ahci host sata device scan failed!\n");
+        return -RT_ERROR;
+    }
+
+    return RT_EOK;
+}
+INIT_COMPONENT_EXPORT(rt_hw_ahci_host_init);
+
+static void ahci_print_info(struct ahci_uc_priv *uc_priv)
+{
+    struct sata_host_regs *host_mmio = uc_priv->mmio_base;
+    u32 vers, cap, impl, speed;
+    const char *speed_s;
+    const char *scc_s;
+
+    vers = readl(&host_mmio->vs);
+    cap = uc_priv->cap;
+    impl = uc_priv->port_map;
+
+    speed = (cap & SATA_HOST_CAP_ISS_MASK) >> SATA_HOST_CAP_ISS_OFFSET;
+
+    if (speed == 1)
+    {
+        speed_s = "1.5";
+    }
+    else if (speed == 2)
+    {
+        speed_s = "3";
+    }
+    else
+    {
+        speed_s = "?";
+    }
+
+    scc_s = "SATA";
+
+    rt_kprintf("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);
+
+    rt_kprintf("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 " : "");
+
+    rt_kprintf("version = %08x\n", ((struct sata_host_regs *)(uc_priv->mmio_base))->versionr);
+}
+
+static int ahci_fill_sg(struct ahci_uc_priv *uc_priv, u8 port,
+                        unsigned char *buf, int buf_len)
+{
+    struct ahci_ioports *pp = &uc_priv->port[port];
+    struct ahci_sg *ahci_sg = pp->cmd_tbl_sg;
+    u32 sg_count, max_bytes;
+    int i;
+
+    max_bytes = MAX_DATA_BYTES_PER_SG;
+    sg_count = ((buf_len - 1) / max_bytes) + 1;
+
+    if (sg_count > AHCI_MAX_SG)
+    {
+        rt_kprintf("Error:Too much sg!\n");
+        return -1;
+    }
+
+    for (i = 0; i < sg_count; i++)
+    {
+        ahci_sg->addr = VADDR_TO_PHY(buf + i * max_bytes);
+        //ahci_sg->addr_hi = 0;
+        ahci_sg->flags_size = cpu_to_le32(0x3fffff &
+                                          (buf_len < max_bytes
+                                               ? (buf_len - 1)
+                                               : (max_bytes - 1)));
+        ahci_sg++;
+        buf_len -= max_bytes;
+    }
+
+    return sg_count;
+}
+
+static void ahci_fill_cmd_slot(struct ahci_ioports *pp, u32 cmd_slot, u32 opts)
+{
+    struct ahci_cmd_hdr *cmd_hdr = (struct ahci_cmd_hdr *)(pp->cmd_slot +
+                                                           AHCI_CMD_SLOT_SZ * cmd_slot);
+
+    memset(cmd_hdr, 0, AHCI_CMD_SLOT_SZ);
+    cmd_hdr->opts = cpu_to_le32(opts);
+    cmd_hdr->status = 0;
+    pp->cmd_slot->tbl_addr = VADDR_TO_PHY(pp->cmd_tbl);
+    /*#ifdef CONFIG_PHYS_64BIT
+    pp->cmd_slot->tbl_addr_hi =
+        cpu_to_le32((u32)(((pp->cmd_tbl) >> 16) >> 16));
+#endif*/
+}
+
+#define AHCI_GET_CMD_SLOT(c) ((c) ? ffs(c) : 0)
+
+static int ahci_exec_ata_cmd(struct ahci_uc_priv *uc_priv, u8 port,
+                             struct sata_fis_h2d *cfis, u8 *buf, u32 buf_len,
+                             s32 is_write)
+{
+    struct ahci_ioports *pp = &uc_priv->port[port];
+    struct sata_port_regs *port_mmio = pp->port_mmio;
+    u32 opts;
+    int sg_count = 0, cmd_slot = 0;
+
+    cmd_slot = AHCI_GET_CMD_SLOT(readl(&port_mmio->ci));
+
+    if (32 == cmd_slot)
+    {
+        rt_kprintf("Can't find empty command slot!\n");
+        return 0;
+    }
+
+    /* Check xfer length */
+    if (buf_len > MAX_BYTES_PER_TRANS)
+    {
+        rt_kprintf("Max transfer length is %dB\n\r",
+                   MAX_BYTES_PER_TRANS);
+        return 0;
+    }
+
+    memcpy((u8 *)(pp->cmd_tbl), cfis, sizeof(struct sata_fis_h2d));
+
+    if (buf && buf_len)
+    {
+        sg_count = ahci_fill_sg(uc_priv, port, buf, buf_len);
+    }
+
+    opts = (sizeof(struct sata_fis_h2d) >> 2) | (sg_count << 16);
+
+    if (is_write)
+    {
+        opts |= 0x40;
+        flush_cache((ulong)buf, buf_len);
+    }
+
+    ahci_fill_cmd_slot(pp, cmd_slot, opts);
+
+    flush_cache((int)(pp->cmd_slot), AHCI_PORT_PRIV_DMA_SZ);
+    writel_with_flush(1 << cmd_slot, &port_mmio->ci);
+
+    if (waiting_for_cmd_completed((u8 *)&port_mmio->ci, 10000,
+                                  0x1 << cmd_slot))
+    {
+        rt_kprintf("timeout exit!\n");
+        return -1;
+    }
+
+    invalidate_dcache_range((int)(pp->cmd_slot),
+                            (int)(pp->cmd_slot) + AHCI_PORT_PRIV_DMA_SZ);
+
+    debug("ahci_exec_ata_cmd: %d byte transferred.\n",
+          pp->cmd_slot->status);
+
+    if (!is_write)
+    {
+        invalidate_dcache_range((ulong)buf, (ulong)buf + buf_len);
+    }
+
+    return buf_len;
+}
+
+static void ahci_set_feature(struct ahci_uc_priv *uc_priv, u8 port)
+{
+    struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN);
+    struct sata_fis_h2d *cfis = &h2d;
+
+    memset(cfis, 0, sizeof(struct sata_fis_h2d));
+    cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
+    cfis->pm_port_c = 1 << 7;
+    cfis->command = ATA_CMD_SET_FEATURES;
+    cfis->features = SETFEATURES_XFER;
+    cfis->sector_count = ffs(uc_priv->udma_mask + 1) + 0x3e;
+
+    ahci_exec_ata_cmd(uc_priv, port, cfis, NULL, 0, READ_CMD);
+}
+
+static int ahci_port_start(struct ahci_uc_priv *uc_priv, u8 port)
+{
+    struct ahci_ioports *pp = &uc_priv->port[port];
+    struct sata_port_regs *port_mmio = pp->port_mmio;
+    u32 port_status;
+    u64 mem;
+    int timeout = 10000000;
+
+    debug("Enter start port: %d\n", port);
+    port_status = readl(&port_mmio->ssts);
+    debug("Port %d status: %x\n", port, port_status);
+
+    if ((port_status & 0xf) != 0x03)
+    {
+        rt_kprintf("No Link on this port!\n");
+        return -1;
+    }
+
+    mem = (u64)malloc(AHCI_PORT_PRIV_DMA_SZ + 1024);
+
+    if (!mem)
+    {
+        rt_kprintf("No mem for table!\n");
+        return -ENOMEM;
+    }
+
+    mem = (mem + 0x400) & (~0x3ff); /* Aligned to 1024-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%p\n", pp->cmd_slot);
+    mem += (AHCI_CMD_SLOT_SZ * DWC_AHSATA_MAX_CMD_SLOTS);
+
+    /*
+     * Second item: Received-FIS area, 256-Byte aligned
+     */
+    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%lx\n", pp->cmd_tbl);
+
+    mem += AHCI_CMD_TBL_HDR;
+
+    writel_with_flush(0x00004444, &port_mmio->dmacr);
+    pp->cmd_tbl_sg = (struct ahci_sg *)mem;
+    writel_with_flush(LOW_PHY(pp->cmd_slot), &port_mmio->clb);
+    writel_with_flush(HIGH_PHY(pp->cmd_slot), &port_mmio->clbu);
+    writel_with_flush(LOW_PHY(pp->rx_fis), &port_mmio->fb);
+    writel_with_flush(HIGH_PHY(pp->rx_fis), &port_mmio->fbu);
+
+    /* Enable FRE */
+    writel_with_flush((SATA_PORT_CMD_FRE | readl(&port_mmio->cmd)),
+                      &port_mmio->cmd);
+
+    /* Wait device ready */
+    while ((readl(&port_mmio->tfd) & (SATA_PORT_TFD_STS_ERR |
+                                      SATA_PORT_TFD_STS_DRQ | SATA_PORT_TFD_STS_BSY)) &&
+           --timeout)
+        ;
+    if (timeout <= 0)
+    {
+        debug("Device not ready for BSY, DRQ and"
+              "ERR in TFD!\n");
+        return -1;
+    }
+
+    writel_with_flush(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX |
+                          PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP |
+                          PORT_CMD_START,
+                      &port_mmio->cmd);
+
+    debug("Exit start port %d\n", port);
+
+    return 0;
+}
+
+static void dwc_ahsata_print_info(struct blk_device *pdev)
+{
+    rt_kprintf("SATA Device Info:\n\r");
+    rt_kprintf("S/N: %s\n\rProduct model number: %s\n\r"
+               "Firmware version: %s\n\rCapacity: %lu sectors\n\r",
+               pdev->product, pdev->vendor, pdev->revision, pdev->lba);
+}
+
+static void dwc_ahsata_identify(struct ahci_uc_priv *uc_priv, u16 *id)
+{
+    struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN);
+    struct sata_fis_h2d *cfis = &h2d;
+    u8 port = uc_priv->hard_port_no;
+
+    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;
+
+    ahci_exec_ata_cmd(uc_priv, port, cfis, (u8 *)id, ATA_ID_WORDS * 2,
+                      READ_CMD);
+    ata_swap_buf_le16(id, ATA_ID_WORDS);
+}
+
+static void dwc_ahsata_xfer_mode(struct ahci_uc_priv *uc_priv, u16 *id)
+{
+    uc_priv->pio_mask = id[ATA_ID_PIO_MODES];
+    uc_priv->udma_mask = id[ATA_ID_UDMA_MODES];
+    debug("pio %04x, udma %04x\n\r", uc_priv->pio_mask, uc_priv->udma_mask);
+}
+
+static u32 dwc_ahsata_rw_cmd(struct ahci_uc_priv *uc_priv, u32 start,
+                             u32 blkcnt, u8 *buffer, int is_write)
+{
+    struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN);
+    struct sata_fis_h2d *cfis = &h2d;
+    u8 port = uc_priv->hard_port_no;
+    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);
+
+    if (ahci_exec_ata_cmd(uc_priv, port, cfis, buffer,
+                          ATA_SECT_SIZE * blkcnt, is_write) > 0)
+        return blkcnt;
+    else
+        return 0;
+}
+
+static void dwc_ahsata_flush_cache(struct ahci_uc_priv *uc_priv)
+{
+    struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN);
+    struct sata_fis_h2d *cfis = &h2d;
+    u8 port = uc_priv->hard_port_no;
+
+    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;
+
+    ahci_exec_ata_cmd(uc_priv, port, cfis, NULL, 0, 0);
+}
+
+static u32 dwc_ahsata_rw_cmd_ext(struct ahci_uc_priv *uc_priv, u32 start,
+                                 lbaint_t blkcnt, u8 *buffer, int is_write)
+{
+    struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN);
+    struct sata_fis_h2d *cfis = &h2d;
+    u8 port = uc_priv->hard_port_no;
+    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;
+
+    if (ahci_exec_ata_cmd(uc_priv, port, cfis, buffer,
+                          ATA_SECT_SIZE * blkcnt, is_write) > 0)
+        return blkcnt;
+    else
+        return 0;
+}
+
+static void dwc_ahsata_flush_cache_ext(struct ahci_uc_priv *uc_priv)
+{
+    struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN);
+    struct sata_fis_h2d *cfis = &h2d;
+    u8 port = uc_priv->hard_port_no;
+
+    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;
+
+    ahci_exec_ata_cmd(uc_priv, port, cfis, NULL, 0, 0);
+}
+
+static void dwc_ahsata_init_wcache(struct ahci_uc_priv *uc_priv, u16 *id)
+{
+    if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id))
+        uc_priv->flags |= SATA_FLAG_WCACHE;
+    if (ata_id_has_flush(id))
+        uc_priv->flags |= SATA_FLAG_FLUSH;
+    if (ata_id_has_flush_ext(id))
+        uc_priv->flags |= SATA_FLAG_FLUSH_EXT;
+}
+
+static u32 ata_low_level_rw_lba48(struct ahci_uc_priv *uc_priv, u32 blknr,
+                                  lbaint_t blkcnt, const 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 (max_blks != dwc_ahsata_rw_cmd_ext(uc_priv, start,
+                                                  max_blks, addr,
+                                                  is_write))
+                return 0;
+            start += max_blks;
+            blks -= max_blks;
+            addr += ATA_SECT_SIZE * max_blks;
+        }
+        else
+        {
+            if (blks != dwc_ahsata_rw_cmd_ext(uc_priv, start, blks,
+                                              addr, is_write))
+                return 0;
+            start += blks;
+            blks = 0;
+            addr += ATA_SECT_SIZE * blks;
+        }
+    } while (blks != 0);
+
+    return blkcnt;
+}
+
+static u32 ata_low_level_rw_lba28(struct ahci_uc_priv *uc_priv, u32 blknr,
+                                  lbaint_t blkcnt, const 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)
+        {
+            if (max_blks != dwc_ahsata_rw_cmd(uc_priv, start,
+                                              max_blks, addr,
+                                              is_write))
+                return 0;
+            start += max_blks;
+            blks -= max_blks;
+            addr += ATA_SECT_SIZE * max_blks;
+        }
+        else
+        {
+            if (blks != dwc_ahsata_rw_cmd(uc_priv, start, blks,
+                                          addr, is_write))
+                return 0;
+            start += blks;
+            blks = 0;
+            addr += ATA_SECT_SIZE * blks;
+        }
+    } while (blks != 0);
+
+    return blkcnt;
+}
+
+static int dwc_ahci_start_ports(struct ahci_uc_priv *uc_priv)
+{
+    u32 linkmap;
+    int i;
+
+    linkmap = uc_priv->link_port_map;
+
+    if (0 == linkmap)
+    {
+        rt_kprintf("No port device detected!\n");
+        return -ENXIO;
+    }
+
+    for (i = 0; i < uc_priv->n_ports; i++)
+    {
+        if ((linkmap >> i) && ((linkmap >> i) & 0x01))
+        {
+            if (ahci_port_start(uc_priv, (u8)i))
+            {
+                rt_kprintf("Can not start port %d\n", i);
+                return 1;
+            }
+
+            uc_priv->hard_port_no = i;
+            break;
+        }
+    }
+
+    return 0;
+}
+
+unsigned char sector_data[512];
+
+void dump_pbuf(void *p, int len)
+{
+    rt_kprintf("----dump_pbuf----\n");
+    rt_kprintf("pbuf = 0x%p,len = %d\n", p, len);
+    u32 i;
+    u8 *q = p;
+    rt_kprintf("%p", q);
+
+    for (i = 0; i < 16; i++)
+    {
+        rt_kprintf(" %02x", i);
+    }
+
+    rt_kprintf("\n");
+
+    for (i = 0; i < len; i++)
+    {
+        if (!(i & 0xF))
+        {
+            rt_kprintf("%p", &q[i]);
+        }
+
+        rt_kprintf(" %02x", q[i]);
+
+        if ((i & 0xF) == 0xF)
+        {
+            rt_kprintf("\n");
+        }
+    }
+
+    rt_kprintf("\n-----------------\n");
+}
+
+static int dwc_ahsata_scan_common(struct ahci_uc_priv *uc_priv,
+                                  struct blk_device *pdev)
+{
+    u8 serial[ATA_ID_SERNO_LEN + 1] = {0};
+    u8 firmware[ATA_ID_FW_REV_LEN + 1] = {0};
+    u8 product[ATA_ID_PROD_LEN + 1] = {0};
+    u8 port = uc_priv->hard_port_no;
+    ALLOC_CACHE_ALIGN_BUFFER(u16, id, ATA_ID_WORDS);
+
+    /* Identify device to get information */
+    dwc_ahsata_identify(uc_priv, id);
+
+    /* Serial number */
+    ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial));
+    memcpy(pdev->product, serial, sizeof(serial));
+
+    /* Firmware version */
+    ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware));
+    memcpy(pdev->revision, firmware, sizeof(firmware));
+
+    /* Product model */
+    ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product));
+    memcpy(pdev->vendor, product, sizeof(product));
+
+    /* Total sectors */
+    pdev->lba = ata_id_n_sectors(id);
+
+    pdev->type = DEV_TYPE_HARDDISK;
+    pdev->blksz = ATA_SECT_SIZE;
+    pdev->lun = 0;
+
+    /* Check if support LBA48 */
+    if (ata_id_has_lba48(id))
+    {
+        pdev->lba48 = 1;
+        debug("Device support LBA48\n\r");
+    }
+
+    /* Get the NCQ queue depth from device */
+    uc_priv->flags &= (~SATA_FLAG_Q_DEP_MASK);
+    uc_priv->flags |= ata_id_queue_depth(id);
+
+    /* Get the xfer mode from device */
+    dwc_ahsata_xfer_mode(uc_priv, id);
+
+    /* Get the write cache status from device */
+    dwc_ahsata_init_wcache(uc_priv, id);
+
+    /* Set the xfer mode to highest speed */
+    ahci_set_feature(uc_priv, port);
+    dwc_ahsata_read((rt_device_t)pdev, 0, sector_data, 1);
+    //dump_pbuf(sector_data, 512);
+    dwc_ahsata_print_info(pdev);
+
+    return 0;
+}
+
+/*
+ * SATA interface between low level driver and command layer
+ */
+static ulong sata_read_common(struct ahci_uc_priv *uc_priv,
+                              struct blk_device *desc, ulong blknr,
+                              lbaint_t blkcnt, void *buffer)
+{
+    u32 rc;
+
+    if (desc->lba48)
+        rc = ata_low_level_rw_lba48(uc_priv, blknr, blkcnt, buffer,
+                                    READ_CMD);
+    else
+        rc = ata_low_level_rw_lba28(uc_priv, blknr, blkcnt, buffer,
+                                    READ_CMD);
+
+    return rc;
+}
+
+static ulong sata_write_common(struct ahci_uc_priv *uc_priv,
+                               struct blk_device *desc, ulong blknr,
+                               lbaint_t blkcnt, const void *buffer)
+{
+    u32 rc;
+    u32 flags = uc_priv->flags;
+
+    if (desc->lba48)
+    {
+        rc = ata_low_level_rw_lba48(uc_priv, blknr, blkcnt, buffer,
+                                    WRITE_CMD);
+        if ((flags & SATA_FLAG_WCACHE) && (flags & SATA_FLAG_FLUSH_EXT))
+            dwc_ahsata_flush_cache_ext(uc_priv);
+    }
+    else
+    {
+        rc = ata_low_level_rw_lba28(uc_priv, blknr, blkcnt, buffer,
+                                    WRITE_CMD);
+        if ((flags & SATA_FLAG_WCACHE) && (flags & SATA_FLAG_FLUSH))
+            dwc_ahsata_flush_cache(uc_priv);
+    }
+
+    return rc;
+}
+
+#if !CONFIG_IS_ENABLED(AHCI)
+static int ahci_init_one(int pdev)
+{
+    int rc;
+    struct ahci_uc_priv *uc_priv = NULL;
+
+    uc_priv = malloc(sizeof(struct ahci_uc_priv));
+    if (!uc_priv)
+        return -ENOMEM;
+
+    memset(uc_priv, 0, sizeof(struct ahci_uc_priv));
+    uc_priv->dev = pdev;
+
+    uc_priv->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_NO_ATAPI;
+
+    uc_priv->mmio_base = (void __iomem *)CONFIG_DWC_AHSATA_BASE_ADDR;
+
+    /* initialize adapter */
+    rc = ahci_host_init(uc_priv);
+    if (rc)
+        goto err_out;
+
+    ahci_print_info(uc_priv);
+
+    /* Save the uc_private struct to block device struct */
+    sata_dev_desc[pdev].priv = uc_priv;
+
+    return 0;
+
+err_out:
+    if (uc_priv)
+        free(uc_priv);
+    return rc;
+}
+
+int init_sata(int dev)
+{
+    struct ahci_uc_priv *uc_priv = NULL;
+
+#if defined(CONFIG_MX6)
+    if (!is_mx6dq() && !is_mx6dqp())
+        return 1;
+#endif
+    if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1))
+    {
+        rt_kprintf("The sata index %d is out of ranges\n\r", dev);
+        return -1;
+    }
+
+    ahci_init_one(dev);
+
+    uc_priv = sata_dev_desc[dev].priv;
+
+    return dwc_ahci_start_ports(uc_priv) ? 1 : 0;
+}
+
+int reset_sata(int dev)
+{
+    struct ahci_uc_priv *uc_priv;
+    struct sata_host_regs *host_mmio;
+
+    if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1))
+    {
+        rt_kprintf("The sata index %d is out of ranges\n\r", dev);
+        return -1;
+    }
+
+    uc_priv = sata_dev_desc[dev].priv;
+    if (NULL == uc_priv)
+        /* not initialized, so nothing to reset */
+        return 0;
+
+    host_mmio = uc_priv->mmio_base;
+    setbits_le32(&host_mmio->ghc, SATA_HOST_GHC_HR);
+    while (readl(&host_mmio->ghc) & SATA_HOST_GHC_HR)
+        udelay(100);
+
+    free(uc_priv);
+    memset(&sata_dev_desc[dev], 0, sizeof(struct blk_desc));
+
+    return 0;
+}
+
+int sata_port_status(int dev, int port)
+{
+    struct sata_port_regs *port_mmio;
+    struct ahci_uc_priv *uc_priv = NULL;
+
+    if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1))
+        return -EINVAL;
+
+    if (sata_dev_desc[dev].priv == NULL)
+        return -ENODEV;
+
+    uc_priv = sata_dev_desc[dev].priv;
+    port_mmio = uc_priv->port[port].port_mmio;
+
+    return readl(&port_mmio->ssts) & SATA_PORT_SSTS_DET_MASK;
+}
+
+/*
+ * SATA interface between low level driver and command layer
+ */
+ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer)
+{
+    struct ahci_uc_priv *uc_priv = sata_dev_desc[dev].priv;
+
+    return sata_read_common(uc_priv, &sata_dev_desc[dev], blknr, blkcnt,
+                            buffer);
+}
+
+ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer)
+{
+    struct ahci_uc_priv *uc_priv = sata_dev_desc[dev].priv;
+
+    return sata_write_common(uc_priv, &sata_dev_desc[dev], blknr, blkcnt,
+                             buffer);
+}
+
+int scan_sata(int dev)
+{
+    struct ahci_uc_priv *uc_priv = sata_dev_desc[dev].priv;
+    struct blk_desc *pdev = &sata_dev_desc[dev];
+
+    return dwc_ahsata_scan_common(uc_priv, pdev);
+}
+#endif /* CONFIG_IS_ENABLED(AHCI) */
+
+#if CONFIG_IS_ENABLED(AHCI)
+
+int dwc_ahsata_port_status(struct rt_device *dev, int port)
+{
+    struct ahci_uc_priv *uc_priv = (struct ahci_uc_priv *)dev;
+    struct sata_port_regs *port_mmio;
+
+    port_mmio = uc_priv->port[port].port_mmio;
+    return readl(&port_mmio->ssts) & SATA_PORT_SSTS_DET_MASK ? 0 : -ENXIO;
+}
+
+int dwc_ahsata_bus_reset(struct rt_device *dev)
+{
+    struct ahci_uc_priv *uc_priv = (struct ahci_uc_priv *)dev;
+    struct sata_host_regs *host_mmio = uc_priv->mmio_base;
+
+    setbits_le32(&host_mmio->ghc, SATA_HOST_GHC_HR);
+
+    while (readl(&host_mmio->ghc) & SATA_HOST_GHC_HR)
+    {
+        udelay(100);
+    }
+
+    return 0;
+}
+
+int dwc_ahsata_scan(struct rt_device *dev)
+{
+    struct ahci_uc_priv *uc_priv = (struct ahci_uc_priv *)dev;
+    struct blk_device *blk;
+    rt_err_t ret;
+
+    blk = (struct blk_device *)rt_device_create(RT_Device_Class_Block, sizeof(struct blk_device) - sizeof(struct rt_device));
+    blk->parent.init = NULL;
+    blk->parent.open = NULL;
+    blk->parent.close = NULL;
+    blk->parent.control = dwc_ahsata_control;
+    blk->parent.read = dwc_ahsata_read;
+    blk->parent.write = dwc_ahsata_write;
+    blk->ahci_device = uc_priv;
+    blk->blksz = 512;
+    blk->log2blksz = 9;
+    blk->lba = 0;
+    ret = rt_device_register((rt_device_t)blk, "dwc_ahsata_blk", RT_DEVICE_FLAG_RDWR);
+
+    if (ret != RT_EOK)
+    {
+        debug("Can't create device\n");
+        return ret;
+    }
+
+    ret = dwc_ahsata_scan_common(uc_priv, blk);
+
+    if (ret)
+    {
+        debug("%s: Failed to scan bus\n", __func__);
+        return ret;
+    }
+
+    return 0;
+}
+
+int dwc_ahsata_probe(struct rt_device *dev)
+{
+    struct ahci_uc_priv *uc_priv = (struct ahci_uc_priv *)dev;
+    int ret;
+
+    uc_priv->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+                          ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_NO_ATAPI;
+
+    /* initialize adapter */
+    ret = ahci_host_init(uc_priv);
+    if (ret)
+        return ret;
+
+    ahci_print_info(uc_priv);
+
+    return dwc_ahci_start_ports(uc_priv);
+}
+
+rt_size_t dwc_ahsata_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
+{
+    struct blk_device *blk = (struct blk_device *)dev;
+    return sata_read_common(blk->ahci_device, blk, pos, size, buffer);
+}
+
+rt_size_t dwc_ahsata_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
+{
+    struct blk_device *blk = (struct blk_device *)dev;
+    return sata_write_common(blk->ahci_device, blk, pos, size, buffer);
+}
+
+rt_err_t dwc_ahsata_control(rt_device_t dev, int cmd, void *args)
+{
+    struct blk_device *blk = (struct blk_device *)dev;
+
+    switch (cmd)
+    {
+    case RT_DEVICE_CTRL_BLK_GETGEOME:
+
+        if (args != NULL)
+        {
+            struct rt_device_blk_geometry *info = (struct rt_device_blk_geometry *)args;
+            info->sector_count = blk->lba;
+            info->bytes_per_sector = blk->blksz;
+            info->block_size = 0;
+        }
+
+        break;
+    }
+
+    return RT_EOK;
+}
+
+#endif

+ 25 - 0
bsp/ls2kdev/drivers/ata/dwc_ahsata.h

@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-08-19     lizhirui     porting to ls2k
+ */
+
+
+#ifndef __DWC_AHSATA_H__
+#define __DWC_AHSATA_H__
+
+#define DWCAHSATA_BASE (0x9000000000000000 | 0x400e0000)
+
+int dwc_ahsata_bus_reset(struct rt_device *dev);
+int dwc_ahsata_probe(struct rt_device *dev);
+int dwc_ahsata_scan(struct rt_device *dev);
+int dwc_ahsata_port_status(struct rt_device *dev, int port);
+rt_size_t dwc_ahsata_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
+rt_size_t dwc_ahsata_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
+rt_err_t dwc_ahsata_control(rt_device_t dev, int cmd, void *args);
+
+#endif

+ 323 - 0
bsp/ls2kdev/drivers/ata/dwc_ahsata_priv.h

@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-08-19     lizhirui     porting to ls2k
+ */
+
+#ifndef __DWC_AHSATA_PRIV_H__
+#define __DWC_AHSATA_PRIV_H__
+
+#define DWC_AHSATA_MAX_CMD_SLOTS 32
+
+/* Max host controller numbers */
+#define SATA_HC_MAX_NUM 4
+/* Max command queue depth per host controller */
+#define DWC_AHSATA_HC_MAX_CMD 32
+/* Max port number per host controller */
+#define SATA_HC_MAX_PORT 16
+
+/* Generic Host Register */
+
+/* HBA Capabilities Register */
+#define SATA_HOST_CAP_S64A 0x80000000
+#define SATA_HOST_CAP_SNCQ 0x40000000
+#define SATA_HOST_CAP_SSNTF 0x20000000
+#define SATA_HOST_CAP_SMPS 0x10000000
+#define SATA_HOST_CAP_SSS 0x08000000
+#define SATA_HOST_CAP_SALP 0x04000000
+#define SATA_HOST_CAP_SAL 0x02000000
+#define SATA_HOST_CAP_SCLO 0x01000000
+#define SATA_HOST_CAP_ISS_MASK 0x00f00000
+#define SATA_HOST_CAP_ISS_OFFSET 20
+#define SATA_HOST_CAP_SNZO 0x00080000
+#define SATA_HOST_CAP_SAM 0x00040000
+#define SATA_HOST_CAP_SPM 0x00020000
+#define SATA_HOST_CAP_PMD 0x00008000
+#define SATA_HOST_CAP_SSC 0x00004000
+#define SATA_HOST_CAP_PSC 0x00002000
+#define SATA_HOST_CAP_NCS 0x00001f00
+#define SATA_HOST_CAP_CCCS 0x00000080
+#define SATA_HOST_CAP_EMS 0x00000040
+#define SATA_HOST_CAP_SXS 0x00000020
+#define SATA_HOST_CAP_NP_MASK 0x0000001f
+
+/* Global HBA Control Register */
+#define SATA_HOST_GHC_AE 0x80000000
+#define SATA_HOST_GHC_IE 0x00000002
+#define SATA_HOST_GHC_HR 0x00000001
+
+/* Interrupt Status Register */
+
+/* Ports Implemented Register */
+
+/* AHCI Version Register */
+#define SATA_HOST_VS_MJR_MASK 0xffff0000
+#define SATA_HOST_VS_MJR_OFFSET 16
+#define SATA_HOST_VS_MJR_MNR 0x0000ffff
+
+/* Command Completion Coalescing Control */
+#define SATA_HOST_CCC_CTL_TV_MASK 0xffff0000
+#define SATA_HOST_CCC_CTL_TV_OFFSET 16
+#define SATA_HOST_CCC_CTL_CC_MASK 0x0000ff00
+#define SATA_HOST_CCC_CTL_CC_OFFSET 8
+#define SATA_HOST_CCC_CTL_INT_MASK 0x000000f8
+#define SATA_HOST_CCC_CTL_INT_OFFSET 3
+#define SATA_HOST_CCC_CTL_EN 0x00000001
+
+/* Command Completion Coalescing Ports */
+
+/* HBA Capabilities Extended Register */
+#define SATA_HOST_CAP2_APST 0x00000004
+
+/* BIST Activate FIS Register */
+#define SATA_HOST_BISTAFR_NCP_MASK 0x0000ff00
+#define SATA_HOST_BISTAFR_NCP_OFFSET 8
+#define SATA_HOST_BISTAFR_PD_MASK 0x000000ff
+#define SATA_HOST_BISTAFR_PD_OFFSET 0
+
+/* BIST Control Register */
+#define SATA_HOST_BISTCR_FERLB 0x00100000
+#define SATA_HOST_BISTCR_TXO 0x00040000
+#define SATA_HOST_BISTCR_CNTCLR 0x00020000
+#define SATA_HOST_BISTCR_NEALB 0x00010000
+#define SATA_HOST_BISTCR_LLC_MASK 0x00000700
+#define SATA_HOST_BISTCR_LLC_OFFSET 8
+#define SATA_HOST_BISTCR_ERREN 0x00000040
+#define SATA_HOST_BISTCR_FLIP 0x00000020
+#define SATA_HOST_BISTCR_PV 0x00000010
+#define SATA_HOST_BISTCR_PATTERN_MASK 0x0000000f
+#define SATA_HOST_BISTCR_PATTERN_OFFSET 0
+
+/* BIST FIS Count Register */
+
+/* BIST Status Register */
+#define SATA_HOST_BISTSR_FRAMERR_MASK 0x0000ffff
+#define SATA_HOST_BISTSR_FRAMERR_OFFSET 0
+#define SATA_HOST_BISTSR_BRSTERR_MASK 0x00ff0000
+#define SATA_HOST_BISTSR_BRSTERR_OFFSET 16
+
+/* BIST DWORD Error Count Register */
+
+/* OOB Register*/
+#define SATA_HOST_OOBR_WE 0x80000000
+#define SATA_HOST_OOBR_cwMin_MASK 0x7f000000
+#define SATA_HOST_OOBR_cwMAX_MASK 0x00ff0000
+#define SATA_HOST_OOBR_ciMin_MASK 0x0000ff00
+#define SATA_HOST_OOBR_ciMax_MASK 0x000000ff
+
+/* Timer 1-ms Register */
+
+/* Global Parameter 1 Register */
+#define SATA_HOST_GPARAM1R_ALIGN_M 0x80000000
+#define SATA_HOST_GPARAM1R_RX_BUFFER 0x40000000
+#define SATA_HOST_GPARAM1R_PHY_DATA_MASK 0x30000000
+#define SATA_HOST_GPARAM1R_PHY_RST 0x08000000
+#define SATA_HOST_GPARAM1R_PHY_CTRL_MASK 0x07e00000
+#define SATA_HOST_GPARAM1R_PHY_STAT_MASK 0x001f8000
+#define SATA_HOST_GPARAM1R_LATCH_M 0x00004000
+#define SATA_HOST_GPARAM1R_BIST_M 0x00002000
+#define SATA_HOST_GPARAM1R_PHY_TYPE 0x00001000
+#define SATA_HOST_GPARAM1R_RETURN_ERR 0x00000400
+#define SATA_HOST_GPARAM1R_AHB_ENDIAN_MASK 0x00000300
+#define SATA_HOST_GPARAM1R_S_HADDR 0X00000080
+#define SATA_HOST_GPARAM1R_M_HADDR 0X00000040
+
+/* Global Parameter 2 Register */
+#define SATA_HOST_GPARAM2R_DEV_CP 0x00004000
+#define SATA_HOST_GPARAM2R_DEV_MP 0x00002000
+#define SATA_HOST_GPARAM2R_DEV_ENCODE_M 0x00001000
+#define SATA_HOST_GPARAM2R_RXOOB_CLK_M 0x00000800
+#define SATA_HOST_GPARAM2R_RXOOB_M 0x00000400
+#define SATA_HOST_GPARAM2R_TX_OOB_M 0x00000200
+#define SATA_HOST_GPARAM2R_RXOOB_CLK_MASK 0x000001ff
+
+/* Port Parameter Register */
+#define SATA_HOST_PPARAMR_TX_MEM_M 0x00000200
+#define SATA_HOST_PPARAMR_TX_MEM_S 0x00000100
+#define SATA_HOST_PPARAMR_RX_MEM_M 0x00000080
+#define SATA_HOST_PPARAMR_RX_MEM_S 0x00000040
+#define SATA_HOST_PPARAMR_TXFIFO_DEPTH_MASK 0x00000038
+#define SATA_HOST_PPARAMR_RXFIFO_DEPTH_MASK 0x00000007
+
+/* Test Register */
+#define SATA_HOST_TESTR_PSEL_MASK 0x00070000
+#define SATA_HOST_TESTR_TEST_IF 0x00000001
+
+/* Port Register Descriptions */
+/* Port# Command List Base Address Register */
+#define SATA_PORT_CLB_CLB_MASK 0xfffffc00
+
+/* Port# Command List Base Address Upper 32-Bits Register */
+
+/* Port# FIS Base Address Register */
+#define SATA_PORT_FB_FB_MASK 0xfffffff0
+
+/* Port# FIS Base Address Upper 32-Bits Register */
+
+/* Port# Interrupt Status Register */
+#define SATA_PORT_IS_CPDS 0x80000000
+#define SATA_PORT_IS_TFES 0x40000000
+#define SATA_PORT_IS_HBFS 0x20000000
+#define SATA_PORT_IS_HBDS 0x10000000
+#define SATA_PORT_IS_IFS 0x08000000
+#define SATA_PORT_IS_INFS 0x04000000
+#define SATA_PORT_IS_OFS 0x01000000
+#define SATA_PORT_IS_IPMS 0x00800000
+#define SATA_PORT_IS_PRCS 0x00400000
+#define SATA_PORT_IS_DMPS 0x00000080
+#define SATA_PORT_IS_PCS 0x00000040
+#define SATA_PORT_IS_DPS 0x00000020
+#define SATA_PORT_IS_UFS 0x00000010
+#define SATA_PORT_IS_SDBS 0x00000008
+#define SATA_PORT_IS_DSS 0x00000004
+#define SATA_PORT_IS_PSS 0x00000002
+#define SATA_PORT_IS_DHRS 0x00000001
+
+/* Port# Interrupt Enable Register */
+#define SATA_PORT_IE_CPDE 0x80000000
+#define SATA_PORT_IE_TFEE 0x40000000
+#define SATA_PORT_IE_HBFE 0x20000000
+#define SATA_PORT_IE_HBDE 0x10000000
+#define SATA_PORT_IE_IFE 0x08000000
+#define SATA_PORT_IE_INFE 0x04000000
+#define SATA_PORT_IE_OFE 0x01000000
+#define SATA_PORT_IE_IPME 0x00800000
+#define SATA_PORT_IE_PRCE 0x00400000
+#define SATA_PORT_IE_DMPE 0x00000080
+#define SATA_PORT_IE_PCE 0x00000040
+#define SATA_PORT_IE_DPE 0x00000020
+#define SATA_PORT_IE_UFE 0x00000010
+#define SATA_PORT_IE_SDBE 0x00000008
+#define SATA_PORT_IE_DSE 0x00000004
+#define SATA_PORT_IE_PSE 0x00000002
+#define SATA_PORT_IE_DHRE 0x00000001
+
+/* Port# Command Register */
+#define SATA_PORT_CMD_ICC_MASK 0xf0000000
+#define SATA_PORT_CMD_ASP 0x08000000
+#define SATA_PORT_CMD_ALPE 0x04000000
+#define SATA_PORT_CMD_DLAE 0x02000000
+#define SATA_PORT_CMD_ATAPI 0x01000000
+#define SATA_PORT_CMD_APSTE 0x00800000
+#define SATA_PORT_CMD_ESP 0x00200000
+#define SATA_PORT_CMD_CPD 0x00100000
+#define SATA_PORT_CMD_MPSP 0x00080000
+#define SATA_PORT_CMD_HPCP 0x00040000
+#define SATA_PORT_CMD_PMA 0x00020000
+#define SATA_PORT_CMD_CPS 0x00010000
+#define SATA_PORT_CMD_CR 0x00008000
+#define SATA_PORT_CMD_FR 0x00004000
+#define SATA_PORT_CMD_MPSS 0x00002000
+#define SATA_PORT_CMD_CCS_MASK 0x00001f00
+#define SATA_PORT_CMD_FRE 0x00000010
+#define SATA_PORT_CMD_CLO 0x00000008
+#define SATA_PORT_CMD_POD 0x00000004
+#define SATA_PORT_CMD_SUD 0x00000002
+#define SATA_PORT_CMD_ST 0x00000001
+
+/* Port# Task File Data Register */
+#define SATA_PORT_TFD_ERR_MASK 0x0000ff00
+#define SATA_PORT_TFD_STS_MASK 0x000000ff
+#define SATA_PORT_TFD_STS_ERR 0x00000001
+#define SATA_PORT_TFD_STS_DRQ 0x00000008
+#define SATA_PORT_TFD_STS_BSY 0x00000080
+
+/* Port# Signature Register */
+
+/* Port# Serial ATA Status {SStatus} Register */
+#define SATA_PORT_SSTS_IPM_MASK 0x00000f00
+#define SATA_PORT_SSTS_SPD_MASK 0x000000f0
+#define SATA_PORT_SSTS_DET_MASK 0x0000000f
+
+/* Port# Serial ATA Control {SControl} Register */
+#define SATA_PORT_SCTL_IPM_MASK 0x00000f00
+#define SATA_PORT_SCTL_SPD_MASK 0x000000f0
+#define SATA_PORT_SCTL_DET_MASK 0x0000000f
+
+/* Port# Serial ATA Error {SError} Register */
+#define SATA_PORT_SERR_DIAG_X 0x04000000
+#define SATA_PORT_SERR_DIAG_F 0x02000000
+#define SATA_PORT_SERR_DIAG_T 0x01000000
+#define SATA_PORT_SERR_DIAG_S 0x00800000
+#define SATA_PORT_SERR_DIAG_H 0x00400000
+#define SATA_PORT_SERR_DIAG_C 0x00200000
+#define SATA_PORT_SERR_DIAG_D 0x00100000
+#define SATA_PORT_SERR_DIAG_B 0x00080000
+#define SATA_PORT_SERR_DIAG_W 0x00040000
+#define SATA_PORT_SERR_DIAG_I 0x00020000
+#define SATA_PORT_SERR_DIAG_N 0x00010000
+#define SATA_PORT_SERR_ERR_E 0x00000800
+#define SATA_PORT_SERR_ERR_P 0x00000400
+#define SATA_PORT_SERR_ERR_C 0x00000200
+#define SATA_PORT_SERR_ERR_T 0x00000100
+#define SATA_PORT_SERR_ERR_M 0x00000002
+#define SATA_PORT_SERR_ERR_I 0x00000001
+
+/* Port# Serial ATA Active {SActive} Register */
+
+/* Port# Command Issue Register */
+
+/* Port# Serial ATA Notification Register */
+
+/* Port# DMA Control Register */
+#define SATA_PORT_DMACR_RXABL_MASK 0x0000f000
+#define SATA_PORT_DMACR_TXABL_MASK 0x00000f00
+#define SATA_PORT_DMACR_RXTS_MASK 0x000000f0
+#define SATA_PORT_DMACR_TXTS_MASK 0x0000000f
+
+/* Port# PHY Control Register */
+
+/* Port# PHY Status Register */
+
+#define SATA_HC_CMD_HDR_ENTRY_SIZE sizeof(struct cmd_hdr_entry)
+
+/* DW0
+*/
+#define CMD_HDR_DI_CFL_MASK 0x0000001f
+#define CMD_HDR_DI_CFL_OFFSET 0
+#define CMD_HDR_DI_A 0x00000020
+#define CMD_HDR_DI_W 0x00000040
+#define CMD_HDR_DI_P 0x00000080
+#define CMD_HDR_DI_R 0x00000100
+#define CMD_HDR_DI_B 0x00000200
+#define CMD_HDR_DI_C 0x00000400
+#define CMD_HDR_DI_PMP_MASK 0x0000f000
+#define CMD_HDR_DI_PMP_OFFSET 12
+#define CMD_HDR_DI_PRDTL 0xffff0000
+#define CMD_HDR_DI_PRDTL_OFFSET 16
+
+/* 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 */
+/* Snoop enable for all descriptor */
+#define CMD_HDR_ATTR_SNOOP 0x00000200
+#define CMD_HDR_ATTR_FPDMA 0x00000100 /* FPDMA queued command */
+#define CMD_HDR_ATTR_RESET 0x00000080 /* Reset - a SRST or device reset */
+/* BIST - require the host to enter BIST mode */
+#define CMD_HDR_ATTR_BIST 0x00000040
+#define CMD_HDR_ATTR_ATAPI 0x00000020 /* ATAPI command */
+#define CMD_HDR_ATTR_TAG 0x0000001f   /* TAG mask */
+
+#define FLAGS_DMA 0x00000000
+#define FLAGS_FPDMA 0x00000001
+
+#define SATA_FLAG_Q_DEP_MASK 0x0000000f
+#define SATA_FLAG_WCACHE 0x00000100
+#define SATA_FLAG_FLUSH 0x00000200
+#define SATA_FLAG_FLUSH_EXT 0x00000400
+
+#define READ_CMD 0
+#define WRITE_CMD 1
+
+#endif /* __DWC_AHSATA_H__ */

+ 152 - 0
bsp/ls2kdev/drivers/ata/fis.h

@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-08-19     lizhirui     porting to ls2k
+ */
+
+#ifndef __FIS_H__
+#define __FIS_H__
+/*
+* Register - Host to Device FIS
+*/
+typedef struct sata_fis_h2d
+{
+    u8 fis_type;
+    u8 pm_port_c;
+    u8 command;
+    u8 features;
+    u8 lba_low;
+    u8 lba_mid;
+    u8 lba_high;
+    u8 device;
+    u8 lba_low_exp;
+    u8 lba_mid_exp;
+    u8 lba_high_exp;
+    u8 features_exp;
+    u8 sector_count;
+    u8 sector_count_exp;
+    u8 res1;
+    u8 control;
+    u8 res2[4];
+} __attribute__((packed)) sata_fis_h2d_t;
+
+/*
+* Register - Host to Device FIS for read/write FPDMA queued
+*/
+typedef struct sata_fis_h2d_ncq
+{
+    u8 fis_type;
+    u8 pm_port_c;
+    u8 command;
+    u8 sector_count_low;
+    u8 lba_low;
+    u8 lba_mid;
+    u8 lba_high;
+    u8 device;
+    u8 lba_low_exp;
+    u8 lba_mid_exp;
+    u8 lba_high_exp;
+    u8 sector_count_high;
+    u8 tag;
+    u8 res1;
+    u8 res2;
+    u8 control;
+    u8 res3[4];
+} __attribute__((packed)) sata_fis_h2d_ncq_t;
+
+/*
+* Register - Device to Host FIS
+*/
+typedef struct sata_fis_d2h
+{
+    u8 fis_type;
+    u8 pm_port_i;
+    u8 status;
+    u8 error;
+    u8 lba_low;
+    u8 lba_mid;
+    u8 lba_high;
+    u8 device;
+    u8 lba_low_exp;
+    u8 lba_mid_exp;
+    u8 lba_high_exp;
+    u8 res1;
+    u8 sector_count;
+    u8 sector_count_exp;
+    u8 res2[2];
+    u8 res3[4];
+} __attribute__((packed)) sata_fis_d2h_t;
+
+/*
+* DMA Setup - Device to Host or Host to Device FIS
+*/
+typedef struct sata_fis_dma_setup
+{
+    u8 fis_type;
+    u8 pm_port_dir_int_act;
+    u8 res1;
+    u8 res2;
+    u32 dma_buffer_id_low;
+    u32 dma_buffer_id_high;
+    u32 res3;
+    u32 dma_buffer_offset;
+    u32 dma_transfer_count;
+    u32 res4;
+} __attribute__((packed)) sata_fis_dma_setup_t;
+
+/*
+* PIO Setup - Device to Host FIS
+*/
+typedef struct sata_fis_pio_setup
+{
+    u8 fis_type;
+    u8 pm_port_dir_int;
+    u8 status;
+    u8 error;
+    u8 lba_low;
+    u8 lba_mid;
+    u8 lba_high;
+    u8 res1;
+    u8 lba_low_exp;
+    u8 lba_mid_exp;
+    u8 lba_high_exp;
+    u8 res2;
+    u8 sector_count;
+    u8 sector_count_exp;
+    u8 res3;
+    u8 e_status;
+    u16 transfer_count;
+    u16 res4;
+} __attribute__((packed)) sata_fis_pio_setup_t;
+
+/*
+* Data - Host to Device or Device to Host FIS
+*/
+typedef struct sata_fis_data
+{
+    u8 fis_type;
+    u8 pm_port;
+    u8 res1;
+    u8 res2;
+    u32 data[2048];
+} __attribute__((packed)) sata_fis_data_t;
+
+/* fis_type - SATA FIS type
+ */
+enum sata_fis_type
+{
+    SATA_FIS_TYPE_REGISTER_H2D = 0x27,
+    SATA_FIS_TYPE_REGISTER_D2H = 0x34,
+    SATA_FIS_TYPE_DMA_ACT_D2H = 0x39,
+    SATA_FIS_TYPE_DMA_SETUP_BI = 0x41,
+    SATA_FIS_TYPE_DATA_BI = 0x46,
+    SATA_FIS_TYPE_BIST_ACT_BI = 0x58,
+    SATA_FIS_TYPE_PIO_SETUP_D2H = 0x5F,
+    SATA_FIS_TYPE_SET_DEVICE_BITS_D2H = 0xA1,
+};
+
+#endif /* __FIS_H__ */

+ 150 - 0
bsp/ls2kdev/drivers/ata/libata.c

@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-08-19     lizhirui     porting to ls2k
+ */
+
+#include <rtthread.h>
+#include <ata_interface.h>
+#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]);
+    }
+}

+ 653 - 0
bsp/ls2kdev/drivers/ata/libata.h

@@ -0,0 +1,653 @@
+/*
+ * Copyright (c) 2006-2020, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-08-19     lizhirui     porting to ls2k
+ */
+
+#ifndef __LIBATA_H__
+#define __LIBATA_H__
+
+enum {
+    /* various global constants */
+    ATA_MAX_DEVICES        = 2,    /* per bus/port */
+    ATA_MAX_PRD        = 256,    /* we could make these 256/256 */
+    ATA_SECT_SIZE        = 512,
+    ATA_MAX_SECTORS_128    = 128,
+    ATA_MAX_SECTORS        = 256,
+    ATA_MAX_SECTORS_LBA48    = 65535,
+    ATA_MAX_SECTORS_TAPE    = 65535,
+
+    ATA_ID_WORDS        = 256,
+    ATA_ID_SERNO        = 10,
+    ATA_ID_FW_REV        = 23,
+    ATA_ID_PROD        = 27,
+    ATA_ID_OLD_PIO_MODES    = 51,
+    ATA_ID_FIELD_VALID    = 53,
+    ATA_ID_LBA_SECTORS    = 60,
+    ATA_ID_MWDMA_MODES    = 63,
+    ATA_ID_PIO_MODES    = 64,
+    ATA_ID_EIDE_DMA_MIN    = 65,
+    ATA_ID_EIDE_PIO        = 67,
+    ATA_ID_EIDE_PIO_IORDY    = 68,
+    ATA_ID_PIO4        = (1 << 1),
+    ATA_ID_QUEUE_DEPTH    = 75,
+    ATA_ID_SATA_CAP        = 76,
+    ATA_ID_SATA_FEATURES    = 78,
+    ATA_ID_SATA_FEATURES_EN    = 79,
+    ATA_ID_MAJOR_VER    = 80,
+    ATA_ID_MINOR_VER    = 81,
+    ATA_ID_UDMA_MODES    = 88,
+    ATA_ID_LBA48_SECTORS    = 100,
+
+    ATA_ID_SERNO_LEN    = 20,
+    ATA_ID_FW_REV_LEN    = 8,
+    ATA_ID_PROD_LEN        = 40,
+
+    ATA_PCI_CTL_OFS        = 2,
+
+    ATA_PIO0        = (1 << 0),
+    ATA_PIO1        = ATA_PIO0 | (1 << 1),
+    ATA_PIO2        = ATA_PIO1 | (1 << 2),
+    ATA_PIO3        = ATA_PIO2 | (1 << 3),
+    ATA_PIO4        = ATA_PIO3 | (1 << 4),
+    ATA_PIO5        = ATA_PIO4 | (1 << 5),
+    ATA_PIO6        = ATA_PIO5 | (1 << 6),
+
+    ATA_SWDMA0        = (1 << 0),
+    ATA_SWDMA1        = ATA_SWDMA0 | (1 << 1),
+    ATA_SWDMA2        = ATA_SWDMA1 | (1 << 2),
+
+    ATA_SWDMA2_ONLY        = (1 << 2),
+
+    ATA_MWDMA0        = (1 << 0),
+    ATA_MWDMA1        = ATA_MWDMA0 | (1 << 1),
+    ATA_MWDMA2        = ATA_MWDMA1 | (1 << 2),
+
+    ATA_MWDMA12_ONLY    = (1 << 1) | (1 << 2),
+    ATA_MWDMA2_ONLY        = (1 << 2),
+
+    ATA_UDMA0        = (1 << 0),
+    ATA_UDMA1        = ATA_UDMA0 | (1 << 1),
+    ATA_UDMA2        = ATA_UDMA1 | (1 << 2),
+    ATA_UDMA3        = ATA_UDMA2 | (1 << 3),
+    ATA_UDMA4        = ATA_UDMA3 | (1 << 4),
+    ATA_UDMA5        = ATA_UDMA4 | (1 << 5),
+    ATA_UDMA6        = ATA_UDMA5 | (1 << 6),
+    ATA_UDMA7        = ATA_UDMA6 | (1 << 7),
+    /* ATA_UDMA7 is just for completeness... doesn't exist (yet?).  */
+
+    ATA_UDMA_MASK_40C    = ATA_UDMA2,    /* udma0-2 */
+
+    /* DMA-related */
+    ATA_PRD_SZ        = 8,
+    ATA_PRD_TBL_SZ        = (ATA_MAX_PRD * ATA_PRD_SZ),
+    ATA_PRD_EOT        = (1 << 31),    /* end-of-table flag */
+
+    ATA_DMA_TABLE_OFS    = 4,
+    ATA_DMA_STATUS        = 2,
+    ATA_DMA_CMD        = 0,
+    ATA_DMA_WR        = (1 << 3),
+    ATA_DMA_START        = (1 << 0),
+    ATA_DMA_INTR        = (1 << 2),
+    ATA_DMA_ERR        = (1 << 1),
+    ATA_DMA_ACTIVE        = (1 << 0),
+
+    /* bits in ATA command block registers */
+    ATA_HOB            = (1 << 7),    /* LBA48 selector */
+    ATA_NIEN        = (1 << 1),    /* disable-irq flag */
+    ATA_LBA            = (1 << 6),    /* LBA28 selector */
+    ATA_DEV1        = (1 << 4),    /* Select Device 1 (slave) */
+    ATA_DEVICE_OBS        = (1 << 7) | (1 << 5), /* obs bits in dev reg */
+    ATA_DEVCTL_OBS        = (1 << 3),    /* obsolete bit in devctl reg */
+    ATA_BUSY        = (1 << 7),    /* BSY status bit */
+    ATA_DRDY        = (1 << 6),    /* device ready */
+    ATA_DF            = (1 << 5),    /* device fault */
+    ATA_DRQ            = (1 << 3),    /* data request i/o */
+    ATA_ERR            = (1 << 0),    /* have an error */
+    ATA_SRST        = (1 << 2),    /* software reset */
+    ATA_ICRC        = (1 << 7),    /* interface CRC error */
+    ATA_UNC            = (1 << 6),    /* uncorrectable media error */
+    ATA_IDNF        = (1 << 4),    /* ID not found */
+    ATA_ABORTED        = (1 << 2),    /* command aborted */
+
+    /* ATA command block registers */
+    ATA_REG_DATA        = 0x00,
+    ATA_REG_ERR        = 0x01,
+    ATA_REG_NSECT        = 0x02,
+    ATA_REG_LBAL        = 0x03,
+    ATA_REG_LBAM        = 0x04,
+    ATA_REG_LBAH        = 0x05,
+    ATA_REG_DEVICE        = 0x06,
+    ATA_REG_STATUS        = 0x07,
+
+    ATA_REG_FEATURE        = ATA_REG_ERR, /* and their aliases */
+    ATA_REG_CMD        = ATA_REG_STATUS,
+    ATA_REG_BYTEL        = ATA_REG_LBAM,
+    ATA_REG_BYTEH        = ATA_REG_LBAH,
+    ATA_REG_DEVSEL        = ATA_REG_DEVICE,
+    ATA_REG_IRQ        = ATA_REG_NSECT,
+
+    /* ATA device commands */
+    ATA_CMD_DEV_RESET        = 0x08, /* ATAPI device reset */
+    ATA_CMD_PIO_READ        = 0x20, /* Read sectors with retry */
+    ATA_CMD_PIO_READ_EXT        = 0x24,
+    ATA_CMD_READ_EXT        = 0x25,
+    ATA_CMD_READ_NATIVE_MAX_EXT = 0x27,
+    ATA_CMD_READ_MULTI_EXT        = 0x29,
+    ATA_CMD_READ_LOG_EXT        = 0x2f,
+    ATA_CMD_PIO_WRITE        = 0x30, /* write sectors with retry */
+    ATA_CMD_PIO_WRITE_EXT        = 0x34,
+    ATA_CMD_WRITE_EXT        = 0x35,
+    ATA_CMD_SET_MAX_EXT        = 0x37,
+    ATA_CMD_WRITE_MULTI_EXT        = 0x39,
+    ATA_CMD_WRITE_FUA_EXT        = 0x3D,
+    ATA_CMD_VERIFY            = 0x40, /* read verify sectors with retry */
+    ATA_CMD_VERIFY_EXT        = 0x42,
+    ATA_CMD_FPDMA_READ        = 0x60,
+    ATA_CMD_FPDMA_WRITE        = 0x61,
+    ATA_CMD_EDD            = 0x90, /* execute device diagnostic */
+    ATA_CMD_INIT_DEV_PARAMS        = 0x91, /* initialize device parameters */
+    ATA_CMD_PACKET            = 0xA0, /* ATAPI packet */
+    ATA_CMD_ID_ATAPI        = 0xA1, /* ATAPI identify device */
+    ATA_CMD_CONF_OVERLAY        = 0xB1,
+    ATA_CMD_READ_MULTI        = 0xC4, /* read multiple */
+    ATA_CMD_WRITE_MULTI        = 0xC5, /* write multiple */
+    ATA_CMD_SET_MULTI        = 0xC6, /* set multiple mode */
+    ATA_CMD_READ            = 0xC8, /* read DMA with retry */
+    ATA_CMD_WRITE            = 0xCA, /* write DMA with retry */
+    ATA_CMD_WRITE_MULTI_FUA_EXT = 0xCE,
+    ATA_CMD_STANDBYNOW1        = 0xE0, /* standby immediate */
+    ATA_CMD_IDLEIMMEDIATE        = 0xE1, /* idle immediate */
+    ATA_CMD_STANDBY            = 0xE2, /* place in standby power mode */
+    ATA_CMD_IDLE            = 0xE3, /* place in idle power mode */
+    ATA_CMD_PMP_READ        = 0xE4, /* read buffer */
+    ATA_CMD_CHK_POWER        = 0xE5, /* check power mode */
+    ATA_CMD_SLEEP            = 0xE6, /* sleep */
+    ATA_CMD_FLUSH            = 0xE7,
+    ATA_CMD_PMP_WRITE        = 0xE8, /* write buffer */
+    ATA_CMD_FLUSH_EXT        = 0xEA,
+    ATA_CMD_ID_ATA            = 0xEC, /* identify device */
+    ATA_CMD_SET_FEATURES        = 0xEF, /* set features */
+    ATA_CMD_SEC_FREEZE_LOCK        = 0xF5, /* security freeze */
+    ATA_CMD_READ_NATIVE_MAX        = 0xF8,
+    ATA_CMD_SET_MAX            = 0xF9,
+
+    /* READ_LOG_EXT pages */
+    ATA_LOG_SATA_NCQ    = 0x10,
+
+    /* READ/WRITE LONG (obsolete) */
+    ATA_CMD_READ_LONG    = 0x22,
+    ATA_CMD_READ_LONG_ONCE    = 0x23,
+    ATA_CMD_WRITE_LONG    = 0x32,
+    ATA_CMD_WRITE_LONG_ONCE    = 0x33,
+
+    /* SETFEATURES stuff */
+    SETFEATURES_XFER    = 0x03,
+    XFER_UDMA_7        = 0x47,
+    XFER_UDMA_6        = 0x46,
+    XFER_UDMA_5        = 0x45,
+    XFER_UDMA_4        = 0x44,
+    XFER_UDMA_3        = 0x43,
+    XFER_UDMA_2        = 0x42,
+    XFER_UDMA_1        = 0x41,
+    XFER_UDMA_0        = 0x40,
+    XFER_MW_DMA_4        = 0x24,    /* CFA only */
+    XFER_MW_DMA_3        = 0x23,    /* CFA only */
+    XFER_MW_DMA_2        = 0x22,
+    XFER_MW_DMA_1        = 0x21,
+    XFER_MW_DMA_0        = 0x20,
+    XFER_SW_DMA_2        = 0x12,
+    XFER_SW_DMA_1        = 0x11,
+    XFER_SW_DMA_0        = 0x10,
+    XFER_PIO_6        = 0x0E,    /* CFA only */
+    XFER_PIO_5        = 0x0D,    /* CFA only */
+    XFER_PIO_4        = 0x0C,
+    XFER_PIO_3        = 0x0B,
+    XFER_PIO_2        = 0x0A,
+    XFER_PIO_1        = 0x09,
+    XFER_PIO_0        = 0x08,
+    XFER_PIO_SLOW        = 0x00,
+
+    SETFEATURES_WC_ON    = 0x02, /* Enable write cache */
+    SETFEATURES_WC_OFF    = 0x82, /* Disable write cache */
+
+    SETFEATURES_SPINUP    = 0x07, /* Spin-up drive */
+
+    SETFEATURES_SATA_ENABLE = 0x10, /* Enable use of SATA feature */
+    SETFEATURES_SATA_DISABLE = 0x90, /* Disable use of SATA feature */
+
+    /* SETFEATURE Sector counts for SATA features */
+    SATA_AN            = 0x05,  /* Asynchronous Notification */
+    SATA_DIPM        = 0x03,  /* Device Initiated Power Management */
+
+    /* feature values for SET_MAX */
+    ATA_SET_MAX_ADDR    = 0x00,
+    ATA_SET_MAX_PASSWD    = 0x01,
+    ATA_SET_MAX_LOCK    = 0x02,
+    ATA_SET_MAX_UNLOCK    = 0x03,
+    ATA_SET_MAX_FREEZE_LOCK    = 0x04,
+
+    /* feature values for DEVICE CONFIGURATION OVERLAY */
+    ATA_DCO_RESTORE        = 0xC0,
+    ATA_DCO_FREEZE_LOCK    = 0xC1,
+    ATA_DCO_IDENTIFY    = 0xC2,
+    ATA_DCO_SET        = 0xC3,
+
+    /* ATAPI stuff */
+    ATAPI_PKT_DMA        = (1 << 0),
+    ATAPI_DMADIR        = (1 << 2),    /* ATAPI data dir:
+                           0=to device, 1=to host */
+    ATAPI_CDB_LEN        = 16,
+
+    /* PMP stuff */
+    SATA_PMP_MAX_PORTS    = 15,
+    SATA_PMP_CTRL_PORT    = 15,
+
+    SATA_PMP_GSCR_DWORDS    = 128,
+    SATA_PMP_GSCR_PROD_ID    = 0,
+    SATA_PMP_GSCR_REV    = 1,
+    SATA_PMP_GSCR_PORT_INFO    = 2,
+    SATA_PMP_GSCR_ERROR    = 32,
+    SATA_PMP_GSCR_ERROR_EN    = 33,
+    SATA_PMP_GSCR_FEAT    = 64,
+    SATA_PMP_GSCR_FEAT_EN    = 96,
+
+    SATA_PMP_PSCR_STATUS    = 0,
+    SATA_PMP_PSCR_ERROR    = 1,
+    SATA_PMP_PSCR_CONTROL    = 2,
+
+    SATA_PMP_FEAT_BIST    = (1 << 0),
+    SATA_PMP_FEAT_PMREQ    = (1 << 1),
+    SATA_PMP_FEAT_DYNSSC    = (1 << 2),
+    SATA_PMP_FEAT_NOTIFY    = (1 << 3),
+
+    /* cable types */
+    ATA_CBL_NONE        = 0,
+    ATA_CBL_PATA40        = 1,
+    ATA_CBL_PATA80        = 2,
+    ATA_CBL_PATA40_SHORT    = 3,    /* 40 wire cable to high UDMA spec */
+    ATA_CBL_PATA_UNK    = 4,    /* don't know, maybe 80c? */
+    ATA_CBL_PATA_IGN    = 5,    /* don't know, ignore cable handling */
+    ATA_CBL_SATA        = 6,
+
+    /* SATA Status and Control Registers */
+    SCR_STATUS        = 0,
+    SCR_ERROR        = 1,
+    SCR_CONTROL        = 2,
+    SCR_ACTIVE        = 3,
+    SCR_NOTIFICATION    = 4,
+
+    /* SError bits */
+    SERR_DATA_RECOVERED    = (1 << 0), /* recovered data error */
+    SERR_COMM_RECOVERED    = (1 << 1), /* recovered comm failure */
+    SERR_DATA        = (1 << 8), /* unrecovered data error */
+    SERR_PERSISTENT        = (1 << 9), /* persistent data/comm error */
+    SERR_PROTOCOL        = (1 << 10), /* protocol violation */
+    SERR_INTERNAL        = (1 << 11), /* host internal error */
+    SERR_PHYRDY_CHG        = (1 << 16), /* PHY RDY changed */
+    SERR_PHY_INT_ERR    = (1 << 17), /* PHY internal error */
+    SERR_COMM_WAKE        = (1 << 18), /* Comm wake */
+    SERR_10B_8B_ERR        = (1 << 19), /* 10b to 8b decode error */
+    SERR_DISPARITY        = (1 << 20), /* Disparity */
+    SERR_CRC        = (1 << 21), /* CRC error */
+    SERR_HANDSHAKE        = (1 << 22), /* Handshake error */
+    SERR_LINK_SEQ_ERR    = (1 << 23), /* Link sequence error */
+    SERR_TRANS_ST_ERROR    = (1 << 24), /* Transport state trans. error */
+    SERR_UNRECOG_FIS    = (1 << 25), /* Unrecognized FIS */
+    SERR_DEV_XCHG        = (1 << 26), /* device exchanged */
+
+    /* struct ata_taskfile flags */
+    ATA_TFLAG_LBA48        = (1 << 0), /* enable 48-bit LBA and "HOB" */
+    ATA_TFLAG_ISADDR    = (1 << 1), /* enable r/w to nsect/lba regs */
+    ATA_TFLAG_DEVICE    = (1 << 2), /* enable r/w to device reg */
+    ATA_TFLAG_WRITE        = (1 << 3), /* data dir: host->dev==1 (write) */
+    ATA_TFLAG_LBA        = (1 << 4), /* enable LBA */
+    ATA_TFLAG_FUA        = (1 << 5), /* enable FUA */
+    ATA_TFLAG_POLLING    = (1 << 6), /* set nIEN to 1 and use polling */
+
+    /* protocol flags */
+    ATA_PROT_FLAG_PIO    = (1 << 0), /* is PIO */
+    ATA_PROT_FLAG_DMA    = (1 << 1), /* is DMA */
+    ATA_PROT_FLAG_DATA    = ATA_PROT_FLAG_PIO | ATA_PROT_FLAG_DMA,
+    ATA_PROT_FLAG_NCQ    = (1 << 2), /* is NCQ */
+    ATA_PROT_FLAG_ATAPI    = (1 << 3), /* is ATAPI */
+};
+
+enum ata_tf_protocols {
+    /* ATA taskfile protocols */
+    ATA_PROT_UNKNOWN,    /* unknown/invalid */
+    ATA_PROT_NODATA,    /* no data */
+    ATA_PROT_PIO,        /* PIO data xfer */
+    ATA_PROT_DMA,        /* DMA */
+    ATA_PROT_NCQ,        /* NCQ */
+    ATAPI_PROT_NODATA,    /* packet command, no data */
+    ATAPI_PROT_PIO,        /* packet command, PIO data xfer*/
+    ATAPI_PROT_DMA,        /* packet command with special DMA sauce */
+};
+
+enum ata_ioctls {
+    ATA_IOC_GET_IO32    = 0x309,
+    ATA_IOC_SET_IO32    = 0x324,
+};
+
+enum ata_dev_typed {
+    ATA_DEV_ATA,        /* ATA device */
+    ATA_DEV_ATAPI,        /* ATAPI device */
+    ATA_DEV_PMP,        /* Port Multiplier Port */
+    ATA_DEV_UNKNOWN,    /* unknown */
+};
+
+struct ata_taskfile {
+    unsigned long        flags;        /* ATA_TFLAG_xxx */
+    u8            protocol;    /* ATA_PROT_xxx */
+
+    u8            ctl;        /* control reg */
+
+    u8            hob_feature;    /* additional data */
+    u8            hob_nsect;    /* to support LBA48 */
+    u8            hob_lbal;
+    u8            hob_lbam;
+    u8            hob_lbah;
+
+    u8            feature;
+    u8            nsect;
+    u8            lbal;
+    u8            lbam;
+    u8            lbah;
+
+    u8            device;
+
+    u8            command;    /* IO operation */
+};
+
+/*
+ * protocol tests
+ */
+static inline unsigned int ata_prot_flags(u8 prot)
+{
+    switch (prot) {
+    case ATA_PROT_NODATA:
+        return 0;
+    case ATA_PROT_PIO:
+        return ATA_PROT_FLAG_PIO;
+    case ATA_PROT_DMA:
+        return ATA_PROT_FLAG_DMA;
+    case ATA_PROT_NCQ:
+        return ATA_PROT_FLAG_DMA | ATA_PROT_FLAG_NCQ;
+    case ATAPI_PROT_NODATA:
+        return ATA_PROT_FLAG_ATAPI;
+    case ATAPI_PROT_PIO:
+        return ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_PIO;
+    case ATAPI_PROT_DMA:
+        return ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_DMA;
+    }
+    return 0;
+}
+
+static inline int ata_is_atapi(u8 prot)
+{
+    return ata_prot_flags(prot) & ATA_PROT_FLAG_ATAPI;
+}
+
+static inline int ata_is_nodata(u8 prot)
+{
+    return !(ata_prot_flags(prot) & ATA_PROT_FLAG_DATA);
+}
+
+static inline int ata_is_pio(u8 prot)
+{
+    return ata_prot_flags(prot) & ATA_PROT_FLAG_PIO;
+}
+
+static inline int ata_is_dma(u8 prot)
+{
+    return ata_prot_flags(prot) & ATA_PROT_FLAG_DMA;
+}
+
+static inline int ata_is_ncq(u8 prot)
+{
+    return ata_prot_flags(prot) & ATA_PROT_FLAG_NCQ;
+}
+
+static inline int ata_is_data(u8 prot)
+{
+    return ata_prot_flags(prot) & ATA_PROT_FLAG_DATA;
+}
+
+/*
+ * id tests
+ */
+#define ata_id_is_ata(id)        (((id)[0] & (1 << 15)) == 0)
+#define ata_id_has_lba(id)        ((id)[49] & (1 << 9))
+#define ata_id_has_dma(id)        ((id)[49] & (1 << 8))
+#define ata_id_has_ncq(id)        ((id)[76] & (1 << 8))
+#define ata_id_queue_depth(id)        (((id)[75] & 0x1f) + 1)
+#define ata_id_removeable(id)        ((id)[0] & (1 << 7))
+#define ata_id_iordy_disable(id)    ((id)[49] & (1 << 10))
+#define ata_id_has_iordy(id)        ((id)[49] & (1 << 11))
+
+#define ata_id_u32(id,n)    \
+    (((u32) (id)[(n) + 1] << 16) | ((u32) (id)[(n)]))
+#define ata_id_u64(id,n)    \
+    ( ((u64) (id)[(n) + 3] << 48) | \
+      ((u64) (id)[(n) + 2] << 32) | \
+      ((u64) (id)[(n) + 1] << 16) | \
+      ((u64) (id)[(n) + 0]) )
+
+#define ata_id_cdb_intr(id)        (((id)[0] & 0x60) == 0x20)
+
+static inline int ata_id_has_fua(const u16 *id)
+{
+    if ((id[84] & 0xC000) != 0x4000)
+        return 0;
+    return id[84] & (1 << 6);
+}
+
+static inline int ata_id_has_flush(const u16 *id)
+{
+    if ((id[83] & 0xC000) != 0x4000)
+        return 0;
+    return id[83] & (1 << 12);
+}
+
+static inline int ata_id_has_flush_ext(const u16 *id)
+{
+    if ((id[83] & 0xC000) != 0x4000)
+        return 0;
+    return id[83] & (1 << 13);
+}
+
+static inline int ata_id_has_lba48(const u16 *id)
+{
+    if ((id[83] & 0xC000) != 0x4000)
+        return 0;
+    if (!ata_id_u64(id, 100))
+        return 0;
+    return id[83] & (1 << 10);
+}
+
+static inline int ata_id_hpa_enabled(const u16 *id)
+{
+    /* Yes children, word 83 valid bits cover word 82 data */
+    if ((id[83] & 0xC000) != 0x4000)
+        return 0;
+    /* And 87 covers 85-87 */
+    if ((id[87] & 0xC000) != 0x4000)
+        return 0;
+    /* Check command sets enabled as well as supported */
+    if ((id[85] & ( 1 << 10)) == 0)
+        return 0;
+    return id[82] & (1 << 10);
+}
+
+static inline int ata_id_has_wcache(const u16 *id)
+{
+    /* Yes children, word 83 valid bits cover word 82 data */
+    if ((id[83] & 0xC000) != 0x4000)
+        return 0;
+    return id[82] & (1 << 5);
+}
+
+static inline int ata_id_has_pm(const u16 *id)
+{
+    if ((id[83] & 0xC000) != 0x4000)
+        return 0;
+    return id[82] & (1 << 3);
+}
+
+static inline int ata_id_rahead_enabled(const u16 *id)
+{
+    if ((id[87] & 0xC000) != 0x4000)
+        return 0;
+    return id[85] & (1 << 6);
+}
+
+static inline int ata_id_wcache_enabled(const u16 *id)
+{
+    if ((id[87] & 0xC000) != 0x4000)
+        return 0;
+    return id[85] & (1 << 5);
+}
+
+static inline unsigned int ata_id_major_version(const u16 *id)
+{
+    unsigned int mver;
+
+    if (id[ATA_ID_MAJOR_VER] == 0xFFFF)
+        return 0;
+
+    for (mver = 14; mver >= 1; mver--)
+        if (id[ATA_ID_MAJOR_VER] & (1 << mver))
+            break;
+    return mver;
+}
+
+static inline int ata_id_is_sata(const u16 *id)
+{
+    return ata_id_major_version(id) >= 5 && id[93] == 0;
+}
+
+static inline int ata_id_has_tpm(const u16 *id)
+{
+    /* The TPM bits are only valid on ATA8 */
+    if (ata_id_major_version(id) < 8)
+        return 0;
+    if ((id[48] & 0xC000) != 0x4000)
+        return 0;
+    return id[48] & (1 << 0);
+}
+
+static inline int ata_id_has_dword_io(const u16 *id)
+{
+    /* ATA 8 reuses this flag for "trusted" computing */
+    if (ata_id_major_version(id) > 7)
+        return 0;
+    if (id[48] & (1 << 0))
+        return 1;
+    return 0;
+}
+
+static inline int ata_id_current_chs_valid(const u16 *id)
+{
+    /* For ATA-1 devices, if the INITIALIZE DEVICE PARAMETERS command
+       has not been issued to the device then the values of
+       id[54] to id[56] are vendor specific. */
+    return (id[53] & 0x01) && /* Current translation valid */
+        id[54] &&  /* cylinders in current translation */
+        id[55] &&  /* heads in current translation */
+        id[55] <= 16 &&
+        id[56];    /* sectors in current translation */
+}
+
+static inline int ata_id_is_cfa(const u16 *id)
+{
+    u16 v = id[0];
+    if (v == 0x848A)    /* Standard CF */
+        return 1;
+    /* Could be CF hiding as standard ATA */
+    if (ata_id_major_version(id) >= 3 &&  id[82] != 0xFFFF &&
+            (id[82] & ( 1 << 2)))
+        return 1;
+    return 0;
+}
+
+static inline int ata_drive_40wire(const u16 *dev_id)
+{
+    if (ata_id_is_sata(dev_id))
+        return 0;    /* SATA */
+    if ((dev_id[93] & 0xE000) == 0x6000)
+        return 0;    /* 80 wire */
+    return 1;
+}
+
+static inline int ata_drive_40wire_relaxed(const u16 *dev_id)
+{
+    if ((dev_id[93] & 0x2000) == 0x2000)
+        return 0;    /* 80 wire */
+    return 1;
+}
+
+static inline int atapi_cdb_len(const u16 *dev_id)
+{
+    u16 tmp = dev_id[0] & 0x3;
+    switch (tmp) {
+    case 0:        return 12;
+    case 1:        return 16;
+    default:    return -1;
+    }
+}
+
+static inline int atapi_command_packet_set(const u16 *dev_id)
+{
+    return (dev_id[0] >> 8) & 0x1f;
+}
+
+static inline int atapi_id_dmadir(const u16 *dev_id)
+{
+    return ata_id_major_version(dev_id) >= 7 && (dev_id[62] & 0x8000);
+}
+
+static inline int is_multi_taskfile(struct ata_taskfile *tf)
+{
+    return (tf->command == ATA_CMD_READ_MULTI) ||
+           (tf->command == ATA_CMD_WRITE_MULTI) ||
+           (tf->command == ATA_CMD_READ_MULTI_EXT) ||
+           (tf->command == ATA_CMD_WRITE_MULTI_EXT) ||
+           (tf->command == ATA_CMD_WRITE_MULTI_FUA_EXT);
+}
+
+static inline int ata_ok(u8 status)
+{
+    return ((status & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ | ATA_ERR))
+            == ATA_DRDY);
+}
+
+static inline int lba_28_ok(u64 block, u32 n_block)
+{
+    /* check the ending block number */
+    return ((block + n_block - 1) < ((u64)1 << 28)) && (n_block <= 256);
+}
+
+static inline int lba_48_ok(u64 block, u32 n_block)
+{
+    /* check the ending block number */
+    return ((block + n_block - 1) < ((u64)1 << 48)) && (n_block <= 65536);
+}
+
+#define sata_pmp_gscr_vendor(gscr)    ((gscr)[SATA_PMP_GSCR_PROD_ID] & 0xffff)
+#define sata_pmp_gscr_devid(gscr)    ((gscr)[SATA_PMP_GSCR_PROD_ID] >> 16)
+#define sata_pmp_gscr_rev(gscr)        (((gscr)[SATA_PMP_GSCR_REV] >> 8) & 0xff)
+#define sata_pmp_gscr_ports(gscr)    ((gscr)[SATA_PMP_GSCR_PORT_INFO] & 0xf)
+
+u64 ata_id_n_sectors(u16 *id);
+u32 ata_dev_classify(u32 sig);
+void ata_id_c_string(const u16 *id, unsigned char *s,
+             unsigned int ofs, unsigned int len);
+void ata_dump_id(u16 *id);
+void ata_swap_buf_le16(u16 *buf, unsigned int buf_words);
+
+#endif /* __LIBATA_H__ */

+ 10 - 0
bsp/ls2kdev/drivers/pci/SConscript

@@ -0,0 +1,10 @@
+from building import *
+
+cwd = GetCurrentDir()
+src = Glob('*.c')
+
+CPPPATH = [cwd]
+
+group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH)
+
+Return('group')

+ 20 - 0
bsp/ls2kdev/drivers/pci/pci.c

@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-28     lizhirui     first version
+ */
+
+#include <rtthread.h>
+#include <pci.h>
+
+rt_uint64_t pci_get_device_map_addr(rt_uint64_t bus,rt_uint64_t device,rt_uint64_t function,rt_uint32_t index)
+{
+
+    rt_uint64_t device_addr = 0xFE00000000 | (bus << 16) | ((device & 0x1f) << 11) | ((function & 0x07) << 8);
+    struct pci_header *p = (struct pci_header *)(0x9000000000000000UL | device_addr);
+    return 0x9000000000000000UL | ((rt_uint64_t)(p -> BaseAddressRegister[index] & 0xFFFFFFF0));
+}

+ 42 - 0
bsp/ls2kdev/drivers/pci/pci.h

@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2020-12-28     lizhirui     first version
+ */
+
+#ifndef __PCI_H__
+#define __PCI_H__
+
+    struct pci_header
+    {
+        rt_uint16_t VendorID;
+        rt_uint16_t DeviceID;
+        rt_uint16_t Command;
+        rt_uint16_t Status;
+        rt_uint32_t RevisionID : 8;
+        rt_uint32_t ClassCode : 24;
+        rt_uint8_t CachelineSize;
+        rt_uint8_t LatencyTimer;
+        rt_uint8_t HeaderType;
+        rt_uint8_t BIST;
+        rt_uint32_t BaseAddressRegister[6];
+        rt_uint32_t CardbusCISPointer;
+        rt_uint16_t SubsystemVendorID;
+        rt_uint16_t SubsystemID;
+        rt_uint32_t ExpansionROMBaseAddress;
+        rt_uint32_t CapabilitiesPointer : 8;
+        rt_uint32_t resv1 : 24;
+        rt_uint32_t resv2;
+        rt_uint8_t InterruptLine;
+        rt_uint8_t InterruptPin;
+        rt_uint8_t Min_Gnt;
+        rt_uint8_t Max_Lat;
+    };
+
+    rt_uint64_t pci_get_device_map_addr(rt_uint64_t bus,rt_uint64_t device,rt_uint64_t function,rt_uint32_t index);
+
+#endif

+ 6 - 0
bsp/ls2kdev/rtconfig.h

@@ -223,6 +223,9 @@
 #define RT_USING_DFS_LWEXT4
 #define PKG_USING_LWEXT4_LATEST_VERSION
 
+/* Micrium: Micrium software products porting for RT-Thread */
+
+
 /* peripheral libraries and drivers */
 
 
@@ -231,6 +234,9 @@
 
 /* samples: kernel and components samples */
 
+
+/* games: games run on RT-Thread console */
+
 #define SOC_LS2K1000
 
 #endif