diff --git a/bsp/ls2kdev/.config b/bsp/ls2kdev/.config index aec7c7c2b24ec59d0e78dda4f9540e1e687f9fcc..2d89bcb80b58f35c5e18ba325ad947e7a34cd829 100644 --- a/bsp/ls2kdev/.config +++ b/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 @@ -438,12 +448,9 @@ CONFIG_RT_LWIP_USING_PING=y # CONFIG_PKG_USING_GUIENGINE is not set # CONFIG_PKG_USING_CAIRO is not set # CONFIG_PKG_USING_PIXMAN is not set -CONFIG_PKG_USING_LWEXT4=y -CONFIG_PKG_LWEXT4_PATH="/packages/system/lwext4" -CONFIG_RT_USING_DFS_LWEXT4=y -CONFIG_PKG_USING_LWEXT4_LATEST_VERSION=y +# CONFIG_PKG_USING_LWEXT4 is not set +# CONFIG_PKG_USING_LWEXT4_LATEST_VERSION is not set # CONFIG_PKG_USING_LWEXT4_V100 is not set -CONFIG_PKG_LWEXT4_VER="latest" # CONFIG_PKG_USING_PARTITION is not set # CONFIG_PKG_USING_FAL is not set # CONFIG_PKG_USING_FLASHDB is not set @@ -462,8 +469,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 +534,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 +550,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 +571,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 +580,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 diff --git a/bsp/ls2kdev/README.md b/bsp/ls2kdev/README.md index 89e041ad71093ac5d0609a642e2614bb6e38b172..08a7dec06376124d8eef5c5b10380be0c2312d32 100644 --- a/bsp/ls2kdev/README.md +++ b/bsp/ls2kdev/README.md @@ -102,7 +102,7 @@ title TFTPBOOT initrd (wd0,0)/initrd.img ``` -其中`tftfp://10.1.1.118/rtthread.elf`中的`10.1.1.118`为tftp服务器的ip地址。 +其中`tftp://10.1.1.118/rtthread.elf`中的`10.1.1.118`为tftp服务器的ip地址。 **第三步:** @@ -110,7 +110,25 @@ title TFTPBOOT 以上三步完成之后,重启系统,就可以省略每次都需要进入pmon的输入命令的麻烦,板子上电后,可以自动从系统TFTP服务器中获取固件,然后启动,大大提高调试代码效率。 -## 5. 支持情况 +## 5.SATA接口的SSD文件系统支持 + +当前已经支持SATA接口的SSD文件系统驱动,需要通过menuconfig + +``` +RT-Thread online packages ---> + system packages ---> + lwext4: an excellent choice of ext2/3/4 filesystem for microcontrollers +``` + +然后输入下面的命令更新软件包 + +``` +pkgs --update +``` + +输入`scons`编译代码即可使用SATA接口的SSD文件系统。 + +## 6. 支持情况 | 驱动 | 支持情况 | 备注 | | ------ | ---- | :------: | @@ -120,8 +138,9 @@ title TFTPBOOT | GMAC | 支持 | 网卡驱动 | | RTC | 支持 | - | | SPI | 支持 | - | +| SATA SSD | 支持 | 需要打开lwext4软件包 | -## 6. 联系人信息 +## 7. 联系人信息 维护人:[bernard][4] diff --git a/bsp/ls2kdev/applications/mnt.c b/bsp/ls2kdev/applications/mnt.c new file mode 100644 index 0000000000000000000000000000000000000000..1c9b9b047acb9b1f809c3eedcd6c3b8190d58a11 --- /dev/null +++ b/bsp/ls2kdev/applications/mnt.c @@ -0,0 +1,47 @@ +/* + * 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 +#include + +#ifdef PKG_USING_LWEXT4 + +#include +#include +#include +#include +#include +#include +#include +#include + +#define EXT4_DEBUG_ALL (0xFFFFFFFF) +#define EXT4_DEBUG_NO (0) + +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(EXT4_DEBUG_NO); + 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); + +#endif diff --git a/bsp/ls2kdev/drivers/ata/SConscript b/bsp/ls2kdev/drivers/ata/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..164023bd1fe5d5441351af824cfd2ead5320f1b0 --- /dev/null +++ b/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 = ['PKG_USING_LWEXT4'], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/ls2kdev/drivers/ata/ahci.h b/bsp/ls2kdev/drivers/ata/ahci.h new file mode 100644 index 0000000000000000000000000000000000000000..bccec2c3790d3f23f87222ab02a719c048f02ecc --- /dev/null +++ b/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 diff --git a/bsp/ls2kdev/drivers/ata/ata_debug.h b/bsp/ls2kdev/drivers/ata/ata_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..cf628d73eae0539b099a61af3562cb4fb910b4e0 --- /dev/null +++ b/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 +#ifdef ATA_DEBUG +#define debug rt_kprintf +#else +#define debug(...) +#endif +#endif diff --git a/bsp/ls2kdev/drivers/ata/ata_interface.h b/bsp/ls2kdev/drivers/ata/ata_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..fc7fb5cbe6d00fe4218f979d79b723e63440c4de --- /dev/null +++ b/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 diff --git a/bsp/ls2kdev/drivers/ata/blk_device.c b/bsp/ls2kdev/drivers/ata/blk_device.c new file mode 100644 index 0000000000000000000000000000000000000000..c6ed88098809ea1b689dc7d0bbe70d2ffc6da06e --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include +#include +#include + +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; + } +} diff --git a/bsp/ls2kdev/drivers/ata/blk_device.h b/bsp/ls2kdev/drivers/ata/blk_device.h new file mode 100644 index 0000000000000000000000000000000000000000..8401e8aac664748c27fed633bff7b0f887aa30f8 --- /dev/null +++ b/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 +#include + +#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 diff --git a/bsp/ls2kdev/drivers/ata/dwc_ahsata.c b/bsp/ls2kdev/drivers/ata/dwc_ahsata.c new file mode 100644 index 0000000000000000000000000000000000000000..bf76636e067d2250c019bb6df0a74cf4eb401781 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 diff --git a/bsp/ls2kdev/drivers/ata/dwc_ahsata.h b/bsp/ls2kdev/drivers/ata/dwc_ahsata.h new file mode 100644 index 0000000000000000000000000000000000000000..44e993d03e217f8813ae27589764e5739fe877a6 --- /dev/null +++ b/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 diff --git a/bsp/ls2kdev/drivers/ata/dwc_ahsata_priv.h b/bsp/ls2kdev/drivers/ata/dwc_ahsata_priv.h new file mode 100644 index 0000000000000000000000000000000000000000..03e64808b96725df3060447481f953e18ad64ccf --- /dev/null +++ b/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__ */ diff --git a/bsp/ls2kdev/drivers/ata/fis.h b/bsp/ls2kdev/drivers/ata/fis.h new file mode 100644 index 0000000000000000000000000000000000000000..c4c6557b8f7daf62ab4fba6a431009afeb73241a --- /dev/null +++ b/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__ */ diff --git a/bsp/ls2kdev/drivers/ata/libata.c b/bsp/ls2kdev/drivers/ata/libata.c new file mode 100644 index 0000000000000000000000000000000000000000..980fc071fcb6320c4ae5283c47ee318c5f18a9a6 --- /dev/null +++ b/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 +#include +#include + +u64 ata_id_n_sectors(u16 *id) +{ + if (ata_id_has_lba(id)) { + if (ata_id_has_lba48(id)) + return ata_id_u64(id, ATA_ID_LBA48_SECTORS); + else + return ata_id_u32(id, ATA_ID_LBA_SECTORS); + } else { + return 0; + } +} + +u32 ata_dev_classify(u32 sig) +{ + u8 lbam, lbah; + + lbam = (sig >> 16) & 0xff; + lbah = (sig >> 24) & 0xff; + + if (((lbam == 0) && (lbah == 0)) || + ((lbam == 0x3c) && (lbah == 0xc3))) + return ATA_DEV_ATA; + + if ((lbam == 0x14) && (lbah == 0xeb)) + return ATA_DEV_ATAPI; + + if ((lbam == 0x69) && (lbah == 0x96)) + return ATA_DEV_PMP; + + return ATA_DEV_UNKNOWN; +} + +static void ata_id_string(const u16 *id, unsigned char *s, + unsigned int ofs, unsigned int len) +{ + unsigned int c; + + while (len > 0) { + c = id[ofs] >> 8; + *s = c; + s++; + + c = id[ofs] & 0xff; + *s = c; + s++; + + ofs++; + len -= 2; + } +} + +void ata_id_c_string(const u16 *id, unsigned char *s, + unsigned int ofs, unsigned int len) +{ + unsigned char *p; + + ata_id_string(id, s, ofs, len - 1); + + p = s + strnlen((char *)s, len - 1); + while (p > s && p[-1] == ' ') + p--; + *p = '\0'; +} + +void ata_dump_id(u16 *id) +{ + unsigned char serial[ATA_ID_SERNO_LEN + 1]; + unsigned char firmware[ATA_ID_FW_REV_LEN + 1]; + unsigned char product[ATA_ID_PROD_LEN + 1]; + u64 n_sectors; + + /* Serial number */ + ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); + printf("S/N: %s\n\r", serial); + + /* Firmware version */ + ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); + printf("Firmware version: %s\n\r", firmware); + + /* Product model */ + ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); + printf("Product model number: %s\n\r", product); + + /* Total sectors of device */ + n_sectors = ata_id_n_sectors(id); + printf("Capablity: %lld sectors\n\r", n_sectors); + + printf ("id[49]: capabilities = 0x%04x\n" + "id[53]: field valid = 0x%04x\n" + "id[63]: mwdma = 0x%04x\n" + "id[64]: pio = 0x%04x\n" + "id[75]: queue depth = 0x%04x\n", + id[49], + id[53], + id[63], + id[64], + id[75]); + + printf ("id[76]: sata capablity = 0x%04x\n" + "id[78]: sata features supported = 0x%04x\n" + "id[79]: sata features enable = 0x%04x\n", + id[76], + id[78], + id[79]); + + printf ("id[80]: major version = 0x%04x\n" + "id[81]: minor version = 0x%04x\n" + "id[82]: command set supported 1 = 0x%04x\n" + "id[83]: command set supported 2 = 0x%04x\n" + "id[84]: command set extension = 0x%04x\n", + id[80], + id[81], + id[82], + id[83], + id[84]); + printf ("id[85]: command set enable 1 = 0x%04x\n" + "id[86]: command set enable 2 = 0x%04x\n" + "id[87]: command set default = 0x%04x\n" + "id[88]: udma = 0x%04x\n" + "id[93]: hardware reset result = 0x%04x\n", + id[85], + id[86], + id[87], + id[88], + id[93]); +} + +void ata_swap_buf_le16(u16 *buf, unsigned int buf_words) +{ + unsigned int i; + + for (i = 0; i < buf_words; i++) + { + buf[i] = le16_to_cpu(buf[i]); + } +} diff --git a/bsp/ls2kdev/drivers/ata/libata.h b/bsp/ls2kdev/drivers/ata/libata.h new file mode 100644 index 0000000000000000000000000000000000000000..ae00c68446f38c363d0290f6174be095087742fd --- /dev/null +++ b/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__ */ diff --git a/bsp/ls2kdev/drivers/pci/SConscript b/bsp/ls2kdev/drivers/pci/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..6c6d2c7adbfc9081168a85bff1bf4daaeb1ee0ef --- /dev/null +++ b/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') diff --git a/bsp/ls2kdev/drivers/pci/pci.c b/bsp/ls2kdev/drivers/pci/pci.c new file mode 100644 index 0000000000000000000000000000000000000000..7f62e88dc7f9fb10dec0bb6ebdf7541f91738407 --- /dev/null +++ b/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 +#include + +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)); +} diff --git a/bsp/ls2kdev/drivers/pci/pci.h b/bsp/ls2kdev/drivers/pci/pci.h new file mode 100644 index 0000000000000000000000000000000000000000..db4b3a018557c5c7886b2174d7231eb7253e3ffa --- /dev/null +++ b/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 diff --git a/bsp/ls2kdev/rtconfig.h b/bsp/ls2kdev/rtconfig.h index b13f860ffd70abcdefcd7e9c105079c744bec84d..dfaa45a009a3df64c8e85b9e9d77af05ae7a767d 100644 --- a/bsp/ls2kdev/rtconfig.h +++ b/bsp/ls2kdev/rtconfig.h @@ -219,9 +219,9 @@ /* system packages */ -#define PKG_USING_LWEXT4 -#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 +231,9 @@ /* samples: kernel and components samples */ + +/* games: games run on RT-Thread console */ + #define SOC_LS2K1000 #endif