--- /dev/null
+* Broadcom SATA3 AHCI Controller
+
+SATA nodes are defined to describe on-chip Serial ATA controllers.
+Each SATA controller should have its own node.
+
+Required properties:
+- compatible : should be one or more of
+ "brcm,bcm7425-ahci"
+ "brcm,bcm7445-ahci"
+ "brcm,bcm-nsp-ahci"
+ "brcm,sata3-ahci"
+- reg : register mappings for AHCI and SATA_TOP_CTRL
+- reg-names : "ahci" and "top-ctrl"
+- interrupts : interrupt mapping for SATA IRQ
+
+Also see ahci-platform.txt.
+
+Example:
+
+ sata@f045a000 {
+ compatible = "brcm,bcm7445-ahci", "brcm,sata3-ahci";
+ reg = <0xf045a000 0xa9c>, <0xf0458040 0x24>;
+ reg-names = "ahci", "top-ctrl";
+ interrupts = <0 30 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sata0: sata-port@0 {
+ reg = <0>;
+ phys = <&sata_phy 0>;
+ };
+
+ sata1: sata-port@1 {
+ reg = <1>;
+ phys = <&sata_phy 1>;
+ };
+ };
+++ /dev/null
-* Broadcom SATA3 AHCI Controller for STB
-
-SATA nodes are defined to describe on-chip Serial ATA controllers.
-Each SATA controller should have its own node.
-
-Required properties:
-- compatible : should be one or more of
- "brcm,bcm7425-ahci"
- "brcm,bcm7445-ahci"
- "brcm,sata3-ahci"
-- reg : register mappings for AHCI and SATA_TOP_CTRL
-- reg-names : "ahci" and "top-ctrl"
-- interrupts : interrupt mapping for SATA IRQ
-
-Also see ahci-platform.txt.
-
-Example:
-
- sata@f045a000 {
- compatible = "brcm,bcm7445-ahci", "brcm,sata3-ahci";
- reg = <0xf045a000 0xa9c>, <0xf0458040 0x24>;
- reg-names = "ahci", "top-ctrl";
- interrupts = <0 30 0>;
- #address-cells = <1>;
- #size-cells = <0>;
-
- sata0: sata-port@0 {
- reg = <0>;
- phys = <&sata_phy 0>;
- };
-
- sata1: sata-port@1 {
- reg = <1>;
- phys = <&sata_phy 1>;
- };
- };
"brcm,bcm7425-sata-phy"
"brcm,bcm7445-sata-phy"
"brcm,iproc-ns2-sata-phy"
+ "brcm,iproc-nsp-sata-phy"
"brcm,phy-sata3"
- address-cells: should be 1
- size-cells: should be 0
Sub-nodes optional properties:
- brcm,enable-ssc: use spread spectrum clocking (SSC) on this port
- This property is not applicable for "brcm,iproc-ns2-sata-phy".
+ This property is not applicable for "brcm,iproc-ns2-sata-phy" and
+ "brcm,iproc-nsp-sata-phy".
Example:
sata-phy@f0458100 {
F: drivers/ata/
F: include/linux/ata.h
F: include/linux/libata.h
+F: Documentation/devicetree/bindings/ata/
LIBATA PATA ARASAN COMPACT FLASH CONTROLLER
M: Viresh Kumar <vireshk@kernel.org>
<0x30028 0x04>,
<0x3f408 0x04>;
};
+
+ sata_phy: sata_phy@40100 {
+ compatible = "brcm,iproc-nsp-sata-phy";
+ reg = <0x40100 0x340>;
+ reg-names = "phy";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sata_phy0: sata-phy@0 {
+ reg = <0>;
+ #phy-cells = <0>;
+ status = "disabled";
+ };
+
+ sata_phy1: sata-phy@1 {
+ reg = <1>;
+ #phy-cells = <0>;
+ status = "disabled";
+ };
+ };
+
+ sata: ahci@41000 {
+ compatible = "brcm,bcm-nsp-ahci";
+ reg-names = "ahci", "top-ctrl";
+ reg = <0x41000 0x1000>, <0x40020 0x1c>;
+ interrupts = <GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+
+ sata0: sata-port@0 {
+ reg = <0>;
+ phys = <&sata_phy0>;
+ phy-names = "sata-phy";
+ };
+
+ sata1: sata-port@1 {
+ reg = <1>;
+ phys = <&sata_phy1>;
+ phy-names = "sata-phy";
+ };
+ };
};
pcie0: pcie@18012000 {
status = "okay";
};
+&sata_phy0 {
+ status = "okay";
+};
+
+&sata_phy1 {
+ status = "okay";
+};
+
+&sata {
+ status = "okay";
+};
+
&nand {
nandcs@0 {
compatible = "brcm,nandcs";
If unsure, say N.
-config AHCI_BRCMSTB
- tristate "Broadcom STB AHCI SATA support"
- depends on ARCH_BRCMSTB || BMIPS_GENERIC
+config AHCI_BRCM
+ tristate "Broadcom AHCI SATA support"
+ depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM_NSP
help
This option enables support for the AHCI SATA3 controller found on
- STB SoC's.
+ Broadcom SoC's.
If unsure, say N.
obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o
-obj-$(CONFIG_AHCI_BRCMSTB) += ahci_brcmstb.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_BRCM) += ahci_brcm.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_CEVA) += ahci_ceva.o libahci.o libahci_platform.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
},
};
-#if defined(CONFIG_PATA_MARVELL) || defined(CONFIG_PATA_MARVELL_MODULE)
+#if IS_ENABLED(CONFIG_PATA_MARVELL)
static int marvell_enable;
#else
static int marvell_enable = 1;
--- /dev/null
+/*
+ * Broadcom SATA3 AHCI Controller Driver
+ *
+ * Copyright © 2009-2015 Broadcom Corporation
+ *
+ * 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, 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.
+ */
+
+#include <linux/ahci_platform.h>
+#include <linux/compiler.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/libata.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+
+#include "ahci.h"
+
+#define DRV_NAME "brcm-ahci"
+
+#define SATA_TOP_CTRL_VERSION 0x0
+#define SATA_TOP_CTRL_BUS_CTRL 0x4
+ #define MMIO_ENDIAN_SHIFT 0 /* CPU->AHCI */
+ #define DMADESC_ENDIAN_SHIFT 2 /* AHCI->DDR */
+ #define DMADATA_ENDIAN_SHIFT 4 /* AHCI->DDR */
+ #define PIODATA_ENDIAN_SHIFT 6
+ #define ENDIAN_SWAP_NONE 0
+ #define ENDIAN_SWAP_FULL 2
+ #define OVERRIDE_HWINIT BIT(16)
+#define SATA_TOP_CTRL_TP_CTRL 0x8
+#define SATA_TOP_CTRL_PHY_CTRL 0xc
+ #define SATA_TOP_CTRL_PHY_CTRL_1 0x0
+ #define SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE BIT(14)
+ #define SATA_TOP_CTRL_PHY_CTRL_2 0x4
+ #define SATA_TOP_CTRL_2_SW_RST_MDIOREG BIT(0)
+ #define SATA_TOP_CTRL_2_SW_RST_OOB BIT(1)
+ #define SATA_TOP_CTRL_2_SW_RST_RX BIT(2)
+ #define SATA_TOP_CTRL_2_SW_RST_TX BIT(3)
+ #define SATA_TOP_CTRL_2_PHY_GLOBAL_RESET BIT(14)
+ #define SATA_TOP_CTRL_PHY_OFFS 0x8
+ #define SATA_TOP_MAX_PHYS 2
+
+#define SATA_FIRST_PORT_CTRL 0x700
+#define SATA_NEXT_PORT_CTRL_OFFSET 0x80
+#define SATA_PORT_PCTRL6(reg_base) (reg_base + 0x18)
+
+/* On big-endian MIPS, buses are reversed to big endian, so switch them back */
+#if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN)
+#define DATA_ENDIAN 2 /* AHCI->DDR inbound accesses */
+#define MMIO_ENDIAN 2 /* CPU->AHCI outbound accesses */
+#else
+#define DATA_ENDIAN 0
+#define MMIO_ENDIAN 0
+#endif
+
+#define BUS_CTRL_ENDIAN_CONF \
+ ((DATA_ENDIAN << DMADATA_ENDIAN_SHIFT) | \
+ (DATA_ENDIAN << DMADESC_ENDIAN_SHIFT) | \
+ (MMIO_ENDIAN << MMIO_ENDIAN_SHIFT))
+
+enum brcm_ahci_version {
+ BRCM_SATA_BCM7425 = 1,
+ BRCM_SATA_BCM7445,
+ BRCM_SATA_NSP,
+};
+
+enum brcm_ahci_quirks {
+ BRCM_AHCI_QUIRK_NO_NCQ = BIT(0),
+ BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE = BIT(1),
+};
+
+struct brcm_ahci_priv {
+ struct device *dev;
+ void __iomem *top_ctrl;
+ u32 port_mask;
+ u32 quirks;
+ enum brcm_ahci_version version;
+};
+
+static const struct ata_port_info ahci_brcm_port_info = {
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,
+ .link_flags = ATA_LFLAG_NO_DB_DELAY,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &ahci_platform_ops,
+};
+
+static inline u32 brcm_sata_readreg(void __iomem *addr)
+{
+ /*
+ * MIPS endianness is configured by boot strap, which also reverses all
+ * bus endianness (i.e., big-endian CPU + big endian bus ==> native
+ * endian I/O).
+ *
+ * Other architectures (e.g., ARM) either do not support big endian, or
+ * else leave I/O in little endian mode.
+ */
+ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+ return __raw_readl(addr);
+ else
+ return readl_relaxed(addr);
+}
+
+static inline void brcm_sata_writereg(u32 val, void __iomem *addr)
+{
+ /* See brcm_sata_readreg() comments */
+ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+ __raw_writel(val, addr);
+ else
+ writel_relaxed(val, addr);
+}
+
+static void brcm_sata_alpm_init(struct ahci_host_priv *hpriv)
+{
+ struct brcm_ahci_priv *priv = hpriv->plat_data;
+ u32 bus_ctrl, port_ctrl, host_caps;
+ int i;
+
+ /* Enable support for ALPM */
+ bus_ctrl = brcm_sata_readreg(priv->top_ctrl +
+ SATA_TOP_CTRL_BUS_CTRL);
+ brcm_sata_writereg(bus_ctrl | OVERRIDE_HWINIT,
+ priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL);
+ host_caps = readl(hpriv->mmio + HOST_CAP);
+ writel(host_caps | HOST_CAP_ALPM, hpriv->mmio);
+ brcm_sata_writereg(bus_ctrl, priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL);
+
+ /*
+ * Adjust timeout to allow PLL sufficient time to lock while waking
+ * up from slumber mode.
+ */
+ for (i = 0, port_ctrl = SATA_FIRST_PORT_CTRL;
+ i < SATA_TOP_MAX_PHYS;
+ i++, port_ctrl += SATA_NEXT_PORT_CTRL_OFFSET) {
+ if (priv->port_mask & BIT(i))
+ writel(0xff1003fc,
+ hpriv->mmio + SATA_PORT_PCTRL6(port_ctrl));
+ }
+}
+
+static void brcm_sata_phy_enable(struct brcm_ahci_priv *priv, int port)
+{
+ void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL +
+ (port * SATA_TOP_CTRL_PHY_OFFS);
+ void __iomem *p;
+ u32 reg;
+
+ if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE)
+ return;
+
+ /* clear PHY_DEFAULT_POWER_STATE */
+ p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1;
+ reg = brcm_sata_readreg(p);
+ reg &= ~SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE;
+ brcm_sata_writereg(reg, p);
+
+ /* reset the PHY digital logic */
+ p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2;
+ reg = brcm_sata_readreg(p);
+ reg &= ~(SATA_TOP_CTRL_2_SW_RST_MDIOREG | SATA_TOP_CTRL_2_SW_RST_OOB |
+ SATA_TOP_CTRL_2_SW_RST_RX);
+ reg |= SATA_TOP_CTRL_2_SW_RST_TX;
+ brcm_sata_writereg(reg, p);
+ reg = brcm_sata_readreg(p);
+ reg |= SATA_TOP_CTRL_2_PHY_GLOBAL_RESET;
+ brcm_sata_writereg(reg, p);
+ reg = brcm_sata_readreg(p);
+ reg &= ~SATA_TOP_CTRL_2_PHY_GLOBAL_RESET;
+ brcm_sata_writereg(reg, p);
+ (void)brcm_sata_readreg(p);
+}
+
+static void brcm_sata_phy_disable(struct brcm_ahci_priv *priv, int port)
+{
+ void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL +
+ (port * SATA_TOP_CTRL_PHY_OFFS);
+ void __iomem *p;
+ u32 reg;
+
+ if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE)
+ return;
+
+ /* power-off the PHY digital logic */
+ p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2;
+ reg = brcm_sata_readreg(p);
+ reg |= (SATA_TOP_CTRL_2_SW_RST_MDIOREG | SATA_TOP_CTRL_2_SW_RST_OOB |
+ SATA_TOP_CTRL_2_SW_RST_RX | SATA_TOP_CTRL_2_SW_RST_TX |
+ SATA_TOP_CTRL_2_PHY_GLOBAL_RESET);
+ brcm_sata_writereg(reg, p);
+
+ /* set PHY_DEFAULT_POWER_STATE */
+ p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1;
+ reg = brcm_sata_readreg(p);
+ reg |= SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE;
+ brcm_sata_writereg(reg, p);
+}
+
+static void brcm_sata_phys_enable(struct brcm_ahci_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < SATA_TOP_MAX_PHYS; i++)
+ if (priv->port_mask & BIT(i))
+ brcm_sata_phy_enable(priv, i);
+}
+
+static void brcm_sata_phys_disable(struct brcm_ahci_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < SATA_TOP_MAX_PHYS; i++)
+ if (priv->port_mask & BIT(i))
+ brcm_sata_phy_disable(priv, i);
+}
+
+static u32 brcm_ahci_get_portmask(struct platform_device *pdev,
+ struct brcm_ahci_priv *priv)
+{
+ void __iomem *ahci;
+ struct resource *res;
+ u32 impl;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ahci");
+ ahci = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ahci))
+ return 0;
+
+ impl = readl(ahci + HOST_PORTS_IMPL);
+
+ if (fls(impl) > SATA_TOP_MAX_PHYS)
+ dev_warn(priv->dev, "warning: more ports than PHYs (%#x)\n",
+ impl);
+ else if (!impl)
+ dev_info(priv->dev, "no ports found\n");
+
+ devm_iounmap(&pdev->dev, ahci);
+ devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
+
+ return impl;
+}
+
+static void brcm_sata_init(struct brcm_ahci_priv *priv)
+{
+ void __iomem *ctrl = priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL;
+
+ /* Configure endianness */
+ if (priv->version == BRCM_SATA_NSP) {
+ u32 data = brcm_sata_readreg(ctrl);
+
+ data &= ~((0x03 << DMADATA_ENDIAN_SHIFT) |
+ (0x03 << DMADESC_ENDIAN_SHIFT));
+ data |= (0x02 << DMADATA_ENDIAN_SHIFT) |
+ (0x02 << DMADESC_ENDIAN_SHIFT);
+ brcm_sata_writereg(data, ctrl);
+ } else
+ brcm_sata_writereg(BUS_CTRL_ENDIAN_CONF, ctrl);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int brcm_ahci_suspend(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ struct brcm_ahci_priv *priv = hpriv->plat_data;
+ int ret;
+
+ ret = ahci_platform_suspend(dev);
+ brcm_sata_phys_disable(priv);
+ return ret;
+}
+
+static int brcm_ahci_resume(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ struct brcm_ahci_priv *priv = hpriv->plat_data;
+
+ brcm_sata_init(priv);
+ brcm_sata_phys_enable(priv);
+ brcm_sata_alpm_init(hpriv);
+ return ahci_platform_resume(dev);
+}
+#endif
+
+static struct scsi_host_template ahci_platform_sht = {
+ AHCI_SHT(DRV_NAME),
+};
+
+static const struct of_device_id ahci_of_match[] = {
+ {.compatible = "brcm,bcm7425-ahci", .data = (void *)BRCM_SATA_BCM7425},
+ {.compatible = "brcm,bcm7445-ahci", .data = (void *)BRCM_SATA_BCM7445},
+ {.compatible = "brcm,bcm-nsp-ahci", .data = (void *)BRCM_SATA_NSP},
+ {},
+};
+MODULE_DEVICE_TABLE(of, ahci_of_match);
+
+static int brcm_ahci_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *of_id;
+ struct device *dev = &pdev->dev;
+ struct brcm_ahci_priv *priv;
+ struct ahci_host_priv *hpriv;
+ struct resource *res;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ of_id = of_match_node(ahci_of_match, pdev->dev.of_node);
+ if (!of_id)
+ return -ENODEV;
+
+ priv->version = (enum brcm_ahci_version)of_id->data;
+ priv->dev = dev;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "top-ctrl");
+ priv->top_ctrl = devm_ioremap_resource(dev, res);
+ if (IS_ERR(priv->top_ctrl))
+ return PTR_ERR(priv->top_ctrl);
+
+ if ((priv->version == BRCM_SATA_BCM7425) ||
+ (priv->version == BRCM_SATA_NSP)) {
+ priv->quirks |= BRCM_AHCI_QUIRK_NO_NCQ;
+ priv->quirks |= BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE;
+ }
+
+ brcm_sata_init(priv);
+
+ priv->port_mask = brcm_ahci_get_portmask(pdev, priv);
+ if (!priv->port_mask)
+ return -ENODEV;
+
+ brcm_sata_phys_enable(priv);
+
+ hpriv = ahci_platform_get_resources(pdev);
+ if (IS_ERR(hpriv))
+ return PTR_ERR(hpriv);
+ hpriv->plat_data = priv;
+ hpriv->flags = AHCI_HFLAG_WAKE_BEFORE_STOP;
+
+ brcm_sata_alpm_init(hpriv);
+
+ ret = ahci_platform_enable_resources(hpriv);
+ if (ret)
+ return ret;
+
+ if (priv->quirks & BRCM_AHCI_QUIRK_NO_NCQ)
+ hpriv->flags |= AHCI_HFLAG_NO_NCQ;
+
+ ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info,
+ &ahci_platform_sht);
+ if (ret)
+ return ret;
+
+ dev_info(dev, "Broadcom AHCI SATA3 registered\n");
+
+ return 0;
+}
+
+static int brcm_ahci_remove(struct platform_device *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ struct brcm_ahci_priv *priv = hpriv->plat_data;
+ int ret;
+
+ ret = ata_platform_remove_one(pdev);
+ if (ret)
+ return ret;
+
+ brcm_sata_phys_disable(priv);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(ahci_brcm_pm_ops, brcm_ahci_suspend, brcm_ahci_resume);
+
+static struct platform_driver brcm_ahci_driver = {
+ .probe = brcm_ahci_probe,
+ .remove = brcm_ahci_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = ahci_of_match,
+ .pm = &ahci_brcm_pm_ops,
+ },
+};
+module_platform_driver(brcm_ahci_driver);
+
+MODULE_DESCRIPTION("Broadcom SATA3 AHCI Controller Driver");
+MODULE_AUTHOR("Brian Norris");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sata-brcmstb");
+++ /dev/null
-/*
- * Broadcom SATA3 AHCI Controller Driver
- *
- * Copyright © 2009-2015 Broadcom Corporation
- *
- * 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, 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.
- */
-
-#include <linux/ahci_platform.h>
-#include <linux/compiler.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/libata.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/string.h>
-
-#include "ahci.h"
-
-#define DRV_NAME "brcm-ahci"
-
-#define SATA_TOP_CTRL_VERSION 0x0
-#define SATA_TOP_CTRL_BUS_CTRL 0x4
- #define MMIO_ENDIAN_SHIFT 0 /* CPU->AHCI */
- #define DMADESC_ENDIAN_SHIFT 2 /* AHCI->DDR */
- #define DMADATA_ENDIAN_SHIFT 4 /* AHCI->DDR */
- #define PIODATA_ENDIAN_SHIFT 6
- #define ENDIAN_SWAP_NONE 0
- #define ENDIAN_SWAP_FULL 2
- #define OVERRIDE_HWINIT BIT(16)
-#define SATA_TOP_CTRL_TP_CTRL 0x8
-#define SATA_TOP_CTRL_PHY_CTRL 0xc
- #define SATA_TOP_CTRL_PHY_CTRL_1 0x0
- #define SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE BIT(14)
- #define SATA_TOP_CTRL_PHY_CTRL_2 0x4
- #define SATA_TOP_CTRL_2_SW_RST_MDIOREG BIT(0)
- #define SATA_TOP_CTRL_2_SW_RST_OOB BIT(1)
- #define SATA_TOP_CTRL_2_SW_RST_RX BIT(2)
- #define SATA_TOP_CTRL_2_SW_RST_TX BIT(3)
- #define SATA_TOP_CTRL_2_PHY_GLOBAL_RESET BIT(14)
- #define SATA_TOP_CTRL_PHY_OFFS 0x8
- #define SATA_TOP_MAX_PHYS 2
-
-#define SATA_FIRST_PORT_CTRL 0x700
-#define SATA_NEXT_PORT_CTRL_OFFSET 0x80
-#define SATA_PORT_PCTRL6(reg_base) (reg_base + 0x18)
-
-/* On big-endian MIPS, buses are reversed to big endian, so switch them back */
-#if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN)
-#define DATA_ENDIAN 2 /* AHCI->DDR inbound accesses */
-#define MMIO_ENDIAN 2 /* CPU->AHCI outbound accesses */
-#else
-#define DATA_ENDIAN 0
-#define MMIO_ENDIAN 0
-#endif
-
-#define BUS_CTRL_ENDIAN_CONF \
- ((DATA_ENDIAN << DMADATA_ENDIAN_SHIFT) | \
- (DATA_ENDIAN << DMADESC_ENDIAN_SHIFT) | \
- (MMIO_ENDIAN << MMIO_ENDIAN_SHIFT))
-
-enum brcm_ahci_quirks {
- BRCM_AHCI_QUIRK_NO_NCQ = BIT(0),
- BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE = BIT(1),
-};
-
-struct brcm_ahci_priv {
- struct device *dev;
- void __iomem *top_ctrl;
- u32 port_mask;
- u32 quirks;
-};
-
-static const struct ata_port_info ahci_brcm_port_info = {
- .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,
- .link_flags = ATA_LFLAG_NO_DB_DELAY,
- .pio_mask = ATA_PIO4,
- .udma_mask = ATA_UDMA6,
- .port_ops = &ahci_platform_ops,
-};
-
-static inline u32 brcm_sata_readreg(void __iomem *addr)
-{
- /*
- * MIPS endianness is configured by boot strap, which also reverses all
- * bus endianness (i.e., big-endian CPU + big endian bus ==> native
- * endian I/O).
- *
- * Other architectures (e.g., ARM) either do not support big endian, or
- * else leave I/O in little endian mode.
- */
- if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
- return __raw_readl(addr);
- else
- return readl_relaxed(addr);
-}
-
-static inline void brcm_sata_writereg(u32 val, void __iomem *addr)
-{
- /* See brcm_sata_readreg() comments */
- if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
- __raw_writel(val, addr);
- else
- writel_relaxed(val, addr);
-}
-
-static void brcm_sata_alpm_init(struct ahci_host_priv *hpriv)
-{
- struct brcm_ahci_priv *priv = hpriv->plat_data;
- u32 bus_ctrl, port_ctrl, host_caps;
- int i;
-
- /* Enable support for ALPM */
- bus_ctrl = brcm_sata_readreg(priv->top_ctrl +
- SATA_TOP_CTRL_BUS_CTRL);
- brcm_sata_writereg(bus_ctrl | OVERRIDE_HWINIT,
- priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL);
- host_caps = readl(hpriv->mmio + HOST_CAP);
- writel(host_caps | HOST_CAP_ALPM, hpriv->mmio);
- brcm_sata_writereg(bus_ctrl, priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL);
-
- /*
- * Adjust timeout to allow PLL sufficient time to lock while waking
- * up from slumber mode.
- */
- for (i = 0, port_ctrl = SATA_FIRST_PORT_CTRL;
- i < SATA_TOP_MAX_PHYS;
- i++, port_ctrl += SATA_NEXT_PORT_CTRL_OFFSET) {
- if (priv->port_mask & BIT(i))
- writel(0xff1003fc,
- hpriv->mmio + SATA_PORT_PCTRL6(port_ctrl));
- }
-}
-
-static void brcm_sata_phy_enable(struct brcm_ahci_priv *priv, int port)
-{
- void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL +
- (port * SATA_TOP_CTRL_PHY_OFFS);
- void __iomem *p;
- u32 reg;
-
- if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE)
- return;
-
- /* clear PHY_DEFAULT_POWER_STATE */
- p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1;
- reg = brcm_sata_readreg(p);
- reg &= ~SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE;
- brcm_sata_writereg(reg, p);
-
- /* reset the PHY digital logic */
- p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2;
- reg = brcm_sata_readreg(p);
- reg &= ~(SATA_TOP_CTRL_2_SW_RST_MDIOREG | SATA_TOP_CTRL_2_SW_RST_OOB |
- SATA_TOP_CTRL_2_SW_RST_RX);
- reg |= SATA_TOP_CTRL_2_SW_RST_TX;
- brcm_sata_writereg(reg, p);
- reg = brcm_sata_readreg(p);
- reg |= SATA_TOP_CTRL_2_PHY_GLOBAL_RESET;
- brcm_sata_writereg(reg, p);
- reg = brcm_sata_readreg(p);
- reg &= ~SATA_TOP_CTRL_2_PHY_GLOBAL_RESET;
- brcm_sata_writereg(reg, p);
- (void)brcm_sata_readreg(p);
-}
-
-static void brcm_sata_phy_disable(struct brcm_ahci_priv *priv, int port)
-{
- void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL +
- (port * SATA_TOP_CTRL_PHY_OFFS);
- void __iomem *p;
- u32 reg;
-
- if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE)
- return;
-
- /* power-off the PHY digital logic */
- p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2;
- reg = brcm_sata_readreg(p);
- reg |= (SATA_TOP_CTRL_2_SW_RST_MDIOREG | SATA_TOP_CTRL_2_SW_RST_OOB |
- SATA_TOP_CTRL_2_SW_RST_RX | SATA_TOP_CTRL_2_SW_RST_TX |
- SATA_TOP_CTRL_2_PHY_GLOBAL_RESET);
- brcm_sata_writereg(reg, p);
-
- /* set PHY_DEFAULT_POWER_STATE */
- p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1;
- reg = brcm_sata_readreg(p);
- reg |= SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE;
- brcm_sata_writereg(reg, p);
-}
-
-static void brcm_sata_phys_enable(struct brcm_ahci_priv *priv)
-{
- int i;
-
- for (i = 0; i < SATA_TOP_MAX_PHYS; i++)
- if (priv->port_mask & BIT(i))
- brcm_sata_phy_enable(priv, i);
-}
-
-static void brcm_sata_phys_disable(struct brcm_ahci_priv *priv)
-{
- int i;
-
- for (i = 0; i < SATA_TOP_MAX_PHYS; i++)
- if (priv->port_mask & BIT(i))
- brcm_sata_phy_disable(priv, i);
-}
-
-static u32 brcm_ahci_get_portmask(struct platform_device *pdev,
- struct brcm_ahci_priv *priv)
-{
- void __iomem *ahci;
- struct resource *res;
- u32 impl;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ahci");
- ahci = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(ahci))
- return 0;
-
- impl = readl(ahci + HOST_PORTS_IMPL);
-
- if (fls(impl) > SATA_TOP_MAX_PHYS)
- dev_warn(priv->dev, "warning: more ports than PHYs (%#x)\n",
- impl);
- else if (!impl)
- dev_info(priv->dev, "no ports found\n");
-
- devm_iounmap(&pdev->dev, ahci);
- devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
-
- return impl;
-}
-
-static void brcm_sata_init(struct brcm_ahci_priv *priv)
-{
- /* Configure endianness */
- brcm_sata_writereg(BUS_CTRL_ENDIAN_CONF,
- priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int brcm_ahci_suspend(struct device *dev)
-{
- struct ata_host *host = dev_get_drvdata(dev);
- struct ahci_host_priv *hpriv = host->private_data;
- struct brcm_ahci_priv *priv = hpriv->plat_data;
- int ret;
-
- ret = ahci_platform_suspend(dev);
- brcm_sata_phys_disable(priv);
- return ret;
-}
-
-static int brcm_ahci_resume(struct device *dev)
-{
- struct ata_host *host = dev_get_drvdata(dev);
- struct ahci_host_priv *hpriv = host->private_data;
- struct brcm_ahci_priv *priv = hpriv->plat_data;
-
- brcm_sata_init(priv);
- brcm_sata_phys_enable(priv);
- brcm_sata_alpm_init(hpriv);
- return ahci_platform_resume(dev);
-}
-#endif
-
-static struct scsi_host_template ahci_platform_sht = {
- AHCI_SHT(DRV_NAME),
-};
-
-static int brcm_ahci_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct brcm_ahci_priv *priv;
- struct ahci_host_priv *hpriv;
- struct resource *res;
- int ret;
-
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
- priv->dev = dev;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "top-ctrl");
- priv->top_ctrl = devm_ioremap_resource(dev, res);
- if (IS_ERR(priv->top_ctrl))
- return PTR_ERR(priv->top_ctrl);
-
- if (of_device_is_compatible(dev->of_node, "brcm,bcm7425-ahci")) {
- priv->quirks |= BRCM_AHCI_QUIRK_NO_NCQ;
- priv->quirks |= BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE;
- }
-
- brcm_sata_init(priv);
-
- priv->port_mask = brcm_ahci_get_portmask(pdev, priv);
- if (!priv->port_mask)
- return -ENODEV;
-
- brcm_sata_phys_enable(priv);
-
- hpriv = ahci_platform_get_resources(pdev);
- if (IS_ERR(hpriv))
- return PTR_ERR(hpriv);
- hpriv->plat_data = priv;
- hpriv->flags = AHCI_HFLAG_WAKE_BEFORE_STOP;
-
- brcm_sata_alpm_init(hpriv);
-
- ret = ahci_platform_enable_resources(hpriv);
- if (ret)
- return ret;
-
- if (priv->quirks & BRCM_AHCI_QUIRK_NO_NCQ)
- hpriv->flags |= AHCI_HFLAG_NO_NCQ;
-
- ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info,
- &ahci_platform_sht);
- if (ret)
- return ret;
-
- dev_info(dev, "Broadcom AHCI SATA3 registered\n");
-
- return 0;
-}
-
-static int brcm_ahci_remove(struct platform_device *pdev)
-{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
- struct ahci_host_priv *hpriv = host->private_data;
- struct brcm_ahci_priv *priv = hpriv->plat_data;
- int ret;
-
- ret = ata_platform_remove_one(pdev);
- if (ret)
- return ret;
-
- brcm_sata_phys_disable(priv);
-
- return 0;
-}
-
-static const struct of_device_id ahci_of_match[] = {
- {.compatible = "brcm,bcm7425-ahci"},
- {.compatible = "brcm,bcm7445-ahci"},
- {},
-};
-MODULE_DEVICE_TABLE(of, ahci_of_match);
-
-static SIMPLE_DEV_PM_OPS(ahci_brcm_pm_ops, brcm_ahci_suspend, brcm_ahci_resume);
-
-static struct platform_driver brcm_ahci_driver = {
- .probe = brcm_ahci_probe,
- .remove = brcm_ahci_remove,
- .driver = {
- .name = DRV_NAME,
- .of_match_table = ahci_of_match,
- .pm = &ahci_brcm_pm_ops,
- },
-};
-module_platform_driver(brcm_ahci_driver);
-
-MODULE_DESCRIPTION("Broadcom SATA3 AHCI Controller Driver");
-MODULE_AUTHOR("Brian Norris");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:sata-brcmstb");
*/
pp->active_link = qc->dev->link;
- if (qc->tf.protocol == ATA_PROT_NCQ)
+ if (ata_is_ncq(qc->tf.protocol))
writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
if (pp->fbs_enabled && pp->fbs_last_dev != qc->dev->link->pmp) {
static void ahci_port_stop(struct ata_port *ap)
{
const char *emsg = NULL;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *host_mmio = hpriv->mmio;
int rc;
/* de-initialize port */
rc = ahci_deinit_port(ap, &emsg);
if (rc)
ata_port_warn(ap, "%s (%d)\n", emsg, rc);
+
+ /*
+ * Clear GHC.IS to prevent stuck INTx after disabling MSI and
+ * re-enabling INTx.
+ */
+ writel(1 << ap->port_no, host_mmio + HOST_IRQ_STAT);
}
void ahci_print_info(struct ata_host *host, const char *scc_s)
} else
tf.command = ATA_CMD_READ_NATIVE_MAX;
- tf.protocol |= ATA_PROT_NODATA;
+ tf.protocol = ATA_PROT_NODATA;
tf.device |= ATA_LBA;
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
tf.device |= (new_sectors >> 24) & 0xf;
}
- tf.protocol |= ATA_PROT_NODATA;
+ tf.protocol = ATA_PROT_NODATA;
tf.device |= ATA_LBA;
tf.lbal = (new_sectors >> 0) & 0xff;
{
struct ata_link *link = qc->dev->link;
- if (qc->tf.protocol == ATA_PROT_NCQ) {
+ if (ata_is_ncq(qc->tf.protocol)) {
if (!ata_tag_valid(link->active_tag))
return 0;
} else {
ata_sg_clean(qc);
/* command should be marked inactive atomically with qc completion */
- if (qc->tf.protocol == ATA_PROT_NCQ) {
+ if (ata_is_ncq(qc->tf.protocol)) {
link->sactive &= ~(1 << qc->tag);
if (!link->sactive)
ap->nr_active_links--;
{
struct ata_device *dev = qc->dev;
- if (ata_is_nodata(qc->tf.protocol))
+ if (!ata_is_data(qc->tf.protocol))
return;
if ((dev->mwdma_mask || dev->udma_mask) && ata_is_pio(qc->tf.protocol))
switch (qc->tf.command) {
case ATA_CMD_SET_FEATURES:
if (qc->tf.feature != SETFEATURES_WC_ON &&
- qc->tf.feature != SETFEATURES_WC_OFF)
+ qc->tf.feature != SETFEATURES_WC_OFF &&
+ qc->tf.feature != SETFEATURES_RA_ON &&
+ qc->tf.feature != SETFEATURES_RA_OFF)
break;
/* fall through */
case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */
[DMA_FROM_DEVICE] = "in",
};
static const char *prot_str[] = {
+ [ATA_PROT_UNKNOWN] = "unknown",
+ [ATA_PROT_NODATA] = "nodata",
[ATA_PROT_PIO] = "pio",
[ATA_PROT_DMA] = "dma",
- [ATA_PROT_NCQ] = "ncq",
+ [ATA_PROT_NCQ] = "ncq dma",
+ [ATA_PROT_NCQ_NODATA] = "ncq nodata",
+ [ATAPI_PROT_NODATA] = "nodata",
[ATAPI_PROT_PIO] = "pio",
[ATAPI_PROT_DMA] = "dma",
};
}
tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
- tf.protocol |= ATA_PROT_NODATA;
+ tf.protocol = ATA_PROT_NODATA;
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
if (park && (err_mask || tf.lbal != 0xc4)) {
ata_dev_err(dev, "head unload failed!\n");
struct scsi_cmnd *cmd, u16 field, u8 bit)
{
ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x24, 0x0);
- /* "Invalid field in cbd" */
+ /* "Invalid field in CDB" */
scsi_set_sense_field_pointer(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
field, bit, 1);
}
0x03,
0x20, /* SBC-2 (no version claimed) */
- 0x02,
- 0x60 /* SPC-3 (no version claimed) */
+ 0x03,
+ 0x00 /* SPC-3 (no version claimed) */
};
const u8 versions_zbc[] = {
0x00,
0,
0x5, /* claim SPC-3 version compatibility */
2,
- 95 - 4
+ 95 - 4,
+ 0,
+ 0,
+ 2
};
VPRINTK("ENTER\n");
(args->dev->link->ap->pflags & ATA_PFLAG_EXTERNAL))
hdr[1] |= (1 << 7);
- if (args->dev->class == ATA_DEV_ZAC)
+ if (args->dev->class == ATA_DEV_ZAC) {
hdr[0] = TYPE_ZBC;
+ hdr[2] = 0x7; /* claim SPC-5 version compatibility */
+ }
memcpy(rbuf, hdr, sizeof(hdr));
memcpy(&rbuf[8], "ATA ", 8);
* with the unmap bit set.
*/
if (ata_id_has_trim(args->id)) {
- put_unaligned_be64(65535 * 512 / 8, &rbuf[36]);
+ put_unaligned_be64(65535 * ATA_MAX_TRIM_RNUM, &rbuf[36]);
put_unaligned_be32(1, &rbuf[28]);
}
static unsigned int ata_msense_caching(u16 *id, u8 *buf, bool changeable)
{
modecpy(buf, def_cache_mpage, sizeof(def_cache_mpage), changeable);
- if (changeable || ata_id_wcache_enabled(id))
- buf[2] |= (1 << 2); /* write cache enable */
- if (!changeable && !ata_id_rahead_enabled(id))
- buf[12] |= (1 << 5); /* disable read ahead */
+ if (changeable) {
+ buf[2] |= (1 << 2); /* ata_mselect_caching() */
+ } else {
+ buf[2] |= (ata_id_wcache_enabled(id) << 2); /* write cache enable */
+ buf[12] |= (!ata_id_rahead_enabled(id) << 5); /* disable read ahead */
+ }
return sizeof(def_cache_mpage);
}
/**
- * ata_msense_ctl_mode - Simulate MODE SENSE control mode page
+ * ata_msense_control - Simulate MODE SENSE control mode page
* @dev: ATA device of interest
* @buf: output buffer
* @changeable: whether changeable parameters are requested
* LOCKING:
* None.
*/
-static unsigned int ata_msense_ctl_mode(struct ata_device *dev, u8 *buf,
+static unsigned int ata_msense_control(struct ata_device *dev, u8 *buf,
bool changeable)
{
modecpy(buf, def_control_mpage, sizeof(def_control_mpage), changeable);
- if (changeable && (dev->flags & ATA_DFLAG_D_SENSE))
- buf[2] |= (1 << 2); /* Descriptor sense requested */
+ if (changeable) {
+ buf[2] |= (1 << 2); /* ata_mselect_control() */
+ } else {
+ bool d_sense = (dev->flags & ATA_DFLAG_D_SENSE);
+
+ buf[2] |= (d_sense << 2); /* descriptor format sense data */
+ }
return sizeof(def_control_mpage);
}
break;
case CONTROL_MPAGE:
- p += ata_msense_ctl_mode(args->dev, p, page_control == 1);
+ p += ata_msense_control(args->dev, p, page_control == 1);
break;
case ALL_MPAGES:
p += ata_msense_rw_recovery(p, page_control == 1);
p += ata_msense_caching(args->id, p, page_control == 1);
- p += ata_msense_ctl_mode(args->dev, p, page_control == 1);
+ p += ata_msense_control(args->dev, p, page_control == 1);
break;
default: /* invalid page code */
goto invalid_fld;
}
+ if (ata_is_ncq(tf->protocol) && (cdb[2] & 0x3) == 0)
+ tf->protocol = ATA_PROT_NCQ_NODATA;
+
/* enable LBA */
tf->flags |= ATA_TFLAG_LBA;
tf->command = cdb[9];
}
- /* For NCQ commands with FPDMA protocol, copy the tag value */
- if (tf->protocol == ATA_PROT_NCQ)
+ /* For NCQ commands copy the tag value */
+ if (ata_is_ncq(tf->protocol))
tf->nsect = qc->tag << 3;
/* enforce correct master/slave bit */
goto invalid_param_len;
buf = page_address(sg_page(scsi_sglist(scmd)));
- size = ata_set_lba_range_entries(buf, 512, block, n_block);
+
+ if (n_block <= 65535 * ATA_MAX_TRIM_RNUM) {
+ size = ata_set_lba_range_entries(buf, ATA_MAX_TRIM_RNUM, block, n_block);
+ } else {
+ fp = 2;
+ goto invalid_fld;
+ }
if (ata_ncq_enabled(dev) && ata_fpdma_dsm_supported(dev)) {
/* Newer devices support queued TRIM commands */
goto invalid_param_len;
}
sect = n_block / 512;
- options = cdb[14];
+ options = cdb[14] & 0xbf;
if (ata_ncq_enabled(qc->dev) &&
ata_fpdma_zac_mgmt_in_supported(qc->dev)) {
tf->nsect = qc->tag << 3;
tf->feature = sect & 0xff;
tf->hob_feature = (sect >> 8) & 0xff;
- tf->auxiliary = ATA_SUBCMD_ZAC_MGMT_IN_REPORT_ZONES;
+ tf->auxiliary = ATA_SUBCMD_ZAC_MGMT_IN_REPORT_ZONES | (options << 8);
} else {
tf->command = ATA_CMD_ZAC_MGMT_IN;
tf->feature = ATA_SUBCMD_ZAC_MGMT_IN_REPORT_ZONES;
struct scsi_cmnd *scmd = qc->scsicmd;
struct ata_device *dev = qc->dev;
const u8 *cdb = scmd->cmnd;
- u8 reset_all, sa;
+ u8 all, sa;
u64 block;
u32 n_block;
u16 fp = (u16)-1;
if (block > dev->n_sectors)
goto out_of_range;
- reset_all = cdb[14] & 0x1;
+ all = cdb[14] & 0x1;
if (ata_ncq_enabled(qc->dev) &&
ata_fpdma_zac_mgmt_out_supported(qc->dev)) {
- tf->protocol = ATA_PROT_NCQ;
+ tf->protocol = ATA_PROT_NCQ_NODATA;
tf->command = ATA_CMD_NCQ_NON_DATA;
- tf->hob_nsect = ATA_SUBCMD_NCQ_NON_DATA_ZAC_MGMT_OUT;
+ tf->feature = ATA_SUBCMD_NCQ_NON_DATA_ZAC_MGMT_OUT;
tf->nsect = qc->tag << 3;
- tf->auxiliary = sa | (reset_all & 0x1) << 8;
+ tf->auxiliary = sa | ((u16)all << 8);
} else {
tf->protocol = ATA_PROT_NODATA;
tf->command = ATA_CMD_ZAC_MGMT_OUT;
tf->feature = sa;
- tf->hob_feature = reset_all & 0x1;
+ tf->hob_feature = all;
}
tf->lbah = (block >> 16) & 0xff;
tf->lbam = (block >> 8) & 0xff;
/*
* Check that read-only bits are not modified.
*/
- ata_msense_ctl_mode(dev, mpage, false);
+ ata_msense_control(dev, mpage, false);
for (i = 0; i < CONTROL_MPAGE_LEN - 2; i++) {
if (i == 0)
continue;
args.done = cmd->scsi_done;
switch(scsicmd[0]) {
- /* TODO: worth improving? */
- case FORMAT_UNIT:
- ata_scsi_invalid_field(dev, cmd, 0);
- break;
-
case INQUIRY:
if (scsicmd[1] & 2) /* is CmdDt set? */
ata_scsi_invalid_field(dev, cmd, 1);
static int ata_show_ering(struct ata_ering_entry *ent, void *void_arg)
{
struct ata_show_ering_arg* arg = void_arg;
- struct timespec time;
+ u64 seconds;
+ u32 rem;
- jiffies_to_timespec(ent->timestamp,&time);
+ seconds = div_u64_rem(ent->timestamp, HZ, &rem);
arg->written += sprintf(arg->buf + arg->written,
- "[%5lu.%06lu]",
- time.tv_sec, time.tv_nsec);
+ "[%5llu.%09lu]", seconds,
+ rem * NSEC_PER_SEC / HZ);
arg->written += get_ata_err_names(ent->err_mask,
arg->buf + arg->written);
return 0;
qc->ap->hsm_task_state = HSM_ST_ERR;
cf_ctrl_reset(acdev);
- spin_unlock_irqrestore(qc->ap->lock, flags);
+ spin_unlock_irqrestore(&acdev->host->lock, flags);
sff_intr:
dma_complete(acdev);
}
* We must now look at the PIO mode situation. We may need to
* adjust the PIO mode to keep the timings acceptable
*/
- if (adev->dma_mode >= XFER_MW_DMA_2)
- wanted_pio = 4;
+ if (adev->dma_mode >= XFER_MW_DMA_2)
+ wanted_pio = 4;
else if (adev->dma_mode == XFER_MW_DMA_1)
wanted_pio = 3;
else if (adev->dma_mode == XFER_MW_DMA_0)
/* PCI clocking determines the ATA timing values to use */
/* info_hpt366 is safe against re-entry so we can scribble on it */
- switch ((reg1 & 0x700) >> 8) {
+ switch ((reg1 & 0xf00) >> 8) {
case 9:
hpriv = &hpt366_40;
break;
if (pdev->device == 0x6101)
ppi[1] = &ata_dummy_port_info;
-#if defined(CONFIG_SATA_AHCI) || defined(CONFIG_SATA_AHCI_MODULE)
+#if IS_ENABLED(CONFIG_SATA_AHCI)
if (!marvell_pata_active(pdev)) {
printk(KERN_INFO DRV_NAME ": PATA port not active, deferring to AHCI driver.\n");
return -ENODEV;
/* Get physical SATA DMA register base address */
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
hsdev->dma->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(hsdev->dma->regs)) {
- dev_err(&pdev->dev,
- "ioremap failed for AHBDMA register address\n");
+ if (IS_ERR(hsdev->dma->regs))
return PTR_ERR(hsdev->dma->regs);
- }
/* Initialize AHB DMAC */
return dw_dma_probe(hsdev->dma);
static const char *get_prot_descript(u8 protocol)
{
- switch ((enum ata_tf_protocols)protocol) {
+ switch (protocol) {
case ATA_PROT_NODATA:
return "ATA no data";
case ATA_PROT_PIO:
return "ATA DMA";
case ATA_PROT_NCQ:
return "ATA NCQ";
+ case ATA_PROT_NCQ_NODATA:
+ return "ATA NCQ no data";
case ATAPI_PROT_NODATA:
return "ATAPI no data";
case ATAPI_PROT_PIO:
/* Ioremap SATA registers */
res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&ofdev->dev, res);
- if (IS_ERR(base)) {
- dev_err(&ofdev->dev,
- "ioremap failed for SATA register address\n");
+ if (IS_ERR(base))
return PTR_ERR(base);
- }
dev_dbg(&ofdev->dev, "ioremap done for SATA register address\n");
/* Synopsys DWC SATA specific Registers */
BRCM_SATA_PHY_STB_28NM,
BRCM_SATA_PHY_STB_40NM,
BRCM_SATA_PHY_IPROC_NS2,
+ BRCM_SATA_PHY_IPROC_NSP,
};
struct brcm_sata_port {
PLL_REG_BANK_0 = 0x050,
PLL_REG_BANK_0_PLLCONTROL_0 = 0x81,
+ PLLCONTROL_0_FREQ_DET_RESTART = BIT(13),
+ PLLCONTROL_0_FREQ_MONITOR = BIT(12),
+ PLLCONTROL_0_SEQ_START = BIT(15),
+ PLL_CAP_CONTROL = 0x85,
+ PLL_ACTRL2 = 0x8b,
+ PLL_ACTRL2_SELDIV_MASK = 0x1f,
+ PLL_ACTRL2_SELDIV_SHIFT = 9,
PLL1_REG_BANK = 0x060,
PLL1_ACTRL2 = 0x82,
PLL1_ACTRL4 = 0x84,
OOB_REG_BANK = 0x150,
+ OOB1_REG_BANK = 0x160,
OOB_CTRL1 = 0x80,
OOB_CTRL1_BURST_MAX_MASK = 0xf,
OOB_CTRL1_BURST_MAX_SHIFT = 12,
return 0;
}
+static int brcm_nsp_sata_init(struct brcm_sata_port *port)
+{
+ struct brcm_sata_phy *priv = port->phy_priv;
+ struct device *dev = port->phy_priv->dev;
+ void __iomem *base = priv->phy_base;
+ unsigned int oob_bank;
+ unsigned int val, try;
+
+ /* Configure OOB control */
+ if (port->portnum == 0)
+ oob_bank = OOB_REG_BANK;
+ else if (port->portnum == 1)
+ oob_bank = OOB1_REG_BANK;
+ else
+ return -EINVAL;
+
+ val = 0x0;
+ val |= (0x0f << OOB_CTRL1_BURST_MAX_SHIFT);
+ val |= (0x06 << OOB_CTRL1_BURST_MIN_SHIFT);
+ val |= (0x0f << OOB_CTRL1_WAKE_IDLE_MAX_SHIFT);
+ val |= (0x06 << OOB_CTRL1_WAKE_IDLE_MIN_SHIFT);
+ brcm_sata_phy_wr(base, oob_bank, OOB_CTRL1, 0x0, val);
+
+ val = 0x0;
+ val |= (0x2e << OOB_CTRL2_RESET_IDLE_MAX_SHIFT);
+ val |= (0x02 << OOB_CTRL2_BURST_CNT_SHIFT);
+ val |= (0x16 << OOB_CTRL2_RESET_IDLE_MIN_SHIFT);
+ brcm_sata_phy_wr(base, oob_bank, OOB_CTRL2, 0x0, val);
+
+
+ brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_ACTRL2,
+ ~(PLL_ACTRL2_SELDIV_MASK << PLL_ACTRL2_SELDIV_SHIFT),
+ 0x0c << PLL_ACTRL2_SELDIV_SHIFT);
+
+ brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_CAP_CONTROL,
+ 0xff0, 0x4f0);
+
+ val = PLLCONTROL_0_FREQ_DET_RESTART | PLLCONTROL_0_FREQ_MONITOR;
+ brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
+ ~val, val);
+ val = PLLCONTROL_0_SEQ_START;
+ brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
+ ~val, 0);
+ mdelay(10);
+ brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
+ ~val, val);
+
+ /* Wait for pll_seq_done bit */
+ try = 50;
+ while (try--) {
+ val = brcm_sata_phy_rd(base, BLOCK0_REG_BANK,
+ BLOCK0_XGXSSTATUS);
+ if (val & BLOCK0_XGXSSTATUS_PLL_LOCK)
+ break;
+ msleep(20);
+ }
+ if (!try) {
+ /* PLL did not lock; give up */
+ dev_err(dev, "port%d PLL did not lock\n", port->portnum);
+ return -ETIMEDOUT;
+ }
+
+ dev_dbg(dev, "port%d initialized\n", port->portnum);
+
+ return 0;
+}
+
static int brcm_sata_phy_init(struct phy *phy)
{
int rc;
case BRCM_SATA_PHY_IPROC_NS2:
rc = brcm_ns2_sata_init(port);
break;
+ case BRCM_SATA_PHY_IPROC_NSP:
+ rc = brcm_nsp_sata_init(port);
+ break;
default:
rc = -ENODEV;
};
.data = (void *)BRCM_SATA_PHY_STB_40NM },
{ .compatible = "brcm,iproc-ns2-sata-phy",
.data = (void *)BRCM_SATA_PHY_IPROC_NS2 },
+ { .compatible = "brcm,iproc-nsp-sata-phy",
+ .data = (void *)BRCM_SATA_PHY_IPROC_NSP },
{},
};
MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match);
task->task_state_flags = SAS_TASK_STATE_PENDING;
qc->lldd_task = task;
- switch (qc->tf.protocol) {
- case ATA_PROT_NCQ:
- task->ata_task.use_ncq = 1;
- /* fall through */
- case ATAPI_PROT_DMA:
- case ATA_PROT_DMA:
- task->ata_task.dma_xfer = 1;
- break;
- }
+ task->ata_task.use_ncq = ata_is_ncq(qc->tf.protocol);
+ task->ata_task.dma_xfer = ata_is_dma(qc->tf.protocol);
if (qc->scsicmd)
ASSIGN_SAS_TASK(qc->scsicmd, task);
ATA_MAX_SECTORS_128 = 128,
ATA_MAX_SECTORS = 256,
ATA_MAX_SECTORS_1024 = 1024,
- ATA_MAX_SECTORS_LBA48 = 65535,/* TODO: 65536? */
+ ATA_MAX_SECTORS_LBA48 = 65535,/* avoid count to be 0000h */
ATA_MAX_SECTORS_TAPE = 65535,
+ ATA_MAX_TRIM_RNUM = 64, /* 512-byte payload / (6-byte LBA + 2-byte range per entry) */
ATA_ID_WORDS = 256,
ATA_ID_CONFIG = 0,
SETFEATURES_WC_ON = 0x02, /* Enable write cache */
SETFEATURES_WC_OFF = 0x82, /* Disable write cache */
+ SETFEATURES_RA_ON = 0xaa, /* Enable read look-ahead */
+ SETFEATURES_RA_OFF = 0x55, /* Disable read look-ahead */
+
/* Enable/Disable Automatic Acoustic Management */
SETFEATURES_AAM_ON = 0x42,
SETFEATURES_AAM_OFF = 0xC2,
SERR_DEV_XCHG = (1 << 26), /* device exchanged */
};
-enum ata_tf_protocols {
- /* ATA taskfile protocols */
- ATA_PROT_UNKNOWN, /* unknown/invalid */
- ATA_PROT_NODATA, /* no data */
- ATA_PROT_PIO, /* PIO data xfer */
- ATA_PROT_DMA, /* DMA */
- ATA_PROT_NCQ, /* NCQ */
- ATAPI_PROT_NODATA, /* packet command, no data */
- ATAPI_PROT_PIO, /* packet command, PIO data xfer*/
- ATAPI_PROT_DMA, /* packet command with special DMA sauce */
+enum ata_prot_flags {
+ /* protocol flags */
+ ATA_PROT_FLAG_PIO = (1 << 0), /* is PIO */
+ ATA_PROT_FLAG_DMA = (1 << 1), /* is DMA */
+ ATA_PROT_FLAG_NCQ = (1 << 2), /* is NCQ */
+ ATA_PROT_FLAG_ATAPI = (1 << 3), /* is ATAPI */
+
+ /* taskfile protocols */
+ ATA_PROT_UNKNOWN = (u8)-1,
+ ATA_PROT_NODATA = 0,
+ ATA_PROT_PIO = ATA_PROT_FLAG_PIO,
+ ATA_PROT_DMA = ATA_PROT_FLAG_DMA,
+ ATA_PROT_NCQ_NODATA = ATA_PROT_FLAG_NCQ,
+ ATA_PROT_NCQ = ATA_PROT_FLAG_DMA | ATA_PROT_FLAG_NCQ,
+ ATAPI_PROT_NODATA = ATA_PROT_FLAG_ATAPI,
+ ATAPI_PROT_PIO = ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_PIO,
+ ATAPI_PROT_DMA = ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_DMA,
};
enum ata_ioctls {
* TO NV CACHE PINNED SET.
*/
static inline unsigned ata_set_lba_range_entries(void *_buffer,
- unsigned buf_size, u64 sector, unsigned long count)
+ unsigned num, u64 sector, unsigned long count)
{
__le64 *buffer = _buffer;
unsigned i = 0, used_bytes;
- while (i < buf_size / 8 ) { /* 6-byte LBA + 2-byte range per entry */
+ while (i < num) {
u64 entry = sector |
((u64)(count > 0xffff ? 0xffff : count) << 48);
buffer[i++] = __cpu_to_le64(entry);
static inline bool lba_28_ok(u64 block, u32 n_block)
{
/* check the ending block number: must be LESS THAN 0x0fffffff */
- return ((block + n_block) < ((1 << 28) - 1)) && (n_block <= 256);
+ return ((block + n_block) < ((1 << 28) - 1)) && (n_block <= ATA_MAX_SECTORS);
}
static inline bool lba_48_ok(u64 block, u32 n_block)
{
/* check the ending block number */
- return ((block + n_block - 1) < ((u64)1 << 48)) && (n_block <= 65536);
+ return ((block + n_block - 1) < ((u64)1 << 48)) && (n_block <= ATA_MAX_SECTORS_LBA48);
}
#define sata_pmp_gscr_vendor(gscr) ((gscr)[SATA_PMP_GSCR_PROD_ID] & 0xffff)
ATA_TFLAG_FUA = (1 << 5), /* enable FUA */
ATA_TFLAG_POLLING = (1 << 6), /* set nIEN to 1 and use polling */
- /* protocol flags */
- ATA_PROT_FLAG_PIO = (1 << 0), /* is PIO */
- ATA_PROT_FLAG_DMA = (1 << 1), /* is DMA */
- ATA_PROT_FLAG_DATA = ATA_PROT_FLAG_PIO | ATA_PROT_FLAG_DMA,
- ATA_PROT_FLAG_NCQ = (1 << 2), /* is NCQ */
- ATA_PROT_FLAG_ATAPI = (1 << 3), /* is ATAPI */
-
/* struct ata_device stuff */
ATA_DFLAG_LBA = (1 << 0), /* device supports LBA */
ATA_DFLAG_LBA48 = (1 << 1), /* device supports LBA48 */
extern struct ata_port_operations ata_dummy_port_ops;
extern const struct ata_port_info ata_dummy_port_info;
-/*
- * protocol tests
- */
-static inline unsigned int ata_prot_flags(u8 prot)
-{
- switch (prot) {
- case ATA_PROT_NODATA:
- return 0;
- case ATA_PROT_PIO:
- return ATA_PROT_FLAG_PIO;
- case ATA_PROT_DMA:
- return ATA_PROT_FLAG_DMA;
- case ATA_PROT_NCQ:
- return ATA_PROT_FLAG_DMA | ATA_PROT_FLAG_NCQ;
- case ATAPI_PROT_NODATA:
- return ATA_PROT_FLAG_ATAPI;
- case ATAPI_PROT_PIO:
- return ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_PIO;
- case ATAPI_PROT_DMA:
- return ATA_PROT_FLAG_ATAPI | ATA_PROT_FLAG_DMA;
- }
- return 0;
-}
-
-static inline int ata_is_atapi(u8 prot)
-{
- return ata_prot_flags(prot) & ATA_PROT_FLAG_ATAPI;
-}
-
-static inline int ata_is_nodata(u8 prot)
+static inline bool ata_is_atapi(u8 prot)
{
- return !(ata_prot_flags(prot) & ATA_PROT_FLAG_DATA);
+ return prot & ATA_PROT_FLAG_ATAPI;
}
-static inline int ata_is_pio(u8 prot)
+static inline bool ata_is_pio(u8 prot)
{
- return ata_prot_flags(prot) & ATA_PROT_FLAG_PIO;
+ return prot & ATA_PROT_FLAG_PIO;
}
-static inline int ata_is_dma(u8 prot)
+static inline bool ata_is_dma(u8 prot)
{
- return ata_prot_flags(prot) & ATA_PROT_FLAG_DMA;
+ return prot & ATA_PROT_FLAG_DMA;
}
-static inline int ata_is_ncq(u8 prot)
+static inline bool ata_is_ncq(u8 prot)
{
- return ata_prot_flags(prot) & ATA_PROT_FLAG_NCQ;
+ return prot & ATA_PROT_FLAG_NCQ;
}
-static inline int ata_is_data(u8 prot)
+static inline bool ata_is_data(u8 prot)
{
- return ata_prot_flags(prot) & ATA_PROT_FLAG_DATA;
+ return prot & (ATA_PROT_FLAG_PIO | ATA_PROT_FLAG_DMA);
}
static inline int is_multi_taskfile(struct ata_taskfile *tf)
return ap->nr_pmp_links != 0;
}
-static inline int ata_is_host_link(const struct ata_link *link)
+static inline bool ata_is_host_link(const struct ata_link *link)
{
return link == &link->ap->link || link == link->ap->slave_link;
}
return false;
}
-static inline int ata_is_host_link(const struct ata_link *link)
+static inline bool ata_is_host_link(const struct ata_link *link)
{
return 1;
}
ata_protocol_name(ATA_PROT_PIO), \
ata_protocol_name(ATA_PROT_DMA), \
ata_protocol_name(ATA_PROT_NCQ), \
+ ata_protocol_name(ATA_PROT_NCQ_NODATA), \
ata_protocol_name(ATAPI_PROT_NODATA), \
ata_protocol_name(ATAPI_PROT_PIO), \
ata_protocol_name(ATAPI_PROT_DMA))