diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 7850e4a..0234c66 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -42,6 +42,11 @@ depends on DISK_AHCI bool "i.MX AHCI support" +config DISK_SATA_MV + depends on ARCH_MVEBU + select DISK_IDE_SFF + bool "Marvell SATA support" + comment "interface types" config DISK_INTF_PLATFORM_IDE diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index c444c4d..6b83ae2 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_DISK_ATA) += disk_ata_drive.o obj-$(CONFIG_DISK_AHCI) += ahci.o obj-$(CONFIG_DISK_AHCI_IMX) += sata-imx.o +obj-$(CONFIG_DISK_SATA_MV) += sata_mv.o # interface types diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c new file mode 100644 index 0000000..22b29d0 --- /dev/null +++ b/drivers/ata/sata_mv.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include + +#include + +/* This can/should be moved to a more generic place */ +static void ata_ioports_init(struct ata_ioports *io, + void *base_data, void *base_reg, void *base_alt, + unsigned stride) +{ + /* io->cmd_addr is unused */; + io->data_addr = base_data; + io->error_addr = base_reg + 1 * stride; + /* io->feature_addr is unused */ + io->nsect_addr = base_reg + 2 * stride; + io->lbal_addr = base_reg + 3 * stride; + io->lbam_addr = base_reg + 4 * stride; + io->lbah_addr = base_reg + 5 * stride; + io->device_addr = base_reg + 6 * stride; + io->status_addr = base_reg + 7 * stride; + io->command_addr = base_reg + 7 * stride; + /* io->altstatus_addr is unused */ + + if (base_alt) + io->ctl_addr = base_alt; + else + io->ctl_addr = io->status_addr; + + /* io->alt_dev_addr is unused */ +} + +#define REG_WINDOW_CONTROL(n) ((n) * 0x10 + 0x30) +#define REG_WINDOW_BASE(n) ((n) * 0x10 + 0x34) + +#define REG_EDMA_COMMAND(n) ((n) * 0x2000 + 0x2028) +#define REG_EDMA_COMMAND__EATARST 0x00000004 + +#define REG_ATA_BASE 0x2100 +#define REG_SSTATUS(n) ((n) * 0x2000 + 0x2300) +#define REG_SCONTROL(n) ((n) * 0x2000 + 0x2308) +#define REG_SCONTROL__DET 0x0000000f +#define REG_SCONTROL__DET__INIT 0x00000001 +#define REG_SCONTROL__DET__PHYOK 0x00000002 +#define REG_SCONTROL__IPM 0x00000f00 +#define REG_SCONTROL__IPM__PARTIAL 0x00000100 +#define REG_SCONTROL__IPM__SLUMBER 0x00000200 + +static int mv_sata_probe(struct device_d *dev) +{ + struct resource *iores; + void __iomem *base; + struct ide_port *ide; + u32 scontrol; + int ret, i; + + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) { + dev_err(dev, "Failed to request mem resources\n"); + return PTR_ERR(iores); + } + base = IOMEM(iores->start); + + /* disable MBus windows */ + for (i = 0; i < 4; ++i) { + writel(0, base + REG_WINDOW_CONTROL(i)); + writel(0, base + REG_WINDOW_BASE(i)); + } + + /* enable first window */ + writel(0x7fff0e01, base + REG_WINDOW_CONTROL(0)); + writel(0, base + REG_WINDOW_BASE(0)); + + writel(REG_EDMA_COMMAND__EATARST, base + REG_EDMA_COMMAND(0)); + udelay(25); + writel(0x0, base + REG_EDMA_COMMAND(0)); + + scontrol = readl(base + REG_SCONTROL(0)); + scontrol &= ~(REG_SCONTROL__DET | REG_SCONTROL__IPM); + /* disable power management */ + scontrol |= REG_SCONTROL__IPM__PARTIAL | REG_SCONTROL__IPM__SLUMBER; + + /* perform interface communication initialization */ + writel(scontrol | REG_SCONTROL__DET__INIT, base + REG_SCONTROL(0)); + writel(scontrol, base + REG_SCONTROL(0)); + + ret = wait_on_timeout(10 * MSECOND, + (readl(base + REG_SSTATUS(0)) & REG_SCONTROL__DET) == (REG_SCONTROL__DET__INIT | REG_SCONTROL__DET__PHYOK)); + if (ret) { + dev_err(dev, "Failed to wait for phy (sstatus=0x%08x)\n", + readl(base + REG_SSTATUS(0))); + return ret; + } + + ide = xzalloc(sizeof(*ide)); + + ide->port.dev = dev; + + ata_ioports_init(&ide->io, base + REG_ATA_BASE, base + REG_ATA_BASE, + NULL, 4); + + dev->priv = ide; + + ret = ide_port_register(ide); + if (ret) + free(ide); + + return ret; +} + +static const struct of_device_id mv_sata_dt_ids[] = { + { + .compatible = "marvell,armada-370-sata", + }, { + /* sentinel */ + } +}; + +static struct driver_d mv_sata_driver = { + .name = "mv_sata", + .probe = mv_sata_probe, + .of_compatible = mv_sata_dt_ids, +}; +device_platform_driver(mv_sata_driver);