diff options
author | Suman Tripathi <stripathi@apm.com> | 2015-05-11 04:36:15 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2015-05-11 07:26:48 -0400 |
commit | c9802a4be6611520dd99d91d0d9c4efcaa0fa281 (patch) | |
tree | 1fa844c8d02e752f3a16a9bff3610934c51419d8 /drivers/ata | |
parent | 5903b1643f41ccc0cb3a0cde1d12b1c942914317 (diff) |
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. 2a0bdff6b95 ("ahci-xgene: fix the dma state machine lockup for the
IDENTIFY DEVICE PIO mode command")
2. 09c32aaa368 ("ahci_xgene: Fix the dma state machine lockup for the
ATA_CMD_SMART PIO mode command")
3. 1540035da71 ("ahci_xgene: Implement the xgene_ahci_poll_reg_val to
support PMP")
4. a3a84bc7c88 ("ahci_xgene: Implement the workaround to support PMP
enumeration and discovery")
5. 1102407bb71 ("ahci_xgene: Fix the DMA state machine lockup for the
ATA_CMD_PACKET PIO mode command")
6. 72f79f9e35b ("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: Suman Tripathi <stripathi@apm.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/ahci_xgene.c | 105 |
1 files changed, 86 insertions, 19 deletions
diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index 2b78510d94dd..2add250d1555 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
28 | #include <linux/ahci_platform.h> | 28 | #include <linux/ahci_platform.h> |
29 | #include <linux/of_address.h> | 29 | #include <linux/of_address.h> |
30 | #include <linux/of_device.h> | ||
30 | #include <linux/of_irq.h> | 31 | #include <linux/of_irq.h> |
31 | #include <linux/phy/phy.h> | 32 | #include <linux/phy/phy.h> |
32 | #include "ahci.h" | 33 | #include "ahci.h" |
@@ -84,6 +85,11 @@ | |||
84 | /* Max retry for link down */ | 85 | /* Max retry for link down */ |
85 | #define MAX_LINK_DOWN_RETRY 3 | 86 | #define MAX_LINK_DOWN_RETRY 3 |
86 | 87 | ||
88 | enum xgene_ahci_version { | ||
89 | XGENE_AHCI_V1 = 1, | ||
90 | XGENE_AHCI_V2, | ||
91 | }; | ||
92 | |||
87 | struct xgene_ahci_context { | 93 | struct xgene_ahci_context { |
88 | struct ahci_host_priv *hpriv; | 94 | struct ahci_host_priv *hpriv; |
89 | struct device *dev; | 95 | struct device *dev; |
@@ -542,7 +548,7 @@ softreset_retry: | |||
542 | return rc; | 548 | return rc; |
543 | } | 549 | } |
544 | 550 | ||
545 | static struct ata_port_operations xgene_ahci_ops = { | 551 | static struct ata_port_operations xgene_ahci_v1_ops = { |
546 | .inherits = &ahci_ops, | 552 | .inherits = &ahci_ops, |
547 | .host_stop = xgene_ahci_host_stop, | 553 | .host_stop = xgene_ahci_host_stop, |
548 | .hardreset = xgene_ahci_hardreset, | 554 | .hardreset = xgene_ahci_hardreset, |
@@ -552,11 +558,25 @@ static struct ata_port_operations xgene_ahci_ops = { | |||
552 | .pmp_softreset = xgene_ahci_pmp_softreset | 558 | .pmp_softreset = xgene_ahci_pmp_softreset |
553 | }; | 559 | }; |
554 | 560 | ||
555 | static const struct ata_port_info xgene_ahci_port_info = { | 561 | static const struct ata_port_info xgene_ahci_v1_port_info = { |
556 | .flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP, | 562 | .flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP, |
557 | .pio_mask = ATA_PIO4, | 563 | .pio_mask = ATA_PIO4, |
558 | .udma_mask = ATA_UDMA6, | 564 | .udma_mask = ATA_UDMA6, |
559 | .port_ops = &xgene_ahci_ops, | 565 | .port_ops = &xgene_ahci_v1_ops, |
566 | }; | ||
567 | |||
568 | static struct ata_port_operations xgene_ahci_v2_ops = { | ||
569 | .inherits = &ahci_ops, | ||
570 | .host_stop = xgene_ahci_host_stop, | ||
571 | .hardreset = xgene_ahci_hardreset, | ||
572 | .read_id = xgene_ahci_read_id, | ||
573 | }; | ||
574 | |||
575 | static const struct ata_port_info xgene_ahci_v2_port_info = { | ||
576 | .flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP, | ||
577 | .pio_mask = ATA_PIO4, | ||
578 | .udma_mask = ATA_UDMA6, | ||
579 | .port_ops = &xgene_ahci_v2_ops, | ||
560 | }; | 580 | }; |
561 | 581 | ||
562 | static int xgene_ahci_hw_init(struct ahci_host_priv *hpriv) | 582 | static int xgene_ahci_hw_init(struct ahci_host_priv *hpriv) |
@@ -629,12 +649,32 @@ static struct scsi_host_template ahci_platform_sht = { | |||
629 | AHCI_SHT(DRV_NAME), | 649 | AHCI_SHT(DRV_NAME), |
630 | }; | 650 | }; |
631 | 651 | ||
652 | #ifdef CONFIG_ACPI | ||
653 | static const struct acpi_device_id xgene_ahci_acpi_match[] = { | ||
654 | { "APMC0D0D", XGENE_AHCI_V1}, | ||
655 | { "APMC0D32", XGENE_AHCI_V2}, | ||
656 | {}, | ||
657 | }; | ||
658 | MODULE_DEVICE_TABLE(acpi, xgene_ahci_acpi_match); | ||
659 | #endif | ||
660 | |||
661 | static const struct of_device_id xgene_ahci_of_match[] = { | ||
662 | {.compatible = "apm,xgene-ahci", .data = (void *) XGENE_AHCI_V1}, | ||
663 | {.compatible = "apm,xgene-ahci-v2", .data = (void *) XGENE_AHCI_V2}, | ||
664 | {}, | ||
665 | }; | ||
666 | MODULE_DEVICE_TABLE(of, xgene_ahci_of_match); | ||
667 | |||
632 | static int xgene_ahci_probe(struct platform_device *pdev) | 668 | static int xgene_ahci_probe(struct platform_device *pdev) |
633 | { | 669 | { |
634 | struct device *dev = &pdev->dev; | 670 | struct device *dev = &pdev->dev; |
635 | struct ahci_host_priv *hpriv; | 671 | struct ahci_host_priv *hpriv; |
636 | struct xgene_ahci_context *ctx; | 672 | struct xgene_ahci_context *ctx; |
637 | struct resource *res; | 673 | struct resource *res; |
674 | const struct of_device_id *of_devid; | ||
675 | enum xgene_ahci_version version = XGENE_AHCI_V1; | ||
676 | const struct ata_port_info *ppi[] = { &xgene_ahci_v1_port_info, | ||
677 | &xgene_ahci_v2_port_info }; | ||
638 | int rc; | 678 | int rc; |
639 | 679 | ||
640 | hpriv = ahci_platform_get_resources(pdev); | 680 | hpriv = ahci_platform_get_resources(pdev); |
@@ -677,6 +717,37 @@ static int xgene_ahci_probe(struct platform_device *pdev) | |||
677 | ctx->csr_mux = csr; | 717 | ctx->csr_mux = csr; |
678 | } | 718 | } |
679 | 719 | ||
720 | of_devid = of_match_device(xgene_ahci_of_match, dev); | ||
721 | if (of_devid) { | ||
722 | if (of_devid->data) | ||
723 | version = (enum xgene_ahci_version) of_devid->data; | ||
724 | } | ||
725 | #ifdef CONFIG_ACPI | ||
726 | else { | ||
727 | const struct acpi_device_id *acpi_id; | ||
728 | struct acpi_device_info *info; | ||
729 | acpi_status status; | ||
730 | |||
731 | acpi_id = acpi_match_device(xgene_ahci_acpi_match, &pdev->dev); | ||
732 | if (!acpi_id) { | ||
733 | dev_warn(&pdev->dev, "No node entry in ACPI table. Assume version1\n"); | ||
734 | version = XGENE_AHCI_V1; | ||
735 | } | ||
736 | |||
737 | if (acpi_id->driver_data) { | ||
738 | version = (enum xgene_ahci_version) acpi_id->driver_data; | ||
739 | status = acpi_get_object_info(ACPI_HANDLE(&pdev->dev), &info); | ||
740 | if (ACPI_FAILURE(status)) { | ||
741 | dev_warn(&pdev->dev, "%s: Error reading device info. Assume version1\n", | ||
742 | __func__); | ||
743 | version = XGENE_AHCI_V1; | ||
744 | } | ||
745 | if (info->valid & ACPI_VALID_CID) | ||
746 | version = XGENE_AHCI_V2; | ||
747 | } | ||
748 | } | ||
749 | #endif | ||
750 | |||
680 | dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", ctx->csr_core, | 751 | dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", ctx->csr_core, |
681 | hpriv->mmio); | 752 | hpriv->mmio); |
682 | 753 | ||
@@ -704,9 +775,19 @@ static int xgene_ahci_probe(struct platform_device *pdev) | |||
704 | /* Configure the host controller */ | 775 | /* Configure the host controller */ |
705 | xgene_ahci_hw_init(hpriv); | 776 | xgene_ahci_hw_init(hpriv); |
706 | skip_clk_phy: | 777 | skip_clk_phy: |
707 | hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_NCQ; | ||
708 | 778 | ||
709 | rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info, | 779 | switch (version) { |
780 | case XGENE_AHCI_V1: | ||
781 | hpriv->flags = AHCI_HFLAG_NO_NCQ; | ||
782 | break; | ||
783 | case XGENE_AHCI_V2: | ||
784 | hpriv->flags |= AHCI_HFLAG_YES_FBS | AHCI_HFLAG_EDGE_IRQ; | ||
785 | break; | ||
786 | default: | ||
787 | break; | ||
788 | } | ||
789 | |||
790 | rc = ahci_platform_init_host(pdev, hpriv, ppi[version - 1], | ||
710 | &ahci_platform_sht); | 791 | &ahci_platform_sht); |
711 | if (rc) | 792 | if (rc) |
712 | goto disable_resources; | 793 | goto disable_resources; |
@@ -719,20 +800,6 @@ disable_resources: | |||
719 | return rc; | 800 | return rc; |
720 | } | 801 | } |
721 | 802 | ||
722 | #ifdef CONFIG_ACPI | ||
723 | static const struct acpi_device_id xgene_ahci_acpi_match[] = { | ||
724 | { "APMC0D0D", }, | ||
725 | { } | ||
726 | }; | ||
727 | MODULE_DEVICE_TABLE(acpi, xgene_ahci_acpi_match); | ||
728 | #endif | ||
729 | |||
730 | static const struct of_device_id xgene_ahci_of_match[] = { | ||
731 | {.compatible = "apm,xgene-ahci"}, | ||
732 | {}, | ||
733 | }; | ||
734 | MODULE_DEVICE_TABLE(of, xgene_ahci_of_match); | ||
735 | |||
736 | static struct platform_driver xgene_ahci_driver = { | 803 | static struct platform_driver xgene_ahci_driver = { |
737 | .probe = xgene_ahci_probe, | 804 | .probe = xgene_ahci_probe, |
738 | .remove = ata_platform_remove_one, | 805 | .remove = ata_platform_remove_one, |