From f2105c61821b67bc1d572304d901518e88ee007b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 14 Jun 2017 21:28:26 -0600 Subject: sata: Move drivers into new drivers/ata directory At present we have the SATA and PATA drivers mixed up in the drivers/block directory. It is better to split them out into their own place. Use drivers/ata which is what Linux does. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/powerpc/cpu/mpc85xx/cpu_init.c | 2 +- common/Makefile | 1 - common/sata.c | 117 -- drivers/Kconfig | 2 + drivers/Makefile | 3 +- drivers/ata/Kconfig | 62 ++ drivers/ata/Makefile | 22 + drivers/ata/ahci-uclass.c | 14 + drivers/ata/ahci.c | 1094 ++++++++++++++++++ drivers/ata/dwc_ahci.c | 101 ++ drivers/ata/dwc_ahsata.c | 1018 +++++++++++++++++ drivers/ata/dwc_ahsata.h | 320 ++++++ drivers/ata/fsl_sata.c | 854 ++++++++++++++ drivers/ata/fsl_sata.h | 321 ++++++ drivers/ata/libata.c | 144 +++ drivers/ata/mvsata_ide.c | 199 ++++ drivers/ata/mxc_ata.c | 129 +++ drivers/ata/sata.c | 117 ++ drivers/ata/sata_ceva.c | 149 +++ drivers/ata/sata_dwc.c | 2076 +++++++++++++++++++++++++++++++++++ drivers/ata/sata_dwc.h | 465 ++++++++ drivers/ata/sata_mv.c | 1051 ++++++++++++++++++ drivers/ata/sata_sandbox.c | 33 + drivers/ata/sata_sil.c | 715 ++++++++++++ drivers/ata/sata_sil.h | 214 ++++ drivers/ata/sata_sil3114.c | 835 ++++++++++++++ drivers/ata/sata_sil3114.h | 134 +++ drivers/block/Kconfig | 45 - drivers/block/Makefile | 16 +- drivers/block/ahci-uclass.c | 14 - drivers/block/ahci.c | 1094 ------------------ drivers/block/dwc_ahci.c | 101 -- drivers/block/dwc_ahsata.c | 1018 ----------------- drivers/block/dwc_ahsata.h | 320 ------ drivers/block/fsl_sata.c | 854 -------------- drivers/block/fsl_sata.h | 321 ------ drivers/block/libata.c | 144 --- drivers/block/mvsata_ide.c | 199 ---- drivers/block/mxc_ata.c | 129 --- drivers/block/sata_ceva.c | 149 --- drivers/block/sata_dwc.c | 2076 ----------------------------------- drivers/block/sata_dwc.h | 465 -------- drivers/block/sata_mv.c | 1051 ------------------ drivers/block/sata_sandbox.c | 33 - drivers/block/sata_sil.c | 715 ------------ drivers/block/sata_sil.h | 214 ---- drivers/block/sata_sil3114.c | 835 -------------- drivers/block/sata_sil3114.h | 134 --- 48 files changed, 10073 insertions(+), 10046 deletions(-) delete mode 100644 common/sata.c create mode 100644 drivers/ata/Kconfig create mode 100644 drivers/ata/Makefile create mode 100644 drivers/ata/ahci-uclass.c create mode 100644 drivers/ata/ahci.c create mode 100644 drivers/ata/dwc_ahci.c create mode 100644 drivers/ata/dwc_ahsata.c create mode 100644 drivers/ata/dwc_ahsata.h create mode 100644 drivers/ata/fsl_sata.c create mode 100644 drivers/ata/fsl_sata.h create mode 100644 drivers/ata/libata.c create mode 100644 drivers/ata/mvsata_ide.c create mode 100644 drivers/ata/mxc_ata.c create mode 100644 drivers/ata/sata.c create mode 100644 drivers/ata/sata_ceva.c create mode 100644 drivers/ata/sata_dwc.c create mode 100644 drivers/ata/sata_dwc.h create mode 100644 drivers/ata/sata_mv.c create mode 100644 drivers/ata/sata_sandbox.c create mode 100644 drivers/ata/sata_sil.c create mode 100644 drivers/ata/sata_sil.h create mode 100644 drivers/ata/sata_sil3114.c create mode 100644 drivers/ata/sata_sil3114.h delete mode 100644 drivers/block/ahci-uclass.c delete mode 100644 drivers/block/ahci.c delete mode 100644 drivers/block/dwc_ahci.c delete mode 100644 drivers/block/dwc_ahsata.c delete mode 100644 drivers/block/dwc_ahsata.h delete mode 100644 drivers/block/fsl_sata.c delete mode 100644 drivers/block/fsl_sata.h delete mode 100644 drivers/block/libata.c delete mode 100644 drivers/block/mvsata_ide.c delete mode 100644 drivers/block/mxc_ata.c delete mode 100644 drivers/block/sata_ceva.c delete mode 100644 drivers/block/sata_dwc.c delete mode 100644 drivers/block/sata_dwc.h delete mode 100644 drivers/block/sata_mv.c delete mode 100644 drivers/block/sata_sandbox.c delete mode 100644 drivers/block/sata_sil.c delete mode 100644 drivers/block/sata_sil.h delete mode 100644 drivers/block/sata_sil3114.c delete mode 100644 drivers/block/sata_sil3114.h diff --git a/arch/powerpc/cpu/mpc85xx/cpu_init.c b/arch/powerpc/cpu/mpc85xx/cpu_init.c index 388fe2b4ef..a3076d8d71 100644 --- a/arch/powerpc/cpu/mpc85xx/cpu_init.c +++ b/arch/powerpc/cpu/mpc85xx/cpu_init.c @@ -48,7 +48,7 @@ #ifndef CONFIG_ARCH_QEMU_E500 #include #endif -#include "../../../../drivers/block/fsl_sata.h" +#include "../../../../drivers/ata/fsl_sata.h" #ifdef CONFIG_U_QE #include #endif diff --git a/common/Makefile b/common/Makefile index fdf5c31b1c..f04ddc8352 100644 --- a/common/Makefile +++ b/common/Makefile @@ -79,7 +79,6 @@ obj-$(CONFIG_LCD_ROTATION) += lcd_console_rotation.o obj-$(CONFIG_LCD_DT_SIMPLEFB) += lcd_simplefb.o obj-$(CONFIG_LYNXKDI) += lynxkdi.o obj-$(CONFIG_MENU) += menu.o -obj-$(CONFIG_SATA) += sata.o obj-$(CONFIG_SCSI) += scsi.o obj-$(CONFIG_UPDATE_TFTP) += update.o obj-$(CONFIG_DFU_TFTP) += update.o diff --git a/common/sata.c b/common/sata.c deleted file mode 100644 index 42ff5c7755..0000000000 --- a/common/sata.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2000-2005, DENX Software Engineering - * Wolfgang Denk - * Copyright (C) Procsys. All rights reserved. - * Mushtaq Khan - * - * Copyright (C) 2008 Freescale Semiconductor, Inc. - * Dave Liu - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include - -struct blk_desc sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE]; - -#ifdef CONFIG_PARTITIONS -struct blk_desc *sata_get_dev(int dev) -{ - return (dev < CONFIG_SYS_SATA_MAX_DEVICE) ? &sata_dev_desc[dev] : NULL; -} -#endif - -#ifdef CONFIG_BLK -static unsigned long sata_bread(struct udevice *dev, lbaint_t start, - lbaint_t blkcnt, void *dst) -{ - return -ENOSYS; -} - -static unsigned long sata_bwrite(struct udevice *dev, lbaint_t start, - lbaint_t blkcnt, const void *buffer) -{ - return -ENOSYS; -} -#else -static unsigned long sata_bread(struct blk_desc *block_dev, lbaint_t start, - lbaint_t blkcnt, void *dst) -{ - return sata_read(block_dev->devnum, start, blkcnt, dst); -} - -static unsigned long sata_bwrite(struct blk_desc *block_dev, lbaint_t start, - lbaint_t blkcnt, const void *buffer) -{ - return sata_write(block_dev->devnum, start, blkcnt, buffer); -} -#endif - -int __sata_initialize(void) -{ - int rc, ret = -1; - int i; - - for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++) { - memset(&sata_dev_desc[i], 0, sizeof(struct blk_desc)); - sata_dev_desc[i].if_type = IF_TYPE_SATA; - sata_dev_desc[i].devnum = i; - sata_dev_desc[i].part_type = PART_TYPE_UNKNOWN; - sata_dev_desc[i].type = DEV_TYPE_HARDDISK; - sata_dev_desc[i].lba = 0; - sata_dev_desc[i].blksz = 512; - sata_dev_desc[i].log2blksz = LOG2(sata_dev_desc[i].blksz); -#ifndef CONFIG_BLK - sata_dev_desc[i].block_read = sata_bread; - sata_dev_desc[i].block_write = sata_bwrite; -#endif - rc = init_sata(i); - if (!rc) { - rc = scan_sata(i); - if (!rc && sata_dev_desc[i].lba > 0 && - sata_dev_desc[i].blksz > 0) { - part_init(&sata_dev_desc[i]); - ret = i; - } - } - } - - return ret; -} -int sata_initialize(void) __attribute__((weak, alias("__sata_initialize"))); - -__weak int __sata_stop(void) -{ - int i, err = 0; - - for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++) - err |= reset_sata(i); - - if (err) - printf("Could not reset some SATA devices\n"); - - return err; -} -int sata_stop(void) __attribute__((weak, alias("__sata_stop"))); - -#ifdef CONFIG_BLK -static const struct blk_ops sata_blk_ops = { - .read = sata_bread, - .write = sata_bwrite, -}; - -U_BOOT_DRIVER(sata_blk) = { - .name = "sata_blk", - .id = UCLASS_BLK, - .ops = &sata_blk_ops, -}; -#else -U_BOOT_LEGACY_BLK(sata) = { - .if_typename = "sata", - .if_type = IF_TYPE_SATA, - .max_devs = CONFIG_SYS_SATA_MAX_DEVICE, - .desc = sata_dev_desc, -}; -#endif diff --git a/drivers/Kconfig b/drivers/Kconfig index a736386a0d..63e4034c56 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -6,6 +6,8 @@ source "drivers/core/Kconfig" source "drivers/adc/Kconfig" +source "drivers/ata/Kconfig" + source "drivers/block/Kconfig" source "drivers/clk/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 058bccb761..9bbcc7bf9c 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -45,7 +45,7 @@ obj-$(CONFIG_SPL_DFU_SUPPORT) += dfu/ obj-$(CONFIG_SPL_WATCHDOG_SUPPORT) += watchdog/ obj-$(CONFIG_SPL_USB_HOST_SUPPORT) += usb/host/ obj-$(CONFIG_OMAP_USB_PHY) += usb/phy/ -obj-$(CONFIG_SPL_SATA_SUPPORT) += block/ +obj-$(CONFIG_SPL_SATA_SUPPORT) += ata/ obj-$(CONFIG_SPL_USB_HOST_SUPPORT) += block/ obj-$(CONFIG_SPL_MMC_SUPPORT) += block/ endif @@ -66,6 +66,7 @@ endif ifeq ($(CONFIG_SPL_BUILD)$(CONFIG_TPL_BUILD),) obj-y += adc/ +obj-y += ata/ obj-$(CONFIG_DM_DEMO) += demo/ obj-$(CONFIG_BIOSEMU) += bios_emulator/ obj-y += block/ diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig new file mode 100644 index 0000000000..6427f1b94a --- /dev/null +++ b/drivers/ata/Kconfig @@ -0,0 +1,62 @@ +config AHCI + bool "Support SATA controllers with driver model" + depends on DM + help + This enables a uclass for disk controllers in U-Boot. Various driver + types can use this, such as AHCI/SATA. It does not provide any standard + operations at present. The block device interface has not been converted + to driver model. + +config SATA + bool "Support SATA controllers" + help + This enables support for SATA (Serial Advanced Technology + Attachment), a serial bus standard for connecting to hard drives and + other storage devices. + + SATA replaces PATA (originally just ATA), which stands for Parallel AT + Attachment, where AT refers to an IBM AT (Advanced Technology) + computer released in 1984. + + See also CMD_SATA which provides command-line support. + +config SCSI + bool "Support SCSI controllers" + help + This enables support for SCSI (Small Computer System Interface), + a parallel interface widely used with storage peripherals such as + hard drives and optical drives. The SCSI standards define physical + interfaces as well as protocols for controlling devices and + tranferring data. + +config DM_SCSI + bool "Support SCSI controllers with driver model" + depends on BLK + help + This option enables the SCSI (Small Computer System Interface) uclass + which supports SCSI and SATA HDDs. For every device configuration + (IDs/LUNs) a block device is created with RAW read/write and + filesystem support. + +menu "SATA/SCSI device support" + +config SATA_CEVA + bool "Ceva Sata controller" + depends on AHCI + depends on DM_SCSI + help + This option enables Ceva Sata controller hard IP available on Xilinx + ZynqMP. Support up to 2 external devices. Complient with SATA 3.1 and + AHCI 1.3 specifications with hot-plug detect feature. + + +config DWC_AHCI + bool "Enable Synopsys DWC AHCI driver support" + select SCSI_AHCI + select PHY + depends on DM_SCSI + help + Enable this driver to support Sata devices through + Synopsys DWC AHCI module. + +endmenu diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile new file mode 100644 index 0000000000..c48184c4c3 --- /dev/null +++ b/drivers/ata/Makefile @@ -0,0 +1,22 @@ +# +# (C) Copyright 2000-2007 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_DWC_AHCI) += dwc_ahci.o +obj-$(CONFIG_AHCI) += ahci-uclass.o +obj-$(CONFIG_SCSI_AHCI) += ahci.o +obj-$(CONFIG_DWC_AHSATA) += dwc_ahsata.o +obj-$(CONFIG_FSL_SATA) += fsl_sata.o +obj-$(CONFIG_LIBATA) += libata.o +obj-$(CONFIG_MVSATA_IDE) += mvsata_ide.o +obj-$(CONFIG_MX51_PATA) += mxc_ata.o +obj-$(CONFIG_SATA) += sata.o +obj-$(CONFIG_SATA_CEVA) += sata_ceva.o +obj-$(CONFIG_SATA_DWC) += sata_dwc.o +obj-$(CONFIG_SATA_MV) += sata_mv.o +obj-$(CONFIG_SATA_SIL3114) += sata_sil3114.o +obj-$(CONFIG_SATA_SIL) += sata_sil.o +obj-$(CONFIG_SANDBOX) += sata_sandbox.o diff --git a/drivers/ata/ahci-uclass.c b/drivers/ata/ahci-uclass.c new file mode 100644 index 0000000000..7b8c32699f --- /dev/null +++ b/drivers/ata/ahci-uclass.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +UCLASS_DRIVER(ahci) = { + .id = UCLASS_AHCI, + .name = "ahci", +}; diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c new file mode 100644 index 0000000000..f4744718a8 --- /dev/null +++ b/drivers/ata/ahci.c @@ -0,0 +1,1094 @@ +/* + * Copyright (C) Freescale Semiconductor, Inc. 2006. + * Author: Jason Jin + * Zhang Wei + * + * SPDX-License-Identifier: GPL-2.0+ + * + * with the reference on libata and ahci drvier in kernel + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int ata_io_flush(u8 port); + +struct ahci_probe_ent *probe_ent = NULL; +u16 *ataid[AHCI_MAX_PORTS]; + +#define writel_with_flush(a,b) do { writel(a,b); readl(b); } while (0) + +/* + * Some controllers limit number of blocks they can read/write at once. + * Contemporary SSD devices work much faster if the read/write size is aligned + * to a power of 2. Let's set default to 128 and allowing to be overwritten if + * needed. + */ +#ifndef MAX_SATA_BLOCKS_READ_WRITE +#define MAX_SATA_BLOCKS_READ_WRITE 0x80 +#endif + +/* Maximum timeouts for each event */ +#define WAIT_MS_SPINUP 20000 +#define WAIT_MS_DATAIO 10000 +#define WAIT_MS_FLUSH 5000 +#define WAIT_MS_LINKUP 200 + +__weak void __iomem *ahci_port_base(void __iomem *base, u32 port) +{ + return base + 0x100 + (port * 0x80); +} + + +static void ahci_setup_port(struct ahci_ioports *port, void __iomem *base, + unsigned int port_idx) +{ + base = ahci_port_base(base, port_idx); + + port->cmd_addr = base; + port->scr_addr = base + PORT_SCR; +} + + +#define msleep(a) udelay(a * 1000) + +static void ahci_dcache_flush_range(unsigned long begin, unsigned long len) +{ + const unsigned long start = begin; + const unsigned long end = start + len; + + debug("%s: flush dcache: [%#lx, %#lx)\n", __func__, start, end); + flush_dcache_range(start, end); +} + +/* + * SATA controller DMAs to physical RAM. Ensure data from the + * controller is invalidated from dcache; next access comes from + * physical RAM. + */ +static void ahci_dcache_invalidate_range(unsigned long begin, unsigned long len) +{ + const unsigned long start = begin; + const unsigned long end = start + len; + + debug("%s: invalidate dcache: [%#lx, %#lx)\n", __func__, start, end); + invalidate_dcache_range(start, end); +} + +/* + * Ensure data for SATA controller is flushed out of dcache and + * written to physical memory. + */ +static void ahci_dcache_flush_sata_cmd(struct ahci_ioports *pp) +{ + ahci_dcache_flush_range((unsigned long)pp->cmd_slot, + AHCI_PORT_PRIV_DMA_SZ); +} + +static int waiting_for_cmd_completed(void __iomem *offset, + int timeout_msec, + u32 sign) +{ + int i; + u32 status; + + for (i = 0; ((status = readl(offset)) & sign) && i < timeout_msec; i++) + msleep(1); + + return (i < timeout_msec) ? 0 : -1; +} + +int __weak ahci_link_up(struct ahci_probe_ent *probe_ent, u8 port) +{ + u32 tmp; + int j = 0; + void __iomem *port_mmio = probe_ent->port[port].port_mmio; + + /* + * Bring up SATA link. + * SATA link bringup time is usually less than 1 ms; only very + * rarely has it taken between 1-2 ms. Never seen it above 2 ms. + */ + while (j < WAIT_MS_LINKUP) { + tmp = readl(port_mmio + PORT_SCR_STAT); + tmp &= PORT_SCR_STAT_DET_MASK; + if (tmp == PORT_SCR_STAT_DET_PHYRDY) + return 0; + udelay(1000); + j++; + } + return 1; +} + +#ifdef CONFIG_SUNXI_AHCI +/* The sunxi AHCI controller requires this undocumented setup */ +static void sunxi_dma_init(void __iomem *port_mmio) +{ + clrsetbits_le32(port_mmio + PORT_P0DMACR, 0x0000ff00, 0x00004400); +} +#endif + +int ahci_reset(void __iomem *base) +{ + int i = 1000; + u32 __iomem *host_ctl_reg = base + HOST_CTL; + u32 tmp = readl(host_ctl_reg); /* global controller reset */ + + if ((tmp & HOST_RESET) == 0) + writel_with_flush(tmp | HOST_RESET, host_ctl_reg); + + /* + * reset must complete within 1 second, or + * the hardware should be considered fried. + */ + do { + udelay(1000); + tmp = readl(host_ctl_reg); + i--; + } while ((i > 0) && (tmp & HOST_RESET)); + + if (i == 0) { + printf("controller reset failed (0x%x)\n", tmp); + return -1; + } + + return 0; +} + +static int ahci_host_init(struct ahci_probe_ent *probe_ent) +{ +#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI) +# ifdef CONFIG_DM_PCI + struct udevice *dev = probe_ent->dev; + struct pci_child_platdata *pplat = dev_get_parent_platdata(dev); +# else + pci_dev_t pdev = probe_ent->dev; + unsigned short vendor; +# endif + u16 tmp16; +#endif + void __iomem *mmio = probe_ent->mmio_base; + u32 tmp, cap_save, cmd; + int i, j, ret; + void __iomem *port_mmio; + u32 port_map; + + debug("ahci_host_init: start\n"); + + cap_save = readl(mmio + HOST_CAP); + cap_save &= ((1 << 28) | (1 << 17)); + cap_save |= (1 << 27); /* Staggered Spin-up. Not needed. */ + + ret = ahci_reset(probe_ent->mmio_base); + if (ret) + return ret; + + writel_with_flush(HOST_AHCI_EN, mmio + HOST_CTL); + writel(cap_save, mmio + HOST_CAP); + writel_with_flush(0xf, mmio + HOST_PORTS_IMPL); + +#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI) +# ifdef CONFIG_DM_PCI + if (pplat->vendor == PCI_VENDOR_ID_INTEL) { + u16 tmp16; + + dm_pci_read_config16(dev, 0x92, &tmp16); + dm_pci_write_config16(dev, 0x92, tmp16 | 0xf); + } +# else + pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor); + + if (vendor == PCI_VENDOR_ID_INTEL) { + u16 tmp16; + pci_read_config_word(pdev, 0x92, &tmp16); + tmp16 |= 0xf; + pci_write_config_word(pdev, 0x92, tmp16); + } +# endif +#endif + probe_ent->cap = readl(mmio + HOST_CAP); + probe_ent->port_map = readl(mmio + HOST_PORTS_IMPL); + port_map = probe_ent->port_map; + probe_ent->n_ports = (probe_ent->cap & 0x1f) + 1; + + debug("cap 0x%x port_map 0x%x n_ports %d\n", + probe_ent->cap, probe_ent->port_map, probe_ent->n_ports); + + if (probe_ent->n_ports > CONFIG_SYS_SCSI_MAX_SCSI_ID) + probe_ent->n_ports = CONFIG_SYS_SCSI_MAX_SCSI_ID; + + for (i = 0; i < probe_ent->n_ports; i++) { + if (!(port_map & (1 << i))) + continue; + probe_ent->port[i].port_mmio = ahci_port_base(mmio, i); + port_mmio = (u8 *) probe_ent->port[i].port_mmio; + ahci_setup_port(&probe_ent->port[i], mmio, i); + + /* make sure port is not active */ + tmp = readl(port_mmio + PORT_CMD); + if (tmp & (PORT_CMD_LIST_ON | PORT_CMD_FIS_ON | + PORT_CMD_FIS_RX | PORT_CMD_START)) { + debug("Port %d is active. Deactivating.\n", i); + tmp &= ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON | + PORT_CMD_FIS_RX | PORT_CMD_START); + writel_with_flush(tmp, port_mmio + PORT_CMD); + + /* spec says 500 msecs for each bit, so + * this is slightly incorrect. + */ + msleep(500); + } + +#ifdef CONFIG_SUNXI_AHCI + sunxi_dma_init(port_mmio); +#endif + + /* Add the spinup command to whatever mode bits may + * already be on in the command register. + */ + cmd = readl(port_mmio + PORT_CMD); + cmd |= PORT_CMD_SPIN_UP; + writel_with_flush(cmd, port_mmio + PORT_CMD); + + /* Bring up SATA link. */ + ret = ahci_link_up(probe_ent, i); + if (ret) { + printf("SATA link %d timeout.\n", i); + continue; + } else { + debug("SATA link ok.\n"); + } + + /* Clear error status */ + tmp = readl(port_mmio + PORT_SCR_ERR); + if (tmp) + writel(tmp, port_mmio + PORT_SCR_ERR); + + debug("Spinning up device on SATA port %d... ", i); + + j = 0; + while (j < WAIT_MS_SPINUP) { + tmp = readl(port_mmio + PORT_TFDATA); + if (!(tmp & (ATA_BUSY | ATA_DRQ))) + break; + udelay(1000); + tmp = readl(port_mmio + PORT_SCR_STAT); + tmp &= PORT_SCR_STAT_DET_MASK; + if (tmp == PORT_SCR_STAT_DET_PHYRDY) + break; + j++; + } + + tmp = readl(port_mmio + PORT_SCR_STAT) & PORT_SCR_STAT_DET_MASK; + if (tmp == PORT_SCR_STAT_DET_COMINIT) { + debug("SATA link %d down (COMINIT received), retrying...\n", i); + i--; + continue; + } + + printf("Target spinup took %d ms.\n", j); + if (j == WAIT_MS_SPINUP) + debug("timeout.\n"); + else + debug("ok.\n"); + + tmp = readl(port_mmio + PORT_SCR_ERR); + debug("PORT_SCR_ERR 0x%x\n", tmp); + writel(tmp, port_mmio + PORT_SCR_ERR); + + /* ack any pending irq events for this port */ + tmp = readl(port_mmio + PORT_IRQ_STAT); + debug("PORT_IRQ_STAT 0x%x\n", tmp); + if (tmp) + writel(tmp, port_mmio + PORT_IRQ_STAT); + + writel(1 << i, mmio + HOST_IRQ_STAT); + + /* register linkup ports */ + tmp = readl(port_mmio + PORT_SCR_STAT); + debug("SATA port %d status: 0x%x\n", i, tmp); + if ((tmp & PORT_SCR_STAT_DET_MASK) == PORT_SCR_STAT_DET_PHYRDY) + probe_ent->link_port_map |= (0x01 << i); + } + + tmp = readl(mmio + HOST_CTL); + debug("HOST_CTL 0x%x\n", tmp); + writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); + tmp = readl(mmio + HOST_CTL); + debug("HOST_CTL 0x%x\n", tmp); +#if !defined(CONFIG_DM_SCSI) +#ifndef CONFIG_SCSI_AHCI_PLAT +# ifdef CONFIG_DM_PCI + dm_pci_read_config16(dev, PCI_COMMAND, &tmp16); + tmp |= PCI_COMMAND_MASTER; + dm_pci_write_config16(dev, PCI_COMMAND, tmp16); +# else + pci_read_config_word(pdev, PCI_COMMAND, &tmp16); + tmp |= PCI_COMMAND_MASTER; + pci_write_config_word(pdev, PCI_COMMAND, tmp16); +# endif +#endif +#endif + return 0; +} + + +static void ahci_print_info(struct ahci_probe_ent *probe_ent) +{ +#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI) +# if defined(CONFIG_DM_PCI) + struct udevice *dev = probe_ent->dev; +# else + pci_dev_t pdev = probe_ent->dev; +# endif + u16 cc; +#endif + void __iomem *mmio = probe_ent->mmio_base; + u32 vers, cap, cap2, impl, speed; + const char *speed_s; + const char *scc_s; + + vers = readl(mmio + HOST_VERSION); + cap = probe_ent->cap; + cap2 = readl(mmio + HOST_CAP2); + impl = probe_ent->port_map; + + speed = (cap >> 20) & 0xf; + if (speed == 1) + speed_s = "1.5"; + else if (speed == 2) + speed_s = "3"; + else if (speed == 3) + speed_s = "6"; + else + speed_s = "?"; + +#if defined(CONFIG_SCSI_AHCI_PLAT) || defined(CONFIG_DM_SCSI) + scc_s = "SATA"; +#else +# ifdef CONFIG_DM_PCI + dm_pci_read_config16(dev, 0x0a, &cc); +# else + pci_read_config_word(pdev, 0x0a, &cc); +# endif + if (cc == 0x0101) + scc_s = "IDE"; + else if (cc == 0x0106) + scc_s = "SATA"; + else if (cc == 0x0104) + scc_s = "RAID"; + else + scc_s = "unknown"; +#endif + printf("AHCI %02x%02x.%02x%02x " + "%u slots %u ports %s Gbps 0x%x impl %s mode\n", + (vers >> 24) & 0xff, + (vers >> 16) & 0xff, + (vers >> 8) & 0xff, + vers & 0xff, + ((cap >> 8) & 0x1f) + 1, (cap & 0x1f) + 1, speed_s, impl, scc_s); + + printf("flags: " + "%s%s%s%s%s%s%s" + "%s%s%s%s%s%s%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 << 16) ? "fbss " : "", + cap & (1 << 15) ? "pio " : "", + cap & (1 << 14) ? "slum " : "", + cap & (1 << 13) ? "part " : "", + cap & (1 << 7) ? "ccc " : "", + cap & (1 << 6) ? "ems " : "", + cap & (1 << 5) ? "sxs " : "", + cap2 & (1 << 2) ? "apst " : "", + cap2 & (1 << 1) ? "nvmp " : "", + cap2 & (1 << 0) ? "boh " : ""); +} + +#ifndef CONFIG_SCSI_AHCI_PLAT +# if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI) +static int ahci_init_one(struct udevice *dev) +# else +static int ahci_init_one(pci_dev_t dev) +# endif +{ +#if !defined(CONFIG_DM_SCSI) + u16 vendor; +#endif + int rc; + + probe_ent = malloc(sizeof(struct ahci_probe_ent)); + if (!probe_ent) { + printf("%s: No memory for probe_ent\n", __func__); + return -ENOMEM; + } + + memset(probe_ent, 0, sizeof(struct ahci_probe_ent)); + probe_ent->dev = dev; + + probe_ent->host_flags = ATA_FLAG_SATA + | ATA_FLAG_NO_LEGACY + | ATA_FLAG_MMIO + | ATA_FLAG_PIO_DMA + | ATA_FLAG_NO_ATAPI; + probe_ent->pio_mask = 0x1f; + probe_ent->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */ + +#if !defined(CONFIG_DM_SCSI) +#ifdef CONFIG_DM_PCI + probe_ent->mmio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_5, + PCI_REGION_MEM); + + /* Take from kernel: + * JMicron-specific fixup: + * make sure we're in AHCI mode + */ + dm_pci_read_config16(dev, PCI_VENDOR_ID, &vendor); + if (vendor == 0x197b) + dm_pci_write_config8(dev, 0x41, 0xa1); +#else + probe_ent->mmio_base = pci_map_bar(dev, PCI_BASE_ADDRESS_5, + PCI_REGION_MEM); + + /* Take from kernel: + * JMicron-specific fixup: + * make sure we're in AHCI mode + */ + pci_read_config_word(dev, PCI_VENDOR_ID, &vendor); + if (vendor == 0x197b) + pci_write_config_byte(dev, 0x41, 0xa1); +#endif +#else + struct scsi_platdata *plat = dev_get_platdata(dev); + probe_ent->mmio_base = (void *)plat->base; +#endif + + debug("ahci mmio_base=0x%p\n", probe_ent->mmio_base); + /* initialize adapter */ + rc = ahci_host_init(probe_ent); + if (rc) + goto err_out; + + ahci_print_info(probe_ent); + + return 0; + + err_out: + return rc; +} +#endif + +#define MAX_DATA_BYTE_COUNT (4*1024*1024) + +static int ahci_fill_sg(u8 port, unsigned char *buf, int buf_len) +{ + struct ahci_ioports *pp = &(probe_ent->port[port]); + struct ahci_sg *ahci_sg = pp->cmd_tbl_sg; + u32 sg_count; + int i; + + sg_count = ((buf_len - 1) / MAX_DATA_BYTE_COUNT) + 1; + if (sg_count > AHCI_MAX_SG) { + printf("Error:Too much sg!\n"); + return -1; + } + + for (i = 0; i < sg_count; i++) { + ahci_sg->addr = + cpu_to_le32((unsigned long) buf + i * MAX_DATA_BYTE_COUNT); + ahci_sg->addr_hi = 0; + ahci_sg->flags_size = cpu_to_le32(0x3fffff & + (buf_len < MAX_DATA_BYTE_COUNT + ? (buf_len - 1) + : (MAX_DATA_BYTE_COUNT - 1))); + ahci_sg++; + buf_len -= MAX_DATA_BYTE_COUNT; + } + + return sg_count; +} + + +static void ahci_fill_cmd_slot(struct ahci_ioports *pp, u32 opts) +{ + pp->cmd_slot->opts = cpu_to_le32(opts); + pp->cmd_slot->status = 0; + pp->cmd_slot->tbl_addr = cpu_to_le32((u32)pp->cmd_tbl & 0xffffffff); +#ifdef CONFIG_PHYS_64BIT + pp->cmd_slot->tbl_addr_hi = + cpu_to_le32((u32)(((pp->cmd_tbl) >> 16) >> 16)); +#endif +} + +static int wait_spinup(void __iomem *port_mmio) +{ + ulong start; + u32 tf_data; + + start = get_timer(0); + do { + tf_data = readl(port_mmio + PORT_TFDATA); + if (!(tf_data & ATA_BUSY)) + return 0; + } while (get_timer(start) < WAIT_MS_SPINUP); + + return -ETIMEDOUT; +} + +static int ahci_port_start(u8 port) +{ + struct ahci_ioports *pp = &(probe_ent->port[port]); + void __iomem *port_mmio = pp->port_mmio; + u32 port_status; + void __iomem *mem; + + debug("Enter start port: %d\n", port); + port_status = readl(port_mmio + PORT_SCR_STAT); + debug("Port %d status: %x\n", port, port_status); + if ((port_status & 0xf) != 0x03) { + printf("No Link on this port!\n"); + return -1; + } + + mem = malloc(AHCI_PORT_PRIV_DMA_SZ + 2048); + if (!mem) { + free(pp); + printf("%s: No mem for table!\n", __func__); + return -ENOMEM; + } + + /* Aligned to 2048-bytes */ + mem = memalign(2048, AHCI_PORT_PRIV_DMA_SZ); + memset(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 *)(uintptr_t)virt_to_phys((void *)mem); + debug("cmd_slot = %p\n", pp->cmd_slot); + mem += (AHCI_CMD_SLOT_SZ + 224); + + /* + * Second item: Received-FIS area + */ + pp->rx_fis = virt_to_phys((void *)mem); + mem += AHCI_RX_FIS_SZ; + + /* + * Third item: data area for storing a single command + * and its scatter-gather table + */ + pp->cmd_tbl = virt_to_phys((void *)mem); + debug("cmd_tbl_dma = %lx\n", pp->cmd_tbl); + + mem += AHCI_CMD_TBL_HDR; + pp->cmd_tbl_sg = + (struct ahci_sg *)(uintptr_t)virt_to_phys((void *)mem); + + writel_with_flush((unsigned long)pp->cmd_slot, + port_mmio + PORT_LST_ADDR); + + writel_with_flush(pp->rx_fis, port_mmio + PORT_FIS_ADDR); + +#ifdef CONFIG_SUNXI_AHCI + sunxi_dma_init(port_mmio); +#endif + + writel_with_flush(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX | + PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP | + PORT_CMD_START, port_mmio + PORT_CMD); + + debug("Exit start port %d\n", port); + + /* + * Make sure interface is not busy based on error and status + * information from task file data register before proceeding + */ + return wait_spinup(port_mmio); +} + + +static int ahci_device_data_io(u8 port, u8 *fis, int fis_len, u8 *buf, + int buf_len, u8 is_write) +{ + + struct ahci_ioports *pp = &(probe_ent->port[port]); + void __iomem *port_mmio = pp->port_mmio; + u32 opts; + u32 port_status; + int sg_count; + + debug("Enter %s: for port %d\n", __func__, port); + + if (port > probe_ent->n_ports) { + printf("Invalid port number %d\n", port); + return -1; + } + + port_status = readl(port_mmio + PORT_SCR_STAT); + if ((port_status & 0xf) != 0x03) { + debug("No Link on port %d!\n", port); + return -1; + } + + memcpy((unsigned char *)pp->cmd_tbl, fis, fis_len); + + sg_count = ahci_fill_sg(port, buf, buf_len); + opts = (fis_len >> 2) | (sg_count << 16) | (is_write << 6); + ahci_fill_cmd_slot(pp, opts); + + ahci_dcache_flush_sata_cmd(pp); + ahci_dcache_flush_range((unsigned long)buf, (unsigned long)buf_len); + + writel_with_flush(1, port_mmio + PORT_CMD_ISSUE); + + if (waiting_for_cmd_completed(port_mmio + PORT_CMD_ISSUE, + WAIT_MS_DATAIO, 0x1)) { + printf("timeout exit!\n"); + return -1; + } + + ahci_dcache_invalidate_range((unsigned long)buf, + (unsigned long)buf_len); + debug("%s: %d byte transferred.\n", __func__, pp->cmd_slot->status); + + return 0; +} + + +static char *ata_id_strcpy(u16 *target, u16 *src, int len) +{ + int i; + for (i = 0; i < len / 2; i++) + target[i] = swab16(src[i]); + return (char *)target; +} + +/* + * SCSI INQUIRY command operation. + */ +static int ata_scsiop_inquiry(ccb *pccb) +{ + static const u8 hdr[] = { + 0, + 0, + 0x5, /* claim SPC-3 version compatibility */ + 2, + 95 - 4, + }; + u8 fis[20]; + u16 *idbuf; + ALLOC_CACHE_ALIGN_BUFFER(u16, tmpid, ATA_ID_WORDS); + u8 port; + + /* Clean ccb data buffer */ + memset(pccb->pdata, 0, pccb->datalen); + + memcpy(pccb->pdata, hdr, sizeof(hdr)); + + if (pccb->datalen <= 35) + return 0; + + memset(fis, 0, sizeof(fis)); + /* Construct the FIS */ + fis[0] = 0x27; /* Host to device FIS. */ + fis[1] = 1 << 7; /* Command FIS. */ + fis[2] = ATA_CMD_ID_ATA; /* Command byte. */ + + /* Read id from sata */ + port = pccb->target; + + if (ahci_device_data_io(port, (u8 *) &fis, sizeof(fis), (u8 *)tmpid, + ATA_ID_WORDS * 2, 0)) { + debug("scsi_ahci: SCSI inquiry command failure.\n"); + return -EIO; + } + + if (!ataid[port]) { + ataid[port] = malloc(ATA_ID_WORDS * 2); + if (!ataid[port]) { + printf("%s: No memory for ataid[port]\n", __func__); + return -ENOMEM; + } + } + + idbuf = ataid[port]; + + memcpy(idbuf, tmpid, ATA_ID_WORDS * 2); + ata_swap_buf_le16(idbuf, ATA_ID_WORDS); + + memcpy(&pccb->pdata[8], "ATA ", 8); + ata_id_strcpy((u16 *)&pccb->pdata[16], &idbuf[ATA_ID_PROD], 16); + ata_id_strcpy((u16 *)&pccb->pdata[32], &idbuf[ATA_ID_FW_REV], 4); + +#ifdef DEBUG + ata_dump_id(idbuf); +#endif + return 0; +} + + +/* + * SCSI READ10/WRITE10 command operation. + */ +static int ata_scsiop_read_write(ccb *pccb, u8 is_write) +{ + lbaint_t lba = 0; + u16 blocks = 0; + u8 fis[20]; + u8 *user_buffer = pccb->pdata; + u32 user_buffer_size = pccb->datalen; + + /* Retrieve the base LBA number from the ccb structure. */ + if (pccb->cmd[0] == SCSI_READ16) { + memcpy(&lba, pccb->cmd + 2, 8); + lba = be64_to_cpu(lba); + } else { + u32 temp; + memcpy(&temp, pccb->cmd + 2, 4); + lba = be32_to_cpu(temp); + } + + /* + * Retrieve the base LBA number and the block count from + * the ccb structure. + * + * For 10-byte and 16-byte SCSI R/W commands, transfer + * length 0 means transfer 0 block of data. + * However, for ATA R/W commands, sector count 0 means + * 256 or 65536 sectors, not 0 sectors as in SCSI. + * + * WARNING: one or two older ATA drives treat 0 as 0... + */ + if (pccb->cmd[0] == SCSI_READ16) + blocks = (((u16)pccb->cmd[13]) << 8) | ((u16) pccb->cmd[14]); + else + blocks = (((u16)pccb->cmd[7]) << 8) | ((u16) pccb->cmd[8]); + + debug("scsi_ahci: %s %u blocks starting from lba 0x" LBAFU "\n", + is_write ? "write" : "read", blocks, lba); + + /* Preset the FIS */ + memset(fis, 0, sizeof(fis)); + fis[0] = 0x27; /* Host to device FIS. */ + fis[1] = 1 << 7; /* Command FIS. */ + /* Command byte (read/write). */ + fis[2] = is_write ? ATA_CMD_WRITE_EXT : ATA_CMD_READ_EXT; + + while (blocks) { + u16 now_blocks; /* number of blocks per iteration */ + u32 transfer_size; /* number of bytes per iteration */ + + now_blocks = min((u16)MAX_SATA_BLOCKS_READ_WRITE, blocks); + + transfer_size = ATA_SECT_SIZE * now_blocks; + if (transfer_size > user_buffer_size) { + printf("scsi_ahci: Error: buffer too small.\n"); + return -EIO; + } + + /* + * LBA48 SATA command but only use 32bit address range within + * that (unless we've enabled 64bit LBA support). The next + * smaller command range (28bit) is too small. + */ + fis[4] = (lba >> 0) & 0xff; + fis[5] = (lba >> 8) & 0xff; + fis[6] = (lba >> 16) & 0xff; + fis[7] = 1 << 6; /* device reg: set LBA mode */ + fis[8] = ((lba >> 24) & 0xff); +#ifdef CONFIG_SYS_64BIT_LBA + if (pccb->cmd[0] == SCSI_READ16) { + fis[9] = ((lba >> 32) & 0xff); + fis[10] = ((lba >> 40) & 0xff); + } +#endif + + fis[3] = 0xe0; /* features */ + + /* Block (sector) count */ + fis[12] = (now_blocks >> 0) & 0xff; + fis[13] = (now_blocks >> 8) & 0xff; + + /* Read/Write from ahci */ + if (ahci_device_data_io(pccb->target, (u8 *) &fis, sizeof(fis), + user_buffer, transfer_size, + is_write)) { + debug("scsi_ahci: SCSI %s10 command failure.\n", + is_write ? "WRITE" : "READ"); + return -EIO; + } + + /* If this transaction is a write, do a following flush. + * Writes in u-boot are so rare, and the logic to know when is + * the last write and do a flush only there is sufficiently + * difficult. Just do a flush after every write. This incurs, + * usually, one extra flush when the rare writes do happen. + */ + if (is_write) { + if (-EIO == ata_io_flush(pccb->target)) + return -EIO; + } + user_buffer += transfer_size; + user_buffer_size -= transfer_size; + blocks -= now_blocks; + lba += now_blocks; + } + + return 0; +} + + +/* + * SCSI READ CAPACITY10 command operation. + */ +static int ata_scsiop_read_capacity10(ccb *pccb) +{ + u32 cap; + u64 cap64; + u32 block_size; + + if (!ataid[pccb->target]) { + printf("scsi_ahci: SCSI READ CAPACITY10 command failure. " + "\tNo ATA info!\n" + "\tPlease run SCSI command INQUIRY first!\n"); + return -EPERM; + } + + cap64 = ata_id_n_sectors(ataid[pccb->target]); + if (cap64 > 0x100000000ULL) + cap64 = 0xffffffff; + + cap = cpu_to_be32(cap64); + memcpy(pccb->pdata, &cap, sizeof(cap)); + + block_size = cpu_to_be32((u32)512); + memcpy(&pccb->pdata[4], &block_size, 4); + + return 0; +} + + +/* + * SCSI READ CAPACITY16 command operation. + */ +static int ata_scsiop_read_capacity16(ccb *pccb) +{ + u64 cap; + u64 block_size; + + if (!ataid[pccb->target]) { + printf("scsi_ahci: SCSI READ CAPACITY16 command failure. " + "\tNo ATA info!\n" + "\tPlease run SCSI command INQUIRY first!\n"); + return -EPERM; + } + + cap = ata_id_n_sectors(ataid[pccb->target]); + cap = cpu_to_be64(cap); + memcpy(pccb->pdata, &cap, sizeof(cap)); + + block_size = cpu_to_be64((u64)512); + memcpy(&pccb->pdata[8], &block_size, 8); + + return 0; +} + + +/* + * SCSI TEST UNIT READY command operation. + */ +static int ata_scsiop_test_unit_ready(ccb *pccb) +{ + return (ataid[pccb->target]) ? 0 : -EPERM; +} + + +int scsi_exec(ccb *pccb) +{ + int ret; + + switch (pccb->cmd[0]) { + case SCSI_READ16: + case SCSI_READ10: + ret = ata_scsiop_read_write(pccb, 0); + break; + case SCSI_WRITE10: + ret = ata_scsiop_read_write(pccb, 1); + break; + case SCSI_RD_CAPAC10: + ret = ata_scsiop_read_capacity10(pccb); + break; + case SCSI_RD_CAPAC16: + ret = ata_scsiop_read_capacity16(pccb); + break; + case SCSI_TST_U_RDY: + ret = ata_scsiop_test_unit_ready(pccb); + break; + case SCSI_INQUIRY: + ret = ata_scsiop_inquiry(pccb); + break; + default: + printf("Unsupport SCSI command 0x%02x\n", pccb->cmd[0]); + return false; + } + + if (ret) { + debug("SCSI command 0x%02x ret errno %d\n", pccb->cmd[0], ret); + return false; + } + return true; + +} + +#if defined(CONFIG_DM_SCSI) +void scsi_low_level_init(int busdevfunc, struct udevice *dev) +#else +void scsi_low_level_init(int busdevfunc) +#endif +{ + int i; + u32 linkmap; + +#ifndef CONFIG_SCSI_AHCI_PLAT +# if defined(CONFIG_DM_PCI) + struct udevice *dev; + int ret; + + ret = dm_pci_bus_find_bdf(busdevfunc, &dev); + if (ret) + return; + ahci_init_one(dev); +# elif defined(CONFIG_DM_SCSI) + ahci_init_one(dev); +# else + ahci_init_one(busdevfunc); +# endif +#endif + + linkmap = probe_ent->link_port_map; + + for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { + if (((linkmap >> i) & 0x01)) { + if (ahci_port_start((u8) i)) { + printf("Can not start port %d\n", i); + continue; + } + } + } +} + +#ifdef CONFIG_SCSI_AHCI_PLAT +int ahci_init(void __iomem *base) +{ + int i, rc = 0; + u32 linkmap; + + probe_ent = malloc(sizeof(struct ahci_probe_ent)); + if (!probe_ent) { + printf("%s: No memory for probe_ent\n", __func__); + return -ENOMEM; + } + + memset(probe_ent, 0, sizeof(struct ahci_probe_ent)); + + probe_ent->host_flags = ATA_FLAG_SATA + | ATA_FLAG_NO_LEGACY + | ATA_FLAG_MMIO + | ATA_FLAG_PIO_DMA + | ATA_FLAG_NO_ATAPI; + probe_ent->pio_mask = 0x1f; + probe_ent->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */ + + probe_ent->mmio_base = base; + + /* initialize adapter */ + rc = ahci_host_init(probe_ent); + if (rc) + goto err_out; + + ahci_print_info(probe_ent); + + linkmap = probe_ent->link_port_map; + + for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { + if (((linkmap >> i) & 0x01)) { + if (ahci_port_start((u8) i)) { + printf("Can not start port %d\n", i); + continue; + } + } + } +err_out: + return rc; +} + +void __weak scsi_init(void) +{ +} + +#endif + +/* + * In the general case of generic rotating media it makes sense to have a + * flush capability. It probably even makes sense in the case of SSDs because + * one cannot always know for sure what kind of internal cache/flush mechanism + * is embodied therein. At first it was planned to invoke this after the last + * write to disk and before rebooting. In practice, knowing, a priori, which + * is the last write is difficult. Because writing to the disk in u-boot is + * very rare, this flush command will be invoked after every block write. + */ +static int ata_io_flush(u8 port) +{ + u8 fis[20]; + struct ahci_ioports *pp = &(probe_ent->port[port]); + void __iomem *port_mmio = pp->port_mmio; + u32 cmd_fis_len = 5; /* five dwords */ + + /* Preset the FIS */ + memset(fis, 0, 20); + fis[0] = 0x27; /* Host to device FIS. */ + fis[1] = 1 << 7; /* Command FIS. */ + fis[2] = ATA_CMD_FLUSH_EXT; + + memcpy((unsigned char *)pp->cmd_tbl, fis, 20); + ahci_fill_cmd_slot(pp, cmd_fis_len); + ahci_dcache_flush_sata_cmd(pp); + writel_with_flush(1, port_mmio + PORT_CMD_ISSUE); + + if (waiting_for_cmd_completed(port_mmio + PORT_CMD_ISSUE, + WAIT_MS_FLUSH, 0x1)) { + debug("scsi_ahci: flush command timeout on port %d.\n", port); + return -EIO; + } + + return 0; +} + + +__weak void scsi_bus_reset(void) +{ + /*Not implement*/ +} diff --git a/drivers/ata/dwc_ahci.c b/drivers/ata/dwc_ahci.c new file mode 100644 index 0000000000..3f839bf987 --- /dev/null +++ b/drivers/ata/dwc_ahci.c @@ -0,0 +1,101 @@ +/* + * DWC SATA platform driver + * + * (C) Copyright 2016 + * Texas Instruments Incorporated, + * + * Author: Mugunthan V N + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +struct dwc_ahci_priv { + void *base; + void *wrapper_base; +}; + +static int dwc_ahci_ofdata_to_platdata(struct udevice *dev) +{ + struct dwc_ahci_priv *priv = dev_get_priv(dev); + struct scsi_platdata *plat = dev_get_platdata(dev); + fdt_addr_t addr; + + plat->max_id = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), + "max-id", CONFIG_SYS_SCSI_MAX_SCSI_ID); + plat->max_lun = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), + "max-lun", CONFIG_SYS_SCSI_MAX_LUN); + + priv->base = map_physmem(devfdt_get_addr(dev), sizeof(void *), + MAP_NOCACHE); + + addr = devfdt_get_addr_index(dev, 1); + if (addr != FDT_ADDR_T_NONE) { + priv->wrapper_base = map_physmem(addr, sizeof(void *), + MAP_NOCACHE); + } else { + priv->wrapper_base = NULL; + } + + return 0; +} + +static int dwc_ahci_probe(struct udevice *dev) +{ + struct dwc_ahci_priv *priv = dev_get_priv(dev); + int ret; + struct phy phy; + + ret = generic_phy_get_by_name(dev, "sata-phy", &phy); + if (ret) { + error("can't get the phy from DT\n"); + return ret; + } + + ret = generic_phy_init(&phy); + if (ret) { + error("unable to initialize the sata phy\n"); + return ret; + } + + ret = generic_phy_power_on(&phy); + if (ret) { + error("unable to power on the sata phy\n"); + return ret; + } + + if (priv->wrapper_base) { + u32 val = TI_SATA_IDLE_NO | TI_SATA_STANDBY_NO; + + /* Enable SATA module, No Idle, No Standby */ + writel(val, priv->wrapper_base + TI_SATA_SYSCONFIG); + } + + return ahci_init(priv->base); +} + +static const struct udevice_id dwc_ahci_ids[] = { + { .compatible = "snps,dwc-ahci" }, + { } +}; + +U_BOOT_DRIVER(dwc_ahci) = { + .name = "dwc_ahci", + .id = UCLASS_SCSI, + .of_match = dwc_ahci_ids, + .ofdata_to_platdata = dwc_ahci_ofdata_to_platdata, + .probe = dwc_ahci_probe, + .priv_auto_alloc_size = sizeof(struct dwc_ahci_priv), + .platdata_auto_alloc_size = sizeof(struct scsi_platdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; diff --git a/drivers/ata/dwc_ahsata.c b/drivers/ata/dwc_ahsata.c new file mode 100644 index 0000000000..c306e927db --- /dev/null +++ b/drivers/ata/dwc_ahsata.c @@ -0,0 +1,1018 @@ +/* + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. + * Terry Lv + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "dwc_ahsata.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 int is_ready; + +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_probe_ent *probe_ent, + int clk) +{ + struct sata_host_regs *host_mmio = + (struct sata_host_regs *)probe_ent->mmio_base; + + writel(SATA_HOST_OOBR_WE, &(host_mmio->oobr)); + writel(0x02060b14, &(host_mmio->oobr)); + + return 0; +} + +static int ahci_host_init(struct ahci_probe_ent *probe_ent) +{ + u32 tmp, cap_save, num_ports; + int i, j, timeout = 1000; + struct sata_port_regs *port_mmio = NULL; + struct sata_host_regs *host_mmio = + (struct sata_host_regs *)probe_ent->mmio_base; + int clk = mxc_get_clock(MXC_SATA_CLK); + + cap_save = readl(&(host_mmio->cap)); + cap_save |= SATA_HOST_CAP_SSS; + + /* global controller reset */ + tmp = readl(&(host_mmio->ghc)); + if ((tmp & SATA_HOST_GHC_HR) == 0) + writel_with_flush(tmp | SATA_HOST_GHC_HR, &(host_mmio->ghc)); + + while ((readl(&(host_mmio->ghc)) & SATA_HOST_GHC_HR) + && --timeout) + ; + + if (timeout <= 0) { + debug("controller reset failed (0x%x)\n", tmp); + return -1; + } + + /* Set timer 1ms */ + writel(clk / 1000, &(host_mmio->timer1ms)); + + ahci_setup_oobr(probe_ent, 0); + + writel_with_flush(SATA_HOST_GHC_AE, &(host_mmio->ghc)); + writel(cap_save, &(host_mmio->cap)); + num_ports = (cap_save & SATA_HOST_CAP_NP_MASK) + 1; + 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. + */ + probe_ent->cap = readl(&(host_mmio->cap)); + probe_ent->port_map = readl(&(host_mmio->pi)); + + /* Determine how many command slots the HBA supports */ + probe_ent->n_ports = + (probe_ent->cap & SATA_HOST_CAP_NP_MASK) + 1; + + debug("cap 0x%x port_map 0x%x n_ports %d\n", + probe_ent->cap, probe_ent->port_map, probe_ent->n_ports); + + for (i = 0; i < probe_ent->n_ports; i++) { + probe_ent->port[i].port_mmio = + ahci_port_base(host_mmio, i); + port_mmio = + (struct sata_port_regs *)probe_ent->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) + probe_ent->link_port_map |= (0x01 << i); + } + + tmp = readl(&(host_mmio->ghc)); + debug("GHC 0x%x\n", tmp); + writel(tmp | SATA_HOST_GHC_IE, &(host_mmio->ghc)); + tmp = readl(&(host_mmio->ghc)); + debug("GHC 0x%x\n", tmp); + + return 0; +} + +static void ahci_print_info(struct ahci_probe_ent *probe_ent) +{ + struct sata_host_regs *host_mmio = + (struct sata_host_regs *)probe_ent->mmio_base; + u32 vers, cap, impl, speed; + const char *speed_s; + const char *scc_s; + + vers = readl(&(host_mmio->vs)); + cap = probe_ent->cap; + impl = probe_ent->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"; + + printf("AHCI %02x%02x.%02x%02x " + "%u slots %u ports %s Gbps 0x%x impl %s mode\n", + (vers >> 24) & 0xff, + (vers >> 16) & 0xff, + (vers >> 8) & 0xff, + vers & 0xff, + ((cap >> 8) & 0x1f) + 1, + (cap & 0x1f) + 1, + speed_s, + impl, + scc_s); + + printf("flags: " + "%s%s%s%s%s%s" + "%s%s%s%s%s%s%s\n", + cap & (1 << 31) ? "64bit " : "", + cap & (1 << 30) ? "ncq " : "", + cap & (1 << 28) ? "ilck " : "", + cap & (1 << 27) ? "stag " : "", + cap & (1 << 26) ? "pm " : "", + cap & (1 << 25) ? "led " : "", + cap & (1 << 24) ? "clo " : "", + cap & (1 << 19) ? "nz " : "", + cap & (1 << 18) ? "only " : "", + cap & (1 << 17) ? "pmp " : "", + cap & (1 << 15) ? "pio " : "", + cap & (1 << 14) ? "slum " : "", + cap & (1 << 13) ? "part " : ""); +} + +static int ahci_init_one(int pdev) +{ + int rc; + struct ahci_probe_ent *probe_ent = NULL; + + probe_ent = malloc(sizeof(struct ahci_probe_ent)); + memset(probe_ent, 0, sizeof(struct ahci_probe_ent)); + probe_ent->dev = pdev; + + probe_ent->host_flags = ATA_FLAG_SATA + | ATA_FLAG_NO_LEGACY + | ATA_FLAG_MMIO + | ATA_FLAG_PIO_DMA + | ATA_FLAG_NO_ATAPI; + + probe_ent->mmio_base = (void __iomem *)CONFIG_DWC_AHSATA_BASE_ADDR; + + /* initialize adapter */ + rc = ahci_host_init(probe_ent); + if (rc) + goto err_out; + + ahci_print_info(probe_ent); + + /* Save the private struct to block device struct */ + sata_dev_desc[pdev].priv = (void *)probe_ent; + + return 0; + +err_out: + return rc; +} + +static int ahci_fill_sg(struct ahci_probe_ent *probe_ent, + u8 port, unsigned char *buf, int buf_len) +{ + struct ahci_ioports *pp = &(probe_ent->port[port]); + struct ahci_sg *ahci_sg = pp->cmd_tbl_sg; + u32 sg_count, 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) { + printf("Error:Too much sg!\n"); + return -1; + } + + for (i = 0; i < sg_count; i++) { + ahci_sg->addr = + cpu_to_le32((u32)buf + i * max_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 = cpu_to_le32((u32)pp->cmd_tbl & 0xffffffff); +#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_probe_ent *probe_ent, + u8 port, struct sata_fis_h2d *cfis, + u8 *buf, u32 buf_len, s32 is_write) +{ + struct ahci_ioports *pp = &(probe_ent->port[port]); + struct sata_port_regs *port_mmio = + (struct sata_port_regs *)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) { + printf("Can't find empty command slot!\n"); + return 0; + } + + /* Check xfer length */ + if (buf_len > MAX_BYTES_PER_TRANS) { + printf("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(probe_ent, 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)) { + printf("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(u8 dev, u8 port) +{ + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + 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(probe_ent->udma_mask + 1) + 0x3e; + + ahci_exec_ata_cmd(probe_ent, port, cfis, NULL, 0, READ_CMD); +} + +static int ahci_port_start(struct ahci_probe_ent *probe_ent, + u8 port) +{ + struct ahci_ioports *pp = &(probe_ent->port[port]); + struct sata_port_regs *port_mmio = + (struct sata_port_regs *)pp->port_mmio; + u32 port_status; + u32 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) { + printf("No Link on this port!\n"); + return -1; + } + + mem = (u32)malloc(AHCI_PORT_PRIV_DMA_SZ + 1024); + if (!mem) { + free(pp); + printf("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%x\n", (unsigned int) 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((u32)pp->cmd_slot, &(port_mmio->clb)); + writel_with_flush(pp->rx_fis, &(port_mmio->fb)); + + /* 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; +} + +int init_sata(int dev) +{ + int i; + u32 linkmap; + struct ahci_probe_ent *probe_ent = NULL; + +#if defined(CONFIG_MX6) + if (!is_mx6dq() && !is_mx6dqp()) + return 1; +#endif + if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) { + printf("The sata index %d is out of ranges\n\r", dev); + return -1; + } + + ahci_init_one(dev); + + probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + linkmap = probe_ent->link_port_map; + + if (0 == linkmap) { + printf("No port device detected!\n"); + return 1; + } + + for (i = 0; i < probe_ent->n_ports; i++) { + if ((linkmap >> i) && ((linkmap >> i) & 0x01)) { + if (ahci_port_start(probe_ent, (u8)i)) { + printf("Can not start port %d\n", i); + return 1; + } + probe_ent->hard_port_no = i; + break; + } + } + + return 0; +} + +int reset_sata(int dev) +{ + struct ahci_probe_ent *probe_ent; + struct sata_host_regs *host_mmio; + + if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) { + printf("The sata index %d is out of ranges\n\r", dev); + return -1; + } + + probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + if (NULL == probe_ent) + /* not initialized, so nothing to reset */ + return 0; + + host_mmio = (struct sata_host_regs *)probe_ent->mmio_base; + setbits_le32(&host_mmio->ghc, SATA_HOST_GHC_HR); + while (readl(&host_mmio->ghc) & SATA_HOST_GHC_HR) + udelay(100); + + return 0; +} + +static void dwc_ahsata_print_info(int dev) +{ + struct blk_desc *pdev = &(sata_dev_desc[dev]); + + printf("SATA Device Info:\n\r"); +#ifdef CONFIG_SYS_64BIT_LBA + printf("S/N: %s\n\rProduct model number: %s\n\r" + "Firmware version: %s\n\rCapacity: %lld sectors\n\r", + pdev->product, pdev->vendor, pdev->revision, pdev->lba); +#else + printf("S/N: %s\n\rProduct model number: %s\n\r" + "Firmware version: %s\n\rCapacity: %ld sectors\n\r", + pdev->product, pdev->vendor, pdev->revision, pdev->lba); +#endif +} + +static void dwc_ahsata_identify(int dev, u16 *id) +{ + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; + u8 port = probe_ent->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(probe_ent, port, cfis, + (u8 *)id, ATA_ID_WORDS * 2, READ_CMD); + ata_swap_buf_le16(id, ATA_ID_WORDS); +} + +static void dwc_ahsata_xfer_mode(int dev, u16 *id) +{ + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + + probe_ent->pio_mask = id[ATA_ID_PIO_MODES]; + probe_ent->udma_mask = id[ATA_ID_UDMA_MODES]; + debug("pio %04x, udma %04x\n\r", + probe_ent->pio_mask, probe_ent->udma_mask); +} + +static u32 dwc_ahsata_rw_cmd(int dev, u32 start, u32 blkcnt, + u8 *buffer, int is_write) +{ + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; + u8 port = probe_ent->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(probe_ent, port, cfis, + buffer, ATA_SECT_SIZE * blkcnt, is_write) > 0) + return blkcnt; + else + return 0; +} + +void dwc_ahsata_flush_cache(int dev) +{ + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; + u8 port = probe_ent->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(probe_ent, port, cfis, NULL, 0, 0); +} + +static u32 dwc_ahsata_rw_cmd_ext(int dev, u32 start, lbaint_t blkcnt, + u8 *buffer, int is_write) +{ + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; + u8 port = probe_ent->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(probe_ent, port, cfis, buffer, + ATA_SECT_SIZE * blkcnt, is_write) > 0) + return blkcnt; + else + return 0; +} + +u32 dwc_ahsata_rw_ncq_cmd(int dev, u32 start, lbaint_t blkcnt, + u8 *buffer, int is_write) +{ + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; + u8 port = probe_ent->hard_port_no; + u64 block; + + if (sata_dev_desc[dev].lba48 != 1) { + printf("execute FPDMA command on non-LBA48 hard disk\n\r"); + return -1; + } + + block = (u64)start; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + + cfis->command = (is_write) ? ATA_CMD_FPDMA_WRITE + : ATA_CMD_FPDMA_READ; + + cfis->lba_high_exp = (block >> 40) & 0xff; + cfis->lba_mid_exp = (block >> 32) & 0xff; + cfis->lba_low_exp = (block >> 24) & 0xff; + cfis->lba_high = (block >> 16) & 0xff; + cfis->lba_mid = (block >> 8) & 0xff; + cfis->lba_low = block & 0xff; + + cfis->device = ATA_LBA; + cfis->features_exp = (blkcnt >> 8) & 0xff; + cfis->features = blkcnt & 0xff; + + /* Use the latest queue */ + ahci_exec_ata_cmd(probe_ent, port, cfis, + buffer, ATA_SECT_SIZE * blkcnt, is_write); + + return blkcnt; +} + +void dwc_ahsata_flush_cache_ext(int dev) +{ + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; + u8 port = probe_ent->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(probe_ent, port, cfis, NULL, 0, 0); +} + +static void dwc_ahsata_init_wcache(int dev, u16 *id) +{ + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + + if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id)) + probe_ent->flags |= SATA_FLAG_WCACHE; + if (ata_id_has_flush(id)) + probe_ent->flags |= SATA_FLAG_FLUSH; + if (ata_id_has_flush_ext(id)) + probe_ent->flags |= SATA_FLAG_FLUSH_EXT; +} + +u32 ata_low_level_rw_lba48(int dev, 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(dev, 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(dev, start, + blks, addr, is_write)) + return 0; + start += blks; + blks = 0; + addr += ATA_SECT_SIZE * blks; + } + } while (blks != 0); + + return blkcnt; +} + +u32 ata_low_level_rw_lba28(int dev, 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(dev, 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(dev, start, + blks, addr, is_write)) + return 0; + start += blks; + blks = 0; + addr += ATA_SECT_SIZE * blks; + } + } while (blks != 0); + + return blkcnt; +} + +int sata_port_status(int dev, int port) +{ + struct sata_port_regs *port_mmio; + struct ahci_probe_ent *probe_ent = NULL; + + if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) + return -EINVAL; + + if (sata_dev_desc[dev].priv == NULL) + return -ENODEV; + + probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + port_mmio = (struct sata_port_regs *)probe_ent->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) +{ + u32 rc; + + if (sata_dev_desc[dev].lba48) + rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, + buffer, READ_CMD); + else + rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, + buffer, READ_CMD); + return rc; +} + +ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) +{ + u32 rc; + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + u32 flags = probe_ent->flags; + + if (sata_dev_desc[dev].lba48) { + rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, + buffer, WRITE_CMD); + if ((flags & SATA_FLAG_WCACHE) && + (flags & SATA_FLAG_FLUSH_EXT)) + dwc_ahsata_flush_cache_ext(dev); + } else { + rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, + buffer, WRITE_CMD); + if ((flags & SATA_FLAG_WCACHE) && + (flags & SATA_FLAG_FLUSH)) + dwc_ahsata_flush_cache(dev); + } + return rc; +} + +int scan_sata(int dev) +{ + 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 }; + u16 *id; + u64 n_sectors; + struct ahci_probe_ent *probe_ent = + (struct ahci_probe_ent *)sata_dev_desc[dev].priv; + u8 port = probe_ent->hard_port_no; + struct blk_desc *pdev = &(sata_dev_desc[dev]); + + id = (u16 *)memalign(ARCH_DMA_MINALIGN, + roundup(ARCH_DMA_MINALIGN, + (ATA_ID_WORDS * 2))); + if (!id) { + printf("id malloc failed\n\r"); + return -1; + } + + /* Identify device to get information */ + dwc_ahsata_identify(dev, 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)); + + /* Totoal sectors */ + n_sectors = ata_id_n_sectors(id); + pdev->lba = (u32)n_sectors; + + 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 */ + probe_ent->flags &= (~SATA_FLAG_Q_DEP_MASK); + probe_ent->flags |= ata_id_queue_depth(id); + + /* Get the xfer mode from device */ + dwc_ahsata_xfer_mode(dev, id); + + /* Get the write cache status from device */ + dwc_ahsata_init_wcache(dev, id); + + /* Set the xfer mode to highest speed */ + ahci_set_feature(dev, port); + + free((void *)id); + + dwc_ahsata_print_info(dev); + + is_ready = 1; + + return 0; +} diff --git a/drivers/ata/dwc_ahsata.h b/drivers/ata/dwc_ahsata.h new file mode 100644 index 0000000000..caa2e501f9 --- /dev/null +++ b/drivers/ata/dwc_ahsata.h @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * Terry Lv + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __FSL_SATA_H__ +#define __FSL_SATA_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 /* __FSL_SATA_H__ */ diff --git a/drivers/ata/fsl_sata.c b/drivers/ata/fsl_sata.c new file mode 100644 index 0000000000..31f7fab8b4 --- /dev/null +++ b/drivers/ata/fsl_sata.c @@ -0,0 +1,854 @@ +/* + * Copyright (C) 2008,2010 Freescale Semiconductor, Inc. + * Dave Liu + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fsl_sata.h" + +#ifndef CONFIG_SYS_SATA1_FLAGS + #define CONFIG_SYS_SATA1_FLAGS FLAGS_DMA +#endif +#ifndef CONFIG_SYS_SATA2_FLAGS + #define CONFIG_SYS_SATA2_FLAGS FLAGS_DMA +#endif + +static struct fsl_sata_info fsl_sata_info[] = { +#ifdef CONFIG_SATA1 + {CONFIG_SYS_SATA1, CONFIG_SYS_SATA1_FLAGS}, +#else + {0, 0}, +#endif +#ifdef CONFIG_SATA2 + {CONFIG_SYS_SATA2, CONFIG_SYS_SATA2_FLAGS}, +#else + {0, 0}, +#endif +}; + +static inline void sdelay(unsigned long sec) +{ + unsigned long i; + for (i = 0; i < sec; i++) + mdelay(1000); +} + +static void fsl_sata_dump_sfis(struct sata_fis_d2h *s) +{ + printf("Status FIS dump:\n\r"); + printf("fis_type: %02x\n\r", s->fis_type); + printf("pm_port_i: %02x\n\r", s->pm_port_i); + printf("status: %02x\n\r", s->status); + printf("error: %02x\n\r", s->error); + printf("lba_low: %02x\n\r", s->lba_low); + printf("lba_mid: %02x\n\r", s->lba_mid); + printf("lba_high: %02x\n\r", s->lba_high); + printf("device: %02x\n\r", s->device); + printf("lba_low_exp: %02x\n\r", s->lba_low_exp); + printf("lba_mid_exp: %02x\n\r", s->lba_mid_exp); + printf("lba_high_exp: %02x\n\r", s->lba_high_exp); + printf("res1: %02x\n\r", s->res1); + printf("sector_count: %02x\n\r", s->sector_count); + printf("sector_count_exp: %02x\n\r", s->sector_count_exp); +} + +static int ata_wait_register(unsigned __iomem *addr, u32 mask, + u32 val, u32 timeout_msec) +{ + int i; + u32 temp; + + for (i = 0; (((temp = in_le32(addr)) & mask) != val) + && i < timeout_msec; i++) + mdelay(1); + return (i < timeout_msec) ? 0 : -1; +} + +int init_sata(int dev) +{ + u32 length, align; + cmd_hdr_tbl_t *cmd_hdr; + u32 cda; + u32 val32; + fsl_sata_reg_t __iomem *reg; + u32 sig; + int i; + fsl_sata_t *sata; + + if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) { + printf("the sata index %d is out of ranges\n\r", dev); + return -1; + } + +#ifdef CONFIG_MPC85xx + if ((dev == 0) && (!is_serdes_configured(SATA1))) { + printf("SATA%d [dev = %d] is not enabled\n", dev+1, dev); + return -1; + } + if ((dev == 1) && (!is_serdes_configured(SATA2))) { + printf("SATA%d [dev = %d] is not enabled\n", dev+1, dev); + return -1; + } +#endif + + /* Allocate SATA device driver struct */ + sata = (fsl_sata_t *)malloc(sizeof(fsl_sata_t)); + if (!sata) { + printf("alloc the sata device struct failed\n\r"); + return -1; + } + /* Zero all of the device driver struct */ + memset((void *)sata, 0, sizeof(fsl_sata_t)); + + /* Save the private struct to block device struct */ + sata_dev_desc[dev].priv = (void *)sata; + + snprintf(sata->name, 12, "SATA%d", dev); + + /* Set the controller register base address to device struct */ + reg = (fsl_sata_reg_t *)(fsl_sata_info[dev].sata_reg_base); + sata->reg_base = reg; + + /* Allocate the command header table, 4 bytes aligned */ + length = sizeof(struct cmd_hdr_tbl); + align = SATA_HC_CMD_HDR_TBL_ALIGN; + sata->cmd_hdr_tbl_offset = (void *)malloc(length + align); + if (!sata->cmd_hdr_tbl_offset) { + printf("alloc the command header failed\n\r"); + return -1; + } + + cmd_hdr = (cmd_hdr_tbl_t *)(((u32)sata->cmd_hdr_tbl_offset + align) + & ~(align - 1)); + sata->cmd_hdr = cmd_hdr; + + /* Zero all of the command header table */ + memset((void *)sata->cmd_hdr_tbl_offset, 0, length + align); + + /* Allocate command descriptor for all command */ + length = sizeof(struct cmd_desc) * SATA_HC_MAX_CMD; + align = SATA_HC_CMD_DESC_ALIGN; + sata->cmd_desc_offset = (void *)malloc(length + align); + if (!sata->cmd_desc_offset) { + printf("alloc the command descriptor failed\n\r"); + return -1; + } + sata->cmd_desc = (cmd_desc_t *)(((u32)sata->cmd_desc_offset + align) + & ~(align - 1)); + /* Zero all of command descriptor */ + memset((void *)sata->cmd_desc_offset, 0, length + align); + + /* Link the command descriptor to command header */ + for (i = 0; i < SATA_HC_MAX_CMD; i++) { + cda = ((u32)sata->cmd_desc + SATA_HC_CMD_DESC_SIZE * i) + & ~(CMD_HDR_CDA_ALIGN - 1); + cmd_hdr->cmd_slot[i].cda = cpu_to_le32(cda); + } + + /* To have safe state, force the controller offline */ + val32 = in_le32(®->hcontrol); + val32 &= ~HCONTROL_ONOFF; + val32 |= HCONTROL_FORCE_OFFLINE; + out_le32(®->hcontrol, val32); + + /* Wait the controller offline */ + ata_wait_register(®->hstatus, HSTATUS_ONOFF, 0, 1000); + + /* Set the command header base address to CHBA register to tell DMA */ + out_le32(®->chba, (u32)cmd_hdr & ~0x3); + + /* Snoop for the command header */ + val32 = in_le32(®->hcontrol); + val32 |= HCONTROL_HDR_SNOOP; + out_le32(®->hcontrol, val32); + + /* Disable all of interrupts */ + val32 = in_le32(®->hcontrol); + val32 &= ~HCONTROL_INT_EN_ALL; + out_le32(®->hcontrol, val32); + + /* Clear all of interrupts */ + val32 = in_le32(®->hstatus); + out_le32(®->hstatus, val32); + + /* Set the ICC, no interrupt coalescing */ + out_le32(®->icc, 0x01000000); + + /* No PM attatched, the SATA device direct connect */ + out_le32(®->cqpmp, 0); + + /* Clear SError register */ + val32 = in_le32(®->serror); + out_le32(®->serror, val32); + + /* Clear CER register */ + val32 = in_le32(®->cer); + out_le32(®->cer, val32); + + /* Clear DER register */ + val32 = in_le32(®->der); + out_le32(®->der, val32); + + /* No device detection or initialization action requested */ + out_le32(®->scontrol, 0x00000300); + + /* Configure the transport layer, default value */ + out_le32(®->transcfg, 0x08000016); + + /* Configure the link layer, default value */ + out_le32(®->linkcfg, 0x0000ff34); + + /* Bring the controller online */ + val32 = in_le32(®->hcontrol); + val32 |= HCONTROL_ONOFF; + out_le32(®->hcontrol, val32); + + mdelay(100); + + /* print sata device name */ + if (!dev) + printf("%s ", sata->name); + else + printf(" %s ", sata->name); + + /* Wait PHY RDY signal changed for 500ms */ + ata_wait_register(®->hstatus, HSTATUS_PHY_RDY, + HSTATUS_PHY_RDY, 500); + + /* Check PHYRDY */ + val32 = in_le32(®->hstatus); + if (val32 & HSTATUS_PHY_RDY) { + sata->link = 1; + } else { + sata->link = 0; + printf("(No RDY)\n\r"); + return -1; + } + + /* Wait for signature updated, which is 1st D2H */ + ata_wait_register(®->hstatus, HSTATUS_SIGNATURE, + HSTATUS_SIGNATURE, 10000); + + if (val32 & HSTATUS_SIGNATURE) { + sig = in_le32(®->sig); + debug("Signature updated, the sig =%08x\n\r", sig); + sata->ata_device_type = ata_dev_classify(sig); + } + + /* Check the speed */ + val32 = in_le32(®->sstatus); + if ((val32 & SSTATUS_SPD_MASK) == SSTATUS_SPD_GEN1) + printf("(1.5 Gbps)\n\r"); + else if ((val32 & SSTATUS_SPD_MASK) == SSTATUS_SPD_GEN2) + printf("(3 Gbps)\n\r"); + + return 0; +} + +int reset_sata(int dev) +{ + return 0; +} + +static void fsl_sata_dump_regs(fsl_sata_reg_t __iomem *reg) +{ + printf("\n\rSATA: %08x\n\r", (u32)reg); + printf("CQR: %08x\n\r", in_le32(®->cqr)); + printf("CAR: %08x\n\r", in_le32(®->car)); + printf("CCR: %08x\n\r", in_le32(®->ccr)); + printf("CER: %08x\n\r", in_le32(®->cer)); + printf("CQR: %08x\n\r", in_le32(®->cqr)); + printf("DER: %08x\n\r", in_le32(®->der)); + printf("CHBA: %08x\n\r", in_le32(®->chba)); + printf("HStatus: %08x\n\r", in_le32(®->hstatus)); + printf("HControl: %08x\n\r", in_le32(®->hcontrol)); + printf("CQPMP: %08x\n\r", in_le32(®->cqpmp)); + printf("SIG: %08x\n\r", in_le32(®->sig)); + printf("ICC: %08x\n\r", in_le32(®->icc)); + printf("SStatus: %08x\n\r", in_le32(®->sstatus)); + printf("SError: %08x\n\r", in_le32(®->serror)); + printf("SControl: %08x\n\r", in_le32(®->scontrol)); + printf("SNotification: %08x\n\r", in_le32(®->snotification)); + printf("TransCfg: %08x\n\r", in_le32(®->transcfg)); + printf("TransStatus: %08x\n\r", in_le32(®->transstatus)); + printf("LinkCfg: %08x\n\r", in_le32(®->linkcfg)); + printf("LinkCfg1: %08x\n\r", in_le32(®->linkcfg1)); + printf("LinkCfg2: %08x\n\r", in_le32(®->linkcfg2)); + printf("LinkStatus: %08x\n\r", in_le32(®->linkstatus)); + printf("LinkStatus1: %08x\n\r", in_le32(®->linkstatus1)); + printf("PhyCtrlCfg: %08x\n\r", in_le32(®->phyctrlcfg)); + printf("SYSPR: %08x\n\r", in_be32(®->syspr)); +} + +static int fsl_ata_exec_ata_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis, + int is_ncq, int tag, u8 *buffer, u32 len) +{ + cmd_hdr_entry_t *cmd_hdr; + cmd_desc_t *cmd_desc; + sata_fis_h2d_t *h2d; + prd_entry_t *prde; + u32 ext_c_ddc; + u32 prde_count; + u32 val32; + u32 ttl; + fsl_sata_reg_t __iomem *reg = sata->reg_base; + int i; + + /* Check xfer length */ + if (len > SATA_HC_MAX_XFER_LEN) { + printf("max transfer length is 64MB\n\r"); + return 0; + } + + /* Setup the command descriptor */ + cmd_desc = sata->cmd_desc + tag; + + /* Get the pointer cfis of command descriptor */ + h2d = (sata_fis_h2d_t *)cmd_desc->cfis; + + /* Zero the cfis of command descriptor */ + memset((void *)h2d, 0, SATA_HC_CMD_DESC_CFIS_SIZE); + + /* Copy the cfis from user to command descriptor */ + h2d->fis_type = cfis->fis_type; + h2d->pm_port_c = cfis->pm_port_c; + h2d->command = cfis->command; + + h2d->features = cfis->features; + h2d->features_exp = cfis->features_exp; + + h2d->lba_low = cfis->lba_low; + h2d->lba_mid = cfis->lba_mid; + h2d->lba_high = cfis->lba_high; + h2d->lba_low_exp = cfis->lba_low_exp; + h2d->lba_mid_exp = cfis->lba_mid_exp; + h2d->lba_high_exp = cfis->lba_high_exp; + + if (!is_ncq) { + h2d->sector_count = cfis->sector_count; + h2d->sector_count_exp = cfis->sector_count_exp; + } else { /* NCQ */ + h2d->sector_count = (u8)(tag << 3); + } + + h2d->device = cfis->device; + h2d->control = cfis->control; + + /* Setup the PRD table */ + prde = (prd_entry_t *)cmd_desc->prdt; + memset((void *)prde, 0, sizeof(struct prdt)); + + prde_count = 0; + ttl = len; + for (i = 0; i < SATA_HC_MAX_PRD_DIRECT; i++) { + if (!len) + break; + prde->dba = cpu_to_le32((u32)buffer & ~0x3); + debug("dba = %08x\n\r", (u32)buffer); + + if (len < PRD_ENTRY_MAX_XFER_SZ) { + ext_c_ddc = PRD_ENTRY_DATA_SNOOP | len; + debug("ext_c_ddc1 = %08x, len = %08x\n\r", ext_c_ddc, len); + prde->ext_c_ddc = cpu_to_le32(ext_c_ddc); + prde_count++; + prde++; + break; + } else { + ext_c_ddc = PRD_ENTRY_DATA_SNOOP; /* 4M bytes */ + debug("ext_c_ddc2 = %08x, len = %08x\n\r", ext_c_ddc, len); + prde->ext_c_ddc = cpu_to_le32(ext_c_ddc); + buffer += PRD_ENTRY_MAX_XFER_SZ; + len -= PRD_ENTRY_MAX_XFER_SZ; + prde_count++; + prde++; + } + } + + /* Setup the command slot of cmd hdr */ + cmd_hdr = (cmd_hdr_entry_t *)&sata->cmd_hdr->cmd_slot[tag]; + + cmd_hdr->cda = cpu_to_le32((u32)cmd_desc & ~0x3); + + val32 = prde_count << CMD_HDR_PRD_ENTRY_SHIFT; + val32 |= sizeof(sata_fis_h2d_t); + cmd_hdr->prde_fis_len = cpu_to_le32(val32); + + cmd_hdr->ttl = cpu_to_le32(ttl); + + if (!is_ncq) { + val32 = CMD_HDR_ATTR_RES | CMD_HDR_ATTR_SNOOP; + } else { + val32 = CMD_HDR_ATTR_RES | CMD_HDR_ATTR_SNOOP | CMD_HDR_ATTR_FPDMA; + } + + tag &= CMD_HDR_ATTR_TAG; + val32 |= tag; + + debug("attribute = %08x\n\r", val32); + cmd_hdr->attribute = cpu_to_le32(val32); + + /* Make sure cmd desc and cmd slot valid before command issue */ + sync(); + + /* PMP*/ + val32 = (u32)(h2d->pm_port_c & 0x0f); + out_le32(®->cqpmp, val32); + + /* Wait no active */ + if (ata_wait_register(®->car, (1 << tag), 0, 10000)) + printf("Wait no active time out\n\r"); + + /* Issue command */ + if (!(in_le32(®->cqr) & (1 << tag))) { + val32 = 1 << tag; + out_le32(®->cqr, val32); + } + + /* Wait command completed for 10s */ + if (ata_wait_register(®->ccr, (1 << tag), (1 << tag), 10000)) { + if (!is_ncq) + printf("Non-NCQ command time out\n\r"); + else + printf("NCQ command time out\n\r"); + } + + val32 = in_le32(®->cer); + + if (val32) { + u32 der; + fsl_sata_dump_sfis((struct sata_fis_d2h *)cmd_desc->sfis); + printf("CE at device\n\r"); + fsl_sata_dump_regs(reg); + der = in_le32(®->der); + out_le32(®->cer, val32); + out_le32(®->der, der); + } + + /* Clear complete flags */ + val32 = in_le32(®->ccr); + out_le32(®->ccr, val32); + + return len; +} + +static int fsl_ata_exec_reset_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis, + int tag, u8 *buffer, u32 len) +{ + return 0; +} + +static int fsl_sata_exec_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis, + enum cmd_type command_type, int tag, u8 *buffer, u32 len) +{ + int rc; + + if (tag > SATA_HC_MAX_CMD || tag < 0) { + printf("tag is out of range, tag=%d\n\r", tag); + return -1; + } + + switch (command_type) { + case CMD_ATA: + rc = fsl_ata_exec_ata_cmd(sata, cfis, 0, tag, buffer, len); + return rc; + case CMD_RESET: + rc = fsl_ata_exec_reset_cmd(sata, cfis, tag, buffer, len); + return rc; + case CMD_NCQ: + rc = fsl_ata_exec_ata_cmd(sata, cfis, 1, tag, buffer, len); + return rc; + case CMD_ATAPI: + case CMD_VENDOR_BIST: + case CMD_BIST: + printf("not support now\n\r"); + return -1; + default: + break; + } + + return -1; +} + +static void fsl_sata_identify(int dev, u16 *id) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d, *cfis = &h2d; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = ATA_CMD_ID_ATA; + + fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, (u8 *)id, ATA_ID_WORDS * 2); + ata_swap_buf_le16(id, ATA_ID_WORDS); +} + +static void fsl_sata_xfer_mode(int dev, u16 *id) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + + sata->pio = id[ATA_ID_PIO_MODES]; + sata->mwdma = id[ATA_ID_MWDMA_MODES]; + sata->udma = id[ATA_ID_UDMA_MODES]; + debug("pio %04x, mwdma %04x, udma %04x\n\r", sata->pio, sata->mwdma, sata->udma); +} + +static void fsl_sata_set_features(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d, *cfis = &h2d; + u8 udma_cap; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = ATA_CMD_SET_FEATURES; + cfis->features = SETFEATURES_XFER; + + /* First check the device capablity */ + udma_cap = (u8)(sata->udma & 0xff); + debug("udma_cap %02x\n\r", udma_cap); + + if (udma_cap == ATA_UDMA6) + cfis->sector_count = XFER_UDMA_6; + if (udma_cap == ATA_UDMA5) + cfis->sector_count = XFER_UDMA_5; + if (udma_cap == ATA_UDMA4) + cfis->sector_count = XFER_UDMA_4; + if (udma_cap == ATA_UDMA3) + cfis->sector_count = XFER_UDMA_3; + + fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0); +} + +static u32 fsl_sata_rw_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d, *cfis = &h2d; + u32 block; + + block = start; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = (is_write) ? ATA_CMD_WRITE : ATA_CMD_READ; + cfis->device = ATA_LBA; + + cfis->device |= (block >> 24) & 0xf; + cfis->lba_high = (block >> 16) & 0xff; + cfis->lba_mid = (block >> 8) & 0xff; + cfis->lba_low = block & 0xff; + cfis->sector_count = (u8)(blkcnt & 0xff); + + fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, buffer, ATA_SECT_SIZE * blkcnt); + return blkcnt; +} + +static void fsl_sata_flush_cache(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d, *cfis = &h2d; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = ATA_CMD_FLUSH; + + fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0); +} + +static u32 fsl_sata_rw_cmd_ext(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d, *cfis = &h2d; + u64 block; + + block = (u64)start; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + + cfis->command = (is_write) ? ATA_CMD_WRITE_EXT + : ATA_CMD_READ_EXT; + + cfis->lba_high_exp = (block >> 40) & 0xff; + cfis->lba_mid_exp = (block >> 32) & 0xff; + cfis->lba_low_exp = (block >> 24) & 0xff; + cfis->lba_high = (block >> 16) & 0xff; + cfis->lba_mid = (block >> 8) & 0xff; + cfis->lba_low = block & 0xff; + cfis->device = ATA_LBA; + cfis->sector_count_exp = (blkcnt >> 8) & 0xff; + cfis->sector_count = blkcnt & 0xff; + + fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, buffer, ATA_SECT_SIZE * blkcnt); + return blkcnt; +} + +static u32 fsl_sata_rw_ncq_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, + int is_write) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d, *cfis = &h2d; + int ncq_channel; + u64 block; + + if (sata->lba48 != 1) { + printf("execute FPDMA command on non-LBA48 hard disk\n\r"); + return -1; + } + + block = (u64)start; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + + cfis->command = (is_write) ? ATA_CMD_FPDMA_WRITE + : ATA_CMD_FPDMA_READ; + + cfis->lba_high_exp = (block >> 40) & 0xff; + cfis->lba_mid_exp = (block >> 32) & 0xff; + cfis->lba_low_exp = (block >> 24) & 0xff; + cfis->lba_high = (block >> 16) & 0xff; + cfis->lba_mid = (block >> 8) & 0xff; + cfis->lba_low = block & 0xff; + + cfis->device = ATA_LBA; + cfis->features_exp = (blkcnt >> 8) & 0xff; + cfis->features = blkcnt & 0xff; + + if (sata->queue_depth >= SATA_HC_MAX_CMD) + ncq_channel = SATA_HC_MAX_CMD - 1; + else + ncq_channel = sata->queue_depth - 1; + + /* Use the latest queue */ + fsl_sata_exec_cmd(sata, cfis, CMD_NCQ, ncq_channel, buffer, ATA_SECT_SIZE * blkcnt); + return blkcnt; +} + +static void fsl_sata_flush_cache_ext(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + struct sata_fis_h2d h2d, *cfis = &h2d; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = ATA_CMD_FLUSH_EXT; + + fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0); +} + +static void fsl_sata_init_wcache(int dev, u16 *id) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + + if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id)) + sata->wcache = 1; + if (ata_id_has_flush(id)) + sata->flush = 1; + if (ata_id_has_flush_ext(id)) + sata->flush_ext = 1; +} + +static int fsl_sata_get_wcache(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + return sata->wcache; +} + +static int fsl_sata_get_flush(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + return sata->flush; +} + +static int fsl_sata_get_flush_ext(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + return sata->flush_ext; +} + +static u32 ata_low_level_rw_lba48(int dev, 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 (fsl_sata_info[dev].flags != FLAGS_FPDMA) + fsl_sata_rw_cmd_ext(dev, start, max_blks, addr, is_write); + else + fsl_sata_rw_ncq_cmd(dev, start, max_blks, addr, is_write); + start += max_blks; + blks -= max_blks; + addr += ATA_SECT_SIZE * max_blks; + } else { + if (fsl_sata_info[dev].flags != FLAGS_FPDMA) + fsl_sata_rw_cmd_ext(dev, start, blks, addr, is_write); + else + fsl_sata_rw_ncq_cmd(dev, start, blks, addr, is_write); + start += blks; + blks = 0; + addr += ATA_SECT_SIZE * blks; + } + } while (blks != 0); + + return blkcnt; +} + +static u32 ata_low_level_rw_lba28(int dev, u32 blknr, u32 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) { + fsl_sata_rw_cmd(dev, start, max_blks, addr, is_write); + start += max_blks; + blks -= max_blks; + addr += ATA_SECT_SIZE * max_blks; + } else { + fsl_sata_rw_cmd(dev, start, blks, addr, is_write); + start += blks; + blks = 0; + addr += ATA_SECT_SIZE * blks; + } + } while (blks != 0); + + return blkcnt; +} + +/* + * SATA interface between low level driver and command layer + */ +ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) +{ + u32 rc; + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + + if (sata->lba48) + rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, READ_CMD); + else + rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, buffer, READ_CMD); + return rc; +} + +ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) +{ + u32 rc; + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + + if (sata->lba48) { + rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, WRITE_CMD); + if (fsl_sata_get_wcache(dev) && fsl_sata_get_flush_ext(dev)) + fsl_sata_flush_cache_ext(dev); + } else { + rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, buffer, WRITE_CMD); + if (fsl_sata_get_wcache(dev) && fsl_sata_get_flush(dev)) + fsl_sata_flush_cache(dev); + } + return rc; +} + +int scan_sata(int dev) +{ + fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; + unsigned char serial[ATA_ID_SERNO_LEN + 1]; + unsigned char firmware[ATA_ID_FW_REV_LEN + 1]; + unsigned char product[ATA_ID_PROD_LEN + 1]; + u16 *id; + u64 n_sectors; + + /* if no detected link */ + if (!sata->link) + return -1; + + id = (u16 *)malloc(ATA_ID_WORDS * 2); + if (!id) { + printf("id malloc failed\n\r"); + return -1; + } + + /* Identify device to get information */ + fsl_sata_identify(dev, id); + + /* Serial number */ + ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); + memcpy(sata_dev_desc[dev].product, serial, sizeof(serial)); + + /* Firmware version */ + ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); + memcpy(sata_dev_desc[dev].revision, firmware, sizeof(firmware)); + + /* Product model */ + ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); + memcpy(sata_dev_desc[dev].vendor, product, sizeof(product)); + + /* Totoal sectors */ + n_sectors = ata_id_n_sectors(id); + sata_dev_desc[dev].lba = (u32)n_sectors; + +#ifdef CONFIG_LBA48 + /* Check if support LBA48 */ + if (ata_id_has_lba48(id)) { + sata->lba48 = 1; + debug("Device support LBA48\n\r"); + } else + debug("Device supports LBA28\n\r"); +#endif + + /* Get the NCQ queue depth from device */ + sata->queue_depth = ata_id_queue_depth(id); + + /* Get the xfer mode from device */ + fsl_sata_xfer_mode(dev, id); + + /* Get the write cache status from device */ + fsl_sata_init_wcache(dev, id); + + /* Set the xfer mode to highest speed */ + fsl_sata_set_features(dev); +#ifdef DEBUG + fsl_sata_identify(dev, id); + ata_dump_id(id); +#endif + free((void *)id); + return 0; +} diff --git a/drivers/ata/fsl_sata.h b/drivers/ata/fsl_sata.h new file mode 100644 index 0000000000..18d679e782 --- /dev/null +++ b/drivers/ata/fsl_sata.h @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2007-2008 Freescale Semiconductor, Inc. + * Dave Liu + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __FSL_SATA_H__ +#define __FSL_SATA_H__ + +#define SATA_HC_MAX_NUM 4 /* Max host controller numbers */ +#define SATA_HC_MAX_CMD 16 /* Max command queue depth per host controller */ +#define SATA_HC_MAX_PORT 16 /* Max port number per host controller */ + +/* +* SATA Host Controller Registers +*/ +typedef struct fsl_sata_reg { + /* SATA command registers */ + u32 cqr; /* Command queue register */ + u8 res1[0x4]; + u32 car; /* Command active register */ + u8 res2[0x4]; + u32 ccr; /* Command completed register */ + u8 res3[0x4]; + u32 cer; /* Command error register */ + u8 res4[0x4]; + u32 der; /* Device error register */ + u32 chba; /* Command header base address */ + u32 hstatus; /* Host status register */ + u32 hcontrol; /* Host control register */ + u32 cqpmp; /* Port number queue register */ + u32 sig; /* Signature register */ + u32 icc; /* Interrupt coalescing control register */ + u8 res5[0xc4]; + + /* SATA supperset registers */ + u32 sstatus; /* SATA interface status register */ + u32 serror; /* SATA interface error register */ + u32 scontrol; /* SATA interface control register */ + u32 snotification; /* SATA interface notification register */ + u8 res6[0x30]; + + /* SATA control status registers */ + u32 transcfg; /* Transport layer configuration */ + u32 transstatus; /* Transport layer status */ + u32 linkcfg; /* Link layer configuration */ + u32 linkcfg1; /* Link layer configuration1 */ + u32 linkcfg2; /* Link layer configuration2 */ + u32 linkstatus; /* Link layer status */ + u32 linkstatus1; /* Link layer status1 */ + u32 phyctrlcfg; /* PHY control configuration */ + u8 res7[0x2b0]; + + /* SATA system control registers */ + u32 syspr; /* System priority register - big endian */ + u8 res8[0xbec]; +} __attribute__ ((packed)) fsl_sata_reg_t; + +/* HStatus register +*/ +#define HSTATUS_ONOFF 0x80000000 /* Online/offline status */ +#define HSTATUS_FORCE_OFFLINE 0x40000000 /* In process going offline */ +#define HSTATUS_BIST_ERR 0x20000000 + +/* Fatal error */ +#define HSTATUS_MASTER_ERR 0x00004000 +#define HSTATUS_DATA_UNDERRUN 0x00002000 +#define HSTATUS_DATA_OVERRUN 0x00001000 +#define HSTATUS_CRC_ERR_TX 0x00000800 +#define HSTATUS_CRC_ERR_RX 0x00000400 +#define HSTATUS_FIFO_OVERFLOW_TX 0x00000200 +#define HSTATUS_FIFO_OVERFLOW_RX 0x00000100 +#define HSTATUS_FATAL_ERR_ALL (HSTATUS_MASTER_ERR | \ + HSTATUS_DATA_UNDERRUN | \ + HSTATUS_DATA_OVERRUN | \ + HSTATUS_CRC_ERR_TX | \ + HSTATUS_CRC_ERR_RX | \ + HSTATUS_FIFO_OVERFLOW_TX | \ + HSTATUS_FIFO_OVERFLOW_RX) +/* Interrupt status */ +#define HSTATUS_FATAL_ERR 0x00000020 +#define HSTATUS_PHY_RDY 0x00000010 +#define HSTATUS_SIGNATURE 0x00000008 +#define HSTATUS_SNOTIFY 0x00000004 +#define HSTATUS_DEVICE_ERR 0x00000002 +#define HSTATUS_CMD_COMPLETE 0x00000001 + +/* HControl register +*/ +#define HCONTROL_ONOFF 0x80000000 /* Online or offline request */ +#define HCONTROL_FORCE_OFFLINE 0x40000000 /* Force offline request */ +#define HCONTROL_ENTERPRISE_EN 0x10000000 /* Enterprise mode enabled */ +#define HCONTROL_HDR_SNOOP 0x00000400 /* Command header snoop */ +#define HCONTROL_PMP_ATTACHED 0x00000200 /* Port multiplier attached */ + +/* Interrupt enable */ +#define HCONTROL_FATAL_ERR 0x00000020 +#define HCONTROL_PHY_RDY 0x00000010 +#define HCONTROL_SIGNATURE 0x00000008 +#define HCONTROL_SNOTIFY 0x00000004 +#define HCONTROL_DEVICE_ERR 0x00000002 +#define HCONTROL_CMD_COMPLETE 0x00000001 + +#define HCONTROL_INT_EN_ALL (HCONTROL_FATAL_ERR | \ + HCONTROL_PHY_RDY | \ + HCONTROL_SIGNATURE | \ + HCONTROL_SNOTIFY | \ + HCONTROL_DEVICE_ERR | \ + HCONTROL_CMD_COMPLETE) + +/* SStatus register +*/ +#define SSTATUS_IPM_MASK 0x00000780 +#define SSTATUS_IPM_NOPRESENT 0x00000000 +#define SSTATUS_IPM_ACTIVE 0x00000080 +#define SSTATUS_IPM_PATIAL 0x00000100 +#define SSTATUS_IPM_SLUMBER 0x00000300 + +#define SSTATUS_SPD_MASK 0x000000f0 +#define SSTATUS_SPD_GEN1 0x00000010 +#define SSTATUS_SPD_GEN2 0x00000020 + +#define SSTATUS_DET_MASK 0x0000000f +#define SSTATUS_DET_NODEVICE 0x00000000 +#define SSTATUS_DET_DISCONNECT 0x00000001 +#define SSTATUS_DET_CONNECT 0x00000003 +#define SSTATUS_DET_PHY_OFFLINE 0x00000004 + +/* SControl register +*/ +#define SCONTROL_SPM_MASK 0x0000f000 +#define SCONTROL_SPM_GO_PARTIAL 0x00001000 +#define SCONTROL_SPM_GO_SLUMBER 0x00002000 +#define SCONTROL_SPM_GO_ACTIVE 0x00004000 + +#define SCONTROL_IPM_MASK 0x00000f00 +#define SCONTROL_IPM_NO_RESTRICT 0x00000000 +#define SCONTROL_IPM_PARTIAL 0x00000100 +#define SCONTROL_IPM_SLUMBER 0x00000200 +#define SCONTROL_IPM_PART_SLUM 0x00000300 + +#define SCONTROL_SPD_MASK 0x000000f0 +#define SCONTROL_SPD_NO_RESTRICT 0x00000000 +#define SCONTROL_SPD_GEN1 0x00000010 +#define SCONTROL_SPD_GEN2 0x00000020 + +#define SCONTROL_DET_MASK 0x0000000f +#define SCONTROL_DET_HRESET 0x00000001 +#define SCONTROL_DET_DISABLE 0x00000004 + +/* TransCfg register +*/ +#define TRANSCFG_DFIS_SIZE_SHIFT 16 +#define TRANSCFG_RX_WATER_MARK_MASK 0x0000001f + +/* PhyCtrlCfg register +*/ +#define PHYCTRLCFG_FPRFTI_MASK 0x00000018 +#define PHYCTRLCFG_LOOPBACK_MASK 0x0000000e + +/* +* Command Header Entry +*/ +typedef struct cmd_hdr_entry { + __le32 cda; /* Command Descriptor Address, + 4 bytes aligned */ + __le32 prde_fis_len; /* Number of PRD entries and FIS length */ + __le32 ttl; /* Total transfer length */ + __le32 attribute; /* the attribute of command */ +} __attribute__ ((packed)) cmd_hdr_entry_t; + +#define SATA_HC_CMD_HDR_ENTRY_SIZE sizeof(struct cmd_hdr_entry) + +/* cda +*/ +#define CMD_HDR_CDA_ALIGN 4 + +/* prde_fis_len +*/ +#define CMD_HDR_PRD_ENTRY_SHIFT 16 +#define CMD_HDR_PRD_ENTRY_MASK 0x003f0000 +#define CMD_HDR_FIS_LEN_SHIFT 2 + +/* attribute +*/ +#define CMD_HDR_ATTR_RES 0x00000800 /* Reserved bit, should be 1 */ +#define CMD_HDR_ATTR_VBIST 0x00000400 /* Vendor BIST */ +#define CMD_HDR_ATTR_SNOOP 0x00000200 /* Snoop enable for all descriptor */ +#define CMD_HDR_ATTR_FPDMA 0x00000100 /* FPDMA queued command */ +#define CMD_HDR_ATTR_RESET 0x00000080 /* Reset - a SRST or device reset */ +#define CMD_HDR_ATTR_BIST 0x00000040 /* BIST - require the host to enter BIST mode */ +#define CMD_HDR_ATTR_ATAPI 0x00000020 /* ATAPI command */ +#define CMD_HDR_ATTR_TAG 0x0000001f /* TAG mask */ + +/* command type +*/ +enum cmd_type { + CMD_VENDOR_BIST, + CMD_BIST, + CMD_RESET, /* SRST or device reset */ + CMD_ATAPI, + CMD_NCQ, + CMD_ATA, /* None of all above */ +}; + +/* +* Command Header Table +*/ +typedef struct cmd_hdr_tbl { + cmd_hdr_entry_t cmd_slot[SATA_HC_MAX_CMD]; +} __attribute__ ((packed)) cmd_hdr_tbl_t; + +#define SATA_HC_CMD_HDR_TBL_SIZE sizeof(struct cmd_hdr_tbl) +#define SATA_HC_CMD_HDR_TBL_ALIGN 4 + +/* +* PRD entry - Physical Region Descriptor entry +*/ +typedef struct prd_entry { + __le32 dba; /* Data base address, 4 bytes aligned */ + u32 res1; + u32 res2; + __le32 ext_c_ddc; /* Indirect PRD flags, snoop and data word count */ +} __attribute__ ((packed)) prd_entry_t; + +#define SATA_HC_CMD_DESC_PRD_SIZE sizeof(struct prd_entry) + +/* dba +*/ +#define PRD_ENTRY_DBA_ALIGN 4 + +/* ext_c_ddc +*/ +#define PRD_ENTRY_EXT 0x80000000 /* extension flag */ +#ifdef CONFIG_FSL_SATA_V2 +#define PRD_ENTRY_DATA_SNOOP 0x10000000 /* Data snoop enable */ +#else +#define PRD_ENTRY_DATA_SNOOP 0x00400000 /* Data snoop enable */ +#endif +#define PRD_ENTRY_LEN_MASK 0x003fffff /* Data word count */ + +#define PRD_ENTRY_MAX_XFER_SZ (PRD_ENTRY_LEN_MASK + 1) + +/* + * This SATA host controller supports a max of 16 direct PRD entries, but if use + * chained indirect PRD entries, then the contollers supports upto a max of 63 + * entries including direct and indirect PRD entries. + * The PRDT is an array of 63 PRD entries contigiously, but the PRD entries#15 + * will be setup as an indirect descriptor, pointing to it's next (contigious) + * PRD entries#16. + */ +#define SATA_HC_MAX_PRD 63 /* Max PRD entry numbers per command */ +#define SATA_HC_MAX_PRD_DIRECT 16 /* Direct PRDT entries */ +#define SATA_HC_MAX_PRD_USABLE (SATA_HC_MAX_PRD - 1) +#define SATA_HC_MAX_XFER_LEN 0x4000000 + +/* +* PRDT - Physical Region Descriptor Table +*/ +typedef struct prdt { + prd_entry_t prdt[SATA_HC_MAX_PRD]; +} __attribute__ ((packed)) prdt_t; + +/* +* Command Descriptor +*/ +#define SATA_HC_CMD_DESC_CFIS_SIZE 32 /* bytes */ +#define SATA_HC_CMD_DESC_SFIS_SIZE 32 /* bytes */ +#define SATA_HC_CMD_DESC_ACMD_SIZE 16 /* bytes */ +#define SATA_HC_CMD_DESC_RES 16 /* bytes */ + +typedef struct cmd_desc { + u8 cfis[SATA_HC_CMD_DESC_CFIS_SIZE]; + u8 sfis[SATA_HC_CMD_DESC_SFIS_SIZE]; + u8 acmd[SATA_HC_CMD_DESC_ACMD_SIZE]; + u8 res[SATA_HC_CMD_DESC_RES]; + prd_entry_t prdt[SATA_HC_MAX_PRD]; +} __attribute__ ((packed)) cmd_desc_t; + +#define SATA_HC_CMD_DESC_SIZE sizeof(struct cmd_desc) +#define SATA_HC_CMD_DESC_ALIGN 4 + +/* + * SATA device driver info + */ +typedef struct fsl_sata_info { + u32 sata_reg_base; + u32 flags; +} fsl_sata_info_t; + +#define FLAGS_DMA 0x00000000 +#define FLAGS_FPDMA 0x00000001 + +/* + * SATA device driver struct + */ +typedef struct fsl_sata { + char name[12]; + fsl_sata_reg_t *reg_base; /* the base address of controller register */ + void *cmd_hdr_tbl_offset; /* alloc address of command header table */ + cmd_hdr_tbl_t *cmd_hdr; /* aligned address of command header table */ + void *cmd_desc_offset; /* alloc address of command descriptor */ + cmd_desc_t *cmd_desc; /* aligned address of command descriptor */ + int link; /* PHY link status */ + /* device attribute */ + int ata_device_type; /* device type */ + int lba48; + int queue_depth; /* Max NCQ queue depth */ + u16 pio; + u16 mwdma; + u16 udma; + int wcache; + int flush; + int flush_ext; +} fsl_sata_t; + +#define READ_CMD 0 +#define WRITE_CMD 1 + +#endif /* __FSL_SATA_H__ */ diff --git a/drivers/ata/libata.c b/drivers/ata/libata.c new file mode 100644 index 0000000000..d684270dcd --- /dev/null +++ b/drivers/ata/libata.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2008 Freescale Semiconductor, Inc. + * Dave Liu + * port from the libata of linux kernel + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#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/drivers/ata/mvsata_ide.c b/drivers/ata/mvsata_ide.c new file mode 100644 index 0000000000..7b6a1558d2 --- /dev/null +++ b/drivers/ata/mvsata_ide.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2010 Albert ARIBAUD + * + * Written-by: Albert ARIBAUD + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +#if defined(CONFIG_ORION5X) +#include +#elif defined(CONFIG_KIRKWOOD) +#include +#elif defined(CONFIG_ARCH_MVEBU) +#include +#endif + +/* SATA port registers */ +struct mvsata_port_registers { + u32 reserved0[10]; + u32 edma_cmd; + u32 reserved1[181]; + /* offset 0x300 : ATA Interface registers */ + u32 sstatus; + u32 serror; + u32 scontrol; + u32 ltmode; + u32 phymode3; + u32 phymode4; + u32 reserved2[5]; + u32 phymode1; + u32 phymode2; + u32 bist_cr; + u32 bist_dw1; + u32 bist_dw2; + u32 serrorintrmask; +}; + +/* + * Sanity checks: + * - to compile at all, we need CONFIG_SYS_ATA_BASE_ADDR. + * - for ide_preinit to make sense, we need at least one of + * CONFIG_SYS_ATA_IDE0_OFFSET or CONFIG_SYS_ATA_IDE1_OFFSET; + * - for ide_preinit to be called, we need CONFIG_IDE_PREINIT. + * Fail with an explanation message if these conditions are not met. + * This is particularly important for CONFIG_IDE_PREINIT, because + * its lack would not cause a build error. + */ + +#if !defined(CONFIG_SYS_ATA_BASE_ADDR) +#error CONFIG_SYS_ATA_BASE_ADDR must be defined +#elif !defined(CONFIG_SYS_ATA_IDE0_OFFSET) \ + && !defined(CONFIG_SYS_ATA_IDE1_OFFSET) +#error CONFIG_SYS_ATA_IDE0_OFFSET or CONFIG_SYS_ATA_IDE1_OFFSET \ + must be defined +#elif !defined(CONFIG_IDE_PREINIT) +#error CONFIG_IDE_PREINIT must be defined +#endif + +/* + * Masks and values for SControl DETection and Interface Power Management, + * and for SStatus DETection. + */ + +#define MVSATA_EDMA_CMD_ATA_RST 0x00000004 +#define MVSATA_SCONTROL_DET_MASK 0x0000000F +#define MVSATA_SCONTROL_DET_NONE 0x00000000 +#define MVSATA_SCONTROL_DET_INIT 0x00000001 +#define MVSATA_SCONTROL_IPM_MASK 0x00000F00 +#define MVSATA_SCONTROL_IPM_NO_LP_ALLOWED 0x00000300 +#define MVSATA_SCONTROL_MASK \ + (MVSATA_SCONTROL_DET_MASK|MVSATA_SCONTROL_IPM_MASK) +#define MVSATA_PORT_INIT \ + (MVSATA_SCONTROL_DET_INIT|MVSATA_SCONTROL_IPM_NO_LP_ALLOWED) +#define MVSATA_PORT_USE \ + (MVSATA_SCONTROL_DET_NONE|MVSATA_SCONTROL_IPM_NO_LP_ALLOWED) +#define MVSATA_SSTATUS_DET_MASK 0x0000000F +#define MVSATA_SSTATUS_DET_DEVCOMM 0x00000003 + +/* + * Status codes to return to client callers. Currently, callers ignore + * exact value and only care for zero or nonzero, so no need to make this + * public, it is only #define'd for clarity. + * If/when standard negative codes are implemented in U-Boot, then these + * #defines should be moved to, or replaced by ones from, the common list + * of status codes. + */ + +#define MVSATA_STATUS_OK 0 +#define MVSATA_STATUS_TIMEOUT -1 + +/* + * Registers for SATA MBUS memory windows + */ + +#define MVSATA_WIN_CONTROL(w) (MVEBU_AXP_SATA_BASE + 0x30 + ((w) << 4)) +#define MVSATA_WIN_BASE(w) (MVEBU_AXP_SATA_BASE + 0x34 + ((w) << 4)) + +/* + * Initialize SATA memory windows for Armada XP + */ + +#ifdef CONFIG_ARCH_MVEBU +static void mvsata_ide_conf_mbus_windows(void) +{ + const struct mbus_dram_target_info *dram; + int i; + + dram = mvebu_mbus_dram_info(); + + /* Disable windows, Set Size/Base to 0 */ + for (i = 0; i < 4; i++) { + writel(0, MVSATA_WIN_CONTROL(i)); + writel(0, MVSATA_WIN_BASE(i)); + } + + for (i = 0; i < dram->num_cs; i++) { + const struct mbus_dram_window *cs = dram->cs + i; + writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) | + (dram->mbus_dram_target_id << 4) | 1, + MVSATA_WIN_CONTROL(i)); + writel(cs->base & 0xffff0000, MVSATA_WIN_BASE(i)); + } +} +#endif + +/* + * Initialize one MVSATAHC port: set SControl's IPM to "always active" + * and DET to "reset", then wait for SStatus's DET to become "device and + * comm ok" (or time out after 50 us if no device), then set SControl's + * DET back to "no action". + */ + +static int mvsata_ide_initialize_port(struct mvsata_port_registers *port) +{ + u32 control; + u32 status; + u32 timeleft = 10000; /* wait at most 10 ms for SATA reset to complete */ + + /* Hard reset */ + writel(MVSATA_EDMA_CMD_ATA_RST, &port->edma_cmd); + udelay(25); /* taken from original marvell port */ + writel(0, &port->edma_cmd); + + /* Set control IPM to 3 (no low power) and DET to 1 (initialize) */ + control = readl(&port->scontrol); + control = (control & ~MVSATA_SCONTROL_MASK) | MVSATA_PORT_INIT; + writel(control, &port->scontrol); + /* Toggle control DET back to 0 (normal operation) */ + control = (control & ~MVSATA_SCONTROL_MASK) | MVSATA_PORT_USE; + writel(control, &port->scontrol); + /* wait for status DET to become 3 (device and communication OK) */ + while (--timeleft) { + status = readl(&port->sstatus) & MVSATA_SSTATUS_DET_MASK; + if (status == MVSATA_SSTATUS_DET_DEVCOMM) + break; + udelay(1); + } + /* return success or time-out error depending on time left */ + if (!timeleft) + return MVSATA_STATUS_TIMEOUT; + return MVSATA_STATUS_OK; +} + +/* + * ide_preinit() will be called by ide_init in cmd_ide.c and will + * reset the MVSTATHC ports needed by the board. + */ + +int ide_preinit(void) +{ + int ret = MVSATA_STATUS_TIMEOUT; + int status; + +#ifdef CONFIG_ARCH_MVEBU + mvsata_ide_conf_mbus_windows(); +#endif + + /* Enable ATA port 0 (could be SATA port 0 or 1) if declared */ +#if defined(CONFIG_SYS_ATA_IDE0_OFFSET) + status = mvsata_ide_initialize_port( + (struct mvsata_port_registers *) + (CONFIG_SYS_ATA_BASE_ADDR + CONFIG_SYS_ATA_IDE0_OFFSET)); + if (status == MVSATA_STATUS_OK) + ret = MVSATA_STATUS_OK; +#endif + /* Enable ATA port 1 (could be SATA port 0 or 1) if declared */ +#if defined(CONFIG_SYS_ATA_IDE1_OFFSET) + status = mvsata_ide_initialize_port( + (struct mvsata_port_registers *) + (CONFIG_SYS_ATA_BASE_ADDR + CONFIG_SYS_ATA_IDE1_OFFSET)); + if (status == MVSATA_STATUS_OK) + ret = MVSATA_STATUS_OK; +#endif + /* Return success if at least one port initialization succeeded */ + return ret; +} diff --git a/drivers/ata/mxc_ata.c b/drivers/ata/mxc_ata.c new file mode 100644 index 0000000000..44bb406f4d --- /dev/null +++ b/drivers/ata/mxc_ata.c @@ -0,0 +1,129 @@ +/* + * Freescale iMX51 ATA driver + * + * Copyright (C) 2010 Marek Vasut + * + * Based on code by: + * Mahesh Mahadevan + * + * Based on code from original FSL ATA driver, which is + * part of eCos, the Embedded Configurable Operating System. + * Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* MXC ATA register offsets */ +struct mxc_ata_config_regs { + u8 time_off; /* 0x00 */ + u8 time_on; + u8 time_1; + u8 time_2w; + u8 time_2r; + u8 time_ax; + u8 time_pio_rdx; + u8 time_4; + u8 time_9; + u8 time_m; + u8 time_jn; + u8 time_d; + u8 time_k; + u8 time_ack; + u8 time_env; + u8 time_udma_rdx; + u8 time_zah; /* 0x10 */ + u8 time_mlix; + u8 time_dvh; + u8 time_dzfs; + u8 time_dvs; + u8 time_cvh; + u8 time_ss; + u8 time_cyc; + u32 fifo_data_32; /* 0x18 */ + u32 fifo_data_16; + u32 fifo_fill; + u32 ata_control; + u32 interrupt_pending; + u32 interrupt_enable; + u32 interrupt_clear; + u32 fifo_alarm; +}; + +struct mxc_data_hdd_regs { + u32 drive_data; /* 0xa0 */ + u32 drive_features; + u32 drive_sector_count; + u32 drive_sector_num; + u32 drive_cyl_low; + u32 drive_cyl_high; + u32 drive_dev_head; + u32 command; + u32 status; + u32 alt_status; +}; + +/* PIO timing table */ +#define NR_PIO_SPECS 5 +static uint16_t pio_t1[NR_PIO_SPECS] = { 70, 50, 30, 30, 25 }; +static uint16_t pio_t2_8[NR_PIO_SPECS] = { 290, 290, 290, 80, 70 }; +static uint16_t pio_t4[NR_PIO_SPECS] = { 30, 20, 15, 10, 10 }; +static uint16_t pio_t9[NR_PIO_SPECS] = { 20, 15, 10, 10, 10 }; +static uint16_t pio_tA[NR_PIO_SPECS] = { 50, 50, 50, 50, 50 }; + +#define REG2OFF(reg) ((((uint32_t)reg) & 0x3) * 8) +static void set_ata_bus_timing(unsigned char mode) +{ + uint32_t T = 1000000000 / mxc_get_clock(MXC_IPG_CLK); + + struct mxc_ata_config_regs *ata_regs; + ata_regs = (struct mxc_ata_config_regs *)CONFIG_SYS_ATA_BASE_ADDR; + + if (mode >= NR_PIO_SPECS) + return; + + /* Write TIME_OFF/ON/1/2W */ + writeb(3, &ata_regs->time_off); + writeb(3, &ata_regs->time_on); + writeb((pio_t1[mode] + T) / T, &ata_regs->time_1); + writeb((pio_t2_8[mode] + T) / T, &ata_regs->time_2w); + + /* Write TIME_2R/AX/RDX/4 */ + writeb((pio_t2_8[mode] + T) / T, &ata_regs->time_2r); + writeb((pio_tA[mode] + T) / T + 2, &ata_regs->time_ax); + writeb(1, &ata_regs->time_pio_rdx); + writeb((pio_t4[mode] + T) / T, &ata_regs->time_4); + + /* Write TIME_9 ; the rest of timing registers is irrelevant for PIO */ + writeb((pio_t9[mode] + T) / T, &ata_regs->time_9); +} + +int ide_preinit(void) +{ + struct mxc_ata_config_regs *ata_regs; + ata_regs = (struct mxc_ata_config_regs *)CONFIG_SYS_ATA_BASE_ADDR; + + /* 46.3.3.4 @ FSL iMX51 manual */ + /* FIFO normal op., drive reset */ + writel(0x80, &ata_regs->ata_control); + /* FIFO normal op., drive not reset */ + writel(0xc0, &ata_regs->ata_control); + + /* Configure the PIO timing */ + set_ata_bus_timing(CONFIG_MXC_ATA_PIO_MODE); + + /* 46.3.3.4 @ FSL iMX51 manual */ + /* Drive not reset, IORDY handshake */ + writel(0x41, &ata_regs->ata_control); + + return 0; +} diff --git a/drivers/ata/sata.c b/drivers/ata/sata.c new file mode 100644 index 0000000000..42ff5c7755 --- /dev/null +++ b/drivers/ata/sata.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2000-2005, DENX Software Engineering + * Wolfgang Denk + * Copyright (C) Procsys. All rights reserved. + * Mushtaq Khan + * + * Copyright (C) 2008 Freescale Semiconductor, Inc. + * Dave Liu + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +struct blk_desc sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE]; + +#ifdef CONFIG_PARTITIONS +struct blk_desc *sata_get_dev(int dev) +{ + return (dev < CONFIG_SYS_SATA_MAX_DEVICE) ? &sata_dev_desc[dev] : NULL; +} +#endif + +#ifdef CONFIG_BLK +static unsigned long sata_bread(struct udevice *dev, lbaint_t start, + lbaint_t blkcnt, void *dst) +{ + return -ENOSYS; +} + +static unsigned long sata_bwrite(struct udevice *dev, lbaint_t start, + lbaint_t blkcnt, const void *buffer) +{ + return -ENOSYS; +} +#else +static unsigned long sata_bread(struct blk_desc *block_dev, lbaint_t start, + lbaint_t blkcnt, void *dst) +{ + return sata_read(block_dev->devnum, start, blkcnt, dst); +} + +static unsigned long sata_bwrite(struct blk_desc *block_dev, lbaint_t start, + lbaint_t blkcnt, const void *buffer) +{ + return sata_write(block_dev->devnum, start, blkcnt, buffer); +} +#endif + +int __sata_initialize(void) +{ + int rc, ret = -1; + int i; + + for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++) { + memset(&sata_dev_desc[i], 0, sizeof(struct blk_desc)); + sata_dev_desc[i].if_type = IF_TYPE_SATA; + sata_dev_desc[i].devnum = i; + sata_dev_desc[i].part_type = PART_TYPE_UNKNOWN; + sata_dev_desc[i].type = DEV_TYPE_HARDDISK; + sata_dev_desc[i].lba = 0; + sata_dev_desc[i].blksz = 512; + sata_dev_desc[i].log2blksz = LOG2(sata_dev_desc[i].blksz); +#ifndef CONFIG_BLK + sata_dev_desc[i].block_read = sata_bread; + sata_dev_desc[i].block_write = sata_bwrite; +#endif + rc = init_sata(i); + if (!rc) { + rc = scan_sata(i); + if (!rc && sata_dev_desc[i].lba > 0 && + sata_dev_desc[i].blksz > 0) { + part_init(&sata_dev_desc[i]); + ret = i; + } + } + } + + return ret; +} +int sata_initialize(void) __attribute__((weak, alias("__sata_initialize"))); + +__weak int __sata_stop(void) +{ + int i, err = 0; + + for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++) + err |= reset_sata(i); + + if (err) + printf("Could not reset some SATA devices\n"); + + return err; +} +int sata_stop(void) __attribute__((weak, alias("__sata_stop"))); + +#ifdef CONFIG_BLK +static const struct blk_ops sata_blk_ops = { + .read = sata_bread, + .write = sata_bwrite, +}; + +U_BOOT_DRIVER(sata_blk) = { + .name = "sata_blk", + .id = UCLASS_BLK, + .ops = &sata_blk_ops, +}; +#else +U_BOOT_LEGACY_BLK(sata) = { + .if_typename = "sata", + .if_type = IF_TYPE_SATA, + .max_devs = CONFIG_SYS_SATA_MAX_DEVICE, + .desc = sata_dev_desc, +}; +#endif diff --git a/drivers/ata/sata_ceva.c b/drivers/ata/sata_ceva.c new file mode 100644 index 0000000000..0c24fce8dc --- /dev/null +++ b/drivers/ata/sata_ceva.c @@ -0,0 +1,149 @@ +/* + * (C) Copyright 2015 - 2016 Xilinx, Inc. + * Michal Simek + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include +#include +#include +#include +#include + +#include + +/* Vendor Specific Register Offsets */ +#define AHCI_VEND_PCFG 0xA4 +#define AHCI_VEND_PPCFG 0xA8 +#define AHCI_VEND_PP2C 0xAC +#define AHCI_VEND_PP3C 0xB0 +#define AHCI_VEND_PP4C 0xB4 +#define AHCI_VEND_PP5C 0xB8 +#define AHCI_VEND_PAXIC 0xC0 +#define AHCI_VEND_PTC 0xC8 + +/* Vendor Specific Register bit definitions */ +#define PAXIC_ADBW_BW64 0x1 +#define PAXIC_MAWIDD (1 << 8) +#define PAXIC_MARIDD (1 << 16) +#define PAXIC_OTL (0x4 << 20) + +#define PCFG_TPSS_VAL (0x32 << 16) +#define PCFG_TPRS_VAL (0x2 << 12) +#define PCFG_PAD_VAL 0x2 + +#define PPCFG_TTA 0x1FFFE +#define PPCFG_PSSO_EN (1 << 28) +#define PPCFG_PSS_EN (1 << 29) +#define PPCFG_ESDF_EN (1 << 31) + +#define PP2C_CIBGMN 0x0F +#define PP2C_CIBGMX (0x25 << 8) +#define PP2C_CIBGN (0x18 << 16) +#define PP2C_CINMP (0x29 << 24) + +#define PP3C_CWBGMN 0x04 +#define PP3C_CWBGMX (0x0B << 8) +#define PP3C_CWBGN (0x08 << 16) +#define PP3C_CWNMP (0x0F << 24) + +#define PP4C_BMX 0x0a +#define PP4C_BNM (0x08 << 8) +#define PP4C_SFD (0x4a << 16) +#define PP4C_PTST (0x06 << 24) + +#define PP5C_RIT 0x60216 +#define PP5C_RCT (0x7f0 << 20) + +#define PTC_RX_WM_VAL 0x40 +#define PTC_RSVD (1 << 27) + +#define PORT0_BASE 0x100 +#define PORT1_BASE 0x180 + +/* Port Control Register Bit Definitions */ +#define PORT_SCTL_SPD_GEN3 (0x3 << 4) +#define PORT_SCTL_SPD_GEN2 (0x2 << 4) +#define PORT_SCTL_SPD_GEN1 (0x1 << 4) +#define PORT_SCTL_IPM (0x3 << 8) + +#define PORT_BASE 0x100 +#define PORT_OFFSET 0x80 +#define NR_PORTS 2 +#define DRV_NAME "ahci-ceva" +#define CEVA_FLAG_BROKEN_GEN2 1 + +static int ceva_init_sata(ulong mmio) +{ + ulong tmp; + int i; + + /* + * AXI Data bus width to 64 + * Set Mem Addr Read, Write ID for data transfers + * Transfer limit to 72 DWord + */ + tmp = PAXIC_ADBW_BW64 | PAXIC_MAWIDD | PAXIC_MARIDD | PAXIC_OTL; + writel(tmp, mmio + AHCI_VEND_PAXIC); + + /* Set AHCI Enable */ + tmp = readl(mmio + HOST_CTL); + tmp |= HOST_AHCI_EN; + writel(tmp, mmio + HOST_CTL); + + for (i = 0; i < NR_PORTS; i++) { + /* TPSS TPRS scalars, CISE and Port Addr */ + tmp = PCFG_TPSS_VAL | PCFG_TPRS_VAL | (PCFG_PAD_VAL + i); + writel(tmp, mmio + AHCI_VEND_PCFG); + + /* Port Phy Cfg register enables */ + tmp = PPCFG_TTA | PPCFG_PSS_EN | PPCFG_ESDF_EN; + writel(tmp, mmio + AHCI_VEND_PPCFG); + + /* Rx Watermark setting */ + tmp = PTC_RX_WM_VAL | PTC_RSVD; + writel(tmp, mmio + AHCI_VEND_PTC); + + /* Default to Gen 2 Speed and Gen 1 if Gen2 is broken */ + tmp = PORT_SCTL_SPD_GEN3 | PORT_SCTL_IPM; + writel(tmp, mmio + PORT_SCR_CTL + PORT_BASE + PORT_OFFSET * i); + } + return 0; +} + +static int sata_ceva_probe(struct udevice *dev) +{ + struct scsi_platdata *plat = dev_get_platdata(dev); + + ceva_init_sata(plat->base); + return 0; +} + +static const struct udevice_id sata_ceva_ids[] = { + { .compatible = "ceva,ahci-1v84" }, + { } +}; + +static int sata_ceva_ofdata_to_platdata(struct udevice *dev) +{ + struct scsi_platdata *plat = dev_get_platdata(dev); + + plat->base = devfdt_get_addr(dev); + if (plat->base == FDT_ADDR_T_NONE) + return -EINVAL; + + /* Hardcode number for ceva sata controller */ + plat->max_lun = 1; /* Actually two but untested */ + plat->max_id = 2; + + return 0; +} + +U_BOOT_DRIVER(ceva_host_blk) = { + .name = "ceva_sata", + .id = UCLASS_SCSI, + .of_match = sata_ceva_ids, + .probe = sata_ceva_probe, + .ofdata_to_platdata = sata_ceva_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct scsi_platdata), +}; diff --git a/drivers/ata/sata_dwc.c b/drivers/ata/sata_dwc.c new file mode 100644 index 0000000000..a226ca2dec --- /dev/null +++ b/drivers/ata/sata_dwc.c @@ -0,0 +1,2076 @@ +/* + * sata_dwc.c + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + * Copyright 2006 Applied Micro Circuits Corporation + * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED + * + * SPDX-License-Identifier: GPL-2.0+ + */ +/* + * SATA support based on the chip canyonlands. + * + * 04-17-2009 + * The local version of this driver for the canyonlands board + * does not use interrupts but polls the chip instead. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sata_dwc.h" + +#define DMA_NUM_CHANS 1 +#define DMA_NUM_CHAN_REGS 8 + +#define AHB_DMA_BRST_DFLT 16 + +struct dmareg { + u32 low; + u32 high; +}; + +struct dma_chan_regs { + struct dmareg sar; + struct dmareg dar; + struct dmareg llp; + struct dmareg ctl; + struct dmareg sstat; + struct dmareg dstat; + struct dmareg sstatar; + struct dmareg dstatar; + struct dmareg cfg; + struct dmareg sgr; + struct dmareg dsr; +}; + +struct dma_interrupt_regs { + struct dmareg tfr; + struct dmareg block; + struct dmareg srctran; + struct dmareg dsttran; + struct dmareg error; +}; + +struct ahb_dma_regs { + struct dma_chan_regs chan_regs[DMA_NUM_CHAN_REGS]; + struct dma_interrupt_regs interrupt_raw; + struct dma_interrupt_regs interrupt_status; + struct dma_interrupt_regs interrupt_mask; + struct dma_interrupt_regs interrupt_clear; + struct dmareg statusInt; + struct dmareg rq_srcreg; + struct dmareg rq_dstreg; + struct dmareg rq_sgl_srcreg; + struct dmareg rq_sgl_dstreg; + struct dmareg rq_lst_srcreg; + struct dmareg rq_lst_dstreg; + struct dmareg dma_cfg; + struct dmareg dma_chan_en; + struct dmareg dma_id; + struct dmareg dma_test; + struct dmareg res1; + struct dmareg res2; + /* DMA Comp Params + * Param 6 = dma_param[0], Param 5 = dma_param[1], + * Param 4 = dma_param[2] ... + */ + struct dmareg dma_params[6]; +}; + +#define DMA_EN 0x00000001 +#define DMA_DI 0x00000000 +#define DMA_CHANNEL(ch) (0x00000001 << (ch)) +#define DMA_ENABLE_CHAN(ch) ((0x00000001 << (ch)) | \ + ((0x000000001 << (ch)) << 8)) +#define DMA_DISABLE_CHAN(ch) (0x00000000 | \ + ((0x000000001 << (ch)) << 8)) + +#define SATA_DWC_MAX_PORTS 1 +#define SATA_DWC_SCR_OFFSET 0x24 +#define SATA_DWC_REG_OFFSET 0x64 + +struct sata_dwc_regs { + u32 fptagr; + u32 fpbor; + u32 fptcr; + u32 dmacr; + u32 dbtsr; + u32 intpr; + u32 intmr; + u32 errmr; + u32 llcr; + u32 phycr; + u32 physr; + u32 rxbistpd; + u32 rxbistpd1; + u32 rxbistpd2; + u32 txbistpd; + u32 txbistpd1; + u32 txbistpd2; + u32 bistcr; + u32 bistfctr; + u32 bistsr; + u32 bistdecr; + u32 res[15]; + u32 testr; + u32 versionr; + u32 idr; + u32 unimpl[192]; + u32 dmadr[256]; +}; + +#define SATA_DWC_TXFIFO_DEPTH 0x01FF +#define SATA_DWC_RXFIFO_DEPTH 0x01FF + +#define SATA_DWC_DBTSR_MWR(size) ((size / 4) & SATA_DWC_TXFIFO_DEPTH) +#define SATA_DWC_DBTSR_MRD(size) (((size / 4) & \ + SATA_DWC_RXFIFO_DEPTH) << 16) +#define SATA_DWC_INTPR_DMAT 0x00000001 +#define SATA_DWC_INTPR_NEWFP 0x00000002 +#define SATA_DWC_INTPR_PMABRT 0x00000004 +#define SATA_DWC_INTPR_ERR 0x00000008 +#define SATA_DWC_INTPR_NEWBIST 0x00000010 +#define SATA_DWC_INTPR_IPF 0x10000000 +#define SATA_DWC_INTMR_DMATM 0x00000001 +#define SATA_DWC_INTMR_NEWFPM 0x00000002 +#define SATA_DWC_INTMR_PMABRTM 0x00000004 +#define SATA_DWC_INTMR_ERRM 0x00000008 +#define SATA_DWC_INTMR_NEWBISTM 0x00000010 + +#define SATA_DWC_DMACR_TMOD_TXCHEN 0x00000004 +#define SATA_DWC_DMACR_TXRXCH_CLEAR SATA_DWC_DMACR_TMOD_TXCHEN + +#define SATA_DWC_QCMD_MAX 32 + +#define SATA_DWC_SERROR_ERR_BITS 0x0FFF0F03 + +#define HSDEVP_FROM_AP(ap) (struct sata_dwc_device_port*) \ + (ap)->private_data + +struct sata_dwc_device { + struct device *dev; + struct ata_probe_ent *pe; + struct ata_host *host; + u8 *reg_base; + struct sata_dwc_regs *sata_dwc_regs; + int irq_dma; +}; + +struct sata_dwc_device_port { + struct sata_dwc_device *hsdev; + int cmd_issued[SATA_DWC_QCMD_MAX]; + u32 dma_chan[SATA_DWC_QCMD_MAX]; + int dma_pending[SATA_DWC_QCMD_MAX]; +}; + +enum { + SATA_DWC_CMD_ISSUED_NOT = 0, + SATA_DWC_CMD_ISSUED_PEND = 1, + SATA_DWC_CMD_ISSUED_EXEC = 2, + SATA_DWC_CMD_ISSUED_NODATA = 3, + + SATA_DWC_DMA_PENDING_NONE = 0, + SATA_DWC_DMA_PENDING_TX = 1, + SATA_DWC_DMA_PENDING_RX = 2, +}; + +#define msleep(a) udelay(a * 1000) +#define ssleep(a) msleep(a * 1000) + +static int ata_probe_timeout = (ATA_TMOUT_INTERNAL / 100); + +enum sata_dev_state { + SATA_INIT = 0, + SATA_READY = 1, + SATA_NODEVICE = 2, + SATA_ERROR = 3, +}; +enum sata_dev_state dev_state = SATA_INIT; + +static struct ahb_dma_regs *sata_dma_regs = 0; +static struct ata_host *phost; +static struct ata_port ap; +static struct ata_port *pap = ≈ +static struct ata_device ata_device; +static struct sata_dwc_device_port dwc_devp; + +static void *scr_addr_sstatus; +static u32 temp_n_block = 0; + +static unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, unsigned int buflen, + unsigned long timeout); +static unsigned int ata_dev_set_feature(struct ata_device *dev, + u8 enable,u8 feature); +static unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors); +static u8 ata_irq_on(struct ata_port *ap); +static struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, + unsigned int tag); +static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq); +static void ata_tf_to_host(struct ata_port *ap, + const struct ata_taskfile *tf); +static void ata_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf); +static unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc); +static u8 ata_check_altstatus(struct ata_port *ap); +static u8 ata_check_status(struct ata_port *ap); +static void ata_dev_select(struct ata_port *ap, unsigned int device, + unsigned int wait, unsigned int can_sleep); +static void ata_qc_issue(struct ata_queued_cmd *qc); +static void ata_tf_load(struct ata_port *ap, + const struct ata_taskfile *tf); +static int ata_dev_read_sectors(unsigned char* pdata, + unsigned long datalen, u32 block, u32 n_block); +static int ata_dev_write_sectors(unsigned char* pdata, + unsigned long datalen , u32 block, u32 n_block); +static void ata_std_dev_select(struct ata_port *ap, unsigned int device); +static void ata_qc_complete(struct ata_queued_cmd *qc); +static void __ata_qc_complete(struct ata_queued_cmd *qc); +static void fill_result_tf(struct ata_queued_cmd *qc); +static void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); +static void ata_mmio_data_xfer(struct ata_device *dev, + unsigned char *buf, + unsigned int buflen,int do_write); +static void ata_pio_task(struct ata_port *arg_ap); +static void __ata_port_freeze(struct ata_port *ap); +static int ata_port_freeze(struct ata_port *ap); +static void ata_qc_free(struct ata_queued_cmd *qc); +static void ata_pio_sectors(struct ata_queued_cmd *qc); +static void ata_pio_sector(struct ata_queued_cmd *qc); +static void ata_pio_queue_task(struct ata_port *ap, + void *data,unsigned long delay); +static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq); +static int sata_dwc_softreset(struct ata_port *ap); +static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, + unsigned int flags, u16 *id); +static int check_sata_dev_state(void); + +static const struct ata_port_info sata_dwc_port_info[] = { + { + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING | + ATA_FLAG_SRST | ATA_FLAG_NCQ, + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + }, +}; + +int init_sata(int dev) +{ + struct sata_dwc_device hsdev; + struct ata_host host; + struct ata_port_info pi = sata_dwc_port_info[0]; + struct ata_link *link; + struct sata_dwc_device_port hsdevp = dwc_devp; + u8 *base = 0; + u8 *sata_dma_regs_addr = 0; + u8 status; + unsigned long base_addr = 0; + int chan = 0; + int rc; + int i; + + phost = &host; + + base = (u8*)SATA_BASE_ADDR; + + hsdev.sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET); + + host.n_ports = SATA_DWC_MAX_PORTS; + + for (i = 0; i < SATA_DWC_MAX_PORTS; i++) { + ap.pflags |= ATA_PFLAG_INITIALIZING; + ap.flags = ATA_FLAG_DISABLED; + ap.print_id = -1; + ap.ctl = ATA_DEVCTL_OBS; + ap.host = &host; + ap.last_ctl = 0xFF; + + link = &ap.link; + link->ap = ≈ + link->pmp = 0; + link->active_tag = ATA_TAG_POISON; + link->hw_sata_spd_limit = 0; + + ap.port_no = i; + host.ports[i] = ≈ + } + + ap.pio_mask = pi.pio_mask; + ap.mwdma_mask = pi.mwdma_mask; + ap.udma_mask = pi.udma_mask; + ap.flags |= pi.flags; + ap.link.flags |= pi.link_flags; + + host.ports[0]->ioaddr.cmd_addr = base; + host.ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET; + scr_addr_sstatus = base + SATA_DWC_SCR_OFFSET; + + base_addr = (unsigned long)base; + + host.ports[0]->ioaddr.cmd_addr = (void *)base_addr + 0x00; + host.ports[0]->ioaddr.data_addr = (void *)base_addr + 0x00; + + host.ports[0]->ioaddr.error_addr = (void *)base_addr + 0x04; + host.ports[0]->ioaddr.feature_addr = (void *)base_addr + 0x04; + + host.ports[0]->ioaddr.nsect_addr = (void *)base_addr + 0x08; + + host.ports[0]->ioaddr.lbal_addr = (void *)base_addr + 0x0c; + host.ports[0]->ioaddr.lbam_addr = (void *)base_addr + 0x10; + host.ports[0]->ioaddr.lbah_addr = (void *)base_addr + 0x14; + + host.ports[0]->ioaddr.device_addr = (void *)base_addr + 0x18; + host.ports[0]->ioaddr.command_addr = (void *)base_addr + 0x1c; + host.ports[0]->ioaddr.status_addr = (void *)base_addr + 0x1c; + + host.ports[0]->ioaddr.altstatus_addr = (void *)base_addr + 0x20; + host.ports[0]->ioaddr.ctl_addr = (void *)base_addr + 0x20; + + sata_dma_regs_addr = (u8*)SATA_DMA_REG_ADDR; + sata_dma_regs = (void *__iomem)sata_dma_regs_addr; + + status = ata_check_altstatus(&ap); + + if (status == 0x7f) { + printf("Hard Disk not found.\n"); + dev_state = SATA_NODEVICE; + rc = false; + return rc; + } + + printf("Waiting for device..."); + i = 0; + while (1) { + udelay(10000); + + status = ata_check_altstatus(&ap); + + if ((status & ATA_BUSY) == 0) { + printf("\n"); + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + + dev_state = SATA_NODEVICE; + rc = false; + return rc; + } + if ((i >= 100) && ((i % 100) == 0)) + printf("."); + } + + rc = sata_dwc_softreset(&ap); + + if (rc) { + printf("sata_dwc : error. soft reset failed\n"); + return rc; + } + + for (chan = 0; chan < DMA_NUM_CHANS; chan++) { + out_le32(&(sata_dma_regs->interrupt_mask.error.low), + DMA_DISABLE_CHAN(chan)); + + out_le32(&(sata_dma_regs->interrupt_mask.tfr.low), + DMA_DISABLE_CHAN(chan)); + } + + out_le32(&(sata_dma_regs->dma_cfg.low), DMA_DI); + + out_le32(&hsdev.sata_dwc_regs->intmr, + SATA_DWC_INTMR_ERRM | + SATA_DWC_INTMR_PMABRTM); + + /* Unmask the error bits that should trigger + * an error interrupt by setting the error mask register. + */ + out_le32(&hsdev.sata_dwc_regs->errmr, SATA_DWC_SERROR_ERR_BITS); + + hsdev.host = ap.host; + memset(&hsdevp, 0, sizeof(hsdevp)); + hsdevp.hsdev = &hsdev; + + for (i = 0; i < SATA_DWC_QCMD_MAX; i++) + hsdevp.cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT; + + out_le32((void __iomem *)scr_addr_sstatus + 4, + in_le32((void __iomem *)scr_addr_sstatus + 4)); + + rc = 0; + return rc; +} + +int reset_sata(int dev) +{ + return 0; +} + +static u8 ata_check_altstatus(struct ata_port *ap) +{ + u8 val = 0; + val = readb(ap->ioaddr.altstatus_addr); + return val; +} + +static int sata_dwc_softreset(struct ata_port *ap) +{ + u8 nsect,lbal = 0; + u8 tmp = 0; + struct ata_ioports *ioaddr = &ap->ioaddr; + + in_le32((void *)ap->ioaddr.scr_addr + (SCR_ERROR * 4)); + + writeb(0x55, ioaddr->nsect_addr); + writeb(0xaa, ioaddr->lbal_addr); + writeb(0xaa, ioaddr->nsect_addr); + writeb(0x55, ioaddr->lbal_addr); + writeb(0x55, ioaddr->nsect_addr); + writeb(0xaa, ioaddr->lbal_addr); + + nsect = readb(ioaddr->nsect_addr); + lbal = readb(ioaddr->lbal_addr); + + if ((nsect == 0x55) && (lbal == 0xaa)) { + printf("Device found\n"); + } else { + printf("No device found\n"); + dev_state = SATA_NODEVICE; + return false; + } + + tmp = ATA_DEVICE_OBS; + writeb(tmp, ioaddr->device_addr); + writeb(ap->ctl, ioaddr->ctl_addr); + + udelay(200); + + writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr); + + udelay(200); + writeb(ap->ctl, ioaddr->ctl_addr); + + msleep(150); + ata_check_status(ap); + + msleep(50); + ata_check_status(ap); + + while (1) { + u8 status = ata_check_status(ap); + + if (!(status & ATA_BUSY)) + break; + + printf("Hard Disk status is BUSY.\n"); + msleep(50); + } + + tmp = ATA_DEVICE_OBS; + writeb(tmp, ioaddr->device_addr); + + nsect = readb(ioaddr->nsect_addr); + lbal = readb(ioaddr->lbal_addr); + + return 0; +} + +static u8 ata_check_status(struct ata_port *ap) +{ + u8 val = 0; + val = readb(ap->ioaddr.status_addr); + return val; +} + +static int ata_id_has_hipm(const u16 *id) +{ + u16 val = id[76]; + + if (val == 0 || val == 0xffff) + return -1; + + return val & (1 << 9); +} + +static int ata_id_has_dipm(const u16 *id) +{ + u16 val = id[78]; + + if (val == 0 || val == 0xffff) + return -1; + + return val & (1 << 3); +} + +int scan_sata(int dev) +{ + int i; + int rc; + u8 status; + const u16 *id; + struct ata_device *ata_dev = &ata_device; + unsigned long pio_mask, mwdma_mask; + char revbuf[7]; + u16 iobuf[ATA_SECTOR_WORDS]; + + memset(iobuf, 0, sizeof(iobuf)); + + if (dev_state == SATA_NODEVICE) + return 1; + + printf("Waiting for device..."); + i = 0; + while (1) { + udelay(10000); + + status = ata_check_altstatus(&ap); + + if ((status & ATA_BUSY) == 0) { + printf("\n"); + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + + dev_state = SATA_NODEVICE; + return 1; + } + if ((i >= 100) && ((i % 100) == 0)) + printf("."); + } + + udelay(1000); + + rc = ata_dev_read_id(ata_dev, &ata_dev->class, + ATA_READID_POSTRESET,ata_dev->id); + if (rc) { + printf("sata_dwc : error. failed sata scan\n"); + return 1; + } + + /* SATA drives indicate we have a bridge. We don't know which + * end of the link the bridge is which is a problem + */ + if (ata_id_is_sata(ata_dev->id)) + ap.cbl = ATA_CBL_SATA; + + id = ata_dev->id; + + ata_dev->flags &= ~ATA_DFLAG_CFG_MASK; + ata_dev->max_sectors = 0; + ata_dev->cdb_len = 0; + ata_dev->n_sectors = 0; + ata_dev->cylinders = 0; + ata_dev->heads = 0; + ata_dev->sectors = 0; + + if (id[ATA_ID_FIELD_VALID] & (1 << 1)) { + pio_mask = id[ATA_ID_PIO_MODES] & 0x03; + pio_mask <<= 3; + pio_mask |= 0x7; + } else { + /* If word 64 isn't valid then Word 51 high byte holds + * the PIO timing number for the maximum. Turn it into + * a mask. + */ + u8 mode = (id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF; + if (mode < 5) { + pio_mask = (2 << mode) - 1; + } else { + pio_mask = 1; + } + } + + mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07; + + if (ata_id_is_cfa(id)) { + int pio = id[163] & 0x7; + int dma = (id[163] >> 3) & 7; + + if (pio) + pio_mask |= (1 << 5); + if (pio > 1) + pio_mask |= (1 << 6); + if (dma) + mwdma_mask |= (1 << 3); + if (dma > 1) + mwdma_mask |= (1 << 4); + } + + if (ata_dev->class == ATA_DEV_ATA) { + if (ata_id_is_cfa(id)) { + if (id[162] & 1) + printf("supports DRM functions and may " + "not be fully accessable.\n"); + strcpy(revbuf, "CFA"); + } else { + if (ata_id_has_tpm(id)) + printf("supports DRM functions and may " + "not be fully accessable.\n"); + } + + ata_dev->n_sectors = ata_id_n_sectors((u16*)id); + + if (ata_dev->id[59] & 0x100) + ata_dev->multi_count = ata_dev->id[59] & 0xff; + + if (ata_id_has_lba(id)) { + char ncq_desc[20]; + + ata_dev->flags |= ATA_DFLAG_LBA; + if (ata_id_has_lba48(id)) { + ata_dev->flags |= ATA_DFLAG_LBA48; + + if (ata_dev->n_sectors >= (1UL << 28) && + ata_id_has_flush_ext(id)) + ata_dev->flags |= ATA_DFLAG_FLUSH_EXT; + } + if (!ata_id_has_ncq(ata_dev->id)) + ncq_desc[0] = '\0'; + + if (ata_dev->horkage & ATA_HORKAGE_NONCQ) + strcpy(ncq_desc, "NCQ (not used)"); + + if (ap.flags & ATA_FLAG_NCQ) + ata_dev->flags |= ATA_DFLAG_NCQ; + } + ata_dev->cdb_len = 16; + } + ata_dev->max_sectors = ATA_MAX_SECTORS; + if (ata_dev->flags & ATA_DFLAG_LBA48) + ata_dev->max_sectors = ATA_MAX_SECTORS_LBA48; + + if (!(ata_dev->horkage & ATA_HORKAGE_IPM)) { + if (ata_id_has_hipm(ata_dev->id)) + ata_dev->flags |= ATA_DFLAG_HIPM; + if (ata_id_has_dipm(ata_dev->id)) + ata_dev->flags |= ATA_DFLAG_DIPM; + } + + if ((ap.cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ata_dev->id))) { + ata_dev->udma_mask &= ATA_UDMA5; + ata_dev->max_sectors = ATA_MAX_SECTORS; + } + + if (ata_dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { + printf("Drive reports diagnostics failure." + "This may indicate a drive\n"); + printf("fault or invalid emulation." + "Contact drive vendor for information.\n"); + } + + rc = check_sata_dev_state(); + + ata_id_c_string(ata_dev->id, + (unsigned char *)sata_dev_desc[dev].revision, + ATA_ID_FW_REV, sizeof(sata_dev_desc[dev].revision)); + ata_id_c_string(ata_dev->id, + (unsigned char *)sata_dev_desc[dev].vendor, + ATA_ID_PROD, sizeof(sata_dev_desc[dev].vendor)); + ata_id_c_string(ata_dev->id, + (unsigned char *)sata_dev_desc[dev].product, + ATA_ID_SERNO, sizeof(sata_dev_desc[dev].product)); + + sata_dev_desc[dev].lba = (u32) ata_dev->n_sectors; + +#ifdef CONFIG_LBA48 + if (ata_dev->id[83] & (1 << 10)) { + sata_dev_desc[dev].lba48 = 1; + } else { + sata_dev_desc[dev].lba48 = 0; + } +#endif + + return 0; +} + +static u8 ata_busy_wait(struct ata_port *ap, + unsigned int bits,unsigned int max) +{ + u8 status; + + do { + udelay(10); + status = ata_check_status(ap); + max--; + } while (status != 0xff && (status & bits) && (max > 0)); + + return status; +} + +static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, + unsigned int flags, u16 *id) +{ + struct ata_port *ap = pap; + unsigned int class = *p_class; + struct ata_taskfile tf; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1, tried_spinup = 0; + u8 status; + int rc; + + status = ata_busy_wait(ap, ATA_BUSY, 30000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + rc = false; + return rc; + } + + ata_dev_select(ap, dev->devno, 1, 1); + +retry: + memset(&tf, 0, sizeof(tf)); + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + tf.ctl = ap->ctl; + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_ID_ATA; + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + + /* Device presence detection is unreliable on some + * controllers. Always poll IDENTIFY if available. + */ + tf.flags |= ATA_TFLAG_POLLING; + + temp_n_block = 1; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, + sizeof(id[0]) * ATA_ID_WORDS, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + + unsigned int id_cnt; + + for (id_cnt = 0; id_cnt < ATA_ID_WORDS; id_cnt++) + id[id_cnt] = le16_to_cpu(id[id_cnt]); + + + rc = -EINVAL; + reason = "device reports invalid type"; + + if (class == ATA_DEV_ATA) { + if (!ata_id_is_ata(id) && !ata_id_is_cfa(id)) + goto err_out; + } else { + if (ata_id_is_ata(id)) + goto err_out; + } + if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) { + tried_spinup = 1; + /* + * Drive powered-up in standby mode, and requires a specific + * SET_FEATURES spin-up subcommand before it will accept + * anything other than the original IDENTIFY command. + */ + err_mask = ata_dev_set_feature(dev, SETFEATURES_SPINUP, 0); + if (err_mask && id[2] != 0x738c) { + rc = -EIO; + reason = "SPINUP failed"; + goto err_out; + } + /* + * If the drive initially returned incomplete IDENTIFY info, + * we now must reissue the IDENTIFY command. + */ + if (id[2] == 0x37c8) + goto retry; + } + + if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) { + /* + * The exact sequence expected by certain pre-ATA4 drives is: + * SRST RESET + * IDENTIFY (optional in early ATA) + * INITIALIZE DEVICE PARAMETERS (later IDE and ATA) + * anything else.. + * Some drives were very specific about that exact sequence. + * + * Note that ATA4 says lba is mandatory so the second check + * shoud never trigger. + */ + if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { + err_mask = ata_dev_init_params(dev, id[3], id[6]); + if (err_mask) { + rc = -EIO; + reason = "INIT_DEV_PARAMS failed"; + goto err_out; + } + + /* current CHS translation info (id[53-58]) might be + * changed. reread the identify device info. + */ + flags &= ~ATA_READID_POSTRESET; + goto retry; + } + } + + *p_class = class; + return 0; + +err_out: + printf("failed to READ ID (%s, err_mask=0x%x)\n", reason, err_mask); + return rc; +} + +static u8 ata_wait_idle(struct ata_port *ap) +{ + u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); + return status; +} + +static void ata_dev_select(struct ata_port *ap, unsigned int device, + unsigned int wait, unsigned int can_sleep) +{ + if (wait) + ata_wait_idle(ap); + + ata_std_dev_select(ap, device); + + if (wait) + ata_wait_idle(ap); +} + +static void ata_std_dev_select(struct ata_port *ap, unsigned int device) +{ + u8 tmp; + + if (device == 0) { + tmp = ATA_DEVICE_OBS; + } else { + tmp = ATA_DEVICE_OBS | ATA_DEV1; + } + + writeb(tmp, ap->ioaddr.device_addr); + + readb(ap->ioaddr.altstatus_addr); + + udelay(1); +} + +static int waiting_for_reg_state(volatile u8 *offset, + int timeout_msec, + u32 sign) +{ + int i; + u32 status; + + for (i = 0; i < timeout_msec; i++) { + status = readl(offset); + if ((status & sign) != 0) + break; + msleep(1); + } + + return (i < timeout_msec) ? 0 : -1; +} + +static void ata_qc_reinit(struct ata_queued_cmd *qc) +{ + qc->dma_dir = DMA_NONE; + qc->flags = 0; + qc->nbytes = qc->extrabytes = qc->curbytes = 0; + qc->n_elem = 0; + qc->err_mask = 0; + qc->sect_size = ATA_SECT_SIZE; + qc->nbytes = ATA_SECT_SIZE * temp_n_block; + + memset(&qc->tf, 0, sizeof(qc->tf)); + qc->tf.ctl = 0; + qc->tf.device = ATA_DEVICE_OBS; + + qc->result_tf.command = ATA_DRDY; + qc->result_tf.feature = 0; +} + +struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, + unsigned int tag) +{ + if (tag < ATA_MAX_QUEUE) + return &ap->qcmd[tag]; + return NULL; +} + +static void __ata_port_freeze(struct ata_port *ap) +{ + printf("set port freeze.\n"); + ap->pflags |= ATA_PFLAG_FROZEN; +} + +static int ata_port_freeze(struct ata_port *ap) +{ + __ata_port_freeze(ap); + return 0; +} + +unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, unsigned int buflen, + unsigned long timeout) +{ + struct ata_link *link = dev->link; + struct ata_port *ap = pap; + struct ata_queued_cmd *qc; + unsigned int tag, preempted_tag; + u32 preempted_sactive, preempted_qc_active; + int preempted_nr_active_links; + unsigned int err_mask; + int rc = 0; + u8 status; + + status = ata_busy_wait(ap, ATA_BUSY, 300000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + rc = false; + return rc; + } + + if (ap->pflags & ATA_PFLAG_FROZEN) + return AC_ERR_SYSTEM; + + tag = ATA_TAG_INTERNAL; + + if (test_and_set_bit(tag, &ap->qc_allocated)) { + rc = false; + return rc; + } + + qc = __ata_qc_from_tag(ap, tag); + qc->tag = tag; + qc->ap = ap; + qc->dev = dev; + + ata_qc_reinit(qc); + + preempted_tag = link->active_tag; + preempted_sactive = link->sactive; + preempted_qc_active = ap->qc_active; + preempted_nr_active_links = ap->nr_active_links; + link->active_tag = ATA_TAG_POISON; + link->sactive = 0; + ap->qc_active = 0; + ap->nr_active_links = 0; + + qc->tf = *tf; + if (cdb) + memcpy(qc->cdb, cdb, ATAPI_CDB_LEN); + qc->flags |= ATA_QCFLAG_RESULT_TF; + qc->dma_dir = dma_dir; + qc->private_data = 0; + + ata_qc_issue(qc); + + if (!timeout) + timeout = ata_probe_timeout * 1000 / HZ; + + status = ata_busy_wait(ap, ATA_BUSY, 30000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + printf("altstatus = 0x%x.\n", status); + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + if (waiting_for_reg_state(ap->ioaddr.altstatus_addr, 1000, 0x8)) { + u8 status = 0; + u8 errorStatus = 0; + + status = readb(ap->ioaddr.altstatus_addr); + if ((status & 0x01) != 0) { + errorStatus = readb(ap->ioaddr.feature_addr); + if (errorStatus == 0x04 && + qc->tf.command == ATA_CMD_PIO_READ_EXT){ + printf("Hard Disk doesn't support LBA48\n"); + dev_state = SATA_ERROR; + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + } + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + status = ata_busy_wait(ap, ATA_BUSY, 10); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + ata_pio_task(ap); + + if (!rc) { + if (qc->flags & ATA_QCFLAG_ACTIVE) { + qc->err_mask |= AC_ERR_TIMEOUT; + ata_port_freeze(ap); + } + } + + if (qc->flags & ATA_QCFLAG_FAILED) { + if (qc->result_tf.command & (ATA_ERR | ATA_DF)) + qc->err_mask |= AC_ERR_DEV; + + if (!qc->err_mask) + qc->err_mask |= AC_ERR_OTHER; + + if (qc->err_mask & ~AC_ERR_OTHER) + qc->err_mask &= ~AC_ERR_OTHER; + } + + *tf = qc->result_tf; + err_mask = qc->err_mask; + ata_qc_free(qc); + link->active_tag = preempted_tag; + link->sactive = preempted_sactive; + ap->qc_active = preempted_qc_active; + ap->nr_active_links = preempted_nr_active_links; + + if (ap->flags & ATA_FLAG_DISABLED) { + err_mask |= AC_ERR_SYSTEM; + ap->flags &= ~ATA_FLAG_DISABLED; + } + + return err_mask; +} + +static void ata_qc_issue(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; + u8 prot = qc->tf.protocol; + + if (ata_is_ncq(prot)) { + if (!link->sactive) + ap->nr_active_links++; + link->sactive |= 1 << qc->tag; + } else { + ap->nr_active_links++; + link->active_tag = qc->tag; + } + + qc->flags |= ATA_QCFLAG_ACTIVE; + ap->qc_active |= 1 << qc->tag; + + if (qc->dev->flags & ATA_DFLAG_SLEEPING) { + msleep(1); + return; + } + + qc->err_mask |= ata_qc_issue_prot(qc); + if (qc->err_mask) + goto err; + + return; +err: + ata_qc_complete(qc); +} + +static unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + if (ap->flags & ATA_FLAG_PIO_POLLING) { + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + case ATA_PROT_NODATA: + case ATAPI_PROT_PIO: + case ATAPI_PROT_NODATA: + qc->tf.flags |= ATA_TFLAG_POLLING; + break; + default: + break; + } + } + + ata_dev_select(ap, qc->dev->devno, 1, 0); + + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + if (qc->tf.flags & ATA_TFLAG_POLLING) + qc->tf.ctl |= ATA_NIEN; + + ata_tf_to_host(ap, &qc->tf); + + ap->hsm_task_state = HSM_ST; + + if (qc->tf.flags & ATA_TFLAG_POLLING) + ata_pio_queue_task(ap, qc, 0); + + break; + + default: + return AC_ERR_SYSTEM; + } + + return 0; +} + +static void ata_tf_to_host(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + ata_tf_load(ap, tf); + ata_exec_command(ap, tf); +} + +static void ata_tf_load(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + + if (tf->ctl != ap->last_ctl) { + if (ioaddr->ctl_addr) + writeb(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + ata_wait_idle(ap); + } + + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + writeb(tf->hob_feature, ioaddr->feature_addr); + writeb(tf->hob_nsect, ioaddr->nsect_addr); + writeb(tf->hob_lbal, ioaddr->lbal_addr); + writeb(tf->hob_lbam, ioaddr->lbam_addr); + writeb(tf->hob_lbah, ioaddr->lbah_addr); + } + + if (is_addr) { + writeb(tf->feature, ioaddr->feature_addr); + writeb(tf->nsect, ioaddr->nsect_addr); + writeb(tf->lbal, ioaddr->lbal_addr); + writeb(tf->lbam, ioaddr->lbam_addr); + writeb(tf->lbah, ioaddr->lbah_addr); + } + + if (tf->flags & ATA_TFLAG_DEVICE) + writeb(tf->device, ioaddr->device_addr); + + ata_wait_idle(ap); +} + +static void ata_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + writeb(tf->command, ap->ioaddr.command_addr); + + readb(ap->ioaddr.altstatus_addr); + + udelay(1); +} + +static void ata_pio_queue_task(struct ata_port *ap, + void *data,unsigned long delay) +{ + ap->port_task_data = data; +} + +static unsigned int ac_err_mask(u8 status) +{ + if (status & (ATA_BUSY | ATA_DRQ)) + return AC_ERR_HSM; + if (status & (ATA_ERR | ATA_DF)) + return AC_ERR_DEV; + return 0; +} + +static unsigned int __ac_err_mask(u8 status) +{ + unsigned int mask = ac_err_mask(status); + if (mask == 0) + return AC_ERR_OTHER; + return mask; +} + +static void ata_pio_task(struct ata_port *arg_ap) +{ + struct ata_port *ap = arg_ap; + struct ata_queued_cmd *qc = ap->port_task_data; + u8 status; + int poll_next; + +fsm_start: + /* + * This is purely heuristic. This is a fast path. + * Sometimes when we enter, BSY will be cleared in + * a chk-status or two. If not, the drive is probably seeking + * or something. Snooze for a couple msecs, then + * chk-status again. If still busy, queue delayed work. + */ + status = ata_busy_wait(ap, ATA_BUSY, 5); + if (status & ATA_BUSY) { + msleep(2); + status = ata_busy_wait(ap, ATA_BUSY, 10); + if (status & ATA_BUSY) { + ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE); + return; + } + } + + poll_next = ata_hsm_move(ap, qc, status, 1); + + /* another command or interrupt handler + * may be running at this point. + */ + if (poll_next) + goto fsm_start; +} + +static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq) +{ + int poll_next; + +fsm_start: + switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + poll_next = (qc->tf.flags & ATA_TFLAG_POLLING); + + if ((status & ATA_DRQ) == 0) { + if (status & (ATA_ERR | ATA_DF)) { + qc->err_mask |= AC_ERR_DEV; + } else { + qc->err_mask |= AC_ERR_HSM; + } + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + /* Device should not ask for data transfer (DRQ=1) + * when it finds something wrong. + * We ignore DRQ here and stop the HSM by + * changing hsm_task_state to HSM_ST_ERR and + * let the EH abort the command or reset the device. + */ + if (status & (ATA_ERR | ATA_DF)) { + if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) { + printf("DRQ=1 with device error, " + "dev_stat 0x%X\n", status); + qc->err_mask |= AC_ERR_HSM; + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + } + + if (qc->tf.protocol == ATA_PROT_PIO) { + /* PIO data out protocol. + * send first data block. + */ + /* ata_pio_sectors() might change the state + * to HSM_ST_LAST. so, the state is changed here + * before ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST; + ata_pio_sectors(qc); + } else { + printf("protocol is not ATA_PROT_PIO \n"); + } + break; + + case HSM_ST: + if ((status & ATA_DRQ) == 0) { + if (status & (ATA_ERR | ATA_DF)) { + qc->err_mask |= AC_ERR_DEV; + } else { + /* HSM violation. Let EH handle this. + * Phantom devices also trigger this + * condition. Mark hint. + */ + qc->err_mask |= AC_ERR_HSM | AC_ERR_NODEV_HINT; + } + + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + /* For PIO reads, some devices may ask for + * data transfer (DRQ=1) alone with ERR=1. + * We respect DRQ here and transfer one + * block of junk data before changing the + * hsm_task_state to HSM_ST_ERR. + * + * For PIO writes, ERR=1 DRQ=1 doesn't make + * sense since the data block has been + * transferred to the device. + */ + if (status & (ATA_ERR | ATA_DF)) { + qc->err_mask |= AC_ERR_DEV; + + if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { + ata_pio_sectors(qc); + status = ata_wait_idle(ap); + } + + if (status & (ATA_BUSY | ATA_DRQ)) + qc->err_mask |= AC_ERR_HSM; + + /* ata_pio_sectors() might change the + * state to HSM_ST_LAST. so, the state + * is changed after ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + ata_pio_sectors(qc); + if (ap->hsm_task_state == HSM_ST_LAST && + (!(qc->tf.flags & ATA_TFLAG_WRITE))) { + status = ata_wait_idle(ap); + goto fsm_start; + } + + poll_next = 1; + break; + + case HSM_ST_LAST: + if (!ata_ok(status)) { + qc->err_mask |= __ac_err_mask(status); + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + ap->hsm_task_state = HSM_ST_IDLE; + + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + + case HSM_ST_ERR: + /* make sure qc->err_mask is available to + * know what's wrong and recover + */ + ap->hsm_task_state = HSM_ST_IDLE; + + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + default: + poll_next = 0; + } + + return poll_next; +} + +static void ata_pio_sectors(struct ata_queued_cmd *qc) +{ + struct ata_port *ap; + ap = pap; + qc->pdata = ap->pdata; + + ata_pio_sector(qc); + + readb(qc->ap->ioaddr.altstatus_addr); + udelay(1); +} + +static void ata_pio_sector(struct ata_queued_cmd *qc) +{ + int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); + struct ata_port *ap = qc->ap; + unsigned int offset; + unsigned char *buf; + char temp_data_buf[512]; + + if (qc->curbytes == qc->nbytes - qc->sect_size) + ap->hsm_task_state = HSM_ST_LAST; + + offset = qc->curbytes; + + switch (qc->tf.command) { + case ATA_CMD_ID_ATA: + buf = (unsigned char *)&ata_device.id[0]; + break; + case ATA_CMD_PIO_READ_EXT: + case ATA_CMD_PIO_READ: + case ATA_CMD_PIO_WRITE_EXT: + case ATA_CMD_PIO_WRITE: + buf = qc->pdata + offset; + break; + default: + buf = (unsigned char *)&temp_data_buf[0]; + } + + ata_mmio_data_xfer(qc->dev, buf, qc->sect_size, do_write); + + qc->curbytes += qc->sect_size; + +} + +static void ata_mmio_data_xfer(struct ata_device *dev, unsigned char *buf, + unsigned int buflen, int do_write) +{ + struct ata_port *ap = pap; + void __iomem *data_addr = ap->ioaddr.data_addr; + unsigned int words = buflen >> 1; + u16 *buf16 = (u16 *)buf; + unsigned int i = 0; + + udelay(100); + if (do_write) { + for (i = 0; i < words; i++) + writew(le16_to_cpu(buf16[i]), data_addr); + } else { + for (i = 0; i < words; i++) + buf16[i] = cpu_to_le16(readw(data_addr)); + } + + if (buflen & 0x01) { + __le16 align_buf[1] = { 0 }; + unsigned char *trailing_buf = buf + buflen - 1; + + if (do_write) { + memcpy(align_buf, trailing_buf, 1); + writew(le16_to_cpu(align_buf[0]), data_addr); + } else { + align_buf[0] = cpu_to_le16(readw(data_addr)); + memcpy(trailing_buf, align_buf, 1); + } + } +} + +static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) +{ + struct ata_port *ap = qc->ap; + + if (in_wq) { + /* EH might have kicked in while host lock is + * released. + */ + qc = &ap->qcmd[qc->tag]; + if (qc) { + if (!(qc->err_mask & AC_ERR_HSM)) { + ata_irq_on(ap); + ata_qc_complete(qc); + } else { + ata_port_freeze(ap); + } + } + } else { + if (!(qc->err_mask & AC_ERR_HSM)) { + ata_qc_complete(qc); + } else { + ata_port_freeze(ap); + } + } +} + +static u8 ata_irq_on(struct ata_port *ap) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + u8 tmp; + + ap->ctl &= ~ATA_NIEN; + ap->last_ctl = ap->ctl; + + if (ioaddr->ctl_addr) + writeb(ap->ctl, ioaddr->ctl_addr); + + tmp = ata_wait_idle(ap); + + return tmp; +} + +static unsigned int ata_tag_internal(unsigned int tag) +{ + return tag == ATA_MAX_QUEUE - 1; +} + +static void ata_qc_complete(struct ata_queued_cmd *qc) +{ + struct ata_device *dev = qc->dev; + if (qc->err_mask) + qc->flags |= ATA_QCFLAG_FAILED; + + if (qc->flags & ATA_QCFLAG_FAILED) { + if (!ata_tag_internal(qc->tag)) { + fill_result_tf(qc); + return; + } + } + if (qc->flags & ATA_QCFLAG_RESULT_TF) + fill_result_tf(qc); + + /* Some commands need post-processing after successful + * completion. + */ + switch (qc->tf.command) { + case ATA_CMD_SET_FEATURES: + if (qc->tf.feature != SETFEATURES_WC_ON && + qc->tf.feature != SETFEATURES_WC_OFF) + break; + case ATA_CMD_INIT_DEV_PARAMS: + case ATA_CMD_SET_MULTI: + break; + + case ATA_CMD_SLEEP: + dev->flags |= ATA_DFLAG_SLEEPING; + break; + } + + __ata_qc_complete(qc); +} + +static void fill_result_tf(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + qc->result_tf.flags = qc->tf.flags; + ata_tf_read(ap, &qc->result_tf); +} + +static void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + tf->command = ata_check_status(ap); + tf->feature = readb(ioaddr->error_addr); + tf->nsect = readb(ioaddr->nsect_addr); + tf->lbal = readb(ioaddr->lbal_addr); + tf->lbam = readb(ioaddr->lbam_addr); + tf->lbah = readb(ioaddr->lbah_addr); + tf->device = readb(ioaddr->device_addr); + + if (tf->flags & ATA_TFLAG_LBA48) { + if (ioaddr->ctl_addr) { + writeb(tf->ctl | ATA_HOB, ioaddr->ctl_addr); + + tf->hob_feature = readb(ioaddr->error_addr); + tf->hob_nsect = readb(ioaddr->nsect_addr); + tf->hob_lbal = readb(ioaddr->lbal_addr); + tf->hob_lbam = readb(ioaddr->lbam_addr); + tf->hob_lbah = readb(ioaddr->lbah_addr); + + writeb(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + } else { + printf("sata_dwc warnning register read.\n"); + } + } +} + +static void __ata_qc_complete(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; + + link->active_tag = ATA_TAG_POISON; + ap->nr_active_links--; + + if (qc->flags & ATA_QCFLAG_CLEAR_EXCL && ap->excl_link == link) + ap->excl_link = NULL; + + qc->flags &= ~ATA_QCFLAG_ACTIVE; + ap->qc_active &= ~(1 << qc->tag); +} + +static void ata_qc_free(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int tag; + qc->flags = 0; + tag = qc->tag; + if (tag < ATA_MAX_QUEUE) { + qc->tag = ATA_TAG_POISON; + clear_bit(tag, &ap->qc_allocated); + } +} + +static int check_sata_dev_state(void) +{ + unsigned long datalen; + unsigned char *pdata; + int ret = 0; + int i = 0; + char temp_data_buf[512]; + + while (1) { + udelay(10000); + + pdata = (unsigned char*)&temp_data_buf[0]; + datalen = 512; + + ret = ata_dev_read_sectors(pdata, datalen, 0, 1); + + if (ret == true) + break; + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + dev_state = SATA_NODEVICE; + return false; + } + + if ((i >= 100) && ((i % 100) == 0)) + printf("."); + } + + dev_state = SATA_READY; + + return true; +} + +static unsigned int ata_dev_set_feature(struct ata_device *dev, + u8 enable, u8 feature) +{ + struct ata_taskfile tf; + struct ata_port *ap; + ap = pap; + unsigned int err_mask; + + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_SET_FEATURES; + tf.feature = enable; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = feature; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); + + return err_mask; +} + +static unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors) +{ + struct ata_taskfile tf; + struct ata_port *ap; + ap = pap; + unsigned int err_mask; + + if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16) + return AC_ERR_INVALID; + + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_INIT_DEV_PARAMS; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = sectors; + tf.device |= (heads - 1) & 0x0f; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); + + if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED)) + err_mask = 0; + + return err_mask; +} + +#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48) +#define SATA_MAX_READ_BLK 0xFF +#else +#define SATA_MAX_READ_BLK 0xFFFF +#endif + +ulong sata_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer) +{ + ulong start,blks, buf_addr; + unsigned short smallblks; + unsigned long datalen; + unsigned char *pdata; + device &= 0xff; + + u32 block = 0; + u32 n_block = 0; + + if (dev_state != SATA_READY) + return 0; + + buf_addr = (unsigned long)buffer; + start = blknr; + blks = blkcnt; + do { + pdata = (unsigned char *)buf_addr; + if (blks > SATA_MAX_READ_BLK) { + datalen = sata_dev_desc[device].blksz * SATA_MAX_READ_BLK; + smallblks = SATA_MAX_READ_BLK; + + block = (u32)start; + n_block = (u32)smallblks; + + start += SATA_MAX_READ_BLK; + blks -= SATA_MAX_READ_BLK; + } else { + datalen = sata_dev_desc[device].blksz * SATA_MAX_READ_BLK; + datalen = sata_dev_desc[device].blksz * blks; + smallblks = (unsigned short)blks; + + block = (u32)start; + n_block = (u32)smallblks; + + start += blks; + blks = 0; + } + + if (ata_dev_read_sectors(pdata, datalen, block, n_block) != true) { + printf("sata_dwc : Hard disk read error.\n"); + blkcnt -= blks; + break; + } + buf_addr += datalen; + } while (blks != 0); + + return (blkcnt); +} + +static int ata_dev_read_sectors(unsigned char *pdata, unsigned long datalen, + u32 block, u32 n_block) +{ + struct ata_port *ap = pap; + struct ata_device *dev = &ata_device; + struct ata_taskfile tf; + unsigned int class = ATA_DEV_ATA; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1; + + if (dev_state == SATA_ERROR) + return false; + + ata_dev_select(ap, dev->devno, 1, 1); + +retry: + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + + ap->pdata = pdata; + + tf.device = ATA_DEVICE_OBS; + + temp_n_block = n_block; + +#ifdef CONFIG_LBA48 + tf.command = ATA_CMD_PIO_READ_EXT; + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; + + tf.hob_feature = 31; + tf.feature = 31; + tf.hob_nsect = (n_block >> 8) & 0xff; + tf.nsect = n_block & 0xff; + + tf.hob_lbah = 0x0; + tf.hob_lbam = 0x0; + tf.hob_lbal = (block >> 24) & 0xff; + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; +#else + tf.command = ATA_CMD_PIO_READ; + tf.flags |= ATA_TFLAG_LBA ; + + tf.feature = 31; + tf.nsect = n_block & 0xff; + + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = (block >> 24) & 0xf; + + tf.device |= 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; + +#endif + + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.flags |= ATA_TFLAG_POLLING; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, 0, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("READ_SECTORS NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + + reason = "I/O error"; + goto err_out; + } + + return true; + +err_out: + printf("failed to READ SECTORS (%s, err_mask=0x%x)\n", reason, err_mask); + return false; +} + +#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48) +#define SATA_MAX_WRITE_BLK 0xFF +#else +#define SATA_MAX_WRITE_BLK 0xFFFF +#endif + +ulong sata_write(int device, ulong blknr, lbaint_t blkcnt, const void *buffer) +{ + ulong start,blks, buf_addr; + unsigned short smallblks; + unsigned long datalen; + unsigned char *pdata; + device &= 0xff; + + + u32 block = 0; + u32 n_block = 0; + + if (dev_state != SATA_READY) + return 0; + + buf_addr = (unsigned long)buffer; + start = blknr; + blks = blkcnt; + do { + pdata = (unsigned char *)buf_addr; + if (blks > SATA_MAX_WRITE_BLK) { + datalen = sata_dev_desc[device].blksz * SATA_MAX_WRITE_BLK; + smallblks = SATA_MAX_WRITE_BLK; + + block = (u32)start; + n_block = (u32)smallblks; + + start += SATA_MAX_WRITE_BLK; + blks -= SATA_MAX_WRITE_BLK; + } else { + datalen = sata_dev_desc[device].blksz * blks; + smallblks = (unsigned short)blks; + + block = (u32)start; + n_block = (u32)smallblks; + + start += blks; + blks = 0; + } + + if (ata_dev_write_sectors(pdata, datalen, block, n_block) != true) { + printf("sata_dwc : Hard disk read error.\n"); + blkcnt -= blks; + break; + } + buf_addr += datalen; + } while (blks != 0); + + return (blkcnt); +} + +static int ata_dev_write_sectors(unsigned char* pdata, unsigned long datalen, + u32 block, u32 n_block) +{ + struct ata_port *ap = pap; + struct ata_device *dev = &ata_device; + struct ata_taskfile tf; + unsigned int class = ATA_DEV_ATA; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1; + + if (dev_state == SATA_ERROR) + return false; + + ata_dev_select(ap, dev->devno, 1, 1); + +retry: + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + + ap->pdata = pdata; + + tf.device = ATA_DEVICE_OBS; + + temp_n_block = n_block; + + +#ifdef CONFIG_LBA48 + tf.command = ATA_CMD_PIO_WRITE_EXT; + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48 | ATA_TFLAG_WRITE; + + tf.hob_feature = 31; + tf.feature = 31; + tf.hob_nsect = (n_block >> 8) & 0xff; + tf.nsect = n_block & 0xff; + + tf.hob_lbah = 0x0; + tf.hob_lbam = 0x0; + tf.hob_lbal = (block >> 24) & 0xff; + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; +#else + tf.command = ATA_CMD_PIO_WRITE; + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_WRITE; + + tf.feature = 31; + tf.nsect = n_block & 0xff; + + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = (block >> 24) & 0xf; + + tf.device |= 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; + +#endif + + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.flags |= ATA_TFLAG_POLLING; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, 0, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("READ_SECTORS NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + + reason = "I/O error"; + goto err_out; + } + + return true; + +err_out: + printf("failed to WRITE SECTORS (%s, err_mask=0x%x)\n", reason, err_mask); + return false; +} diff --git a/drivers/ata/sata_dwc.h b/drivers/ata/sata_dwc.h new file mode 100644 index 0000000000..e2d9e0c1fc --- /dev/null +++ b/drivers/ata/sata_dwc.h @@ -0,0 +1,465 @@ +/* + * sata_dwc.h + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + * Copyright 2006 Applied Micro Circuits Corporation + * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED + * + * SPDX-License-Identifier: GPL-2.0+ + */ +/* + * SATA support based on the chip canyonlands. + * + * 04-17-2009 + * The local version of this driver for the canyonlands board + * does not use interrupts but polls the chip instead. + */ + + +#ifndef _SATA_DWC_H_ +#define _SATA_DWC_H_ + +#define __U_BOOT__ + +#define HZ 100 +#define READ 0 +#define WRITE 1 + +enum { + ATA_READID_POSTRESET = (1 << 0), + + ATA_DNXFER_PIO = 0, + ATA_DNXFER_DMA = 1, + ATA_DNXFER_40C = 2, + ATA_DNXFER_FORCE_PIO = 3, + ATA_DNXFER_FORCE_PIO0 = 4, + + ATA_DNXFER_QUIET = (1 << 31), +}; + +enum hsm_task_states { + HSM_ST_IDLE, + HSM_ST_FIRST, + HSM_ST, + HSM_ST_LAST, + HSM_ST_ERR, +}; + +#define ATA_SHORT_PAUSE ((HZ >> 6) + 1) + +struct ata_queued_cmd { + struct ata_port *ap; + struct ata_device *dev; + + struct ata_taskfile tf; + u8 cdb[ATAPI_CDB_LEN]; + unsigned long flags; + unsigned int tag; + unsigned int n_elem; + + int dma_dir; + unsigned int sect_size; + + unsigned int nbytes; + unsigned int extrabytes; + unsigned int curbytes; + + unsigned int err_mask; + struct ata_taskfile result_tf; + + void *private_data; +#ifndef __U_BOOT__ + void *lldd_task; +#endif + unsigned char *pdata; +}; + +typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc); + +#define ATA_TAG_POISON 0xfafbfcfdU + +enum { + LIBATA_MAX_PRD = ATA_MAX_PRD / 2, + LIBATA_DUMB_MAX_PRD = ATA_MAX_PRD / 4, + ATA_MAX_PORTS = 8, + ATA_DEF_QUEUE = 1, + ATA_MAX_QUEUE = 32, + ATA_TAG_INTERNAL = ATA_MAX_QUEUE - 1, + ATA_MAX_BUS = 2, + ATA_DEF_BUSY_WAIT = 10000, + + ATAPI_MAX_DRAIN = 16 << 10, + + ATA_SHT_EMULATED = 1, + ATA_SHT_CMD_PER_LUN = 1, + ATA_SHT_THIS_ID = -1, + ATA_SHT_USE_CLUSTERING = 1, + + ATA_DFLAG_LBA = (1 << 0), + ATA_DFLAG_LBA48 = (1 << 1), + ATA_DFLAG_CDB_INTR = (1 << 2), + ATA_DFLAG_NCQ = (1 << 3), + ATA_DFLAG_FLUSH_EXT = (1 << 4), + ATA_DFLAG_ACPI_PENDING = (1 << 5), + ATA_DFLAG_ACPI_FAILED = (1 << 6), + ATA_DFLAG_AN = (1 << 7), + ATA_DFLAG_HIPM = (1 << 8), + ATA_DFLAG_DIPM = (1 << 9), + ATA_DFLAG_DMADIR = (1 << 10), + ATA_DFLAG_CFG_MASK = (1 << 12) - 1, + + ATA_DFLAG_PIO = (1 << 12), + ATA_DFLAG_NCQ_OFF = (1 << 13), + ATA_DFLAG_SPUNDOWN = (1 << 14), + ATA_DFLAG_SLEEPING = (1 << 15), + ATA_DFLAG_DUBIOUS_XFER = (1 << 16), + ATA_DFLAG_INIT_MASK = (1 << 24) - 1, + + ATA_DFLAG_DETACH = (1 << 24), + ATA_DFLAG_DETACHED = (1 << 25), + + ATA_LFLAG_HRST_TO_RESUME = (1 << 0), + ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), + ATA_LFLAG_NO_SRST = (1 << 2), + ATA_LFLAG_ASSUME_ATA = (1 << 3), + ATA_LFLAG_ASSUME_SEMB = (1 << 4), + ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, + ATA_LFLAG_NO_RETRY = (1 << 5), + ATA_LFLAG_DISABLED = (1 << 6), + + ATA_FLAG_SLAVE_POSS = (1 << 0), + ATA_FLAG_SATA = (1 << 1), + ATA_FLAG_NO_LEGACY = (1 << 2), + ATA_FLAG_MMIO = (1 << 3), + ATA_FLAG_SRST = (1 << 4), + ATA_FLAG_SATA_RESET = (1 << 5), + ATA_FLAG_NO_ATAPI = (1 << 6), + ATA_FLAG_PIO_DMA = (1 << 7), + ATA_FLAG_PIO_LBA48 = (1 << 8), + ATA_FLAG_PIO_POLLING = (1 << 9), + ATA_FLAG_NCQ = (1 << 10), + ATA_FLAG_DEBUGMSG = (1 << 13), + ATA_FLAG_IGN_SIMPLEX = (1 << 15), + ATA_FLAG_NO_IORDY = (1 << 16), + ATA_FLAG_ACPI_SATA = (1 << 17), + ATA_FLAG_AN = (1 << 18), + ATA_FLAG_PMP = (1 << 19), + ATA_FLAG_IPM = (1 << 20), + + ATA_FLAG_DISABLED = (1 << 23), + + ATA_PFLAG_EH_PENDING = (1 << 0), + ATA_PFLAG_EH_IN_PROGRESS = (1 << 1), + ATA_PFLAG_FROZEN = (1 << 2), + ATA_PFLAG_RECOVERED = (1 << 3), + ATA_PFLAG_LOADING = (1 << 4), + ATA_PFLAG_UNLOADING = (1 << 5), + ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), + ATA_PFLAG_INITIALIZING = (1 << 7), + ATA_PFLAG_RESETTING = (1 << 8), + ATA_PFLAG_SUSPENDED = (1 << 17), + ATA_PFLAG_PM_PENDING = (1 << 18), + + ATA_QCFLAG_ACTIVE = (1 << 0), + ATA_QCFLAG_DMAMAP = (1 << 1), + ATA_QCFLAG_IO = (1 << 3), + ATA_QCFLAG_RESULT_TF = (1 << 4), + ATA_QCFLAG_CLEAR_EXCL = (1 << 5), + ATA_QCFLAG_QUIET = (1 << 6), + + ATA_QCFLAG_FAILED = (1 << 16), + ATA_QCFLAG_SENSE_VALID = (1 << 17), + ATA_QCFLAG_EH_SCHEDULED = (1 << 18), + + ATA_HOST_SIMPLEX = (1 << 0), + ATA_HOST_STARTED = (1 << 1), + + ATA_TMOUT_BOOT = 30 * 100, + ATA_TMOUT_BOOT_QUICK = 7 * 100, + ATA_TMOUT_INTERNAL = 30 * 100, + ATA_TMOUT_INTERNAL_QUICK = 5 * 100, + + /* FIXME: GoVault needs 2s but we can't afford that without + * parallel probing. 800ms is enough for iVDR disk + * HHD424020F7SV00. Increase to 2secs when parallel probing + * is in place. + */ + ATA_TMOUT_FF_WAIT = 4 * 100 / 5, + + BUS_UNKNOWN = 0, + BUS_DMA = 1, + BUS_IDLE = 2, + BUS_NOINTR = 3, + BUS_NODATA = 4, + BUS_TIMER = 5, + BUS_PIO = 6, + BUS_EDD = 7, + BUS_IDENTIFY = 8, + BUS_PACKET = 9, + + PORT_UNKNOWN = 0, + PORT_ENABLED = 1, + PORT_DISABLED = 2, + + /* encoding various smaller bitmaps into a single + * unsigned long bitmap + */ + ATA_NR_PIO_MODES = 7, + ATA_NR_MWDMA_MODES = 5, + ATA_NR_UDMA_MODES = 8, + + ATA_SHIFT_PIO = 0, + ATA_SHIFT_MWDMA = ATA_SHIFT_PIO + ATA_NR_PIO_MODES, + ATA_SHIFT_UDMA = ATA_SHIFT_MWDMA + ATA_NR_MWDMA_MODES, + + ATA_DMA_PAD_SZ = 4, + + ATA_ERING_SIZE = 32, + + ATA_DEFER_LINK = 1, + ATA_DEFER_PORT = 2, + + ATA_EH_DESC_LEN = 80, + + ATA_EH_REVALIDATE = (1 << 0), + ATA_EH_SOFTRESET = (1 << 1), + ATA_EH_HARDRESET = (1 << 2), + ATA_EH_ENABLE_LINK = (1 << 3), + ATA_EH_LPM = (1 << 4), + + ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, + ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, + + ATA_EHI_HOTPLUGGED = (1 << 0), + ATA_EHI_RESUME_LINK = (1 << 1), + ATA_EHI_NO_AUTOPSY = (1 << 2), + ATA_EHI_QUIET = (1 << 3), + + ATA_EHI_DID_SOFTRESET = (1 << 16), + ATA_EHI_DID_HARDRESET = (1 << 17), + ATA_EHI_PRINTINFO = (1 << 18), + ATA_EHI_SETMODE = (1 << 19), + ATA_EHI_POST_SETMODE = (1 << 20), + + ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET, + ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, + + ATA_EH_MAX_TRIES = 5, + + ATA_PROBE_MAX_TRIES = 3, + ATA_EH_DEV_TRIES = 3, + ATA_EH_PMP_TRIES = 5, + ATA_EH_PMP_LINK_TRIES = 3, + + SATA_PMP_SCR_TIMEOUT = 250, + + /* Horkage types. May be set by libata or controller on drives + (some horkage may be drive/controller pair dependant */ + + ATA_HORKAGE_DIAGNOSTIC = (1 << 0), + ATA_HORKAGE_NODMA = (1 << 1), + ATA_HORKAGE_NONCQ = (1 << 2), + ATA_HORKAGE_MAX_SEC_128 = (1 << 3), + ATA_HORKAGE_BROKEN_HPA = (1 << 4), + ATA_HORKAGE_SKIP_PM = (1 << 5), + ATA_HORKAGE_HPA_SIZE = (1 << 6), + ATA_HORKAGE_IPM = (1 << 7), + ATA_HORKAGE_IVB = (1 << 8), + ATA_HORKAGE_STUCK_ERR = (1 << 9), + + ATA_DMA_MASK_ATA = (1 << 0), + ATA_DMA_MASK_ATAPI = (1 << 1), + ATA_DMA_MASK_CFA = (1 << 2), + + ATAPI_READ = 0, + ATAPI_WRITE = 1, + ATAPI_READ_CD = 2, + ATAPI_PASS_THRU = 3, + ATAPI_MISC = 4, +}; + +enum ata_completion_errors { + AC_ERR_DEV = (1 << 0), + AC_ERR_HSM = (1 << 1), + AC_ERR_TIMEOUT = (1 << 2), + AC_ERR_MEDIA = (1 << 3), + AC_ERR_ATA_BUS = (1 << 4), + AC_ERR_HOST_BUS = (1 << 5), + AC_ERR_SYSTEM = (1 << 6), + AC_ERR_INVALID = (1 << 7), + AC_ERR_OTHER = (1 << 8), + AC_ERR_NODEV_HINT = (1 << 9), + AC_ERR_NCQ = (1 << 10), +}; + +enum ata_xfer_mask { + ATA_MASK_PIO = ((1LU << ATA_NR_PIO_MODES) - 1) << ATA_SHIFT_PIO, + ATA_MASK_MWDMA = ((1LU << ATA_NR_MWDMA_MODES) - 1) << ATA_SHIFT_MWDMA, + ATA_MASK_UDMA = ((1LU << ATA_NR_UDMA_MODES) - 1) << ATA_SHIFT_UDMA, +}; + +struct ata_port_info { +#ifndef __U_BOOT__ + struct scsi_host_template *sht; +#endif + unsigned long flags; + unsigned long link_flags; + unsigned long pio_mask; + unsigned long mwdma_mask; + unsigned long udma_mask; +#ifndef __U_BOOT__ + const struct ata_port_operations *port_ops; + void *private_data; +#endif +}; + +struct ata_ioports { + void __iomem *cmd_addr; + void __iomem *data_addr; + void __iomem *error_addr; + void __iomem *feature_addr; + void __iomem *nsect_addr; + void __iomem *lbal_addr; + void __iomem *lbam_addr; + void __iomem *lbah_addr; + void __iomem *device_addr; + void __iomem *status_addr; + void __iomem *command_addr; + void __iomem *altstatus_addr; + void __iomem *ctl_addr; +#ifndef __U_BOOT__ + void __iomem *bmdma_addr; +#endif + void __iomem *scr_addr; +}; + +struct ata_host { +#ifndef __U_BOOT__ + void __iomem * const *iomap; + void *private_data; + const struct ata_port_operations *ops; + unsigned long flags; + struct ata_port *simplex_claimed; +#endif + unsigned int n_ports; + struct ata_port *ports[0]; +}; + +#ifndef __U_BOOT__ +struct ata_port_stats { + unsigned long unhandled_irq; + unsigned long idle_irq; + unsigned long rw_reqbuf; +}; +#endif + +struct ata_device { + struct ata_link *link; + unsigned int devno; + unsigned long flags; + unsigned int horkage; +#ifndef __U_BOOT__ + struct scsi_device *sdev; +#ifdef CONFIG_ATA_ACPI + acpi_handle acpi_handle; + union acpi_object *gtf_cache; +#endif +#endif + u64 n_sectors; + unsigned int class; + + union { + u16 id[ATA_ID_WORDS]; + u32 gscr[SATA_PMP_GSCR_DWORDS]; + }; +#ifndef __U_BOOT__ + u8 pio_mode; + u8 dma_mode; + u8 xfer_mode; + unsigned int xfer_shift; +#endif + unsigned int multi_count; + unsigned int max_sectors; + unsigned int cdb_len; +#ifndef __U_BOOT__ + unsigned long pio_mask; + unsigned long mwdma_mask; +#endif + unsigned long udma_mask; + u16 cylinders; + u16 heads; + u16 sectors; +#ifndef __U_BOOT__ + int spdn_cnt; +#endif +}; + +enum dma_data_direction { + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2, + DMA_NONE = 3, +}; + +struct ata_link { + struct ata_port *ap; + int pmp; + unsigned int active_tag; + u32 sactive; + unsigned int flags; + unsigned int hw_sata_spd_limit; +#ifndef __U_BOOT__ + unsigned int sata_spd_limit; + unsigned int sata_spd; + struct ata_device device[2]; +#endif +}; + +struct ata_port { + unsigned long flags; + unsigned int pflags; + unsigned int print_id; + unsigned int port_no; + + struct ata_ioports ioaddr; + + u8 ctl; + u8 last_ctl; + unsigned int pio_mask; + unsigned int mwdma_mask; + unsigned int udma_mask; + unsigned int cbl; + + struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; + unsigned long qc_allocated; + unsigned int qc_active; + int nr_active_links; + + struct ata_link link; +#ifndef __U_BOOT__ + int nr_pmp_links; + struct ata_link *pmp_link; +#endif + struct ata_link *excl_link; + int nr_pmp_links; +#ifndef __U_BOOT__ + struct ata_port_stats stats; + struct device *dev; + u32 msg_enable; +#endif + struct ata_host *host; + void *port_task_data; + + unsigned int hsm_task_state; + void *private_data; + unsigned char *pdata; +}; + +#endif diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c new file mode 100644 index 0000000000..78e3da442d --- /dev/null +++ b/drivers/ata/sata_mv.c @@ -0,0 +1,1051 @@ +/* + * Copyright (C) Excito Elektronik i Skåne AB, 2010. + * Author: Tor Krill + * + * Copyright (C) 2015 Stefan Roese + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * This driver supports the SATA controller of some Mavell SoC's. + * Here a (most likely incomplete) list of the supported SoC's: + * - Kirkwood + * - Armada 370 + * - Armada XP + * + * This driver implementation is an alternative to the already available + * driver via the "ide" commands interface (drivers/block/mvsata_ide.c). + * But this driver only supports PIO mode and as this new driver also + * supports transfer via DMA, its much faster. + * + * Please note, that the newer SoC's (e.g. Armada 38x) are not supported + * by this driver. As they have an AHCI compatible SATA controller + * integrated. + */ + +/* + * TODO: + * Better error recovery + * No support for using PRDs (Thus max 64KB transfers) + * No NCQ support + * No port multiplier support + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_KIRKWOOD) +#include +#define SATAHC_BASE KW_SATA_BASE +#else +#include +#define SATAHC_BASE MVEBU_AXP_SATA_BASE +#endif + +#define SATA0_BASE (SATAHC_BASE + 0x2000) +#define SATA1_BASE (SATAHC_BASE + 0x4000) + +/* EDMA registers */ +#define EDMA_CFG 0x000 +#define EDMA_CFG_NCQ (1 << 5) +#define EDMA_CFG_EQUE (1 << 9) +#define EDMA_TIMER 0x004 +#define EDMA_IECR 0x008 +#define EDMA_IEMR 0x00c +#define EDMA_RQBA_HI 0x010 +#define EDMA_RQIPR 0x014 +#define EDMA_RQIPR_IPMASK (0x1f << 5) +#define EDMA_RQIPR_IPSHIFT 5 +#define EDMA_RQOPR 0x018 +#define EDMA_RQOPR_OPMASK (0x1f << 5) +#define EDMA_RQOPR_OPSHIFT 5 +#define EDMA_RSBA_HI 0x01c +#define EDMA_RSIPR 0x020 +#define EDMA_RSIPR_IPMASK (0x1f << 3) +#define EDMA_RSIPR_IPSHIFT 3 +#define EDMA_RSOPR 0x024 +#define EDMA_RSOPR_OPMASK (0x1f << 3) +#define EDMA_RSOPR_OPSHIFT 3 +#define EDMA_CMD 0x028 +#define EDMA_CMD_ENEDMA (0x01 << 0) +#define EDMA_CMD_DISEDMA (0x01 << 1) +#define EDMA_CMD_ATARST (0x01 << 2) +#define EDMA_CMD_FREEZE (0x01 << 4) +#define EDMA_TEST_CTL 0x02c +#define EDMA_STATUS 0x030 +#define EDMA_IORTO 0x034 +#define EDMA_CDTR 0x040 +#define EDMA_HLTCND 0x060 +#define EDMA_NTSR 0x094 + +/* Basic DMA registers */ +#define BDMA_CMD 0x224 +#define BDMA_STATUS 0x228 +#define BDMA_DTLB 0x22c +#define BDMA_DTHB 0x230 +#define BDMA_DRL 0x234 +#define BDMA_DRH 0x238 + +/* SATA Interface registers */ +#define SIR_ICFG 0x050 +#define SIR_CFG_GEN2EN (0x1 << 7) +#define SIR_PLL_CFG 0x054 +#define SIR_SSTATUS 0x300 +#define SSTATUS_DET_MASK (0x0f << 0) +#define SIR_SERROR 0x304 +#define SIR_SCONTROL 0x308 +#define SIR_SCONTROL_DETEN (0x01 << 0) +#define SIR_LTMODE 0x30c +#define SIR_LTMODE_NELBE (0x01 << 7) +#define SIR_PHYMODE3 0x310 +#define SIR_PHYMODE4 0x314 +#define SIR_PHYMODE1 0x32c +#define SIR_PHYMODE2 0x330 +#define SIR_BIST_CTRL 0x334 +#define SIR_BIST_DW1 0x338 +#define SIR_BIST_DW2 0x33c +#define SIR_SERR_IRQ_MASK 0x340 +#define SIR_SATA_IFCTRL 0x344 +#define SIR_SATA_TESTCTRL 0x348 +#define SIR_SATA_IFSTATUS 0x34c +#define SIR_VEND_UNIQ 0x35c +#define SIR_FIS_CFG 0x360 +#define SIR_FIS_IRQ_CAUSE 0x364 +#define SIR_FIS_IRQ_MASK 0x368 +#define SIR_FIS_DWORD0 0x370 +#define SIR_FIS_DWORD1 0x374 +#define SIR_FIS_DWORD2 0x378 +#define SIR_FIS_DWORD3 0x37c +#define SIR_FIS_DWORD4 0x380 +#define SIR_FIS_DWORD5 0x384 +#define SIR_FIS_DWORD6 0x388 +#define SIR_PHYM9_GEN2 0x398 +#define SIR_PHYM9_GEN1 0x39c +#define SIR_PHY_CFG 0x3a0 +#define SIR_PHYCTL 0x3a4 +#define SIR_PHYM10 0x3a8 +#define SIR_PHYM12 0x3b0 + +/* Shadow registers */ +#define PIO_DATA 0x100 +#define PIO_ERR_FEATURES 0x104 +#define PIO_SECTOR_COUNT 0x108 +#define PIO_LBA_LOW 0x10c +#define PIO_LBA_MID 0x110 +#define PIO_LBA_HI 0x114 +#define PIO_DEVICE 0x118 +#define PIO_CMD_STATUS 0x11c +#define PIO_STATUS_ERR (0x01 << 0) +#define PIO_STATUS_DRQ (0x01 << 3) +#define PIO_STATUS_DF (0x01 << 5) +#define PIO_STATUS_DRDY (0x01 << 6) +#define PIO_STATUS_BSY (0x01 << 7) +#define PIO_CTRL_ALTSTAT 0x120 + +/* SATAHC arbiter registers */ +#define SATAHC_CFG 0x000 +#define SATAHC_RQOP 0x004 +#define SATAHC_RQIP 0x008 +#define SATAHC_ICT 0x00c +#define SATAHC_ITT 0x010 +#define SATAHC_ICR 0x014 +#define SATAHC_ICR_PORT0 (0x01 << 0) +#define SATAHC_ICR_PORT1 (0x01 << 1) +#define SATAHC_MIC 0x020 +#define SATAHC_MIM 0x024 +#define SATAHC_LED_CFG 0x02c + +#define REQUEST_QUEUE_SIZE 32 +#define RESPONSE_QUEUE_SIZE REQUEST_QUEUE_SIZE + +struct crqb { + u32 dtb_low; /* DW0 */ + u32 dtb_high; /* DW1 */ + u32 control_flags; /* DW2 */ + u32 drb_count; /* DW3 */ + u32 ata_cmd_feat; /* DW4 */ + u32 ata_addr; /* DW5 */ + u32 ata_addr_exp; /* DW6 */ + u32 ata_sect_count; /* DW7 */ +}; + +#define CRQB_ALIGN 0x400 + +#define CRQB_CNTRLFLAGS_DIR (0x01 << 0) +#define CRQB_CNTRLFLAGS_DQTAGMASK (0x1f << 1) +#define CRQB_CNTRLFLAGS_DQTAGSHIFT 1 +#define CRQB_CNTRLFLAGS_PMPORTMASK (0x0f << 12) +#define CRQB_CNTRLFLAGS_PMPORTSHIFT 12 +#define CRQB_CNTRLFLAGS_PRDMODE (0x01 << 16) +#define CRQB_CNTRLFLAGS_HQTAGMASK (0x1f << 17) +#define CRQB_CNTRLFLAGS_HQTAGSHIFT 17 + +#define CRQB_CMDFEAT_CMDMASK (0xff << 16) +#define CRQB_CMDFEAT_CMDSHIFT 16 +#define CRQB_CMDFEAT_FEATMASK (0xff << 16) +#define CRQB_CMDFEAT_FEATSHIFT 24 + +#define CRQB_ADDR_LBA_LOWMASK (0xff << 0) +#define CRQB_ADDR_LBA_LOWSHIFT 0 +#define CRQB_ADDR_LBA_MIDMASK (0xff << 8) +#define CRQB_ADDR_LBA_MIDSHIFT 8 +#define CRQB_ADDR_LBA_HIGHMASK (0xff << 16) +#define CRQB_ADDR_LBA_HIGHSHIFT 16 +#define CRQB_ADDR_DEVICE_MASK (0xff << 24) +#define CRQB_ADDR_DEVICE_SHIFT 24 + +#define CRQB_ADDR_LBA_LOW_EXP_MASK (0xff << 0) +#define CRQB_ADDR_LBA_LOW_EXP_SHIFT 0 +#define CRQB_ADDR_LBA_MID_EXP_MASK (0xff << 8) +#define CRQB_ADDR_LBA_MID_EXP_SHIFT 8 +#define CRQB_ADDR_LBA_HIGH_EXP_MASK (0xff << 16) +#define CRQB_ADDR_LBA_HIGH_EXP_SHIFT 16 +#define CRQB_ADDR_FEATURE_EXP_MASK (0xff << 24) +#define CRQB_ADDR_FEATURE_EXP_SHIFT 24 + +#define CRQB_SECTCOUNT_COUNT_MASK (0xff << 0) +#define CRQB_SECTCOUNT_COUNT_SHIFT 0 +#define CRQB_SECTCOUNT_COUNT_EXP_MASK (0xff << 8) +#define CRQB_SECTCOUNT_COUNT_EXP_SHIFT 8 + +#define MVSATA_WIN_CONTROL(w) (MVEBU_AXP_SATA_BASE + 0x30 + ((w) << 4)) +#define MVSATA_WIN_BASE(w) (MVEBU_AXP_SATA_BASE + 0x34 + ((w) << 4)) + +struct eprd { + u32 phyaddr_low; + u32 bytecount_eot; + u32 phyaddr_hi; + u32 reserved; +}; + +#define EPRD_PHYADDR_MASK 0xfffffffe +#define EPRD_BYTECOUNT_MASK 0x0000ffff +#define EPRD_EOT (0x01 << 31) + +struct crpb { + u32 id; + u32 flags; + u32 timestamp; +}; + +#define CRPB_ALIGN 0x100 + +#define READ_CMD 0 +#define WRITE_CMD 1 + +/* + * Since we don't use PRDs yet max transfer size + * is 64KB + */ +#define MV_ATA_MAX_SECTORS (65535 / ATA_SECT_SIZE) + +/* Keep track if hw is initialized or not */ +static u32 hw_init; + +struct mv_priv { + char name[12]; + u32 link; + u32 regbase; + u32 queue_depth; + u16 pio; + u16 mwdma; + u16 udma; + + void *crqb_alloc; + struct crqb *request; + + void *crpb_alloc; + struct crpb *response; +}; + +static int ata_wait_register(u32 *addr, u32 mask, u32 val, u32 timeout_msec) +{ + ulong start; + + start = get_timer(0); + do { + if ((in_le32(addr) & mask) == val) + return 0; + } while (get_timer(start) < timeout_msec); + + return -ETIMEDOUT; +} + +/* Cut from sata_mv in linux kernel */ +static int mv_stop_edma_engine(int port) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + int i; + + /* Disable eDMA. The disable bit auto clears. */ + out_le32(priv->regbase + EDMA_CMD, EDMA_CMD_DISEDMA); + + /* Wait for the chip to confirm eDMA is off. */ + for (i = 10000; i > 0; i--) { + u32 reg = in_le32(priv->regbase + EDMA_CMD); + if (!(reg & EDMA_CMD_ENEDMA)) { + debug("EDMA stop on port %d succesful\n", port); + return 0; + } + udelay(10); + } + debug("EDMA stop on port %d failed\n", port); + return -1; +} + +static int mv_start_edma_engine(int port) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + u32 tmp; + + /* Check preconditions */ + tmp = in_le32(priv->regbase + SIR_SSTATUS); + if ((tmp & SSTATUS_DET_MASK) != 0x03) { + printf("Device error on port: %d\n", port); + return -1; + } + + tmp = in_le32(priv->regbase + PIO_CMD_STATUS); + if (tmp & (ATA_BUSY | ATA_DRQ)) { + printf("Device not ready on port: %d\n", port); + return -1; + } + + /* Clear interrupt cause */ + out_le32(priv->regbase + EDMA_IECR, 0x0); + + tmp = in_le32(SATAHC_BASE + SATAHC_ICR); + tmp &= ~(port == 0 ? SATAHC_ICR_PORT0 : SATAHC_ICR_PORT1); + out_le32(SATAHC_BASE + SATAHC_ICR, tmp); + + /* Configure edma operation */ + tmp = in_le32(priv->regbase + EDMA_CFG); + tmp &= ~EDMA_CFG_NCQ; /* No NCQ */ + tmp &= ~EDMA_CFG_EQUE; /* Dont queue operations */ + out_le32(priv->regbase + EDMA_CFG, tmp); + + out_le32(priv->regbase + SIR_FIS_IRQ_CAUSE, 0x0); + + /* Configure fis, set all to no-wait for now */ + out_le32(priv->regbase + SIR_FIS_CFG, 0x0); + + /* Setup request queue */ + out_le32(priv->regbase + EDMA_RQBA_HI, 0x0); + out_le32(priv->regbase + EDMA_RQIPR, priv->request); + out_le32(priv->regbase + EDMA_RQOPR, 0x0); + + /* Setup response queue */ + out_le32(priv->regbase + EDMA_RSBA_HI, 0x0); + out_le32(priv->regbase + EDMA_RSOPR, priv->response); + out_le32(priv->regbase + EDMA_RSIPR, 0x0); + + /* Start edma */ + out_le32(priv->regbase + EDMA_CMD, EDMA_CMD_ENEDMA); + + return 0; +} + +static int mv_reset_channel(int port) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + + /* Make sure edma is stopped */ + mv_stop_edma_engine(port); + + out_le32(priv->regbase + EDMA_CMD, EDMA_CMD_ATARST); + udelay(25); /* allow reset propagation */ + out_le32(priv->regbase + EDMA_CMD, 0); + mdelay(10); + + return 0; +} + +static void mv_reset_port(int port) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + + mv_reset_channel(port); + + out_le32(priv->regbase + EDMA_CMD, 0x0); + out_le32(priv->regbase + EDMA_CFG, 0x101f); + out_le32(priv->regbase + EDMA_IECR, 0x0); + out_le32(priv->regbase + EDMA_IEMR, 0x0); + out_le32(priv->regbase + EDMA_RQBA_HI, 0x0); + out_le32(priv->regbase + EDMA_RQIPR, 0x0); + out_le32(priv->regbase + EDMA_RQOPR, 0x0); + out_le32(priv->regbase + EDMA_RSBA_HI, 0x0); + out_le32(priv->regbase + EDMA_RSIPR, 0x0); + out_le32(priv->regbase + EDMA_RSOPR, 0x0); + out_le32(priv->regbase + EDMA_IORTO, 0xfa); +} + +static void mv_reset_one_hc(void) +{ + out_le32(SATAHC_BASE + SATAHC_ICT, 0x00); + out_le32(SATAHC_BASE + SATAHC_ITT, 0x00); + out_le32(SATAHC_BASE + SATAHC_ICR, 0x00); +} + +static int probe_port(int port) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + int tries, tries2, set15 = 0; + u32 tmp; + + debug("Probe port: %d\n", port); + + for (tries = 0; tries < 2; tries++) { + /* Clear SError */ + out_le32(priv->regbase + SIR_SERROR, 0x0); + + /* trigger com-init */ + tmp = in_le32(priv->regbase + SIR_SCONTROL); + tmp = (tmp & 0x0f0) | 0x300 | SIR_SCONTROL_DETEN; + out_le32(priv->regbase + SIR_SCONTROL, tmp); + + mdelay(1); + + tmp = in_le32(priv->regbase + SIR_SCONTROL); + tries2 = 5; + do { + tmp = (tmp & 0x0f0) | 0x300; + out_le32(priv->regbase + SIR_SCONTROL, tmp); + mdelay(10); + tmp = in_le32(priv->regbase + SIR_SCONTROL); + } while ((tmp & 0xf0f) != 0x300 && tries2--); + + mdelay(10); + + for (tries2 = 0; tries2 < 200; tries2++) { + tmp = in_le32(priv->regbase + SIR_SSTATUS); + if ((tmp & SSTATUS_DET_MASK) == 0x03) { + debug("Found device on port\n"); + return 0; + } + mdelay(1); + } + + if ((tmp & SSTATUS_DET_MASK) == 0) { + debug("No device attached on port %d\n", port); + return -ENODEV; + } + + if (!set15) { + /* Try on 1.5Gb/S */ + debug("Try 1.5Gb link\n"); + set15 = 1; + out_le32(priv->regbase + SIR_SCONTROL, 0x304); + + tmp = in_le32(priv->regbase + SIR_ICFG); + tmp &= ~SIR_CFG_GEN2EN; + out_le32(priv->regbase + SIR_ICFG, tmp); + + mv_reset_channel(port); + } + } + + debug("Failed to probe port\n"); + return -1; +} + +/* Get request queue in pointer */ +static int get_reqip(int port) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + u32 tmp; + + tmp = in_le32(priv->regbase + EDMA_RQIPR) & EDMA_RQIPR_IPMASK; + tmp = tmp >> EDMA_RQIPR_IPSHIFT; + + return tmp; +} + +static void set_reqip(int port, int reqin) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + u32 tmp; + + tmp = in_le32(priv->regbase + EDMA_RQIPR) & ~EDMA_RQIPR_IPMASK; + tmp |= ((reqin << EDMA_RQIPR_IPSHIFT) & EDMA_RQIPR_IPMASK); + out_le32(priv->regbase + EDMA_RQIPR, tmp); +} + +/* Get next available slot, ignoring possible overwrite */ +static int get_next_reqip(int port) +{ + int slot = get_reqip(port); + slot = (slot + 1) % REQUEST_QUEUE_SIZE; + return slot; +} + +/* Get response queue in pointer */ +static int get_rspip(int port) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + u32 tmp; + + tmp = in_le32(priv->regbase + EDMA_RSIPR) & EDMA_RSIPR_IPMASK; + tmp = tmp >> EDMA_RSIPR_IPSHIFT; + + return tmp; +} + +/* Get response queue out pointer */ +static int get_rspop(int port) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + u32 tmp; + + tmp = in_le32(priv->regbase + EDMA_RSOPR) & EDMA_RSOPR_OPMASK; + tmp = tmp >> EDMA_RSOPR_OPSHIFT; + return tmp; +} + +/* Get next response queue pointer */ +static int get_next_rspop(int port) +{ + return (get_rspop(port) + 1) % RESPONSE_QUEUE_SIZE; +} + +/* Set response queue pointer */ +static void set_rspop(int port, int reqin) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + u32 tmp; + + tmp = in_le32(priv->regbase + EDMA_RSOPR) & ~EDMA_RSOPR_OPMASK; + tmp |= ((reqin << EDMA_RSOPR_OPSHIFT) & EDMA_RSOPR_OPMASK); + + out_le32(priv->regbase + EDMA_RSOPR, tmp); +} + +static int wait_dma_completion(int port, int index, u32 timeout_msec) +{ + u32 tmp, res; + + tmp = port == 0 ? SATAHC_ICR_PORT0 : SATAHC_ICR_PORT1; + res = ata_wait_register((u32 *)(SATAHC_BASE + SATAHC_ICR), tmp, + tmp, timeout_msec); + if (res) + printf("Failed to wait for completion on port %d\n", port); + + return res; +} + +static void process_responses(int port) +{ +#ifdef DEBUG + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; +#endif + u32 tmp; + u32 outind = get_rspop(port); + + /* Ack interrupts */ + tmp = in_le32(SATAHC_BASE + SATAHC_ICR); + if (port == 0) + tmp &= ~(BIT(0) | BIT(8)); + else + tmp &= ~(BIT(1) | BIT(9)); + tmp &= ~(BIT(4)); + out_le32(SATAHC_BASE + SATAHC_ICR, tmp); + + while (get_rspip(port) != outind) { +#ifdef DEBUG + debug("Response index %d flags %08x on port %d\n", outind, + priv->response[outind].flags, port); +#endif + outind = get_next_rspop(port); + set_rspop(port, outind); + } +} + +static int mv_ata_exec_ata_cmd(int port, struct sata_fis_h2d *cfis, + u8 *buffer, u32 len, u32 iswrite) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + struct crqb *req; + int slot; + u32 start; + + if (len >= 64 * 1024) { + printf("We only support <64K transfers for now\n"); + return -1; + } + + /* Initialize request */ + slot = get_reqip(port); + memset(&priv->request[slot], 0, sizeof(struct crqb)); + req = &priv->request[slot]; + + req->dtb_low = (u32)buffer; + + /* Dont use PRDs */ + req->control_flags = CRQB_CNTRLFLAGS_PRDMODE; + req->control_flags |= iswrite ? 0 : CRQB_CNTRLFLAGS_DIR; + req->control_flags |= + ((cfis->pm_port_c << CRQB_CNTRLFLAGS_PMPORTSHIFT) + & CRQB_CNTRLFLAGS_PMPORTMASK); + + req->drb_count = len; + + req->ata_cmd_feat = (cfis->command << CRQB_CMDFEAT_CMDSHIFT) & + CRQB_CMDFEAT_CMDMASK; + req->ata_cmd_feat |= (cfis->features << CRQB_CMDFEAT_FEATSHIFT) & + CRQB_CMDFEAT_FEATMASK; + + req->ata_addr = (cfis->lba_low << CRQB_ADDR_LBA_LOWSHIFT) & + CRQB_ADDR_LBA_LOWMASK; + req->ata_addr |= (cfis->lba_mid << CRQB_ADDR_LBA_MIDSHIFT) & + CRQB_ADDR_LBA_MIDMASK; + req->ata_addr |= (cfis->lba_high << CRQB_ADDR_LBA_HIGHSHIFT) & + CRQB_ADDR_LBA_HIGHMASK; + req->ata_addr |= (cfis->device << CRQB_ADDR_DEVICE_SHIFT) & + CRQB_ADDR_DEVICE_MASK; + + req->ata_addr_exp = (cfis->lba_low_exp << CRQB_ADDR_LBA_LOW_EXP_SHIFT) & + CRQB_ADDR_LBA_LOW_EXP_MASK; + req->ata_addr_exp |= + (cfis->lba_mid_exp << CRQB_ADDR_LBA_MID_EXP_SHIFT) & + CRQB_ADDR_LBA_MID_EXP_MASK; + req->ata_addr_exp |= + (cfis->lba_high_exp << CRQB_ADDR_LBA_HIGH_EXP_SHIFT) & + CRQB_ADDR_LBA_HIGH_EXP_MASK; + req->ata_addr_exp |= + (cfis->features_exp << CRQB_ADDR_FEATURE_EXP_SHIFT) & + CRQB_ADDR_FEATURE_EXP_MASK; + + req->ata_sect_count = + (cfis->sector_count << CRQB_SECTCOUNT_COUNT_SHIFT) & + CRQB_SECTCOUNT_COUNT_MASK; + req->ata_sect_count |= + (cfis->sector_count_exp << CRQB_SECTCOUNT_COUNT_EXP_SHIFT) & + CRQB_SECTCOUNT_COUNT_EXP_MASK; + + /* Flush data */ + start = (u32)req & ~(ARCH_DMA_MINALIGN - 1); + flush_dcache_range(start, + start + ALIGN(sizeof(*req), ARCH_DMA_MINALIGN)); + + /* Trigger operation */ + slot = get_next_reqip(port); + set_reqip(port, slot); + + /* Wait for completion */ + if (wait_dma_completion(port, slot, 10000)) { + printf("ATA operation timed out\n"); + return -1; + } + + process_responses(port); + + /* Invalidate data on read */ + if (buffer && len) { + start = (u32)buffer & ~(ARCH_DMA_MINALIGN - 1); + invalidate_dcache_range(start, + start + ALIGN(len, ARCH_DMA_MINALIGN)); + } + + return len; +} + +static u32 mv_sata_rw_cmd_ext(int port, lbaint_t start, u32 blkcnt, + u8 *buffer, int is_write) +{ + struct sata_fis_h2d cfis; + u32 res; + u64 block; + + block = (u64)start; + + memset(&cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + 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; + + res = mv_ata_exec_ata_cmd(port, &cfis, buffer, ATA_SECT_SIZE * blkcnt, + is_write); + + return res >= 0 ? blkcnt : res; +} + +static u32 mv_sata_rw_cmd(int port, lbaint_t start, u32 blkcnt, u8 *buffer, + int is_write) +{ + struct sata_fis_h2d cfis; + lbaint_t block; + u32 res; + + block = start; + + memset(&cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + 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); + + res = mv_ata_exec_ata_cmd(port, &cfis, buffer, ATA_SECT_SIZE * blkcnt, + is_write); + + return res >= 0 ? blkcnt : res; +} + +static u32 ata_low_level_rw(int dev, lbaint_t blknr, lbaint_t blkcnt, + void *buffer, int is_write) +{ + lbaint_t start, blks; + u8 *addr; + int max_blks; + + debug("%s: %ld %ld\n", __func__, blknr, blkcnt); + + start = blknr; + blks = blkcnt; + addr = (u8 *)buffer; + + max_blks = MV_ATA_MAX_SECTORS; + do { + if (blks > max_blks) { + if (sata_dev_desc[dev].lba48) { + mv_sata_rw_cmd_ext(dev, start, max_blks, addr, + is_write); + } else { + mv_sata_rw_cmd(dev, start, max_blks, addr, + is_write); + } + start += max_blks; + blks -= max_blks; + addr += ATA_SECT_SIZE * max_blks; + } else { + if (sata_dev_desc[dev].lba48) { + mv_sata_rw_cmd_ext(dev, start, blks, addr, + is_write); + } else { + mv_sata_rw_cmd(dev, start, blks, addr, + is_write); + } + start += blks; + blks = 0; + addr += ATA_SECT_SIZE * blks; + } + } while (blks != 0); + + return blkcnt; +} + +static int mv_ata_exec_ata_cmd_nondma(int port, + struct sata_fis_h2d *cfis, u8 *buffer, + u32 len, u32 iswrite) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + int i; + u16 *tp; + + debug("%s\n", __func__); + + out_le32(priv->regbase + PIO_SECTOR_COUNT, cfis->sector_count); + out_le32(priv->regbase + PIO_LBA_HI, cfis->lba_high); + out_le32(priv->regbase + PIO_LBA_MID, cfis->lba_mid); + out_le32(priv->regbase + PIO_LBA_LOW, cfis->lba_low); + out_le32(priv->regbase + PIO_ERR_FEATURES, cfis->features); + out_le32(priv->regbase + PIO_DEVICE, cfis->device); + out_le32(priv->regbase + PIO_CMD_STATUS, cfis->command); + + if (ata_wait_register((u32 *)(priv->regbase + PIO_CMD_STATUS), + ATA_BUSY, 0x0, 10000)) { + debug("Failed to wait for completion\n"); + return -1; + } + + if (len > 0) { + tp = (u16 *)buffer; + for (i = 0; i < len / 2; i++) { + if (iswrite) + out_le16(priv->regbase + PIO_DATA, *tp++); + else + *tp++ = in_le16(priv->regbase + PIO_DATA); + } + } + + return len; +} + +static int mv_sata_identify(int port, u16 *id) +{ + struct sata_fis_h2d h2d; + + memset(&h2d, 0, sizeof(struct sata_fis_h2d)); + + h2d.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + h2d.command = ATA_CMD_ID_ATA; + + /* Give device time to get operational */ + mdelay(10); + + return mv_ata_exec_ata_cmd_nondma(port, &h2d, (u8 *)id, + ATA_ID_WORDS * 2, READ_CMD); +} + +static void mv_sata_xfer_mode(int port, u16 *id) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + + priv->pio = id[ATA_ID_PIO_MODES]; + priv->mwdma = id[ATA_ID_MWDMA_MODES]; + priv->udma = id[ATA_ID_UDMA_MODES]; + debug("pio %04x, mwdma %04x, udma %04x\n", priv->pio, priv->mwdma, + priv->udma); +} + +static void mv_sata_set_features(int port) +{ + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + struct sata_fis_h2d cfis; + u8 udma_cap; + + memset(&cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis.command = ATA_CMD_SET_FEATURES; + cfis.features = SETFEATURES_XFER; + + /* First check the device capablity */ + udma_cap = (u8) (priv->udma & 0xff); + + if (udma_cap == ATA_UDMA6) + cfis.sector_count = XFER_UDMA_6; + if (udma_cap == ATA_UDMA5) + cfis.sector_count = XFER_UDMA_5; + if (udma_cap == ATA_UDMA4) + cfis.sector_count = XFER_UDMA_4; + if (udma_cap == ATA_UDMA3) + cfis.sector_count = XFER_UDMA_3; + + mv_ata_exec_ata_cmd_nondma(port, &cfis, NULL, 0, READ_CMD); +} + +int mv_sata_spin_down(int dev) +{ + struct sata_fis_h2d cfis; + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[dev].priv; + + if (priv->link == 0) { + debug("No device on port: %d\n", dev); + return 1; + } + + memset(&cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis.command = ATA_CMD_STANDBY; + + return mv_ata_exec_ata_cmd_nondma(dev, &cfis, NULL, 0, READ_CMD); +} + +int mv_sata_spin_up(int dev) +{ + struct sata_fis_h2d cfis; + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[dev].priv; + + if (priv->link == 0) { + debug("No device on port: %d\n", dev); + return 1; + } + + memset(&cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis.command = ATA_CMD_IDLE; + + return mv_ata_exec_ata_cmd_nondma(dev, &cfis, NULL, 0, READ_CMD); +} + +ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) +{ + return ata_low_level_rw(dev, blknr, blkcnt, buffer, READ_CMD); +} + +ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) +{ + return ata_low_level_rw(dev, blknr, blkcnt, (void *)buffer, WRITE_CMD); +} + +/* + * Initialize SATA memory windows + */ +static void mvsata_ide_conf_mbus_windows(void) +{ + const struct mbus_dram_target_info *dram; + int i; + + dram = mvebu_mbus_dram_info(); + + /* Disable windows, Set Size/Base to 0 */ + for (i = 0; i < 4; i++) { + writel(0, MVSATA_WIN_CONTROL(i)); + writel(0, MVSATA_WIN_BASE(i)); + } + + for (i = 0; i < dram->num_cs; i++) { + const struct mbus_dram_window *cs = dram->cs + i; + writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) | + (dram->mbus_dram_target_id << 4) | 1, + MVSATA_WIN_CONTROL(i)); + writel(cs->base & 0xffff0000, MVSATA_WIN_BASE(i)); + } +} + +int init_sata(int dev) +{ + struct mv_priv *priv; + + debug("Initialize sata dev: %d\n", dev); + + if (dev < 0 || dev >= CONFIG_SYS_SATA_MAX_DEVICE) { + printf("Invalid sata device %d\n", dev); + return -1; + } + + priv = (struct mv_priv *)malloc(sizeof(struct mv_priv)); + if (!priv) { + printf("Failed to allocate memory for private sata data\n"); + return -ENOMEM; + } + + memset((void *)priv, 0, sizeof(struct mv_priv)); + + /* Allocate and align request buffer */ + priv->crqb_alloc = malloc(sizeof(struct crqb) * REQUEST_QUEUE_SIZE + + CRQB_ALIGN); + if (!priv->crqb_alloc) { + printf("Unable to allocate memory for request queue\n"); + return -ENOMEM; + } + memset(priv->crqb_alloc, 0, + sizeof(struct crqb) * REQUEST_QUEUE_SIZE + CRQB_ALIGN); + priv->request = (struct crqb *)(((u32) priv->crqb_alloc + CRQB_ALIGN) & + ~(CRQB_ALIGN - 1)); + + /* Allocate and align response buffer */ + priv->crpb_alloc = malloc(sizeof(struct crpb) * REQUEST_QUEUE_SIZE + + CRPB_ALIGN); + if (!priv->crpb_alloc) { + printf("Unable to allocate memory for response queue\n"); + return -ENOMEM; + } + memset(priv->crpb_alloc, 0, + sizeof(struct crpb) * REQUEST_QUEUE_SIZE + CRPB_ALIGN); + priv->response = (struct crpb *)(((u32) priv->crpb_alloc + CRPB_ALIGN) & + ~(CRPB_ALIGN - 1)); + + sata_dev_desc[dev].priv = (void *)priv; + + sprintf(priv->name, "SATA%d", dev); + + priv->regbase = dev == 0 ? SATA0_BASE : SATA1_BASE; + + if (!hw_init) { + debug("Initialize sata hw\n"); + hw_init = 1; + mv_reset_one_hc(); + mvsata_ide_conf_mbus_windows(); + } + + mv_reset_port(dev); + + if (probe_port(dev)) { + priv->link = 0; + return -ENODEV; + } + priv->link = 1; + + return 0; +} + +int reset_sata(int dev) +{ + return 0; +} + +int scan_sata(int port) +{ + 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; + u16 *id; + struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; + + if (!priv->link) + return -ENODEV; + + id = (u16 *)malloc(ATA_ID_WORDS * 2); + if (!id) { + printf("Failed to malloc id data\n"); + return -ENOMEM; + } + + mv_sata_identify(port, id); + ata_swap_buf_le16(id, ATA_ID_WORDS); +#ifdef DEBUG + ata_dump_id(id); +#endif + + /* Serial number */ + ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); + memcpy(sata_dev_desc[port].product, serial, sizeof(serial)); + + /* Firmware version */ + ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); + memcpy(sata_dev_desc[port].revision, firmware, sizeof(firmware)); + + /* Product model */ + ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); + memcpy(sata_dev_desc[port].vendor, product, sizeof(product)); + + /* Total sectors */ + n_sectors = ata_id_n_sectors(id); + sata_dev_desc[port].lba = n_sectors; + + /* Check if support LBA48 */ + if (ata_id_has_lba48(id)) { + sata_dev_desc[port].lba48 = 1; + debug("Device support LBA48\n"); + } + + /* Get the NCQ queue depth from device */ + priv->queue_depth = ata_id_queue_depth(id); + + /* Get the xfer mode from device */ + mv_sata_xfer_mode(port, id); + + /* Set the xfer mode to highest speed */ + mv_sata_set_features(port); + + /* Start up */ + mv_start_edma_engine(port); + + return 0; +} diff --git a/drivers/ata/sata_sandbox.c b/drivers/ata/sata_sandbox.c new file mode 100644 index 0000000000..bd967d290c --- /dev/null +++ b/drivers/ata/sata_sandbox.c @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 Google, Inc + * Written by Simon Glass + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +int init_sata(int dev) +{ + return 0; +} + +int reset_sata(int dev) +{ + return 0; +} + +int scan_sata(int dev) +{ + return 0; +} + +ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) +{ + return 0; +} + +ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) +{ + return 0; +} diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c new file mode 100644 index 0000000000..daff7d4ab5 --- /dev/null +++ b/drivers/ata/sata_sil.c @@ -0,0 +1,715 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. + * Author: Tang Yuantian + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sata_sil.h" + +/* Convert sectorsize to wordsize */ +#define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2) +#define virt_to_bus(devno, v) pci_virt_to_mem(devno, (void *) (v)) + +static struct sata_info sata_info; + +static struct pci_device_id supported[] = { + {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3131}, + {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3132}, + {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3124}, + {} +}; + +static void sil_sata_dump_fis(struct sata_fis_d2h *s) +{ + printf("Status FIS dump:\n"); + printf("fis_type: %02x\n", s->fis_type); + printf("pm_port_i: %02x\n", s->pm_port_i); + printf("status: %02x\n", s->status); + printf("error: %02x\n", s->error); + printf("lba_low: %02x\n", s->lba_low); + printf("lba_mid: %02x\n", s->lba_mid); + printf("lba_high: %02x\n", s->lba_high); + printf("device: %02x\n", s->device); + printf("lba_low_exp: %02x\n", s->lba_low_exp); + printf("lba_mid_exp: %02x\n", s->lba_mid_exp); + printf("lba_high_exp: %02x\n", s->lba_high_exp); + printf("res1: %02x\n", s->res1); + printf("sector_count: %02x\n", s->sector_count); + printf("sector_count_exp: %02x\n", s->sector_count_exp); +} + +static const char *sata_spd_string(unsigned int speed) +{ + static const char * const spd_str[] = { + "1.5 Gbps", + "3.0 Gbps", + "6.0 Gbps", + }; + + if ((speed - 1) > 2) + return ""; + + return spd_str[speed - 1]; +} + +static u32 ata_wait_register(void *reg, u32 mask, + u32 val, int timeout_msec) +{ + u32 tmp; + + tmp = readl(reg); + while ((tmp & mask) == val && timeout_msec > 0) { + mdelay(1); + timeout_msec--; + tmp = readl(reg); + } + + return tmp; +} + +static void sil_config_port(void *port) +{ + /* configure IRQ WoC */ + writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); + + /* zero error counters. */ + writew(0x8000, port + PORT_DECODE_ERR_THRESH); + writew(0x8000, port + PORT_CRC_ERR_THRESH); + writew(0x8000, port + PORT_HSHK_ERR_THRESH); + writew(0x0000, port + PORT_DECODE_ERR_CNT); + writew(0x0000, port + PORT_CRC_ERR_CNT); + writew(0x0000, port + PORT_HSHK_ERR_CNT); + + /* always use 64bit activation */ + writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); + + /* clear port multiplier enable and resume bits */ + writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR); +} + +static int sil_init_port(void *port) +{ + u32 tmp; + + writel(PORT_CS_INIT, port + PORT_CTRL_STAT); + ata_wait_register(port + PORT_CTRL_STAT, + PORT_CS_INIT, PORT_CS_INIT, 100); + tmp = ata_wait_register(port + PORT_CTRL_STAT, + PORT_CS_RDY, 0, 100); + + if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) + return 1; + + return 0; +} + +static void sil_read_fis(int dev, int tag, struct sata_fis_d2h *fis) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + void *port = sata->port; + struct sil_prb *prb; + int i; + u32 *src, *dst; + + prb = port + PORT_LRAM + tag * PORT_LRAM_SLOT_SZ; + src = (u32 *)&prb->fis; + dst = (u32 *)fis; + for (i = 0; i < sizeof(struct sata_fis_h2d); i += 4) + *dst++ = readl(src++); +} + +static int sil_exec_cmd(int dev, struct sil_cmd_block *pcmd, int tag) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + void *port = sata->port; + u64 paddr = virt_to_bus(sata->devno, pcmd); + u32 irq_mask, irq_stat; + int rc; + + writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR); + + /* better to add momery barrior here */ + writel((u32)paddr, port + PORT_CMD_ACTIVATE + tag * 8); + writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + tag * 8 + 4); + + irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT; + irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, + 0, 10000); + + /* clear IRQs */ + writel(irq_mask, port + PORT_IRQ_STAT); + irq_stat >>= PORT_IRQ_RAW_SHIFT; + + if (irq_stat & PORT_IRQ_COMPLETE) + rc = 0; + else { + /* force port into known state */ + sil_init_port(port); + if (irq_stat & PORT_IRQ_ERROR) + rc = 1; /* error */ + else + rc = 2; /* busy */ + } + + return rc; +} + +static int sil_cmd_set_feature(int dev) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + struct sil_cmd_block cmdb, *pcmd = &cmdb; + struct sata_fis_d2h fis; + u8 udma_cap; + int ret; + + memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block)); + pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + pcmd->prb.fis.pm_port_c = (1 << 7); + pcmd->prb.fis.command = ATA_CMD_SET_FEATURES; + pcmd->prb.fis.features = SETFEATURES_XFER; + + /* First check the device capablity */ + udma_cap = (u8)(sata->udma & 0xff); + debug("udma_cap %02x\n", udma_cap); + + if (udma_cap == ATA_UDMA6) + pcmd->prb.fis.sector_count = XFER_UDMA_6; + if (udma_cap == ATA_UDMA5) + pcmd->prb.fis.sector_count = XFER_UDMA_5; + if (udma_cap == ATA_UDMA4) + pcmd->prb.fis.sector_count = XFER_UDMA_4; + if (udma_cap == ATA_UDMA3) + pcmd->prb.fis.sector_count = XFER_UDMA_3; + + ret = sil_exec_cmd(dev, pcmd, 0); + if (ret) { + sil_read_fis(dev, 0, &fis); + printf("Err: exe cmd(0x%x).\n", + readl(sata->port + PORT_SERROR)); + sil_sata_dump_fis(&fis); + return 1; + } + + return 0; +} + +static int sil_cmd_identify_device(int dev, u16 *id) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + struct sil_cmd_block cmdb, *pcmd = &cmdb; + struct sata_fis_d2h fis; + int ret; + + memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block)); + pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL); + pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ); + pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + pcmd->prb.fis.pm_port_c = (1 << 7); + pcmd->prb.fis.command = ATA_CMD_ID_ATA; + pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, id)); + pcmd->sge.cnt = cpu_to_le32(sizeof(id[0]) * ATA_ID_WORDS); + pcmd->sge.flags = cpu_to_le32(SGE_TRM); + + ret = sil_exec_cmd(dev, pcmd, 0); + if (ret) { + sil_read_fis(dev, 0, &fis); + printf("Err: id cmd(0x%x).\n", readl(sata->port + PORT_SERROR)); + sil_sata_dump_fis(&fis); + return 1; + } + ata_swap_buf_le16(id, ATA_ID_WORDS); + + return 0; +} + +static int sil_cmd_soft_reset(int dev) +{ + struct sil_cmd_block cmdb, *pcmd = &cmdb; + struct sil_sata *sata = sata_dev_desc[dev].priv; + struct sata_fis_d2h fis; + void *port = sata->port; + int ret; + + /* put the port into known state */ + if (sil_init_port(port)) { + printf("SRST: port %d not ready\n", dev); + return 1; + } + + memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block)); + + pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_SRST); + pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + pcmd->prb.fis.pm_port_c = 0xf; + + ret = sil_exec_cmd(dev, &cmdb, 0); + if (ret) { + sil_read_fis(dev, 0, &fis); + printf("SRST cmd error.\n"); + sil_sata_dump_fis(&fis); + return 1; + } + + return 0; +} + +static ulong sil_sata_rw_cmd(int dev, ulong start, ulong blkcnt, + u8 *buffer, int is_write) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + struct sil_cmd_block cmdb, *pcmd = &cmdb; + struct sata_fis_d2h fis; + u64 block; + int ret; + + block = (u64)start; + memset(pcmd, 0, sizeof(struct sil_cmd_block)); + pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL); + pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + pcmd->prb.fis.pm_port_c = (1 << 7); + if (is_write) { + pcmd->prb.fis.command = ATA_CMD_WRITE; + pcmd->prb.prot = cpu_to_le16(PRB_PROT_WRITE); + } else { + pcmd->prb.fis.command = ATA_CMD_READ; + pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ); + } + + pcmd->prb.fis.device = ATA_LBA; + pcmd->prb.fis.device |= (block >> 24) & 0xf; + pcmd->prb.fis.lba_high = (block >> 16) & 0xff; + pcmd->prb.fis.lba_mid = (block >> 8) & 0xff; + pcmd->prb.fis.lba_low = block & 0xff; + pcmd->prb.fis.sector_count = (u8)blkcnt & 0xff; + + pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, buffer)); + pcmd->sge.cnt = cpu_to_le32(blkcnt * ATA_SECT_SIZE); + pcmd->sge.flags = cpu_to_le32(SGE_TRM); + + ret = sil_exec_cmd(dev, pcmd, 0); + if (ret) { + sil_read_fis(dev, 0, &fis); + printf("Err: rw cmd(0x%08x).\n", + readl(sata->port + PORT_SERROR)); + sil_sata_dump_fis(&fis); + return 1; + } + + return blkcnt; +} + +static ulong sil_sata_rw_cmd_ext(int dev, ulong start, ulong blkcnt, + u8 *buffer, int is_write) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + struct sil_cmd_block cmdb, *pcmd = &cmdb; + struct sata_fis_d2h fis; + u64 block; + int ret; + + block = (u64)start; + memset(pcmd, 0, sizeof(struct sil_cmd_block)); + pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL); + pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + pcmd->prb.fis.pm_port_c = (1 << 7); + if (is_write) { + pcmd->prb.fis.command = ATA_CMD_WRITE_EXT; + pcmd->prb.prot = cpu_to_le16(PRB_PROT_WRITE); + } else { + pcmd->prb.fis.command = ATA_CMD_READ_EXT; + pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ); + } + + pcmd->prb.fis.lba_high_exp = (block >> 40) & 0xff; + pcmd->prb.fis.lba_mid_exp = (block >> 32) & 0xff; + pcmd->prb.fis.lba_low_exp = (block >> 24) & 0xff; + pcmd->prb.fis.lba_high = (block >> 16) & 0xff; + pcmd->prb.fis.lba_mid = (block >> 8) & 0xff; + pcmd->prb.fis.lba_low = block & 0xff; + pcmd->prb.fis.device = ATA_LBA; + pcmd->prb.fis.sector_count_exp = (blkcnt >> 8) & 0xff; + pcmd->prb.fis.sector_count = blkcnt & 0xff; + + pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, buffer)); + pcmd->sge.cnt = cpu_to_le32(blkcnt * ATA_SECT_SIZE); + pcmd->sge.flags = cpu_to_le32(SGE_TRM); + + ret = sil_exec_cmd(dev, pcmd, 0); + if (ret) { + sil_read_fis(dev, 0, &fis); + printf("Err: rw ext cmd(0x%08x).\n", + readl(sata->port + PORT_SERROR)); + sil_sata_dump_fis(&fis); + return 1; + } + + return blkcnt; +} + +static ulong sil_sata_rw_lba28(int dev, ulong blknr, lbaint_t blkcnt, + const void *buffer, int is_write) +{ + ulong start, blks, max_blks; + u8 *addr; + + start = blknr; + blks = blkcnt; + addr = (u8 *)buffer; + + max_blks = ATA_MAX_SECTORS; + do { + if (blks > max_blks) { + sil_sata_rw_cmd(dev, start, max_blks, addr, is_write); + start += max_blks; + blks -= max_blks; + addr += ATA_SECT_SIZE * max_blks; + } else { + sil_sata_rw_cmd(dev, start, blks, addr, is_write); + start += blks; + blks = 0; + addr += ATA_SECT_SIZE * blks; + } + } while (blks != 0); + + return blkcnt; +} + +static ulong sil_sata_rw_lba48(int dev, ulong blknr, lbaint_t blkcnt, + const void *buffer, int is_write) +{ + ulong start, blks, max_blks; + u8 *addr; + + start = blknr; + blks = blkcnt; + addr = (u8 *)buffer; + + max_blks = ATA_MAX_SECTORS_LBA48; + do { + if (blks > max_blks) { + sil_sata_rw_cmd_ext(dev, start, max_blks, + addr, is_write); + start += max_blks; + blks -= max_blks; + addr += ATA_SECT_SIZE * max_blks; + } else { + sil_sata_rw_cmd_ext(dev, start, blks, + addr, is_write); + start += blks; + blks = 0; + addr += ATA_SECT_SIZE * blks; + } + } while (blks != 0); + + return blkcnt; +} + +static void sil_sata_cmd_flush_cache(int dev) +{ + struct sil_cmd_block cmdb, *pcmd = &cmdb; + + memset((void *)pcmd, 0, sizeof(struct sil_cmd_block)); + pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + pcmd->prb.fis.pm_port_c = (1 << 7); + pcmd->prb.fis.command = ATA_CMD_FLUSH; + + sil_exec_cmd(dev, pcmd, 0); +} + +static void sil_sata_cmd_flush_cache_ext(int dev) +{ + struct sil_cmd_block cmdb, *pcmd = &cmdb; + + memset((void *)pcmd, 0, sizeof(struct sil_cmd_block)); + pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; + pcmd->prb.fis.pm_port_c = (1 << 7); + pcmd->prb.fis.command = ATA_CMD_FLUSH_EXT; + + sil_exec_cmd(dev, pcmd, 0); +} + +static void sil_sata_init_wcache(int dev, u16 *id) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + + if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id)) + sata->wcache = 1; + if (ata_id_has_flush(id)) + sata->flush = 1; + if (ata_id_has_flush_ext(id)) + sata->flush_ext = 1; +} + +static int sil_sata_get_wcache(int dev) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + + return sata->wcache; +} + +static int sil_sata_get_flush(int dev) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + + return sata->flush; +} + +static int sil_sata_get_flush_ext(int dev) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + + return sata->flush_ext; +} + +/* + * SATA interface between low level driver and command layer + */ +ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + ulong rc; + + if (sata->lba48) + rc = sil_sata_rw_lba48(dev, blknr, blkcnt, buffer, READ_CMD); + else + rc = sil_sata_rw_lba28(dev, blknr, blkcnt, buffer, READ_CMD); + + return rc; +} + +/* + * SATA interface between low level driver and command layer + */ +ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) +{ + struct sil_sata *sata = sata_dev_desc[dev].priv; + ulong rc; + + if (sata->lba48) { + rc = sil_sata_rw_lba48(dev, blknr, blkcnt, buffer, WRITE_CMD); + if (sil_sata_get_wcache(dev) && sil_sata_get_flush_ext(dev)) + sil_sata_cmd_flush_cache_ext(dev); + } else { + rc = sil_sata_rw_lba28(dev, blknr, blkcnt, buffer, WRITE_CMD); + if (sil_sata_get_wcache(dev) && sil_sata_get_flush(dev)) + sil_sata_cmd_flush_cache(dev); + } + + return rc; +} + +/* + * SATA interface between low level driver and command layer + */ +int init_sata(int dev) +{ + static int init_done, idx; + pci_dev_t devno; + u16 word; + + if (init_done == 1 && dev < sata_info.maxport) + return 0; + + init_done = 1; + + /* Find PCI device(s) */ + devno = pci_find_devices(supported, idx++); + if (devno == -1) + return 1; + + pci_read_config_word(devno, PCI_DEVICE_ID, &word); + + /* get the port count */ + word &= 0xf; + + sata_info.portbase = sata_info.maxport; + sata_info.maxport = sata_info.portbase + word; + sata_info.devno = devno; + + /* Read out all BARs */ + sata_info.iobase[0] = (ulong)pci_map_bar(devno, + PCI_BASE_ADDRESS_0, PCI_REGION_MEM); + sata_info.iobase[1] = (ulong)pci_map_bar(devno, + PCI_BASE_ADDRESS_2, PCI_REGION_MEM); + sata_info.iobase[2] = (ulong)pci_map_bar(devno, + PCI_BASE_ADDRESS_4, PCI_REGION_MEM); + + /* mask out the unused bits */ + sata_info.iobase[0] &= 0xffffff80; + sata_info.iobase[1] &= 0xfffffc00; + sata_info.iobase[2] &= 0xffffff80; + + /* Enable Bus Mastering and memory region */ + pci_write_config_word(devno, PCI_COMMAND, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + + /* Check if mem accesses and Bus Mastering are enabled. */ + pci_read_config_word(devno, PCI_COMMAND, &word); + if (!(word & PCI_COMMAND_MEMORY) || + (!(word & PCI_COMMAND_MASTER))) { + printf("Error: Can not enable MEM access or Bus Mastering.\n"); + debug("PCI command: %04x\n", word); + return 1; + } + + /* GPIO off */ + writel(0, (void *)(sata_info.iobase[0] + HOST_FLASH_CMD)); + /* clear global reset & mask interrupts during initialization */ + writel(0, (void *)(sata_info.iobase[0] + HOST_CTRL)); + + return 0; +} + +int reset_sata(int dev) +{ + return 0; +} + +/* + * SATA interface between low level driver and command layer + */ +int scan_sata(int dev) +{ + 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]; + struct sil_sata *sata; + void *port; + int cnt; + u16 *id; + u32 tmp; + + if (dev >= sata_info.maxport) { + printf("SATA#%d is not present\n", dev); + return 1; + } + + printf("SATA#%d\n", dev); + port = (void *)sata_info.iobase[1] + + PORT_REGS_SIZE * (dev - sata_info.portbase); + + /* Initial PHY setting */ + writel(0x20c, port + PORT_PHY_CFG); + + /* clear port RST */ + tmp = readl(port + PORT_CTRL_STAT); + if (tmp & PORT_CS_PORT_RST) { + writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); + tmp = ata_wait_register(port + PORT_CTRL_STAT, + PORT_CS_PORT_RST, PORT_CS_PORT_RST, 100); + if (tmp & PORT_CS_PORT_RST) + printf("Err: Failed to clear port RST\n"); + } + + /* Check if device is present */ + for (cnt = 0; cnt < 100; cnt++) { + tmp = readl(port + PORT_SSTATUS); + if ((tmp & 0xF) == 0x3) + break; + mdelay(1); + } + + tmp = readl(port + PORT_SSTATUS); + if ((tmp & 0xf) != 0x3) { + printf(" (No RDY)\n"); + return 1; + } + + /* Wait for port ready */ + tmp = ata_wait_register(port + PORT_CTRL_STAT, + PORT_CS_RDY, PORT_CS_RDY, 100); + if ((tmp & PORT_CS_RDY) != PORT_CS_RDY) { + printf("%d port not ready.\n", dev); + return 1; + } + + /* configure port */ + sil_config_port(port); + + /* Reset port */ + writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); + readl(port + PORT_CTRL_STAT); + tmp = ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_DEV_RST, + PORT_CS_DEV_RST, 100); + if (tmp & PORT_CS_DEV_RST) { + printf("%d port reset failed.\n", dev); + return 1; + } + + sata = (struct sil_sata *)malloc(sizeof(struct sil_sata)); + if (!sata) { + printf("%d no memory.\n", dev); + return 1; + } + memset((void *)sata, 0, sizeof(struct sil_sata)); + + /* turn on port interrupt */ + tmp = readl((void *)(sata_info.iobase[0] + HOST_CTRL)); + tmp |= (1 << (dev - sata_info.portbase)); + writel(tmp, (void *)(sata_info.iobase[0] + HOST_CTRL)); + + /* Save the private struct to block device struct */ + sata_dev_desc[dev].priv = (void *)sata; + sata->port = port; + sata->devno = sata_info.devno; + sprintf(sata->name, "SATA#%d", dev); + sil_cmd_soft_reset(dev); + tmp = readl(port + PORT_SSTATUS); + tmp = (tmp >> 4) & 0xf; + printf(" (%s)\n", sata_spd_string(tmp)); + + id = (u16 *)malloc(ATA_ID_WORDS * 2); + if (!id) { + printf("Id malloc failed\n"); + free((void *)sata); + return 1; + } + sil_cmd_identify_device(dev, id); + +#ifdef CONFIG_LBA48 + /* Check if support LBA48 */ + if (ata_id_has_lba48(id)) { + sata_dev_desc[dev].lba48 = 1; + sata->lba48 = 1; + debug("Device supports LBA48\n"); + } else + debug("Device supports LBA28\n"); +#endif + + /* Serial number */ + ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); + memcpy(sata_dev_desc[dev].product, serial, sizeof(serial)); + + /* Firmware version */ + ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); + memcpy(sata_dev_desc[dev].revision, firmware, sizeof(firmware)); + + /* Product model */ + ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); + memcpy(sata_dev_desc[dev].vendor, product, sizeof(product)); + + /* Totoal sectors */ + sata_dev_desc[dev].lba = ata_id_n_sectors(id); + + sil_sata_init_wcache(dev, id); + sil_cmd_set_feature(dev); + +#ifdef DEBUG + sil_cmd_identify_device(dev, id); + ata_dump_id(id); +#endif + free((void *)id); + + return 0; +} diff --git a/drivers/ata/sata_sil.h b/drivers/ata/sata_sil.h new file mode 100644 index 0000000000..55954efdd6 --- /dev/null +++ b/drivers/ata/sata_sil.h @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. + * Author: Tang Yuantian + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef SATA_SIL3132_H +#define SATA_SIL3132_H + +#define READ_CMD 0 +#define WRITE_CMD 1 + +/* + * SATA device driver struct for each dev + */ +struct sil_sata { + char name[12]; + void *port; /* the port base address */ + int lba48; + u16 pio; + u16 mwdma; + u16 udma; + pci_dev_t devno; + int wcache; + int flush; + int flush_ext; +}; + +/* sata info for each controller */ +struct sata_info { + ulong iobase[3]; + pci_dev_t devno; + int portbase; + int maxport; +}; + +/* + * Scatter gather entry (SGE),MUST 8 bytes aligned + */ +struct sil_sge { + __le64 addr; + __le32 cnt; + __le32 flags; +} __attribute__ ((aligned(8), packed)); + +/* + * Port request block, MUST 8 bytes aligned + */ +struct sil_prb { + __le16 ctrl; + __le16 prot; + __le32 rx_cnt; + struct sata_fis_h2d fis; +} __attribute__ ((aligned(8), packed)); + +struct sil_cmd_block { + struct sil_prb prb; + struct sil_sge sge; +}; + +enum { + HOST_SLOT_STAT = 0x00, /* 32 bit slot stat * 4 */ + HOST_CTRL = 0x40, + HOST_IRQ_STAT = 0x44, + HOST_PHY_CFG = 0x48, + HOST_BIST_CTRL = 0x50, + HOST_BIST_PTRN = 0x54, + HOST_BIST_STAT = 0x58, + HOST_MEM_BIST_STAT = 0x5c, + HOST_FLASH_CMD = 0x70, + /* 8 bit regs */ + HOST_FLASH_DATA = 0x74, + HOST_TRANSITION_DETECT = 0x75, + HOST_GPIO_CTRL = 0x76, + HOST_I2C_ADDR = 0x78, /* 32 bit */ + HOST_I2C_DATA = 0x7c, + HOST_I2C_XFER_CNT = 0x7e, + HOST_I2C_CTRL = 0x7f, + + /* HOST_SLOT_STAT bits */ + HOST_SSTAT_ATTN = (1 << 31), + + /* HOST_CTRL bits */ + HOST_CTRL_M66EN = (1 << 16), /* M66EN PCI bus signal */ + HOST_CTRL_TRDY = (1 << 17), /* latched PCI TRDY */ + HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */ + HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */ + HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */ + HOST_CTRL_GLOBAL_RST = (1 << 31), /* global reset */ + + /* + * Port registers + * (8192 bytes @ +0x0000, +0x2000, +0x4000 and +0x6000 @ BAR2) + */ + PORT_REGS_SIZE = 0x2000, + + PORT_LRAM = 0x0000, /* 31 LRAM slots and PMP regs */ + PORT_LRAM_SLOT_SZ = 0x0080, /* 32 bytes PRB + 2 SGE, ACT... */ + + PORT_PMP = 0x0f80, /* 8 bytes PMP * 16 (128 bytes) */ + PORT_PMP_STATUS = 0x0000, /* port device status offset */ + PORT_PMP_QACTIVE = 0x0004, /* port device QActive offset */ + PORT_PMP_SIZE = 0x0008, /* 8 bytes per PMP */ + + /* 32 bit regs */ + PORT_CTRL_STAT = 0x1000, /* write: ctrl-set, read: stat */ + PORT_CTRL_CLR = 0x1004, /* write: ctrl-clear */ + PORT_IRQ_STAT = 0x1008, /* high: status, low: interrupt */ + PORT_IRQ_ENABLE_SET = 0x1010, /* write: enable-set */ + PORT_IRQ_ENABLE_CLR = 0x1014, /* write: enable-clear */ + PORT_ACTIVATE_UPPER_ADDR = 0x101c, + PORT_EXEC_FIFO = 0x1020, /* command execution fifo */ + PORT_CMD_ERR = 0x1024, /* command error number */ + PORT_FIS_CFG = 0x1028, + PORT_FIFO_THRES = 0x102c, + + /* 16 bit regs */ + PORT_DECODE_ERR_CNT = 0x1040, + PORT_DECODE_ERR_THRESH = 0x1042, + PORT_CRC_ERR_CNT = 0x1044, + PORT_CRC_ERR_THRESH = 0x1046, + PORT_HSHK_ERR_CNT = 0x1048, + PORT_HSHK_ERR_THRESH = 0x104a, + + /* 32 bit regs */ + PORT_PHY_CFG = 0x1050, + PORT_SLOT_STAT = 0x1800, + PORT_CMD_ACTIVATE = 0x1c00, /* 64 bit cmd activate * 31 */ + PORT_CONTEXT = 0x1e04, + PORT_EXEC_DIAG = 0x1e00, /* 32bit exec diag * 16 */ + PORT_PSD_DIAG = 0x1e40, /* 32bit psd diag * 16 */ + PORT_SCONTROL = 0x1f00, + PORT_SSTATUS = 0x1f04, + PORT_SERROR = 0x1f08, + PORT_SACTIVE = 0x1f0c, + + /* PORT_CTRL_STAT bits */ + PORT_CS_PORT_RST = (1 << 0), /* port reset */ + PORT_CS_DEV_RST = (1 << 1), /* device reset */ + PORT_CS_INIT = (1 << 2), /* port initialize */ + PORT_CS_IRQ_WOC = (1 << 3), /* interrupt write one to clear */ + PORT_CS_CDB16 = (1 << 5), /* 0=12b cdb, 1=16b cdb */ + PORT_CS_PMP_RESUME = (1 << 6), /* PMP resume */ + PORT_CS_32BIT_ACTV = (1 << 10), /* 32-bit activation */ + PORT_CS_PMP_EN = (1 << 13), /* port multiplier enable */ + PORT_CS_RDY = (1 << 31), /* port ready to accept commands */ + + /* PORT_IRQ_STAT/ENABLE_SET/CLR */ + /* bits[11:0] are masked */ + PORT_IRQ_COMPLETE = (1 << 0), /* command(s) completed */ + PORT_IRQ_ERROR = (1 << 1), /* command execution error */ + PORT_IRQ_PORTRDY_CHG = (1 << 2), /* port ready change */ + PORT_IRQ_PWR_CHG = (1 << 3), /* power management change */ + PORT_IRQ_PHYRDY_CHG = (1 << 4), /* PHY ready change */ + PORT_IRQ_COMWAKE = (1 << 5), /* COMWAKE received */ + PORT_IRQ_UNK_FIS = (1 << 6), /* unknown FIS received */ + PORT_IRQ_DEV_XCHG = (1 << 7), /* device exchanged */ + PORT_IRQ_8B10B = (1 << 8), /* 8b/10b decode error threshold */ + PORT_IRQ_CRC = (1 << 9), /* CRC error threshold */ + PORT_IRQ_HANDSHAKE = (1 << 10), /* handshake error threshold */ + PORT_IRQ_SDB_NOTIFY = (1 << 11), /* SDB notify received */ + + DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR | + PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG | + PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_NOTIFY, + + /* bits[27:16] are unmasked (raw) */ + PORT_IRQ_RAW_SHIFT = 16, + PORT_IRQ_MASKED_MASK = 0x7ff, + PORT_IRQ_RAW_MASK = (0x7ff << PORT_IRQ_RAW_SHIFT), + + /* ENABLE_SET/CLR specific, intr steering - 2 bit field */ + PORT_IRQ_STEER_SHIFT = 30, + PORT_IRQ_STEER_MASK = (3 << PORT_IRQ_STEER_SHIFT), + + /* PORT_CMD_ERR constants */ + PORT_CERR_DEV = 1, /* Error bit in D2H Register FIS */ + PORT_CERR_SDB = 2, /* Error bit in SDB FIS */ + PORT_CERR_DATA = 3, /* Error in data FIS not detected by dev */ + PORT_CERR_SEND = 4, /* Initial cmd FIS transmission failure */ + PORT_CERR_INCONSISTENT = 5, /* Protocol mismatch */ + PORT_CERR_DIRECTION = 6, /* Data direction mismatch */ + PORT_CERR_UNDERRUN = 7, /* Ran out of SGEs while writing */ + PORT_CERR_OVERRUN = 8, /* Ran out of SGEs while reading */ + + /* bits of PRB control field */ + PRB_CTRL_PROTOCOL = (1 << 0), /* override def. ATA protocol */ + PRB_CTRL_PACKET_READ = (1 << 4), /* PACKET cmd read */ + PRB_CTRL_PACKET_WRITE = (1 << 5), /* PACKET cmd write */ + PRB_CTRL_NIEN = (1 << 6), /* Mask completion irq */ + PRB_CTRL_SRST = (1 << 7), /* Soft reset request (ign BSY?) */ + + /* PRB protocol field */ + PRB_PROT_PACKET = (1 << 0), + PRB_PROT_TCQ = (1 << 1), + PRB_PROT_NCQ = (1 << 2), + PRB_PROT_READ = (1 << 3), + PRB_PROT_WRITE = (1 << 4), + PRB_PROT_TRANSPARENT = (1 << 5), + + /* + * Other constants + */ + SGE_TRM = (1 << 31), /* Last SGE in chain */ + SGE_LNK = (1 << 30), /* linked list + Points to SGT, not SGE */ + SGE_DRD = (1 << 29), /* discard data read (/dev/null) + data address ignored */ + + CMD_ERR = 0x21, +}; + +#endif diff --git a/drivers/ata/sata_sil3114.c b/drivers/ata/sata_sil3114.c new file mode 100644 index 0000000000..61ffb66a77 --- /dev/null +++ b/drivers/ata/sata_sil3114.c @@ -0,0 +1,835 @@ +/* + * Copyright (C) Excito Elektronik i Skåne AB, All rights reserved. + * Author: Tor Krill + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This is a driver for Silicon Image sil3114 sata chip modelled on + * the ata_piix driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sata_sil3114.h" + +/* Convert sectorsize to wordsize */ +#define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2) + +/* Forwards */ +u8 sil3114_spin_up (int num); +u8 sil3114_spin_down (int num); +static int sata_bus_softreset (int num); +static void sata_identify (int num, int dev); +static u8 check_power_mode (int num); +static void sata_port (struct sata_ioports *ioport); +static void set_Feature_cmd (int num, int dev); +static u8 sata_busy_wait (struct sata_ioports *ioaddr, int bits, + unsigned int max, u8 usealtstatus); +static u8 sata_chk_status (struct sata_ioports *ioaddr, u8 usealtstatus); +static void msleep (int count); + +static u32 iobase[6] = { 0, 0, 0, 0, 0, 0}; /* PCI BAR registers for device */ + +static struct sata_port port[CONFIG_SYS_SATA_MAX_DEVICE]; + +static void output_data (struct sata_ioports *ioaddr, u16 * sect_buf, int words) +{ + while (words--) { + __raw_writew (*sect_buf++, (void *)ioaddr->data_addr); + } +} + +static int input_data (struct sata_ioports *ioaddr, u16 * sect_buf, int words) +{ + while (words--) { + *sect_buf++ = __raw_readw ((void *)ioaddr->data_addr); + } + return 0; +} + +static int sata_bus_softreset (int num) +{ + u8 status = 0; + + port[num].dev_mask = 1; + + port[num].ctl_reg = 0x08; /*Default value of control reg */ + writeb (port[num].ctl_reg, port[num].ioaddr.ctl_addr); + udelay (10); + writeb (port[num].ctl_reg | ATA_SRST, port[num].ioaddr.ctl_addr); + udelay (10); + writeb (port[num].ctl_reg, port[num].ioaddr.ctl_addr); + + /* spec mandates ">= 2ms" before checking status. + * We wait 150ms, because that was the magic delay used for + * ATAPI devices in Hale Landis's ATADRVR, for the period of time + * between when the ATA command register is written, and then + * status is checked. Because waiting for "a while" before + * checking status is fine, post SRST, we perform this magic + * delay here as well. + */ + msleep (150); + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 300, 0); + while ((status & ATA_BUSY)) { + msleep (100); + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 3, 0); + } + + if (status & ATA_BUSY) { + printf ("ata%u is slow to respond,plz be patient\n", num); + } + + while ((status & ATA_BUSY)) { + msleep (100); + status = sata_chk_status (&port[num].ioaddr, 0); + } + + if (status & ATA_BUSY) { + printf ("ata%u failed to respond : ", num); + printf ("bus reset failed\n"); + port[num].dev_mask = 0; + return 1; + } + return 0; +} + +static void sata_identify (int num, int dev) +{ + u8 cmd = 0, status = 0, devno = num; + u16 iobuf[ATA_SECTOR_WORDS]; + u64 n_sectors = 0; + + memset (iobuf, 0, sizeof (iobuf)); + + if (!(port[num].dev_mask & 0x01)) { + printf ("dev%d is not present on port#%d\n", dev, num); + return; + } + + debug ("port=%d dev=%d\n", num, dev); + + status = 0; + cmd = ATA_CMD_ID_ATA; /*Device Identify Command */ + writeb (cmd, port[num].ioaddr.command_addr); + readb (port[num].ioaddr.altstatus_addr); + udelay (10); + + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 1000, 0); + if (status & ATA_ERR) { + printf ("\ndevice not responding\n"); + port[num].dev_mask &= ~0x01; + return; + } + + input_data (&port[num].ioaddr, iobuf, ATA_SECTOR_WORDS); + + ata_swap_buf_le16 (iobuf, ATA_SECTOR_WORDS); + + debug ("Specific config: %x\n", iobuf[2]); + + /* we require LBA and DMA support (bits 8 & 9 of word 49) */ + if (!ata_id_has_dma (iobuf) || !ata_id_has_lba (iobuf)) { + debug ("ata%u: no dma/lba\n", num); + } +#ifdef DEBUG + ata_dump_id (iobuf); +#endif + n_sectors = ata_id_n_sectors (iobuf); + + if (n_sectors == 0) { + port[num].dev_mask &= ~0x01; + return; + } + ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].revision, + ATA_ID_FW_REV, sizeof (sata_dev_desc[devno].revision)); + ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].vendor, + ATA_ID_PROD, sizeof (sata_dev_desc[devno].vendor)); + ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].product, + ATA_ID_SERNO, sizeof (sata_dev_desc[devno].product)); + + /* TODO - atm we asume harddisk ie not removable */ + sata_dev_desc[devno].removable = 0; + + sata_dev_desc[devno].lba = (u32) n_sectors; + debug("lba=0x%lx\n", sata_dev_desc[devno].lba); + +#ifdef CONFIG_LBA48 + if (iobuf[83] & (1 << 10)) { + sata_dev_desc[devno].lba48 = 1; + } else { + sata_dev_desc[devno].lba48 = 0; + } +#endif + + /* assuming HD */ + sata_dev_desc[devno].type = DEV_TYPE_HARDDISK; + sata_dev_desc[devno].blksz = ATA_SECT_SIZE; + sata_dev_desc[devno].lun = 0; /* just to fill something in... */ +} + +static void set_Feature_cmd (int num, int dev) +{ + u8 status = 0; + + if (!(port[num].dev_mask & 0x01)) { + debug ("dev%d is not present on port#%d\n", dev, num); + return; + } + + writeb (SETFEATURES_XFER, port[num].ioaddr.feature_addr); + writeb (XFER_PIO_4, port[num].ioaddr.nsect_addr); + writeb (0, port[num].ioaddr.lbal_addr); + writeb (0, port[num].ioaddr.lbam_addr); + writeb (0, port[num].ioaddr.lbah_addr); + + writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); + writeb (ATA_CMD_SET_FEATURES, port[num].ioaddr.command_addr); + + udelay (50); + msleep (150); + + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 5000, 0); + if ((status & (ATA_BUSY | ATA_ERR))) { + printf ("Error : status 0x%02x\n", status); + port[num].dev_mask &= ~0x01; + } +} + +u8 sil3114_spin_down (int num) +{ + u8 status = 0; + + debug ("Spin down disk\n"); + + if (!(port[num].dev_mask & 0x01)) { + debug ("Device ata%d is not present\n", num); + return 1; + } + + if ((status = check_power_mode (num)) == 0x00) { + debug ("Already in standby\n"); + return 0; + } + + if (status == 0x01) { + printf ("Failed to check power mode on ata%d\n", num); + return 1; + } + + if (!((status = sata_chk_status (&port[num].ioaddr, 0)) & ATA_DRDY)) { + printf ("Device ata%d not ready\n", num); + return 1; + } + + writeb (0x00, port[num].ioaddr.feature_addr); + + writeb (0x00, port[num].ioaddr.nsect_addr); + writeb (0x00, port[num].ioaddr.lbal_addr); + writeb (0x00, port[num].ioaddr.lbam_addr); + writeb (0x00, port[num].ioaddr.lbah_addr); + + writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); + writeb (ATA_CMD_STANDBY, port[num].ioaddr.command_addr); + + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 30000, 0); + if ((status & (ATA_BUSY | ATA_ERR))) { + printf ("Error waiting for disk spin down: status 0x%02x\n", + status); + port[num].dev_mask &= ~0x01; + return 1; + } + return 0; +} + +u8 sil3114_spin_up (int num) +{ + u8 status = 0; + + debug ("Spin up disk\n"); + + if (!(port[num].dev_mask & 0x01)) { + debug ("Device ata%d is not present\n", num); + return 1; + } + + if ((status = check_power_mode (num)) != 0x00) { + if (status == 0x01) { + printf ("Failed to check power mode on ata%d\n", num); + return 1; + } else { + /* should be up and running already */ + return 0; + } + } + + if (!((status = sata_chk_status (&port[num].ioaddr, 0)) & ATA_DRDY)) { + printf ("Device ata%d not ready\n", num); + return 1; + } + + debug ("Stautus of device check: %d\n", status); + + writeb (0x00, port[num].ioaddr.feature_addr); + + writeb (0x00, port[num].ioaddr.nsect_addr); + writeb (0x00, port[num].ioaddr.lbal_addr); + writeb (0x00, port[num].ioaddr.lbam_addr); + writeb (0x00, port[num].ioaddr.lbah_addr); + + writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); + writeb (ATA_CMD_IDLE, port[num].ioaddr.command_addr); + + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 30000, 0); + if ((status & (ATA_BUSY | ATA_ERR))) { + printf ("Error waiting for disk spin up: status 0x%02x\n", + status); + port[num].dev_mask &= ~0x01; + return 1; + } + + /* Wait for disk to enter Active state */ + do { + msleep (10); + status = check_power_mode (num); + } while ((status == 0x00) || (status == 0x80)); + + if (status == 0x01) { + printf ("Falied waiting for disk to spin up\n"); + return 1; + } + + return 0; +} + +/* Return value is not the usual here + * 0x00 - Device stand by + * 0x01 - Operation failed + * 0x80 - Device idle + * 0xff - Device active +*/ +static u8 check_power_mode (int num) +{ + u8 status = 0; + u8 res = 0; + if (!(port[num].dev_mask & 0x01)) { + debug ("Device ata%d is not present\n", num); + return 1; + } + + if (!(sata_chk_status (&port[num].ioaddr, 0) & ATA_DRDY)) { + printf ("Device ata%d not ready\n", num); + return 1; + } + + writeb (0, port[num].ioaddr.feature_addr); + writeb (0, port[num].ioaddr.nsect_addr); + writeb (0, port[num].ioaddr.lbal_addr); + writeb (0, port[num].ioaddr.lbam_addr); + writeb (0, port[num].ioaddr.lbah_addr); + + writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); + writeb (ATA_CMD_CHK_POWER, port[num].ioaddr.command_addr); + + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 5000, 0); + if ((status & (ATA_BUSY | ATA_ERR))) { + printf + ("Error waiting for check power mode complete : status 0x%02x\n", + status); + port[num].dev_mask &= ~0x01; + return 1; + } + res = readb (port[num].ioaddr.nsect_addr); + debug ("Check powermode: %d\n", res); + return res; + +} + +static void sata_port (struct sata_ioports *ioport) +{ + ioport->data_addr = ioport->cmd_addr + ATA_REG_DATA; + ioport->error_addr = ioport->cmd_addr + ATA_REG_ERR; + ioport->feature_addr = ioport->cmd_addr + ATA_REG_FEATURE; + ioport->nsect_addr = ioport->cmd_addr + ATA_REG_NSECT; + ioport->lbal_addr = ioport->cmd_addr + ATA_REG_LBAL; + ioport->lbam_addr = ioport->cmd_addr + ATA_REG_LBAM; + ioport->lbah_addr = ioport->cmd_addr + ATA_REG_LBAH; + ioport->device_addr = ioport->cmd_addr + ATA_REG_DEVICE; + ioport->status_addr = ioport->cmd_addr + ATA_REG_STATUS; + ioport->command_addr = ioport->cmd_addr + ATA_REG_CMD; +} + +static u8 wait_for_irq (int num, unsigned int max) +{ + + u32 port = iobase[5]; + switch (num) { + case 0: + port += VND_TF_CNST_CH0; + break; + case 1: + port += VND_TF_CNST_CH1; + break; + case 2: + port += VND_TF_CNST_CH2; + break; + case 3: + port += VND_TF_CNST_CH3; + break; + default: + return 1; + } + + do { + if (readl (port) & VND_TF_CNST_INTST) { + break; + } + udelay (1000); + max--; + } while ((max > 0)); + + return (max == 0); +} + +static u8 sata_busy_wait (struct sata_ioports *ioaddr, int bits, + unsigned int max, u8 usealtstatus) +{ + u8 status; + + do { + if (!((status = sata_chk_status (ioaddr, usealtstatus)) & bits)) { + break; + } + udelay (1000); + max--; + } while ((status & bits) && (max > 0)); + + return status; +} + +static u8 sata_chk_status (struct sata_ioports *ioaddr, u8 usealtstatus) +{ + if (!usealtstatus) { + return readb (ioaddr->status_addr); + } else { + return readb (ioaddr->altstatus_addr); + } +} + +static void msleep (int count) +{ + int i; + + for (i = 0; i < count; i++) + udelay (1000); +} + +/* Read up to 255 sectors + * + * Returns sectors read +*/ +static u8 do_one_read (int device, ulong block, u8 blkcnt, u16 * buff, + uchar lba48) +{ + + u8 sr = 0; + u8 status; + u64 blknr = (u64) block; + + if (!(sata_chk_status (&port[device].ioaddr, 0) & ATA_DRDY)) { + printf ("Device ata%d not ready\n", device); + return 0; + } + + /* Set up transfer */ +#ifdef CONFIG_LBA48 + if (lba48) { + /* write high bits */ + writeb (0, port[device].ioaddr.nsect_addr); + writeb ((blknr >> 24) & 0xFF, port[device].ioaddr.lbal_addr); + writeb ((blknr >> 32) & 0xFF, port[device].ioaddr.lbam_addr); + writeb ((blknr >> 40) & 0xFF, port[device].ioaddr.lbah_addr); + } +#endif + writeb (blkcnt, port[device].ioaddr.nsect_addr); + writeb (((blknr) >> 0) & 0xFF, port[device].ioaddr.lbal_addr); + writeb ((blknr >> 8) & 0xFF, port[device].ioaddr.lbam_addr); + writeb ((blknr >> 16) & 0xFF, port[device].ioaddr.lbah_addr); + +#ifdef CONFIG_LBA48 + if (lba48) { + writeb (ATA_LBA, port[device].ioaddr.device_addr); + writeb (ATA_CMD_PIO_READ_EXT, port[device].ioaddr.command_addr); + } else +#endif + { + writeb (ATA_LBA | ((blknr >> 24) & 0xF), + port[device].ioaddr.device_addr); + writeb (ATA_CMD_PIO_READ, port[device].ioaddr.command_addr); + } + + status = sata_busy_wait (&port[device].ioaddr, ATA_BUSY, 10000, 1); + + if (status & ATA_BUSY) { + u8 err = 0; + + printf ("Device %d not responding status %d\n", device, status); + err = readb (port[device].ioaddr.error_addr); + printf ("Error reg = 0x%x\n", err); + + return (sr); + } + while (blkcnt--) { + + if (wait_for_irq (device, 500)) { + printf ("ata%u irq failed\n", device); + return sr; + } + + status = sata_chk_status (&port[device].ioaddr, 0); + if (status & ATA_ERR) { + printf ("ata%u error %d\n", device, + readb (port[device].ioaddr.error_addr)); + return sr; + } + /* Read one sector */ + input_data (&port[device].ioaddr, buff, ATA_SECTOR_WORDS); + buff += ATA_SECTOR_WORDS; + sr++; + + } + return sr; +} + +ulong sata_read (int device, ulong block, lbaint_t blkcnt, void *buff) +{ + ulong n = 0, sread; + u16 *buffer = (u16 *) buff; + u8 status = 0; + u64 blknr = (u64) block; + unsigned char lba48 = 0; + +#ifdef CONFIG_LBA48 + if (blknr > 0xfffffff) { + if (!sata_dev_desc[device].lba48) { + printf ("Drive doesn't support 48-bit addressing\n"); + return 0; + } + /* more than 28 bits used, use 48bit mode */ + lba48 = 1; + } +#endif + + while (blkcnt > 0) { + + if (blkcnt > 255) { + sread = 255; + } else { + sread = blkcnt; + } + + status = do_one_read (device, blknr, sread, buffer, lba48); + if (status != sread) { + printf ("Read failed\n"); + return n; + } + + blkcnt -= sread; + blknr += sread; + n += sread; + buffer += sread * ATA_SECTOR_WORDS; + } + return n; +} + +ulong sata_write (int device, ulong block, lbaint_t blkcnt, const void *buff) +{ + ulong n = 0; + u16 *buffer = (u16 *) buff; + unsigned char status = 0, num = 0; + u64 blknr = (u64) block; +#ifdef CONFIG_LBA48 + unsigned char lba48 = 0; + + if (blknr > 0xfffffff) { + if (!sata_dev_desc[device].lba48) { + printf ("Drive doesn't support 48-bit addressing\n"); + return 0; + } + /* more than 28 bits used, use 48bit mode */ + lba48 = 1; + } +#endif + /*Port Number */ + num = device; + + while (blkcnt-- > 0) { + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500, 0); + if (status & ATA_BUSY) { + printf ("ata%u failed to respond\n", port[num].port_no); + return n; + } +#ifdef CONFIG_LBA48 + if (lba48) { + /* write high bits */ + writeb (0, port[num].ioaddr.nsect_addr); + writeb ((blknr >> 24) & 0xFF, + port[num].ioaddr.lbal_addr); + writeb ((blknr >> 32) & 0xFF, + port[num].ioaddr.lbam_addr); + writeb ((blknr >> 40) & 0xFF, + port[num].ioaddr.lbah_addr); + } +#endif + writeb (1, port[num].ioaddr.nsect_addr); + writeb ((blknr >> 0) & 0xFF, port[num].ioaddr.lbal_addr); + writeb ((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr); + writeb ((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr); +#ifdef CONFIG_LBA48 + if (lba48) { + writeb (ATA_LBA, port[num].ioaddr.device_addr); + writeb (ATA_CMD_PIO_WRITE_EXT, port[num].ioaddr.command_addr); + } else +#endif + { + writeb (ATA_LBA | ((blknr >> 24) & 0xF), + port[num].ioaddr.device_addr); + writeb (ATA_CMD_PIO_WRITE, port[num].ioaddr.command_addr); + } + + msleep (50); + /*may take up to 4 sec */ + status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 4000, 0); + if ((status & (ATA_DRQ | ATA_BUSY | ATA_ERR)) != ATA_DRQ) { + printf ("Error no DRQ dev %d blk %ld: sts 0x%02x\n", + device, (ulong) blknr, status); + return (n); + } + + output_data (&port[num].ioaddr, buffer, ATA_SECTOR_WORDS); + readb (port[num].ioaddr.altstatus_addr); + udelay (50); + + ++n; + ++blknr; + buffer += ATA_SECTOR_WORDS; + } + return n; +} + +/* Driver implementation */ +static u8 sil_get_device_cache_line (pci_dev_t pdev) +{ + u8 cache_line = 0; + pci_read_config_byte (pdev, PCI_CACHE_LINE_SIZE, &cache_line); + return cache_line; +} + +int init_sata (int dev) +{ + static u8 init_done = 0; + static int res = 1; + pci_dev_t devno; + u8 cls = 0; + u16 cmd = 0; + u32 sconf = 0; + + if (init_done) { + return res; + } + + init_done = 1; + + if ((devno = pci_find_device (SIL_VEND_ID, SIL3114_DEVICE_ID, 0)) == -1) { + res = 1; + return res; + } + + /* Read out all BARs, even though we only use MMIO from BAR5 */ + pci_read_config_dword (devno, PCI_BASE_ADDRESS_0, &iobase[0]); + pci_read_config_dword (devno, PCI_BASE_ADDRESS_1, &iobase[1]); + pci_read_config_dword (devno, PCI_BASE_ADDRESS_2, &iobase[2]); + pci_read_config_dword (devno, PCI_BASE_ADDRESS_3, &iobase[3]); + pci_read_config_dword (devno, PCI_BASE_ADDRESS_4, &iobase[4]); + pci_read_config_dword (devno, PCI_BASE_ADDRESS_5, &iobase[5]); + + if ((iobase[0] == 0xFFFFFFFF) || (iobase[1] == 0xFFFFFFFF) || + (iobase[2] == 0xFFFFFFFF) || (iobase[3] == 0xFFFFFFFF) || + (iobase[4] == 0xFFFFFFFF) || (iobase[5] == 0xFFFFFFFF)) { + printf ("Error no base addr for SATA controller\n"); + res = 1; + return res; + } + + /* mask off unused bits */ + iobase[0] &= 0xfffffffc; + iobase[1] &= 0xfffffff8; + iobase[2] &= 0xfffffffc; + iobase[3] &= 0xfffffff8; + iobase[4] &= 0xfffffff0; + iobase[5] &= 0xfffffc00; + + /* from sata_sil in Linux kernel */ + cls = sil_get_device_cache_line (devno); + if (cls) { + cls >>= 3; + cls++; /* cls = (line_size/8)+1 */ + writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH0); + writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH1); + writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH2); + writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH3); + } else { + printf ("Cache line not set. Driver may not function\n"); + } + + /* Enable operation */ + pci_read_config_word (devno, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; + pci_write_config_word (devno, PCI_COMMAND, cmd); + + /* Disable interrupt usage */ + pci_read_config_dword (devno, VND_SYSCONFSTAT, &sconf); + sconf |= (VND_SYSCONFSTAT_CHN_0_INTBLOCK | VND_SYSCONFSTAT_CHN_1_INTBLOCK); + pci_write_config_dword (devno, VND_SYSCONFSTAT, sconf); + + res = 0; + return res; +} + +int reset_sata(int dev) +{ + return 0; +} + +/* Check if device is connected to port */ +int sata_bus_probe (int portno) +{ + u32 port = iobase[5]; + u32 val; + switch (portno) { + case 0: + port += VND_SSTATUS_CH0; + break; + case 1: + port += VND_SSTATUS_CH1; + break; + case 2: + port += VND_SSTATUS_CH2; + break; + case 3: + port += VND_SSTATUS_CH3; + break; + default: + return 0; + } + val = readl (port); + if ((val & SATA_DET_PRES) == SATA_DET_PRES) { + return 1; + } else { + return 0; + } +} + +int sata_phy_reset (int portno) +{ + u32 port = iobase[5]; + u32 val; + switch (portno) { + case 0: + port += VND_SCONTROL_CH0; + break; + case 1: + port += VND_SCONTROL_CH1; + break; + case 2: + port += VND_SCONTROL_CH2; + break; + case 3: + port += VND_SCONTROL_CH3; + break; + default: + return 0; + } + val = readl (port); + writel (val | SATA_SC_DET_RST, port); + msleep (150); + writel (val & ~SATA_SC_DET_RST, port); + return 0; +} + +int scan_sata (int dev) +{ + /* A bit brain dead, but the code has a legacy */ + switch (dev) { + case 0: + port[0].port_no = 0; + port[0].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH0; + port[0].ioaddr.altstatus_addr = port[0].ioaddr.ctl_addr = + (iobase[5] + VND_TF2_CH0) | ATA_PCI_CTL_OFS; + port[0].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH0; + break; +#if (CONFIG_SYS_SATA_MAX_DEVICE >= 1) + case 1: + port[1].port_no = 0; + port[1].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH1; + port[1].ioaddr.altstatus_addr = port[1].ioaddr.ctl_addr = + (iobase[5] + VND_TF2_CH1) | ATA_PCI_CTL_OFS; + port[1].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH1; + break; +#elif (CONFIG_SYS_SATA_MAX_DEVICE >= 2) + case 2: + port[2].port_no = 0; + port[2].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH2; + port[2].ioaddr.altstatus_addr = port[2].ioaddr.ctl_addr = + (iobase[5] + VND_TF2_CH2) | ATA_PCI_CTL_OFS; + port[2].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH2; + break; +#elif (CONFIG_SYS_SATA_MAX_DEVICE >= 3) + case 3: + port[3].port_no = 0; + port[3].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH3; + port[3].ioaddr.altstatus_addr = port[3].ioaddr.ctl_addr = + (iobase[5] + VND_TF2_CH3) | ATA_PCI_CTL_OFS; + port[3].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH3; + break; +#endif + default: + printf ("Tried to scan unknown port: ata%d\n", dev); + return 1; + } + + /* Initialize other registers */ + sata_port (&port[dev].ioaddr); + + /* Check for attached device */ + if (!sata_bus_probe (dev)) { + port[dev].port_state = 0; + debug ("SATA#%d port is not present\n", dev); + } else { + debug ("SATA#%d port is present\n", dev); + if (sata_bus_softreset (dev)) { + /* soft reset failed, try a hard one */ + sata_phy_reset (dev); + if (sata_bus_softreset (dev)) { + port[dev].port_state = 0; + } else { + port[dev].port_state = 1; + } + } else { + port[dev].port_state = 1; + } + } + if (port[dev].port_state == 1) { + /* Probe device and set xfer mode */ + sata_identify (dev, 0); + set_Feature_cmd (dev, 0); + } + + return 0; +} diff --git a/drivers/ata/sata_sil3114.h b/drivers/ata/sata_sil3114.h new file mode 100644 index 0000000000..091fca1d40 --- /dev/null +++ b/drivers/ata/sata_sil3114.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) Excito Elektronik i Skåne AB, All rights reserved. + * Author: Tor Krill + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef SATA_SIL3114_H +#define SATA_SIL3114_H + +struct sata_ioports { + unsigned long cmd_addr; + unsigned long data_addr; + unsigned long error_addr; + unsigned long feature_addr; + unsigned long nsect_addr; + unsigned long lbal_addr; + unsigned long lbam_addr; + unsigned long lbah_addr; + unsigned long device_addr; + unsigned long status_addr; + unsigned long command_addr; + unsigned long altstatus_addr; + unsigned long ctl_addr; + unsigned long bmdma_addr; + unsigned long scr_addr; +}; + +struct sata_port { + unsigned char port_no; /* primary=0, secondary=1 */ + struct sata_ioports ioaddr; /* ATA cmd/ctl/dma reg blks */ + unsigned char ctl_reg; + unsigned char last_ctl; + unsigned char port_state; /* 1-port is available and */ + /* 0-port is not available */ + unsigned char dev_mask; +}; + +/* Missing ata defines */ +#define ATA_CMD_STANDBY 0xE2 +#define ATA_CMD_STANDBYNOW1 0xE0 +#define ATA_CMD_IDLE 0xE3 +#define ATA_CMD_IDLEIMMEDIATE 0xE1 + +/* Defines for SIL3114 chip */ + +/* PCI defines */ +#define SIL_VEND_ID 0x1095 +#define SIL3114_DEVICE_ID 0x3114 + +/* some vendor specific registers */ +#define VND_SYSCONFSTAT 0x88 /* System Configuration Status and Command */ +#define VND_SYSCONFSTAT_CHN_0_INTBLOCK (1<<22) +#define VND_SYSCONFSTAT_CHN_1_INTBLOCK (1<<23) +#define VND_SYSCONFSTAT_CHN_2_INTBLOCK (1<<24) +#define VND_SYSCONFSTAT_CHN_3_INTBLOCK (1<<25) + +/* internal registers mapped by BAR5 */ +/* SATA Control*/ +#define VND_SCONTROL_CH0 0x100 +#define VND_SCONTROL_CH1 0x180 +#define VND_SCONTROL_CH2 0x300 +#define VND_SCONTROL_CH3 0x380 + +#define SATA_SC_IPM_T2P (1<<16) +#define SATA_SC_IPM_T2S (2<<16) +#define SATA_SC_SPD_1_5 (1<<4) +#define SATA_SC_SPD_3_0 (2<<4) +#define SATA_SC_DET_RST (1) /* ATA Reset sequence */ +#define SATA_SC_DET_PDIS (4) /* PHY Disable */ + +/* SATA Status */ +#define VND_SSTATUS_CH0 0x104 +#define VND_SSTATUS_CH1 0x184 +#define VND_SSTATUS_CH2 0x304 +#define VND_SSTATUS_CH3 0x384 + +#define SATA_SS_IPM_ACTIVE (1<<8) +#define SATA_SS_IPM_PARTIAL (2<<8) +#define SATA_SS_IPM_SLUMBER (6<<8) +#define SATA_SS_SPD_1_5 (1<<4) +#define SATA_SS_SPD_3_0 (2<<4) +#define SATA_DET_P_NOPHY (1) /* Device presence but no PHY connection established */ +#define SATA_DET_PRES (3) /* Device presence and active PHY */ +#define SATA_DET_OFFLINE (4) /* Device offline or in loopback mode */ + +/* Task file registers in BAR5 mapping */ +#define VND_TF0_CH0 0x80 +#define VND_TF0_CH1 0xc0 +#define VND_TF0_CH2 0x280 +#define VND_TF0_CH3 0x2c0 +#define VND_TF1_CH0 0x88 +#define VND_TF1_CH1 0xc8 +#define VND_TF1_CH2 0x288 +#define VND_TF1_CH3 0x2c8 +#define VND_TF2_CH0 0x88 +#define VND_TF2_CH1 0xc8 +#define VND_TF2_CH2 0x288 +#define VND_TF2_CH3 0x2c8 + +#define VND_BMDMA_CH0 0x00 +#define VND_BMDMA_CH1 0x08 +#define VND_BMDMA_CH2 0x200 +#define VND_BMDMA_CH3 0x208 +#define VND_BMDMA2_CH0 0x10 +#define VND_BMDMA2_CH1 0x18 +#define VND_BMDMA2_CH2 0x210 +#define VND_BMDMA2_CH3 0x218 + +/* FIFO control */ +#define VND_FIFOCFG_CH0 0x40 +#define VND_FIFOCFG_CH1 0x44 +#define VND_FIFOCFG_CH2 0x240 +#define VND_FIFOCFG_CH3 0x244 + +/* Task File configuration and status */ +#define VND_TF_CNST_CH0 0xa0 +#define VND_TF_CNST_CH1 0xe0 +#define VND_TF_CNST_CH2 0x2a0 +#define VND_TF_CNST_CH3 0x2e0 + +#define VND_TF_CNST_BFCMD (1<<1) +#define VND_TF_CNST_CHNRST (1<<2) +#define VND_TF_CNST_VDMA (1<<10) +#define VND_TF_CNST_INTST (1<<11) +#define VND_TF_CNST_WDTO (1<<12) +#define VND_TF_CNST_WDEN (1<<13) +#define VND_TF_CNST_WDIEN (1<<14) + +/* for testing */ +#define VND_SSDR 0x04c /* System Software Data Register */ +#define VND_FMACS 0x050 /* Flash Memory Address control and status */ + +#endif diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index ed7fa88bf5..1ddd6508e4 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -10,28 +10,6 @@ config BLK be partitioned into several areas, called 'partitions' in U-Boot. A filesystem can be placed in each partition. -config AHCI - bool "Support SATA controllers with driver model" - depends on DM - help - This enables a uclass for disk controllers in U-Boot. Various driver - types can use this, such as AHCI/SATA. It does not provide any standard - operations at present. The block device interface has not been converted - to driver model. - -config SATA - bool "Support SATA controllers" - help - This enables support for SATA (Serial Advanced Technology - Attachment), a serial bus standard for connecting to hard drives and - other storage devices. - - SATA replaces PATA (originally just ATA), which stands for Parallel AT - Attachment, where AT refers to an IBM AT (Advanced Technology) - computer released in 1984. - - See also CMD_SATA which provides command-line support. - config SCSI bool "Support SCSI controllers" help @@ -59,29 +37,6 @@ config BLOCK_CACHE it will prevent repeated reads from directory structures and other filesystem data structures. -menu "SATA/SCSI device support" - -config SATA_CEVA - bool "Ceva Sata controller" - depends on AHCI - depends on DM_SCSI - help - This option enables Ceva Sata controller hard IP available on Xilinx - ZynqMP. Support up to 2 external devices. Complient with SATA 3.1 and - AHCI 1.3 specifications with hot-plug detect feature. - - -config DWC_AHCI - bool "Enable Synopsys DWC AHCI driver support" - select SCSI_AHCI - select PHY - depends on DM_SCSI - help - Enable this driver to support Sata devices through - Synopsys DWC AHCI module. - -endmenu - config IDE bool "Support IDE controllers" help diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 035e078f81..064c76fc98 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -11,22 +11,8 @@ ifndef CONFIG_BLK obj-y += blk_legacy.o endif -obj-$(CONFIG_DWC_AHCI) += dwc_ahci.o -obj-$(CONFIG_AHCI) += ahci-uclass.o -obj-$(CONFIG_DM_SCSI) += scsi-uclass.o -obj-$(CONFIG_SCSI_AHCI) += ahci.o -obj-$(CONFIG_DWC_AHSATA) += dwc_ahsata.o -obj-$(CONFIG_FSL_SATA) += fsl_sata.o obj-$(CONFIG_IDE) += ide.o obj-$(CONFIG_IDE_FTIDE020) += ftide020.o -obj-$(CONFIG_LIBATA) += libata.o -obj-$(CONFIG_MVSATA_IDE) += mvsata_ide.o -obj-$(CONFIG_MX51_PATA) += mxc_ata.o -obj-$(CONFIG_SATA_CEVA) += sata_ceva.o -obj-$(CONFIG_SATA_DWC) += sata_dwc.o -obj-$(CONFIG_SATA_MV) += sata_mv.o -obj-$(CONFIG_SATA_SIL3114) += sata_sil3114.o -obj-$(CONFIG_SATA_SIL) += sata_sil.o -obj-$(CONFIG_SANDBOX) += sandbox.o sandbox_scsi.o sata_sandbox.o +obj-$(CONFIG_SANDBOX) += sandbox.o sandbox_scsi.o obj-$(CONFIG_SYSTEMACE) += systemace.o obj-$(CONFIG_BLOCK_CACHE) += blkcache.o diff --git a/drivers/block/ahci-uclass.c b/drivers/block/ahci-uclass.c deleted file mode 100644 index 7b8c32699f..0000000000 --- a/drivers/block/ahci-uclass.c +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2015 Google, Inc - * Written by Simon Glass - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include - -UCLASS_DRIVER(ahci) = { - .id = UCLASS_AHCI, - .name = "ahci", -}; diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c deleted file mode 100644 index f4744718a8..0000000000 --- a/drivers/block/ahci.c +++ /dev/null @@ -1,1094 +0,0 @@ -/* - * Copyright (C) Freescale Semiconductor, Inc. 2006. - * Author: Jason Jin - * Zhang Wei - * - * SPDX-License-Identifier: GPL-2.0+ - * - * with the reference on libata and ahci drvier in kernel - */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int ata_io_flush(u8 port); - -struct ahci_probe_ent *probe_ent = NULL; -u16 *ataid[AHCI_MAX_PORTS]; - -#define writel_with_flush(a,b) do { writel(a,b); readl(b); } while (0) - -/* - * Some controllers limit number of blocks they can read/write at once. - * Contemporary SSD devices work much faster if the read/write size is aligned - * to a power of 2. Let's set default to 128 and allowing to be overwritten if - * needed. - */ -#ifndef MAX_SATA_BLOCKS_READ_WRITE -#define MAX_SATA_BLOCKS_READ_WRITE 0x80 -#endif - -/* Maximum timeouts for each event */ -#define WAIT_MS_SPINUP 20000 -#define WAIT_MS_DATAIO 10000 -#define WAIT_MS_FLUSH 5000 -#define WAIT_MS_LINKUP 200 - -__weak void __iomem *ahci_port_base(void __iomem *base, u32 port) -{ - return base + 0x100 + (port * 0x80); -} - - -static void ahci_setup_port(struct ahci_ioports *port, void __iomem *base, - unsigned int port_idx) -{ - base = ahci_port_base(base, port_idx); - - port->cmd_addr = base; - port->scr_addr = base + PORT_SCR; -} - - -#define msleep(a) udelay(a * 1000) - -static void ahci_dcache_flush_range(unsigned long begin, unsigned long len) -{ - const unsigned long start = begin; - const unsigned long end = start + len; - - debug("%s: flush dcache: [%#lx, %#lx)\n", __func__, start, end); - flush_dcache_range(start, end); -} - -/* - * SATA controller DMAs to physical RAM. Ensure data from the - * controller is invalidated from dcache; next access comes from - * physical RAM. - */ -static void ahci_dcache_invalidate_range(unsigned long begin, unsigned long len) -{ - const unsigned long start = begin; - const unsigned long end = start + len; - - debug("%s: invalidate dcache: [%#lx, %#lx)\n", __func__, start, end); - invalidate_dcache_range(start, end); -} - -/* - * Ensure data for SATA controller is flushed out of dcache and - * written to physical memory. - */ -static void ahci_dcache_flush_sata_cmd(struct ahci_ioports *pp) -{ - ahci_dcache_flush_range((unsigned long)pp->cmd_slot, - AHCI_PORT_PRIV_DMA_SZ); -} - -static int waiting_for_cmd_completed(void __iomem *offset, - int timeout_msec, - u32 sign) -{ - int i; - u32 status; - - for (i = 0; ((status = readl(offset)) & sign) && i < timeout_msec; i++) - msleep(1); - - return (i < timeout_msec) ? 0 : -1; -} - -int __weak ahci_link_up(struct ahci_probe_ent *probe_ent, u8 port) -{ - u32 tmp; - int j = 0; - void __iomem *port_mmio = probe_ent->port[port].port_mmio; - - /* - * Bring up SATA link. - * SATA link bringup time is usually less than 1 ms; only very - * rarely has it taken between 1-2 ms. Never seen it above 2 ms. - */ - while (j < WAIT_MS_LINKUP) { - tmp = readl(port_mmio + PORT_SCR_STAT); - tmp &= PORT_SCR_STAT_DET_MASK; - if (tmp == PORT_SCR_STAT_DET_PHYRDY) - return 0; - udelay(1000); - j++; - } - return 1; -} - -#ifdef CONFIG_SUNXI_AHCI -/* The sunxi AHCI controller requires this undocumented setup */ -static void sunxi_dma_init(void __iomem *port_mmio) -{ - clrsetbits_le32(port_mmio + PORT_P0DMACR, 0x0000ff00, 0x00004400); -} -#endif - -int ahci_reset(void __iomem *base) -{ - int i = 1000; - u32 __iomem *host_ctl_reg = base + HOST_CTL; - u32 tmp = readl(host_ctl_reg); /* global controller reset */ - - if ((tmp & HOST_RESET) == 0) - writel_with_flush(tmp | HOST_RESET, host_ctl_reg); - - /* - * reset must complete within 1 second, or - * the hardware should be considered fried. - */ - do { - udelay(1000); - tmp = readl(host_ctl_reg); - i--; - } while ((i > 0) && (tmp & HOST_RESET)); - - if (i == 0) { - printf("controller reset failed (0x%x)\n", tmp); - return -1; - } - - return 0; -} - -static int ahci_host_init(struct ahci_probe_ent *probe_ent) -{ -#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI) -# ifdef CONFIG_DM_PCI - struct udevice *dev = probe_ent->dev; - struct pci_child_platdata *pplat = dev_get_parent_platdata(dev); -# else - pci_dev_t pdev = probe_ent->dev; - unsigned short vendor; -# endif - u16 tmp16; -#endif - void __iomem *mmio = probe_ent->mmio_base; - u32 tmp, cap_save, cmd; - int i, j, ret; - void __iomem *port_mmio; - u32 port_map; - - debug("ahci_host_init: start\n"); - - cap_save = readl(mmio + HOST_CAP); - cap_save &= ((1 << 28) | (1 << 17)); - cap_save |= (1 << 27); /* Staggered Spin-up. Not needed. */ - - ret = ahci_reset(probe_ent->mmio_base); - if (ret) - return ret; - - writel_with_flush(HOST_AHCI_EN, mmio + HOST_CTL); - writel(cap_save, mmio + HOST_CAP); - writel_with_flush(0xf, mmio + HOST_PORTS_IMPL); - -#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI) -# ifdef CONFIG_DM_PCI - if (pplat->vendor == PCI_VENDOR_ID_INTEL) { - u16 tmp16; - - dm_pci_read_config16(dev, 0x92, &tmp16); - dm_pci_write_config16(dev, 0x92, tmp16 | 0xf); - } -# else - pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor); - - if (vendor == PCI_VENDOR_ID_INTEL) { - u16 tmp16; - pci_read_config_word(pdev, 0x92, &tmp16); - tmp16 |= 0xf; - pci_write_config_word(pdev, 0x92, tmp16); - } -# endif -#endif - probe_ent->cap = readl(mmio + HOST_CAP); - probe_ent->port_map = readl(mmio + HOST_PORTS_IMPL); - port_map = probe_ent->port_map; - probe_ent->n_ports = (probe_ent->cap & 0x1f) + 1; - - debug("cap 0x%x port_map 0x%x n_ports %d\n", - probe_ent->cap, probe_ent->port_map, probe_ent->n_ports); - - if (probe_ent->n_ports > CONFIG_SYS_SCSI_MAX_SCSI_ID) - probe_ent->n_ports = CONFIG_SYS_SCSI_MAX_SCSI_ID; - - for (i = 0; i < probe_ent->n_ports; i++) { - if (!(port_map & (1 << i))) - continue; - probe_ent->port[i].port_mmio = ahci_port_base(mmio, i); - port_mmio = (u8 *) probe_ent->port[i].port_mmio; - ahci_setup_port(&probe_ent->port[i], mmio, i); - - /* make sure port is not active */ - tmp = readl(port_mmio + PORT_CMD); - if (tmp & (PORT_CMD_LIST_ON | PORT_CMD_FIS_ON | - PORT_CMD_FIS_RX | PORT_CMD_START)) { - debug("Port %d is active. Deactivating.\n", i); - tmp &= ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON | - PORT_CMD_FIS_RX | PORT_CMD_START); - writel_with_flush(tmp, port_mmio + PORT_CMD); - - /* spec says 500 msecs for each bit, so - * this is slightly incorrect. - */ - msleep(500); - } - -#ifdef CONFIG_SUNXI_AHCI - sunxi_dma_init(port_mmio); -#endif - - /* Add the spinup command to whatever mode bits may - * already be on in the command register. - */ - cmd = readl(port_mmio + PORT_CMD); - cmd |= PORT_CMD_SPIN_UP; - writel_with_flush(cmd, port_mmio + PORT_CMD); - - /* Bring up SATA link. */ - ret = ahci_link_up(probe_ent, i); - if (ret) { - printf("SATA link %d timeout.\n", i); - continue; - } else { - debug("SATA link ok.\n"); - } - - /* Clear error status */ - tmp = readl(port_mmio + PORT_SCR_ERR); - if (tmp) - writel(tmp, port_mmio + PORT_SCR_ERR); - - debug("Spinning up device on SATA port %d... ", i); - - j = 0; - while (j < WAIT_MS_SPINUP) { - tmp = readl(port_mmio + PORT_TFDATA); - if (!(tmp & (ATA_BUSY | ATA_DRQ))) - break; - udelay(1000); - tmp = readl(port_mmio + PORT_SCR_STAT); - tmp &= PORT_SCR_STAT_DET_MASK; - if (tmp == PORT_SCR_STAT_DET_PHYRDY) - break; - j++; - } - - tmp = readl(port_mmio + PORT_SCR_STAT) & PORT_SCR_STAT_DET_MASK; - if (tmp == PORT_SCR_STAT_DET_COMINIT) { - debug("SATA link %d down (COMINIT received), retrying...\n", i); - i--; - continue; - } - - printf("Target spinup took %d ms.\n", j); - if (j == WAIT_MS_SPINUP) - debug("timeout.\n"); - else - debug("ok.\n"); - - tmp = readl(port_mmio + PORT_SCR_ERR); - debug("PORT_SCR_ERR 0x%x\n", tmp); - writel(tmp, port_mmio + PORT_SCR_ERR); - - /* ack any pending irq events for this port */ - tmp = readl(port_mmio + PORT_IRQ_STAT); - debug("PORT_IRQ_STAT 0x%x\n", tmp); - if (tmp) - writel(tmp, port_mmio + PORT_IRQ_STAT); - - writel(1 << i, mmio + HOST_IRQ_STAT); - - /* register linkup ports */ - tmp = readl(port_mmio + PORT_SCR_STAT); - debug("SATA port %d status: 0x%x\n", i, tmp); - if ((tmp & PORT_SCR_STAT_DET_MASK) == PORT_SCR_STAT_DET_PHYRDY) - probe_ent->link_port_map |= (0x01 << i); - } - - tmp = readl(mmio + HOST_CTL); - debug("HOST_CTL 0x%x\n", tmp); - writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); - tmp = readl(mmio + HOST_CTL); - debug("HOST_CTL 0x%x\n", tmp); -#if !defined(CONFIG_DM_SCSI) -#ifndef CONFIG_SCSI_AHCI_PLAT -# ifdef CONFIG_DM_PCI - dm_pci_read_config16(dev, PCI_COMMAND, &tmp16); - tmp |= PCI_COMMAND_MASTER; - dm_pci_write_config16(dev, PCI_COMMAND, tmp16); -# else - pci_read_config_word(pdev, PCI_COMMAND, &tmp16); - tmp |= PCI_COMMAND_MASTER; - pci_write_config_word(pdev, PCI_COMMAND, tmp16); -# endif -#endif -#endif - return 0; -} - - -static void ahci_print_info(struct ahci_probe_ent *probe_ent) -{ -#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI) -# if defined(CONFIG_DM_PCI) - struct udevice *dev = probe_ent->dev; -# else - pci_dev_t pdev = probe_ent->dev; -# endif - u16 cc; -#endif - void __iomem *mmio = probe_ent->mmio_base; - u32 vers, cap, cap2, impl, speed; - const char *speed_s; - const char *scc_s; - - vers = readl(mmio + HOST_VERSION); - cap = probe_ent->cap; - cap2 = readl(mmio + HOST_CAP2); - impl = probe_ent->port_map; - - speed = (cap >> 20) & 0xf; - if (speed == 1) - speed_s = "1.5"; - else if (speed == 2) - speed_s = "3"; - else if (speed == 3) - speed_s = "6"; - else - speed_s = "?"; - -#if defined(CONFIG_SCSI_AHCI_PLAT) || defined(CONFIG_DM_SCSI) - scc_s = "SATA"; -#else -# ifdef CONFIG_DM_PCI - dm_pci_read_config16(dev, 0x0a, &cc); -# else - pci_read_config_word(pdev, 0x0a, &cc); -# endif - if (cc == 0x0101) - scc_s = "IDE"; - else if (cc == 0x0106) - scc_s = "SATA"; - else if (cc == 0x0104) - scc_s = "RAID"; - else - scc_s = "unknown"; -#endif - printf("AHCI %02x%02x.%02x%02x " - "%u slots %u ports %s Gbps 0x%x impl %s mode\n", - (vers >> 24) & 0xff, - (vers >> 16) & 0xff, - (vers >> 8) & 0xff, - vers & 0xff, - ((cap >> 8) & 0x1f) + 1, (cap & 0x1f) + 1, speed_s, impl, scc_s); - - printf("flags: " - "%s%s%s%s%s%s%s" - "%s%s%s%s%s%s%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 << 16) ? "fbss " : "", - cap & (1 << 15) ? "pio " : "", - cap & (1 << 14) ? "slum " : "", - cap & (1 << 13) ? "part " : "", - cap & (1 << 7) ? "ccc " : "", - cap & (1 << 6) ? "ems " : "", - cap & (1 << 5) ? "sxs " : "", - cap2 & (1 << 2) ? "apst " : "", - cap2 & (1 << 1) ? "nvmp " : "", - cap2 & (1 << 0) ? "boh " : ""); -} - -#ifndef CONFIG_SCSI_AHCI_PLAT -# if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI) -static int ahci_init_one(struct udevice *dev) -# else -static int ahci_init_one(pci_dev_t dev) -# endif -{ -#if !defined(CONFIG_DM_SCSI) - u16 vendor; -#endif - int rc; - - probe_ent = malloc(sizeof(struct ahci_probe_ent)); - if (!probe_ent) { - printf("%s: No memory for probe_ent\n", __func__); - return -ENOMEM; - } - - memset(probe_ent, 0, sizeof(struct ahci_probe_ent)); - probe_ent->dev = dev; - - probe_ent->host_flags = ATA_FLAG_SATA - | ATA_FLAG_NO_LEGACY - | ATA_FLAG_MMIO - | ATA_FLAG_PIO_DMA - | ATA_FLAG_NO_ATAPI; - probe_ent->pio_mask = 0x1f; - probe_ent->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */ - -#if !defined(CONFIG_DM_SCSI) -#ifdef CONFIG_DM_PCI - probe_ent->mmio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_5, - PCI_REGION_MEM); - - /* Take from kernel: - * JMicron-specific fixup: - * make sure we're in AHCI mode - */ - dm_pci_read_config16(dev, PCI_VENDOR_ID, &vendor); - if (vendor == 0x197b) - dm_pci_write_config8(dev, 0x41, 0xa1); -#else - probe_ent->mmio_base = pci_map_bar(dev, PCI_BASE_ADDRESS_5, - PCI_REGION_MEM); - - /* Take from kernel: - * JMicron-specific fixup: - * make sure we're in AHCI mode - */ - pci_read_config_word(dev, PCI_VENDOR_ID, &vendor); - if (vendor == 0x197b) - pci_write_config_byte(dev, 0x41, 0xa1); -#endif -#else - struct scsi_platdata *plat = dev_get_platdata(dev); - probe_ent->mmio_base = (void *)plat->base; -#endif - - debug("ahci mmio_base=0x%p\n", probe_ent->mmio_base); - /* initialize adapter */ - rc = ahci_host_init(probe_ent); - if (rc) - goto err_out; - - ahci_print_info(probe_ent); - - return 0; - - err_out: - return rc; -} -#endif - -#define MAX_DATA_BYTE_COUNT (4*1024*1024) - -static int ahci_fill_sg(u8 port, unsigned char *buf, int buf_len) -{ - struct ahci_ioports *pp = &(probe_ent->port[port]); - struct ahci_sg *ahci_sg = pp->cmd_tbl_sg; - u32 sg_count; - int i; - - sg_count = ((buf_len - 1) / MAX_DATA_BYTE_COUNT) + 1; - if (sg_count > AHCI_MAX_SG) { - printf("Error:Too much sg!\n"); - return -1; - } - - for (i = 0; i < sg_count; i++) { - ahci_sg->addr = - cpu_to_le32((unsigned long) buf + i * MAX_DATA_BYTE_COUNT); - ahci_sg->addr_hi = 0; - ahci_sg->flags_size = cpu_to_le32(0x3fffff & - (buf_len < MAX_DATA_BYTE_COUNT - ? (buf_len - 1) - : (MAX_DATA_BYTE_COUNT - 1))); - ahci_sg++; - buf_len -= MAX_DATA_BYTE_COUNT; - } - - return sg_count; -} - - -static void ahci_fill_cmd_slot(struct ahci_ioports *pp, u32 opts) -{ - pp->cmd_slot->opts = cpu_to_le32(opts); - pp->cmd_slot->status = 0; - pp->cmd_slot->tbl_addr = cpu_to_le32((u32)pp->cmd_tbl & 0xffffffff); -#ifdef CONFIG_PHYS_64BIT - pp->cmd_slot->tbl_addr_hi = - cpu_to_le32((u32)(((pp->cmd_tbl) >> 16) >> 16)); -#endif -} - -static int wait_spinup(void __iomem *port_mmio) -{ - ulong start; - u32 tf_data; - - start = get_timer(0); - do { - tf_data = readl(port_mmio + PORT_TFDATA); - if (!(tf_data & ATA_BUSY)) - return 0; - } while (get_timer(start) < WAIT_MS_SPINUP); - - return -ETIMEDOUT; -} - -static int ahci_port_start(u8 port) -{ - struct ahci_ioports *pp = &(probe_ent->port[port]); - void __iomem *port_mmio = pp->port_mmio; - u32 port_status; - void __iomem *mem; - - debug("Enter start port: %d\n", port); - port_status = readl(port_mmio + PORT_SCR_STAT); - debug("Port %d status: %x\n", port, port_status); - if ((port_status & 0xf) != 0x03) { - printf("No Link on this port!\n"); - return -1; - } - - mem = malloc(AHCI_PORT_PRIV_DMA_SZ + 2048); - if (!mem) { - free(pp); - printf("%s: No mem for table!\n", __func__); - return -ENOMEM; - } - - /* Aligned to 2048-bytes */ - mem = memalign(2048, AHCI_PORT_PRIV_DMA_SZ); - memset(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 *)(uintptr_t)virt_to_phys((void *)mem); - debug("cmd_slot = %p\n", pp->cmd_slot); - mem += (AHCI_CMD_SLOT_SZ + 224); - - /* - * Second item: Received-FIS area - */ - pp->rx_fis = virt_to_phys((void *)mem); - mem += AHCI_RX_FIS_SZ; - - /* - * Third item: data area for storing a single command - * and its scatter-gather table - */ - pp->cmd_tbl = virt_to_phys((void *)mem); - debug("cmd_tbl_dma = %lx\n", pp->cmd_tbl); - - mem += AHCI_CMD_TBL_HDR; - pp->cmd_tbl_sg = - (struct ahci_sg *)(uintptr_t)virt_to_phys((void *)mem); - - writel_with_flush((unsigned long)pp->cmd_slot, - port_mmio + PORT_LST_ADDR); - - writel_with_flush(pp->rx_fis, port_mmio + PORT_FIS_ADDR); - -#ifdef CONFIG_SUNXI_AHCI - sunxi_dma_init(port_mmio); -#endif - - writel_with_flush(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX | - PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP | - PORT_CMD_START, port_mmio + PORT_CMD); - - debug("Exit start port %d\n", port); - - /* - * Make sure interface is not busy based on error and status - * information from task file data register before proceeding - */ - return wait_spinup(port_mmio); -} - - -static int ahci_device_data_io(u8 port, u8 *fis, int fis_len, u8 *buf, - int buf_len, u8 is_write) -{ - - struct ahci_ioports *pp = &(probe_ent->port[port]); - void __iomem *port_mmio = pp->port_mmio; - u32 opts; - u32 port_status; - int sg_count; - - debug("Enter %s: for port %d\n", __func__, port); - - if (port > probe_ent->n_ports) { - printf("Invalid port number %d\n", port); - return -1; - } - - port_status = readl(port_mmio + PORT_SCR_STAT); - if ((port_status & 0xf) != 0x03) { - debug("No Link on port %d!\n", port); - return -1; - } - - memcpy((unsigned char *)pp->cmd_tbl, fis, fis_len); - - sg_count = ahci_fill_sg(port, buf, buf_len); - opts = (fis_len >> 2) | (sg_count << 16) | (is_write << 6); - ahci_fill_cmd_slot(pp, opts); - - ahci_dcache_flush_sata_cmd(pp); - ahci_dcache_flush_range((unsigned long)buf, (unsigned long)buf_len); - - writel_with_flush(1, port_mmio + PORT_CMD_ISSUE); - - if (waiting_for_cmd_completed(port_mmio + PORT_CMD_ISSUE, - WAIT_MS_DATAIO, 0x1)) { - printf("timeout exit!\n"); - return -1; - } - - ahci_dcache_invalidate_range((unsigned long)buf, - (unsigned long)buf_len); - debug("%s: %d byte transferred.\n", __func__, pp->cmd_slot->status); - - return 0; -} - - -static char *ata_id_strcpy(u16 *target, u16 *src, int len) -{ - int i; - for (i = 0; i < len / 2; i++) - target[i] = swab16(src[i]); - return (char *)target; -} - -/* - * SCSI INQUIRY command operation. - */ -static int ata_scsiop_inquiry(ccb *pccb) -{ - static const u8 hdr[] = { - 0, - 0, - 0x5, /* claim SPC-3 version compatibility */ - 2, - 95 - 4, - }; - u8 fis[20]; - u16 *idbuf; - ALLOC_CACHE_ALIGN_BUFFER(u16, tmpid, ATA_ID_WORDS); - u8 port; - - /* Clean ccb data buffer */ - memset(pccb->pdata, 0, pccb->datalen); - - memcpy(pccb->pdata, hdr, sizeof(hdr)); - - if (pccb->datalen <= 35) - return 0; - - memset(fis, 0, sizeof(fis)); - /* Construct the FIS */ - fis[0] = 0x27; /* Host to device FIS. */ - fis[1] = 1 << 7; /* Command FIS. */ - fis[2] = ATA_CMD_ID_ATA; /* Command byte. */ - - /* Read id from sata */ - port = pccb->target; - - if (ahci_device_data_io(port, (u8 *) &fis, sizeof(fis), (u8 *)tmpid, - ATA_ID_WORDS * 2, 0)) { - debug("scsi_ahci: SCSI inquiry command failure.\n"); - return -EIO; - } - - if (!ataid[port]) { - ataid[port] = malloc(ATA_ID_WORDS * 2); - if (!ataid[port]) { - printf("%s: No memory for ataid[port]\n", __func__); - return -ENOMEM; - } - } - - idbuf = ataid[port]; - - memcpy(idbuf, tmpid, ATA_ID_WORDS * 2); - ata_swap_buf_le16(idbuf, ATA_ID_WORDS); - - memcpy(&pccb->pdata[8], "ATA ", 8); - ata_id_strcpy((u16 *)&pccb->pdata[16], &idbuf[ATA_ID_PROD], 16); - ata_id_strcpy((u16 *)&pccb->pdata[32], &idbuf[ATA_ID_FW_REV], 4); - -#ifdef DEBUG - ata_dump_id(idbuf); -#endif - return 0; -} - - -/* - * SCSI READ10/WRITE10 command operation. - */ -static int ata_scsiop_read_write(ccb *pccb, u8 is_write) -{ - lbaint_t lba = 0; - u16 blocks = 0; - u8 fis[20]; - u8 *user_buffer = pccb->pdata; - u32 user_buffer_size = pccb->datalen; - - /* Retrieve the base LBA number from the ccb structure. */ - if (pccb->cmd[0] == SCSI_READ16) { - memcpy(&lba, pccb->cmd + 2, 8); - lba = be64_to_cpu(lba); - } else { - u32 temp; - memcpy(&temp, pccb->cmd + 2, 4); - lba = be32_to_cpu(temp); - } - - /* - * Retrieve the base LBA number and the block count from - * the ccb structure. - * - * For 10-byte and 16-byte SCSI R/W commands, transfer - * length 0 means transfer 0 block of data. - * However, for ATA R/W commands, sector count 0 means - * 256 or 65536 sectors, not 0 sectors as in SCSI. - * - * WARNING: one or two older ATA drives treat 0 as 0... - */ - if (pccb->cmd[0] == SCSI_READ16) - blocks = (((u16)pccb->cmd[13]) << 8) | ((u16) pccb->cmd[14]); - else - blocks = (((u16)pccb->cmd[7]) << 8) | ((u16) pccb->cmd[8]); - - debug("scsi_ahci: %s %u blocks starting from lba 0x" LBAFU "\n", - is_write ? "write" : "read", blocks, lba); - - /* Preset the FIS */ - memset(fis, 0, sizeof(fis)); - fis[0] = 0x27; /* Host to device FIS. */ - fis[1] = 1 << 7; /* Command FIS. */ - /* Command byte (read/write). */ - fis[2] = is_write ? ATA_CMD_WRITE_EXT : ATA_CMD_READ_EXT; - - while (blocks) { - u16 now_blocks; /* number of blocks per iteration */ - u32 transfer_size; /* number of bytes per iteration */ - - now_blocks = min((u16)MAX_SATA_BLOCKS_READ_WRITE, blocks); - - transfer_size = ATA_SECT_SIZE * now_blocks; - if (transfer_size > user_buffer_size) { - printf("scsi_ahci: Error: buffer too small.\n"); - return -EIO; - } - - /* - * LBA48 SATA command but only use 32bit address range within - * that (unless we've enabled 64bit LBA support). The next - * smaller command range (28bit) is too small. - */ - fis[4] = (lba >> 0) & 0xff; - fis[5] = (lba >> 8) & 0xff; - fis[6] = (lba >> 16) & 0xff; - fis[7] = 1 << 6; /* device reg: set LBA mode */ - fis[8] = ((lba >> 24) & 0xff); -#ifdef CONFIG_SYS_64BIT_LBA - if (pccb->cmd[0] == SCSI_READ16) { - fis[9] = ((lba >> 32) & 0xff); - fis[10] = ((lba >> 40) & 0xff); - } -#endif - - fis[3] = 0xe0; /* features */ - - /* Block (sector) count */ - fis[12] = (now_blocks >> 0) & 0xff; - fis[13] = (now_blocks >> 8) & 0xff; - - /* Read/Write from ahci */ - if (ahci_device_data_io(pccb->target, (u8 *) &fis, sizeof(fis), - user_buffer, transfer_size, - is_write)) { - debug("scsi_ahci: SCSI %s10 command failure.\n", - is_write ? "WRITE" : "READ"); - return -EIO; - } - - /* If this transaction is a write, do a following flush. - * Writes in u-boot are so rare, and the logic to know when is - * the last write and do a flush only there is sufficiently - * difficult. Just do a flush after every write. This incurs, - * usually, one extra flush when the rare writes do happen. - */ - if (is_write) { - if (-EIO == ata_io_flush(pccb->target)) - return -EIO; - } - user_buffer += transfer_size; - user_buffer_size -= transfer_size; - blocks -= now_blocks; - lba += now_blocks; - } - - return 0; -} - - -/* - * SCSI READ CAPACITY10 command operation. - */ -static int ata_scsiop_read_capacity10(ccb *pccb) -{ - u32 cap; - u64 cap64; - u32 block_size; - - if (!ataid[pccb->target]) { - printf("scsi_ahci: SCSI READ CAPACITY10 command failure. " - "\tNo ATA info!\n" - "\tPlease run SCSI command INQUIRY first!\n"); - return -EPERM; - } - - cap64 = ata_id_n_sectors(ataid[pccb->target]); - if (cap64 > 0x100000000ULL) - cap64 = 0xffffffff; - - cap = cpu_to_be32(cap64); - memcpy(pccb->pdata, &cap, sizeof(cap)); - - block_size = cpu_to_be32((u32)512); - memcpy(&pccb->pdata[4], &block_size, 4); - - return 0; -} - - -/* - * SCSI READ CAPACITY16 command operation. - */ -static int ata_scsiop_read_capacity16(ccb *pccb) -{ - u64 cap; - u64 block_size; - - if (!ataid[pccb->target]) { - printf("scsi_ahci: SCSI READ CAPACITY16 command failure. " - "\tNo ATA info!\n" - "\tPlease run SCSI command INQUIRY first!\n"); - return -EPERM; - } - - cap = ata_id_n_sectors(ataid[pccb->target]); - cap = cpu_to_be64(cap); - memcpy(pccb->pdata, &cap, sizeof(cap)); - - block_size = cpu_to_be64((u64)512); - memcpy(&pccb->pdata[8], &block_size, 8); - - return 0; -} - - -/* - * SCSI TEST UNIT READY command operation. - */ -static int ata_scsiop_test_unit_ready(ccb *pccb) -{ - return (ataid[pccb->target]) ? 0 : -EPERM; -} - - -int scsi_exec(ccb *pccb) -{ - int ret; - - switch (pccb->cmd[0]) { - case SCSI_READ16: - case SCSI_READ10: - ret = ata_scsiop_read_write(pccb, 0); - break; - case SCSI_WRITE10: - ret = ata_scsiop_read_write(pccb, 1); - break; - case SCSI_RD_CAPAC10: - ret = ata_scsiop_read_capacity10(pccb); - break; - case SCSI_RD_CAPAC16: - ret = ata_scsiop_read_capacity16(pccb); - break; - case SCSI_TST_U_RDY: - ret = ata_scsiop_test_unit_ready(pccb); - break; - case SCSI_INQUIRY: - ret = ata_scsiop_inquiry(pccb); - break; - default: - printf("Unsupport SCSI command 0x%02x\n", pccb->cmd[0]); - return false; - } - - if (ret) { - debug("SCSI command 0x%02x ret errno %d\n", pccb->cmd[0], ret); - return false; - } - return true; - -} - -#if defined(CONFIG_DM_SCSI) -void scsi_low_level_init(int busdevfunc, struct udevice *dev) -#else -void scsi_low_level_init(int busdevfunc) -#endif -{ - int i; - u32 linkmap; - -#ifndef CONFIG_SCSI_AHCI_PLAT -# if defined(CONFIG_DM_PCI) - struct udevice *dev; - int ret; - - ret = dm_pci_bus_find_bdf(busdevfunc, &dev); - if (ret) - return; - ahci_init_one(dev); -# elif defined(CONFIG_DM_SCSI) - ahci_init_one(dev); -# else - ahci_init_one(busdevfunc); -# endif -#endif - - linkmap = probe_ent->link_port_map; - - for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { - if (((linkmap >> i) & 0x01)) { - if (ahci_port_start((u8) i)) { - printf("Can not start port %d\n", i); - continue; - } - } - } -} - -#ifdef CONFIG_SCSI_AHCI_PLAT -int ahci_init(void __iomem *base) -{ - int i, rc = 0; - u32 linkmap; - - probe_ent = malloc(sizeof(struct ahci_probe_ent)); - if (!probe_ent) { - printf("%s: No memory for probe_ent\n", __func__); - return -ENOMEM; - } - - memset(probe_ent, 0, sizeof(struct ahci_probe_ent)); - - probe_ent->host_flags = ATA_FLAG_SATA - | ATA_FLAG_NO_LEGACY - | ATA_FLAG_MMIO - | ATA_FLAG_PIO_DMA - | ATA_FLAG_NO_ATAPI; - probe_ent->pio_mask = 0x1f; - probe_ent->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */ - - probe_ent->mmio_base = base; - - /* initialize adapter */ - rc = ahci_host_init(probe_ent); - if (rc) - goto err_out; - - ahci_print_info(probe_ent); - - linkmap = probe_ent->link_port_map; - - for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) { - if (((linkmap >> i) & 0x01)) { - if (ahci_port_start((u8) i)) { - printf("Can not start port %d\n", i); - continue; - } - } - } -err_out: - return rc; -} - -void __weak scsi_init(void) -{ -} - -#endif - -/* - * In the general case of generic rotating media it makes sense to have a - * flush capability. It probably even makes sense in the case of SSDs because - * one cannot always know for sure what kind of internal cache/flush mechanism - * is embodied therein. At first it was planned to invoke this after the last - * write to disk and before rebooting. In practice, knowing, a priori, which - * is the last write is difficult. Because writing to the disk in u-boot is - * very rare, this flush command will be invoked after every block write. - */ -static int ata_io_flush(u8 port) -{ - u8 fis[20]; - struct ahci_ioports *pp = &(probe_ent->port[port]); - void __iomem *port_mmio = pp->port_mmio; - u32 cmd_fis_len = 5; /* five dwords */ - - /* Preset the FIS */ - memset(fis, 0, 20); - fis[0] = 0x27; /* Host to device FIS. */ - fis[1] = 1 << 7; /* Command FIS. */ - fis[2] = ATA_CMD_FLUSH_EXT; - - memcpy((unsigned char *)pp->cmd_tbl, fis, 20); - ahci_fill_cmd_slot(pp, cmd_fis_len); - ahci_dcache_flush_sata_cmd(pp); - writel_with_flush(1, port_mmio + PORT_CMD_ISSUE); - - if (waiting_for_cmd_completed(port_mmio + PORT_CMD_ISSUE, - WAIT_MS_FLUSH, 0x1)) { - debug("scsi_ahci: flush command timeout on port %d.\n", port); - return -EIO; - } - - return 0; -} - - -__weak void scsi_bus_reset(void) -{ - /*Not implement*/ -} diff --git a/drivers/block/dwc_ahci.c b/drivers/block/dwc_ahci.c deleted file mode 100644 index 3f839bf987..0000000000 --- a/drivers/block/dwc_ahci.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * DWC SATA platform driver - * - * (C) Copyright 2016 - * Texas Instruments Incorporated, - * - * Author: Mugunthan V N - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -struct dwc_ahci_priv { - void *base; - void *wrapper_base; -}; - -static int dwc_ahci_ofdata_to_platdata(struct udevice *dev) -{ - struct dwc_ahci_priv *priv = dev_get_priv(dev); - struct scsi_platdata *plat = dev_get_platdata(dev); - fdt_addr_t addr; - - plat->max_id = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), - "max-id", CONFIG_SYS_SCSI_MAX_SCSI_ID); - plat->max_lun = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), - "max-lun", CONFIG_SYS_SCSI_MAX_LUN); - - priv->base = map_physmem(devfdt_get_addr(dev), sizeof(void *), - MAP_NOCACHE); - - addr = devfdt_get_addr_index(dev, 1); - if (addr != FDT_ADDR_T_NONE) { - priv->wrapper_base = map_physmem(addr, sizeof(void *), - MAP_NOCACHE); - } else { - priv->wrapper_base = NULL; - } - - return 0; -} - -static int dwc_ahci_probe(struct udevice *dev) -{ - struct dwc_ahci_priv *priv = dev_get_priv(dev); - int ret; - struct phy phy; - - ret = generic_phy_get_by_name(dev, "sata-phy", &phy); - if (ret) { - error("can't get the phy from DT\n"); - return ret; - } - - ret = generic_phy_init(&phy); - if (ret) { - error("unable to initialize the sata phy\n"); - return ret; - } - - ret = generic_phy_power_on(&phy); - if (ret) { - error("unable to power on the sata phy\n"); - return ret; - } - - if (priv->wrapper_base) { - u32 val = TI_SATA_IDLE_NO | TI_SATA_STANDBY_NO; - - /* Enable SATA module, No Idle, No Standby */ - writel(val, priv->wrapper_base + TI_SATA_SYSCONFIG); - } - - return ahci_init(priv->base); -} - -static const struct udevice_id dwc_ahci_ids[] = { - { .compatible = "snps,dwc-ahci" }, - { } -}; - -U_BOOT_DRIVER(dwc_ahci) = { - .name = "dwc_ahci", - .id = UCLASS_SCSI, - .of_match = dwc_ahci_ids, - .ofdata_to_platdata = dwc_ahci_ofdata_to_platdata, - .probe = dwc_ahci_probe, - .priv_auto_alloc_size = sizeof(struct dwc_ahci_priv), - .platdata_auto_alloc_size = sizeof(struct scsi_platdata), - .flags = DM_FLAG_ALLOC_PRIV_DMA, -}; diff --git a/drivers/block/dwc_ahsata.c b/drivers/block/dwc_ahsata.c deleted file mode 100644 index c306e927db..0000000000 --- a/drivers/block/dwc_ahsata.c +++ /dev/null @@ -1,1018 +0,0 @@ -/* - * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. - * Terry Lv - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include "dwc_ahsata.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 int is_ready; - -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_probe_ent *probe_ent, - int clk) -{ - struct sata_host_regs *host_mmio = - (struct sata_host_regs *)probe_ent->mmio_base; - - writel(SATA_HOST_OOBR_WE, &(host_mmio->oobr)); - writel(0x02060b14, &(host_mmio->oobr)); - - return 0; -} - -static int ahci_host_init(struct ahci_probe_ent *probe_ent) -{ - u32 tmp, cap_save, num_ports; - int i, j, timeout = 1000; - struct sata_port_regs *port_mmio = NULL; - struct sata_host_regs *host_mmio = - (struct sata_host_regs *)probe_ent->mmio_base; - int clk = mxc_get_clock(MXC_SATA_CLK); - - cap_save = readl(&(host_mmio->cap)); - cap_save |= SATA_HOST_CAP_SSS; - - /* global controller reset */ - tmp = readl(&(host_mmio->ghc)); - if ((tmp & SATA_HOST_GHC_HR) == 0) - writel_with_flush(tmp | SATA_HOST_GHC_HR, &(host_mmio->ghc)); - - while ((readl(&(host_mmio->ghc)) & SATA_HOST_GHC_HR) - && --timeout) - ; - - if (timeout <= 0) { - debug("controller reset failed (0x%x)\n", tmp); - return -1; - } - - /* Set timer 1ms */ - writel(clk / 1000, &(host_mmio->timer1ms)); - - ahci_setup_oobr(probe_ent, 0); - - writel_with_flush(SATA_HOST_GHC_AE, &(host_mmio->ghc)); - writel(cap_save, &(host_mmio->cap)); - num_ports = (cap_save & SATA_HOST_CAP_NP_MASK) + 1; - 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. - */ - probe_ent->cap = readl(&(host_mmio->cap)); - probe_ent->port_map = readl(&(host_mmio->pi)); - - /* Determine how many command slots the HBA supports */ - probe_ent->n_ports = - (probe_ent->cap & SATA_HOST_CAP_NP_MASK) + 1; - - debug("cap 0x%x port_map 0x%x n_ports %d\n", - probe_ent->cap, probe_ent->port_map, probe_ent->n_ports); - - for (i = 0; i < probe_ent->n_ports; i++) { - probe_ent->port[i].port_mmio = - ahci_port_base(host_mmio, i); - port_mmio = - (struct sata_port_regs *)probe_ent->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) - probe_ent->link_port_map |= (0x01 << i); - } - - tmp = readl(&(host_mmio->ghc)); - debug("GHC 0x%x\n", tmp); - writel(tmp | SATA_HOST_GHC_IE, &(host_mmio->ghc)); - tmp = readl(&(host_mmio->ghc)); - debug("GHC 0x%x\n", tmp); - - return 0; -} - -static void ahci_print_info(struct ahci_probe_ent *probe_ent) -{ - struct sata_host_regs *host_mmio = - (struct sata_host_regs *)probe_ent->mmio_base; - u32 vers, cap, impl, speed; - const char *speed_s; - const char *scc_s; - - vers = readl(&(host_mmio->vs)); - cap = probe_ent->cap; - impl = probe_ent->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"; - - printf("AHCI %02x%02x.%02x%02x " - "%u slots %u ports %s Gbps 0x%x impl %s mode\n", - (vers >> 24) & 0xff, - (vers >> 16) & 0xff, - (vers >> 8) & 0xff, - vers & 0xff, - ((cap >> 8) & 0x1f) + 1, - (cap & 0x1f) + 1, - speed_s, - impl, - scc_s); - - printf("flags: " - "%s%s%s%s%s%s" - "%s%s%s%s%s%s%s\n", - cap & (1 << 31) ? "64bit " : "", - cap & (1 << 30) ? "ncq " : "", - cap & (1 << 28) ? "ilck " : "", - cap & (1 << 27) ? "stag " : "", - cap & (1 << 26) ? "pm " : "", - cap & (1 << 25) ? "led " : "", - cap & (1 << 24) ? "clo " : "", - cap & (1 << 19) ? "nz " : "", - cap & (1 << 18) ? "only " : "", - cap & (1 << 17) ? "pmp " : "", - cap & (1 << 15) ? "pio " : "", - cap & (1 << 14) ? "slum " : "", - cap & (1 << 13) ? "part " : ""); -} - -static int ahci_init_one(int pdev) -{ - int rc; - struct ahci_probe_ent *probe_ent = NULL; - - probe_ent = malloc(sizeof(struct ahci_probe_ent)); - memset(probe_ent, 0, sizeof(struct ahci_probe_ent)); - probe_ent->dev = pdev; - - probe_ent->host_flags = ATA_FLAG_SATA - | ATA_FLAG_NO_LEGACY - | ATA_FLAG_MMIO - | ATA_FLAG_PIO_DMA - | ATA_FLAG_NO_ATAPI; - - probe_ent->mmio_base = (void __iomem *)CONFIG_DWC_AHSATA_BASE_ADDR; - - /* initialize adapter */ - rc = ahci_host_init(probe_ent); - if (rc) - goto err_out; - - ahci_print_info(probe_ent); - - /* Save the private struct to block device struct */ - sata_dev_desc[pdev].priv = (void *)probe_ent; - - return 0; - -err_out: - return rc; -} - -static int ahci_fill_sg(struct ahci_probe_ent *probe_ent, - u8 port, unsigned char *buf, int buf_len) -{ - struct ahci_ioports *pp = &(probe_ent->port[port]); - struct ahci_sg *ahci_sg = pp->cmd_tbl_sg; - u32 sg_count, 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) { - printf("Error:Too much sg!\n"); - return -1; - } - - for (i = 0; i < sg_count; i++) { - ahci_sg->addr = - cpu_to_le32((u32)buf + i * max_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 = cpu_to_le32((u32)pp->cmd_tbl & 0xffffffff); -#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_probe_ent *probe_ent, - u8 port, struct sata_fis_h2d *cfis, - u8 *buf, u32 buf_len, s32 is_write) -{ - struct ahci_ioports *pp = &(probe_ent->port[port]); - struct sata_port_regs *port_mmio = - (struct sata_port_regs *)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) { - printf("Can't find empty command slot!\n"); - return 0; - } - - /* Check xfer length */ - if (buf_len > MAX_BYTES_PER_TRANS) { - printf("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(probe_ent, 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)) { - printf("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(u8 dev, u8 port) -{ - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - 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(probe_ent->udma_mask + 1) + 0x3e; - - ahci_exec_ata_cmd(probe_ent, port, cfis, NULL, 0, READ_CMD); -} - -static int ahci_port_start(struct ahci_probe_ent *probe_ent, - u8 port) -{ - struct ahci_ioports *pp = &(probe_ent->port[port]); - struct sata_port_regs *port_mmio = - (struct sata_port_regs *)pp->port_mmio; - u32 port_status; - u32 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) { - printf("No Link on this port!\n"); - return -1; - } - - mem = (u32)malloc(AHCI_PORT_PRIV_DMA_SZ + 1024); - if (!mem) { - free(pp); - printf("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%x\n", (unsigned int) 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((u32)pp->cmd_slot, &(port_mmio->clb)); - writel_with_flush(pp->rx_fis, &(port_mmio->fb)); - - /* 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; -} - -int init_sata(int dev) -{ - int i; - u32 linkmap; - struct ahci_probe_ent *probe_ent = NULL; - -#if defined(CONFIG_MX6) - if (!is_mx6dq() && !is_mx6dqp()) - return 1; -#endif - if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) { - printf("The sata index %d is out of ranges\n\r", dev); - return -1; - } - - ahci_init_one(dev); - - probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - linkmap = probe_ent->link_port_map; - - if (0 == linkmap) { - printf("No port device detected!\n"); - return 1; - } - - for (i = 0; i < probe_ent->n_ports; i++) { - if ((linkmap >> i) && ((linkmap >> i) & 0x01)) { - if (ahci_port_start(probe_ent, (u8)i)) { - printf("Can not start port %d\n", i); - return 1; - } - probe_ent->hard_port_no = i; - break; - } - } - - return 0; -} - -int reset_sata(int dev) -{ - struct ahci_probe_ent *probe_ent; - struct sata_host_regs *host_mmio; - - if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) { - printf("The sata index %d is out of ranges\n\r", dev); - return -1; - } - - probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - if (NULL == probe_ent) - /* not initialized, so nothing to reset */ - return 0; - - host_mmio = (struct sata_host_regs *)probe_ent->mmio_base; - setbits_le32(&host_mmio->ghc, SATA_HOST_GHC_HR); - while (readl(&host_mmio->ghc) & SATA_HOST_GHC_HR) - udelay(100); - - return 0; -} - -static void dwc_ahsata_print_info(int dev) -{ - struct blk_desc *pdev = &(sata_dev_desc[dev]); - - printf("SATA Device Info:\n\r"); -#ifdef CONFIG_SYS_64BIT_LBA - printf("S/N: %s\n\rProduct model number: %s\n\r" - "Firmware version: %s\n\rCapacity: %lld sectors\n\r", - pdev->product, pdev->vendor, pdev->revision, pdev->lba); -#else - printf("S/N: %s\n\rProduct model number: %s\n\r" - "Firmware version: %s\n\rCapacity: %ld sectors\n\r", - pdev->product, pdev->vendor, pdev->revision, pdev->lba); -#endif -} - -static void dwc_ahsata_identify(int dev, u16 *id) -{ - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); - struct sata_fis_h2d *cfis = &h2d; - u8 port = probe_ent->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(probe_ent, port, cfis, - (u8 *)id, ATA_ID_WORDS * 2, READ_CMD); - ata_swap_buf_le16(id, ATA_ID_WORDS); -} - -static void dwc_ahsata_xfer_mode(int dev, u16 *id) -{ - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - - probe_ent->pio_mask = id[ATA_ID_PIO_MODES]; - probe_ent->udma_mask = id[ATA_ID_UDMA_MODES]; - debug("pio %04x, udma %04x\n\r", - probe_ent->pio_mask, probe_ent->udma_mask); -} - -static u32 dwc_ahsata_rw_cmd(int dev, u32 start, u32 blkcnt, - u8 *buffer, int is_write) -{ - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); - struct sata_fis_h2d *cfis = &h2d; - u8 port = probe_ent->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(probe_ent, port, cfis, - buffer, ATA_SECT_SIZE * blkcnt, is_write) > 0) - return blkcnt; - else - return 0; -} - -void dwc_ahsata_flush_cache(int dev) -{ - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); - struct sata_fis_h2d *cfis = &h2d; - u8 port = probe_ent->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(probe_ent, port, cfis, NULL, 0, 0); -} - -static u32 dwc_ahsata_rw_cmd_ext(int dev, u32 start, lbaint_t blkcnt, - u8 *buffer, int is_write) -{ - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); - struct sata_fis_h2d *cfis = &h2d; - u8 port = probe_ent->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(probe_ent, port, cfis, buffer, - ATA_SECT_SIZE * blkcnt, is_write) > 0) - return blkcnt; - else - return 0; -} - -u32 dwc_ahsata_rw_ncq_cmd(int dev, u32 start, lbaint_t blkcnt, - u8 *buffer, int is_write) -{ - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); - struct sata_fis_h2d *cfis = &h2d; - u8 port = probe_ent->hard_port_no; - u64 block; - - if (sata_dev_desc[dev].lba48 != 1) { - printf("execute FPDMA command on non-LBA48 hard disk\n\r"); - return -1; - } - - block = (u64)start; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - - cfis->command = (is_write) ? ATA_CMD_FPDMA_WRITE - : ATA_CMD_FPDMA_READ; - - cfis->lba_high_exp = (block >> 40) & 0xff; - cfis->lba_mid_exp = (block >> 32) & 0xff; - cfis->lba_low_exp = (block >> 24) & 0xff; - cfis->lba_high = (block >> 16) & 0xff; - cfis->lba_mid = (block >> 8) & 0xff; - cfis->lba_low = block & 0xff; - - cfis->device = ATA_LBA; - cfis->features_exp = (blkcnt >> 8) & 0xff; - cfis->features = blkcnt & 0xff; - - /* Use the latest queue */ - ahci_exec_ata_cmd(probe_ent, port, cfis, - buffer, ATA_SECT_SIZE * blkcnt, is_write); - - return blkcnt; -} - -void dwc_ahsata_flush_cache_ext(int dev) -{ - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); - struct sata_fis_h2d *cfis = &h2d; - u8 port = probe_ent->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(probe_ent, port, cfis, NULL, 0, 0); -} - -static void dwc_ahsata_init_wcache(int dev, u16 *id) -{ - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - - if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id)) - probe_ent->flags |= SATA_FLAG_WCACHE; - if (ata_id_has_flush(id)) - probe_ent->flags |= SATA_FLAG_FLUSH; - if (ata_id_has_flush_ext(id)) - probe_ent->flags |= SATA_FLAG_FLUSH_EXT; -} - -u32 ata_low_level_rw_lba48(int dev, 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(dev, 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(dev, start, - blks, addr, is_write)) - return 0; - start += blks; - blks = 0; - addr += ATA_SECT_SIZE * blks; - } - } while (blks != 0); - - return blkcnt; -} - -u32 ata_low_level_rw_lba28(int dev, 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(dev, 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(dev, start, - blks, addr, is_write)) - return 0; - start += blks; - blks = 0; - addr += ATA_SECT_SIZE * blks; - } - } while (blks != 0); - - return blkcnt; -} - -int sata_port_status(int dev, int port) -{ - struct sata_port_regs *port_mmio; - struct ahci_probe_ent *probe_ent = NULL; - - if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) - return -EINVAL; - - if (sata_dev_desc[dev].priv == NULL) - return -ENODEV; - - probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - port_mmio = (struct sata_port_regs *)probe_ent->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) -{ - u32 rc; - - if (sata_dev_desc[dev].lba48) - rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, - buffer, READ_CMD); - else - rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, - buffer, READ_CMD); - return rc; -} - -ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) -{ - u32 rc; - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - u32 flags = probe_ent->flags; - - if (sata_dev_desc[dev].lba48) { - rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, - buffer, WRITE_CMD); - if ((flags & SATA_FLAG_WCACHE) && - (flags & SATA_FLAG_FLUSH_EXT)) - dwc_ahsata_flush_cache_ext(dev); - } else { - rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, - buffer, WRITE_CMD); - if ((flags & SATA_FLAG_WCACHE) && - (flags & SATA_FLAG_FLUSH)) - dwc_ahsata_flush_cache(dev); - } - return rc; -} - -int scan_sata(int dev) -{ - 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 }; - u16 *id; - u64 n_sectors; - struct ahci_probe_ent *probe_ent = - (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - u8 port = probe_ent->hard_port_no; - struct blk_desc *pdev = &(sata_dev_desc[dev]); - - id = (u16 *)memalign(ARCH_DMA_MINALIGN, - roundup(ARCH_DMA_MINALIGN, - (ATA_ID_WORDS * 2))); - if (!id) { - printf("id malloc failed\n\r"); - return -1; - } - - /* Identify device to get information */ - dwc_ahsata_identify(dev, 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)); - - /* Totoal sectors */ - n_sectors = ata_id_n_sectors(id); - pdev->lba = (u32)n_sectors; - - 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 */ - probe_ent->flags &= (~SATA_FLAG_Q_DEP_MASK); - probe_ent->flags |= ata_id_queue_depth(id); - - /* Get the xfer mode from device */ - dwc_ahsata_xfer_mode(dev, id); - - /* Get the write cache status from device */ - dwc_ahsata_init_wcache(dev, id); - - /* Set the xfer mode to highest speed */ - ahci_set_feature(dev, port); - - free((void *)id); - - dwc_ahsata_print_info(dev); - - is_ready = 1; - - return 0; -} diff --git a/drivers/block/dwc_ahsata.h b/drivers/block/dwc_ahsata.h deleted file mode 100644 index caa2e501f9..0000000000 --- a/drivers/block/dwc_ahsata.h +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (C) 2010 Freescale Semiconductor, Inc. - * Terry Lv - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef __FSL_SATA_H__ -#define __FSL_SATA_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 /* __FSL_SATA_H__ */ diff --git a/drivers/block/fsl_sata.c b/drivers/block/fsl_sata.c deleted file mode 100644 index 31f7fab8b4..0000000000 --- a/drivers/block/fsl_sata.c +++ /dev/null @@ -1,854 +0,0 @@ -/* - * Copyright (C) 2008,2010 Freescale Semiconductor, Inc. - * Dave Liu - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "fsl_sata.h" - -#ifndef CONFIG_SYS_SATA1_FLAGS - #define CONFIG_SYS_SATA1_FLAGS FLAGS_DMA -#endif -#ifndef CONFIG_SYS_SATA2_FLAGS - #define CONFIG_SYS_SATA2_FLAGS FLAGS_DMA -#endif - -static struct fsl_sata_info fsl_sata_info[] = { -#ifdef CONFIG_SATA1 - {CONFIG_SYS_SATA1, CONFIG_SYS_SATA1_FLAGS}, -#else - {0, 0}, -#endif -#ifdef CONFIG_SATA2 - {CONFIG_SYS_SATA2, CONFIG_SYS_SATA2_FLAGS}, -#else - {0, 0}, -#endif -}; - -static inline void sdelay(unsigned long sec) -{ - unsigned long i; - for (i = 0; i < sec; i++) - mdelay(1000); -} - -static void fsl_sata_dump_sfis(struct sata_fis_d2h *s) -{ - printf("Status FIS dump:\n\r"); - printf("fis_type: %02x\n\r", s->fis_type); - printf("pm_port_i: %02x\n\r", s->pm_port_i); - printf("status: %02x\n\r", s->status); - printf("error: %02x\n\r", s->error); - printf("lba_low: %02x\n\r", s->lba_low); - printf("lba_mid: %02x\n\r", s->lba_mid); - printf("lba_high: %02x\n\r", s->lba_high); - printf("device: %02x\n\r", s->device); - printf("lba_low_exp: %02x\n\r", s->lba_low_exp); - printf("lba_mid_exp: %02x\n\r", s->lba_mid_exp); - printf("lba_high_exp: %02x\n\r", s->lba_high_exp); - printf("res1: %02x\n\r", s->res1); - printf("sector_count: %02x\n\r", s->sector_count); - printf("sector_count_exp: %02x\n\r", s->sector_count_exp); -} - -static int ata_wait_register(unsigned __iomem *addr, u32 mask, - u32 val, u32 timeout_msec) -{ - int i; - u32 temp; - - for (i = 0; (((temp = in_le32(addr)) & mask) != val) - && i < timeout_msec; i++) - mdelay(1); - return (i < timeout_msec) ? 0 : -1; -} - -int init_sata(int dev) -{ - u32 length, align; - cmd_hdr_tbl_t *cmd_hdr; - u32 cda; - u32 val32; - fsl_sata_reg_t __iomem *reg; - u32 sig; - int i; - fsl_sata_t *sata; - - if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) { - printf("the sata index %d is out of ranges\n\r", dev); - return -1; - } - -#ifdef CONFIG_MPC85xx - if ((dev == 0) && (!is_serdes_configured(SATA1))) { - printf("SATA%d [dev = %d] is not enabled\n", dev+1, dev); - return -1; - } - if ((dev == 1) && (!is_serdes_configured(SATA2))) { - printf("SATA%d [dev = %d] is not enabled\n", dev+1, dev); - return -1; - } -#endif - - /* Allocate SATA device driver struct */ - sata = (fsl_sata_t *)malloc(sizeof(fsl_sata_t)); - if (!sata) { - printf("alloc the sata device struct failed\n\r"); - return -1; - } - /* Zero all of the device driver struct */ - memset((void *)sata, 0, sizeof(fsl_sata_t)); - - /* Save the private struct to block device struct */ - sata_dev_desc[dev].priv = (void *)sata; - - snprintf(sata->name, 12, "SATA%d", dev); - - /* Set the controller register base address to device struct */ - reg = (fsl_sata_reg_t *)(fsl_sata_info[dev].sata_reg_base); - sata->reg_base = reg; - - /* Allocate the command header table, 4 bytes aligned */ - length = sizeof(struct cmd_hdr_tbl); - align = SATA_HC_CMD_HDR_TBL_ALIGN; - sata->cmd_hdr_tbl_offset = (void *)malloc(length + align); - if (!sata->cmd_hdr_tbl_offset) { - printf("alloc the command header failed\n\r"); - return -1; - } - - cmd_hdr = (cmd_hdr_tbl_t *)(((u32)sata->cmd_hdr_tbl_offset + align) - & ~(align - 1)); - sata->cmd_hdr = cmd_hdr; - - /* Zero all of the command header table */ - memset((void *)sata->cmd_hdr_tbl_offset, 0, length + align); - - /* Allocate command descriptor for all command */ - length = sizeof(struct cmd_desc) * SATA_HC_MAX_CMD; - align = SATA_HC_CMD_DESC_ALIGN; - sata->cmd_desc_offset = (void *)malloc(length + align); - if (!sata->cmd_desc_offset) { - printf("alloc the command descriptor failed\n\r"); - return -1; - } - sata->cmd_desc = (cmd_desc_t *)(((u32)sata->cmd_desc_offset + align) - & ~(align - 1)); - /* Zero all of command descriptor */ - memset((void *)sata->cmd_desc_offset, 0, length + align); - - /* Link the command descriptor to command header */ - for (i = 0; i < SATA_HC_MAX_CMD; i++) { - cda = ((u32)sata->cmd_desc + SATA_HC_CMD_DESC_SIZE * i) - & ~(CMD_HDR_CDA_ALIGN - 1); - cmd_hdr->cmd_slot[i].cda = cpu_to_le32(cda); - } - - /* To have safe state, force the controller offline */ - val32 = in_le32(®->hcontrol); - val32 &= ~HCONTROL_ONOFF; - val32 |= HCONTROL_FORCE_OFFLINE; - out_le32(®->hcontrol, val32); - - /* Wait the controller offline */ - ata_wait_register(®->hstatus, HSTATUS_ONOFF, 0, 1000); - - /* Set the command header base address to CHBA register to tell DMA */ - out_le32(®->chba, (u32)cmd_hdr & ~0x3); - - /* Snoop for the command header */ - val32 = in_le32(®->hcontrol); - val32 |= HCONTROL_HDR_SNOOP; - out_le32(®->hcontrol, val32); - - /* Disable all of interrupts */ - val32 = in_le32(®->hcontrol); - val32 &= ~HCONTROL_INT_EN_ALL; - out_le32(®->hcontrol, val32); - - /* Clear all of interrupts */ - val32 = in_le32(®->hstatus); - out_le32(®->hstatus, val32); - - /* Set the ICC, no interrupt coalescing */ - out_le32(®->icc, 0x01000000); - - /* No PM attatched, the SATA device direct connect */ - out_le32(®->cqpmp, 0); - - /* Clear SError register */ - val32 = in_le32(®->serror); - out_le32(®->serror, val32); - - /* Clear CER register */ - val32 = in_le32(®->cer); - out_le32(®->cer, val32); - - /* Clear DER register */ - val32 = in_le32(®->der); - out_le32(®->der, val32); - - /* No device detection or initialization action requested */ - out_le32(®->scontrol, 0x00000300); - - /* Configure the transport layer, default value */ - out_le32(®->transcfg, 0x08000016); - - /* Configure the link layer, default value */ - out_le32(®->linkcfg, 0x0000ff34); - - /* Bring the controller online */ - val32 = in_le32(®->hcontrol); - val32 |= HCONTROL_ONOFF; - out_le32(®->hcontrol, val32); - - mdelay(100); - - /* print sata device name */ - if (!dev) - printf("%s ", sata->name); - else - printf(" %s ", sata->name); - - /* Wait PHY RDY signal changed for 500ms */ - ata_wait_register(®->hstatus, HSTATUS_PHY_RDY, - HSTATUS_PHY_RDY, 500); - - /* Check PHYRDY */ - val32 = in_le32(®->hstatus); - if (val32 & HSTATUS_PHY_RDY) { - sata->link = 1; - } else { - sata->link = 0; - printf("(No RDY)\n\r"); - return -1; - } - - /* Wait for signature updated, which is 1st D2H */ - ata_wait_register(®->hstatus, HSTATUS_SIGNATURE, - HSTATUS_SIGNATURE, 10000); - - if (val32 & HSTATUS_SIGNATURE) { - sig = in_le32(®->sig); - debug("Signature updated, the sig =%08x\n\r", sig); - sata->ata_device_type = ata_dev_classify(sig); - } - - /* Check the speed */ - val32 = in_le32(®->sstatus); - if ((val32 & SSTATUS_SPD_MASK) == SSTATUS_SPD_GEN1) - printf("(1.5 Gbps)\n\r"); - else if ((val32 & SSTATUS_SPD_MASK) == SSTATUS_SPD_GEN2) - printf("(3 Gbps)\n\r"); - - return 0; -} - -int reset_sata(int dev) -{ - return 0; -} - -static void fsl_sata_dump_regs(fsl_sata_reg_t __iomem *reg) -{ - printf("\n\rSATA: %08x\n\r", (u32)reg); - printf("CQR: %08x\n\r", in_le32(®->cqr)); - printf("CAR: %08x\n\r", in_le32(®->car)); - printf("CCR: %08x\n\r", in_le32(®->ccr)); - printf("CER: %08x\n\r", in_le32(®->cer)); - printf("CQR: %08x\n\r", in_le32(®->cqr)); - printf("DER: %08x\n\r", in_le32(®->der)); - printf("CHBA: %08x\n\r", in_le32(®->chba)); - printf("HStatus: %08x\n\r", in_le32(®->hstatus)); - printf("HControl: %08x\n\r", in_le32(®->hcontrol)); - printf("CQPMP: %08x\n\r", in_le32(®->cqpmp)); - printf("SIG: %08x\n\r", in_le32(®->sig)); - printf("ICC: %08x\n\r", in_le32(®->icc)); - printf("SStatus: %08x\n\r", in_le32(®->sstatus)); - printf("SError: %08x\n\r", in_le32(®->serror)); - printf("SControl: %08x\n\r", in_le32(®->scontrol)); - printf("SNotification: %08x\n\r", in_le32(®->snotification)); - printf("TransCfg: %08x\n\r", in_le32(®->transcfg)); - printf("TransStatus: %08x\n\r", in_le32(®->transstatus)); - printf("LinkCfg: %08x\n\r", in_le32(®->linkcfg)); - printf("LinkCfg1: %08x\n\r", in_le32(®->linkcfg1)); - printf("LinkCfg2: %08x\n\r", in_le32(®->linkcfg2)); - printf("LinkStatus: %08x\n\r", in_le32(®->linkstatus)); - printf("LinkStatus1: %08x\n\r", in_le32(®->linkstatus1)); - printf("PhyCtrlCfg: %08x\n\r", in_le32(®->phyctrlcfg)); - printf("SYSPR: %08x\n\r", in_be32(®->syspr)); -} - -static int fsl_ata_exec_ata_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis, - int is_ncq, int tag, u8 *buffer, u32 len) -{ - cmd_hdr_entry_t *cmd_hdr; - cmd_desc_t *cmd_desc; - sata_fis_h2d_t *h2d; - prd_entry_t *prde; - u32 ext_c_ddc; - u32 prde_count; - u32 val32; - u32 ttl; - fsl_sata_reg_t __iomem *reg = sata->reg_base; - int i; - - /* Check xfer length */ - if (len > SATA_HC_MAX_XFER_LEN) { - printf("max transfer length is 64MB\n\r"); - return 0; - } - - /* Setup the command descriptor */ - cmd_desc = sata->cmd_desc + tag; - - /* Get the pointer cfis of command descriptor */ - h2d = (sata_fis_h2d_t *)cmd_desc->cfis; - - /* Zero the cfis of command descriptor */ - memset((void *)h2d, 0, SATA_HC_CMD_DESC_CFIS_SIZE); - - /* Copy the cfis from user to command descriptor */ - h2d->fis_type = cfis->fis_type; - h2d->pm_port_c = cfis->pm_port_c; - h2d->command = cfis->command; - - h2d->features = cfis->features; - h2d->features_exp = cfis->features_exp; - - h2d->lba_low = cfis->lba_low; - h2d->lba_mid = cfis->lba_mid; - h2d->lba_high = cfis->lba_high; - h2d->lba_low_exp = cfis->lba_low_exp; - h2d->lba_mid_exp = cfis->lba_mid_exp; - h2d->lba_high_exp = cfis->lba_high_exp; - - if (!is_ncq) { - h2d->sector_count = cfis->sector_count; - h2d->sector_count_exp = cfis->sector_count_exp; - } else { /* NCQ */ - h2d->sector_count = (u8)(tag << 3); - } - - h2d->device = cfis->device; - h2d->control = cfis->control; - - /* Setup the PRD table */ - prde = (prd_entry_t *)cmd_desc->prdt; - memset((void *)prde, 0, sizeof(struct prdt)); - - prde_count = 0; - ttl = len; - for (i = 0; i < SATA_HC_MAX_PRD_DIRECT; i++) { - if (!len) - break; - prde->dba = cpu_to_le32((u32)buffer & ~0x3); - debug("dba = %08x\n\r", (u32)buffer); - - if (len < PRD_ENTRY_MAX_XFER_SZ) { - ext_c_ddc = PRD_ENTRY_DATA_SNOOP | len; - debug("ext_c_ddc1 = %08x, len = %08x\n\r", ext_c_ddc, len); - prde->ext_c_ddc = cpu_to_le32(ext_c_ddc); - prde_count++; - prde++; - break; - } else { - ext_c_ddc = PRD_ENTRY_DATA_SNOOP; /* 4M bytes */ - debug("ext_c_ddc2 = %08x, len = %08x\n\r", ext_c_ddc, len); - prde->ext_c_ddc = cpu_to_le32(ext_c_ddc); - buffer += PRD_ENTRY_MAX_XFER_SZ; - len -= PRD_ENTRY_MAX_XFER_SZ; - prde_count++; - prde++; - } - } - - /* Setup the command slot of cmd hdr */ - cmd_hdr = (cmd_hdr_entry_t *)&sata->cmd_hdr->cmd_slot[tag]; - - cmd_hdr->cda = cpu_to_le32((u32)cmd_desc & ~0x3); - - val32 = prde_count << CMD_HDR_PRD_ENTRY_SHIFT; - val32 |= sizeof(sata_fis_h2d_t); - cmd_hdr->prde_fis_len = cpu_to_le32(val32); - - cmd_hdr->ttl = cpu_to_le32(ttl); - - if (!is_ncq) { - val32 = CMD_HDR_ATTR_RES | CMD_HDR_ATTR_SNOOP; - } else { - val32 = CMD_HDR_ATTR_RES | CMD_HDR_ATTR_SNOOP | CMD_HDR_ATTR_FPDMA; - } - - tag &= CMD_HDR_ATTR_TAG; - val32 |= tag; - - debug("attribute = %08x\n\r", val32); - cmd_hdr->attribute = cpu_to_le32(val32); - - /* Make sure cmd desc and cmd slot valid before command issue */ - sync(); - - /* PMP*/ - val32 = (u32)(h2d->pm_port_c & 0x0f); - out_le32(®->cqpmp, val32); - - /* Wait no active */ - if (ata_wait_register(®->car, (1 << tag), 0, 10000)) - printf("Wait no active time out\n\r"); - - /* Issue command */ - if (!(in_le32(®->cqr) & (1 << tag))) { - val32 = 1 << tag; - out_le32(®->cqr, val32); - } - - /* Wait command completed for 10s */ - if (ata_wait_register(®->ccr, (1 << tag), (1 << tag), 10000)) { - if (!is_ncq) - printf("Non-NCQ command time out\n\r"); - else - printf("NCQ command time out\n\r"); - } - - val32 = in_le32(®->cer); - - if (val32) { - u32 der; - fsl_sata_dump_sfis((struct sata_fis_d2h *)cmd_desc->sfis); - printf("CE at device\n\r"); - fsl_sata_dump_regs(reg); - der = in_le32(®->der); - out_le32(®->cer, val32); - out_le32(®->der, der); - } - - /* Clear complete flags */ - val32 = in_le32(®->ccr); - out_le32(®->ccr, val32); - - return len; -} - -static int fsl_ata_exec_reset_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis, - int tag, u8 *buffer, u32 len) -{ - return 0; -} - -static int fsl_sata_exec_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis, - enum cmd_type command_type, int tag, u8 *buffer, u32 len) -{ - int rc; - - if (tag > SATA_HC_MAX_CMD || tag < 0) { - printf("tag is out of range, tag=%d\n\r", tag); - return -1; - } - - switch (command_type) { - case CMD_ATA: - rc = fsl_ata_exec_ata_cmd(sata, cfis, 0, tag, buffer, len); - return rc; - case CMD_RESET: - rc = fsl_ata_exec_reset_cmd(sata, cfis, tag, buffer, len); - return rc; - case CMD_NCQ: - rc = fsl_ata_exec_ata_cmd(sata, cfis, 1, tag, buffer, len); - return rc; - case CMD_ATAPI: - case CMD_VENDOR_BIST: - case CMD_BIST: - printf("not support now\n\r"); - return -1; - default: - break; - } - - return -1; -} - -static void fsl_sata_identify(int dev, u16 *id) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - cfis->command = ATA_CMD_ID_ATA; - - fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, (u8 *)id, ATA_ID_WORDS * 2); - ata_swap_buf_le16(id, ATA_ID_WORDS); -} - -static void fsl_sata_xfer_mode(int dev, u16 *id) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - - sata->pio = id[ATA_ID_PIO_MODES]; - sata->mwdma = id[ATA_ID_MWDMA_MODES]; - sata->udma = id[ATA_ID_UDMA_MODES]; - debug("pio %04x, mwdma %04x, udma %04x\n\r", sata->pio, sata->mwdma, sata->udma); -} - -static void fsl_sata_set_features(int dev) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; - u8 udma_cap; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - cfis->command = ATA_CMD_SET_FEATURES; - cfis->features = SETFEATURES_XFER; - - /* First check the device capablity */ - udma_cap = (u8)(sata->udma & 0xff); - debug("udma_cap %02x\n\r", udma_cap); - - if (udma_cap == ATA_UDMA6) - cfis->sector_count = XFER_UDMA_6; - if (udma_cap == ATA_UDMA5) - cfis->sector_count = XFER_UDMA_5; - if (udma_cap == ATA_UDMA4) - cfis->sector_count = XFER_UDMA_4; - if (udma_cap == ATA_UDMA3) - cfis->sector_count = XFER_UDMA_3; - - fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0); -} - -static u32 fsl_sata_rw_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; - u32 block; - - block = start; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - cfis->command = (is_write) ? ATA_CMD_WRITE : ATA_CMD_READ; - cfis->device = ATA_LBA; - - cfis->device |= (block >> 24) & 0xf; - cfis->lba_high = (block >> 16) & 0xff; - cfis->lba_mid = (block >> 8) & 0xff; - cfis->lba_low = block & 0xff; - cfis->sector_count = (u8)(blkcnt & 0xff); - - fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, buffer, ATA_SECT_SIZE * blkcnt); - return blkcnt; -} - -static void fsl_sata_flush_cache(int dev) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - cfis->command = ATA_CMD_FLUSH; - - fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0); -} - -static u32 fsl_sata_rw_cmd_ext(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; - u64 block; - - block = (u64)start; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - - cfis->command = (is_write) ? ATA_CMD_WRITE_EXT - : ATA_CMD_READ_EXT; - - cfis->lba_high_exp = (block >> 40) & 0xff; - cfis->lba_mid_exp = (block >> 32) & 0xff; - cfis->lba_low_exp = (block >> 24) & 0xff; - cfis->lba_high = (block >> 16) & 0xff; - cfis->lba_mid = (block >> 8) & 0xff; - cfis->lba_low = block & 0xff; - cfis->device = ATA_LBA; - cfis->sector_count_exp = (blkcnt >> 8) & 0xff; - cfis->sector_count = blkcnt & 0xff; - - fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, buffer, ATA_SECT_SIZE * blkcnt); - return blkcnt; -} - -static u32 fsl_sata_rw_ncq_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, - int is_write) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; - int ncq_channel; - u64 block; - - if (sata->lba48 != 1) { - printf("execute FPDMA command on non-LBA48 hard disk\n\r"); - return -1; - } - - block = (u64)start; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - - cfis->command = (is_write) ? ATA_CMD_FPDMA_WRITE - : ATA_CMD_FPDMA_READ; - - cfis->lba_high_exp = (block >> 40) & 0xff; - cfis->lba_mid_exp = (block >> 32) & 0xff; - cfis->lba_low_exp = (block >> 24) & 0xff; - cfis->lba_high = (block >> 16) & 0xff; - cfis->lba_mid = (block >> 8) & 0xff; - cfis->lba_low = block & 0xff; - - cfis->device = ATA_LBA; - cfis->features_exp = (blkcnt >> 8) & 0xff; - cfis->features = blkcnt & 0xff; - - if (sata->queue_depth >= SATA_HC_MAX_CMD) - ncq_channel = SATA_HC_MAX_CMD - 1; - else - ncq_channel = sata->queue_depth - 1; - - /* Use the latest queue */ - fsl_sata_exec_cmd(sata, cfis, CMD_NCQ, ncq_channel, buffer, ATA_SECT_SIZE * blkcnt); - return blkcnt; -} - -static void fsl_sata_flush_cache_ext(int dev) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - cfis->command = ATA_CMD_FLUSH_EXT; - - fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0); -} - -static void fsl_sata_init_wcache(int dev, u16 *id) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - - if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id)) - sata->wcache = 1; - if (ata_id_has_flush(id)) - sata->flush = 1; - if (ata_id_has_flush_ext(id)) - sata->flush_ext = 1; -} - -static int fsl_sata_get_wcache(int dev) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - return sata->wcache; -} - -static int fsl_sata_get_flush(int dev) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - return sata->flush; -} - -static int fsl_sata_get_flush_ext(int dev) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - return sata->flush_ext; -} - -static u32 ata_low_level_rw_lba48(int dev, 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 (fsl_sata_info[dev].flags != FLAGS_FPDMA) - fsl_sata_rw_cmd_ext(dev, start, max_blks, addr, is_write); - else - fsl_sata_rw_ncq_cmd(dev, start, max_blks, addr, is_write); - start += max_blks; - blks -= max_blks; - addr += ATA_SECT_SIZE * max_blks; - } else { - if (fsl_sata_info[dev].flags != FLAGS_FPDMA) - fsl_sata_rw_cmd_ext(dev, start, blks, addr, is_write); - else - fsl_sata_rw_ncq_cmd(dev, start, blks, addr, is_write); - start += blks; - blks = 0; - addr += ATA_SECT_SIZE * blks; - } - } while (blks != 0); - - return blkcnt; -} - -static u32 ata_low_level_rw_lba28(int dev, u32 blknr, u32 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) { - fsl_sata_rw_cmd(dev, start, max_blks, addr, is_write); - start += max_blks; - blks -= max_blks; - addr += ATA_SECT_SIZE * max_blks; - } else { - fsl_sata_rw_cmd(dev, start, blks, addr, is_write); - start += blks; - blks = 0; - addr += ATA_SECT_SIZE * blks; - } - } while (blks != 0); - - return blkcnt; -} - -/* - * SATA interface between low level driver and command layer - */ -ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) -{ - u32 rc; - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - - if (sata->lba48) - rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, READ_CMD); - else - rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, buffer, READ_CMD); - return rc; -} - -ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) -{ - u32 rc; - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - - if (sata->lba48) { - rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, WRITE_CMD); - if (fsl_sata_get_wcache(dev) && fsl_sata_get_flush_ext(dev)) - fsl_sata_flush_cache_ext(dev); - } else { - rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, buffer, WRITE_CMD); - if (fsl_sata_get_wcache(dev) && fsl_sata_get_flush(dev)) - fsl_sata_flush_cache(dev); - } - return rc; -} - -int scan_sata(int dev) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - unsigned char serial[ATA_ID_SERNO_LEN + 1]; - unsigned char firmware[ATA_ID_FW_REV_LEN + 1]; - unsigned char product[ATA_ID_PROD_LEN + 1]; - u16 *id; - u64 n_sectors; - - /* if no detected link */ - if (!sata->link) - return -1; - - id = (u16 *)malloc(ATA_ID_WORDS * 2); - if (!id) { - printf("id malloc failed\n\r"); - return -1; - } - - /* Identify device to get information */ - fsl_sata_identify(dev, id); - - /* Serial number */ - ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); - memcpy(sata_dev_desc[dev].product, serial, sizeof(serial)); - - /* Firmware version */ - ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); - memcpy(sata_dev_desc[dev].revision, firmware, sizeof(firmware)); - - /* Product model */ - ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); - memcpy(sata_dev_desc[dev].vendor, product, sizeof(product)); - - /* Totoal sectors */ - n_sectors = ata_id_n_sectors(id); - sata_dev_desc[dev].lba = (u32)n_sectors; - -#ifdef CONFIG_LBA48 - /* Check if support LBA48 */ - if (ata_id_has_lba48(id)) { - sata->lba48 = 1; - debug("Device support LBA48\n\r"); - } else - debug("Device supports LBA28\n\r"); -#endif - - /* Get the NCQ queue depth from device */ - sata->queue_depth = ata_id_queue_depth(id); - - /* Get the xfer mode from device */ - fsl_sata_xfer_mode(dev, id); - - /* Get the write cache status from device */ - fsl_sata_init_wcache(dev, id); - - /* Set the xfer mode to highest speed */ - fsl_sata_set_features(dev); -#ifdef DEBUG - fsl_sata_identify(dev, id); - ata_dump_id(id); -#endif - free((void *)id); - return 0; -} diff --git a/drivers/block/fsl_sata.h b/drivers/block/fsl_sata.h deleted file mode 100644 index 18d679e782..0000000000 --- a/drivers/block/fsl_sata.h +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright (C) 2007-2008 Freescale Semiconductor, Inc. - * Dave Liu - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef __FSL_SATA_H__ -#define __FSL_SATA_H__ - -#define SATA_HC_MAX_NUM 4 /* Max host controller numbers */ -#define SATA_HC_MAX_CMD 16 /* Max command queue depth per host controller */ -#define SATA_HC_MAX_PORT 16 /* Max port number per host controller */ - -/* -* SATA Host Controller Registers -*/ -typedef struct fsl_sata_reg { - /* SATA command registers */ - u32 cqr; /* Command queue register */ - u8 res1[0x4]; - u32 car; /* Command active register */ - u8 res2[0x4]; - u32 ccr; /* Command completed register */ - u8 res3[0x4]; - u32 cer; /* Command error register */ - u8 res4[0x4]; - u32 der; /* Device error register */ - u32 chba; /* Command header base address */ - u32 hstatus; /* Host status register */ - u32 hcontrol; /* Host control register */ - u32 cqpmp; /* Port number queue register */ - u32 sig; /* Signature register */ - u32 icc; /* Interrupt coalescing control register */ - u8 res5[0xc4]; - - /* SATA supperset registers */ - u32 sstatus; /* SATA interface status register */ - u32 serror; /* SATA interface error register */ - u32 scontrol; /* SATA interface control register */ - u32 snotification; /* SATA interface notification register */ - u8 res6[0x30]; - - /* SATA control status registers */ - u32 transcfg; /* Transport layer configuration */ - u32 transstatus; /* Transport layer status */ - u32 linkcfg; /* Link layer configuration */ - u32 linkcfg1; /* Link layer configuration1 */ - u32 linkcfg2; /* Link layer configuration2 */ - u32 linkstatus; /* Link layer status */ - u32 linkstatus1; /* Link layer status1 */ - u32 phyctrlcfg; /* PHY control configuration */ - u8 res7[0x2b0]; - - /* SATA system control registers */ - u32 syspr; /* System priority register - big endian */ - u8 res8[0xbec]; -} __attribute__ ((packed)) fsl_sata_reg_t; - -/* HStatus register -*/ -#define HSTATUS_ONOFF 0x80000000 /* Online/offline status */ -#define HSTATUS_FORCE_OFFLINE 0x40000000 /* In process going offline */ -#define HSTATUS_BIST_ERR 0x20000000 - -/* Fatal error */ -#define HSTATUS_MASTER_ERR 0x00004000 -#define HSTATUS_DATA_UNDERRUN 0x00002000 -#define HSTATUS_DATA_OVERRUN 0x00001000 -#define HSTATUS_CRC_ERR_TX 0x00000800 -#define HSTATUS_CRC_ERR_RX 0x00000400 -#define HSTATUS_FIFO_OVERFLOW_TX 0x00000200 -#define HSTATUS_FIFO_OVERFLOW_RX 0x00000100 -#define HSTATUS_FATAL_ERR_ALL (HSTATUS_MASTER_ERR | \ - HSTATUS_DATA_UNDERRUN | \ - HSTATUS_DATA_OVERRUN | \ - HSTATUS_CRC_ERR_TX | \ - HSTATUS_CRC_ERR_RX | \ - HSTATUS_FIFO_OVERFLOW_TX | \ - HSTATUS_FIFO_OVERFLOW_RX) -/* Interrupt status */ -#define HSTATUS_FATAL_ERR 0x00000020 -#define HSTATUS_PHY_RDY 0x00000010 -#define HSTATUS_SIGNATURE 0x00000008 -#define HSTATUS_SNOTIFY 0x00000004 -#define HSTATUS_DEVICE_ERR 0x00000002 -#define HSTATUS_CMD_COMPLETE 0x00000001 - -/* HControl register -*/ -#define HCONTROL_ONOFF 0x80000000 /* Online or offline request */ -#define HCONTROL_FORCE_OFFLINE 0x40000000 /* Force offline request */ -#define HCONTROL_ENTERPRISE_EN 0x10000000 /* Enterprise mode enabled */ -#define HCONTROL_HDR_SNOOP 0x00000400 /* Command header snoop */ -#define HCONTROL_PMP_ATTACHED 0x00000200 /* Port multiplier attached */ - -/* Interrupt enable */ -#define HCONTROL_FATAL_ERR 0x00000020 -#define HCONTROL_PHY_RDY 0x00000010 -#define HCONTROL_SIGNATURE 0x00000008 -#define HCONTROL_SNOTIFY 0x00000004 -#define HCONTROL_DEVICE_ERR 0x00000002 -#define HCONTROL_CMD_COMPLETE 0x00000001 - -#define HCONTROL_INT_EN_ALL (HCONTROL_FATAL_ERR | \ - HCONTROL_PHY_RDY | \ - HCONTROL_SIGNATURE | \ - HCONTROL_SNOTIFY | \ - HCONTROL_DEVICE_ERR | \ - HCONTROL_CMD_COMPLETE) - -/* SStatus register -*/ -#define SSTATUS_IPM_MASK 0x00000780 -#define SSTATUS_IPM_NOPRESENT 0x00000000 -#define SSTATUS_IPM_ACTIVE 0x00000080 -#define SSTATUS_IPM_PATIAL 0x00000100 -#define SSTATUS_IPM_SLUMBER 0x00000300 - -#define SSTATUS_SPD_MASK 0x000000f0 -#define SSTATUS_SPD_GEN1 0x00000010 -#define SSTATUS_SPD_GEN2 0x00000020 - -#define SSTATUS_DET_MASK 0x0000000f -#define SSTATUS_DET_NODEVICE 0x00000000 -#define SSTATUS_DET_DISCONNECT 0x00000001 -#define SSTATUS_DET_CONNECT 0x00000003 -#define SSTATUS_DET_PHY_OFFLINE 0x00000004 - -/* SControl register -*/ -#define SCONTROL_SPM_MASK 0x0000f000 -#define SCONTROL_SPM_GO_PARTIAL 0x00001000 -#define SCONTROL_SPM_GO_SLUMBER 0x00002000 -#define SCONTROL_SPM_GO_ACTIVE 0x00004000 - -#define SCONTROL_IPM_MASK 0x00000f00 -#define SCONTROL_IPM_NO_RESTRICT 0x00000000 -#define SCONTROL_IPM_PARTIAL 0x00000100 -#define SCONTROL_IPM_SLUMBER 0x00000200 -#define SCONTROL_IPM_PART_SLUM 0x00000300 - -#define SCONTROL_SPD_MASK 0x000000f0 -#define SCONTROL_SPD_NO_RESTRICT 0x00000000 -#define SCONTROL_SPD_GEN1 0x00000010 -#define SCONTROL_SPD_GEN2 0x00000020 - -#define SCONTROL_DET_MASK 0x0000000f -#define SCONTROL_DET_HRESET 0x00000001 -#define SCONTROL_DET_DISABLE 0x00000004 - -/* TransCfg register -*/ -#define TRANSCFG_DFIS_SIZE_SHIFT 16 -#define TRANSCFG_RX_WATER_MARK_MASK 0x0000001f - -/* PhyCtrlCfg register -*/ -#define PHYCTRLCFG_FPRFTI_MASK 0x00000018 -#define PHYCTRLCFG_LOOPBACK_MASK 0x0000000e - -/* -* Command Header Entry -*/ -typedef struct cmd_hdr_entry { - __le32 cda; /* Command Descriptor Address, - 4 bytes aligned */ - __le32 prde_fis_len; /* Number of PRD entries and FIS length */ - __le32 ttl; /* Total transfer length */ - __le32 attribute; /* the attribute of command */ -} __attribute__ ((packed)) cmd_hdr_entry_t; - -#define SATA_HC_CMD_HDR_ENTRY_SIZE sizeof(struct cmd_hdr_entry) - -/* cda -*/ -#define CMD_HDR_CDA_ALIGN 4 - -/* prde_fis_len -*/ -#define CMD_HDR_PRD_ENTRY_SHIFT 16 -#define CMD_HDR_PRD_ENTRY_MASK 0x003f0000 -#define CMD_HDR_FIS_LEN_SHIFT 2 - -/* attribute -*/ -#define CMD_HDR_ATTR_RES 0x00000800 /* Reserved bit, should be 1 */ -#define CMD_HDR_ATTR_VBIST 0x00000400 /* Vendor BIST */ -#define CMD_HDR_ATTR_SNOOP 0x00000200 /* Snoop enable for all descriptor */ -#define CMD_HDR_ATTR_FPDMA 0x00000100 /* FPDMA queued command */ -#define CMD_HDR_ATTR_RESET 0x00000080 /* Reset - a SRST or device reset */ -#define CMD_HDR_ATTR_BIST 0x00000040 /* BIST - require the host to enter BIST mode */ -#define CMD_HDR_ATTR_ATAPI 0x00000020 /* ATAPI command */ -#define CMD_HDR_ATTR_TAG 0x0000001f /* TAG mask */ - -/* command type -*/ -enum cmd_type { - CMD_VENDOR_BIST, - CMD_BIST, - CMD_RESET, /* SRST or device reset */ - CMD_ATAPI, - CMD_NCQ, - CMD_ATA, /* None of all above */ -}; - -/* -* Command Header Table -*/ -typedef struct cmd_hdr_tbl { - cmd_hdr_entry_t cmd_slot[SATA_HC_MAX_CMD]; -} __attribute__ ((packed)) cmd_hdr_tbl_t; - -#define SATA_HC_CMD_HDR_TBL_SIZE sizeof(struct cmd_hdr_tbl) -#define SATA_HC_CMD_HDR_TBL_ALIGN 4 - -/* -* PRD entry - Physical Region Descriptor entry -*/ -typedef struct prd_entry { - __le32 dba; /* Data base address, 4 bytes aligned */ - u32 res1; - u32 res2; - __le32 ext_c_ddc; /* Indirect PRD flags, snoop and data word count */ -} __attribute__ ((packed)) prd_entry_t; - -#define SATA_HC_CMD_DESC_PRD_SIZE sizeof(struct prd_entry) - -/* dba -*/ -#define PRD_ENTRY_DBA_ALIGN 4 - -/* ext_c_ddc -*/ -#define PRD_ENTRY_EXT 0x80000000 /* extension flag */ -#ifdef CONFIG_FSL_SATA_V2 -#define PRD_ENTRY_DATA_SNOOP 0x10000000 /* Data snoop enable */ -#else -#define PRD_ENTRY_DATA_SNOOP 0x00400000 /* Data snoop enable */ -#endif -#define PRD_ENTRY_LEN_MASK 0x003fffff /* Data word count */ - -#define PRD_ENTRY_MAX_XFER_SZ (PRD_ENTRY_LEN_MASK + 1) - -/* - * This SATA host controller supports a max of 16 direct PRD entries, but if use - * chained indirect PRD entries, then the contollers supports upto a max of 63 - * entries including direct and indirect PRD entries. - * The PRDT is an array of 63 PRD entries contigiously, but the PRD entries#15 - * will be setup as an indirect descriptor, pointing to it's next (contigious) - * PRD entries#16. - */ -#define SATA_HC_MAX_PRD 63 /* Max PRD entry numbers per command */ -#define SATA_HC_MAX_PRD_DIRECT 16 /* Direct PRDT entries */ -#define SATA_HC_MAX_PRD_USABLE (SATA_HC_MAX_PRD - 1) -#define SATA_HC_MAX_XFER_LEN 0x4000000 - -/* -* PRDT - Physical Region Descriptor Table -*/ -typedef struct prdt { - prd_entry_t prdt[SATA_HC_MAX_PRD]; -} __attribute__ ((packed)) prdt_t; - -/* -* Command Descriptor -*/ -#define SATA_HC_CMD_DESC_CFIS_SIZE 32 /* bytes */ -#define SATA_HC_CMD_DESC_SFIS_SIZE 32 /* bytes */ -#define SATA_HC_CMD_DESC_ACMD_SIZE 16 /* bytes */ -#define SATA_HC_CMD_DESC_RES 16 /* bytes */ - -typedef struct cmd_desc { - u8 cfis[SATA_HC_CMD_DESC_CFIS_SIZE]; - u8 sfis[SATA_HC_CMD_DESC_SFIS_SIZE]; - u8 acmd[SATA_HC_CMD_DESC_ACMD_SIZE]; - u8 res[SATA_HC_CMD_DESC_RES]; - prd_entry_t prdt[SATA_HC_MAX_PRD]; -} __attribute__ ((packed)) cmd_desc_t; - -#define SATA_HC_CMD_DESC_SIZE sizeof(struct cmd_desc) -#define SATA_HC_CMD_DESC_ALIGN 4 - -/* - * SATA device driver info - */ -typedef struct fsl_sata_info { - u32 sata_reg_base; - u32 flags; -} fsl_sata_info_t; - -#define FLAGS_DMA 0x00000000 -#define FLAGS_FPDMA 0x00000001 - -/* - * SATA device driver struct - */ -typedef struct fsl_sata { - char name[12]; - fsl_sata_reg_t *reg_base; /* the base address of controller register */ - void *cmd_hdr_tbl_offset; /* alloc address of command header table */ - cmd_hdr_tbl_t *cmd_hdr; /* aligned address of command header table */ - void *cmd_desc_offset; /* alloc address of command descriptor */ - cmd_desc_t *cmd_desc; /* aligned address of command descriptor */ - int link; /* PHY link status */ - /* device attribute */ - int ata_device_type; /* device type */ - int lba48; - int queue_depth; /* Max NCQ queue depth */ - u16 pio; - u16 mwdma; - u16 udma; - int wcache; - int flush; - int flush_ext; -} fsl_sata_t; - -#define READ_CMD 0 -#define WRITE_CMD 1 - -#endif /* __FSL_SATA_H__ */ diff --git a/drivers/block/libata.c b/drivers/block/libata.c deleted file mode 100644 index d684270dcd..0000000000 --- a/drivers/block/libata.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2008 Freescale Semiconductor, Inc. - * Dave Liu - * port from the libata of linux kernel - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#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/drivers/block/mvsata_ide.c b/drivers/block/mvsata_ide.c deleted file mode 100644 index 7b6a1558d2..0000000000 --- a/drivers/block/mvsata_ide.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (C) 2010 Albert ARIBAUD - * - * Written-by: Albert ARIBAUD - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include - -#if defined(CONFIG_ORION5X) -#include -#elif defined(CONFIG_KIRKWOOD) -#include -#elif defined(CONFIG_ARCH_MVEBU) -#include -#endif - -/* SATA port registers */ -struct mvsata_port_registers { - u32 reserved0[10]; - u32 edma_cmd; - u32 reserved1[181]; - /* offset 0x300 : ATA Interface registers */ - u32 sstatus; - u32 serror; - u32 scontrol; - u32 ltmode; - u32 phymode3; - u32 phymode4; - u32 reserved2[5]; - u32 phymode1; - u32 phymode2; - u32 bist_cr; - u32 bist_dw1; - u32 bist_dw2; - u32 serrorintrmask; -}; - -/* - * Sanity checks: - * - to compile at all, we need CONFIG_SYS_ATA_BASE_ADDR. - * - for ide_preinit to make sense, we need at least one of - * CONFIG_SYS_ATA_IDE0_OFFSET or CONFIG_SYS_ATA_IDE1_OFFSET; - * - for ide_preinit to be called, we need CONFIG_IDE_PREINIT. - * Fail with an explanation message if these conditions are not met. - * This is particularly important for CONFIG_IDE_PREINIT, because - * its lack would not cause a build error. - */ - -#if !defined(CONFIG_SYS_ATA_BASE_ADDR) -#error CONFIG_SYS_ATA_BASE_ADDR must be defined -#elif !defined(CONFIG_SYS_ATA_IDE0_OFFSET) \ - && !defined(CONFIG_SYS_ATA_IDE1_OFFSET) -#error CONFIG_SYS_ATA_IDE0_OFFSET or CONFIG_SYS_ATA_IDE1_OFFSET \ - must be defined -#elif !defined(CONFIG_IDE_PREINIT) -#error CONFIG_IDE_PREINIT must be defined -#endif - -/* - * Masks and values for SControl DETection and Interface Power Management, - * and for SStatus DETection. - */ - -#define MVSATA_EDMA_CMD_ATA_RST 0x00000004 -#define MVSATA_SCONTROL_DET_MASK 0x0000000F -#define MVSATA_SCONTROL_DET_NONE 0x00000000 -#define MVSATA_SCONTROL_DET_INIT 0x00000001 -#define MVSATA_SCONTROL_IPM_MASK 0x00000F00 -#define MVSATA_SCONTROL_IPM_NO_LP_ALLOWED 0x00000300 -#define MVSATA_SCONTROL_MASK \ - (MVSATA_SCONTROL_DET_MASK|MVSATA_SCONTROL_IPM_MASK) -#define MVSATA_PORT_INIT \ - (MVSATA_SCONTROL_DET_INIT|MVSATA_SCONTROL_IPM_NO_LP_ALLOWED) -#define MVSATA_PORT_USE \ - (MVSATA_SCONTROL_DET_NONE|MVSATA_SCONTROL_IPM_NO_LP_ALLOWED) -#define MVSATA_SSTATUS_DET_MASK 0x0000000F -#define MVSATA_SSTATUS_DET_DEVCOMM 0x00000003 - -/* - * Status codes to return to client callers. Currently, callers ignore - * exact value and only care for zero or nonzero, so no need to make this - * public, it is only #define'd for clarity. - * If/when standard negative codes are implemented in U-Boot, then these - * #defines should be moved to, or replaced by ones from, the common list - * of status codes. - */ - -#define MVSATA_STATUS_OK 0 -#define MVSATA_STATUS_TIMEOUT -1 - -/* - * Registers for SATA MBUS memory windows - */ - -#define MVSATA_WIN_CONTROL(w) (MVEBU_AXP_SATA_BASE + 0x30 + ((w) << 4)) -#define MVSATA_WIN_BASE(w) (MVEBU_AXP_SATA_BASE + 0x34 + ((w) << 4)) - -/* - * Initialize SATA memory windows for Armada XP - */ - -#ifdef CONFIG_ARCH_MVEBU -static void mvsata_ide_conf_mbus_windows(void) -{ - const struct mbus_dram_target_info *dram; - int i; - - dram = mvebu_mbus_dram_info(); - - /* Disable windows, Set Size/Base to 0 */ - for (i = 0; i < 4; i++) { - writel(0, MVSATA_WIN_CONTROL(i)); - writel(0, MVSATA_WIN_BASE(i)); - } - - for (i = 0; i < dram->num_cs; i++) { - const struct mbus_dram_window *cs = dram->cs + i; - writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) | - (dram->mbus_dram_target_id << 4) | 1, - MVSATA_WIN_CONTROL(i)); - writel(cs->base & 0xffff0000, MVSATA_WIN_BASE(i)); - } -} -#endif - -/* - * Initialize one MVSATAHC port: set SControl's IPM to "always active" - * and DET to "reset", then wait for SStatus's DET to become "device and - * comm ok" (or time out after 50 us if no device), then set SControl's - * DET back to "no action". - */ - -static int mvsata_ide_initialize_port(struct mvsata_port_registers *port) -{ - u32 control; - u32 status; - u32 timeleft = 10000; /* wait at most 10 ms for SATA reset to complete */ - - /* Hard reset */ - writel(MVSATA_EDMA_CMD_ATA_RST, &port->edma_cmd); - udelay(25); /* taken from original marvell port */ - writel(0, &port->edma_cmd); - - /* Set control IPM to 3 (no low power) and DET to 1 (initialize) */ - control = readl(&port->scontrol); - control = (control & ~MVSATA_SCONTROL_MASK) | MVSATA_PORT_INIT; - writel(control, &port->scontrol); - /* Toggle control DET back to 0 (normal operation) */ - control = (control & ~MVSATA_SCONTROL_MASK) | MVSATA_PORT_USE; - writel(control, &port->scontrol); - /* wait for status DET to become 3 (device and communication OK) */ - while (--timeleft) { - status = readl(&port->sstatus) & MVSATA_SSTATUS_DET_MASK; - if (status == MVSATA_SSTATUS_DET_DEVCOMM) - break; - udelay(1); - } - /* return success or time-out error depending on time left */ - if (!timeleft) - return MVSATA_STATUS_TIMEOUT; - return MVSATA_STATUS_OK; -} - -/* - * ide_preinit() will be called by ide_init in cmd_ide.c and will - * reset the MVSTATHC ports needed by the board. - */ - -int ide_preinit(void) -{ - int ret = MVSATA_STATUS_TIMEOUT; - int status; - -#ifdef CONFIG_ARCH_MVEBU - mvsata_ide_conf_mbus_windows(); -#endif - - /* Enable ATA port 0 (could be SATA port 0 or 1) if declared */ -#if defined(CONFIG_SYS_ATA_IDE0_OFFSET) - status = mvsata_ide_initialize_port( - (struct mvsata_port_registers *) - (CONFIG_SYS_ATA_BASE_ADDR + CONFIG_SYS_ATA_IDE0_OFFSET)); - if (status == MVSATA_STATUS_OK) - ret = MVSATA_STATUS_OK; -#endif - /* Enable ATA port 1 (could be SATA port 0 or 1) if declared */ -#if defined(CONFIG_SYS_ATA_IDE1_OFFSET) - status = mvsata_ide_initialize_port( - (struct mvsata_port_registers *) - (CONFIG_SYS_ATA_BASE_ADDR + CONFIG_SYS_ATA_IDE1_OFFSET)); - if (status == MVSATA_STATUS_OK) - ret = MVSATA_STATUS_OK; -#endif - /* Return success if at least one port initialization succeeded */ - return ret; -} diff --git a/drivers/block/mxc_ata.c b/drivers/block/mxc_ata.c deleted file mode 100644 index 44bb406f4d..0000000000 --- a/drivers/block/mxc_ata.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Freescale iMX51 ATA driver - * - * Copyright (C) 2010 Marek Vasut - * - * Based on code by: - * Mahesh Mahadevan - * - * Based on code from original FSL ATA driver, which is - * part of eCos, the Embedded Configurable Operating System. - * Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -/* MXC ATA register offsets */ -struct mxc_ata_config_regs { - u8 time_off; /* 0x00 */ - u8 time_on; - u8 time_1; - u8 time_2w; - u8 time_2r; - u8 time_ax; - u8 time_pio_rdx; - u8 time_4; - u8 time_9; - u8 time_m; - u8 time_jn; - u8 time_d; - u8 time_k; - u8 time_ack; - u8 time_env; - u8 time_udma_rdx; - u8 time_zah; /* 0x10 */ - u8 time_mlix; - u8 time_dvh; - u8 time_dzfs; - u8 time_dvs; - u8 time_cvh; - u8 time_ss; - u8 time_cyc; - u32 fifo_data_32; /* 0x18 */ - u32 fifo_data_16; - u32 fifo_fill; - u32 ata_control; - u32 interrupt_pending; - u32 interrupt_enable; - u32 interrupt_clear; - u32 fifo_alarm; -}; - -struct mxc_data_hdd_regs { - u32 drive_data; /* 0xa0 */ - u32 drive_features; - u32 drive_sector_count; - u32 drive_sector_num; - u32 drive_cyl_low; - u32 drive_cyl_high; - u32 drive_dev_head; - u32 command; - u32 status; - u32 alt_status; -}; - -/* PIO timing table */ -#define NR_PIO_SPECS 5 -static uint16_t pio_t1[NR_PIO_SPECS] = { 70, 50, 30, 30, 25 }; -static uint16_t pio_t2_8[NR_PIO_SPECS] = { 290, 290, 290, 80, 70 }; -static uint16_t pio_t4[NR_PIO_SPECS] = { 30, 20, 15, 10, 10 }; -static uint16_t pio_t9[NR_PIO_SPECS] = { 20, 15, 10, 10, 10 }; -static uint16_t pio_tA[NR_PIO_SPECS] = { 50, 50, 50, 50, 50 }; - -#define REG2OFF(reg) ((((uint32_t)reg) & 0x3) * 8) -static void set_ata_bus_timing(unsigned char mode) -{ - uint32_t T = 1000000000 / mxc_get_clock(MXC_IPG_CLK); - - struct mxc_ata_config_regs *ata_regs; - ata_regs = (struct mxc_ata_config_regs *)CONFIG_SYS_ATA_BASE_ADDR; - - if (mode >= NR_PIO_SPECS) - return; - - /* Write TIME_OFF/ON/1/2W */ - writeb(3, &ata_regs->time_off); - writeb(3, &ata_regs->time_on); - writeb((pio_t1[mode] + T) / T, &ata_regs->time_1); - writeb((pio_t2_8[mode] + T) / T, &ata_regs->time_2w); - - /* Write TIME_2R/AX/RDX/4 */ - writeb((pio_t2_8[mode] + T) / T, &ata_regs->time_2r); - writeb((pio_tA[mode] + T) / T + 2, &ata_regs->time_ax); - writeb(1, &ata_regs->time_pio_rdx); - writeb((pio_t4[mode] + T) / T, &ata_regs->time_4); - - /* Write TIME_9 ; the rest of timing registers is irrelevant for PIO */ - writeb((pio_t9[mode] + T) / T, &ata_regs->time_9); -} - -int ide_preinit(void) -{ - struct mxc_ata_config_regs *ata_regs; - ata_regs = (struct mxc_ata_config_regs *)CONFIG_SYS_ATA_BASE_ADDR; - - /* 46.3.3.4 @ FSL iMX51 manual */ - /* FIFO normal op., drive reset */ - writel(0x80, &ata_regs->ata_control); - /* FIFO normal op., drive not reset */ - writel(0xc0, &ata_regs->ata_control); - - /* Configure the PIO timing */ - set_ata_bus_timing(CONFIG_MXC_ATA_PIO_MODE); - - /* 46.3.3.4 @ FSL iMX51 manual */ - /* Drive not reset, IORDY handshake */ - writel(0x41, &ata_regs->ata_control); - - return 0; -} diff --git a/drivers/block/sata_ceva.c b/drivers/block/sata_ceva.c deleted file mode 100644 index 0c24fce8dc..0000000000 --- a/drivers/block/sata_ceva.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * (C) Copyright 2015 - 2016 Xilinx, Inc. - * Michal Simek - * - * SPDX-License-Identifier: GPL-2.0+ - */ -#include -#include -#include -#include -#include - -#include - -/* Vendor Specific Register Offsets */ -#define AHCI_VEND_PCFG 0xA4 -#define AHCI_VEND_PPCFG 0xA8 -#define AHCI_VEND_PP2C 0xAC -#define AHCI_VEND_PP3C 0xB0 -#define AHCI_VEND_PP4C 0xB4 -#define AHCI_VEND_PP5C 0xB8 -#define AHCI_VEND_PAXIC 0xC0 -#define AHCI_VEND_PTC 0xC8 - -/* Vendor Specific Register bit definitions */ -#define PAXIC_ADBW_BW64 0x1 -#define PAXIC_MAWIDD (1 << 8) -#define PAXIC_MARIDD (1 << 16) -#define PAXIC_OTL (0x4 << 20) - -#define PCFG_TPSS_VAL (0x32 << 16) -#define PCFG_TPRS_VAL (0x2 << 12) -#define PCFG_PAD_VAL 0x2 - -#define PPCFG_TTA 0x1FFFE -#define PPCFG_PSSO_EN (1 << 28) -#define PPCFG_PSS_EN (1 << 29) -#define PPCFG_ESDF_EN (1 << 31) - -#define PP2C_CIBGMN 0x0F -#define PP2C_CIBGMX (0x25 << 8) -#define PP2C_CIBGN (0x18 << 16) -#define PP2C_CINMP (0x29 << 24) - -#define PP3C_CWBGMN 0x04 -#define PP3C_CWBGMX (0x0B << 8) -#define PP3C_CWBGN (0x08 << 16) -#define PP3C_CWNMP (0x0F << 24) - -#define PP4C_BMX 0x0a -#define PP4C_BNM (0x08 << 8) -#define PP4C_SFD (0x4a << 16) -#define PP4C_PTST (0x06 << 24) - -#define PP5C_RIT 0x60216 -#define PP5C_RCT (0x7f0 << 20) - -#define PTC_RX_WM_VAL 0x40 -#define PTC_RSVD (1 << 27) - -#define PORT0_BASE 0x100 -#define PORT1_BASE 0x180 - -/* Port Control Register Bit Definitions */ -#define PORT_SCTL_SPD_GEN3 (0x3 << 4) -#define PORT_SCTL_SPD_GEN2 (0x2 << 4) -#define PORT_SCTL_SPD_GEN1 (0x1 << 4) -#define PORT_SCTL_IPM (0x3 << 8) - -#define PORT_BASE 0x100 -#define PORT_OFFSET 0x80 -#define NR_PORTS 2 -#define DRV_NAME "ahci-ceva" -#define CEVA_FLAG_BROKEN_GEN2 1 - -static int ceva_init_sata(ulong mmio) -{ - ulong tmp; - int i; - - /* - * AXI Data bus width to 64 - * Set Mem Addr Read, Write ID for data transfers - * Transfer limit to 72 DWord - */ - tmp = PAXIC_ADBW_BW64 | PAXIC_MAWIDD | PAXIC_MARIDD | PAXIC_OTL; - writel(tmp, mmio + AHCI_VEND_PAXIC); - - /* Set AHCI Enable */ - tmp = readl(mmio + HOST_CTL); - tmp |= HOST_AHCI_EN; - writel(tmp, mmio + HOST_CTL); - - for (i = 0; i < NR_PORTS; i++) { - /* TPSS TPRS scalars, CISE and Port Addr */ - tmp = PCFG_TPSS_VAL | PCFG_TPRS_VAL | (PCFG_PAD_VAL + i); - writel(tmp, mmio + AHCI_VEND_PCFG); - - /* Port Phy Cfg register enables */ - tmp = PPCFG_TTA | PPCFG_PSS_EN | PPCFG_ESDF_EN; - writel(tmp, mmio + AHCI_VEND_PPCFG); - - /* Rx Watermark setting */ - tmp = PTC_RX_WM_VAL | PTC_RSVD; - writel(tmp, mmio + AHCI_VEND_PTC); - - /* Default to Gen 2 Speed and Gen 1 if Gen2 is broken */ - tmp = PORT_SCTL_SPD_GEN3 | PORT_SCTL_IPM; - writel(tmp, mmio + PORT_SCR_CTL + PORT_BASE + PORT_OFFSET * i); - } - return 0; -} - -static int sata_ceva_probe(struct udevice *dev) -{ - struct scsi_platdata *plat = dev_get_platdata(dev); - - ceva_init_sata(plat->base); - return 0; -} - -static const struct udevice_id sata_ceva_ids[] = { - { .compatible = "ceva,ahci-1v84" }, - { } -}; - -static int sata_ceva_ofdata_to_platdata(struct udevice *dev) -{ - struct scsi_platdata *plat = dev_get_platdata(dev); - - plat->base = devfdt_get_addr(dev); - if (plat->base == FDT_ADDR_T_NONE) - return -EINVAL; - - /* Hardcode number for ceva sata controller */ - plat->max_lun = 1; /* Actually two but untested */ - plat->max_id = 2; - - return 0; -} - -U_BOOT_DRIVER(ceva_host_blk) = { - .name = "ceva_sata", - .id = UCLASS_SCSI, - .of_match = sata_ceva_ids, - .probe = sata_ceva_probe, - .ofdata_to_platdata = sata_ceva_ofdata_to_platdata, - .platdata_auto_alloc_size = sizeof(struct scsi_platdata), -}; diff --git a/drivers/block/sata_dwc.c b/drivers/block/sata_dwc.c deleted file mode 100644 index a226ca2dec..0000000000 --- a/drivers/block/sata_dwc.c +++ /dev/null @@ -1,2076 +0,0 @@ -/* - * sata_dwc.c - * - * Synopsys DesignWare Cores (DWC) SATA host driver - * - * Author: Mark Miesfeld - * - * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese - * Copyright 2008 DENX Software Engineering - * - * Based on versions provided by AMCC and Synopsys which are: - * Copyright 2006 Applied Micro Circuits Corporation - * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED - * - * SPDX-License-Identifier: GPL-2.0+ - */ -/* - * SATA support based on the chip canyonlands. - * - * 04-17-2009 - * The local version of this driver for the canyonlands board - * does not use interrupts but polls the chip instead. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sata_dwc.h" - -#define DMA_NUM_CHANS 1 -#define DMA_NUM_CHAN_REGS 8 - -#define AHB_DMA_BRST_DFLT 16 - -struct dmareg { - u32 low; - u32 high; -}; - -struct dma_chan_regs { - struct dmareg sar; - struct dmareg dar; - struct dmareg llp; - struct dmareg ctl; - struct dmareg sstat; - struct dmareg dstat; - struct dmareg sstatar; - struct dmareg dstatar; - struct dmareg cfg; - struct dmareg sgr; - struct dmareg dsr; -}; - -struct dma_interrupt_regs { - struct dmareg tfr; - struct dmareg block; - struct dmareg srctran; - struct dmareg dsttran; - struct dmareg error; -}; - -struct ahb_dma_regs { - struct dma_chan_regs chan_regs[DMA_NUM_CHAN_REGS]; - struct dma_interrupt_regs interrupt_raw; - struct dma_interrupt_regs interrupt_status; - struct dma_interrupt_regs interrupt_mask; - struct dma_interrupt_regs interrupt_clear; - struct dmareg statusInt; - struct dmareg rq_srcreg; - struct dmareg rq_dstreg; - struct dmareg rq_sgl_srcreg; - struct dmareg rq_sgl_dstreg; - struct dmareg rq_lst_srcreg; - struct dmareg rq_lst_dstreg; - struct dmareg dma_cfg; - struct dmareg dma_chan_en; - struct dmareg dma_id; - struct dmareg dma_test; - struct dmareg res1; - struct dmareg res2; - /* DMA Comp Params - * Param 6 = dma_param[0], Param 5 = dma_param[1], - * Param 4 = dma_param[2] ... - */ - struct dmareg dma_params[6]; -}; - -#define DMA_EN 0x00000001 -#define DMA_DI 0x00000000 -#define DMA_CHANNEL(ch) (0x00000001 << (ch)) -#define DMA_ENABLE_CHAN(ch) ((0x00000001 << (ch)) | \ - ((0x000000001 << (ch)) << 8)) -#define DMA_DISABLE_CHAN(ch) (0x00000000 | \ - ((0x000000001 << (ch)) << 8)) - -#define SATA_DWC_MAX_PORTS 1 -#define SATA_DWC_SCR_OFFSET 0x24 -#define SATA_DWC_REG_OFFSET 0x64 - -struct sata_dwc_regs { - u32 fptagr; - u32 fpbor; - u32 fptcr; - u32 dmacr; - u32 dbtsr; - u32 intpr; - u32 intmr; - u32 errmr; - u32 llcr; - u32 phycr; - u32 physr; - u32 rxbistpd; - u32 rxbistpd1; - u32 rxbistpd2; - u32 txbistpd; - u32 txbistpd1; - u32 txbistpd2; - u32 bistcr; - u32 bistfctr; - u32 bistsr; - u32 bistdecr; - u32 res[15]; - u32 testr; - u32 versionr; - u32 idr; - u32 unimpl[192]; - u32 dmadr[256]; -}; - -#define SATA_DWC_TXFIFO_DEPTH 0x01FF -#define SATA_DWC_RXFIFO_DEPTH 0x01FF - -#define SATA_DWC_DBTSR_MWR(size) ((size / 4) & SATA_DWC_TXFIFO_DEPTH) -#define SATA_DWC_DBTSR_MRD(size) (((size / 4) & \ - SATA_DWC_RXFIFO_DEPTH) << 16) -#define SATA_DWC_INTPR_DMAT 0x00000001 -#define SATA_DWC_INTPR_NEWFP 0x00000002 -#define SATA_DWC_INTPR_PMABRT 0x00000004 -#define SATA_DWC_INTPR_ERR 0x00000008 -#define SATA_DWC_INTPR_NEWBIST 0x00000010 -#define SATA_DWC_INTPR_IPF 0x10000000 -#define SATA_DWC_INTMR_DMATM 0x00000001 -#define SATA_DWC_INTMR_NEWFPM 0x00000002 -#define SATA_DWC_INTMR_PMABRTM 0x00000004 -#define SATA_DWC_INTMR_ERRM 0x00000008 -#define SATA_DWC_INTMR_NEWBISTM 0x00000010 - -#define SATA_DWC_DMACR_TMOD_TXCHEN 0x00000004 -#define SATA_DWC_DMACR_TXRXCH_CLEAR SATA_DWC_DMACR_TMOD_TXCHEN - -#define SATA_DWC_QCMD_MAX 32 - -#define SATA_DWC_SERROR_ERR_BITS 0x0FFF0F03 - -#define HSDEVP_FROM_AP(ap) (struct sata_dwc_device_port*) \ - (ap)->private_data - -struct sata_dwc_device { - struct device *dev; - struct ata_probe_ent *pe; - struct ata_host *host; - u8 *reg_base; - struct sata_dwc_regs *sata_dwc_regs; - int irq_dma; -}; - -struct sata_dwc_device_port { - struct sata_dwc_device *hsdev; - int cmd_issued[SATA_DWC_QCMD_MAX]; - u32 dma_chan[SATA_DWC_QCMD_MAX]; - int dma_pending[SATA_DWC_QCMD_MAX]; -}; - -enum { - SATA_DWC_CMD_ISSUED_NOT = 0, - SATA_DWC_CMD_ISSUED_PEND = 1, - SATA_DWC_CMD_ISSUED_EXEC = 2, - SATA_DWC_CMD_ISSUED_NODATA = 3, - - SATA_DWC_DMA_PENDING_NONE = 0, - SATA_DWC_DMA_PENDING_TX = 1, - SATA_DWC_DMA_PENDING_RX = 2, -}; - -#define msleep(a) udelay(a * 1000) -#define ssleep(a) msleep(a * 1000) - -static int ata_probe_timeout = (ATA_TMOUT_INTERNAL / 100); - -enum sata_dev_state { - SATA_INIT = 0, - SATA_READY = 1, - SATA_NODEVICE = 2, - SATA_ERROR = 3, -}; -enum sata_dev_state dev_state = SATA_INIT; - -static struct ahb_dma_regs *sata_dma_regs = 0; -static struct ata_host *phost; -static struct ata_port ap; -static struct ata_port *pap = ≈ -static struct ata_device ata_device; -static struct sata_dwc_device_port dwc_devp; - -static void *scr_addr_sstatus; -static u32 temp_n_block = 0; - -static unsigned ata_exec_internal(struct ata_device *dev, - struct ata_taskfile *tf, const u8 *cdb, - int dma_dir, unsigned int buflen, - unsigned long timeout); -static unsigned int ata_dev_set_feature(struct ata_device *dev, - u8 enable,u8 feature); -static unsigned int ata_dev_init_params(struct ata_device *dev, - u16 heads, u16 sectors); -static u8 ata_irq_on(struct ata_port *ap); -static struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, - unsigned int tag); -static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, - u8 status, int in_wq); -static void ata_tf_to_host(struct ata_port *ap, - const struct ata_taskfile *tf); -static void ata_exec_command(struct ata_port *ap, - const struct ata_taskfile *tf); -static unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc); -static u8 ata_check_altstatus(struct ata_port *ap); -static u8 ata_check_status(struct ata_port *ap); -static void ata_dev_select(struct ata_port *ap, unsigned int device, - unsigned int wait, unsigned int can_sleep); -static void ata_qc_issue(struct ata_queued_cmd *qc); -static void ata_tf_load(struct ata_port *ap, - const struct ata_taskfile *tf); -static int ata_dev_read_sectors(unsigned char* pdata, - unsigned long datalen, u32 block, u32 n_block); -static int ata_dev_write_sectors(unsigned char* pdata, - unsigned long datalen , u32 block, u32 n_block); -static void ata_std_dev_select(struct ata_port *ap, unsigned int device); -static void ata_qc_complete(struct ata_queued_cmd *qc); -static void __ata_qc_complete(struct ata_queued_cmd *qc); -static void fill_result_tf(struct ata_queued_cmd *qc); -static void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); -static void ata_mmio_data_xfer(struct ata_device *dev, - unsigned char *buf, - unsigned int buflen,int do_write); -static void ata_pio_task(struct ata_port *arg_ap); -static void __ata_port_freeze(struct ata_port *ap); -static int ata_port_freeze(struct ata_port *ap); -static void ata_qc_free(struct ata_queued_cmd *qc); -static void ata_pio_sectors(struct ata_queued_cmd *qc); -static void ata_pio_sector(struct ata_queued_cmd *qc); -static void ata_pio_queue_task(struct ata_port *ap, - void *data,unsigned long delay); -static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq); -static int sata_dwc_softreset(struct ata_port *ap); -static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, - unsigned int flags, u16 *id); -static int check_sata_dev_state(void); - -static const struct ata_port_info sata_dwc_port_info[] = { - { - .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | - ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING | - ATA_FLAG_SRST | ATA_FLAG_NCQ, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = 0x7f, - }, -}; - -int init_sata(int dev) -{ - struct sata_dwc_device hsdev; - struct ata_host host; - struct ata_port_info pi = sata_dwc_port_info[0]; - struct ata_link *link; - struct sata_dwc_device_port hsdevp = dwc_devp; - u8 *base = 0; - u8 *sata_dma_regs_addr = 0; - u8 status; - unsigned long base_addr = 0; - int chan = 0; - int rc; - int i; - - phost = &host; - - base = (u8*)SATA_BASE_ADDR; - - hsdev.sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET); - - host.n_ports = SATA_DWC_MAX_PORTS; - - for (i = 0; i < SATA_DWC_MAX_PORTS; i++) { - ap.pflags |= ATA_PFLAG_INITIALIZING; - ap.flags = ATA_FLAG_DISABLED; - ap.print_id = -1; - ap.ctl = ATA_DEVCTL_OBS; - ap.host = &host; - ap.last_ctl = 0xFF; - - link = &ap.link; - link->ap = ≈ - link->pmp = 0; - link->active_tag = ATA_TAG_POISON; - link->hw_sata_spd_limit = 0; - - ap.port_no = i; - host.ports[i] = ≈ - } - - ap.pio_mask = pi.pio_mask; - ap.mwdma_mask = pi.mwdma_mask; - ap.udma_mask = pi.udma_mask; - ap.flags |= pi.flags; - ap.link.flags |= pi.link_flags; - - host.ports[0]->ioaddr.cmd_addr = base; - host.ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET; - scr_addr_sstatus = base + SATA_DWC_SCR_OFFSET; - - base_addr = (unsigned long)base; - - host.ports[0]->ioaddr.cmd_addr = (void *)base_addr + 0x00; - host.ports[0]->ioaddr.data_addr = (void *)base_addr + 0x00; - - host.ports[0]->ioaddr.error_addr = (void *)base_addr + 0x04; - host.ports[0]->ioaddr.feature_addr = (void *)base_addr + 0x04; - - host.ports[0]->ioaddr.nsect_addr = (void *)base_addr + 0x08; - - host.ports[0]->ioaddr.lbal_addr = (void *)base_addr + 0x0c; - host.ports[0]->ioaddr.lbam_addr = (void *)base_addr + 0x10; - host.ports[0]->ioaddr.lbah_addr = (void *)base_addr + 0x14; - - host.ports[0]->ioaddr.device_addr = (void *)base_addr + 0x18; - host.ports[0]->ioaddr.command_addr = (void *)base_addr + 0x1c; - host.ports[0]->ioaddr.status_addr = (void *)base_addr + 0x1c; - - host.ports[0]->ioaddr.altstatus_addr = (void *)base_addr + 0x20; - host.ports[0]->ioaddr.ctl_addr = (void *)base_addr + 0x20; - - sata_dma_regs_addr = (u8*)SATA_DMA_REG_ADDR; - sata_dma_regs = (void *__iomem)sata_dma_regs_addr; - - status = ata_check_altstatus(&ap); - - if (status == 0x7f) { - printf("Hard Disk not found.\n"); - dev_state = SATA_NODEVICE; - rc = false; - return rc; - } - - printf("Waiting for device..."); - i = 0; - while (1) { - udelay(10000); - - status = ata_check_altstatus(&ap); - - if ((status & ATA_BUSY) == 0) { - printf("\n"); - break; - } - - i++; - if (i > (ATA_RESET_TIME * 100)) { - printf("** TimeOUT **\n"); - - dev_state = SATA_NODEVICE; - rc = false; - return rc; - } - if ((i >= 100) && ((i % 100) == 0)) - printf("."); - } - - rc = sata_dwc_softreset(&ap); - - if (rc) { - printf("sata_dwc : error. soft reset failed\n"); - return rc; - } - - for (chan = 0; chan < DMA_NUM_CHANS; chan++) { - out_le32(&(sata_dma_regs->interrupt_mask.error.low), - DMA_DISABLE_CHAN(chan)); - - out_le32(&(sata_dma_regs->interrupt_mask.tfr.low), - DMA_DISABLE_CHAN(chan)); - } - - out_le32(&(sata_dma_regs->dma_cfg.low), DMA_DI); - - out_le32(&hsdev.sata_dwc_regs->intmr, - SATA_DWC_INTMR_ERRM | - SATA_DWC_INTMR_PMABRTM); - - /* Unmask the error bits that should trigger - * an error interrupt by setting the error mask register. - */ - out_le32(&hsdev.sata_dwc_regs->errmr, SATA_DWC_SERROR_ERR_BITS); - - hsdev.host = ap.host; - memset(&hsdevp, 0, sizeof(hsdevp)); - hsdevp.hsdev = &hsdev; - - for (i = 0; i < SATA_DWC_QCMD_MAX; i++) - hsdevp.cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT; - - out_le32((void __iomem *)scr_addr_sstatus + 4, - in_le32((void __iomem *)scr_addr_sstatus + 4)); - - rc = 0; - return rc; -} - -int reset_sata(int dev) -{ - return 0; -} - -static u8 ata_check_altstatus(struct ata_port *ap) -{ - u8 val = 0; - val = readb(ap->ioaddr.altstatus_addr); - return val; -} - -static int sata_dwc_softreset(struct ata_port *ap) -{ - u8 nsect,lbal = 0; - u8 tmp = 0; - struct ata_ioports *ioaddr = &ap->ioaddr; - - in_le32((void *)ap->ioaddr.scr_addr + (SCR_ERROR * 4)); - - writeb(0x55, ioaddr->nsect_addr); - writeb(0xaa, ioaddr->lbal_addr); - writeb(0xaa, ioaddr->nsect_addr); - writeb(0x55, ioaddr->lbal_addr); - writeb(0x55, ioaddr->nsect_addr); - writeb(0xaa, ioaddr->lbal_addr); - - nsect = readb(ioaddr->nsect_addr); - lbal = readb(ioaddr->lbal_addr); - - if ((nsect == 0x55) && (lbal == 0xaa)) { - printf("Device found\n"); - } else { - printf("No device found\n"); - dev_state = SATA_NODEVICE; - return false; - } - - tmp = ATA_DEVICE_OBS; - writeb(tmp, ioaddr->device_addr); - writeb(ap->ctl, ioaddr->ctl_addr); - - udelay(200); - - writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr); - - udelay(200); - writeb(ap->ctl, ioaddr->ctl_addr); - - msleep(150); - ata_check_status(ap); - - msleep(50); - ata_check_status(ap); - - while (1) { - u8 status = ata_check_status(ap); - - if (!(status & ATA_BUSY)) - break; - - printf("Hard Disk status is BUSY.\n"); - msleep(50); - } - - tmp = ATA_DEVICE_OBS; - writeb(tmp, ioaddr->device_addr); - - nsect = readb(ioaddr->nsect_addr); - lbal = readb(ioaddr->lbal_addr); - - return 0; -} - -static u8 ata_check_status(struct ata_port *ap) -{ - u8 val = 0; - val = readb(ap->ioaddr.status_addr); - return val; -} - -static int ata_id_has_hipm(const u16 *id) -{ - u16 val = id[76]; - - if (val == 0 || val == 0xffff) - return -1; - - return val & (1 << 9); -} - -static int ata_id_has_dipm(const u16 *id) -{ - u16 val = id[78]; - - if (val == 0 || val == 0xffff) - return -1; - - return val & (1 << 3); -} - -int scan_sata(int dev) -{ - int i; - int rc; - u8 status; - const u16 *id; - struct ata_device *ata_dev = &ata_device; - unsigned long pio_mask, mwdma_mask; - char revbuf[7]; - u16 iobuf[ATA_SECTOR_WORDS]; - - memset(iobuf, 0, sizeof(iobuf)); - - if (dev_state == SATA_NODEVICE) - return 1; - - printf("Waiting for device..."); - i = 0; - while (1) { - udelay(10000); - - status = ata_check_altstatus(&ap); - - if ((status & ATA_BUSY) == 0) { - printf("\n"); - break; - } - - i++; - if (i > (ATA_RESET_TIME * 100)) { - printf("** TimeOUT **\n"); - - dev_state = SATA_NODEVICE; - return 1; - } - if ((i >= 100) && ((i % 100) == 0)) - printf("."); - } - - udelay(1000); - - rc = ata_dev_read_id(ata_dev, &ata_dev->class, - ATA_READID_POSTRESET,ata_dev->id); - if (rc) { - printf("sata_dwc : error. failed sata scan\n"); - return 1; - } - - /* SATA drives indicate we have a bridge. We don't know which - * end of the link the bridge is which is a problem - */ - if (ata_id_is_sata(ata_dev->id)) - ap.cbl = ATA_CBL_SATA; - - id = ata_dev->id; - - ata_dev->flags &= ~ATA_DFLAG_CFG_MASK; - ata_dev->max_sectors = 0; - ata_dev->cdb_len = 0; - ata_dev->n_sectors = 0; - ata_dev->cylinders = 0; - ata_dev->heads = 0; - ata_dev->sectors = 0; - - if (id[ATA_ID_FIELD_VALID] & (1 << 1)) { - pio_mask = id[ATA_ID_PIO_MODES] & 0x03; - pio_mask <<= 3; - pio_mask |= 0x7; - } else { - /* If word 64 isn't valid then Word 51 high byte holds - * the PIO timing number for the maximum. Turn it into - * a mask. - */ - u8 mode = (id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF; - if (mode < 5) { - pio_mask = (2 << mode) - 1; - } else { - pio_mask = 1; - } - } - - mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07; - - if (ata_id_is_cfa(id)) { - int pio = id[163] & 0x7; - int dma = (id[163] >> 3) & 7; - - if (pio) - pio_mask |= (1 << 5); - if (pio > 1) - pio_mask |= (1 << 6); - if (dma) - mwdma_mask |= (1 << 3); - if (dma > 1) - mwdma_mask |= (1 << 4); - } - - if (ata_dev->class == ATA_DEV_ATA) { - if (ata_id_is_cfa(id)) { - if (id[162] & 1) - printf("supports DRM functions and may " - "not be fully accessable.\n"); - strcpy(revbuf, "CFA"); - } else { - if (ata_id_has_tpm(id)) - printf("supports DRM functions and may " - "not be fully accessable.\n"); - } - - ata_dev->n_sectors = ata_id_n_sectors((u16*)id); - - if (ata_dev->id[59] & 0x100) - ata_dev->multi_count = ata_dev->id[59] & 0xff; - - if (ata_id_has_lba(id)) { - char ncq_desc[20]; - - ata_dev->flags |= ATA_DFLAG_LBA; - if (ata_id_has_lba48(id)) { - ata_dev->flags |= ATA_DFLAG_LBA48; - - if (ata_dev->n_sectors >= (1UL << 28) && - ata_id_has_flush_ext(id)) - ata_dev->flags |= ATA_DFLAG_FLUSH_EXT; - } - if (!ata_id_has_ncq(ata_dev->id)) - ncq_desc[0] = '\0'; - - if (ata_dev->horkage & ATA_HORKAGE_NONCQ) - strcpy(ncq_desc, "NCQ (not used)"); - - if (ap.flags & ATA_FLAG_NCQ) - ata_dev->flags |= ATA_DFLAG_NCQ; - } - ata_dev->cdb_len = 16; - } - ata_dev->max_sectors = ATA_MAX_SECTORS; - if (ata_dev->flags & ATA_DFLAG_LBA48) - ata_dev->max_sectors = ATA_MAX_SECTORS_LBA48; - - if (!(ata_dev->horkage & ATA_HORKAGE_IPM)) { - if (ata_id_has_hipm(ata_dev->id)) - ata_dev->flags |= ATA_DFLAG_HIPM; - if (ata_id_has_dipm(ata_dev->id)) - ata_dev->flags |= ATA_DFLAG_DIPM; - } - - if ((ap.cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ata_dev->id))) { - ata_dev->udma_mask &= ATA_UDMA5; - ata_dev->max_sectors = ATA_MAX_SECTORS; - } - - if (ata_dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { - printf("Drive reports diagnostics failure." - "This may indicate a drive\n"); - printf("fault or invalid emulation." - "Contact drive vendor for information.\n"); - } - - rc = check_sata_dev_state(); - - ata_id_c_string(ata_dev->id, - (unsigned char *)sata_dev_desc[dev].revision, - ATA_ID_FW_REV, sizeof(sata_dev_desc[dev].revision)); - ata_id_c_string(ata_dev->id, - (unsigned char *)sata_dev_desc[dev].vendor, - ATA_ID_PROD, sizeof(sata_dev_desc[dev].vendor)); - ata_id_c_string(ata_dev->id, - (unsigned char *)sata_dev_desc[dev].product, - ATA_ID_SERNO, sizeof(sata_dev_desc[dev].product)); - - sata_dev_desc[dev].lba = (u32) ata_dev->n_sectors; - -#ifdef CONFIG_LBA48 - if (ata_dev->id[83] & (1 << 10)) { - sata_dev_desc[dev].lba48 = 1; - } else { - sata_dev_desc[dev].lba48 = 0; - } -#endif - - return 0; -} - -static u8 ata_busy_wait(struct ata_port *ap, - unsigned int bits,unsigned int max) -{ - u8 status; - - do { - udelay(10); - status = ata_check_status(ap); - max--; - } while (status != 0xff && (status & bits) && (max > 0)); - - return status; -} - -static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, - unsigned int flags, u16 *id) -{ - struct ata_port *ap = pap; - unsigned int class = *p_class; - struct ata_taskfile tf; - unsigned int err_mask = 0; - const char *reason; - int may_fallback = 1, tried_spinup = 0; - u8 status; - int rc; - - status = ata_busy_wait(ap, ATA_BUSY, 30000); - if (status & ATA_BUSY) { - printf("BSY = 0 check. timeout.\n"); - rc = false; - return rc; - } - - ata_dev_select(ap, dev->devno, 1, 1); - -retry: - memset(&tf, 0, sizeof(tf)); - ap->print_id = 1; - ap->flags &= ~ATA_FLAG_DISABLED; - tf.ctl = ap->ctl; - tf.device = ATA_DEVICE_OBS; - tf.command = ATA_CMD_ID_ATA; - tf.protocol = ATA_PROT_PIO; - - /* Some devices choke if TF registers contain garbage. Make - * sure those are properly initialized. - */ - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - - /* Device presence detection is unreliable on some - * controllers. Always poll IDENTIFY if available. - */ - tf.flags |= ATA_TFLAG_POLLING; - - temp_n_block = 1; - - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, - sizeof(id[0]) * ATA_ID_WORDS, 0); - - if (err_mask) { - if (err_mask & AC_ERR_NODEV_HINT) { - printf("NODEV after polling detection\n"); - return -ENOENT; - } - - if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { - /* Device or controller might have reported - * the wrong device class. Give a shot at the - * other IDENTIFY if the current one is - * aborted by the device. - */ - if (may_fallback) { - may_fallback = 0; - - if (class == ATA_DEV_ATA) { - class = ATA_DEV_ATAPI; - } else { - class = ATA_DEV_ATA; - } - goto retry; - } - /* Control reaches here iff the device aborted - * both flavors of IDENTIFYs which happens - * sometimes with phantom devices. - */ - printf("both IDENTIFYs aborted, assuming NODEV\n"); - return -ENOENT; - } - rc = -EIO; - reason = "I/O error"; - goto err_out; - } - - /* Falling back doesn't make sense if ID data was read - * successfully at least once. - */ - may_fallback = 0; - - unsigned int id_cnt; - - for (id_cnt = 0; id_cnt < ATA_ID_WORDS; id_cnt++) - id[id_cnt] = le16_to_cpu(id[id_cnt]); - - - rc = -EINVAL; - reason = "device reports invalid type"; - - if (class == ATA_DEV_ATA) { - if (!ata_id_is_ata(id) && !ata_id_is_cfa(id)) - goto err_out; - } else { - if (ata_id_is_ata(id)) - goto err_out; - } - if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) { - tried_spinup = 1; - /* - * Drive powered-up in standby mode, and requires a specific - * SET_FEATURES spin-up subcommand before it will accept - * anything other than the original IDENTIFY command. - */ - err_mask = ata_dev_set_feature(dev, SETFEATURES_SPINUP, 0); - if (err_mask && id[2] != 0x738c) { - rc = -EIO; - reason = "SPINUP failed"; - goto err_out; - } - /* - * If the drive initially returned incomplete IDENTIFY info, - * we now must reissue the IDENTIFY command. - */ - if (id[2] == 0x37c8) - goto retry; - } - - if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) { - /* - * The exact sequence expected by certain pre-ATA4 drives is: - * SRST RESET - * IDENTIFY (optional in early ATA) - * INITIALIZE DEVICE PARAMETERS (later IDE and ATA) - * anything else.. - * Some drives were very specific about that exact sequence. - * - * Note that ATA4 says lba is mandatory so the second check - * shoud never trigger. - */ - if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { - err_mask = ata_dev_init_params(dev, id[3], id[6]); - if (err_mask) { - rc = -EIO; - reason = "INIT_DEV_PARAMS failed"; - goto err_out; - } - - /* current CHS translation info (id[53-58]) might be - * changed. reread the identify device info. - */ - flags &= ~ATA_READID_POSTRESET; - goto retry; - } - } - - *p_class = class; - return 0; - -err_out: - printf("failed to READ ID (%s, err_mask=0x%x)\n", reason, err_mask); - return rc; -} - -static u8 ata_wait_idle(struct ata_port *ap) -{ - u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - return status; -} - -static void ata_dev_select(struct ata_port *ap, unsigned int device, - unsigned int wait, unsigned int can_sleep) -{ - if (wait) - ata_wait_idle(ap); - - ata_std_dev_select(ap, device); - - if (wait) - ata_wait_idle(ap); -} - -static void ata_std_dev_select(struct ata_port *ap, unsigned int device) -{ - u8 tmp; - - if (device == 0) { - tmp = ATA_DEVICE_OBS; - } else { - tmp = ATA_DEVICE_OBS | ATA_DEV1; - } - - writeb(tmp, ap->ioaddr.device_addr); - - readb(ap->ioaddr.altstatus_addr); - - udelay(1); -} - -static int waiting_for_reg_state(volatile u8 *offset, - int timeout_msec, - u32 sign) -{ - int i; - u32 status; - - for (i = 0; i < timeout_msec; i++) { - status = readl(offset); - if ((status & sign) != 0) - break; - msleep(1); - } - - return (i < timeout_msec) ? 0 : -1; -} - -static void ata_qc_reinit(struct ata_queued_cmd *qc) -{ - qc->dma_dir = DMA_NONE; - qc->flags = 0; - qc->nbytes = qc->extrabytes = qc->curbytes = 0; - qc->n_elem = 0; - qc->err_mask = 0; - qc->sect_size = ATA_SECT_SIZE; - qc->nbytes = ATA_SECT_SIZE * temp_n_block; - - memset(&qc->tf, 0, sizeof(qc->tf)); - qc->tf.ctl = 0; - qc->tf.device = ATA_DEVICE_OBS; - - qc->result_tf.command = ATA_DRDY; - qc->result_tf.feature = 0; -} - -struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, - unsigned int tag) -{ - if (tag < ATA_MAX_QUEUE) - return &ap->qcmd[tag]; - return NULL; -} - -static void __ata_port_freeze(struct ata_port *ap) -{ - printf("set port freeze.\n"); - ap->pflags |= ATA_PFLAG_FROZEN; -} - -static int ata_port_freeze(struct ata_port *ap) -{ - __ata_port_freeze(ap); - return 0; -} - -unsigned ata_exec_internal(struct ata_device *dev, - struct ata_taskfile *tf, const u8 *cdb, - int dma_dir, unsigned int buflen, - unsigned long timeout) -{ - struct ata_link *link = dev->link; - struct ata_port *ap = pap; - struct ata_queued_cmd *qc; - unsigned int tag, preempted_tag; - u32 preempted_sactive, preempted_qc_active; - int preempted_nr_active_links; - unsigned int err_mask; - int rc = 0; - u8 status; - - status = ata_busy_wait(ap, ATA_BUSY, 300000); - if (status & ATA_BUSY) { - printf("BSY = 0 check. timeout.\n"); - rc = false; - return rc; - } - - if (ap->pflags & ATA_PFLAG_FROZEN) - return AC_ERR_SYSTEM; - - tag = ATA_TAG_INTERNAL; - - if (test_and_set_bit(tag, &ap->qc_allocated)) { - rc = false; - return rc; - } - - qc = __ata_qc_from_tag(ap, tag); - qc->tag = tag; - qc->ap = ap; - qc->dev = dev; - - ata_qc_reinit(qc); - - preempted_tag = link->active_tag; - preempted_sactive = link->sactive; - preempted_qc_active = ap->qc_active; - preempted_nr_active_links = ap->nr_active_links; - link->active_tag = ATA_TAG_POISON; - link->sactive = 0; - ap->qc_active = 0; - ap->nr_active_links = 0; - - qc->tf = *tf; - if (cdb) - memcpy(qc->cdb, cdb, ATAPI_CDB_LEN); - qc->flags |= ATA_QCFLAG_RESULT_TF; - qc->dma_dir = dma_dir; - qc->private_data = 0; - - ata_qc_issue(qc); - - if (!timeout) - timeout = ata_probe_timeout * 1000 / HZ; - - status = ata_busy_wait(ap, ATA_BUSY, 30000); - if (status & ATA_BUSY) { - printf("BSY = 0 check. timeout.\n"); - printf("altstatus = 0x%x.\n", status); - qc->err_mask |= AC_ERR_OTHER; - return qc->err_mask; - } - - if (waiting_for_reg_state(ap->ioaddr.altstatus_addr, 1000, 0x8)) { - u8 status = 0; - u8 errorStatus = 0; - - status = readb(ap->ioaddr.altstatus_addr); - if ((status & 0x01) != 0) { - errorStatus = readb(ap->ioaddr.feature_addr); - if (errorStatus == 0x04 && - qc->tf.command == ATA_CMD_PIO_READ_EXT){ - printf("Hard Disk doesn't support LBA48\n"); - dev_state = SATA_ERROR; - qc->err_mask |= AC_ERR_OTHER; - return qc->err_mask; - } - } - qc->err_mask |= AC_ERR_OTHER; - return qc->err_mask; - } - - status = ata_busy_wait(ap, ATA_BUSY, 10); - if (status & ATA_BUSY) { - printf("BSY = 0 check. timeout.\n"); - qc->err_mask |= AC_ERR_OTHER; - return qc->err_mask; - } - - ata_pio_task(ap); - - if (!rc) { - if (qc->flags & ATA_QCFLAG_ACTIVE) { - qc->err_mask |= AC_ERR_TIMEOUT; - ata_port_freeze(ap); - } - } - - if (qc->flags & ATA_QCFLAG_FAILED) { - if (qc->result_tf.command & (ATA_ERR | ATA_DF)) - qc->err_mask |= AC_ERR_DEV; - - if (!qc->err_mask) - qc->err_mask |= AC_ERR_OTHER; - - if (qc->err_mask & ~AC_ERR_OTHER) - qc->err_mask &= ~AC_ERR_OTHER; - } - - *tf = qc->result_tf; - err_mask = qc->err_mask; - ata_qc_free(qc); - link->active_tag = preempted_tag; - link->sactive = preempted_sactive; - ap->qc_active = preempted_qc_active; - ap->nr_active_links = preempted_nr_active_links; - - if (ap->flags & ATA_FLAG_DISABLED) { - err_mask |= AC_ERR_SYSTEM; - ap->flags &= ~ATA_FLAG_DISABLED; - } - - return err_mask; -} - -static void ata_qc_issue(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct ata_link *link = qc->dev->link; - u8 prot = qc->tf.protocol; - - if (ata_is_ncq(prot)) { - if (!link->sactive) - ap->nr_active_links++; - link->sactive |= 1 << qc->tag; - } else { - ap->nr_active_links++; - link->active_tag = qc->tag; - } - - qc->flags |= ATA_QCFLAG_ACTIVE; - ap->qc_active |= 1 << qc->tag; - - if (qc->dev->flags & ATA_DFLAG_SLEEPING) { - msleep(1); - return; - } - - qc->err_mask |= ata_qc_issue_prot(qc); - if (qc->err_mask) - goto err; - - return; -err: - ata_qc_complete(qc); -} - -static unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - - if (ap->flags & ATA_FLAG_PIO_POLLING) { - switch (qc->tf.protocol) { - case ATA_PROT_PIO: - case ATA_PROT_NODATA: - case ATAPI_PROT_PIO: - case ATAPI_PROT_NODATA: - qc->tf.flags |= ATA_TFLAG_POLLING; - break; - default: - break; - } - } - - ata_dev_select(ap, qc->dev->devno, 1, 0); - - switch (qc->tf.protocol) { - case ATA_PROT_PIO: - if (qc->tf.flags & ATA_TFLAG_POLLING) - qc->tf.ctl |= ATA_NIEN; - - ata_tf_to_host(ap, &qc->tf); - - ap->hsm_task_state = HSM_ST; - - if (qc->tf.flags & ATA_TFLAG_POLLING) - ata_pio_queue_task(ap, qc, 0); - - break; - - default: - return AC_ERR_SYSTEM; - } - - return 0; -} - -static void ata_tf_to_host(struct ata_port *ap, - const struct ata_taskfile *tf) -{ - ata_tf_load(ap, tf); - ata_exec_command(ap, tf); -} - -static void ata_tf_load(struct ata_port *ap, - const struct ata_taskfile *tf) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; - - if (tf->ctl != ap->last_ctl) { - if (ioaddr->ctl_addr) - writeb(tf->ctl, ioaddr->ctl_addr); - ap->last_ctl = tf->ctl; - ata_wait_idle(ap); - } - - if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - writeb(tf->hob_feature, ioaddr->feature_addr); - writeb(tf->hob_nsect, ioaddr->nsect_addr); - writeb(tf->hob_lbal, ioaddr->lbal_addr); - writeb(tf->hob_lbam, ioaddr->lbam_addr); - writeb(tf->hob_lbah, ioaddr->lbah_addr); - } - - if (is_addr) { - writeb(tf->feature, ioaddr->feature_addr); - writeb(tf->nsect, ioaddr->nsect_addr); - writeb(tf->lbal, ioaddr->lbal_addr); - writeb(tf->lbam, ioaddr->lbam_addr); - writeb(tf->lbah, ioaddr->lbah_addr); - } - - if (tf->flags & ATA_TFLAG_DEVICE) - writeb(tf->device, ioaddr->device_addr); - - ata_wait_idle(ap); -} - -static void ata_exec_command(struct ata_port *ap, - const struct ata_taskfile *tf) -{ - writeb(tf->command, ap->ioaddr.command_addr); - - readb(ap->ioaddr.altstatus_addr); - - udelay(1); -} - -static void ata_pio_queue_task(struct ata_port *ap, - void *data,unsigned long delay) -{ - ap->port_task_data = data; -} - -static unsigned int ac_err_mask(u8 status) -{ - if (status & (ATA_BUSY | ATA_DRQ)) - return AC_ERR_HSM; - if (status & (ATA_ERR | ATA_DF)) - return AC_ERR_DEV; - return 0; -} - -static unsigned int __ac_err_mask(u8 status) -{ - unsigned int mask = ac_err_mask(status); - if (mask == 0) - return AC_ERR_OTHER; - return mask; -} - -static void ata_pio_task(struct ata_port *arg_ap) -{ - struct ata_port *ap = arg_ap; - struct ata_queued_cmd *qc = ap->port_task_data; - u8 status; - int poll_next; - -fsm_start: - /* - * This is purely heuristic. This is a fast path. - * Sometimes when we enter, BSY will be cleared in - * a chk-status or two. If not, the drive is probably seeking - * or something. Snooze for a couple msecs, then - * chk-status again. If still busy, queue delayed work. - */ - status = ata_busy_wait(ap, ATA_BUSY, 5); - if (status & ATA_BUSY) { - msleep(2); - status = ata_busy_wait(ap, ATA_BUSY, 10); - if (status & ATA_BUSY) { - ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE); - return; - } - } - - poll_next = ata_hsm_move(ap, qc, status, 1); - - /* another command or interrupt handler - * may be running at this point. - */ - if (poll_next) - goto fsm_start; -} - -static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, - u8 status, int in_wq) -{ - int poll_next; - -fsm_start: - switch (ap->hsm_task_state) { - case HSM_ST_FIRST: - poll_next = (qc->tf.flags & ATA_TFLAG_POLLING); - - if ((status & ATA_DRQ) == 0) { - if (status & (ATA_ERR | ATA_DF)) { - qc->err_mask |= AC_ERR_DEV; - } else { - qc->err_mask |= AC_ERR_HSM; - } - ap->hsm_task_state = HSM_ST_ERR; - goto fsm_start; - } - - /* Device should not ask for data transfer (DRQ=1) - * when it finds something wrong. - * We ignore DRQ here and stop the HSM by - * changing hsm_task_state to HSM_ST_ERR and - * let the EH abort the command or reset the device. - */ - if (status & (ATA_ERR | ATA_DF)) { - if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) { - printf("DRQ=1 with device error, " - "dev_stat 0x%X\n", status); - qc->err_mask |= AC_ERR_HSM; - ap->hsm_task_state = HSM_ST_ERR; - goto fsm_start; - } - } - - if (qc->tf.protocol == ATA_PROT_PIO) { - /* PIO data out protocol. - * send first data block. - */ - /* ata_pio_sectors() might change the state - * to HSM_ST_LAST. so, the state is changed here - * before ata_pio_sectors(). - */ - ap->hsm_task_state = HSM_ST; - ata_pio_sectors(qc); - } else { - printf("protocol is not ATA_PROT_PIO \n"); - } - break; - - case HSM_ST: - if ((status & ATA_DRQ) == 0) { - if (status & (ATA_ERR | ATA_DF)) { - qc->err_mask |= AC_ERR_DEV; - } else { - /* HSM violation. Let EH handle this. - * Phantom devices also trigger this - * condition. Mark hint. - */ - qc->err_mask |= AC_ERR_HSM | AC_ERR_NODEV_HINT; - } - - ap->hsm_task_state = HSM_ST_ERR; - goto fsm_start; - } - /* For PIO reads, some devices may ask for - * data transfer (DRQ=1) alone with ERR=1. - * We respect DRQ here and transfer one - * block of junk data before changing the - * hsm_task_state to HSM_ST_ERR. - * - * For PIO writes, ERR=1 DRQ=1 doesn't make - * sense since the data block has been - * transferred to the device. - */ - if (status & (ATA_ERR | ATA_DF)) { - qc->err_mask |= AC_ERR_DEV; - - if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { - ata_pio_sectors(qc); - status = ata_wait_idle(ap); - } - - if (status & (ATA_BUSY | ATA_DRQ)) - qc->err_mask |= AC_ERR_HSM; - - /* ata_pio_sectors() might change the - * state to HSM_ST_LAST. so, the state - * is changed after ata_pio_sectors(). - */ - ap->hsm_task_state = HSM_ST_ERR; - goto fsm_start; - } - - ata_pio_sectors(qc); - if (ap->hsm_task_state == HSM_ST_LAST && - (!(qc->tf.flags & ATA_TFLAG_WRITE))) { - status = ata_wait_idle(ap); - goto fsm_start; - } - - poll_next = 1; - break; - - case HSM_ST_LAST: - if (!ata_ok(status)) { - qc->err_mask |= __ac_err_mask(status); - ap->hsm_task_state = HSM_ST_ERR; - goto fsm_start; - } - - ap->hsm_task_state = HSM_ST_IDLE; - - ata_hsm_qc_complete(qc, in_wq); - - poll_next = 0; - break; - - case HSM_ST_ERR: - /* make sure qc->err_mask is available to - * know what's wrong and recover - */ - ap->hsm_task_state = HSM_ST_IDLE; - - ata_hsm_qc_complete(qc, in_wq); - - poll_next = 0; - break; - default: - poll_next = 0; - } - - return poll_next; -} - -static void ata_pio_sectors(struct ata_queued_cmd *qc) -{ - struct ata_port *ap; - ap = pap; - qc->pdata = ap->pdata; - - ata_pio_sector(qc); - - readb(qc->ap->ioaddr.altstatus_addr); - udelay(1); -} - -static void ata_pio_sector(struct ata_queued_cmd *qc) -{ - int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); - struct ata_port *ap = qc->ap; - unsigned int offset; - unsigned char *buf; - char temp_data_buf[512]; - - if (qc->curbytes == qc->nbytes - qc->sect_size) - ap->hsm_task_state = HSM_ST_LAST; - - offset = qc->curbytes; - - switch (qc->tf.command) { - case ATA_CMD_ID_ATA: - buf = (unsigned char *)&ata_device.id[0]; - break; - case ATA_CMD_PIO_READ_EXT: - case ATA_CMD_PIO_READ: - case ATA_CMD_PIO_WRITE_EXT: - case ATA_CMD_PIO_WRITE: - buf = qc->pdata + offset; - break; - default: - buf = (unsigned char *)&temp_data_buf[0]; - } - - ata_mmio_data_xfer(qc->dev, buf, qc->sect_size, do_write); - - qc->curbytes += qc->sect_size; - -} - -static void ata_mmio_data_xfer(struct ata_device *dev, unsigned char *buf, - unsigned int buflen, int do_write) -{ - struct ata_port *ap = pap; - void __iomem *data_addr = ap->ioaddr.data_addr; - unsigned int words = buflen >> 1; - u16 *buf16 = (u16 *)buf; - unsigned int i = 0; - - udelay(100); - if (do_write) { - for (i = 0; i < words; i++) - writew(le16_to_cpu(buf16[i]), data_addr); - } else { - for (i = 0; i < words; i++) - buf16[i] = cpu_to_le16(readw(data_addr)); - } - - if (buflen & 0x01) { - __le16 align_buf[1] = { 0 }; - unsigned char *trailing_buf = buf + buflen - 1; - - if (do_write) { - memcpy(align_buf, trailing_buf, 1); - writew(le16_to_cpu(align_buf[0]), data_addr); - } else { - align_buf[0] = cpu_to_le16(readw(data_addr)); - memcpy(trailing_buf, align_buf, 1); - } - } -} - -static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) -{ - struct ata_port *ap = qc->ap; - - if (in_wq) { - /* EH might have kicked in while host lock is - * released. - */ - qc = &ap->qcmd[qc->tag]; - if (qc) { - if (!(qc->err_mask & AC_ERR_HSM)) { - ata_irq_on(ap); - ata_qc_complete(qc); - } else { - ata_port_freeze(ap); - } - } - } else { - if (!(qc->err_mask & AC_ERR_HSM)) { - ata_qc_complete(qc); - } else { - ata_port_freeze(ap); - } - } -} - -static u8 ata_irq_on(struct ata_port *ap) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - u8 tmp; - - ap->ctl &= ~ATA_NIEN; - ap->last_ctl = ap->ctl; - - if (ioaddr->ctl_addr) - writeb(ap->ctl, ioaddr->ctl_addr); - - tmp = ata_wait_idle(ap); - - return tmp; -} - -static unsigned int ata_tag_internal(unsigned int tag) -{ - return tag == ATA_MAX_QUEUE - 1; -} - -static void ata_qc_complete(struct ata_queued_cmd *qc) -{ - struct ata_device *dev = qc->dev; - if (qc->err_mask) - qc->flags |= ATA_QCFLAG_FAILED; - - if (qc->flags & ATA_QCFLAG_FAILED) { - if (!ata_tag_internal(qc->tag)) { - fill_result_tf(qc); - return; - } - } - if (qc->flags & ATA_QCFLAG_RESULT_TF) - fill_result_tf(qc); - - /* Some commands need post-processing after successful - * completion. - */ - switch (qc->tf.command) { - case ATA_CMD_SET_FEATURES: - if (qc->tf.feature != SETFEATURES_WC_ON && - qc->tf.feature != SETFEATURES_WC_OFF) - break; - case ATA_CMD_INIT_DEV_PARAMS: - case ATA_CMD_SET_MULTI: - break; - - case ATA_CMD_SLEEP: - dev->flags |= ATA_DFLAG_SLEEPING; - break; - } - - __ata_qc_complete(qc); -} - -static void fill_result_tf(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - - qc->result_tf.flags = qc->tf.flags; - ata_tf_read(ap, &qc->result_tf); -} - -static void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) -{ - struct ata_ioports *ioaddr = &ap->ioaddr; - - tf->command = ata_check_status(ap); - tf->feature = readb(ioaddr->error_addr); - tf->nsect = readb(ioaddr->nsect_addr); - tf->lbal = readb(ioaddr->lbal_addr); - tf->lbam = readb(ioaddr->lbam_addr); - tf->lbah = readb(ioaddr->lbah_addr); - tf->device = readb(ioaddr->device_addr); - - if (tf->flags & ATA_TFLAG_LBA48) { - if (ioaddr->ctl_addr) { - writeb(tf->ctl | ATA_HOB, ioaddr->ctl_addr); - - tf->hob_feature = readb(ioaddr->error_addr); - tf->hob_nsect = readb(ioaddr->nsect_addr); - tf->hob_lbal = readb(ioaddr->lbal_addr); - tf->hob_lbam = readb(ioaddr->lbam_addr); - tf->hob_lbah = readb(ioaddr->lbah_addr); - - writeb(tf->ctl, ioaddr->ctl_addr); - ap->last_ctl = tf->ctl; - } else { - printf("sata_dwc warnning register read.\n"); - } - } -} - -static void __ata_qc_complete(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct ata_link *link = qc->dev->link; - - link->active_tag = ATA_TAG_POISON; - ap->nr_active_links--; - - if (qc->flags & ATA_QCFLAG_CLEAR_EXCL && ap->excl_link == link) - ap->excl_link = NULL; - - qc->flags &= ~ATA_QCFLAG_ACTIVE; - ap->qc_active &= ~(1 << qc->tag); -} - -static void ata_qc_free(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - unsigned int tag; - qc->flags = 0; - tag = qc->tag; - if (tag < ATA_MAX_QUEUE) { - qc->tag = ATA_TAG_POISON; - clear_bit(tag, &ap->qc_allocated); - } -} - -static int check_sata_dev_state(void) -{ - unsigned long datalen; - unsigned char *pdata; - int ret = 0; - int i = 0; - char temp_data_buf[512]; - - while (1) { - udelay(10000); - - pdata = (unsigned char*)&temp_data_buf[0]; - datalen = 512; - - ret = ata_dev_read_sectors(pdata, datalen, 0, 1); - - if (ret == true) - break; - - i++; - if (i > (ATA_RESET_TIME * 100)) { - printf("** TimeOUT **\n"); - dev_state = SATA_NODEVICE; - return false; - } - - if ((i >= 100) && ((i % 100) == 0)) - printf("."); - } - - dev_state = SATA_READY; - - return true; -} - -static unsigned int ata_dev_set_feature(struct ata_device *dev, - u8 enable, u8 feature) -{ - struct ata_taskfile tf; - struct ata_port *ap; - ap = pap; - unsigned int err_mask; - - memset(&tf, 0, sizeof(tf)); - tf.ctl = ap->ctl; - - tf.device = ATA_DEVICE_OBS; - tf.command = ATA_CMD_SET_FEATURES; - tf.feature = enable; - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf.protocol = ATA_PROT_NODATA; - tf.nsect = feature; - - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); - - return err_mask; -} - -static unsigned int ata_dev_init_params(struct ata_device *dev, - u16 heads, u16 sectors) -{ - struct ata_taskfile tf; - struct ata_port *ap; - ap = pap; - unsigned int err_mask; - - if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16) - return AC_ERR_INVALID; - - memset(&tf, 0, sizeof(tf)); - tf.ctl = ap->ctl; - tf.device = ATA_DEVICE_OBS; - tf.command = ATA_CMD_INIT_DEV_PARAMS; - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf.protocol = ATA_PROT_NODATA; - tf.nsect = sectors; - tf.device |= (heads - 1) & 0x0f; - - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); - - if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED)) - err_mask = 0; - - return err_mask; -} - -#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48) -#define SATA_MAX_READ_BLK 0xFF -#else -#define SATA_MAX_READ_BLK 0xFFFF -#endif - -ulong sata_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer) -{ - ulong start,blks, buf_addr; - unsigned short smallblks; - unsigned long datalen; - unsigned char *pdata; - device &= 0xff; - - u32 block = 0; - u32 n_block = 0; - - if (dev_state != SATA_READY) - return 0; - - buf_addr = (unsigned long)buffer; - start = blknr; - blks = blkcnt; - do { - pdata = (unsigned char *)buf_addr; - if (blks > SATA_MAX_READ_BLK) { - datalen = sata_dev_desc[device].blksz * SATA_MAX_READ_BLK; - smallblks = SATA_MAX_READ_BLK; - - block = (u32)start; - n_block = (u32)smallblks; - - start += SATA_MAX_READ_BLK; - blks -= SATA_MAX_READ_BLK; - } else { - datalen = sata_dev_desc[device].blksz * SATA_MAX_READ_BLK; - datalen = sata_dev_desc[device].blksz * blks; - smallblks = (unsigned short)blks; - - block = (u32)start; - n_block = (u32)smallblks; - - start += blks; - blks = 0; - } - - if (ata_dev_read_sectors(pdata, datalen, block, n_block) != true) { - printf("sata_dwc : Hard disk read error.\n"); - blkcnt -= blks; - break; - } - buf_addr += datalen; - } while (blks != 0); - - return (blkcnt); -} - -static int ata_dev_read_sectors(unsigned char *pdata, unsigned long datalen, - u32 block, u32 n_block) -{ - struct ata_port *ap = pap; - struct ata_device *dev = &ata_device; - struct ata_taskfile tf; - unsigned int class = ATA_DEV_ATA; - unsigned int err_mask = 0; - const char *reason; - int may_fallback = 1; - - if (dev_state == SATA_ERROR) - return false; - - ata_dev_select(ap, dev->devno, 1, 1); - -retry: - memset(&tf, 0, sizeof(tf)); - tf.ctl = ap->ctl; - ap->print_id = 1; - ap->flags &= ~ATA_FLAG_DISABLED; - - ap->pdata = pdata; - - tf.device = ATA_DEVICE_OBS; - - temp_n_block = n_block; - -#ifdef CONFIG_LBA48 - tf.command = ATA_CMD_PIO_READ_EXT; - tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; - - tf.hob_feature = 31; - tf.feature = 31; - tf.hob_nsect = (n_block >> 8) & 0xff; - tf.nsect = n_block & 0xff; - - tf.hob_lbah = 0x0; - tf.hob_lbam = 0x0; - tf.hob_lbal = (block >> 24) & 0xff; - tf.lbah = (block >> 16) & 0xff; - tf.lbam = (block >> 8) & 0xff; - tf.lbal = block & 0xff; - - tf.device = 1 << 6; - if (tf.flags & ATA_TFLAG_FUA) - tf.device |= 1 << 7; -#else - tf.command = ATA_CMD_PIO_READ; - tf.flags |= ATA_TFLAG_LBA ; - - tf.feature = 31; - tf.nsect = n_block & 0xff; - - tf.lbah = (block >> 16) & 0xff; - tf.lbam = (block >> 8) & 0xff; - tf.lbal = block & 0xff; - - tf.device = (block >> 24) & 0xf; - - tf.device |= 1 << 6; - if (tf.flags & ATA_TFLAG_FUA) - tf.device |= 1 << 7; - -#endif - - tf.protocol = ATA_PROT_PIO; - - /* Some devices choke if TF registers contain garbage. Make - * sure those are properly initialized. - */ - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf.flags |= ATA_TFLAG_POLLING; - - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, 0, 0); - - if (err_mask) { - if (err_mask & AC_ERR_NODEV_HINT) { - printf("READ_SECTORS NODEV after polling detection\n"); - return -ENOENT; - } - - if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { - /* Device or controller might have reported - * the wrong device class. Give a shot at the - * other IDENTIFY if the current one is - * aborted by the device. - */ - if (may_fallback) { - may_fallback = 0; - - if (class == ATA_DEV_ATA) { - class = ATA_DEV_ATAPI; - } else { - class = ATA_DEV_ATA; - } - goto retry; - } - /* Control reaches here iff the device aborted - * both flavors of IDENTIFYs which happens - * sometimes with phantom devices. - */ - printf("both IDENTIFYs aborted, assuming NODEV\n"); - return -ENOENT; - } - - reason = "I/O error"; - goto err_out; - } - - return true; - -err_out: - printf("failed to READ SECTORS (%s, err_mask=0x%x)\n", reason, err_mask); - return false; -} - -#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48) -#define SATA_MAX_WRITE_BLK 0xFF -#else -#define SATA_MAX_WRITE_BLK 0xFFFF -#endif - -ulong sata_write(int device, ulong blknr, lbaint_t blkcnt, const void *buffer) -{ - ulong start,blks, buf_addr; - unsigned short smallblks; - unsigned long datalen; - unsigned char *pdata; - device &= 0xff; - - - u32 block = 0; - u32 n_block = 0; - - if (dev_state != SATA_READY) - return 0; - - buf_addr = (unsigned long)buffer; - start = blknr; - blks = blkcnt; - do { - pdata = (unsigned char *)buf_addr; - if (blks > SATA_MAX_WRITE_BLK) { - datalen = sata_dev_desc[device].blksz * SATA_MAX_WRITE_BLK; - smallblks = SATA_MAX_WRITE_BLK; - - block = (u32)start; - n_block = (u32)smallblks; - - start += SATA_MAX_WRITE_BLK; - blks -= SATA_MAX_WRITE_BLK; - } else { - datalen = sata_dev_desc[device].blksz * blks; - smallblks = (unsigned short)blks; - - block = (u32)start; - n_block = (u32)smallblks; - - start += blks; - blks = 0; - } - - if (ata_dev_write_sectors(pdata, datalen, block, n_block) != true) { - printf("sata_dwc : Hard disk read error.\n"); - blkcnt -= blks; - break; - } - buf_addr += datalen; - } while (blks != 0); - - return (blkcnt); -} - -static int ata_dev_write_sectors(unsigned char* pdata, unsigned long datalen, - u32 block, u32 n_block) -{ - struct ata_port *ap = pap; - struct ata_device *dev = &ata_device; - struct ata_taskfile tf; - unsigned int class = ATA_DEV_ATA; - unsigned int err_mask = 0; - const char *reason; - int may_fallback = 1; - - if (dev_state == SATA_ERROR) - return false; - - ata_dev_select(ap, dev->devno, 1, 1); - -retry: - memset(&tf, 0, sizeof(tf)); - tf.ctl = ap->ctl; - ap->print_id = 1; - ap->flags &= ~ATA_FLAG_DISABLED; - - ap->pdata = pdata; - - tf.device = ATA_DEVICE_OBS; - - temp_n_block = n_block; - - -#ifdef CONFIG_LBA48 - tf.command = ATA_CMD_PIO_WRITE_EXT; - tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48 | ATA_TFLAG_WRITE; - - tf.hob_feature = 31; - tf.feature = 31; - tf.hob_nsect = (n_block >> 8) & 0xff; - tf.nsect = n_block & 0xff; - - tf.hob_lbah = 0x0; - tf.hob_lbam = 0x0; - tf.hob_lbal = (block >> 24) & 0xff; - tf.lbah = (block >> 16) & 0xff; - tf.lbam = (block >> 8) & 0xff; - tf.lbal = block & 0xff; - - tf.device = 1 << 6; - if (tf.flags & ATA_TFLAG_FUA) - tf.device |= 1 << 7; -#else - tf.command = ATA_CMD_PIO_WRITE; - tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_WRITE; - - tf.feature = 31; - tf.nsect = n_block & 0xff; - - tf.lbah = (block >> 16) & 0xff; - tf.lbam = (block >> 8) & 0xff; - tf.lbal = block & 0xff; - - tf.device = (block >> 24) & 0xf; - - tf.device |= 1 << 6; - if (tf.flags & ATA_TFLAG_FUA) - tf.device |= 1 << 7; - -#endif - - tf.protocol = ATA_PROT_PIO; - - /* Some devices choke if TF registers contain garbage. Make - * sure those are properly initialized. - */ - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf.flags |= ATA_TFLAG_POLLING; - - err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, 0, 0); - - if (err_mask) { - if (err_mask & AC_ERR_NODEV_HINT) { - printf("READ_SECTORS NODEV after polling detection\n"); - return -ENOENT; - } - - if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { - /* Device or controller might have reported - * the wrong device class. Give a shot at the - * other IDENTIFY if the current one is - * aborted by the device. - */ - if (may_fallback) { - may_fallback = 0; - - if (class == ATA_DEV_ATA) { - class = ATA_DEV_ATAPI; - } else { - class = ATA_DEV_ATA; - } - goto retry; - } - /* Control reaches here iff the device aborted - * both flavors of IDENTIFYs which happens - * sometimes with phantom devices. - */ - printf("both IDENTIFYs aborted, assuming NODEV\n"); - return -ENOENT; - } - - reason = "I/O error"; - goto err_out; - } - - return true; - -err_out: - printf("failed to WRITE SECTORS (%s, err_mask=0x%x)\n", reason, err_mask); - return false; -} diff --git a/drivers/block/sata_dwc.h b/drivers/block/sata_dwc.h deleted file mode 100644 index e2d9e0c1fc..0000000000 --- a/drivers/block/sata_dwc.h +++ /dev/null @@ -1,465 +0,0 @@ -/* - * sata_dwc.h - * - * Synopsys DesignWare Cores (DWC) SATA host driver - * - * Author: Mark Miesfeld - * - * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese - * Copyright 2008 DENX Software Engineering - * - * Based on versions provided by AMCC and Synopsys which are: - * Copyright 2006 Applied Micro Circuits Corporation - * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED - * - * SPDX-License-Identifier: GPL-2.0+ - */ -/* - * SATA support based on the chip canyonlands. - * - * 04-17-2009 - * The local version of this driver for the canyonlands board - * does not use interrupts but polls the chip instead. - */ - - -#ifndef _SATA_DWC_H_ -#define _SATA_DWC_H_ - -#define __U_BOOT__ - -#define HZ 100 -#define READ 0 -#define WRITE 1 - -enum { - ATA_READID_POSTRESET = (1 << 0), - - ATA_DNXFER_PIO = 0, - ATA_DNXFER_DMA = 1, - ATA_DNXFER_40C = 2, - ATA_DNXFER_FORCE_PIO = 3, - ATA_DNXFER_FORCE_PIO0 = 4, - - ATA_DNXFER_QUIET = (1 << 31), -}; - -enum hsm_task_states { - HSM_ST_IDLE, - HSM_ST_FIRST, - HSM_ST, - HSM_ST_LAST, - HSM_ST_ERR, -}; - -#define ATA_SHORT_PAUSE ((HZ >> 6) + 1) - -struct ata_queued_cmd { - struct ata_port *ap; - struct ata_device *dev; - - struct ata_taskfile tf; - u8 cdb[ATAPI_CDB_LEN]; - unsigned long flags; - unsigned int tag; - unsigned int n_elem; - - int dma_dir; - unsigned int sect_size; - - unsigned int nbytes; - unsigned int extrabytes; - unsigned int curbytes; - - unsigned int err_mask; - struct ata_taskfile result_tf; - - void *private_data; -#ifndef __U_BOOT__ - void *lldd_task; -#endif - unsigned char *pdata; -}; - -typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc); - -#define ATA_TAG_POISON 0xfafbfcfdU - -enum { - LIBATA_MAX_PRD = ATA_MAX_PRD / 2, - LIBATA_DUMB_MAX_PRD = ATA_MAX_PRD / 4, - ATA_MAX_PORTS = 8, - ATA_DEF_QUEUE = 1, - ATA_MAX_QUEUE = 32, - ATA_TAG_INTERNAL = ATA_MAX_QUEUE - 1, - ATA_MAX_BUS = 2, - ATA_DEF_BUSY_WAIT = 10000, - - ATAPI_MAX_DRAIN = 16 << 10, - - ATA_SHT_EMULATED = 1, - ATA_SHT_CMD_PER_LUN = 1, - ATA_SHT_THIS_ID = -1, - ATA_SHT_USE_CLUSTERING = 1, - - ATA_DFLAG_LBA = (1 << 0), - ATA_DFLAG_LBA48 = (1 << 1), - ATA_DFLAG_CDB_INTR = (1 << 2), - ATA_DFLAG_NCQ = (1 << 3), - ATA_DFLAG_FLUSH_EXT = (1 << 4), - ATA_DFLAG_ACPI_PENDING = (1 << 5), - ATA_DFLAG_ACPI_FAILED = (1 << 6), - ATA_DFLAG_AN = (1 << 7), - ATA_DFLAG_HIPM = (1 << 8), - ATA_DFLAG_DIPM = (1 << 9), - ATA_DFLAG_DMADIR = (1 << 10), - ATA_DFLAG_CFG_MASK = (1 << 12) - 1, - - ATA_DFLAG_PIO = (1 << 12), - ATA_DFLAG_NCQ_OFF = (1 << 13), - ATA_DFLAG_SPUNDOWN = (1 << 14), - ATA_DFLAG_SLEEPING = (1 << 15), - ATA_DFLAG_DUBIOUS_XFER = (1 << 16), - ATA_DFLAG_INIT_MASK = (1 << 24) - 1, - - ATA_DFLAG_DETACH = (1 << 24), - ATA_DFLAG_DETACHED = (1 << 25), - - ATA_LFLAG_HRST_TO_RESUME = (1 << 0), - ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), - ATA_LFLAG_NO_SRST = (1 << 2), - ATA_LFLAG_ASSUME_ATA = (1 << 3), - ATA_LFLAG_ASSUME_SEMB = (1 << 4), - ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, - ATA_LFLAG_NO_RETRY = (1 << 5), - ATA_LFLAG_DISABLED = (1 << 6), - - ATA_FLAG_SLAVE_POSS = (1 << 0), - ATA_FLAG_SATA = (1 << 1), - ATA_FLAG_NO_LEGACY = (1 << 2), - ATA_FLAG_MMIO = (1 << 3), - ATA_FLAG_SRST = (1 << 4), - ATA_FLAG_SATA_RESET = (1 << 5), - ATA_FLAG_NO_ATAPI = (1 << 6), - ATA_FLAG_PIO_DMA = (1 << 7), - ATA_FLAG_PIO_LBA48 = (1 << 8), - ATA_FLAG_PIO_POLLING = (1 << 9), - ATA_FLAG_NCQ = (1 << 10), - ATA_FLAG_DEBUGMSG = (1 << 13), - ATA_FLAG_IGN_SIMPLEX = (1 << 15), - ATA_FLAG_NO_IORDY = (1 << 16), - ATA_FLAG_ACPI_SATA = (1 << 17), - ATA_FLAG_AN = (1 << 18), - ATA_FLAG_PMP = (1 << 19), - ATA_FLAG_IPM = (1 << 20), - - ATA_FLAG_DISABLED = (1 << 23), - - ATA_PFLAG_EH_PENDING = (1 << 0), - ATA_PFLAG_EH_IN_PROGRESS = (1 << 1), - ATA_PFLAG_FROZEN = (1 << 2), - ATA_PFLAG_RECOVERED = (1 << 3), - ATA_PFLAG_LOADING = (1 << 4), - ATA_PFLAG_UNLOADING = (1 << 5), - ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), - ATA_PFLAG_INITIALIZING = (1 << 7), - ATA_PFLAG_RESETTING = (1 << 8), - ATA_PFLAG_SUSPENDED = (1 << 17), - ATA_PFLAG_PM_PENDING = (1 << 18), - - ATA_QCFLAG_ACTIVE = (1 << 0), - ATA_QCFLAG_DMAMAP = (1 << 1), - ATA_QCFLAG_IO = (1 << 3), - ATA_QCFLAG_RESULT_TF = (1 << 4), - ATA_QCFLAG_CLEAR_EXCL = (1 << 5), - ATA_QCFLAG_QUIET = (1 << 6), - - ATA_QCFLAG_FAILED = (1 << 16), - ATA_QCFLAG_SENSE_VALID = (1 << 17), - ATA_QCFLAG_EH_SCHEDULED = (1 << 18), - - ATA_HOST_SIMPLEX = (1 << 0), - ATA_HOST_STARTED = (1 << 1), - - ATA_TMOUT_BOOT = 30 * 100, - ATA_TMOUT_BOOT_QUICK = 7 * 100, - ATA_TMOUT_INTERNAL = 30 * 100, - ATA_TMOUT_INTERNAL_QUICK = 5 * 100, - - /* FIXME: GoVault needs 2s but we can't afford that without - * parallel probing. 800ms is enough for iVDR disk - * HHD424020F7SV00. Increase to 2secs when parallel probing - * is in place. - */ - ATA_TMOUT_FF_WAIT = 4 * 100 / 5, - - BUS_UNKNOWN = 0, - BUS_DMA = 1, - BUS_IDLE = 2, - BUS_NOINTR = 3, - BUS_NODATA = 4, - BUS_TIMER = 5, - BUS_PIO = 6, - BUS_EDD = 7, - BUS_IDENTIFY = 8, - BUS_PACKET = 9, - - PORT_UNKNOWN = 0, - PORT_ENABLED = 1, - PORT_DISABLED = 2, - - /* encoding various smaller bitmaps into a single - * unsigned long bitmap - */ - ATA_NR_PIO_MODES = 7, - ATA_NR_MWDMA_MODES = 5, - ATA_NR_UDMA_MODES = 8, - - ATA_SHIFT_PIO = 0, - ATA_SHIFT_MWDMA = ATA_SHIFT_PIO + ATA_NR_PIO_MODES, - ATA_SHIFT_UDMA = ATA_SHIFT_MWDMA + ATA_NR_MWDMA_MODES, - - ATA_DMA_PAD_SZ = 4, - - ATA_ERING_SIZE = 32, - - ATA_DEFER_LINK = 1, - ATA_DEFER_PORT = 2, - - ATA_EH_DESC_LEN = 80, - - ATA_EH_REVALIDATE = (1 << 0), - ATA_EH_SOFTRESET = (1 << 1), - ATA_EH_HARDRESET = (1 << 2), - ATA_EH_ENABLE_LINK = (1 << 3), - ATA_EH_LPM = (1 << 4), - - ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, - ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, - - ATA_EHI_HOTPLUGGED = (1 << 0), - ATA_EHI_RESUME_LINK = (1 << 1), - ATA_EHI_NO_AUTOPSY = (1 << 2), - ATA_EHI_QUIET = (1 << 3), - - ATA_EHI_DID_SOFTRESET = (1 << 16), - ATA_EHI_DID_HARDRESET = (1 << 17), - ATA_EHI_PRINTINFO = (1 << 18), - ATA_EHI_SETMODE = (1 << 19), - ATA_EHI_POST_SETMODE = (1 << 20), - - ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET, - ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, - - ATA_EH_MAX_TRIES = 5, - - ATA_PROBE_MAX_TRIES = 3, - ATA_EH_DEV_TRIES = 3, - ATA_EH_PMP_TRIES = 5, - ATA_EH_PMP_LINK_TRIES = 3, - - SATA_PMP_SCR_TIMEOUT = 250, - - /* Horkage types. May be set by libata or controller on drives - (some horkage may be drive/controller pair dependant */ - - ATA_HORKAGE_DIAGNOSTIC = (1 << 0), - ATA_HORKAGE_NODMA = (1 << 1), - ATA_HORKAGE_NONCQ = (1 << 2), - ATA_HORKAGE_MAX_SEC_128 = (1 << 3), - ATA_HORKAGE_BROKEN_HPA = (1 << 4), - ATA_HORKAGE_SKIP_PM = (1 << 5), - ATA_HORKAGE_HPA_SIZE = (1 << 6), - ATA_HORKAGE_IPM = (1 << 7), - ATA_HORKAGE_IVB = (1 << 8), - ATA_HORKAGE_STUCK_ERR = (1 << 9), - - ATA_DMA_MASK_ATA = (1 << 0), - ATA_DMA_MASK_ATAPI = (1 << 1), - ATA_DMA_MASK_CFA = (1 << 2), - - ATAPI_READ = 0, - ATAPI_WRITE = 1, - ATAPI_READ_CD = 2, - ATAPI_PASS_THRU = 3, - ATAPI_MISC = 4, -}; - -enum ata_completion_errors { - AC_ERR_DEV = (1 << 0), - AC_ERR_HSM = (1 << 1), - AC_ERR_TIMEOUT = (1 << 2), - AC_ERR_MEDIA = (1 << 3), - AC_ERR_ATA_BUS = (1 << 4), - AC_ERR_HOST_BUS = (1 << 5), - AC_ERR_SYSTEM = (1 << 6), - AC_ERR_INVALID = (1 << 7), - AC_ERR_OTHER = (1 << 8), - AC_ERR_NODEV_HINT = (1 << 9), - AC_ERR_NCQ = (1 << 10), -}; - -enum ata_xfer_mask { - ATA_MASK_PIO = ((1LU << ATA_NR_PIO_MODES) - 1) << ATA_SHIFT_PIO, - ATA_MASK_MWDMA = ((1LU << ATA_NR_MWDMA_MODES) - 1) << ATA_SHIFT_MWDMA, - ATA_MASK_UDMA = ((1LU << ATA_NR_UDMA_MODES) - 1) << ATA_SHIFT_UDMA, -}; - -struct ata_port_info { -#ifndef __U_BOOT__ - struct scsi_host_template *sht; -#endif - unsigned long flags; - unsigned long link_flags; - unsigned long pio_mask; - unsigned long mwdma_mask; - unsigned long udma_mask; -#ifndef __U_BOOT__ - const struct ata_port_operations *port_ops; - void *private_data; -#endif -}; - -struct ata_ioports { - void __iomem *cmd_addr; - void __iomem *data_addr; - void __iomem *error_addr; - void __iomem *feature_addr; - void __iomem *nsect_addr; - void __iomem *lbal_addr; - void __iomem *lbam_addr; - void __iomem *lbah_addr; - void __iomem *device_addr; - void __iomem *status_addr; - void __iomem *command_addr; - void __iomem *altstatus_addr; - void __iomem *ctl_addr; -#ifndef __U_BOOT__ - void __iomem *bmdma_addr; -#endif - void __iomem *scr_addr; -}; - -struct ata_host { -#ifndef __U_BOOT__ - void __iomem * const *iomap; - void *private_data; - const struct ata_port_operations *ops; - unsigned long flags; - struct ata_port *simplex_claimed; -#endif - unsigned int n_ports; - struct ata_port *ports[0]; -}; - -#ifndef __U_BOOT__ -struct ata_port_stats { - unsigned long unhandled_irq; - unsigned long idle_irq; - unsigned long rw_reqbuf; -}; -#endif - -struct ata_device { - struct ata_link *link; - unsigned int devno; - unsigned long flags; - unsigned int horkage; -#ifndef __U_BOOT__ - struct scsi_device *sdev; -#ifdef CONFIG_ATA_ACPI - acpi_handle acpi_handle; - union acpi_object *gtf_cache; -#endif -#endif - u64 n_sectors; - unsigned int class; - - union { - u16 id[ATA_ID_WORDS]; - u32 gscr[SATA_PMP_GSCR_DWORDS]; - }; -#ifndef __U_BOOT__ - u8 pio_mode; - u8 dma_mode; - u8 xfer_mode; - unsigned int xfer_shift; -#endif - unsigned int multi_count; - unsigned int max_sectors; - unsigned int cdb_len; -#ifndef __U_BOOT__ - unsigned long pio_mask; - unsigned long mwdma_mask; -#endif - unsigned long udma_mask; - u16 cylinders; - u16 heads; - u16 sectors; -#ifndef __U_BOOT__ - int spdn_cnt; -#endif -}; - -enum dma_data_direction { - DMA_BIDIRECTIONAL = 0, - DMA_TO_DEVICE = 1, - DMA_FROM_DEVICE = 2, - DMA_NONE = 3, -}; - -struct ata_link { - struct ata_port *ap; - int pmp; - unsigned int active_tag; - u32 sactive; - unsigned int flags; - unsigned int hw_sata_spd_limit; -#ifndef __U_BOOT__ - unsigned int sata_spd_limit; - unsigned int sata_spd; - struct ata_device device[2]; -#endif -}; - -struct ata_port { - unsigned long flags; - unsigned int pflags; - unsigned int print_id; - unsigned int port_no; - - struct ata_ioports ioaddr; - - u8 ctl; - u8 last_ctl; - unsigned int pio_mask; - unsigned int mwdma_mask; - unsigned int udma_mask; - unsigned int cbl; - - struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; - unsigned long qc_allocated; - unsigned int qc_active; - int nr_active_links; - - struct ata_link link; -#ifndef __U_BOOT__ - int nr_pmp_links; - struct ata_link *pmp_link; -#endif - struct ata_link *excl_link; - int nr_pmp_links; -#ifndef __U_BOOT__ - struct ata_port_stats stats; - struct device *dev; - u32 msg_enable; -#endif - struct ata_host *host; - void *port_task_data; - - unsigned int hsm_task_state; - void *private_data; - unsigned char *pdata; -}; - -#endif diff --git a/drivers/block/sata_mv.c b/drivers/block/sata_mv.c deleted file mode 100644 index 78e3da442d..0000000000 --- a/drivers/block/sata_mv.c +++ /dev/null @@ -1,1051 +0,0 @@ -/* - * Copyright (C) Excito Elektronik i Skåne AB, 2010. - * Author: Tor Krill - * - * Copyright (C) 2015 Stefan Roese - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -/* - * This driver supports the SATA controller of some Mavell SoC's. - * Here a (most likely incomplete) list of the supported SoC's: - * - Kirkwood - * - Armada 370 - * - Armada XP - * - * This driver implementation is an alternative to the already available - * driver via the "ide" commands interface (drivers/block/mvsata_ide.c). - * But this driver only supports PIO mode and as this new driver also - * supports transfer via DMA, its much faster. - * - * Please note, that the newer SoC's (e.g. Armada 38x) are not supported - * by this driver. As they have an AHCI compatible SATA controller - * integrated. - */ - -/* - * TODO: - * Better error recovery - * No support for using PRDs (Thus max 64KB transfers) - * No NCQ support - * No port multiplier support - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(CONFIG_KIRKWOOD) -#include -#define SATAHC_BASE KW_SATA_BASE -#else -#include -#define SATAHC_BASE MVEBU_AXP_SATA_BASE -#endif - -#define SATA0_BASE (SATAHC_BASE + 0x2000) -#define SATA1_BASE (SATAHC_BASE + 0x4000) - -/* EDMA registers */ -#define EDMA_CFG 0x000 -#define EDMA_CFG_NCQ (1 << 5) -#define EDMA_CFG_EQUE (1 << 9) -#define EDMA_TIMER 0x004 -#define EDMA_IECR 0x008 -#define EDMA_IEMR 0x00c -#define EDMA_RQBA_HI 0x010 -#define EDMA_RQIPR 0x014 -#define EDMA_RQIPR_IPMASK (0x1f << 5) -#define EDMA_RQIPR_IPSHIFT 5 -#define EDMA_RQOPR 0x018 -#define EDMA_RQOPR_OPMASK (0x1f << 5) -#define EDMA_RQOPR_OPSHIFT 5 -#define EDMA_RSBA_HI 0x01c -#define EDMA_RSIPR 0x020 -#define EDMA_RSIPR_IPMASK (0x1f << 3) -#define EDMA_RSIPR_IPSHIFT 3 -#define EDMA_RSOPR 0x024 -#define EDMA_RSOPR_OPMASK (0x1f << 3) -#define EDMA_RSOPR_OPSHIFT 3 -#define EDMA_CMD 0x028 -#define EDMA_CMD_ENEDMA (0x01 << 0) -#define EDMA_CMD_DISEDMA (0x01 << 1) -#define EDMA_CMD_ATARST (0x01 << 2) -#define EDMA_CMD_FREEZE (0x01 << 4) -#define EDMA_TEST_CTL 0x02c -#define EDMA_STATUS 0x030 -#define EDMA_IORTO 0x034 -#define EDMA_CDTR 0x040 -#define EDMA_HLTCND 0x060 -#define EDMA_NTSR 0x094 - -/* Basic DMA registers */ -#define BDMA_CMD 0x224 -#define BDMA_STATUS 0x228 -#define BDMA_DTLB 0x22c -#define BDMA_DTHB 0x230 -#define BDMA_DRL 0x234 -#define BDMA_DRH 0x238 - -/* SATA Interface registers */ -#define SIR_ICFG 0x050 -#define SIR_CFG_GEN2EN (0x1 << 7) -#define SIR_PLL_CFG 0x054 -#define SIR_SSTATUS 0x300 -#define SSTATUS_DET_MASK (0x0f << 0) -#define SIR_SERROR 0x304 -#define SIR_SCONTROL 0x308 -#define SIR_SCONTROL_DETEN (0x01 << 0) -#define SIR_LTMODE 0x30c -#define SIR_LTMODE_NELBE (0x01 << 7) -#define SIR_PHYMODE3 0x310 -#define SIR_PHYMODE4 0x314 -#define SIR_PHYMODE1 0x32c -#define SIR_PHYMODE2 0x330 -#define SIR_BIST_CTRL 0x334 -#define SIR_BIST_DW1 0x338 -#define SIR_BIST_DW2 0x33c -#define SIR_SERR_IRQ_MASK 0x340 -#define SIR_SATA_IFCTRL 0x344 -#define SIR_SATA_TESTCTRL 0x348 -#define SIR_SATA_IFSTATUS 0x34c -#define SIR_VEND_UNIQ 0x35c -#define SIR_FIS_CFG 0x360 -#define SIR_FIS_IRQ_CAUSE 0x364 -#define SIR_FIS_IRQ_MASK 0x368 -#define SIR_FIS_DWORD0 0x370 -#define SIR_FIS_DWORD1 0x374 -#define SIR_FIS_DWORD2 0x378 -#define SIR_FIS_DWORD3 0x37c -#define SIR_FIS_DWORD4 0x380 -#define SIR_FIS_DWORD5 0x384 -#define SIR_FIS_DWORD6 0x388 -#define SIR_PHYM9_GEN2 0x398 -#define SIR_PHYM9_GEN1 0x39c -#define SIR_PHY_CFG 0x3a0 -#define SIR_PHYCTL 0x3a4 -#define SIR_PHYM10 0x3a8 -#define SIR_PHYM12 0x3b0 - -/* Shadow registers */ -#define PIO_DATA 0x100 -#define PIO_ERR_FEATURES 0x104 -#define PIO_SECTOR_COUNT 0x108 -#define PIO_LBA_LOW 0x10c -#define PIO_LBA_MID 0x110 -#define PIO_LBA_HI 0x114 -#define PIO_DEVICE 0x118 -#define PIO_CMD_STATUS 0x11c -#define PIO_STATUS_ERR (0x01 << 0) -#define PIO_STATUS_DRQ (0x01 << 3) -#define PIO_STATUS_DF (0x01 << 5) -#define PIO_STATUS_DRDY (0x01 << 6) -#define PIO_STATUS_BSY (0x01 << 7) -#define PIO_CTRL_ALTSTAT 0x120 - -/* SATAHC arbiter registers */ -#define SATAHC_CFG 0x000 -#define SATAHC_RQOP 0x004 -#define SATAHC_RQIP 0x008 -#define SATAHC_ICT 0x00c -#define SATAHC_ITT 0x010 -#define SATAHC_ICR 0x014 -#define SATAHC_ICR_PORT0 (0x01 << 0) -#define SATAHC_ICR_PORT1 (0x01 << 1) -#define SATAHC_MIC 0x020 -#define SATAHC_MIM 0x024 -#define SATAHC_LED_CFG 0x02c - -#define REQUEST_QUEUE_SIZE 32 -#define RESPONSE_QUEUE_SIZE REQUEST_QUEUE_SIZE - -struct crqb { - u32 dtb_low; /* DW0 */ - u32 dtb_high; /* DW1 */ - u32 control_flags; /* DW2 */ - u32 drb_count; /* DW3 */ - u32 ata_cmd_feat; /* DW4 */ - u32 ata_addr; /* DW5 */ - u32 ata_addr_exp; /* DW6 */ - u32 ata_sect_count; /* DW7 */ -}; - -#define CRQB_ALIGN 0x400 - -#define CRQB_CNTRLFLAGS_DIR (0x01 << 0) -#define CRQB_CNTRLFLAGS_DQTAGMASK (0x1f << 1) -#define CRQB_CNTRLFLAGS_DQTAGSHIFT 1 -#define CRQB_CNTRLFLAGS_PMPORTMASK (0x0f << 12) -#define CRQB_CNTRLFLAGS_PMPORTSHIFT 12 -#define CRQB_CNTRLFLAGS_PRDMODE (0x01 << 16) -#define CRQB_CNTRLFLAGS_HQTAGMASK (0x1f << 17) -#define CRQB_CNTRLFLAGS_HQTAGSHIFT 17 - -#define CRQB_CMDFEAT_CMDMASK (0xff << 16) -#define CRQB_CMDFEAT_CMDSHIFT 16 -#define CRQB_CMDFEAT_FEATMASK (0xff << 16) -#define CRQB_CMDFEAT_FEATSHIFT 24 - -#define CRQB_ADDR_LBA_LOWMASK (0xff << 0) -#define CRQB_ADDR_LBA_LOWSHIFT 0 -#define CRQB_ADDR_LBA_MIDMASK (0xff << 8) -#define CRQB_ADDR_LBA_MIDSHIFT 8 -#define CRQB_ADDR_LBA_HIGHMASK (0xff << 16) -#define CRQB_ADDR_LBA_HIGHSHIFT 16 -#define CRQB_ADDR_DEVICE_MASK (0xff << 24) -#define CRQB_ADDR_DEVICE_SHIFT 24 - -#define CRQB_ADDR_LBA_LOW_EXP_MASK (0xff << 0) -#define CRQB_ADDR_LBA_LOW_EXP_SHIFT 0 -#define CRQB_ADDR_LBA_MID_EXP_MASK (0xff << 8) -#define CRQB_ADDR_LBA_MID_EXP_SHIFT 8 -#define CRQB_ADDR_LBA_HIGH_EXP_MASK (0xff << 16) -#define CRQB_ADDR_LBA_HIGH_EXP_SHIFT 16 -#define CRQB_ADDR_FEATURE_EXP_MASK (0xff << 24) -#define CRQB_ADDR_FEATURE_EXP_SHIFT 24 - -#define CRQB_SECTCOUNT_COUNT_MASK (0xff << 0) -#define CRQB_SECTCOUNT_COUNT_SHIFT 0 -#define CRQB_SECTCOUNT_COUNT_EXP_MASK (0xff << 8) -#define CRQB_SECTCOUNT_COUNT_EXP_SHIFT 8 - -#define MVSATA_WIN_CONTROL(w) (MVEBU_AXP_SATA_BASE + 0x30 + ((w) << 4)) -#define MVSATA_WIN_BASE(w) (MVEBU_AXP_SATA_BASE + 0x34 + ((w) << 4)) - -struct eprd { - u32 phyaddr_low; - u32 bytecount_eot; - u32 phyaddr_hi; - u32 reserved; -}; - -#define EPRD_PHYADDR_MASK 0xfffffffe -#define EPRD_BYTECOUNT_MASK 0x0000ffff -#define EPRD_EOT (0x01 << 31) - -struct crpb { - u32 id; - u32 flags; - u32 timestamp; -}; - -#define CRPB_ALIGN 0x100 - -#define READ_CMD 0 -#define WRITE_CMD 1 - -/* - * Since we don't use PRDs yet max transfer size - * is 64KB - */ -#define MV_ATA_MAX_SECTORS (65535 / ATA_SECT_SIZE) - -/* Keep track if hw is initialized or not */ -static u32 hw_init; - -struct mv_priv { - char name[12]; - u32 link; - u32 regbase; - u32 queue_depth; - u16 pio; - u16 mwdma; - u16 udma; - - void *crqb_alloc; - struct crqb *request; - - void *crpb_alloc; - struct crpb *response; -}; - -static int ata_wait_register(u32 *addr, u32 mask, u32 val, u32 timeout_msec) -{ - ulong start; - - start = get_timer(0); - do { - if ((in_le32(addr) & mask) == val) - return 0; - } while (get_timer(start) < timeout_msec); - - return -ETIMEDOUT; -} - -/* Cut from sata_mv in linux kernel */ -static int mv_stop_edma_engine(int port) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - int i; - - /* Disable eDMA. The disable bit auto clears. */ - out_le32(priv->regbase + EDMA_CMD, EDMA_CMD_DISEDMA); - - /* Wait for the chip to confirm eDMA is off. */ - for (i = 10000; i > 0; i--) { - u32 reg = in_le32(priv->regbase + EDMA_CMD); - if (!(reg & EDMA_CMD_ENEDMA)) { - debug("EDMA stop on port %d succesful\n", port); - return 0; - } - udelay(10); - } - debug("EDMA stop on port %d failed\n", port); - return -1; -} - -static int mv_start_edma_engine(int port) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - u32 tmp; - - /* Check preconditions */ - tmp = in_le32(priv->regbase + SIR_SSTATUS); - if ((tmp & SSTATUS_DET_MASK) != 0x03) { - printf("Device error on port: %d\n", port); - return -1; - } - - tmp = in_le32(priv->regbase + PIO_CMD_STATUS); - if (tmp & (ATA_BUSY | ATA_DRQ)) { - printf("Device not ready on port: %d\n", port); - return -1; - } - - /* Clear interrupt cause */ - out_le32(priv->regbase + EDMA_IECR, 0x0); - - tmp = in_le32(SATAHC_BASE + SATAHC_ICR); - tmp &= ~(port == 0 ? SATAHC_ICR_PORT0 : SATAHC_ICR_PORT1); - out_le32(SATAHC_BASE + SATAHC_ICR, tmp); - - /* Configure edma operation */ - tmp = in_le32(priv->regbase + EDMA_CFG); - tmp &= ~EDMA_CFG_NCQ; /* No NCQ */ - tmp &= ~EDMA_CFG_EQUE; /* Dont queue operations */ - out_le32(priv->regbase + EDMA_CFG, tmp); - - out_le32(priv->regbase + SIR_FIS_IRQ_CAUSE, 0x0); - - /* Configure fis, set all to no-wait for now */ - out_le32(priv->regbase + SIR_FIS_CFG, 0x0); - - /* Setup request queue */ - out_le32(priv->regbase + EDMA_RQBA_HI, 0x0); - out_le32(priv->regbase + EDMA_RQIPR, priv->request); - out_le32(priv->regbase + EDMA_RQOPR, 0x0); - - /* Setup response queue */ - out_le32(priv->regbase + EDMA_RSBA_HI, 0x0); - out_le32(priv->regbase + EDMA_RSOPR, priv->response); - out_le32(priv->regbase + EDMA_RSIPR, 0x0); - - /* Start edma */ - out_le32(priv->regbase + EDMA_CMD, EDMA_CMD_ENEDMA); - - return 0; -} - -static int mv_reset_channel(int port) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - - /* Make sure edma is stopped */ - mv_stop_edma_engine(port); - - out_le32(priv->regbase + EDMA_CMD, EDMA_CMD_ATARST); - udelay(25); /* allow reset propagation */ - out_le32(priv->regbase + EDMA_CMD, 0); - mdelay(10); - - return 0; -} - -static void mv_reset_port(int port) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - - mv_reset_channel(port); - - out_le32(priv->regbase + EDMA_CMD, 0x0); - out_le32(priv->regbase + EDMA_CFG, 0x101f); - out_le32(priv->regbase + EDMA_IECR, 0x0); - out_le32(priv->regbase + EDMA_IEMR, 0x0); - out_le32(priv->regbase + EDMA_RQBA_HI, 0x0); - out_le32(priv->regbase + EDMA_RQIPR, 0x0); - out_le32(priv->regbase + EDMA_RQOPR, 0x0); - out_le32(priv->regbase + EDMA_RSBA_HI, 0x0); - out_le32(priv->regbase + EDMA_RSIPR, 0x0); - out_le32(priv->regbase + EDMA_RSOPR, 0x0); - out_le32(priv->regbase + EDMA_IORTO, 0xfa); -} - -static void mv_reset_one_hc(void) -{ - out_le32(SATAHC_BASE + SATAHC_ICT, 0x00); - out_le32(SATAHC_BASE + SATAHC_ITT, 0x00); - out_le32(SATAHC_BASE + SATAHC_ICR, 0x00); -} - -static int probe_port(int port) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - int tries, tries2, set15 = 0; - u32 tmp; - - debug("Probe port: %d\n", port); - - for (tries = 0; tries < 2; tries++) { - /* Clear SError */ - out_le32(priv->regbase + SIR_SERROR, 0x0); - - /* trigger com-init */ - tmp = in_le32(priv->regbase + SIR_SCONTROL); - tmp = (tmp & 0x0f0) | 0x300 | SIR_SCONTROL_DETEN; - out_le32(priv->regbase + SIR_SCONTROL, tmp); - - mdelay(1); - - tmp = in_le32(priv->regbase + SIR_SCONTROL); - tries2 = 5; - do { - tmp = (tmp & 0x0f0) | 0x300; - out_le32(priv->regbase + SIR_SCONTROL, tmp); - mdelay(10); - tmp = in_le32(priv->regbase + SIR_SCONTROL); - } while ((tmp & 0xf0f) != 0x300 && tries2--); - - mdelay(10); - - for (tries2 = 0; tries2 < 200; tries2++) { - tmp = in_le32(priv->regbase + SIR_SSTATUS); - if ((tmp & SSTATUS_DET_MASK) == 0x03) { - debug("Found device on port\n"); - return 0; - } - mdelay(1); - } - - if ((tmp & SSTATUS_DET_MASK) == 0) { - debug("No device attached on port %d\n", port); - return -ENODEV; - } - - if (!set15) { - /* Try on 1.5Gb/S */ - debug("Try 1.5Gb link\n"); - set15 = 1; - out_le32(priv->regbase + SIR_SCONTROL, 0x304); - - tmp = in_le32(priv->regbase + SIR_ICFG); - tmp &= ~SIR_CFG_GEN2EN; - out_le32(priv->regbase + SIR_ICFG, tmp); - - mv_reset_channel(port); - } - } - - debug("Failed to probe port\n"); - return -1; -} - -/* Get request queue in pointer */ -static int get_reqip(int port) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - u32 tmp; - - tmp = in_le32(priv->regbase + EDMA_RQIPR) & EDMA_RQIPR_IPMASK; - tmp = tmp >> EDMA_RQIPR_IPSHIFT; - - return tmp; -} - -static void set_reqip(int port, int reqin) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - u32 tmp; - - tmp = in_le32(priv->regbase + EDMA_RQIPR) & ~EDMA_RQIPR_IPMASK; - tmp |= ((reqin << EDMA_RQIPR_IPSHIFT) & EDMA_RQIPR_IPMASK); - out_le32(priv->regbase + EDMA_RQIPR, tmp); -} - -/* Get next available slot, ignoring possible overwrite */ -static int get_next_reqip(int port) -{ - int slot = get_reqip(port); - slot = (slot + 1) % REQUEST_QUEUE_SIZE; - return slot; -} - -/* Get response queue in pointer */ -static int get_rspip(int port) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - u32 tmp; - - tmp = in_le32(priv->regbase + EDMA_RSIPR) & EDMA_RSIPR_IPMASK; - tmp = tmp >> EDMA_RSIPR_IPSHIFT; - - return tmp; -} - -/* Get response queue out pointer */ -static int get_rspop(int port) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - u32 tmp; - - tmp = in_le32(priv->regbase + EDMA_RSOPR) & EDMA_RSOPR_OPMASK; - tmp = tmp >> EDMA_RSOPR_OPSHIFT; - return tmp; -} - -/* Get next response queue pointer */ -static int get_next_rspop(int port) -{ - return (get_rspop(port) + 1) % RESPONSE_QUEUE_SIZE; -} - -/* Set response queue pointer */ -static void set_rspop(int port, int reqin) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - u32 tmp; - - tmp = in_le32(priv->regbase + EDMA_RSOPR) & ~EDMA_RSOPR_OPMASK; - tmp |= ((reqin << EDMA_RSOPR_OPSHIFT) & EDMA_RSOPR_OPMASK); - - out_le32(priv->regbase + EDMA_RSOPR, tmp); -} - -static int wait_dma_completion(int port, int index, u32 timeout_msec) -{ - u32 tmp, res; - - tmp = port == 0 ? SATAHC_ICR_PORT0 : SATAHC_ICR_PORT1; - res = ata_wait_register((u32 *)(SATAHC_BASE + SATAHC_ICR), tmp, - tmp, timeout_msec); - if (res) - printf("Failed to wait for completion on port %d\n", port); - - return res; -} - -static void process_responses(int port) -{ -#ifdef DEBUG - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; -#endif - u32 tmp; - u32 outind = get_rspop(port); - - /* Ack interrupts */ - tmp = in_le32(SATAHC_BASE + SATAHC_ICR); - if (port == 0) - tmp &= ~(BIT(0) | BIT(8)); - else - tmp &= ~(BIT(1) | BIT(9)); - tmp &= ~(BIT(4)); - out_le32(SATAHC_BASE + SATAHC_ICR, tmp); - - while (get_rspip(port) != outind) { -#ifdef DEBUG - debug("Response index %d flags %08x on port %d\n", outind, - priv->response[outind].flags, port); -#endif - outind = get_next_rspop(port); - set_rspop(port, outind); - } -} - -static int mv_ata_exec_ata_cmd(int port, struct sata_fis_h2d *cfis, - u8 *buffer, u32 len, u32 iswrite) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - struct crqb *req; - int slot; - u32 start; - - if (len >= 64 * 1024) { - printf("We only support <64K transfers for now\n"); - return -1; - } - - /* Initialize request */ - slot = get_reqip(port); - memset(&priv->request[slot], 0, sizeof(struct crqb)); - req = &priv->request[slot]; - - req->dtb_low = (u32)buffer; - - /* Dont use PRDs */ - req->control_flags = CRQB_CNTRLFLAGS_PRDMODE; - req->control_flags |= iswrite ? 0 : CRQB_CNTRLFLAGS_DIR; - req->control_flags |= - ((cfis->pm_port_c << CRQB_CNTRLFLAGS_PMPORTSHIFT) - & CRQB_CNTRLFLAGS_PMPORTMASK); - - req->drb_count = len; - - req->ata_cmd_feat = (cfis->command << CRQB_CMDFEAT_CMDSHIFT) & - CRQB_CMDFEAT_CMDMASK; - req->ata_cmd_feat |= (cfis->features << CRQB_CMDFEAT_FEATSHIFT) & - CRQB_CMDFEAT_FEATMASK; - - req->ata_addr = (cfis->lba_low << CRQB_ADDR_LBA_LOWSHIFT) & - CRQB_ADDR_LBA_LOWMASK; - req->ata_addr |= (cfis->lba_mid << CRQB_ADDR_LBA_MIDSHIFT) & - CRQB_ADDR_LBA_MIDMASK; - req->ata_addr |= (cfis->lba_high << CRQB_ADDR_LBA_HIGHSHIFT) & - CRQB_ADDR_LBA_HIGHMASK; - req->ata_addr |= (cfis->device << CRQB_ADDR_DEVICE_SHIFT) & - CRQB_ADDR_DEVICE_MASK; - - req->ata_addr_exp = (cfis->lba_low_exp << CRQB_ADDR_LBA_LOW_EXP_SHIFT) & - CRQB_ADDR_LBA_LOW_EXP_MASK; - req->ata_addr_exp |= - (cfis->lba_mid_exp << CRQB_ADDR_LBA_MID_EXP_SHIFT) & - CRQB_ADDR_LBA_MID_EXP_MASK; - req->ata_addr_exp |= - (cfis->lba_high_exp << CRQB_ADDR_LBA_HIGH_EXP_SHIFT) & - CRQB_ADDR_LBA_HIGH_EXP_MASK; - req->ata_addr_exp |= - (cfis->features_exp << CRQB_ADDR_FEATURE_EXP_SHIFT) & - CRQB_ADDR_FEATURE_EXP_MASK; - - req->ata_sect_count = - (cfis->sector_count << CRQB_SECTCOUNT_COUNT_SHIFT) & - CRQB_SECTCOUNT_COUNT_MASK; - req->ata_sect_count |= - (cfis->sector_count_exp << CRQB_SECTCOUNT_COUNT_EXP_SHIFT) & - CRQB_SECTCOUNT_COUNT_EXP_MASK; - - /* Flush data */ - start = (u32)req & ~(ARCH_DMA_MINALIGN - 1); - flush_dcache_range(start, - start + ALIGN(sizeof(*req), ARCH_DMA_MINALIGN)); - - /* Trigger operation */ - slot = get_next_reqip(port); - set_reqip(port, slot); - - /* Wait for completion */ - if (wait_dma_completion(port, slot, 10000)) { - printf("ATA operation timed out\n"); - return -1; - } - - process_responses(port); - - /* Invalidate data on read */ - if (buffer && len) { - start = (u32)buffer & ~(ARCH_DMA_MINALIGN - 1); - invalidate_dcache_range(start, - start + ALIGN(len, ARCH_DMA_MINALIGN)); - } - - return len; -} - -static u32 mv_sata_rw_cmd_ext(int port, lbaint_t start, u32 blkcnt, - u8 *buffer, int is_write) -{ - struct sata_fis_h2d cfis; - u32 res; - u64 block; - - block = (u64)start; - - memset(&cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - 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; - - res = mv_ata_exec_ata_cmd(port, &cfis, buffer, ATA_SECT_SIZE * blkcnt, - is_write); - - return res >= 0 ? blkcnt : res; -} - -static u32 mv_sata_rw_cmd(int port, lbaint_t start, u32 blkcnt, u8 *buffer, - int is_write) -{ - struct sata_fis_h2d cfis; - lbaint_t block; - u32 res; - - block = start; - - memset(&cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - 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); - - res = mv_ata_exec_ata_cmd(port, &cfis, buffer, ATA_SECT_SIZE * blkcnt, - is_write); - - return res >= 0 ? blkcnt : res; -} - -static u32 ata_low_level_rw(int dev, lbaint_t blknr, lbaint_t blkcnt, - void *buffer, int is_write) -{ - lbaint_t start, blks; - u8 *addr; - int max_blks; - - debug("%s: %ld %ld\n", __func__, blknr, blkcnt); - - start = blknr; - blks = blkcnt; - addr = (u8 *)buffer; - - max_blks = MV_ATA_MAX_SECTORS; - do { - if (blks > max_blks) { - if (sata_dev_desc[dev].lba48) { - mv_sata_rw_cmd_ext(dev, start, max_blks, addr, - is_write); - } else { - mv_sata_rw_cmd(dev, start, max_blks, addr, - is_write); - } - start += max_blks; - blks -= max_blks; - addr += ATA_SECT_SIZE * max_blks; - } else { - if (sata_dev_desc[dev].lba48) { - mv_sata_rw_cmd_ext(dev, start, blks, addr, - is_write); - } else { - mv_sata_rw_cmd(dev, start, blks, addr, - is_write); - } - start += blks; - blks = 0; - addr += ATA_SECT_SIZE * blks; - } - } while (blks != 0); - - return blkcnt; -} - -static int mv_ata_exec_ata_cmd_nondma(int port, - struct sata_fis_h2d *cfis, u8 *buffer, - u32 len, u32 iswrite) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - int i; - u16 *tp; - - debug("%s\n", __func__); - - out_le32(priv->regbase + PIO_SECTOR_COUNT, cfis->sector_count); - out_le32(priv->regbase + PIO_LBA_HI, cfis->lba_high); - out_le32(priv->regbase + PIO_LBA_MID, cfis->lba_mid); - out_le32(priv->regbase + PIO_LBA_LOW, cfis->lba_low); - out_le32(priv->regbase + PIO_ERR_FEATURES, cfis->features); - out_le32(priv->regbase + PIO_DEVICE, cfis->device); - out_le32(priv->regbase + PIO_CMD_STATUS, cfis->command); - - if (ata_wait_register((u32 *)(priv->regbase + PIO_CMD_STATUS), - ATA_BUSY, 0x0, 10000)) { - debug("Failed to wait for completion\n"); - return -1; - } - - if (len > 0) { - tp = (u16 *)buffer; - for (i = 0; i < len / 2; i++) { - if (iswrite) - out_le16(priv->regbase + PIO_DATA, *tp++); - else - *tp++ = in_le16(priv->regbase + PIO_DATA); - } - } - - return len; -} - -static int mv_sata_identify(int port, u16 *id) -{ - struct sata_fis_h2d h2d; - - memset(&h2d, 0, sizeof(struct sata_fis_h2d)); - - h2d.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - h2d.command = ATA_CMD_ID_ATA; - - /* Give device time to get operational */ - mdelay(10); - - return mv_ata_exec_ata_cmd_nondma(port, &h2d, (u8 *)id, - ATA_ID_WORDS * 2, READ_CMD); -} - -static void mv_sata_xfer_mode(int port, u16 *id) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - - priv->pio = id[ATA_ID_PIO_MODES]; - priv->mwdma = id[ATA_ID_MWDMA_MODES]; - priv->udma = id[ATA_ID_UDMA_MODES]; - debug("pio %04x, mwdma %04x, udma %04x\n", priv->pio, priv->mwdma, - priv->udma); -} - -static void mv_sata_set_features(int port) -{ - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - struct sata_fis_h2d cfis; - u8 udma_cap; - - memset(&cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis.command = ATA_CMD_SET_FEATURES; - cfis.features = SETFEATURES_XFER; - - /* First check the device capablity */ - udma_cap = (u8) (priv->udma & 0xff); - - if (udma_cap == ATA_UDMA6) - cfis.sector_count = XFER_UDMA_6; - if (udma_cap == ATA_UDMA5) - cfis.sector_count = XFER_UDMA_5; - if (udma_cap == ATA_UDMA4) - cfis.sector_count = XFER_UDMA_4; - if (udma_cap == ATA_UDMA3) - cfis.sector_count = XFER_UDMA_3; - - mv_ata_exec_ata_cmd_nondma(port, &cfis, NULL, 0, READ_CMD); -} - -int mv_sata_spin_down(int dev) -{ - struct sata_fis_h2d cfis; - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[dev].priv; - - if (priv->link == 0) { - debug("No device on port: %d\n", dev); - return 1; - } - - memset(&cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis.command = ATA_CMD_STANDBY; - - return mv_ata_exec_ata_cmd_nondma(dev, &cfis, NULL, 0, READ_CMD); -} - -int mv_sata_spin_up(int dev) -{ - struct sata_fis_h2d cfis; - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[dev].priv; - - if (priv->link == 0) { - debug("No device on port: %d\n", dev); - return 1; - } - - memset(&cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis.command = ATA_CMD_IDLE; - - return mv_ata_exec_ata_cmd_nondma(dev, &cfis, NULL, 0, READ_CMD); -} - -ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) -{ - return ata_low_level_rw(dev, blknr, blkcnt, buffer, READ_CMD); -} - -ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) -{ - return ata_low_level_rw(dev, blknr, blkcnt, (void *)buffer, WRITE_CMD); -} - -/* - * Initialize SATA memory windows - */ -static void mvsata_ide_conf_mbus_windows(void) -{ - const struct mbus_dram_target_info *dram; - int i; - - dram = mvebu_mbus_dram_info(); - - /* Disable windows, Set Size/Base to 0 */ - for (i = 0; i < 4; i++) { - writel(0, MVSATA_WIN_CONTROL(i)); - writel(0, MVSATA_WIN_BASE(i)); - } - - for (i = 0; i < dram->num_cs; i++) { - const struct mbus_dram_window *cs = dram->cs + i; - writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) | - (dram->mbus_dram_target_id << 4) | 1, - MVSATA_WIN_CONTROL(i)); - writel(cs->base & 0xffff0000, MVSATA_WIN_BASE(i)); - } -} - -int init_sata(int dev) -{ - struct mv_priv *priv; - - debug("Initialize sata dev: %d\n", dev); - - if (dev < 0 || dev >= CONFIG_SYS_SATA_MAX_DEVICE) { - printf("Invalid sata device %d\n", dev); - return -1; - } - - priv = (struct mv_priv *)malloc(sizeof(struct mv_priv)); - if (!priv) { - printf("Failed to allocate memory for private sata data\n"); - return -ENOMEM; - } - - memset((void *)priv, 0, sizeof(struct mv_priv)); - - /* Allocate and align request buffer */ - priv->crqb_alloc = malloc(sizeof(struct crqb) * REQUEST_QUEUE_SIZE + - CRQB_ALIGN); - if (!priv->crqb_alloc) { - printf("Unable to allocate memory for request queue\n"); - return -ENOMEM; - } - memset(priv->crqb_alloc, 0, - sizeof(struct crqb) * REQUEST_QUEUE_SIZE + CRQB_ALIGN); - priv->request = (struct crqb *)(((u32) priv->crqb_alloc + CRQB_ALIGN) & - ~(CRQB_ALIGN - 1)); - - /* Allocate and align response buffer */ - priv->crpb_alloc = malloc(sizeof(struct crpb) * REQUEST_QUEUE_SIZE + - CRPB_ALIGN); - if (!priv->crpb_alloc) { - printf("Unable to allocate memory for response queue\n"); - return -ENOMEM; - } - memset(priv->crpb_alloc, 0, - sizeof(struct crpb) * REQUEST_QUEUE_SIZE + CRPB_ALIGN); - priv->response = (struct crpb *)(((u32) priv->crpb_alloc + CRPB_ALIGN) & - ~(CRPB_ALIGN - 1)); - - sata_dev_desc[dev].priv = (void *)priv; - - sprintf(priv->name, "SATA%d", dev); - - priv->regbase = dev == 0 ? SATA0_BASE : SATA1_BASE; - - if (!hw_init) { - debug("Initialize sata hw\n"); - hw_init = 1; - mv_reset_one_hc(); - mvsata_ide_conf_mbus_windows(); - } - - mv_reset_port(dev); - - if (probe_port(dev)) { - priv->link = 0; - return -ENODEV; - } - priv->link = 1; - - return 0; -} - -int reset_sata(int dev) -{ - return 0; -} - -int scan_sata(int port) -{ - 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; - u16 *id; - struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv; - - if (!priv->link) - return -ENODEV; - - id = (u16 *)malloc(ATA_ID_WORDS * 2); - if (!id) { - printf("Failed to malloc id data\n"); - return -ENOMEM; - } - - mv_sata_identify(port, id); - ata_swap_buf_le16(id, ATA_ID_WORDS); -#ifdef DEBUG - ata_dump_id(id); -#endif - - /* Serial number */ - ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); - memcpy(sata_dev_desc[port].product, serial, sizeof(serial)); - - /* Firmware version */ - ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); - memcpy(sata_dev_desc[port].revision, firmware, sizeof(firmware)); - - /* Product model */ - ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); - memcpy(sata_dev_desc[port].vendor, product, sizeof(product)); - - /* Total sectors */ - n_sectors = ata_id_n_sectors(id); - sata_dev_desc[port].lba = n_sectors; - - /* Check if support LBA48 */ - if (ata_id_has_lba48(id)) { - sata_dev_desc[port].lba48 = 1; - debug("Device support LBA48\n"); - } - - /* Get the NCQ queue depth from device */ - priv->queue_depth = ata_id_queue_depth(id); - - /* Get the xfer mode from device */ - mv_sata_xfer_mode(port, id); - - /* Set the xfer mode to highest speed */ - mv_sata_set_features(port); - - /* Start up */ - mv_start_edma_engine(port); - - return 0; -} diff --git a/drivers/block/sata_sandbox.c b/drivers/block/sata_sandbox.c deleted file mode 100644 index bd967d290c..0000000000 --- a/drivers/block/sata_sandbox.c +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2015 Google, Inc - * Written by Simon Glass - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include - -int init_sata(int dev) -{ - return 0; -} - -int reset_sata(int dev) -{ - return 0; -} - -int scan_sata(int dev) -{ - return 0; -} - -ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) -{ - return 0; -} - -ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) -{ - return 0; -} diff --git a/drivers/block/sata_sil.c b/drivers/block/sata_sil.c deleted file mode 100644 index daff7d4ab5..0000000000 --- a/drivers/block/sata_sil.c +++ /dev/null @@ -1,715 +0,0 @@ -/* - * Copyright (C) 2011 Freescale Semiconductor, Inc. - * Author: Tang Yuantian - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sata_sil.h" - -/* Convert sectorsize to wordsize */ -#define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2) -#define virt_to_bus(devno, v) pci_virt_to_mem(devno, (void *) (v)) - -static struct sata_info sata_info; - -static struct pci_device_id supported[] = { - {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3131}, - {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3132}, - {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3124}, - {} -}; - -static void sil_sata_dump_fis(struct sata_fis_d2h *s) -{ - printf("Status FIS dump:\n"); - printf("fis_type: %02x\n", s->fis_type); - printf("pm_port_i: %02x\n", s->pm_port_i); - printf("status: %02x\n", s->status); - printf("error: %02x\n", s->error); - printf("lba_low: %02x\n", s->lba_low); - printf("lba_mid: %02x\n", s->lba_mid); - printf("lba_high: %02x\n", s->lba_high); - printf("device: %02x\n", s->device); - printf("lba_low_exp: %02x\n", s->lba_low_exp); - printf("lba_mid_exp: %02x\n", s->lba_mid_exp); - printf("lba_high_exp: %02x\n", s->lba_high_exp); - printf("res1: %02x\n", s->res1); - printf("sector_count: %02x\n", s->sector_count); - printf("sector_count_exp: %02x\n", s->sector_count_exp); -} - -static const char *sata_spd_string(unsigned int speed) -{ - static const char * const spd_str[] = { - "1.5 Gbps", - "3.0 Gbps", - "6.0 Gbps", - }; - - if ((speed - 1) > 2) - return ""; - - return spd_str[speed - 1]; -} - -static u32 ata_wait_register(void *reg, u32 mask, - u32 val, int timeout_msec) -{ - u32 tmp; - - tmp = readl(reg); - while ((tmp & mask) == val && timeout_msec > 0) { - mdelay(1); - timeout_msec--; - tmp = readl(reg); - } - - return tmp; -} - -static void sil_config_port(void *port) -{ - /* configure IRQ WoC */ - writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); - - /* zero error counters. */ - writew(0x8000, port + PORT_DECODE_ERR_THRESH); - writew(0x8000, port + PORT_CRC_ERR_THRESH); - writew(0x8000, port + PORT_HSHK_ERR_THRESH); - writew(0x0000, port + PORT_DECODE_ERR_CNT); - writew(0x0000, port + PORT_CRC_ERR_CNT); - writew(0x0000, port + PORT_HSHK_ERR_CNT); - - /* always use 64bit activation */ - writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); - - /* clear port multiplier enable and resume bits */ - writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR); -} - -static int sil_init_port(void *port) -{ - u32 tmp; - - writel(PORT_CS_INIT, port + PORT_CTRL_STAT); - ata_wait_register(port + PORT_CTRL_STAT, - PORT_CS_INIT, PORT_CS_INIT, 100); - tmp = ata_wait_register(port + PORT_CTRL_STAT, - PORT_CS_RDY, 0, 100); - - if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) - return 1; - - return 0; -} - -static void sil_read_fis(int dev, int tag, struct sata_fis_d2h *fis) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - void *port = sata->port; - struct sil_prb *prb; - int i; - u32 *src, *dst; - - prb = port + PORT_LRAM + tag * PORT_LRAM_SLOT_SZ; - src = (u32 *)&prb->fis; - dst = (u32 *)fis; - for (i = 0; i < sizeof(struct sata_fis_h2d); i += 4) - *dst++ = readl(src++); -} - -static int sil_exec_cmd(int dev, struct sil_cmd_block *pcmd, int tag) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - void *port = sata->port; - u64 paddr = virt_to_bus(sata->devno, pcmd); - u32 irq_mask, irq_stat; - int rc; - - writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR); - - /* better to add momery barrior here */ - writel((u32)paddr, port + PORT_CMD_ACTIVATE + tag * 8); - writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + tag * 8 + 4); - - irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT; - irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, - 0, 10000); - - /* clear IRQs */ - writel(irq_mask, port + PORT_IRQ_STAT); - irq_stat >>= PORT_IRQ_RAW_SHIFT; - - if (irq_stat & PORT_IRQ_COMPLETE) - rc = 0; - else { - /* force port into known state */ - sil_init_port(port); - if (irq_stat & PORT_IRQ_ERROR) - rc = 1; /* error */ - else - rc = 2; /* busy */ - } - - return rc; -} - -static int sil_cmd_set_feature(int dev) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - struct sil_cmd_block cmdb, *pcmd = &cmdb; - struct sata_fis_d2h fis; - u8 udma_cap; - int ret; - - memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block)); - pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - pcmd->prb.fis.pm_port_c = (1 << 7); - pcmd->prb.fis.command = ATA_CMD_SET_FEATURES; - pcmd->prb.fis.features = SETFEATURES_XFER; - - /* First check the device capablity */ - udma_cap = (u8)(sata->udma & 0xff); - debug("udma_cap %02x\n", udma_cap); - - if (udma_cap == ATA_UDMA6) - pcmd->prb.fis.sector_count = XFER_UDMA_6; - if (udma_cap == ATA_UDMA5) - pcmd->prb.fis.sector_count = XFER_UDMA_5; - if (udma_cap == ATA_UDMA4) - pcmd->prb.fis.sector_count = XFER_UDMA_4; - if (udma_cap == ATA_UDMA3) - pcmd->prb.fis.sector_count = XFER_UDMA_3; - - ret = sil_exec_cmd(dev, pcmd, 0); - if (ret) { - sil_read_fis(dev, 0, &fis); - printf("Err: exe cmd(0x%x).\n", - readl(sata->port + PORT_SERROR)); - sil_sata_dump_fis(&fis); - return 1; - } - - return 0; -} - -static int sil_cmd_identify_device(int dev, u16 *id) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - struct sil_cmd_block cmdb, *pcmd = &cmdb; - struct sata_fis_d2h fis; - int ret; - - memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block)); - pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL); - pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ); - pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - pcmd->prb.fis.pm_port_c = (1 << 7); - pcmd->prb.fis.command = ATA_CMD_ID_ATA; - pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, id)); - pcmd->sge.cnt = cpu_to_le32(sizeof(id[0]) * ATA_ID_WORDS); - pcmd->sge.flags = cpu_to_le32(SGE_TRM); - - ret = sil_exec_cmd(dev, pcmd, 0); - if (ret) { - sil_read_fis(dev, 0, &fis); - printf("Err: id cmd(0x%x).\n", readl(sata->port + PORT_SERROR)); - sil_sata_dump_fis(&fis); - return 1; - } - ata_swap_buf_le16(id, ATA_ID_WORDS); - - return 0; -} - -static int sil_cmd_soft_reset(int dev) -{ - struct sil_cmd_block cmdb, *pcmd = &cmdb; - struct sil_sata *sata = sata_dev_desc[dev].priv; - struct sata_fis_d2h fis; - void *port = sata->port; - int ret; - - /* put the port into known state */ - if (sil_init_port(port)) { - printf("SRST: port %d not ready\n", dev); - return 1; - } - - memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block)); - - pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_SRST); - pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - pcmd->prb.fis.pm_port_c = 0xf; - - ret = sil_exec_cmd(dev, &cmdb, 0); - if (ret) { - sil_read_fis(dev, 0, &fis); - printf("SRST cmd error.\n"); - sil_sata_dump_fis(&fis); - return 1; - } - - return 0; -} - -static ulong sil_sata_rw_cmd(int dev, ulong start, ulong blkcnt, - u8 *buffer, int is_write) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - struct sil_cmd_block cmdb, *pcmd = &cmdb; - struct sata_fis_d2h fis; - u64 block; - int ret; - - block = (u64)start; - memset(pcmd, 0, sizeof(struct sil_cmd_block)); - pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL); - pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - pcmd->prb.fis.pm_port_c = (1 << 7); - if (is_write) { - pcmd->prb.fis.command = ATA_CMD_WRITE; - pcmd->prb.prot = cpu_to_le16(PRB_PROT_WRITE); - } else { - pcmd->prb.fis.command = ATA_CMD_READ; - pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ); - } - - pcmd->prb.fis.device = ATA_LBA; - pcmd->prb.fis.device |= (block >> 24) & 0xf; - pcmd->prb.fis.lba_high = (block >> 16) & 0xff; - pcmd->prb.fis.lba_mid = (block >> 8) & 0xff; - pcmd->prb.fis.lba_low = block & 0xff; - pcmd->prb.fis.sector_count = (u8)blkcnt & 0xff; - - pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, buffer)); - pcmd->sge.cnt = cpu_to_le32(blkcnt * ATA_SECT_SIZE); - pcmd->sge.flags = cpu_to_le32(SGE_TRM); - - ret = sil_exec_cmd(dev, pcmd, 0); - if (ret) { - sil_read_fis(dev, 0, &fis); - printf("Err: rw cmd(0x%08x).\n", - readl(sata->port + PORT_SERROR)); - sil_sata_dump_fis(&fis); - return 1; - } - - return blkcnt; -} - -static ulong sil_sata_rw_cmd_ext(int dev, ulong start, ulong blkcnt, - u8 *buffer, int is_write) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - struct sil_cmd_block cmdb, *pcmd = &cmdb; - struct sata_fis_d2h fis; - u64 block; - int ret; - - block = (u64)start; - memset(pcmd, 0, sizeof(struct sil_cmd_block)); - pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL); - pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - pcmd->prb.fis.pm_port_c = (1 << 7); - if (is_write) { - pcmd->prb.fis.command = ATA_CMD_WRITE_EXT; - pcmd->prb.prot = cpu_to_le16(PRB_PROT_WRITE); - } else { - pcmd->prb.fis.command = ATA_CMD_READ_EXT; - pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ); - } - - pcmd->prb.fis.lba_high_exp = (block >> 40) & 0xff; - pcmd->prb.fis.lba_mid_exp = (block >> 32) & 0xff; - pcmd->prb.fis.lba_low_exp = (block >> 24) & 0xff; - pcmd->prb.fis.lba_high = (block >> 16) & 0xff; - pcmd->prb.fis.lba_mid = (block >> 8) & 0xff; - pcmd->prb.fis.lba_low = block & 0xff; - pcmd->prb.fis.device = ATA_LBA; - pcmd->prb.fis.sector_count_exp = (blkcnt >> 8) & 0xff; - pcmd->prb.fis.sector_count = blkcnt & 0xff; - - pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, buffer)); - pcmd->sge.cnt = cpu_to_le32(blkcnt * ATA_SECT_SIZE); - pcmd->sge.flags = cpu_to_le32(SGE_TRM); - - ret = sil_exec_cmd(dev, pcmd, 0); - if (ret) { - sil_read_fis(dev, 0, &fis); - printf("Err: rw ext cmd(0x%08x).\n", - readl(sata->port + PORT_SERROR)); - sil_sata_dump_fis(&fis); - return 1; - } - - return blkcnt; -} - -static ulong sil_sata_rw_lba28(int dev, ulong blknr, lbaint_t blkcnt, - const void *buffer, int is_write) -{ - ulong start, blks, max_blks; - u8 *addr; - - start = blknr; - blks = blkcnt; - addr = (u8 *)buffer; - - max_blks = ATA_MAX_SECTORS; - do { - if (blks > max_blks) { - sil_sata_rw_cmd(dev, start, max_blks, addr, is_write); - start += max_blks; - blks -= max_blks; - addr += ATA_SECT_SIZE * max_blks; - } else { - sil_sata_rw_cmd(dev, start, blks, addr, is_write); - start += blks; - blks = 0; - addr += ATA_SECT_SIZE * blks; - } - } while (blks != 0); - - return blkcnt; -} - -static ulong sil_sata_rw_lba48(int dev, ulong blknr, lbaint_t blkcnt, - const void *buffer, int is_write) -{ - ulong start, blks, max_blks; - u8 *addr; - - start = blknr; - blks = blkcnt; - addr = (u8 *)buffer; - - max_blks = ATA_MAX_SECTORS_LBA48; - do { - if (blks > max_blks) { - sil_sata_rw_cmd_ext(dev, start, max_blks, - addr, is_write); - start += max_blks; - blks -= max_blks; - addr += ATA_SECT_SIZE * max_blks; - } else { - sil_sata_rw_cmd_ext(dev, start, blks, - addr, is_write); - start += blks; - blks = 0; - addr += ATA_SECT_SIZE * blks; - } - } while (blks != 0); - - return blkcnt; -} - -static void sil_sata_cmd_flush_cache(int dev) -{ - struct sil_cmd_block cmdb, *pcmd = &cmdb; - - memset((void *)pcmd, 0, sizeof(struct sil_cmd_block)); - pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - pcmd->prb.fis.pm_port_c = (1 << 7); - pcmd->prb.fis.command = ATA_CMD_FLUSH; - - sil_exec_cmd(dev, pcmd, 0); -} - -static void sil_sata_cmd_flush_cache_ext(int dev) -{ - struct sil_cmd_block cmdb, *pcmd = &cmdb; - - memset((void *)pcmd, 0, sizeof(struct sil_cmd_block)); - pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; - pcmd->prb.fis.pm_port_c = (1 << 7); - pcmd->prb.fis.command = ATA_CMD_FLUSH_EXT; - - sil_exec_cmd(dev, pcmd, 0); -} - -static void sil_sata_init_wcache(int dev, u16 *id) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - - if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id)) - sata->wcache = 1; - if (ata_id_has_flush(id)) - sata->flush = 1; - if (ata_id_has_flush_ext(id)) - sata->flush_ext = 1; -} - -static int sil_sata_get_wcache(int dev) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - - return sata->wcache; -} - -static int sil_sata_get_flush(int dev) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - - return sata->flush; -} - -static int sil_sata_get_flush_ext(int dev) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - - return sata->flush_ext; -} - -/* - * SATA interface between low level driver and command layer - */ -ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - ulong rc; - - if (sata->lba48) - rc = sil_sata_rw_lba48(dev, blknr, blkcnt, buffer, READ_CMD); - else - rc = sil_sata_rw_lba28(dev, blknr, blkcnt, buffer, READ_CMD); - - return rc; -} - -/* - * SATA interface between low level driver and command layer - */ -ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - ulong rc; - - if (sata->lba48) { - rc = sil_sata_rw_lba48(dev, blknr, blkcnt, buffer, WRITE_CMD); - if (sil_sata_get_wcache(dev) && sil_sata_get_flush_ext(dev)) - sil_sata_cmd_flush_cache_ext(dev); - } else { - rc = sil_sata_rw_lba28(dev, blknr, blkcnt, buffer, WRITE_CMD); - if (sil_sata_get_wcache(dev) && sil_sata_get_flush(dev)) - sil_sata_cmd_flush_cache(dev); - } - - return rc; -} - -/* - * SATA interface between low level driver and command layer - */ -int init_sata(int dev) -{ - static int init_done, idx; - pci_dev_t devno; - u16 word; - - if (init_done == 1 && dev < sata_info.maxport) - return 0; - - init_done = 1; - - /* Find PCI device(s) */ - devno = pci_find_devices(supported, idx++); - if (devno == -1) - return 1; - - pci_read_config_word(devno, PCI_DEVICE_ID, &word); - - /* get the port count */ - word &= 0xf; - - sata_info.portbase = sata_info.maxport; - sata_info.maxport = sata_info.portbase + word; - sata_info.devno = devno; - - /* Read out all BARs */ - sata_info.iobase[0] = (ulong)pci_map_bar(devno, - PCI_BASE_ADDRESS_0, PCI_REGION_MEM); - sata_info.iobase[1] = (ulong)pci_map_bar(devno, - PCI_BASE_ADDRESS_2, PCI_REGION_MEM); - sata_info.iobase[2] = (ulong)pci_map_bar(devno, - PCI_BASE_ADDRESS_4, PCI_REGION_MEM); - - /* mask out the unused bits */ - sata_info.iobase[0] &= 0xffffff80; - sata_info.iobase[1] &= 0xfffffc00; - sata_info.iobase[2] &= 0xffffff80; - - /* Enable Bus Mastering and memory region */ - pci_write_config_word(devno, PCI_COMMAND, - PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - - /* Check if mem accesses and Bus Mastering are enabled. */ - pci_read_config_word(devno, PCI_COMMAND, &word); - if (!(word & PCI_COMMAND_MEMORY) || - (!(word & PCI_COMMAND_MASTER))) { - printf("Error: Can not enable MEM access or Bus Mastering.\n"); - debug("PCI command: %04x\n", word); - return 1; - } - - /* GPIO off */ - writel(0, (void *)(sata_info.iobase[0] + HOST_FLASH_CMD)); - /* clear global reset & mask interrupts during initialization */ - writel(0, (void *)(sata_info.iobase[0] + HOST_CTRL)); - - return 0; -} - -int reset_sata(int dev) -{ - return 0; -} - -/* - * SATA interface between low level driver and command layer - */ -int scan_sata(int dev) -{ - 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]; - struct sil_sata *sata; - void *port; - int cnt; - u16 *id; - u32 tmp; - - if (dev >= sata_info.maxport) { - printf("SATA#%d is not present\n", dev); - return 1; - } - - printf("SATA#%d\n", dev); - port = (void *)sata_info.iobase[1] + - PORT_REGS_SIZE * (dev - sata_info.portbase); - - /* Initial PHY setting */ - writel(0x20c, port + PORT_PHY_CFG); - - /* clear port RST */ - tmp = readl(port + PORT_CTRL_STAT); - if (tmp & PORT_CS_PORT_RST) { - writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); - tmp = ata_wait_register(port + PORT_CTRL_STAT, - PORT_CS_PORT_RST, PORT_CS_PORT_RST, 100); - if (tmp & PORT_CS_PORT_RST) - printf("Err: Failed to clear port RST\n"); - } - - /* Check if device is present */ - for (cnt = 0; cnt < 100; cnt++) { - tmp = readl(port + PORT_SSTATUS); - if ((tmp & 0xF) == 0x3) - break; - mdelay(1); - } - - tmp = readl(port + PORT_SSTATUS); - if ((tmp & 0xf) != 0x3) { - printf(" (No RDY)\n"); - return 1; - } - - /* Wait for port ready */ - tmp = ata_wait_register(port + PORT_CTRL_STAT, - PORT_CS_RDY, PORT_CS_RDY, 100); - if ((tmp & PORT_CS_RDY) != PORT_CS_RDY) { - printf("%d port not ready.\n", dev); - return 1; - } - - /* configure port */ - sil_config_port(port); - - /* Reset port */ - writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); - readl(port + PORT_CTRL_STAT); - tmp = ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_DEV_RST, - PORT_CS_DEV_RST, 100); - if (tmp & PORT_CS_DEV_RST) { - printf("%d port reset failed.\n", dev); - return 1; - } - - sata = (struct sil_sata *)malloc(sizeof(struct sil_sata)); - if (!sata) { - printf("%d no memory.\n", dev); - return 1; - } - memset((void *)sata, 0, sizeof(struct sil_sata)); - - /* turn on port interrupt */ - tmp = readl((void *)(sata_info.iobase[0] + HOST_CTRL)); - tmp |= (1 << (dev - sata_info.portbase)); - writel(tmp, (void *)(sata_info.iobase[0] + HOST_CTRL)); - - /* Save the private struct to block device struct */ - sata_dev_desc[dev].priv = (void *)sata; - sata->port = port; - sata->devno = sata_info.devno; - sprintf(sata->name, "SATA#%d", dev); - sil_cmd_soft_reset(dev); - tmp = readl(port + PORT_SSTATUS); - tmp = (tmp >> 4) & 0xf; - printf(" (%s)\n", sata_spd_string(tmp)); - - id = (u16 *)malloc(ATA_ID_WORDS * 2); - if (!id) { - printf("Id malloc failed\n"); - free((void *)sata); - return 1; - } - sil_cmd_identify_device(dev, id); - -#ifdef CONFIG_LBA48 - /* Check if support LBA48 */ - if (ata_id_has_lba48(id)) { - sata_dev_desc[dev].lba48 = 1; - sata->lba48 = 1; - debug("Device supports LBA48\n"); - } else - debug("Device supports LBA28\n"); -#endif - - /* Serial number */ - ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); - memcpy(sata_dev_desc[dev].product, serial, sizeof(serial)); - - /* Firmware version */ - ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); - memcpy(sata_dev_desc[dev].revision, firmware, sizeof(firmware)); - - /* Product model */ - ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); - memcpy(sata_dev_desc[dev].vendor, product, sizeof(product)); - - /* Totoal sectors */ - sata_dev_desc[dev].lba = ata_id_n_sectors(id); - - sil_sata_init_wcache(dev, id); - sil_cmd_set_feature(dev); - -#ifdef DEBUG - sil_cmd_identify_device(dev, id); - ata_dump_id(id); -#endif - free((void *)id); - - return 0; -} diff --git a/drivers/block/sata_sil.h b/drivers/block/sata_sil.h deleted file mode 100644 index 55954efdd6..0000000000 --- a/drivers/block/sata_sil.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2011 Freescale Semiconductor, Inc. - * Author: Tang Yuantian - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef SATA_SIL3132_H -#define SATA_SIL3132_H - -#define READ_CMD 0 -#define WRITE_CMD 1 - -/* - * SATA device driver struct for each dev - */ -struct sil_sata { - char name[12]; - void *port; /* the port base address */ - int lba48; - u16 pio; - u16 mwdma; - u16 udma; - pci_dev_t devno; - int wcache; - int flush; - int flush_ext; -}; - -/* sata info for each controller */ -struct sata_info { - ulong iobase[3]; - pci_dev_t devno; - int portbase; - int maxport; -}; - -/* - * Scatter gather entry (SGE),MUST 8 bytes aligned - */ -struct sil_sge { - __le64 addr; - __le32 cnt; - __le32 flags; -} __attribute__ ((aligned(8), packed)); - -/* - * Port request block, MUST 8 bytes aligned - */ -struct sil_prb { - __le16 ctrl; - __le16 prot; - __le32 rx_cnt; - struct sata_fis_h2d fis; -} __attribute__ ((aligned(8), packed)); - -struct sil_cmd_block { - struct sil_prb prb; - struct sil_sge sge; -}; - -enum { - HOST_SLOT_STAT = 0x00, /* 32 bit slot stat * 4 */ - HOST_CTRL = 0x40, - HOST_IRQ_STAT = 0x44, - HOST_PHY_CFG = 0x48, - HOST_BIST_CTRL = 0x50, - HOST_BIST_PTRN = 0x54, - HOST_BIST_STAT = 0x58, - HOST_MEM_BIST_STAT = 0x5c, - HOST_FLASH_CMD = 0x70, - /* 8 bit regs */ - HOST_FLASH_DATA = 0x74, - HOST_TRANSITION_DETECT = 0x75, - HOST_GPIO_CTRL = 0x76, - HOST_I2C_ADDR = 0x78, /* 32 bit */ - HOST_I2C_DATA = 0x7c, - HOST_I2C_XFER_CNT = 0x7e, - HOST_I2C_CTRL = 0x7f, - - /* HOST_SLOT_STAT bits */ - HOST_SSTAT_ATTN = (1 << 31), - - /* HOST_CTRL bits */ - HOST_CTRL_M66EN = (1 << 16), /* M66EN PCI bus signal */ - HOST_CTRL_TRDY = (1 << 17), /* latched PCI TRDY */ - HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */ - HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */ - HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */ - HOST_CTRL_GLOBAL_RST = (1 << 31), /* global reset */ - - /* - * Port registers - * (8192 bytes @ +0x0000, +0x2000, +0x4000 and +0x6000 @ BAR2) - */ - PORT_REGS_SIZE = 0x2000, - - PORT_LRAM = 0x0000, /* 31 LRAM slots and PMP regs */ - PORT_LRAM_SLOT_SZ = 0x0080, /* 32 bytes PRB + 2 SGE, ACT... */ - - PORT_PMP = 0x0f80, /* 8 bytes PMP * 16 (128 bytes) */ - PORT_PMP_STATUS = 0x0000, /* port device status offset */ - PORT_PMP_QACTIVE = 0x0004, /* port device QActive offset */ - PORT_PMP_SIZE = 0x0008, /* 8 bytes per PMP */ - - /* 32 bit regs */ - PORT_CTRL_STAT = 0x1000, /* write: ctrl-set, read: stat */ - PORT_CTRL_CLR = 0x1004, /* write: ctrl-clear */ - PORT_IRQ_STAT = 0x1008, /* high: status, low: interrupt */ - PORT_IRQ_ENABLE_SET = 0x1010, /* write: enable-set */ - PORT_IRQ_ENABLE_CLR = 0x1014, /* write: enable-clear */ - PORT_ACTIVATE_UPPER_ADDR = 0x101c, - PORT_EXEC_FIFO = 0x1020, /* command execution fifo */ - PORT_CMD_ERR = 0x1024, /* command error number */ - PORT_FIS_CFG = 0x1028, - PORT_FIFO_THRES = 0x102c, - - /* 16 bit regs */ - PORT_DECODE_ERR_CNT = 0x1040, - PORT_DECODE_ERR_THRESH = 0x1042, - PORT_CRC_ERR_CNT = 0x1044, - PORT_CRC_ERR_THRESH = 0x1046, - PORT_HSHK_ERR_CNT = 0x1048, - PORT_HSHK_ERR_THRESH = 0x104a, - - /* 32 bit regs */ - PORT_PHY_CFG = 0x1050, - PORT_SLOT_STAT = 0x1800, - PORT_CMD_ACTIVATE = 0x1c00, /* 64 bit cmd activate * 31 */ - PORT_CONTEXT = 0x1e04, - PORT_EXEC_DIAG = 0x1e00, /* 32bit exec diag * 16 */ - PORT_PSD_DIAG = 0x1e40, /* 32bit psd diag * 16 */ - PORT_SCONTROL = 0x1f00, - PORT_SSTATUS = 0x1f04, - PORT_SERROR = 0x1f08, - PORT_SACTIVE = 0x1f0c, - - /* PORT_CTRL_STAT bits */ - PORT_CS_PORT_RST = (1 << 0), /* port reset */ - PORT_CS_DEV_RST = (1 << 1), /* device reset */ - PORT_CS_INIT = (1 << 2), /* port initialize */ - PORT_CS_IRQ_WOC = (1 << 3), /* interrupt write one to clear */ - PORT_CS_CDB16 = (1 << 5), /* 0=12b cdb, 1=16b cdb */ - PORT_CS_PMP_RESUME = (1 << 6), /* PMP resume */ - PORT_CS_32BIT_ACTV = (1 << 10), /* 32-bit activation */ - PORT_CS_PMP_EN = (1 << 13), /* port multiplier enable */ - PORT_CS_RDY = (1 << 31), /* port ready to accept commands */ - - /* PORT_IRQ_STAT/ENABLE_SET/CLR */ - /* bits[11:0] are masked */ - PORT_IRQ_COMPLETE = (1 << 0), /* command(s) completed */ - PORT_IRQ_ERROR = (1 << 1), /* command execution error */ - PORT_IRQ_PORTRDY_CHG = (1 << 2), /* port ready change */ - PORT_IRQ_PWR_CHG = (1 << 3), /* power management change */ - PORT_IRQ_PHYRDY_CHG = (1 << 4), /* PHY ready change */ - PORT_IRQ_COMWAKE = (1 << 5), /* COMWAKE received */ - PORT_IRQ_UNK_FIS = (1 << 6), /* unknown FIS received */ - PORT_IRQ_DEV_XCHG = (1 << 7), /* device exchanged */ - PORT_IRQ_8B10B = (1 << 8), /* 8b/10b decode error threshold */ - PORT_IRQ_CRC = (1 << 9), /* CRC error threshold */ - PORT_IRQ_HANDSHAKE = (1 << 10), /* handshake error threshold */ - PORT_IRQ_SDB_NOTIFY = (1 << 11), /* SDB notify received */ - - DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR | - PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG | - PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_NOTIFY, - - /* bits[27:16] are unmasked (raw) */ - PORT_IRQ_RAW_SHIFT = 16, - PORT_IRQ_MASKED_MASK = 0x7ff, - PORT_IRQ_RAW_MASK = (0x7ff << PORT_IRQ_RAW_SHIFT), - - /* ENABLE_SET/CLR specific, intr steering - 2 bit field */ - PORT_IRQ_STEER_SHIFT = 30, - PORT_IRQ_STEER_MASK = (3 << PORT_IRQ_STEER_SHIFT), - - /* PORT_CMD_ERR constants */ - PORT_CERR_DEV = 1, /* Error bit in D2H Register FIS */ - PORT_CERR_SDB = 2, /* Error bit in SDB FIS */ - PORT_CERR_DATA = 3, /* Error in data FIS not detected by dev */ - PORT_CERR_SEND = 4, /* Initial cmd FIS transmission failure */ - PORT_CERR_INCONSISTENT = 5, /* Protocol mismatch */ - PORT_CERR_DIRECTION = 6, /* Data direction mismatch */ - PORT_CERR_UNDERRUN = 7, /* Ran out of SGEs while writing */ - PORT_CERR_OVERRUN = 8, /* Ran out of SGEs while reading */ - - /* bits of PRB control field */ - PRB_CTRL_PROTOCOL = (1 << 0), /* override def. ATA protocol */ - PRB_CTRL_PACKET_READ = (1 << 4), /* PACKET cmd read */ - PRB_CTRL_PACKET_WRITE = (1 << 5), /* PACKET cmd write */ - PRB_CTRL_NIEN = (1 << 6), /* Mask completion irq */ - PRB_CTRL_SRST = (1 << 7), /* Soft reset request (ign BSY?) */ - - /* PRB protocol field */ - PRB_PROT_PACKET = (1 << 0), - PRB_PROT_TCQ = (1 << 1), - PRB_PROT_NCQ = (1 << 2), - PRB_PROT_READ = (1 << 3), - PRB_PROT_WRITE = (1 << 4), - PRB_PROT_TRANSPARENT = (1 << 5), - - /* - * Other constants - */ - SGE_TRM = (1 << 31), /* Last SGE in chain */ - SGE_LNK = (1 << 30), /* linked list - Points to SGT, not SGE */ - SGE_DRD = (1 << 29), /* discard data read (/dev/null) - data address ignored */ - - CMD_ERR = 0x21, -}; - -#endif diff --git a/drivers/block/sata_sil3114.c b/drivers/block/sata_sil3114.c deleted file mode 100644 index 61ffb66a77..0000000000 --- a/drivers/block/sata_sil3114.c +++ /dev/null @@ -1,835 +0,0 @@ -/* - * Copyright (C) Excito Elektronik i Skåne AB, All rights reserved. - * Author: Tor Krill - * - * SPDX-License-Identifier: GPL-2.0+ - * - * This is a driver for Silicon Image sil3114 sata chip modelled on - * the ata_piix driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sata_sil3114.h" - -/* Convert sectorsize to wordsize */ -#define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2) - -/* Forwards */ -u8 sil3114_spin_up (int num); -u8 sil3114_spin_down (int num); -static int sata_bus_softreset (int num); -static void sata_identify (int num, int dev); -static u8 check_power_mode (int num); -static void sata_port (struct sata_ioports *ioport); -static void set_Feature_cmd (int num, int dev); -static u8 sata_busy_wait (struct sata_ioports *ioaddr, int bits, - unsigned int max, u8 usealtstatus); -static u8 sata_chk_status (struct sata_ioports *ioaddr, u8 usealtstatus); -static void msleep (int count); - -static u32 iobase[6] = { 0, 0, 0, 0, 0, 0}; /* PCI BAR registers for device */ - -static struct sata_port port[CONFIG_SYS_SATA_MAX_DEVICE]; - -static void output_data (struct sata_ioports *ioaddr, u16 * sect_buf, int words) -{ - while (words--) { - __raw_writew (*sect_buf++, (void *)ioaddr->data_addr); - } -} - -static int input_data (struct sata_ioports *ioaddr, u16 * sect_buf, int words) -{ - while (words--) { - *sect_buf++ = __raw_readw ((void *)ioaddr->data_addr); - } - return 0; -} - -static int sata_bus_softreset (int num) -{ - u8 status = 0; - - port[num].dev_mask = 1; - - port[num].ctl_reg = 0x08; /*Default value of control reg */ - writeb (port[num].ctl_reg, port[num].ioaddr.ctl_addr); - udelay (10); - writeb (port[num].ctl_reg | ATA_SRST, port[num].ioaddr.ctl_addr); - udelay (10); - writeb (port[num].ctl_reg, port[num].ioaddr.ctl_addr); - - /* spec mandates ">= 2ms" before checking status. - * We wait 150ms, because that was the magic delay used for - * ATAPI devices in Hale Landis's ATADRVR, for the period of time - * between when the ATA command register is written, and then - * status is checked. Because waiting for "a while" before - * checking status is fine, post SRST, we perform this magic - * delay here as well. - */ - msleep (150); - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 300, 0); - while ((status & ATA_BUSY)) { - msleep (100); - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 3, 0); - } - - if (status & ATA_BUSY) { - printf ("ata%u is slow to respond,plz be patient\n", num); - } - - while ((status & ATA_BUSY)) { - msleep (100); - status = sata_chk_status (&port[num].ioaddr, 0); - } - - if (status & ATA_BUSY) { - printf ("ata%u failed to respond : ", num); - printf ("bus reset failed\n"); - port[num].dev_mask = 0; - return 1; - } - return 0; -} - -static void sata_identify (int num, int dev) -{ - u8 cmd = 0, status = 0, devno = num; - u16 iobuf[ATA_SECTOR_WORDS]; - u64 n_sectors = 0; - - memset (iobuf, 0, sizeof (iobuf)); - - if (!(port[num].dev_mask & 0x01)) { - printf ("dev%d is not present on port#%d\n", dev, num); - return; - } - - debug ("port=%d dev=%d\n", num, dev); - - status = 0; - cmd = ATA_CMD_ID_ATA; /*Device Identify Command */ - writeb (cmd, port[num].ioaddr.command_addr); - readb (port[num].ioaddr.altstatus_addr); - udelay (10); - - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 1000, 0); - if (status & ATA_ERR) { - printf ("\ndevice not responding\n"); - port[num].dev_mask &= ~0x01; - return; - } - - input_data (&port[num].ioaddr, iobuf, ATA_SECTOR_WORDS); - - ata_swap_buf_le16 (iobuf, ATA_SECTOR_WORDS); - - debug ("Specific config: %x\n", iobuf[2]); - - /* we require LBA and DMA support (bits 8 & 9 of word 49) */ - if (!ata_id_has_dma (iobuf) || !ata_id_has_lba (iobuf)) { - debug ("ata%u: no dma/lba\n", num); - } -#ifdef DEBUG - ata_dump_id (iobuf); -#endif - n_sectors = ata_id_n_sectors (iobuf); - - if (n_sectors == 0) { - port[num].dev_mask &= ~0x01; - return; - } - ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].revision, - ATA_ID_FW_REV, sizeof (sata_dev_desc[devno].revision)); - ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].vendor, - ATA_ID_PROD, sizeof (sata_dev_desc[devno].vendor)); - ata_id_c_string (iobuf, (unsigned char *)sata_dev_desc[devno].product, - ATA_ID_SERNO, sizeof (sata_dev_desc[devno].product)); - - /* TODO - atm we asume harddisk ie not removable */ - sata_dev_desc[devno].removable = 0; - - sata_dev_desc[devno].lba = (u32) n_sectors; - debug("lba=0x%lx\n", sata_dev_desc[devno].lba); - -#ifdef CONFIG_LBA48 - if (iobuf[83] & (1 << 10)) { - sata_dev_desc[devno].lba48 = 1; - } else { - sata_dev_desc[devno].lba48 = 0; - } -#endif - - /* assuming HD */ - sata_dev_desc[devno].type = DEV_TYPE_HARDDISK; - sata_dev_desc[devno].blksz = ATA_SECT_SIZE; - sata_dev_desc[devno].lun = 0; /* just to fill something in... */ -} - -static void set_Feature_cmd (int num, int dev) -{ - u8 status = 0; - - if (!(port[num].dev_mask & 0x01)) { - debug ("dev%d is not present on port#%d\n", dev, num); - return; - } - - writeb (SETFEATURES_XFER, port[num].ioaddr.feature_addr); - writeb (XFER_PIO_4, port[num].ioaddr.nsect_addr); - writeb (0, port[num].ioaddr.lbal_addr); - writeb (0, port[num].ioaddr.lbam_addr); - writeb (0, port[num].ioaddr.lbah_addr); - - writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); - writeb (ATA_CMD_SET_FEATURES, port[num].ioaddr.command_addr); - - udelay (50); - msleep (150); - - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 5000, 0); - if ((status & (ATA_BUSY | ATA_ERR))) { - printf ("Error : status 0x%02x\n", status); - port[num].dev_mask &= ~0x01; - } -} - -u8 sil3114_spin_down (int num) -{ - u8 status = 0; - - debug ("Spin down disk\n"); - - if (!(port[num].dev_mask & 0x01)) { - debug ("Device ata%d is not present\n", num); - return 1; - } - - if ((status = check_power_mode (num)) == 0x00) { - debug ("Already in standby\n"); - return 0; - } - - if (status == 0x01) { - printf ("Failed to check power mode on ata%d\n", num); - return 1; - } - - if (!((status = sata_chk_status (&port[num].ioaddr, 0)) & ATA_DRDY)) { - printf ("Device ata%d not ready\n", num); - return 1; - } - - writeb (0x00, port[num].ioaddr.feature_addr); - - writeb (0x00, port[num].ioaddr.nsect_addr); - writeb (0x00, port[num].ioaddr.lbal_addr); - writeb (0x00, port[num].ioaddr.lbam_addr); - writeb (0x00, port[num].ioaddr.lbah_addr); - - writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); - writeb (ATA_CMD_STANDBY, port[num].ioaddr.command_addr); - - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 30000, 0); - if ((status & (ATA_BUSY | ATA_ERR))) { - printf ("Error waiting for disk spin down: status 0x%02x\n", - status); - port[num].dev_mask &= ~0x01; - return 1; - } - return 0; -} - -u8 sil3114_spin_up (int num) -{ - u8 status = 0; - - debug ("Spin up disk\n"); - - if (!(port[num].dev_mask & 0x01)) { - debug ("Device ata%d is not present\n", num); - return 1; - } - - if ((status = check_power_mode (num)) != 0x00) { - if (status == 0x01) { - printf ("Failed to check power mode on ata%d\n", num); - return 1; - } else { - /* should be up and running already */ - return 0; - } - } - - if (!((status = sata_chk_status (&port[num].ioaddr, 0)) & ATA_DRDY)) { - printf ("Device ata%d not ready\n", num); - return 1; - } - - debug ("Stautus of device check: %d\n", status); - - writeb (0x00, port[num].ioaddr.feature_addr); - - writeb (0x00, port[num].ioaddr.nsect_addr); - writeb (0x00, port[num].ioaddr.lbal_addr); - writeb (0x00, port[num].ioaddr.lbam_addr); - writeb (0x00, port[num].ioaddr.lbah_addr); - - writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); - writeb (ATA_CMD_IDLE, port[num].ioaddr.command_addr); - - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 30000, 0); - if ((status & (ATA_BUSY | ATA_ERR))) { - printf ("Error waiting for disk spin up: status 0x%02x\n", - status); - port[num].dev_mask &= ~0x01; - return 1; - } - - /* Wait for disk to enter Active state */ - do { - msleep (10); - status = check_power_mode (num); - } while ((status == 0x00) || (status == 0x80)); - - if (status == 0x01) { - printf ("Falied waiting for disk to spin up\n"); - return 1; - } - - return 0; -} - -/* Return value is not the usual here - * 0x00 - Device stand by - * 0x01 - Operation failed - * 0x80 - Device idle - * 0xff - Device active -*/ -static u8 check_power_mode (int num) -{ - u8 status = 0; - u8 res = 0; - if (!(port[num].dev_mask & 0x01)) { - debug ("Device ata%d is not present\n", num); - return 1; - } - - if (!(sata_chk_status (&port[num].ioaddr, 0) & ATA_DRDY)) { - printf ("Device ata%d not ready\n", num); - return 1; - } - - writeb (0, port[num].ioaddr.feature_addr); - writeb (0, port[num].ioaddr.nsect_addr); - writeb (0, port[num].ioaddr.lbal_addr); - writeb (0, port[num].ioaddr.lbam_addr); - writeb (0, port[num].ioaddr.lbah_addr); - - writeb (ATA_DEVICE_OBS, port[num].ioaddr.device_addr); - writeb (ATA_CMD_CHK_POWER, port[num].ioaddr.command_addr); - - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 5000, 0); - if ((status & (ATA_BUSY | ATA_ERR))) { - printf - ("Error waiting for check power mode complete : status 0x%02x\n", - status); - port[num].dev_mask &= ~0x01; - return 1; - } - res = readb (port[num].ioaddr.nsect_addr); - debug ("Check powermode: %d\n", res); - return res; - -} - -static void sata_port (struct sata_ioports *ioport) -{ - ioport->data_addr = ioport->cmd_addr + ATA_REG_DATA; - ioport->error_addr = ioport->cmd_addr + ATA_REG_ERR; - ioport->feature_addr = ioport->cmd_addr + ATA_REG_FEATURE; - ioport->nsect_addr = ioport->cmd_addr + ATA_REG_NSECT; - ioport->lbal_addr = ioport->cmd_addr + ATA_REG_LBAL; - ioport->lbam_addr = ioport->cmd_addr + ATA_REG_LBAM; - ioport->lbah_addr = ioport->cmd_addr + ATA_REG_LBAH; - ioport->device_addr = ioport->cmd_addr + ATA_REG_DEVICE; - ioport->status_addr = ioport->cmd_addr + ATA_REG_STATUS; - ioport->command_addr = ioport->cmd_addr + ATA_REG_CMD; -} - -static u8 wait_for_irq (int num, unsigned int max) -{ - - u32 port = iobase[5]; - switch (num) { - case 0: - port += VND_TF_CNST_CH0; - break; - case 1: - port += VND_TF_CNST_CH1; - break; - case 2: - port += VND_TF_CNST_CH2; - break; - case 3: - port += VND_TF_CNST_CH3; - break; - default: - return 1; - } - - do { - if (readl (port) & VND_TF_CNST_INTST) { - break; - } - udelay (1000); - max--; - } while ((max > 0)); - - return (max == 0); -} - -static u8 sata_busy_wait (struct sata_ioports *ioaddr, int bits, - unsigned int max, u8 usealtstatus) -{ - u8 status; - - do { - if (!((status = sata_chk_status (ioaddr, usealtstatus)) & bits)) { - break; - } - udelay (1000); - max--; - } while ((status & bits) && (max > 0)); - - return status; -} - -static u8 sata_chk_status (struct sata_ioports *ioaddr, u8 usealtstatus) -{ - if (!usealtstatus) { - return readb (ioaddr->status_addr); - } else { - return readb (ioaddr->altstatus_addr); - } -} - -static void msleep (int count) -{ - int i; - - for (i = 0; i < count; i++) - udelay (1000); -} - -/* Read up to 255 sectors - * - * Returns sectors read -*/ -static u8 do_one_read (int device, ulong block, u8 blkcnt, u16 * buff, - uchar lba48) -{ - - u8 sr = 0; - u8 status; - u64 blknr = (u64) block; - - if (!(sata_chk_status (&port[device].ioaddr, 0) & ATA_DRDY)) { - printf ("Device ata%d not ready\n", device); - return 0; - } - - /* Set up transfer */ -#ifdef CONFIG_LBA48 - if (lba48) { - /* write high bits */ - writeb (0, port[device].ioaddr.nsect_addr); - writeb ((blknr >> 24) & 0xFF, port[device].ioaddr.lbal_addr); - writeb ((blknr >> 32) & 0xFF, port[device].ioaddr.lbam_addr); - writeb ((blknr >> 40) & 0xFF, port[device].ioaddr.lbah_addr); - } -#endif - writeb (blkcnt, port[device].ioaddr.nsect_addr); - writeb (((blknr) >> 0) & 0xFF, port[device].ioaddr.lbal_addr); - writeb ((blknr >> 8) & 0xFF, port[device].ioaddr.lbam_addr); - writeb ((blknr >> 16) & 0xFF, port[device].ioaddr.lbah_addr); - -#ifdef CONFIG_LBA48 - if (lba48) { - writeb (ATA_LBA, port[device].ioaddr.device_addr); - writeb (ATA_CMD_PIO_READ_EXT, port[device].ioaddr.command_addr); - } else -#endif - { - writeb (ATA_LBA | ((blknr >> 24) & 0xF), - port[device].ioaddr.device_addr); - writeb (ATA_CMD_PIO_READ, port[device].ioaddr.command_addr); - } - - status = sata_busy_wait (&port[device].ioaddr, ATA_BUSY, 10000, 1); - - if (status & ATA_BUSY) { - u8 err = 0; - - printf ("Device %d not responding status %d\n", device, status); - err = readb (port[device].ioaddr.error_addr); - printf ("Error reg = 0x%x\n", err); - - return (sr); - } - while (blkcnt--) { - - if (wait_for_irq (device, 500)) { - printf ("ata%u irq failed\n", device); - return sr; - } - - status = sata_chk_status (&port[device].ioaddr, 0); - if (status & ATA_ERR) { - printf ("ata%u error %d\n", device, - readb (port[device].ioaddr.error_addr)); - return sr; - } - /* Read one sector */ - input_data (&port[device].ioaddr, buff, ATA_SECTOR_WORDS); - buff += ATA_SECTOR_WORDS; - sr++; - - } - return sr; -} - -ulong sata_read (int device, ulong block, lbaint_t blkcnt, void *buff) -{ - ulong n = 0, sread; - u16 *buffer = (u16 *) buff; - u8 status = 0; - u64 blknr = (u64) block; - unsigned char lba48 = 0; - -#ifdef CONFIG_LBA48 - if (blknr > 0xfffffff) { - if (!sata_dev_desc[device].lba48) { - printf ("Drive doesn't support 48-bit addressing\n"); - return 0; - } - /* more than 28 bits used, use 48bit mode */ - lba48 = 1; - } -#endif - - while (blkcnt > 0) { - - if (blkcnt > 255) { - sread = 255; - } else { - sread = blkcnt; - } - - status = do_one_read (device, blknr, sread, buffer, lba48); - if (status != sread) { - printf ("Read failed\n"); - return n; - } - - blkcnt -= sread; - blknr += sread; - n += sread; - buffer += sread * ATA_SECTOR_WORDS; - } - return n; -} - -ulong sata_write (int device, ulong block, lbaint_t blkcnt, const void *buff) -{ - ulong n = 0; - u16 *buffer = (u16 *) buff; - unsigned char status = 0, num = 0; - u64 blknr = (u64) block; -#ifdef CONFIG_LBA48 - unsigned char lba48 = 0; - - if (blknr > 0xfffffff) { - if (!sata_dev_desc[device].lba48) { - printf ("Drive doesn't support 48-bit addressing\n"); - return 0; - } - /* more than 28 bits used, use 48bit mode */ - lba48 = 1; - } -#endif - /*Port Number */ - num = device; - - while (blkcnt-- > 0) { - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 500, 0); - if (status & ATA_BUSY) { - printf ("ata%u failed to respond\n", port[num].port_no); - return n; - } -#ifdef CONFIG_LBA48 - if (lba48) { - /* write high bits */ - writeb (0, port[num].ioaddr.nsect_addr); - writeb ((blknr >> 24) & 0xFF, - port[num].ioaddr.lbal_addr); - writeb ((blknr >> 32) & 0xFF, - port[num].ioaddr.lbam_addr); - writeb ((blknr >> 40) & 0xFF, - port[num].ioaddr.lbah_addr); - } -#endif - writeb (1, port[num].ioaddr.nsect_addr); - writeb ((blknr >> 0) & 0xFF, port[num].ioaddr.lbal_addr); - writeb ((blknr >> 8) & 0xFF, port[num].ioaddr.lbam_addr); - writeb ((blknr >> 16) & 0xFF, port[num].ioaddr.lbah_addr); -#ifdef CONFIG_LBA48 - if (lba48) { - writeb (ATA_LBA, port[num].ioaddr.device_addr); - writeb (ATA_CMD_PIO_WRITE_EXT, port[num].ioaddr.command_addr); - } else -#endif - { - writeb (ATA_LBA | ((blknr >> 24) & 0xF), - port[num].ioaddr.device_addr); - writeb (ATA_CMD_PIO_WRITE, port[num].ioaddr.command_addr); - } - - msleep (50); - /*may take up to 4 sec */ - status = sata_busy_wait (&port[num].ioaddr, ATA_BUSY, 4000, 0); - if ((status & (ATA_DRQ | ATA_BUSY | ATA_ERR)) != ATA_DRQ) { - printf ("Error no DRQ dev %d blk %ld: sts 0x%02x\n", - device, (ulong) blknr, status); - return (n); - } - - output_data (&port[num].ioaddr, buffer, ATA_SECTOR_WORDS); - readb (port[num].ioaddr.altstatus_addr); - udelay (50); - - ++n; - ++blknr; - buffer += ATA_SECTOR_WORDS; - } - return n; -} - -/* Driver implementation */ -static u8 sil_get_device_cache_line (pci_dev_t pdev) -{ - u8 cache_line = 0; - pci_read_config_byte (pdev, PCI_CACHE_LINE_SIZE, &cache_line); - return cache_line; -} - -int init_sata (int dev) -{ - static u8 init_done = 0; - static int res = 1; - pci_dev_t devno; - u8 cls = 0; - u16 cmd = 0; - u32 sconf = 0; - - if (init_done) { - return res; - } - - init_done = 1; - - if ((devno = pci_find_device (SIL_VEND_ID, SIL3114_DEVICE_ID, 0)) == -1) { - res = 1; - return res; - } - - /* Read out all BARs, even though we only use MMIO from BAR5 */ - pci_read_config_dword (devno, PCI_BASE_ADDRESS_0, &iobase[0]); - pci_read_config_dword (devno, PCI_BASE_ADDRESS_1, &iobase[1]); - pci_read_config_dword (devno, PCI_BASE_ADDRESS_2, &iobase[2]); - pci_read_config_dword (devno, PCI_BASE_ADDRESS_3, &iobase[3]); - pci_read_config_dword (devno, PCI_BASE_ADDRESS_4, &iobase[4]); - pci_read_config_dword (devno, PCI_BASE_ADDRESS_5, &iobase[5]); - - if ((iobase[0] == 0xFFFFFFFF) || (iobase[1] == 0xFFFFFFFF) || - (iobase[2] == 0xFFFFFFFF) || (iobase[3] == 0xFFFFFFFF) || - (iobase[4] == 0xFFFFFFFF) || (iobase[5] == 0xFFFFFFFF)) { - printf ("Error no base addr for SATA controller\n"); - res = 1; - return res; - } - - /* mask off unused bits */ - iobase[0] &= 0xfffffffc; - iobase[1] &= 0xfffffff8; - iobase[2] &= 0xfffffffc; - iobase[3] &= 0xfffffff8; - iobase[4] &= 0xfffffff0; - iobase[5] &= 0xfffffc00; - - /* from sata_sil in Linux kernel */ - cls = sil_get_device_cache_line (devno); - if (cls) { - cls >>= 3; - cls++; /* cls = (line_size/8)+1 */ - writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH0); - writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH1); - writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH2); - writel (cls << 8 | cls, iobase[5] + VND_FIFOCFG_CH3); - } else { - printf ("Cache line not set. Driver may not function\n"); - } - - /* Enable operation */ - pci_read_config_word (devno, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; - pci_write_config_word (devno, PCI_COMMAND, cmd); - - /* Disable interrupt usage */ - pci_read_config_dword (devno, VND_SYSCONFSTAT, &sconf); - sconf |= (VND_SYSCONFSTAT_CHN_0_INTBLOCK | VND_SYSCONFSTAT_CHN_1_INTBLOCK); - pci_write_config_dword (devno, VND_SYSCONFSTAT, sconf); - - res = 0; - return res; -} - -int reset_sata(int dev) -{ - return 0; -} - -/* Check if device is connected to port */ -int sata_bus_probe (int portno) -{ - u32 port = iobase[5]; - u32 val; - switch (portno) { - case 0: - port += VND_SSTATUS_CH0; - break; - case 1: - port += VND_SSTATUS_CH1; - break; - case 2: - port += VND_SSTATUS_CH2; - break; - case 3: - port += VND_SSTATUS_CH3; - break; - default: - return 0; - } - val = readl (port); - if ((val & SATA_DET_PRES) == SATA_DET_PRES) { - return 1; - } else { - return 0; - } -} - -int sata_phy_reset (int portno) -{ - u32 port = iobase[5]; - u32 val; - switch (portno) { - case 0: - port += VND_SCONTROL_CH0; - break; - case 1: - port += VND_SCONTROL_CH1; - break; - case 2: - port += VND_SCONTROL_CH2; - break; - case 3: - port += VND_SCONTROL_CH3; - break; - default: - return 0; - } - val = readl (port); - writel (val | SATA_SC_DET_RST, port); - msleep (150); - writel (val & ~SATA_SC_DET_RST, port); - return 0; -} - -int scan_sata (int dev) -{ - /* A bit brain dead, but the code has a legacy */ - switch (dev) { - case 0: - port[0].port_no = 0; - port[0].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH0; - port[0].ioaddr.altstatus_addr = port[0].ioaddr.ctl_addr = - (iobase[5] + VND_TF2_CH0) | ATA_PCI_CTL_OFS; - port[0].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH0; - break; -#if (CONFIG_SYS_SATA_MAX_DEVICE >= 1) - case 1: - port[1].port_no = 0; - port[1].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH1; - port[1].ioaddr.altstatus_addr = port[1].ioaddr.ctl_addr = - (iobase[5] + VND_TF2_CH1) | ATA_PCI_CTL_OFS; - port[1].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH1; - break; -#elif (CONFIG_SYS_SATA_MAX_DEVICE >= 2) - case 2: - port[2].port_no = 0; - port[2].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH2; - port[2].ioaddr.altstatus_addr = port[2].ioaddr.ctl_addr = - (iobase[5] + VND_TF2_CH2) | ATA_PCI_CTL_OFS; - port[2].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH2; - break; -#elif (CONFIG_SYS_SATA_MAX_DEVICE >= 3) - case 3: - port[3].port_no = 0; - port[3].ioaddr.cmd_addr = iobase[5] + VND_TF0_CH3; - port[3].ioaddr.altstatus_addr = port[3].ioaddr.ctl_addr = - (iobase[5] + VND_TF2_CH3) | ATA_PCI_CTL_OFS; - port[3].ioaddr.bmdma_addr = iobase[5] + VND_BMDMA_CH3; - break; -#endif - default: - printf ("Tried to scan unknown port: ata%d\n", dev); - return 1; - } - - /* Initialize other registers */ - sata_port (&port[dev].ioaddr); - - /* Check for attached device */ - if (!sata_bus_probe (dev)) { - port[dev].port_state = 0; - debug ("SATA#%d port is not present\n", dev); - } else { - debug ("SATA#%d port is present\n", dev); - if (sata_bus_softreset (dev)) { - /* soft reset failed, try a hard one */ - sata_phy_reset (dev); - if (sata_bus_softreset (dev)) { - port[dev].port_state = 0; - } else { - port[dev].port_state = 1; - } - } else { - port[dev].port_state = 1; - } - } - if (port[dev].port_state == 1) { - /* Probe device and set xfer mode */ - sata_identify (dev, 0); - set_Feature_cmd (dev, 0); - } - - return 0; -} diff --git a/drivers/block/sata_sil3114.h b/drivers/block/sata_sil3114.h deleted file mode 100644 index 091fca1d40..0000000000 --- a/drivers/block/sata_sil3114.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) Excito Elektronik i Skåne AB, All rights reserved. - * Author: Tor Krill - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef SATA_SIL3114_H -#define SATA_SIL3114_H - -struct sata_ioports { - unsigned long cmd_addr; - unsigned long data_addr; - unsigned long error_addr; - unsigned long feature_addr; - unsigned long nsect_addr; - unsigned long lbal_addr; - unsigned long lbam_addr; - unsigned long lbah_addr; - unsigned long device_addr; - unsigned long status_addr; - unsigned long command_addr; - unsigned long altstatus_addr; - unsigned long ctl_addr; - unsigned long bmdma_addr; - unsigned long scr_addr; -}; - -struct sata_port { - unsigned char port_no; /* primary=0, secondary=1 */ - struct sata_ioports ioaddr; /* ATA cmd/ctl/dma reg blks */ - unsigned char ctl_reg; - unsigned char last_ctl; - unsigned char port_state; /* 1-port is available and */ - /* 0-port is not available */ - unsigned char dev_mask; -}; - -/* Missing ata defines */ -#define ATA_CMD_STANDBY 0xE2 -#define ATA_CMD_STANDBYNOW1 0xE0 -#define ATA_CMD_IDLE 0xE3 -#define ATA_CMD_IDLEIMMEDIATE 0xE1 - -/* Defines for SIL3114 chip */ - -/* PCI defines */ -#define SIL_VEND_ID 0x1095 -#define SIL3114_DEVICE_ID 0x3114 - -/* some vendor specific registers */ -#define VND_SYSCONFSTAT 0x88 /* System Configuration Status and Command */ -#define VND_SYSCONFSTAT_CHN_0_INTBLOCK (1<<22) -#define VND_SYSCONFSTAT_CHN_1_INTBLOCK (1<<23) -#define VND_SYSCONFSTAT_CHN_2_INTBLOCK (1<<24) -#define VND_SYSCONFSTAT_CHN_3_INTBLOCK (1<<25) - -/* internal registers mapped by BAR5 */ -/* SATA Control*/ -#define VND_SCONTROL_CH0 0x100 -#define VND_SCONTROL_CH1 0x180 -#define VND_SCONTROL_CH2 0x300 -#define VND_SCONTROL_CH3 0x380 - -#define SATA_SC_IPM_T2P (1<<16) -#define SATA_SC_IPM_T2S (2<<16) -#define SATA_SC_SPD_1_5 (1<<4) -#define SATA_SC_SPD_3_0 (2<<4) -#define SATA_SC_DET_RST (1) /* ATA Reset sequence */ -#define SATA_SC_DET_PDIS (4) /* PHY Disable */ - -/* SATA Status */ -#define VND_SSTATUS_CH0 0x104 -#define VND_SSTATUS_CH1 0x184 -#define VND_SSTATUS_CH2 0x304 -#define VND_SSTATUS_CH3 0x384 - -#define SATA_SS_IPM_ACTIVE (1<<8) -#define SATA_SS_IPM_PARTIAL (2<<8) -#define SATA_SS_IPM_SLUMBER (6<<8) -#define SATA_SS_SPD_1_5 (1<<4) -#define SATA_SS_SPD_3_0 (2<<4) -#define SATA_DET_P_NOPHY (1) /* Device presence but no PHY connection established */ -#define SATA_DET_PRES (3) /* Device presence and active PHY */ -#define SATA_DET_OFFLINE (4) /* Device offline or in loopback mode */ - -/* Task file registers in BAR5 mapping */ -#define VND_TF0_CH0 0x80 -#define VND_TF0_CH1 0xc0 -#define VND_TF0_CH2 0x280 -#define VND_TF0_CH3 0x2c0 -#define VND_TF1_CH0 0x88 -#define VND_TF1_CH1 0xc8 -#define VND_TF1_CH2 0x288 -#define VND_TF1_CH3 0x2c8 -#define VND_TF2_CH0 0x88 -#define VND_TF2_CH1 0xc8 -#define VND_TF2_CH2 0x288 -#define VND_TF2_CH3 0x2c8 - -#define VND_BMDMA_CH0 0x00 -#define VND_BMDMA_CH1 0x08 -#define VND_BMDMA_CH2 0x200 -#define VND_BMDMA_CH3 0x208 -#define VND_BMDMA2_CH0 0x10 -#define VND_BMDMA2_CH1 0x18 -#define VND_BMDMA2_CH2 0x210 -#define VND_BMDMA2_CH3 0x218 - -/* FIFO control */ -#define VND_FIFOCFG_CH0 0x40 -#define VND_FIFOCFG_CH1 0x44 -#define VND_FIFOCFG_CH2 0x240 -#define VND_FIFOCFG_CH3 0x244 - -/* Task File configuration and status */ -#define VND_TF_CNST_CH0 0xa0 -#define VND_TF_CNST_CH1 0xe0 -#define VND_TF_CNST_CH2 0x2a0 -#define VND_TF_CNST_CH3 0x2e0 - -#define VND_TF_CNST_BFCMD (1<<1) -#define VND_TF_CNST_CHNRST (1<<2) -#define VND_TF_CNST_VDMA (1<<10) -#define VND_TF_CNST_INTST (1<<11) -#define VND_TF_CNST_WDTO (1<<12) -#define VND_TF_CNST_WDEN (1<<13) -#define VND_TF_CNST_WDIEN (1<<14) - -/* for testing */ -#define VND_SSDR 0x04c /* System Software Data Register */ -#define VND_FMACS 0x050 /* Flash Memory Address control and status */ - -#endif -- cgit v1.2.3