Skip to content

Commit

Permalink
ata: ahci_mvebu: new driver for Marvell Armada 380 AHCI interfaces
Browse files Browse the repository at this point in the history
The Marvell Armada 380 SoC includes two AHCI compatible
interfaces. However, like all DMA-capable Marvell interface, they
require special handling to configure MBus windows. Therefore, this
commit adds a new ahci_mvebu driver, which relies on the
libahci_platform.c code recently introduced.

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Acked-by: Jason Cooper <jason@lakedaemon.net>
Signed-off-by: Tejun Heo <tj@kernel.org>
  • Loading branch information
Thomas Petazzoni authored and Tejun Heo committed May 4, 2014
1 parent 5799d6d commit a3464ed
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 0 deletions.
1 change: 1 addition & 0 deletions Documentation/devicetree/bindings/ata/ahci-platform.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Required properties:
- "fsl,imx53-ahci"
- "fsl,imx6q-ahci"
- "ibm,476gtr-ahci"
- "marvell,armada-380-ahci"
- "snps,dwc-ahci"
- "snps,exynos5440-ahci"
- "snps,spear-ahci"
Expand Down
9 changes: 9 additions & 0 deletions drivers/ata/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,15 @@ config AHCI_IMX

If unsure, say N.

config AHCI_MVEBU
tristate "Marvell EBU AHCI SATA support"
depends on ARCH_MVEBU
help
This option enables support for the Marvebu EBU SoC's
onboard AHCI SATA.

If unsure, say N.

config AHCI_SUNXI
tristate "Allwinner sunxi AHCI SATA support"
depends on ARCH_SUNXI
Expand Down
1 change: 1 addition & 0 deletions drivers/ata/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o
obj-$(CONFIG_AHCI_DA850) += ahci_da850.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_ST) += ahci_st.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_XGENE) += ahci_xgene.o libahci.o libahci_platform.o
Expand Down
127 changes: 127 additions & 0 deletions drivers/ata/ahci_mvebu.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* AHCI glue platform driver for Marvell EBU SOCs
*
* Copyright (C) 2014 Marvell
*
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
* Marcin Wojtas <mw@semihalf.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/

#include <linux/ahci_platform.h>
#include <linux/kernel.h>
#include <linux/mbus.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include "ahci.h"

#define AHCI_VENDOR_SPECIFIC_0_ADDR 0xa0
#define AHCI_VENDOR_SPECIFIC_0_DATA 0xa4

#define AHCI_WINDOW_CTRL(win) (0x60 + ((win) << 4))
#define AHCI_WINDOW_BASE(win) (0x64 + ((win) << 4))
#define AHCI_WINDOW_SIZE(win) (0x68 + ((win) << 4))

static void ahci_mvebu_mbus_config(struct ahci_host_priv *hpriv,
const struct mbus_dram_target_info *dram)
{
int i;

for (i = 0; i < 4; i++) {
writel(0, hpriv->mmio + AHCI_WINDOW_CTRL(i));
writel(0, hpriv->mmio + AHCI_WINDOW_BASE(i));
writel(0, hpriv->mmio + AHCI_WINDOW_SIZE(i));
}

for (i = 0; i < dram->num_cs; i++) {
const struct mbus_dram_window *cs = dram->cs + i;

writel((cs->mbus_attr << 8) |
(dram->mbus_dram_target_id << 4) | 1,
hpriv->mmio + AHCI_WINDOW_CTRL(i));
writel(cs->base, hpriv->mmio + AHCI_WINDOW_BASE(i));
writel(((cs->size - 1) & 0xffff0000),
hpriv->mmio + AHCI_WINDOW_SIZE(i));
}
}

static void ahci_mvebu_regret_option(struct ahci_host_priv *hpriv)
{
/*
* Enable the regret bit to allow the SATA unit to regret a
* request that didn't receive an acknowlegde and avoid a
* deadlock
*/
writel(0x4, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_ADDR);
writel(0x80, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_DATA);
}

static const struct ata_port_info ahci_mvebu_port_info = {
.flags = AHCI_FLAG_COMMON,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_platform_ops,
};

static int ahci_mvebu_probe(struct platform_device *pdev)
{
struct ahci_host_priv *hpriv;
const struct mbus_dram_target_info *dram;
int rc;

hpriv = ahci_platform_get_resources(pdev);
if (IS_ERR(hpriv))
return PTR_ERR(hpriv);

rc = ahci_platform_enable_resources(hpriv);
if (rc)
return rc;

dram = mv_mbus_dram_info();
if (!dram)
return -ENODEV;

ahci_mvebu_mbus_config(hpriv, dram);
ahci_mvebu_regret_option(hpriv);

rc = ahci_platform_init_host(pdev, hpriv, &ahci_mvebu_port_info, 0, 0);
if (rc)
goto disable_resources;

return 0;

disable_resources:
ahci_platform_disable_resources(hpriv);
return rc;
}

static const struct of_device_id ahci_mvebu_of_match[] = {
{ .compatible = "marvell,armada-380-ahci", },
{ },
};
MODULE_DEVICE_TABLE(of, ahci_mvebu_of_match);

/*
* We currently don't provide power management related operations,
* since there is no suspend/resume support at the platform level for
* Armada 38x for the moment.
*/
static struct platform_driver ahci_mvebu_driver = {
.probe = ahci_mvebu_probe,
.remove = ata_platform_remove_one,
.driver = {
.name = "ahci-mvebu",
.owner = THIS_MODULE,
.of_match_table = ahci_mvebu_of_match,
},
};
module_platform_driver(ahci_mvebu_driver);

MODULE_DESCRIPTION("Marvell EBU AHCI SATA driver");
MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>, Marcin Wojtas <mw@semihalf.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:ahci_mvebu");

0 comments on commit a3464ed

Please sign in to comment.