Commit c9802a4b authored by Suman Tripathi's avatar Suman Tripathi Committed by Tejun Heo

ata: ahci_xgene: Add AHCI Support for 2nd HW version of APM X-Gene SoC AHCI SATA Host controller.

This patch enables full AHCI feature support for APM X-Gene SoC SATA
host controller. The following errata's are removed:

1. 2a0bdff6 ("ahci-xgene: fix the dma state machine lockup for the
                 IDENTIFY DEVICE PIO mode command")
2. 09c32aaa ("ahci_xgene: Fix the dma state machine lockup for the
                 ATA_CMD_SMART PIO mode command")
3. 1540035d ("ahci_xgene: Implement the xgene_ahci_poll_reg_val to
                 support PMP")
4. a3a84bc7 ("ahci_xgene: Implement the workaround to support PMP
                 enumeration and discovery")
5. 1102407b ("ahci_xgene: Fix the DMA state machine lockup for the
                 ATA_CMD_PACKET PIO mode command")
6. 72f79f9e ("ahci_xgene: Removing NCQ support from the APM X-Gene
		SoC AHCI SATA Host Controller driver")

In addition, enable PMP support for APM X-Gene SoC and enable FBS
support for second generation APM X-Gene SoC.
Signed-off-by: default avatarSuman Tripathi <stripathi@apm.com>
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
parent 5903b164
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/ahci_platform.h> #include <linux/ahci_platform.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include "ahci.h" #include "ahci.h"
...@@ -84,6 +85,11 @@ ...@@ -84,6 +85,11 @@
/* Max retry for link down */ /* Max retry for link down */
#define MAX_LINK_DOWN_RETRY 3 #define MAX_LINK_DOWN_RETRY 3
enum xgene_ahci_version {
XGENE_AHCI_V1 = 1,
XGENE_AHCI_V2,
};
struct xgene_ahci_context { struct xgene_ahci_context {
struct ahci_host_priv *hpriv; struct ahci_host_priv *hpriv;
struct device *dev; struct device *dev;
...@@ -542,7 +548,7 @@ static int xgene_ahci_softreset(struct ata_link *link, unsigned int *class, ...@@ -542,7 +548,7 @@ static int xgene_ahci_softreset(struct ata_link *link, unsigned int *class,
return rc; return rc;
} }
static struct ata_port_operations xgene_ahci_ops = { static struct ata_port_operations xgene_ahci_v1_ops = {
.inherits = &ahci_ops, .inherits = &ahci_ops,
.host_stop = xgene_ahci_host_stop, .host_stop = xgene_ahci_host_stop,
.hardreset = xgene_ahci_hardreset, .hardreset = xgene_ahci_hardreset,
...@@ -552,11 +558,25 @@ static struct ata_port_operations xgene_ahci_ops = { ...@@ -552,11 +558,25 @@ static struct ata_port_operations xgene_ahci_ops = {
.pmp_softreset = xgene_ahci_pmp_softreset .pmp_softreset = xgene_ahci_pmp_softreset
}; };
static const struct ata_port_info xgene_ahci_port_info = { static const struct ata_port_info xgene_ahci_v1_port_info = {
.flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP, .flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP,
.pio_mask = ATA_PIO4, .pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6, .udma_mask = ATA_UDMA6,
.port_ops = &xgene_ahci_ops, .port_ops = &xgene_ahci_v1_ops,
};
static struct ata_port_operations xgene_ahci_v2_ops = {
.inherits = &ahci_ops,
.host_stop = xgene_ahci_host_stop,
.hardreset = xgene_ahci_hardreset,
.read_id = xgene_ahci_read_id,
};
static const struct ata_port_info xgene_ahci_v2_port_info = {
.flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &xgene_ahci_v2_ops,
}; };
static int xgene_ahci_hw_init(struct ahci_host_priv *hpriv) static int xgene_ahci_hw_init(struct ahci_host_priv *hpriv)
...@@ -629,12 +649,32 @@ static struct scsi_host_template ahci_platform_sht = { ...@@ -629,12 +649,32 @@ static struct scsi_host_template ahci_platform_sht = {
AHCI_SHT(DRV_NAME), AHCI_SHT(DRV_NAME),
}; };
#ifdef CONFIG_ACPI
static const struct acpi_device_id xgene_ahci_acpi_match[] = {
{ "APMC0D0D", XGENE_AHCI_V1},
{ "APMC0D32", XGENE_AHCI_V2},
{},
};
MODULE_DEVICE_TABLE(acpi, xgene_ahci_acpi_match);
#endif
static const struct of_device_id xgene_ahci_of_match[] = {
{.compatible = "apm,xgene-ahci", .data = (void *) XGENE_AHCI_V1},
{.compatible = "apm,xgene-ahci-v2", .data = (void *) XGENE_AHCI_V2},
{},
};
MODULE_DEVICE_TABLE(of, xgene_ahci_of_match);
static int xgene_ahci_probe(struct platform_device *pdev) static int xgene_ahci_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct ahci_host_priv *hpriv; struct ahci_host_priv *hpriv;
struct xgene_ahci_context *ctx; struct xgene_ahci_context *ctx;
struct resource *res; struct resource *res;
const struct of_device_id *of_devid;
enum xgene_ahci_version version = XGENE_AHCI_V1;
const struct ata_port_info *ppi[] = { &xgene_ahci_v1_port_info,
&xgene_ahci_v2_port_info };
int rc; int rc;
hpriv = ahci_platform_get_resources(pdev); hpriv = ahci_platform_get_resources(pdev);
...@@ -677,6 +717,37 @@ static int xgene_ahci_probe(struct platform_device *pdev) ...@@ -677,6 +717,37 @@ static int xgene_ahci_probe(struct platform_device *pdev)
ctx->csr_mux = csr; ctx->csr_mux = csr;
} }
of_devid = of_match_device(xgene_ahci_of_match, dev);
if (of_devid) {
if (of_devid->data)
version = (enum xgene_ahci_version) of_devid->data;
}
#ifdef CONFIG_ACPI
else {
const struct acpi_device_id *acpi_id;
struct acpi_device_info *info;
acpi_status status;
acpi_id = acpi_match_device(xgene_ahci_acpi_match, &pdev->dev);
if (!acpi_id) {
dev_warn(&pdev->dev, "No node entry in ACPI table. Assume version1\n");
version = XGENE_AHCI_V1;
}
if (acpi_id->driver_data) {
version = (enum xgene_ahci_version) acpi_id->driver_data;
status = acpi_get_object_info(ACPI_HANDLE(&pdev->dev), &info);
if (ACPI_FAILURE(status)) {
dev_warn(&pdev->dev, "%s: Error reading device info. Assume version1\n",
__func__);
version = XGENE_AHCI_V1;
}
if (info->valid & ACPI_VALID_CID)
version = XGENE_AHCI_V2;
}
}
#endif
dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", ctx->csr_core, dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", ctx->csr_core,
hpriv->mmio); hpriv->mmio);
...@@ -704,9 +775,19 @@ static int xgene_ahci_probe(struct platform_device *pdev) ...@@ -704,9 +775,19 @@ static int xgene_ahci_probe(struct platform_device *pdev)
/* Configure the host controller */ /* Configure the host controller */
xgene_ahci_hw_init(hpriv); xgene_ahci_hw_init(hpriv);
skip_clk_phy: skip_clk_phy:
hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_NCQ;
rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info, switch (version) {
case XGENE_AHCI_V1:
hpriv->flags = AHCI_HFLAG_NO_NCQ;
break;
case XGENE_AHCI_V2:
hpriv->flags |= AHCI_HFLAG_YES_FBS | AHCI_HFLAG_EDGE_IRQ;
break;
default:
break;
}
rc = ahci_platform_init_host(pdev, hpriv, ppi[version - 1],
&ahci_platform_sht); &ahci_platform_sht);
if (rc) if (rc)
goto disable_resources; goto disable_resources;
...@@ -719,20 +800,6 @@ static int xgene_ahci_probe(struct platform_device *pdev) ...@@ -719,20 +800,6 @@ static int xgene_ahci_probe(struct platform_device *pdev)
return rc; return rc;
} }
#ifdef CONFIG_ACPI
static const struct acpi_device_id xgene_ahci_acpi_match[] = {
{ "APMC0D0D", },
{ }
};
MODULE_DEVICE_TABLE(acpi, xgene_ahci_acpi_match);
#endif
static const struct of_device_id xgene_ahci_of_match[] = {
{.compatible = "apm,xgene-ahci"},
{},
};
MODULE_DEVICE_TABLE(of, xgene_ahci_of_match);
static struct platform_driver xgene_ahci_driver = { static struct platform_driver xgene_ahci_driver = {
.probe = xgene_ahci_probe, .probe = xgene_ahci_probe,
.remove = ata_platform_remove_one, .remove = ata_platform_remove_one,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment