* [PATCH v12 0/3] ata: Add APM X-Gene SoC AHCI SATA host controller support
@ 2014-02-21 17:47 Loc Ho
[not found] ` <1393004853-25994-1-git-send-email-lho-qTEPVZfXA3Y@public.gmane.org>
0 siblings, 1 reply; 6+ messages in thread
From: Loc Ho @ 2014-02-21 17:47 UTC (permalink / raw)
To: olof, tj, arnd
Cc: linux-scsi, linux-ide, devicetree, linux-arm-kernel, ddutile, jcm,
patches, Loc Ho, Tuan Phan, Suman Tripathi
This patch adds support for the APM X-Gene SoC AHCI SATA host controller. In
order for the host controller to work, the corresponding PHY driver
musts also be available.
v12:
* Remove function xgene_ahci_get_channel and use the ata_port field port_no
* Update comment for function xgene_ahci_read_id to function comment style
'/**'
* Update comment for multiple lines to fully-winged style
v11:
* Drop the export functions requirement with libachi
* Change CONFIG_SATA_XGENE to CONFIG_AHCI_XGENE
* Rename file sata_xgene.c to ahci_xgene.c
* Convert to use Hans De Geode version 5 ahci_platform code re-factor changes
to reduce code duplication. For extra context, use plat_data to store our
context. The probe function follows the ahci_sunxi implementation. A number
of code fragments update to reflect this change.
* Update comment for function xgene_ahci_read_id
* Minor code move around in function xgene_ahci_do_hardreset and use
ATA_BUSY instead 0x80
* Fix hardreset to use start_engine function pointer as required due to newer
kernel rebased
* Fix the set DMA mask for 32-bit as well
v10:
* Update binding documentation
v9:
* Remove ACPI/EFI include files
* Remove the IO flush support, interrupt routine, and DTS resources
* Remove function xgene_rd, xgene_wr, and xgene_wr_flush
* Remove PMP support (function xgene_ahci_qc_issue, xgene_ahci_qc_prep,
xgene_ahci_qc_fill_rtf, xgene_ahci_softreset, and xgene_ahci_do_softreset)
* Rename function xgene_ahci_enable_phy to xgene_ahci_force_phy_rdy
* Clean up hardreset functions
* Require v7 of the PHY driver
v8:
* Remove _ADDR from defines
* Remove define MSTAWAUX_COHERENT_BYPASS_SET and
STARAUX_COHERENT_BYPASS_SET and use direct coding
* Remove the un-necessary check for DTS boot with built in ACPI table
* Switch to use dma_set_mask_and_coherent for setting DMA mask
* Remove ACPI table matching code
* Update clock-names for sata01clk, sata23clk, and sata45clk
v7:
* Update the clock code by toggle the clock
* Update the DTS clock mask values due to the clock spilt between host and
v5 of the PHY drivers
v6:
* Update binding documentation
* Change select PHY_XGENE_SATA to PHY_XGENE
* Add ULL to constants
* Change indentation and comments
* Clean up the probe functions a bit more
* Remove xgene_ahci_remove function
* Add the flush register to DTS
* Remove the interrupt-parent from DTS
v5:
* Sync up to v3 of the PHY driver
* Remove MSLIM wrapper functions
* Change the memory shutdown loop to use usleep_range
* Use devm_ioremap_resource instead devm_ioremap
* Remove suspend/resume functions as not needed
v4:
* Remove the ID property in DT
* Remove the temporary PHY direct function call and use PHY function
* Change printk to pr_debug
* Move the IOB flush addresses into the DT
* Remove the parameters retrieval function as no longer needed
* Remove the header file as no longer needed
* Require v2 patch of the SATA PHY driver. Require slightly modification
in the Kconfig as it is moved to folder driver/phy and use Kconfig
PHY_XGENE_SATA instead SATA_XGENE_PHY.
v3:
* Move out the SATA PHY to another driver
* Remove the clock-cells entry from DTS
* Remove debug wrapper
* Remove delay functions wrapper
* Clean up resource and IRQ query
* Remove query clock name
* Switch to use dma_set_mask/dma_coherent_mask
* Remove un-necessary devm_kfree
* Update GPL license header to v2
* Spilt up function xgene_ahci_hardreset
* Spilt up function xgene_ahci_probe
* Remove all reference of CONFIG_ARCH_MSLIM
* Clean up chip revision code
v2:
* Clean up file sata_xgene.c with Lindent and etc
* Clean up file sata_xgene_serdes.c with Lindent and etc
* Add description to each patch
v1:
* inital version
Signed-off-by: Loc Ho <lho@apm.com>
Signed-off-by: Tuan Phan <tphan@apm.com>
Signed-off-by: Suman Tripathi <stripathi@apm.com>
---
Loc Ho (3):
Documentation: Add documentation for APM X-Gene SoC SATA host
controller DTS binding
ata: Add APM X-Gene SoC AHCI SATA host controller driver
arm64: Add APM X-Gene SoC AHCI SATA host controller DTS entries
.../devicetree/bindings/ata/apm-xgene.txt | 70 +++
arch/arm64/boot/dts/apm-storm.dtsi | 75 +++
drivers/ata/Kconfig | 8 +
drivers/ata/Makefile | 1 +
drivers/ata/ahci_xgene.c | 540 ++++++++++++++++++++
5 files changed, 694 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/ata/apm-xgene.txt
create mode 100644 drivers/ata/ahci_xgene.c
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v12 1/3] Documentation: Add documentation for APM X-Gene SoC SATA host controller DTS binding
[not found] ` <1393004853-25994-1-git-send-email-lho-qTEPVZfXA3Y@public.gmane.org>
@ 2014-02-21 17:47 ` Loc Ho
2014-02-21 17:47 ` [PATCH v12 2/3] ata: Add APM X-Gene SoC AHCI SATA host controller driver Loc Ho
0 siblings, 1 reply; 6+ messages in thread
From: Loc Ho @ 2014-02-21 17:47 UTC (permalink / raw)
To: olof-nZhT3qVonbNeoWH0uzbU5w, tj-DgEjT+Ai2ygdnm+yROfE0A,
arnd-r2nGTMty4D4
Cc: linux-scsi-u79uwXL29TY76Z2rM5mHXA,
linux-ide-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
ddutile-H+wXaHxf7aLQT0dZR+AlfA, jcm-H+wXaHxf7aLQT0dZR+AlfA,
patches-qTEPVZfXA3Y, Loc Ho, Tuan Phan, Suman Tripathi
Signed-off-by: Loc Ho <lho-qTEPVZfXA3Y@public.gmane.org>
Signed-off-by: Tuan Phan <tphan-qTEPVZfXA3Y@public.gmane.org>
Signed-off-by: Suman Tripathi <stripathi-qTEPVZfXA3Y@public.gmane.org>
---
.../devicetree/bindings/ata/apm-xgene.txt | 70 ++++++++++++++++++++
1 files changed, 70 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/ata/apm-xgene.txt
diff --git a/Documentation/devicetree/bindings/ata/apm-xgene.txt b/Documentation/devicetree/bindings/ata/apm-xgene.txt
new file mode 100644
index 0000000..633eb3b
--- /dev/null
+++ b/Documentation/devicetree/bindings/ata/apm-xgene.txt
@@ -0,0 +1,70 @@
+* APM X-Gene 6.0 Gb/s SATA host controller nodes
+
+SATA host controller nodes are defined to describe on-chip Serial ATA
+controllers. Each SATA controller (pair of ports) have its own node.
+
+Required properties:
+- compatible : Shall contain:
+ * "apm,xgene-ahci-sgmii" if mux'ed with SGMII
+ * "apm,xgene-ahci-pcie" if mux'ed with PCIe
+- reg : First memory resource shall be the AHCI memory
+ resource.
+ Second memory resource shall be the host controller
+ memory resource.
+- interrupts : Interrupt-specifier for SATA host controller IRQ.
+- clocks : Reference to the clock entry.
+- phys : A list of phandles + phy-specifiers, one for each
+ entry in phy-names.
+- phy-names : Should contain:
+ * "sata-6g" for the SATA 6.0Gbps PHY
+
+Optional properties:
+- status : Shall be "ok" if enabled or "disabled" if disabled.
+ Default is "ok".
+- interrupt-parent : Interrupt controller.
+
+Example:
+ sataclk: sataclk {
+ compatible = "fixed-clock";
+ #clock-cells = <1>;
+ clock-frequency = <100000000>;
+ clock-output-names = "sataclk";
+ };
+
+ phy2: phy@1f22a000 {
+ compatible = "apm,xgene-phy";
+ reg = <0x0 0x1f22a000 0x0 0x100>,
+ <0x0 0x1f22c000 0x0 0x100>;
+ #phy-cells = <1>;
+ };
+
+ phy3: phy@1f23a000 {
+ compatible = "apm,xgene-phy";
+ reg = <0x0 0x1f23a000 0x0 0x100>,
+ <0x0 0x1f23c000 0x0 0x100>;
+ #phy-cells = <1>;
+ };
+
+ sata2: sata@1a400000 {
+ compatible = "apm,xgene-ahci-sgmii";
+ reg = <0x0 0x1a400000 0x0 0x1000>,
+ <0x0 0x1f220000 0x0 0x10000>;
+ interrupt-parent = <&gic>;
+ interrupts = <0x0 0x87 0x4>;
+ status = "ok";
+ clocks = <&sataclk 0>;
+ phys = <&phy2 0>;
+ phy-names = "sata-6g";
+ };
+
+ sata3: sata@1a800000 {
+ compatible = "apm,xgene-ahci-pcie";
+ reg = <0x0 0x1a800000 0x0 0x1000>,
+ <0x0 0x1f230000 0x0 0x10000>;
+ interrupt-parent = <&gic>;
+ interrupts = <0x0 0x88 0x4>;
+ status = "ok";
+ clocks = <&sataclk 0>;
+ phys = <&phy3 0>;
+ phy-names = "sata-6g";
+ };
--
1.5.5
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v12 2/3] ata: Add APM X-Gene SoC AHCI SATA host controller driver
2014-02-21 17:47 ` [PATCH v12 1/3] Documentation: Add documentation for APM X-Gene SoC SATA host controller DTS binding Loc Ho
@ 2014-02-21 17:47 ` Loc Ho
2014-02-21 17:47 ` [PATCH v12 3/3] arm64: Add APM X-Gene SoC AHCI SATA host controller DTS entries Loc Ho
2014-02-21 17:55 ` [PATCH v12 2/3] ata: Add APM X-Gene SoC AHCI SATA host controller driver Tejun Heo
0 siblings, 2 replies; 6+ messages in thread
From: Loc Ho @ 2014-02-21 17:47 UTC (permalink / raw)
To: olof, tj, arnd
Cc: linux-scsi, linux-ide, devicetree, linux-arm-kernel, ddutile, jcm,
patches, Loc Ho, Tuan Phan, Suman Tripathi
This patch adds support for the APM X-Gene SoC AHCI SATA host controller
driver. It requires the corresponding APM X-Gene SoC PHY driver.
Signed-off-by: Loc Ho <lho@apm.com>
Signed-off-by: Tuan Phan <tphan@apm.com>
Signed-off-by: Suman Tripathi <stripathi@apm.com>
---
drivers/ata/Kconfig | 8 +
drivers/ata/Makefile | 1 +
drivers/ata/ahci_xgene.c | 540 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 549 insertions(+), 0 deletions(-)
create mode 100644 drivers/ata/ahci_xgene.c
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index cc67cc0..174e398 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -115,6 +115,14 @@ config AHCI_SUNXI
If unsure, say N.
+config AHCI_XGENE
+ tristate "APM X-Gene 6.0Gbps AHCI SATA host controller support"
+ depends on ARM64 || COMPILE_TEST
+ select SATA_AHCI_PLATFORM
+ select PHY_XGENE
+ help
+ This option enables support for APM X-Gene SoC SATA host controller.
+
config SATA_FSL
tristate "Freescale 3.0Gbps SATA support"
depends on FSL_SOC
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 246050b..72b423b 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o
obj-$(CONFIG_AHCI_IMX) += ahci_imx.o
obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o
+obj-$(CONFIG_AHCI_XGENE) += ahci_xgene.o
# SFF w/ custom DMA
obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c
new file mode 100644
index 0000000..be0c4fc
--- /dev/null
+++ b/drivers/ata/ahci_xgene.c
@@ -0,0 +1,540 @@
+/*
+ * AppliedMicro X-Gene SoC SATA Host Controller Driver
+ *
+ * Copyright (c) 2014, Applied Micro Circuits Corporation
+ * Author: Loc Ho <lho@apm.com>
+ * Tuan Phan <tphan@apm.com>
+ * Suman Tripathi <stripathi@apm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/ahci_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/phy/phy.h>
+#include "ahci.h"
+
+/* Controller who PHY shared with SGMII Ethernet PHY */
+#define XGENE_AHCI_SGMII_DTS "apm,xgene-ahci-sgmii"
+
+/* Controller who PHY (internal reference clock macro) shared with PCIe */
+#define XGENE_AHCI_PCIE_DTS "apm,xgene-ahci-pcie"
+
+/* Max # of disk per a controller */
+#define MAX_AHCI_CHN_PERCTR 2
+
+#define SATA_ENET_MUX_OFFSET 0x00007000
+#define SATA_DIAG_OFFSET 0x0000D000
+#define SATA_GLB_OFFSET 0x0000D850
+#define SATA_SHIM_OFFSET 0x0000E000
+#define SATA_MASTER_OFFSET 0x0000F000
+#define SATA_PORT0_OFFSET 0x00000100
+#define SATA_PORT1_OFFSET 0x00000180
+
+/* MUX CSR */
+#define SATA_ENET_CONFIG_REG 0x00000000
+#define CFG_SATA_ENET_SELECT_MASK 0x00000001
+
+/* SATA host controller CSR */
+#define SLVRDERRATTRIBUTES 0x00000000
+#define SLVWRERRATTRIBUTES 0x00000004
+#define MSTRDERRATTRIBUTES 0x00000008
+#define MSTWRERRATTRIBUTES 0x0000000c
+#define BUSCTLREG 0x00000014
+#define IOFMSTRWAUX 0x00000018
+#define INTSTATUSMASK 0x0000002c
+#define ERRINTSTATUS 0x00000030
+#define ERRINTSTATUSMASK 0x00000034
+
+/* SATA host AHCI CSR */
+#define PORTCFG 0x000000a4
+#define PORTADDR_SET(dst, src) \
+ (((dst) & ~0x0000003f) | (((u32)(src)) & 0x0000003f))
+#define PORTPHY1CFG 0x000000a8
+#define PORTPHY1CFG_FRCPHYRDY_SET(dst, src) \
+ (((dst) & ~0x00100000) | (((u32)(src) << 0x14) & 0x00100000))
+#define PORTPHY2CFG 0x000000ac
+#define PORTPHY3CFG 0x000000b0
+#define PORTPHY4CFG 0x000000b4
+#define PORTPHY5CFG 0x000000b8
+#define SCTL0 0x0000012C
+#define PORTPHY5CFG_RTCHG_SET(dst, src) \
+ (((dst) & ~0xfff00000) | (((u32)(src) << 0x14) & 0xfff00000))
+#define PORTAXICFG_EN_CONTEXT_SET(dst, src) \
+ (((dst) & ~0x01000000) | (((u32)(src) << 0x18) & 0x01000000))
+#define PORTAXICFG 0x000000bc
+#define PORTAXICFG_OUTTRANS_SET(dst, src) \
+ (((dst) & ~0x00f00000) | (((u32)(src) << 0x14) & 0x00f00000))
+
+/* SATA host controller slave CSR */
+#define INT_SLV_TMOMASK 0x00000010
+
+/* SATA global diagnostic CSR */
+#define CFG_MEM_RAM_SHUTDOWN 0x00000070
+#define BLOCK_MEM_RDY 0x00000074
+
+#define pdata_to_ctx(x) container_of(x, struct xgene_ahci_context, plat_data)
+
+struct xgene_ahci_context {
+ struct ahci_platform_data plat_data;
+ struct ahci_host_priv *hpriv;
+ struct device *dev;
+ void __iomem *csr_base; /* CSR base address of IP */
+ struct phy *phy;
+};
+
+static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx)
+{
+ void __iomem *diagcsr = ctx->csr_base + SATA_DIAG_OFFSET;
+ int try;
+ u32 val;
+
+ val = readl(diagcsr + CFG_MEM_RAM_SHUTDOWN);
+ if (val == 0) {
+ dev_dbg(ctx->dev, "memory already released from shutdown\n");
+ return 0;
+ }
+ dev_dbg(ctx->dev, "Release memory from shutdown\n");
+ /* SATA controller memory in shutdown. Remove from shutdown. */
+ writel(0x0, diagcsr + CFG_MEM_RAM_SHUTDOWN);
+ readl(diagcsr + CFG_MEM_RAM_SHUTDOWN); /* Force a barrier */
+
+ /* Check for at least ~1ms */
+ try = 1000;
+ do {
+ val = readl(diagcsr + BLOCK_MEM_RDY);
+ if (val != 0xFFFFFFFF)
+ usleep_range(1, 100);
+ } while (val != 0xFFFFFFFF && try-- > 0);
+ if (try <= 0) {
+ dev_err(ctx->dev, "failed to release memory from shutdown\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/**
+ * Custom Query ID command
+ *
+ * Due to HW errata, we must stop and re-start the port state machine after
+ * read ID command. Also disable support for DEVSLP as hardware don't support
+ * it.
+ */
+static unsigned int xgene_ahci_read_id(struct ata_device *dev,
+ struct ata_taskfile *tf, u16 *id)
+{
+ u32 err_mask;
+ void __iomem *port_mmio = ahci_port_base(dev->link->ap);
+
+ err_mask = ata_do_dev_read_id(dev, tf, id);
+ if (err_mask)
+ return err_mask;
+
+ /*
+ * Mask reserved area. Bit78 spec of Link Power Management
+ * bit15-8: reserved
+ * bit7: NCQ autosence
+ * bit6: Software settings preservation supported
+ * bit5: reserved
+ * bit4: In-order sata delivery supported
+ * bit3: DIPM requests supported
+ * bit2: DMA Setup FIS Auto-Activate optimization supported
+ * bit1: DMA Setup FIX non-Zero buffer offsets supported
+ * bit0: Reserved
+ *
+ * Clear reserved bit (DEVSLP bit) as we don't support DEVSLP
+ */
+ id[78] &= 0x00FF;
+
+ /* Restart the port if required due to HW errata */
+ if (!readl(port_mmio + PORT_CMD_ISSUE)) {
+ writel(PORT_CMD_FIS_RX, port_mmio + PORT_CMD);
+ readl(port_mmio + PORT_CMD); /* Force a barrier */
+ writel(PORT_CMD_FIS_RX | PORT_CMD_START, port_mmio + PORT_CMD);
+ readl(port_mmio + PORT_CMD); /* Force a barrier */
+ }
+ return 0;
+}
+
+static void xgene_ahci_force_phy_rdy(struct xgene_ahci_context *ctx,
+ int channel, int force)
+{
+ void __iomem *mmio = ctx->hpriv->mmio;
+ u32 val;
+
+ val = readl(mmio + PORTCFG);
+ val = PORTADDR_SET(val, channel == 0 ? 2 : 3);
+ writel(val, mmio + PORTCFG);
+ readl(mmio + PORTCFG); /* Force a barrier */
+ val = readl(mmio + PORTPHY1CFG);
+ val = PORTPHY1CFG_FRCPHYRDY_SET(val, force);
+ writel(val, mmio + PORTPHY1CFG);
+}
+
+static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel)
+{
+ void __iomem *mmio = ctx->hpriv->mmio;
+ u32 val;
+
+ dev_dbg(ctx->dev, "port configure mmio 0x%p channel %d\n",
+ mmio, channel);
+ val = readl(mmio + PORTCFG);
+ val = PORTADDR_SET(val, channel == 0 ? 2 : 3);
+ writel(val, mmio + PORTCFG);
+ readl(mmio + PORTCFG); /* Force a barrier */
+ /* Disable fix rate */
+ writel(0x0001fffe, mmio + PORTPHY1CFG);
+ readl(mmio + PORTPHY1CFG); /* Force a barrier */
+ writel(0x5018461c, mmio + PORTPHY2CFG);
+ readl(mmio + PORTPHY2CFG); /* Force a barrier */
+ writel(0x1c081907, mmio + PORTPHY3CFG);
+ readl(mmio + PORTPHY3CFG); /* Force a barrier */
+ writel(0x1c080815, mmio + PORTPHY4CFG);
+ readl(mmio + PORTPHY4CFG); /* Force a barrier */
+ /* Set window negotiation */
+ val = readl(mmio + PORTPHY5CFG);
+ val = PORTPHY5CFG_RTCHG_SET(val, 0x300);
+ writel(val, mmio + PORTPHY5CFG);
+ readl(mmio + PORTPHY5CFG); /* Force a barrier */
+ val = readl(mmio + PORTAXICFG);
+ val = PORTAXICFG_EN_CONTEXT_SET(val, 0x1); /* Enable context mgmt */
+ val = PORTAXICFG_OUTTRANS_SET(val, 0xe); /* Set outstanding */
+ writel(val, mmio + PORTAXICFG);
+ readl(mmio + PORTAXICFG); /* Force a barrier */
+}
+
+static int xgene_ahci_phy_restart(struct ata_link *link)
+{
+ struct ata_port *port = link->ap;
+ struct ahci_host_priv *hpriv = port->host->private_data;
+ struct xgene_ahci_context *ctx = pdata_to_ctx(hpriv->plat_data);
+
+ xgene_ahci_force_phy_rdy(ctx, port->port_no, 1);
+ xgene_ahci_force_phy_rdy(ctx, port->port_no, 0);
+ return 0;
+}
+
+static int xgene_ahci_do_hardreset(struct ata_link *link,
+ unsigned long deadline, bool *online)
+{
+ const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+ struct ata_port *ap = link->ap;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct xgene_ahci_context *ctx = pdata_to_ctx(hpriv->plat_data);
+ struct ahci_port_priv *pp = ap->private_data;
+ u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ata_taskfile tf;
+ int first_time = 1;
+ int rc;
+ u32 val;
+ int i;
+
+hardreset_retry:
+ /* clear D2H reception area to properly wait for D2H FIS */
+ ata_tf_init(link->device, &tf);
+ tf.command = ATA_BUSY;
+ ata_tf_to_fis(&tf, 0, 0, d2h_fis);
+ rc = sata_link_hardreset(link, timing, deadline, online,
+ ahci_check_ready);
+
+ if (*online) {
+ /* Check to ensure that the disk comes up in matching speed */
+ if (first_time) {
+ u32 gen_speed;
+
+ first_time = 0;
+ sata_scr_read(link, SCR_STATUS, &gen_speed);
+ gen_speed = (gen_speed >> 4) & 0xf;
+ if (gen_speed == 1 || gen_speed == 2) {
+ /*
+ * For Gen2/1 and first time, let's check again
+ * with Gen2/1 PHY to ensure actual Gen2/1 disk.
+ */
+ phy_set_speed(ctx->phy, ap->port_no,
+ gen_speed == 2 ? 3000000000ULL :
+ 1500000000ULL);
+ xgene_ahci_phy_restart(link);
+ goto hardreset_retry;
+ }
+ }
+
+ /* Clear SER_DISPARITY/SER_10B_8B_ERR if set due to errata */
+ for (i = 0; i < 5; i++) {
+ /* Check if error bit set */
+ val = readl(port_mmio + PORT_SCR_ERR);
+ if (!(val & (SERR_DISPARITY | SERR_10B_8B_ERR)))
+ break;
+ /* Clear any error due to errata */
+ xgene_ahci_force_phy_rdy(ctx, ap->port_no, 1);
+ /* Reset the PHY Rx path */
+ phy_set_speed(ctx->phy, ap->port_no, 0);
+ xgene_ahci_force_phy_rdy(ctx, ap->port_no, 0);
+ /* Clear all errors */
+ val = readl(port_mmio + PORT_SCR_ERR);
+ writel(val, port_mmio + PORT_SCR_ERR);
+ }
+ }
+
+ /* clear all errors if any pending */
+ val = readl(port_mmio + PORT_SCR_ERR);
+ writel(val, port_mmio + PORT_SCR_ERR);
+
+ return rc;
+}
+
+static int xgene_ahci_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ bool online;
+ int rc;
+ int portcmd_saved;
+ u32 portclb_saved;
+ u32 portclbhi_saved;
+ u32 portrxfis_saved;
+ u32 portrxfishi_saved;
+
+ /* As hardreset reset these CSR, let save it to restore later */
+ portcmd_saved = readl(port_mmio + PORT_CMD);
+ portclb_saved = readl(port_mmio + PORT_LST_ADDR);
+ portclbhi_saved = readl(port_mmio + PORT_LST_ADDR_HI);
+ portrxfis_saved = readl(port_mmio + PORT_FIS_ADDR);
+ portrxfishi_saved = readl(port_mmio + PORT_FIS_ADDR_HI);
+
+ ahci_stop_engine(ap);
+
+ rc = xgene_ahci_do_hardreset(link, deadline, &online);
+
+ /* As controller hardreset clear them, let restore them */
+ writel(portcmd_saved, port_mmio + PORT_CMD);
+ writel(portclb_saved, port_mmio + PORT_LST_ADDR);
+ writel(portclbhi_saved, port_mmio + PORT_LST_ADDR_HI);
+ writel(portrxfis_saved, port_mmio + PORT_FIS_ADDR);
+ writel(portrxfishi_saved, port_mmio + PORT_FIS_ADDR_HI);
+
+ hpriv->start_engine(ap);
+
+ if (online)
+ *class = ahci_dev_classify(ap);
+
+ return rc;
+}
+
+static struct ata_port_operations xgene_ahci_ops = {
+ .inherits = &ahci_ops,
+ .hardreset = xgene_ahci_hardreset,
+ .read_id = xgene_ahci_read_id,
+};
+
+static const struct ata_port_info xgene_ahci_port_info = {
+ AHCI_HFLAGS(AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ),
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &xgene_ahci_ops,
+};
+
+static int xgene_ahci_hw_init(struct ahci_host_priv *hpriv)
+{
+ struct xgene_ahci_context *ctx = pdata_to_ctx(hpriv->plat_data);
+ int i;
+ int rc;
+ u32 val;
+
+ /* Remove IP RAM out of shutdown */
+ rc = xgene_ahci_init_memram(ctx);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < MAX_AHCI_CHN_PERCTR; i++)
+ xgene_ahci_set_phy_cfg(ctx, i);
+
+ /* AXI disable Mask */
+ writel(0xffffffff, hpriv->mmio + HOST_IRQ_STAT);
+ readl(hpriv->mmio + HOST_IRQ_STAT); /* Force a barrier */
+ writel(0, ctx->csr_base + INTSTATUSMASK);
+ readl(ctx->csr_base + INTSTATUSMASK); /* Force a barrier */
+ dev_dbg(ctx->dev, "top level interrupt mask 0x%X value 0x%08X\n",
+ INTSTATUSMASK, val);
+
+ writel(0x0, ctx->csr_base + ERRINTSTATUSMASK);
+ readl(ctx->csr_base + ERRINTSTATUSMASK); /* Force a barrier */
+ writel(0x0, ctx->csr_base + SATA_SHIM_OFFSET + INT_SLV_TMOMASK);
+ readl(ctx->csr_base + SATA_SHIM_OFFSET + INT_SLV_TMOMASK);
+
+ /* Enable AXI Interrupt */
+ writel(0xffffffff, ctx->csr_base + SLVRDERRATTRIBUTES);
+ writel(0xffffffff, ctx->csr_base + SLVWRERRATTRIBUTES);
+ writel(0xffffffff, ctx->csr_base + MSTRDERRATTRIBUTES);
+ writel(0xffffffff, ctx->csr_base + MSTWRERRATTRIBUTES);
+
+ /* Enable coherency */
+ val = readl(ctx->csr_base + BUSCTLREG);
+ val &= ~0x00000002; /* Enable write coherency */
+ val &= ~0x00000001; /* Enable read coherency */
+ writel(val, ctx->csr_base + BUSCTLREG);
+
+ val = readl(ctx->csr_base + IOFMSTRWAUX);
+ val |= (1 << 3); /* Enable read coherency */
+ val |= (1 << 9); /* Enable write coherency */
+ writel(val, ctx->csr_base + IOFMSTRWAUX);
+ val = readl(ctx->csr_base + IOFMSTRWAUX);
+ dev_dbg(ctx->dev, "coherency 0x%X value 0x%08X\n",
+ IOFMSTRWAUX, val);
+
+ return rc;
+}
+
+static int xgene_ahci_mux_select(struct xgene_ahci_context *ctx)
+{
+ void *mux_csr = ctx->csr_base + SATA_ENET_MUX_OFFSET;
+ u32 val;
+
+ val = readl(mux_csr + SATA_ENET_CONFIG_REG);
+ val &= ~CFG_SATA_ENET_SELECT_MASK;
+ writel(val, mux_csr + SATA_ENET_CONFIG_REG);
+ val = readl(mux_csr + SATA_ENET_CONFIG_REG);
+ return val & CFG_SATA_ENET_SELECT_MASK ? -1 : 0;
+}
+
+static int xgene_ahci_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ahci_host_priv *hpriv;
+ struct xgene_ahci_context *hplat_data;
+ struct resource *res;
+ int rc;
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+
+ hplat_data = devm_kzalloc(dev, sizeof(*hplat_data), GFP_KERNEL);
+ if (!hplat_data) {
+ dev_err(dev, "can't allocate host context\n");
+ return -ENOMEM;
+ }
+ hpriv->plat_data = hplat_data;
+ hplat_data->hpriv = hpriv;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ dev_err(dev, "no csr space\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Can't use devm_ioremap_resource due to overlapping region.
+ * 0xYYYY.0000 - host core
+ * 0xYYYY.7000 - Mux (if applicable)
+ * 0xYYYY.A000 - PHY indirect access
+ * 0xYYYY.C000 - Clock
+ * 0xYYYY.D000 - RAM shutdown removal
+ * As we map the entire region as one, it overlaps with the PHY driver.
+ */
+ hplat_data->csr_base = devm_ioremap(dev, res->start,
+ resource_size(res));
+ if (!hplat_data->csr_base) {
+ dev_err(dev, "can't map %pR\n", res);
+ return -ENOMEM;
+ }
+
+ dev_dbg(dev, "VAddr 0x%p Mmio VAddr 0x%p\n", hplat_data->csr_base,
+ hpriv->mmio);
+
+ /* Select ATA */
+ if (of_device_is_compatible(pdev->dev.of_node,
+ XGENE_AHCI_SGMII_DTS)) {
+ if (xgene_ahci_mux_select(hplat_data)) {
+ dev_err(dev, "SATA mux selection failed\n");
+ return -ENODEV;
+ }
+ }
+
+ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+ goto put_resources;
+
+ /* HW requires toggle of the clock */
+ ahci_platform_disable_clks(hpriv);
+ rc = ahci_platform_enable_clks(hpriv);
+ if (rc)
+ goto put_resources;
+
+ /* Configure the PHY */
+ hplat_data->phy = devm_phy_get(dev, "sata-6g");
+ if (!hplat_data->phy) {
+ dev_err(dev, "no PHY available\n");
+ rc = -ENODEV;
+ goto disable_resources;
+ }
+
+ rc = phy_init(hplat_data->phy);
+ if (rc) {
+ dev_err(dev, "PHY initialize failed %d\n", rc);
+ goto disable_resources;
+ }
+
+ /* Configure the host controller */
+ xgene_ahci_hw_init(hpriv);
+
+ /* Setup DMA mask - 32 for 32-bit system and 64 for 64-bit system */
+ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(8*sizeof(void *)));
+ if (rc) {
+ dev_err(dev, "Unable to set dma mask\n");
+ goto disable_resources;
+ }
+
+ rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info, 0, 0);
+ if (rc)
+ goto disable_resources;
+
+ dev_dbg(dev, "X-Gene SATA host controller initialized\n");
+ return 0;
+
+disable_resources:
+ ahci_platform_disable_resources(hpriv);
+put_resources:
+ ahci_platform_put_resources(hpriv);
+ return rc;
+}
+
+static const struct of_device_id xgene_ahci_of_match[] = {
+ {.compatible = XGENE_AHCI_SGMII_DTS,},
+ {.compatible = XGENE_AHCI_PCIE_DTS,},
+ {},
+};
+MODULE_DEVICE_TABLE(of, xgene_ahci_of_match);
+
+static struct platform_driver xgene_ahci_driver = {
+ .driver = {
+ .name = "xgene-ahci",
+ .owner = THIS_MODULE,
+ .of_match_table = xgene_ahci_of_match,
+ },
+ .probe = xgene_ahci_probe,
+};
+
+module_platform_driver(xgene_ahci_driver);
+
+MODULE_DESCRIPTION("APM X-Gene AHCI SATA driver");
+MODULE_AUTHOR("Loc Ho <lho@apm.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.4");
--
1.5.5
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v12 3/3] arm64: Add APM X-Gene SoC AHCI SATA host controller DTS entries
2014-02-21 17:47 ` [PATCH v12 2/3] ata: Add APM X-Gene SoC AHCI SATA host controller driver Loc Ho
@ 2014-02-21 17:47 ` Loc Ho
2014-02-21 17:55 ` [PATCH v12 2/3] ata: Add APM X-Gene SoC AHCI SATA host controller driver Tejun Heo
1 sibling, 0 replies; 6+ messages in thread
From: Loc Ho @ 2014-02-21 17:47 UTC (permalink / raw)
To: olof, tj, arnd
Cc: linux-scsi, linux-ide, devicetree, linux-arm-kernel, ddutile, jcm,
patches, Loc Ho, Tuan Phan, Suman Tripathi
Signed-off-by: Loc Ho <lho@apm.com>
Signed-off-by: Tuan Phan <tphan@apm.com>
Signed-off-by: Suman Tripathi <stripathi@apm.com>
---
arch/arm64/boot/dts/apm-storm.dtsi | 75 ++++++++++++++++++++++++++++++++++++
1 files changed, 75 insertions(+), 0 deletions(-)
diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi
index c78ddcf..57b0770 100644
--- a/arch/arm64/boot/dts/apm-storm.dtsi
+++ b/arch/arm64/boot/dts/apm-storm.dtsi
@@ -221,6 +221,48 @@
enable-offset = <0x0>;
enable-mask = <0x06>;
};
+
+ sata01clk: sata01clk@1f21c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ clock-names = "socplldiv2";
+ reg = <0x0 0x1f21c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "sata01clk";
+ csr-offset = <0x4>;
+ csr-mask = <0x05>;
+ enable-offset = <0x0>;
+ enable-mask = <0x39>;
+ };
+
+ sata23clk: sata23clk@1f22c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ clock-names = "socplldiv2";
+ reg = <0x0 0x1f22c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "sata23clk";
+ csr-offset = <0x4>;
+ csr-mask = <0x05>;
+ enable-offset = <0x0>;
+ enable-mask = <0x39>;
+ };
+
+ sata45clk: sata45clk@1f23c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ clock-names = "socplldiv2";
+ reg = <0x0 0x1f23c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "sata45clk";
+ csr-offset = <0x4>;
+ csr-mask = <0x05>;
+ enable-offset = <0x0>;
+ enable-mask = <0x39>;
+ };
};
serial0: serial@1c020000 {
@@ -262,5 +304,38 @@
apm,tx-boost-gain = <31 31 31 31 31 31>;
apm,tx-eye-tuning = <2 10 10 2 10 10>;
};
+
+ sata1: sata@1a000000 {
+ compatible = "apm,xgene-ahci-sgmii";
+ reg = <0x0 0x1a000000 0x0 0x1000>,
+ <0x0 0x1f210000 0x0 0x10000>;
+ interrupts = <0x0 0x86 0x4>;
+ status = "disabled";
+ clocks = <&sata01clk 0>;
+ phys = <&phy1 0>;
+ phy-names = "sata-6g";
+ };
+
+ sata2: sata@1a400000 {
+ compatible = "apm,xgene-ahci-sgmii";
+ reg = <0x0 0x1a400000 0x0 0x1000>,
+ <0x0 0x1f220000 0x0 0x10000>;
+ interrupts = <0x0 0x87 0x4>;
+ status = "ok";
+ clocks = <&sata23clk 0>;
+ phys = <&phy2 0>;
+ phy-names = "sata-6g";
+ };
+
+ sata3: sata@1a800000 {
+ compatible = "apm,xgene-ahci-pcie";
+ reg = <0x0 0x1a800000 0x0 0x1000>,
+ <0x0 0x1f230000 0x0 0x10000>;
+ interrupts = <0x0 0x88 0x4>;
+ status = "ok";
+ clocks = <&sata45clk 0>;
+ phys = <&phy3 0>;
+ phy-names = "sata-6g";
+ };
};
};
--
1.5.5
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v12 2/3] ata: Add APM X-Gene SoC AHCI SATA host controller driver
2014-02-21 17:47 ` [PATCH v12 2/3] ata: Add APM X-Gene SoC AHCI SATA host controller driver Loc Ho
2014-02-21 17:47 ` [PATCH v12 3/3] arm64: Add APM X-Gene SoC AHCI SATA host controller DTS entries Loc Ho
@ 2014-02-21 17:55 ` Tejun Heo
[not found] ` <CAPw-ZTkWbYfCKs+4ZJ7_zuuFZy5RH51319Pj=3i5kdg162UVXg@mail.gmail.com>
1 sibling, 1 reply; 6+ messages in thread
From: Tejun Heo @ 2014-02-21 17:55 UTC (permalink / raw)
To: Loc Ho
Cc: olof, arnd, linux-scsi, linux-ide, devicetree, linux-arm-kernel,
ddutile, jcm, patches, Tuan Phan, Suman Tripathi
Hello, Loc.
On Fri, Feb 21, 2014 at 10:47:32AM -0700, Loc Ho wrote:
> +/**
> + * Custom Query ID command
> + *
> + * Due to HW errata, we must stop and re-start the port state machine after
> + * read ID command. Also disable support for DEVSLP as hardware don't support
> + * it.
> + */
Sorry about not being clear before but /** function comment means
something like
/**
* ata_scsi_port_error_handler - recover the port after the commands
* @host: SCSI host containing the port
* @ap: the ATA port
*
* Handle the recovery of the port @ap after all the commands have
* been recovered.
*/
> +static int xgene_ahci_do_hardreset(struct ata_link *link,
> + unsigned long deadline, bool *online)
> +{
> + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
> + struct ata_port *ap = link->ap;
> + struct ahci_host_priv *hpriv = ap->host->private_data;
> + struct xgene_ahci_context *ctx = pdata_to_ctx(hpriv->plat_data);
> + struct ahci_port_priv *pp = ap->private_data;
> + u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
> + void __iomem *port_mmio = ahci_port_base(ap);
> + struct ata_taskfile tf;
> + int first_time = 1;
> + int rc;
> + u32 val;
> + int i;
> +
> +hardreset_retry:
> + /* clear D2H reception area to properly wait for D2H FIS */
> + ata_tf_init(link->device, &tf);
> + tf.command = ATA_BUSY;
> + ata_tf_to_fis(&tf, 0, 0, d2h_fis);
> + rc = sata_link_hardreset(link, timing, deadline, online,
> + ahci_check_ready);
> +
> + if (*online) {
> + /* Check to ensure that the disk comes up in matching speed */
> + if (first_time) {
> + u32 gen_speed;
> +
> + first_time = 0;
> + sata_scr_read(link, SCR_STATUS, &gen_speed);
> + gen_speed = (gen_speed >> 4) & 0xf;
> + if (gen_speed == 1 || gen_speed == 2) {
> + /*
> + * For Gen2/1 and first time, let's check again
> + * with Gen2/1 PHY to ensure actual Gen2/1 disk.
> + */
Can you please go back two reviews and re-read what I requested?
Also, if you're unsure, please don't hesitate to ask back. It's
usually a lot easier for both parties than iterating through patchsets
without properly understanding each other.
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v12 2/3] ata: Add APM X-Gene SoC AHCI SATA host controller driver
[not found] ` <CAPw-ZTkWbYfCKs+4ZJ7_zuuFZy5RH51319Pj=3i5kdg162UVXg@mail.gmail.com>
@ 2014-02-21 19:00 ` Tejun Heo
0 siblings, 0 replies; 6+ messages in thread
From: Tejun Heo @ 2014-02-21 19:00 UTC (permalink / raw)
To: Loc Ho
Cc: Olof Johansson, Arnd Bergmann, Linux SCSI List,
linux-ide@vger.kernel.org, devicetree@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, Don Dutile, Jon Masters,
patches@apm.com, Tuan Phan, Suman Tripathi
Hello, Loc.
On Fri, Feb 21, 2014 at 10:43:52AM -0800, Loc Ho wrote:
> Do you want this for all functions or only one that with comment? Also,
> for both drivers - host and PHY drivres?
Oh, no need to do that for every function. It's just customary to use
function comment when there's sufficient amount to explain for the
whole function.
> > Can you please go back two reviews and re-read what I requested?
> > Also, if you're unsure, please don't hesitate to ask back. It's
> > usually a lot easier for both parties than iterating through patchsets
> > without properly understanding each other.
> >
>
> Before posting this morning, I had gone over all response email from you
> since we first interacted. I am not quite follow what you want here. Are
> you suggesting that I should move this out as an errata patch?
Hmmm... maybe I was too ambiguous. Because the behavior is quite
unusual and can make the error handling behavior deviate, I think it
deserves to explain 1. why such behavior is necessary and 2. what the
implications are (e.g. in corner cases, how long it could add to reset
timeout) and preferably 3. rationale for choosing this specific
approach given #1 and #2, so that when someone else reads the code
later on [s]he doesn't have to second-guess the original intention of
the workaround.
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2014-02-21 19:00 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-02-21 17:47 [PATCH v12 0/3] ata: Add APM X-Gene SoC AHCI SATA host controller support Loc Ho
[not found] ` <1393004853-25994-1-git-send-email-lho-qTEPVZfXA3Y@public.gmane.org>
2014-02-21 17:47 ` [PATCH v12 1/3] Documentation: Add documentation for APM X-Gene SoC SATA host controller DTS binding Loc Ho
2014-02-21 17:47 ` [PATCH v12 2/3] ata: Add APM X-Gene SoC AHCI SATA host controller driver Loc Ho
2014-02-21 17:47 ` [PATCH v12 3/3] arm64: Add APM X-Gene SoC AHCI SATA host controller DTS entries Loc Ho
2014-02-21 17:55 ` [PATCH v12 2/3] ata: Add APM X-Gene SoC AHCI SATA host controller driver Tejun Heo
[not found] ` <CAPw-ZTkWbYfCKs+4ZJ7_zuuFZy5RH51319Pj=3i5kdg162UVXg@mail.gmail.com>
2014-02-21 19:00 ` Tejun Heo
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).