#include <asm/io.h>
#include <malloc.h>
#include <memalign.h>
+#include <pci.h>
#include <scsi.h>
#include <libata.h>
#include <linux/ctype.h>
#include <ahci.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
static int ata_io_flush(struct ahci_uc_priv *uc_priv, u8 port);
+#ifndef CONFIG_DM_SCSI
struct ahci_uc_priv *probe_ent = NULL;
+#endif
#define writel_with_flush(a,b) do { writel(a,b); readl(b); } while (0)
cap2 & (1 << 0) ? "boh " : "");
}
-#ifndef CONFIG_SCSI_AHCI_PLAT
+#if defined(CONFIG_DM_SCSI) || !defined(CONFIG_SCSI_AHCI_PLAT)
# if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI)
-static int ahci_init_one(struct udevice *dev)
+static int ahci_init_one(struct ahci_uc_priv *uc_priv, struct udevice *dev)
# else
-static int ahci_init_one(pci_dev_t dev)
+static int ahci_init_one(struct ahci_uc_priv *uc_priv, pci_dev_t dev)
# endif
{
- struct ahci_uc_priv *uc_priv;
#if !defined(CONFIG_DM_SCSI)
u16 vendor;
#endif
int rc;
- probe_ent = malloc(sizeof(struct ahci_uc_priv));
- if (!probe_ent) {
- printf("%s: No memory for uc_priv\n", __func__);
- return -ENOMEM;
- }
-
- uc_priv = probe_ent;
- memset(uc_priv, 0, sizeof(struct ahci_uc_priv));
uc_priv->dev = dev;
uc_priv->host_flags = ATA_FLAG_SATA
}
-int scsi_exec(struct scsi_cmd *pccb)
+static int ahci_scsi_exec(struct udevice *dev, struct scsi_cmd *pccb)
{
- struct ahci_uc_priv *uc_priv = probe_ent;
+ struct ahci_uc_priv *uc_priv;
+#ifdef CONFIG_DM_SCSI
+ uc_priv = dev_get_uclass_priv(dev->parent);
+#else
+ uc_priv = probe_ent;
+#endif
int ret;
switch (pccb->cmd[0]) {
break;
default:
printf("Unsupport SCSI command 0x%02x\n", pccb->cmd[0]);
- return false;
+ return -ENOTSUPP;
}
if (ret) {
debug("SCSI command 0x%02x ret errno %d\n", pccb->cmd[0], ret);
- return false;
+ return ret;
}
- return true;
+ return 0;
}
struct ahci_uc_priv *uc_priv;
#ifndef CONFIG_SCSI_AHCI_PLAT
+ probe_ent = calloc(1, sizeof(struct ahci_uc_priv));
+ if (!probe_ent) {
+ printf("%s: No memory for uc_priv\n", __func__);
+ return;
+ }
+ uc_priv = probe_ent;
# if defined(CONFIG_DM_PCI)
struct udevice *dev;
int ret;
ret = dm_pci_bus_find_bdf(busdevfunc, &dev);
if (ret)
return;
- ahci_init_one(dev);
+ ahci_init_one(uc_priv, dev);
# else
- ahci_init_one(busdevfunc);
+ ahci_init_one(uc_priv, busdevfunc);
# endif
-#endif
+#else
uc_priv = probe_ent;
+#endif
ahci_start_ports(uc_priv);
}
# if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI)
int achi_init_one_dm(struct udevice *dev)
{
- return ahci_init_one(dev);
+ struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ return ahci_init_one(uc_priv, dev);
}
#endif
#endif
int achi_start_ports_dm(struct udevice *dev)
{
- struct ahci_uc_priv *uc_priv = probe_ent;
+ struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev);
return ahci_start_ports(uc_priv);
}
#ifdef CONFIG_SCSI_AHCI_PLAT
-int ahci_init(void __iomem *base)
+static int ahci_init_common(struct ahci_uc_priv *uc_priv, void __iomem *base)
{
- struct ahci_uc_priv *uc_priv;
- int rc = 0;
-
- probe_ent = malloc(sizeof(struct ahci_uc_priv));
- if (!probe_ent) {
- printf("%s: No memory for uc_priv\n", __func__);
- return -ENOMEM;
- }
-
- uc_priv = probe_ent;
- memset(uc_priv, 0, sizeof(struct ahci_uc_priv));
+ int rc;
uc_priv->host_flags = ATA_FLAG_SATA
| ATA_FLAG_NO_LEGACY
return rc;
}
+#ifndef CONFIG_DM_SCSI
+int ahci_init(void __iomem *base)
+{
+ struct ahci_uc_priv *uc_priv;
+
+ probe_ent = malloc(sizeof(struct ahci_uc_priv));
+ if (!probe_ent) {
+ printf("%s: No memory for uc_priv\n", __func__);
+ return -ENOMEM;
+ }
+
+ uc_priv = probe_ent;
+ memset(uc_priv, 0, sizeof(struct ahci_uc_priv));
+
+ return ahci_init_common(uc_priv, base);
+}
+#endif
+
+int ahci_init_dm(struct udevice *dev, void __iomem *base)
+{
+ struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ return ahci_init_common(uc_priv, base);
+}
+
void __weak scsi_init(void)
{
}
-#endif
+#endif /* CONFIG_SCSI_AHCI_PLAT */
/*
* In the general case of generic rotating media it makes sense to have a
return 0;
}
+static int ahci_scsi_bus_reset(struct udevice *dev)
+{
+ /* Not implemented */
+
+ return 0;
+}
+
+#ifdef CONFIG_DM_SCSI
+int ahci_bind_scsi(struct udevice *ahci_dev, struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret;
+
+ ret = device_bind_driver(ahci_dev, "ahci_scsi", "ahci_scsi", &dev);
+ if (ret)
+ return ret;
+ *devp = dev;
+
+ return 0;
+}
+
+int ahci_probe_scsi(struct udevice *ahci_dev, ulong base)
+{
+ struct ahci_uc_priv *uc_priv;
+ struct scsi_platdata *uc_plat;
+ struct udevice *dev;
+ int ret;
+
+ device_find_first_child(ahci_dev, &dev);
+ if (!dev)
+ return -ENODEV;
+ uc_plat = dev_get_uclass_platdata(dev);
+ uc_plat->base = base;
+ uc_plat->max_lun = 1;
+ uc_plat->max_id = 2;
+
+ uc_priv = dev_get_uclass_priv(ahci_dev);
+ ret = ahci_init_one(uc_priv, dev);
+ if (ret)
+ return ret;
+ ret = ahci_start_ports(uc_priv);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+#ifdef CONFIG_DM_PCI
+int ahci_probe_scsi_pci(struct udevice *ahci_dev)
+{
+ ulong base;
+
+ base = (ulong)dm_pci_map_bar(ahci_dev, PCI_BASE_ADDRESS_5,
+ PCI_REGION_MEM);
+
+ return ahci_probe_scsi(ahci_dev, base);
+}
+#endif
+
+struct scsi_ops scsi_ops = {
+ .exec = ahci_scsi_exec,
+ .bus_reset = ahci_scsi_bus_reset,
+};
-__weak void scsi_bus_reset(void)
+U_BOOT_DRIVER(ahci_scsi) = {
+ .name = "ahci_scsi",
+ .id = UCLASS_SCSI,
+ .ops = &scsi_ops,
+};
+#else
+int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb)
{
- /*Not implement*/
+ return ahci_scsi_exec(dev, pccb);
}
+
+__weak int scsi_bus_reset(struct udevice *dev)
+{
+ return ahci_scsi_bus_reset(dev);
+
+ return 0;
+}
+#endif