Merge branch '2022-05-03-virtio-pci-add-and-fix-consistency-checks'
[platform/kernel/u-boot.git] / drivers / ata / ahci.c
index 333f045..de6131f 100644 (file)
@@ -9,6 +9,11 @@
  * This driver provides a SCSI interface to SATA.
  */
 #include <common.h>
+#include <blk.h>
+#include <cpu_func.h>
+#include <log.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
 
 #include <command.h>
 #include <dm.h>
@@ -50,22 +55,13 @@ struct ahci_uc_priv *probe_ent = NULL;
 #define WAIT_MS_FLUSH  5000
 #define WAIT_MS_LINKUP 200
 
+#define AHCI_CAP_S64A BIT(31)
+
 __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)
@@ -114,7 +110,7 @@ static int waiting_for_cmd_completed(void __iomem *offset,
        return (i < timeout_msec) ? 0 : -1;
 }
 
-int __weak ahci_link_up(struct ahci_uc_priv *uc_priv, u8 port)
+int __weak ahci_link_up(struct ahci_uc_priv *uc_priv, int port)
 {
        u32 tmp;
        int j = 0;
@@ -174,13 +170,8 @@ int ahci_reset(void __iomem *base)
 static int ahci_host_init(struct ahci_uc_priv *uc_priv)
 {
 #if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI)
-# ifdef CONFIG_DM_PCI
        struct udevice *dev = uc_priv->dev;
-       struct pci_child_platdata *pplat = dev_get_parent_platdata(dev);
-# else
-       pci_dev_t pdev = uc_priv->dev;
-       unsigned short vendor;
-# endif
+       struct pci_child_plat *pplat = dev_get_parent_plat(dev);
        u16 tmp16;
 #endif
        void __iomem *mmio = uc_priv->mmio_base;
@@ -204,23 +195,12 @@ static int ahci_host_init(struct ahci_uc_priv *uc_priv)
        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
        uc_priv->cap = readl(mmio + HOST_CAP);
        uc_priv->port_map = readl(mmio + HOST_PORTS_IMPL);
@@ -230,15 +210,16 @@ static int ahci_host_init(struct ahci_uc_priv *uc_priv)
        debug("cap 0x%x  port_map 0x%x  n_ports %d\n",
              uc_priv->cap, uc_priv->port_map, uc_priv->n_ports);
 
+#if !defined(CONFIG_DM_SCSI)
        if (uc_priv->n_ports > CONFIG_SYS_SCSI_MAX_SCSI_ID)
                uc_priv->n_ports = CONFIG_SYS_SCSI_MAX_SCSI_ID;
+#endif
 
        for (i = 0; i < uc_priv->n_ports; i++) {
                if (!(port_map & (1 << i)))
                        continue;
                uc_priv->port[i].port_mmio = ahci_port_base(mmio, i);
                port_mmio = (u8 *)uc_priv->port[i].port_mmio;
-               ahci_setup_port(&uc_priv->port[i], mmio, i);
 
                /* make sure port is not active */
                tmp = readl(port_mmio + PORT_CMD);
@@ -334,15 +315,9 @@ static int ahci_host_init(struct ahci_uc_priv *uc_priv)
        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;
@@ -352,11 +327,7 @@ static int ahci_host_init(struct ahci_uc_priv *uc_priv)
 static void ahci_print_info(struct ahci_uc_priv *uc_priv)
 {
 #if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI)
-# if defined(CONFIG_DM_PCI)
        struct udevice *dev = uc_priv->dev;
-# else
-       pci_dev_t pdev = uc_priv->dev;
-# endif
        u16 cc;
 #endif
        void __iomem *mmio = uc_priv->mmio_base;
@@ -382,11 +353,7 @@ static void ahci_print_info(struct ahci_uc_priv *uc_priv)
 #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)
@@ -431,11 +398,7 @@ static void ahci_print_info(struct ahci_uc_priv *uc_priv)
 }
 
 #if defined(CONFIG_DM_SCSI) || !defined(CONFIG_SCSI_AHCI_PLAT)
-# if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI)
 static int ahci_init_one(struct ahci_uc_priv *uc_priv, struct udevice *dev)
-# else
-static int ahci_init_one(struct ahci_uc_priv *uc_priv, pci_dev_t dev)
-# endif
 {
 #if !defined(CONFIG_DM_SCSI)
        u16 vendor;
@@ -453,9 +416,8 @@ static int ahci_init_one(struct ahci_uc_priv *uc_priv, pci_dev_t dev)
        uc_priv->udma_mask = 0x7f;      /*Fixme,assume to support UDMA6 */
 
 #if !defined(CONFIG_DM_SCSI)
-#ifdef CONFIG_DM_PCI
-       uc_priv->mmio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_5,
-                                             PCI_REGION_MEM);
+       uc_priv->mmio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_5, 0, 0,
+                                           PCI_REGION_TYPE, PCI_REGION_MEM);
 
        /* Take from kernel:
         * JMicron-specific fixup:
@@ -465,19 +427,7 @@ static int ahci_init_one(struct ahci_uc_priv *uc_priv, pci_dev_t dev)
        if (vendor == 0x197b)
                dm_pci_write_config8(dev, 0x41, 0xa1);
 #else
-       uc_priv->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_uclass_platdata(dev);
+       struct scsi_plat *plat = dev_get_uclass_plat(dev);
        uc_priv->mmio_base = (void *)plat->base;
 #endif
 
@@ -503,6 +453,7 @@ static int ahci_fill_sg(struct ahci_uc_priv *uc_priv, u8 port,
 {
        struct ahci_ioports *pp = &(uc_priv->port[port]);
        struct ahci_sg *ahci_sg = pp->cmd_tbl_sg;
+       phys_addr_t pa = virt_to_phys(buf);
        u32 sg_count;
        int i;
 
@@ -513,29 +464,33 @@ static int ahci_fill_sg(struct ahci_uc_priv *uc_priv, u8 port,
        }
 
        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->addr = cpu_to_le32(lower_32_bits(pa));
+               ahci_sg->addr_hi = cpu_to_le32(upper_32_bits(pa));
+               if (ahci_sg->addr_hi && !(uc_priv->cap & AHCI_CAP_S64A)) {
+                       printf("Error: DMA address too high\n");
+                       return -1;
+               }
                ahci_sg->flags_size = cpu_to_le32(0x3fffff &
-                                         (buf_len < MAX_DATA_BYTE_COUNT
-                                          ? (buf_len - 1)
-                                          (MAX_DATA_BYTE_COUNT - 1)));
+                                         (buf_len < MAX_DATA_BYTE_COUNT ?
+                                          (buf_len - 1) :
+                                          (MAX_DATA_BYTE_COUNT - 1)));
                ahci_sg++;
                buf_len -= MAX_DATA_BYTE_COUNT;
+               pa += MAX_DATA_BYTE_COUNT;
        }
 
        return sg_count;
 }
 
-
 static void ahci_fill_cmd_slot(struct ahci_ioports *pp, u32 opts)
 {
+       phys_addr_t pa = virt_to_phys((void *)pp->cmd_tbl);
+
        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);
+       pp->cmd_slot->tbl_addr = cpu_to_le32(lower_32_bits(pa));
 #ifdef CONFIG_PHYS_64BIT
-       pp->cmd_slot->tbl_addr_hi =
-           cpu_to_le32((u32)(((pp->cmd_tbl) >> 16) >> 16));
+       pp->cmd_slot->tbl_addr_hi = cpu_to_le32(upper_32_bits(pa));
 #endif
 }
 
@@ -558,6 +513,7 @@ static int ahci_port_start(struct ahci_uc_priv *uc_priv, u8 port)
 {
        struct ahci_ioports *pp = &(uc_priv->port[port]);
        void __iomem *port_mmio = pp->port_mmio;
+       u64 dma_addr;
        u32 port_status;
        void __iomem *mem;
 
@@ -569,15 +525,12 @@ static int ahci_port_start(struct ahci_uc_priv *uc_priv, u8 port)
                return -1;
        }
 
-       mem = malloc(AHCI_PORT_PRIV_DMA_SZ + 2048);
+       mem = memalign(2048, AHCI_PORT_PRIV_DMA_SZ);
        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);
 
        /*
@@ -606,10 +559,12 @@ static int ahci_port_start(struct ahci_uc_priv *uc_priv, u8 port)
        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);
+       dma_addr = (ulong)pp->cmd_slot;
+       writel_with_flush(dma_addr, port_mmio + PORT_LST_ADDR);
+       writel_with_flush(dma_addr >> 32, port_mmio + PORT_LST_ADDR_HI);
+       dma_addr = (ulong)pp->rx_fis;
+       writel_with_flush(dma_addr, port_mmio + PORT_FIS_ADDR);
+       writel_with_flush(dma_addr >> 32, port_mmio + PORT_FIS_ADDR_HI);
 
 #ifdef CONFIG_SUNXI_AHCI
        sunxi_dma_init(port_mmio);
@@ -671,12 +626,12 @@ static int ahci_device_data_io(struct ahci_uc_priv *uc_priv, u8 port, u8 *fis,
 
        ahci_dcache_invalidate_range((unsigned long)buf,
                                     (unsigned long)buf_len);
-       debug("%s: %d byte transferred.\n", __func__, pp->cmd_slot->status);
+       debug("%s: %d byte transferred.\n", __func__,
+             le32_to_cpu(pp->cmd_slot->status));
 
        return 0;
 }
 
-
 static char *ata_id_strcpy(u16 *target, u16 *src, int len)
 {
        int i;
@@ -1004,7 +959,6 @@ void scsi_low_level_init(int busdevfunc)
                return;
        }
        uc_priv = probe_ent;
-# if defined(CONFIG_DM_PCI)
        struct udevice *dev;
        int ret;
 
@@ -1012,9 +966,6 @@ void scsi_low_level_init(int busdevfunc)
        if (ret)
                return;
        ahci_init_one(uc_priv, dev);
-# else
-       ahci_init_one(uc_priv, busdevfunc);
-# endif
 #else
        uc_priv = probe_ent;
 #endif
@@ -1024,7 +975,6 @@ void scsi_low_level_init(int busdevfunc)
 #endif
 
 #ifndef CONFIG_SCSI_AHCI_PLAT
-# if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI)
 int ahci_init_one_dm(struct udevice *dev)
 {
        struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev);
@@ -1032,7 +982,6 @@ int ahci_init_one_dm(struct udevice *dev)
        return ahci_init_one(uc_priv, dev);
 }
 #endif
-#endif
 
 int ahci_start_ports_dm(struct udevice *dev)
 {
@@ -1160,14 +1109,14 @@ int ahci_bind_scsi(struct udevice *ahci_dev, struct udevice **devp)
 int ahci_probe_scsi(struct udevice *ahci_dev, ulong base)
 {
        struct ahci_uc_priv *uc_priv;
-       struct scsi_platdata *uc_plat;
+       struct scsi_plat *uc_plat;
        struct udevice *dev;
        int ret;
 
        device_find_first_child(ahci_dev, &dev);
        if (!dev)
                return -ENODEV;
-       uc_plat = dev_get_uclass_platdata(dev);
+       uc_plat = dev_get_uclass_plat(dev);
        uc_plat->base = base;
        uc_plat->max_lun = 1;
        uc_plat->max_id = 2;
@@ -1180,20 +1129,45 @@ int ahci_probe_scsi(struct udevice *ahci_dev, ulong base)
        if (ret)
                return ret;
 
+       /*
+        * scsi_scan_dev() scans devices up-to the number of max_id.
+        * Update max_id if the number of detected ports exceeds max_id.
+        * This allows SCSI to scan all detected ports.
+        */
+       uc_plat->max_id = max_t(unsigned long, uc_priv->n_ports,
+                               uc_plat->max_id);
+       /* If port count is less than max_id, update max_id */
+       if (uc_priv->n_ports < uc_plat->max_id)
+               uc_plat->max_id = uc_priv->n_ports;
+
        return 0;
 }
 
-#ifdef CONFIG_DM_PCI
 int ahci_probe_scsi_pci(struct udevice *ahci_dev)
 {
        ulong base;
+       u16 vendor, device;
 
-       base = (ulong)dm_pci_map_bar(ahci_dev, PCI_BASE_ADDRESS_5,
-                                    PCI_REGION_MEM);
+       base = (ulong)dm_pci_map_bar(ahci_dev, PCI_BASE_ADDRESS_5, 0, 0,
+                                    PCI_REGION_TYPE, PCI_REGION_MEM);
 
+       /*
+        * Note:
+        * Right now, we have only one quirk here, which is not enough to
+        * introduce a new Kconfig option to select this. Once we have more
+        * quirks in this AHCI code, we should add a Kconfig option for
+        * this though.
+        */
+       dm_pci_read_config16(ahci_dev, PCI_VENDOR_ID, &vendor);
+       dm_pci_read_config16(ahci_dev, PCI_DEVICE_ID, &device);
+
+       if (vendor == PCI_VENDOR_ID_CAVIUM &&
+           device == PCI_DEVICE_ID_CAVIUM_SATA)
+               base = (uintptr_t)dm_pci_map_bar(ahci_dev, PCI_BASE_ADDRESS_0,
+                                                0, 0, PCI_REGION_TYPE,
+                                                PCI_REGION_MEM);
        return ahci_probe_scsi(ahci_dev, base);
 }
-#endif
 
 struct scsi_ops scsi_ops = {
        .exec           = ahci_scsi_exec,