From 462098b090897fbcf00088b225eb7a3adc407e98 Mon Sep 17 00:00:00 2001 From: Levente Kurusa Date: Tue, 29 Oct 2013 20:01:46 +0100 Subject: [PATCH 01/20] ata: libata-eh: Remove unnecessary snprintf arithmetic Remove an unnecessary arithmetic operation from a call to snprintf, because the size parameter of snprintf includes the trailing null space. Also, initialize the buffer on definition instead of a memset call. Signed-off-by: Levente Kurusa Signed-off-by: Tejun Heo --- drivers/ata/libata-eh.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 92d7797223be..6d8757008318 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2402,7 +2402,7 @@ static void ata_eh_link_report(struct ata_link *link) struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; const char *frozen, *desc; - char tries_buf[6]; + char tries_buf[6] = ""; int tag, nr_failed = 0; if (ehc->i.flags & ATA_EHI_QUIET) @@ -2433,9 +2433,8 @@ static void ata_eh_link_report(struct ata_link *link) if (ap->pflags & ATA_PFLAG_FROZEN) frozen = " frozen"; - memset(tries_buf, 0, sizeof(tries_buf)); if (ap->eh_tries < ATA_EH_MAX_TRIES) - snprintf(tries_buf, sizeof(tries_buf) - 1, " t%d", + snprintf(tries_buf, sizeof(tries_buf), " t%d", ap->eh_tries); if (ehc->i.dev) { From cb85696d7277592ddbd2897db9a29f3ec6e9fe11 Mon Sep 17 00:00:00 2001 From: James Laird Date: Tue, 19 Nov 2013 11:06:38 +1100 Subject: [PATCH 02/20] ahci: mcp89: enter AHCI mode under Apple BIOS emulation Apple's BIOS emulation forcibly disables MCP89 AHCI, eg. on Macbook7,1. We can re-enable it, replacing the previous workaround of using ata_generic. tj: whitespace adjustments, dropped inline from is_mcp89_apple() Signed-off-by: James Laird Signed-off-by: Tejun Heo --- drivers/ata/ahci.c | 60 +++++++++++++++++++++++++++++++++------ drivers/ata/ata_generic.c | 7 ----- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index e2903d03180e..c55e00562527 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -83,6 +83,8 @@ enum board_ids { static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); +static void ahci_mcp89_apple_enable(struct pci_dev *pdev); +static bool is_mcp89_apple(struct pci_dev *pdev); static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); #ifdef CONFIG_PM @@ -659,6 +661,10 @@ static int ahci_pci_device_resume(struct pci_dev *pdev) if (rc) return rc; + /* Apple BIOS helpfully mangles the registers on resume */ + if (is_mcp89_apple(pdev)) + ahci_mcp89_apple_enable(pdev); + if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { rc = ahci_pci_reset_controller(host); if (rc) @@ -775,6 +781,48 @@ static void ahci_p5wdh_workaround(struct ata_host *host) } } +/* + * Macbook7,1 firmware forcibly disables MCP89 AHCI and changes PCI ID when + * booting in BIOS compatibility mode. We restore the registers but not ID. + */ +static void ahci_mcp89_apple_enable(struct pci_dev *pdev) +{ + u32 val; + + printk(KERN_INFO "ahci: enabling MCP89 AHCI mode\n"); + + pci_read_config_dword(pdev, 0xf8, &val); + val |= 1 << 0x1b; + /* the following changes the device ID, but appears not to affect function */ + /* val = (val & ~0xf0000000) | 0x80000000; */ + pci_write_config_dword(pdev, 0xf8, val); + + pci_read_config_dword(pdev, 0x54c, &val); + val |= 1 << 0xc; + pci_write_config_dword(pdev, 0x54c, val); + + pci_read_config_dword(pdev, 0x4a4, &val); + val &= 0xff; + val |= 0x01060100; + pci_write_config_dword(pdev, 0x4a4, val); + + pci_read_config_dword(pdev, 0x54c, &val); + val &= ~(1 << 0xc); + pci_write_config_dword(pdev, 0x54c, val); + + pci_read_config_dword(pdev, 0xf8, &val); + val &= ~(1 << 0x1b); + pci_write_config_dword(pdev, 0xf8, val); +} + +static bool is_mcp89_apple(struct pci_dev *pdev) +{ + return pdev->vendor == PCI_VENDOR_ID_NVIDIA && + pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA && + pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE && + pdev->subsystem_device == 0xcb89; +} + /* only some SB600 ahci controllers can do 64bit DMA */ static bool ahci_sb600_enable_64bit(struct pci_dev *pdev) { @@ -1207,15 +1255,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (pdev->vendor == PCI_VENDOR_ID_MARVELL && !marvell_enable) return -ENODEV; - /* - * For some reason, MCP89 on MacBook 7,1 doesn't work with - * ahci, use ata_generic instead. - */ - if (pdev->vendor == PCI_VENDOR_ID_NVIDIA && - pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA && - pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE && - pdev->subsystem_device == 0xcb89) - return -ENODEV; + /* Apple BIOS on MCP89 prevents us using AHCI */ + if (is_mcp89_apple(pdev)) + ahci_mcp89_apple_enable(pdev); /* Promise's PDC42819 is a SAS/SATA controller that has an AHCI mode. * At the moment, we can only use the AHCI mode. Let the users know diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index f8f38a08abc5..7d196656adb5 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -221,13 +221,6 @@ static struct pci_device_id ata_generic[] = { { PCI_DEVICE(PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558), }, { PCI_DEVICE(PCI_VENDOR_ID_CENATEK,PCI_DEVICE_ID_CENATEK_IDE), .driver_data = ATA_GEN_FORCE_DMA }, - /* - * For some reason, MCP89 on MacBook 7,1 doesn't work with - * ahci, use ata_generic instead. - */ - { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA, - PCI_VENDOR_ID_APPLE, 0xcb89, - .driver_data = ATA_GEN_FORCE_DMA }, #if !defined(CONFIG_PATA_TOSHIBA) && !defined(CONFIG_PATA_TOSHIBA_MODULE) { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), }, { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), }, From e67adb4e669db834c1f95cbdf99bb4e9ec8455b3 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Fri, 8 Nov 2013 16:09:29 +0400 Subject: [PATCH 03/20] sata_rcar: Add R-Car Gen2 SATA PHY support R-Car Gen2 SoCs have a different PHY which is not compatible with the older R-Car H1 (R8A7779) version. This adds OF/platform device id tables and PHY initialization callbacks for the following Gen2 SoCs: * R-Car H2: R8A7790; * R-Car M2: R8A7791. PHY initialization method is chosen based on the device id. Default PHY settings are applied for Gen2 SoCs, which should suit the Gen2 boards available. While at it, this also adds "sata-r8a7779" compatibility string for R8A7779 SATA, while keeping the old one for compatibility. Signed-off-by: Valentine Barshak Signed-off-by: Tejun Heo --- drivers/ata/sata_rcar.c | 118 ++++++++++++++++++++++++++++++++++------ 1 file changed, 102 insertions(+), 16 deletions(-) diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index 1dae9a9009f7..2b25bd83fc9d 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -123,12 +124,37 @@ #define SATA_RCAR_DMA_BOUNDARY 0x1FFFFFFEUL +/* Gen2 Physical Layer Control Registers */ +#define RCAR_GEN2_PHY_CTL1_REG 0x1704 +#define RCAR_GEN2_PHY_CTL1 0x34180002 +#define RCAR_GEN2_PHY_CTL1_SS 0xC180 /* Spread Spectrum */ + +#define RCAR_GEN2_PHY_CTL2_REG 0x170C +#define RCAR_GEN2_PHY_CTL2 0x00002303 + +#define RCAR_GEN2_PHY_CTL3_REG 0x171C +#define RCAR_GEN2_PHY_CTL3 0x000B0194 + +#define RCAR_GEN2_PHY_CTL4_REG 0x1724 +#define RCAR_GEN2_PHY_CTL4 0x00030994 + +#define RCAR_GEN2_PHY_CTL5_REG 0x1740 +#define RCAR_GEN2_PHY_CTL5 0x03004001 +#define RCAR_GEN2_PHY_CTL5_DC BIT(1) /* DC connection */ +#define RCAR_GEN2_PHY_CTL5_TR BIT(2) /* Termination Resistor */ + +enum sata_rcar_type { + RCAR_GEN1_SATA, + RCAR_GEN2_SATA, +}; + struct sata_rcar_priv { void __iomem *base; struct clk *clk; + enum sata_rcar_type type; }; -static void sata_rcar_phy_initialize(struct sata_rcar_priv *priv) +static void sata_rcar_gen1_phy_preinit(struct sata_rcar_priv *priv) { void __iomem *base = priv->base; @@ -141,8 +167,8 @@ static void sata_rcar_phy_initialize(struct sata_rcar_priv *priv) iowrite32(0, base + SATAPHYRESET_REG); } -static void sata_rcar_phy_write(struct sata_rcar_priv *priv, u16 reg, u32 val, - int group) +static void sata_rcar_gen1_phy_write(struct sata_rcar_priv *priv, u16 reg, + u32 val, int group) { void __iomem *base = priv->base; int timeout; @@ -170,6 +196,29 @@ static void sata_rcar_phy_write(struct sata_rcar_priv *priv, u16 reg, u32 val, iowrite32(0, base + SATAPHYADDR_REG); } +static void sata_rcar_gen1_phy_init(struct sata_rcar_priv *priv) +{ + sata_rcar_gen1_phy_preinit(priv); + sata_rcar_gen1_phy_write(priv, SATAPCTLR1_REG, 0x00200188, 0); + sata_rcar_gen1_phy_write(priv, SATAPCTLR1_REG, 0x00200188, 1); + sata_rcar_gen1_phy_write(priv, SATAPCTLR3_REG, 0x0000A061, 0); + sata_rcar_gen1_phy_write(priv, SATAPCTLR2_REG, 0x20000000, 0); + sata_rcar_gen1_phy_write(priv, SATAPCTLR2_REG, 0x20000000, 1); + sata_rcar_gen1_phy_write(priv, SATAPCTLR4_REG, 0x28E80000, 0); +} + +static void sata_rcar_gen2_phy_init(struct sata_rcar_priv *priv) +{ + void __iomem *base = priv->base; + + iowrite32(RCAR_GEN2_PHY_CTL1, base + RCAR_GEN2_PHY_CTL1_REG); + iowrite32(RCAR_GEN2_PHY_CTL2, base + RCAR_GEN2_PHY_CTL2_REG); + iowrite32(RCAR_GEN2_PHY_CTL3, base + RCAR_GEN2_PHY_CTL3_REG); + iowrite32(RCAR_GEN2_PHY_CTL4, base + RCAR_GEN2_PHY_CTL4_REG); + iowrite32(RCAR_GEN2_PHY_CTL5 | RCAR_GEN2_PHY_CTL5_DC | + RCAR_GEN2_PHY_CTL5_TR, base + RCAR_GEN2_PHY_CTL5_REG); +} + static void sata_rcar_freeze(struct ata_port *ap) { struct sata_rcar_priv *priv = ap->host->private_data; @@ -738,13 +787,17 @@ static void sata_rcar_init_controller(struct ata_host *host) u32 val; /* reset and setup phy */ - sata_rcar_phy_initialize(priv); - sata_rcar_phy_write(priv, SATAPCTLR1_REG, 0x00200188, 0); - sata_rcar_phy_write(priv, SATAPCTLR1_REG, 0x00200188, 1); - sata_rcar_phy_write(priv, SATAPCTLR3_REG, 0x0000A061, 0); - sata_rcar_phy_write(priv, SATAPCTLR2_REG, 0x20000000, 0); - sata_rcar_phy_write(priv, SATAPCTLR2_REG, 0x20000000, 1); - sata_rcar_phy_write(priv, SATAPCTLR4_REG, 0x28E80000, 0); + switch (priv->type) { + case RCAR_GEN1_SATA: + sata_rcar_gen1_phy_init(priv); + break; + case RCAR_GEN2_SATA: + sata_rcar_gen2_phy_init(priv); + break; + default: + dev_warn(host->dev, "SATA phy is not initialized\n"); + break; + } /* SATA-IP reset state */ val = ioread32(base + ATAPI_CONTROL1_REG); @@ -770,8 +823,40 @@ static void sata_rcar_init_controller(struct ata_host *host) iowrite32(ATAPI_INT_ENABLE_SATAINT, base + ATAPI_INT_ENABLE_REG); } +static struct of_device_id sata_rcar_match[] = { + { + /* Deprecated by "renesas,sata-r8a7779" */ + .compatible = "renesas,rcar-sata", + .data = (void *)RCAR_GEN1_SATA, + }, + { + .compatible = "renesas,sata-r8a7779", + .data = (void *)RCAR_GEN1_SATA, + }, + { + .compatible = "renesas,sata-r8a7790", + .data = (void *)RCAR_GEN2_SATA + }, + { + .compatible = "renesas,sata-r8a7791", + .data = (void *)RCAR_GEN2_SATA + }, + { }, +}; +MODULE_DEVICE_TABLE(of, sata_rcar_match); + +static const struct platform_device_id sata_rcar_id_table[] = { + { "sata_rcar", RCAR_GEN1_SATA }, /* Deprecated by "sata-r8a7779" */ + { "sata-r8a7779", RCAR_GEN1_SATA }, + { "sata-r8a7790", RCAR_GEN2_SATA }, + { "sata-r8a7791", RCAR_GEN2_SATA }, + { }, +}; +MODULE_DEVICE_TABLE(platform, sata_rcar_id_table); + static int sata_rcar_probe(struct platform_device *pdev) { + const struct of_device_id *of_id; struct ata_host *host; struct sata_rcar_priv *priv; struct resource *mem; @@ -787,6 +872,12 @@ static int sata_rcar_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + of_id = of_match_device(sata_rcar_match, &pdev->dev); + if (of_id) + priv->type = (enum sata_rcar_type)of_id->data; + else + priv->type = platform_get_device_id(pdev)->driver_data; + priv->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { dev_err(&pdev->dev, "failed to get access to sata clock\n"); @@ -892,15 +983,10 @@ static const struct dev_pm_ops sata_rcar_pm_ops = { }; #endif -static struct of_device_id sata_rcar_match[] = { - { .compatible = "renesas,rcar-sata", }, - {}, -}; -MODULE_DEVICE_TABLE(of, sata_rcar_match); - static struct platform_driver sata_rcar_driver = { .probe = sata_rcar_probe, .remove = sata_rcar_remove, + .id_table = sata_rcar_id_table, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, From 80361fa02e59cbc4ddfd4ceae18441092797149f Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Fri, 8 Nov 2013 16:09:30 +0400 Subject: [PATCH 04/20] libata, dt: Document sata_rcar bindings These bindings can be used to register SATA devices found on R-Car SoC. Signed-off-by: Valentine Barshak Signed-off-by: Tejun Heo --- .../devicetree/bindings/ata/sata_rcar.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Documentation/devicetree/bindings/ata/sata_rcar.txt diff --git a/Documentation/devicetree/bindings/ata/sata_rcar.txt b/Documentation/devicetree/bindings/ata/sata_rcar.txt new file mode 100644 index 000000000000..1e6111333fa8 --- /dev/null +++ b/Documentation/devicetree/bindings/ata/sata_rcar.txt @@ -0,0 +1,18 @@ +* Renesas R-Car SATA + +Required properties: +- compatible : should contain one of the following: + - "renesas,sata-r8a7779" for R-Car H1 + - "renesas,sata-r8a7790" for R-Car H2 + - "renesas,sata-r8a7791" for R-Car M2 +- reg : address and length of the SATA registers; +- interrupts : must consist of one interrupt specifier. + +Example: + +sata: sata@fc600000 { + compatible = "renesas,sata-r8a7779"; + reg = <0xfc600000 0x2000>; + interrupt-parent = <&gic>; + interrupts = <0 100 IRQ_TYPE_LEVEL_HIGH>; +}; From 8403e2ec8d4c759f821996d3bc43ca7c512ac9a0 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 25 Nov 2013 09:47:01 +0100 Subject: [PATCH 05/20] ahci: imx: Pull out the clock enable/disable calls The same code for enabling and disabling SATA clock was found in multiple places in the driver. Implement functions that enable/disable the SATA clock and use them in such places instead of duplicating the code. Signed-off-by: Marek Vasut Reviewed-by: Shawn Guo Cc: Richard Zhu Cc: Linux-IDE Signed-off-by: Tejun Heo --- drivers/ata/ahci_imx.c | 143 +++++++++++++++++++++-------------------- 1 file changed, 75 insertions(+), 68 deletions(-) diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 3e23e9941dad..6214411349de 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -47,6 +47,36 @@ static int ahci_imx_hotplug; module_param_named(hotplug, ahci_imx_hotplug, int, 0644); MODULE_PARM_DESC(hotplug, "AHCI IMX hot-plug support (0=Don't support, 1=support)"); +static int imx_sata_clock_enable(struct device *dev) +{ + struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); + int ret; + + ret = clk_prepare_enable(imxpriv->sata_ref_clk); + if (ret < 0) { + dev_err(dev, "prepare-enable sata_ref clock err:%d\n", ret); + return ret; + } + + regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, + IMX6Q_GPR13_SATA_MPLL_CLK_EN, + IMX6Q_GPR13_SATA_MPLL_CLK_EN); + + usleep_range(1000, 2000); + + return 0; +} + +static void imx_sata_clock_disable(struct device *dev) +{ + struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); + + regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, + IMX6Q_GPR13_SATA_MPLL_CLK_EN, + !IMX6Q_GPR13_SATA_MPLL_CLK_EN); + clk_disable_unprepare(imxpriv->sata_ref_clk); +} + static void ahci_imx_error_handler(struct ata_port *ap) { u32 reg_val; @@ -72,10 +102,7 @@ static void ahci_imx_error_handler(struct ata_port *ap) */ reg_val = readl(mmio + PORT_PHY_CTL); writel(reg_val | PORT_PHY_CTL_PDDQ_LOC, mmio + PORT_PHY_CTL); - regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, - IMX6Q_GPR13_SATA_MPLL_CLK_EN, - !IMX6Q_GPR13_SATA_MPLL_CLK_EN); - clk_disable_unprepare(imxpriv->sata_ref_clk); + imx_sata_clock_disable(ap->dev); imxpriv->no_device = true; } @@ -97,46 +124,9 @@ static int imx6q_sata_init(struct device *dev, void __iomem *mmio) unsigned int reg_val; struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); - imxpriv->gpr = - syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); - if (IS_ERR(imxpriv->gpr)) { - dev_err(dev, "failed to find fsl,imx6q-iomux-gpr regmap\n"); - return PTR_ERR(imxpriv->gpr); - } - - ret = clk_prepare_enable(imxpriv->sata_ref_clk); - if (ret < 0) { - dev_err(dev, "prepare-enable sata_ref clock err:%d\n", ret); + ret = imx_sata_clock_enable(dev); + if (ret < 0) return ret; - } - - /* - * set PHY Paremeters, two steps to configure the GPR13, - * one write for rest of parameters, mask of first write - * is 0x07ffffff, and the other one write for setting - * the mpll_clk_en. - */ - regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK - | IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK - | IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK - | IMX6Q_GPR13_SATA_SPD_MODE_MASK - | IMX6Q_GPR13_SATA_MPLL_SS_EN - | IMX6Q_GPR13_SATA_TX_ATTEN_MASK - | IMX6Q_GPR13_SATA_TX_BOOST_MASK - | IMX6Q_GPR13_SATA_TX_LVL_MASK - | IMX6Q_GPR13_SATA_MPLL_CLK_EN - | IMX6Q_GPR13_SATA_TX_EDGE_RATE - , IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB - | IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M - | IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F - | IMX6Q_GPR13_SATA_SPD_MODE_3P0G - | IMX6Q_GPR13_SATA_MPLL_SS_EN - | IMX6Q_GPR13_SATA_TX_ATTEN_9_16 - | IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB - | IMX6Q_GPR13_SATA_TX_LVL_1_025_V); - regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_MPLL_CLK_EN, - IMX6Q_GPR13_SATA_MPLL_CLK_EN); - usleep_range(100, 200); /* * Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL, @@ -164,11 +154,7 @@ static int imx6q_sata_init(struct device *dev, void __iomem *mmio) static void imx6q_sata_exit(struct device *dev) { - struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); - - regmap_update_bits(imxpriv->gpr, 0x34, IMX6Q_GPR13_SATA_MPLL_CLK_EN, - !IMX6Q_GPR13_SATA_MPLL_CLK_EN); - clk_disable_unprepare(imxpriv->sata_ref_clk); + imx_sata_clock_disable(dev); } static int imx_ahci_suspend(struct device *dev) @@ -179,12 +165,8 @@ static int imx_ahci_suspend(struct device *dev) * If no_device is set, The CLKs had been gated off in the * initialization so don't do it again here. */ - if (!imxpriv->no_device) { - regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, - IMX6Q_GPR13_SATA_MPLL_CLK_EN, - !IMX6Q_GPR13_SATA_MPLL_CLK_EN); - clk_disable_unprepare(imxpriv->sata_ref_clk); - } + if (!imxpriv->no_device) + imx_sata_clock_disable(dev); return 0; } @@ -192,22 +174,12 @@ static int imx_ahci_suspend(struct device *dev) static int imx_ahci_resume(struct device *dev) { struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); - int ret; + int ret = 0; - if (!imxpriv->no_device) { - ret = clk_prepare_enable(imxpriv->sata_ref_clk); - if (ret < 0) { - dev_err(dev, "pre-enable sata_ref clock err:%d\n", ret); - return ret; - } + if (!imxpriv->no_device) + ret = imx_sata_clock_enable(dev); - regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, - IMX6Q_GPR13_SATA_MPLL_CLK_EN, - IMX6Q_GPR13_SATA_MPLL_CLK_EN); - usleep_range(1000, 2000); - } - - return 0; + return ret; } static struct ahci_platform_data imx6q_sata_pdata = { @@ -290,6 +262,41 @@ static int imx_ahci_probe(struct platform_device *pdev) ahci_dev->dma_mask = &ahci_dev->coherent_dma_mask; ahci_dev->of_node = dev->of_node; + imxpriv->gpr = + syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); + + if (IS_ERR(imxpriv->gpr)) { + dev_err(dev, "failed to find fsl,imx6q-iomux-gpr regmap\n"); + ret = PTR_ERR(imxpriv->gpr); + goto err_out; + } + + /* + * Set PHY Paremeters, two steps to configure the GPR13, + * one write for rest of parameters, mask of first write + * is 0x07ffffff, and the other one write for setting + * the mpll_clk_en happens in imx_sata_clock_enable(). + */ + regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, + IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK | + IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK | + IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK | + IMX6Q_GPR13_SATA_SPD_MODE_MASK | + IMX6Q_GPR13_SATA_MPLL_SS_EN | + IMX6Q_GPR13_SATA_TX_ATTEN_MASK | + IMX6Q_GPR13_SATA_TX_BOOST_MASK | + IMX6Q_GPR13_SATA_TX_LVL_MASK | + IMX6Q_GPR13_SATA_MPLL_CLK_EN | + IMX6Q_GPR13_SATA_TX_EDGE_RATE, + IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB | + IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M | + IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F | + IMX6Q_GPR13_SATA_SPD_MODE_3P0G | + IMX6Q_GPR13_SATA_MPLL_SS_EN | + IMX6Q_GPR13_SATA_TX_ATTEN_9_16 | + IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB | + IMX6Q_GPR13_SATA_TX_LVL_1_025_V); + ret = platform_device_add_resources(ahci_pdev, res, 2); if (ret) goto err_out; From 4a23d1793f8e268e5867eec6c20abe78ec28ba5f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 25 Nov 2013 09:47:02 +0100 Subject: [PATCH 06/20] ahci: imx: Add i.MX53 support Add minor adjustments to support i.MX53 SATA port as well as i.MX6Q one. The difference here is mostly the clock which need to be enabled and also the lack of need of programming IOMUXC registers on i.MX53. All of which is well handles in the clock enable/disable functions. Note that this patch also cleans up the names of the common functions, so they don't read imx6q_* but imx_* instead. Signed-off-by: Marek Vasut Reviewed-by: Shawn Guo Cc: Richard Zhu Cc: Linux-IDE Signed-off-by: Tejun Heo --- drivers/ata/ahci_imx.c | 182 ++++++++++++++++++++++++++++------------- 1 file changed, 123 insertions(+), 59 deletions(-) diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 6214411349de..8cb89655cf06 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -34,10 +34,21 @@ enum { HOST_TIMER1MS = 0xe0, /* Timer 1-ms */ }; +enum ahci_imx_type { + AHCI_IMX53, + AHCI_IMX6Q, +}; + struct imx_ahci_priv { struct platform_device *ahci_pdev; + enum ahci_imx_type type; + + /* i.MX53 clock */ + struct clk *sata_gate_clk; + /* Common clock */ struct clk *sata_ref_clk; struct clk *ahb_clk; + struct regmap *gpr; bool no_device; bool first_time; @@ -52,29 +63,52 @@ static int imx_sata_clock_enable(struct device *dev) struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); int ret; - ret = clk_prepare_enable(imxpriv->sata_ref_clk); - if (ret < 0) { - dev_err(dev, "prepare-enable sata_ref clock err:%d\n", ret); - return ret; + if (imxpriv->type == AHCI_IMX53) { + ret = clk_prepare_enable(imxpriv->sata_gate_clk); + if (ret < 0) { + dev_err(dev, "prepare-enable sata_gate clock err:%d\n", + ret); + return ret; + } } - regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, - IMX6Q_GPR13_SATA_MPLL_CLK_EN, - IMX6Q_GPR13_SATA_MPLL_CLK_EN); + ret = clk_prepare_enable(imxpriv->sata_ref_clk); + if (ret < 0) { + dev_err(dev, "prepare-enable sata_ref clock err:%d\n", + ret); + goto clk_err; + } + + if (imxpriv->type == AHCI_IMX6Q) { + regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, + IMX6Q_GPR13_SATA_MPLL_CLK_EN, + IMX6Q_GPR13_SATA_MPLL_CLK_EN); + } usleep_range(1000, 2000); return 0; + +clk_err: + if (imxpriv->type == AHCI_IMX53) + clk_disable_unprepare(imxpriv->sata_gate_clk); + return ret; } static void imx_sata_clock_disable(struct device *dev) { struct imx_ahci_priv *imxpriv = dev_get_drvdata(dev->parent); - regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, - IMX6Q_GPR13_SATA_MPLL_CLK_EN, - !IMX6Q_GPR13_SATA_MPLL_CLK_EN); + if (imxpriv->type == AHCI_IMX6Q) { + regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, + IMX6Q_GPR13_SATA_MPLL_CLK_EN, + !IMX6Q_GPR13_SATA_MPLL_CLK_EN); + } + clk_disable_unprepare(imxpriv->sata_ref_clk); + + if (imxpriv->type == AHCI_IMX53) + clk_disable_unprepare(imxpriv->sata_gate_clk); } static void ahci_imx_error_handler(struct ata_port *ap) @@ -106,9 +140,25 @@ static void ahci_imx_error_handler(struct ata_port *ap) imxpriv->no_device = true; } +int ahci_imx_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + struct ata_port *ap = link->ap; + struct imx_ahci_priv *imxpriv = dev_get_drvdata(ap->dev->parent); + int ret = -EIO; + + if (imxpriv->type == AHCI_IMX53) + ret = ahci_pmp_retry_srst_ops.softreset(link, class, deadline); + else if (imxpriv->type == AHCI_IMX6Q) + ret = ahci_ops.softreset(link, class, deadline); + + return ret; +} + static struct ata_port_operations ahci_imx_ops = { .inherits = &ahci_platform_ops, .error_handler = ahci_imx_error_handler, + .softreset = ahci_imx_softreset, }; static const struct ata_port_info ahci_imx_port_info = { @@ -118,7 +168,7 @@ static const struct ata_port_info ahci_imx_port_info = { .port_ops = &ahci_imx_ops, }; -static int imx6q_sata_init(struct device *dev, void __iomem *mmio) +static int imx_sata_init(struct device *dev, void __iomem *mmio) { int ret = 0; unsigned int reg_val; @@ -152,7 +202,7 @@ static int imx6q_sata_init(struct device *dev, void __iomem *mmio) return 0; } -static void imx6q_sata_exit(struct device *dev) +static void imx_sata_exit(struct device *dev) { imx_sata_clock_disable(dev); } @@ -182,16 +232,18 @@ static int imx_ahci_resume(struct device *dev) return ret; } -static struct ahci_platform_data imx6q_sata_pdata = { - .init = imx6q_sata_init, - .exit = imx6q_sata_exit, - .ata_port_info = &ahci_imx_port_info, - .suspend = imx_ahci_suspend, - .resume = imx_ahci_resume, +static struct ahci_platform_data imx_sata_pdata = { + .init = imx_sata_init, + .exit = imx_sata_exit, + .ata_port_info = &ahci_imx_port_info, + .suspend = imx_ahci_suspend, + .resume = imx_ahci_resume, + }; static const struct of_device_id imx_ahci_of_match[] = { - { .compatible = "fsl,imx6q-ahci", .data = &imx6q_sata_pdata}, + { .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 }, + { .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q }, {}, }; MODULE_DEVICE_TABLE(of, imx_ahci_of_match); @@ -201,12 +253,20 @@ static int imx_ahci_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct resource *mem, *irq, res[2]; const struct of_device_id *of_id; + enum ahci_imx_type type; const struct ahci_platform_data *pdata = NULL; struct imx_ahci_priv *imxpriv; struct device *ahci_dev; struct platform_device *ahci_pdev; int ret; + of_id = of_match_device(imx_ahci_of_match, dev); + if (!of_id) + return -EINVAL; + + type = (enum ahci_imx_type)of_id->data; + pdata = &imx_sata_pdata; + imxpriv = devm_kzalloc(dev, sizeof(*imxpriv), GFP_KERNEL); if (!imxpriv) { dev_err(dev, "can't alloc ahci_host_priv\n"); @@ -222,6 +282,8 @@ static int imx_ahci_probe(struct platform_device *pdev) imxpriv->no_device = false; imxpriv->first_time = true; + imxpriv->type = type; + imxpriv->ahb_clk = devm_clk_get(dev, "ahb"); if (IS_ERR(imxpriv->ahb_clk)) { dev_err(dev, "can't get ahb clock.\n"); @@ -229,6 +291,15 @@ static int imx_ahci_probe(struct platform_device *pdev) goto err_out; } + if (type == AHCI_IMX53) { + imxpriv->sata_gate_clk = devm_clk_get(dev, "sata_gate"); + if (IS_ERR(imxpriv->sata_gate_clk)) { + dev_err(dev, "can't get sata_gate clock.\n"); + ret = PTR_ERR(imxpriv->sata_gate_clk); + goto err_out; + } + } + imxpriv->sata_ref_clk = devm_clk_get(dev, "sata_ref"); if (IS_ERR(imxpriv->sata_ref_clk)) { dev_err(dev, "can't get sata_ref clock.\n"); @@ -239,14 +310,6 @@ static int imx_ahci_probe(struct platform_device *pdev) imxpriv->ahci_pdev = ahci_pdev; platform_set_drvdata(pdev, imxpriv); - of_id = of_match_device(imx_ahci_of_match, dev); - if (of_id) { - pdata = of_id->data; - } else { - ret = -EINVAL; - goto err_out; - } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!mem || !irq) { @@ -262,41 +325,42 @@ static int imx_ahci_probe(struct platform_device *pdev) ahci_dev->dma_mask = &ahci_dev->coherent_dma_mask; ahci_dev->of_node = dev->of_node; - imxpriv->gpr = - syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); + if (type == AHCI_IMX6Q) { + imxpriv->gpr = syscon_regmap_lookup_by_compatible( + "fsl,imx6q-iomuxc-gpr"); + if (IS_ERR(imxpriv->gpr)) { + dev_err(dev, + "failed to find fsl,imx6q-iomux-gpr regmap\n"); + return PTR_ERR(imxpriv->gpr); + } - if (IS_ERR(imxpriv->gpr)) { - dev_err(dev, "failed to find fsl,imx6q-iomux-gpr regmap\n"); - ret = PTR_ERR(imxpriv->gpr); - goto err_out; + /* + * Set PHY Paremeters, two steps to configure the GPR13, + * one write for rest of parameters, mask of first write + * is 0x07fffffe, and the other one write for setting + * the mpll_clk_en happens in imx_sata_clock_enable(). + */ + regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, + IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK | + IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK | + IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK | + IMX6Q_GPR13_SATA_SPD_MODE_MASK | + IMX6Q_GPR13_SATA_MPLL_SS_EN | + IMX6Q_GPR13_SATA_TX_ATTEN_MASK | + IMX6Q_GPR13_SATA_TX_BOOST_MASK | + IMX6Q_GPR13_SATA_TX_LVL_MASK | + IMX6Q_GPR13_SATA_MPLL_CLK_EN | + IMX6Q_GPR13_SATA_TX_EDGE_RATE, + IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB | + IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M | + IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F | + IMX6Q_GPR13_SATA_SPD_MODE_3P0G | + IMX6Q_GPR13_SATA_MPLL_SS_EN | + IMX6Q_GPR13_SATA_TX_ATTEN_9_16 | + IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB | + IMX6Q_GPR13_SATA_TX_LVL_1_025_V); } - /* - * Set PHY Paremeters, two steps to configure the GPR13, - * one write for rest of parameters, mask of first write - * is 0x07ffffff, and the other one write for setting - * the mpll_clk_en happens in imx_sata_clock_enable(). - */ - regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, - IMX6Q_GPR13_SATA_RX_EQ_VAL_MASK | - IMX6Q_GPR13_SATA_RX_LOS_LVL_MASK | - IMX6Q_GPR13_SATA_RX_DPLL_MODE_MASK | - IMX6Q_GPR13_SATA_SPD_MODE_MASK | - IMX6Q_GPR13_SATA_MPLL_SS_EN | - IMX6Q_GPR13_SATA_TX_ATTEN_MASK | - IMX6Q_GPR13_SATA_TX_BOOST_MASK | - IMX6Q_GPR13_SATA_TX_LVL_MASK | - IMX6Q_GPR13_SATA_MPLL_CLK_EN | - IMX6Q_GPR13_SATA_TX_EDGE_RATE, - IMX6Q_GPR13_SATA_RX_EQ_VAL_3_0_DB | - IMX6Q_GPR13_SATA_RX_LOS_LVL_SATA2M | - IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F | - IMX6Q_GPR13_SATA_SPD_MODE_3P0G | - IMX6Q_GPR13_SATA_MPLL_SS_EN | - IMX6Q_GPR13_SATA_TX_ATTEN_9_16 | - IMX6Q_GPR13_SATA_TX_BOOST_3_33_DB | - IMX6Q_GPR13_SATA_TX_LVL_1_025_V); - ret = platform_device_add_resources(ahci_pdev, res, 2); if (ret) goto err_out; From ee4e5a9abf470908bb04feadec236c51e19fc413 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Tue, 3 Dec 2013 10:25:37 -0500 Subject: [PATCH 07/20] ahci: imx: ahci_imx_softreset() can be static Acked-by: Marek Vasut Signed-off-by: Fengguang Wu Signed-off-by: Tejun Heo --- drivers/ata/ahci_imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 8cb89655cf06..2daa28891b7f 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -140,7 +140,7 @@ static void ahci_imx_error_handler(struct ata_port *ap) imxpriv->no_device = true; } -int ahci_imx_softreset(struct ata_link *link, unsigned int *class, +static int ahci_imx_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { struct ata_port *ap = link->ap; From 7d6203af30b45bb1506e20935a270286c3e2393f Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 7 Dec 2013 14:00:19 +0800 Subject: [PATCH 08/20] ahci: imx: fix the error handling in imx_ahci_probe() Release alloced resources instead of direct return from imx_ahci_probe() in the error handling case. Fixes: 4a23d1793f8e ('ahci: imx: Add i.MX53 support') Signed-off-by: Wei Yongjun Signed-off-by: Tejun Heo Acked-by: Marek Vasut --- drivers/ata/ahci_imx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 2daa28891b7f..dd4d6f74d7bd 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -331,7 +331,8 @@ static int imx_ahci_probe(struct platform_device *pdev) if (IS_ERR(imxpriv->gpr)) { dev_err(dev, "failed to find fsl,imx6q-iomux-gpr regmap\n"); - return PTR_ERR(imxpriv->gpr); + ret = PTR_ERR(imxpriv->gpr); + goto err_out; } /* From d934145139664daa1ae918d3f0a7f3f47225ff33 Mon Sep 17 00:00:00 2001 From: Rashika Kheria Date: Sat, 14 Dec 2013 19:38:08 +0530 Subject: [PATCH 09/20] drivers: ata: Mark the function ahci_init_interrupts() as static in ahci.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch marks the function ahci_init_interrupts() as static in ahci.c because it is not used outside this file. Thus, it also eliminates the following warning in ahci.c: drivers/ata/ahci.c:1099:5: warning: no previous prototype for ‘ahci_init_interrupts’ [-Wmissing-prototypes] Signed-off-by: Rashika Kheria Signed-off-by: Tejun Heo Reviewed-by: Josh Triplett --- drivers/ata/ahci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index ef8642e12a76..ea5b5a33a8b8 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1145,7 +1145,7 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host) {} #endif -int ahci_init_interrupts(struct pci_dev *pdev, struct ahci_host_priv *hpriv) +static int ahci_init_interrupts(struct pci_dev *pdev, struct ahci_host_priv *hpriv) { int rc; unsigned int maxvec; From 73993396d8591580f03fe0ee9c6cc5ea8fa09928 Mon Sep 17 00:00:00 2001 From: Rashika Kheria Date: Sat, 14 Dec 2013 19:40:21 +0530 Subject: [PATCH 10/20] drivers: ata: Mark the function as static in libahci.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch marks the function ahci_port_intr() and ahci_hw_port_interrupt() as static in libahci.c because they are not used outside this file. Thus, it also eliminates the following warnings in libahci.c: drivers/ata/libahci.c:1767:6: warning: no previous prototype for ‘ahci_port_intr’ [-Wmissing-prototypes] drivers/ata/libahci.c:1800:6: warning: no previous prototype for ‘ahci_hw_port_interrupt’ [-Wmissing-prototypes] Signed-off-by: Rashika Kheria Signed-off-by: Tejun Heo Reviewed-by: Josh Triplett --- drivers/ata/libahci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index c482f8cadd7a..36605abe5a67 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1764,7 +1764,7 @@ static void ahci_handle_port_interrupt(struct ata_port *ap, } } -void ahci_port_intr(struct ata_port *ap) +static void ahci_port_intr(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); u32 status; @@ -1797,7 +1797,7 @@ irqreturn_t ahci_thread_fn(int irq, void *dev_instance) } EXPORT_SYMBOL_GPL(ahci_thread_fn); -void ahci_hw_port_interrupt(struct ata_port *ap) +static void ahci_hw_port_interrupt(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); struct ahci_port_priv *pp = ap->private_data; From 96f7f6bd855cc47988e3efb1efc4926404ae6f60 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 31 Dec 2013 10:59:13 +0530 Subject: [PATCH 11/20] ata: pata_samsung_cf: Move plat/regs-ata.h to drivers/ata plat/regs-ata.h is used only by Samsung PATA driver. Move this file to the drivers folder to remove platform dependency required for multiplatform support. Signed-off-by: Sachin Kamat Reviewed-by: Jingoo Han Signed-off-by: Tejun Heo --- drivers/ata/pata_samsung_cf.c | 2 +- .../plat/regs-ata.h => drivers/ata/pata_samsung_cf.h | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) rename arch/arm/plat-samsung/include/plat/regs-ata.h => drivers/ata/pata_samsung_cf.h (91%) diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c index 898e544a7ae8..e04d70b7ce76 100644 --- a/drivers/ata/pata_samsung_cf.c +++ b/drivers/ata/pata_samsung_cf.c @@ -24,7 +24,7 @@ #include #include -#include +#include "pata_samsung_cf.h" #define DRV_NAME "pata_samsung_cf" #define DRV_VERSION "0.1" diff --git a/arch/arm/plat-samsung/include/plat/regs-ata.h b/drivers/ata/pata_samsung_cf.h similarity index 91% rename from arch/arm/plat-samsung/include/plat/regs-ata.h rename to drivers/ata/pata_samsung_cf.h index f5df92fdae26..eeefe2e0cdc6 100644 --- a/arch/arm/plat-samsung/include/plat/regs-ata.h +++ b/drivers/ata/pata_samsung_cf.h @@ -1,5 +1,4 @@ -/* linux/arch/arm/plat-samsung/include/plat/regs-ata.h - * +/* * Copyright (c) 2010 Samsung Electronics Co., Ltd. * http://www.samsung.com * @@ -10,8 +9,8 @@ * published by the Free Software Foundation. */ -#ifndef __ASM_PLAT_REGS_ATA_H -#define __ASM_PLAT_REGS_ATA_H __FILE__ +#ifndef __PATA_SAMSUNG_CF_H +#define __PATA_SAMSUNG_CF_H #define S3C_CFATA_REG(x) (x) @@ -53,4 +52,4 @@ #define S3C_ATA_CFG_SWAP 0x40 #define S3C_ATA_CFG_IORDYEN 0x02 -#endif /* __ASM_PLAT_REGS_ATA_H */ +#endif /* __PATA_SAMSUNG_CF_H */ From 15e5318c9cb92dc49f1326bce44798575e3b5774 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 2 Jan 2014 08:39:31 +0530 Subject: [PATCH 12/20] ata: pata_samsung_cf: Merge pata_samsung_cf.h into pata_samsung_cf.c Since pata_samsung_cf.h is referenced only by pata_samsung_cf.c, merge it into the .c file. Signed-off-by: Sachin Kamat Signed-off-by: Tejun Heo --- drivers/ata/pata_samsung_cf.c | 38 +++++++++++++++++++++++- drivers/ata/pata_samsung_cf.h | 55 ----------------------------------- 2 files changed, 37 insertions(+), 56 deletions(-) delete mode 100644 drivers/ata/pata_samsung_cf.h diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c index e04d70b7ce76..cd2746b169a9 100644 --- a/drivers/ata/pata_samsung_cf.c +++ b/drivers/ata/pata_samsung_cf.c @@ -24,11 +24,47 @@ #include #include -#include "pata_samsung_cf.h" #define DRV_NAME "pata_samsung_cf" #define DRV_VERSION "0.1" +#define S3C_CFATA_REG(x) (x) +#define S3C_CFATA_MUX S3C_CFATA_REG(0x0) +#define S3C_ATA_CTRL S3C_CFATA_REG(0x0) +#define S3C_ATA_STATUS S3C_CFATA_REG(0x4) +#define S3C_ATA_CMD S3C_CFATA_REG(0x8) +#define S3C_ATA_SWRST S3C_CFATA_REG(0xc) +#define S3C_ATA_IRQ S3C_CFATA_REG(0x10) +#define S3C_ATA_IRQ_MSK S3C_CFATA_REG(0x14) +#define S3C_ATA_CFG S3C_CFATA_REG(0x18) + +#define S3C_ATA_MDMA_TIME S3C_CFATA_REG(0x28) +#define S3C_ATA_PIO_TIME S3C_CFATA_REG(0x2c) +#define S3C_ATA_UDMA_TIME S3C_CFATA_REG(0x30) +#define S3C_ATA_XFR_NUM S3C_CFATA_REG(0x34) +#define S3C_ATA_XFR_CNT S3C_CFATA_REG(0x38) +#define S3C_ATA_TBUF_START S3C_CFATA_REG(0x3c) +#define S3C_ATA_TBUF_SIZE S3C_CFATA_REG(0x40) +#define S3C_ATA_SBUF_START S3C_CFATA_REG(0x44) +#define S3C_ATA_SBUF_SIZE S3C_CFATA_REG(0x48) +#define S3C_ATA_CADR_TBUF S3C_CFATA_REG(0x4c) +#define S3C_ATA_CADR_SBUF S3C_CFATA_REG(0x50) +#define S3C_ATA_PIO_DTR S3C_CFATA_REG(0x54) +#define S3C_ATA_PIO_FED S3C_CFATA_REG(0x58) +#define S3C_ATA_PIO_SCR S3C_CFATA_REG(0x5c) +#define S3C_ATA_PIO_LLR S3C_CFATA_REG(0x60) +#define S3C_ATA_PIO_LMR S3C_CFATA_REG(0x64) +#define S3C_ATA_PIO_LHR S3C_CFATA_REG(0x68) +#define S3C_ATA_PIO_DVR S3C_CFATA_REG(0x6c) +#define S3C_ATA_PIO_CSD S3C_CFATA_REG(0x70) +#define S3C_ATA_PIO_DAD S3C_CFATA_REG(0x74) +#define S3C_ATA_PIO_READY S3C_CFATA_REG(0x78) +#define S3C_ATA_PIO_RDATA S3C_CFATA_REG(0x7c) + +#define S3C_CFATA_MUX_TRUEIDE 0x01 +#define S3C_ATA_CFG_SWAP 0x40 +#define S3C_ATA_CFG_IORDYEN 0x02 + enum s3c_cpu_type { TYPE_S3C64XX, TYPE_S5PC100, diff --git a/drivers/ata/pata_samsung_cf.h b/drivers/ata/pata_samsung_cf.h deleted file mode 100644 index eeefe2e0cdc6..000000000000 --- a/drivers/ata/pata_samsung_cf.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * Samsung CF-ATA register definitions - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef __PATA_SAMSUNG_CF_H -#define __PATA_SAMSUNG_CF_H - -#define S3C_CFATA_REG(x) (x) - -#define S3C_CFATA_MUX S3C_CFATA_REG(0x0) - -#define S3C_ATA_CTRL S3C_CFATA_REG(0x0) -#define S3C_ATA_STATUS S3C_CFATA_REG(0x4) -#define S3C_ATA_CMD S3C_CFATA_REG(0x8) -#define S3C_ATA_SWRST S3C_CFATA_REG(0xc) -#define S3C_ATA_IRQ S3C_CFATA_REG(0x10) -#define S3C_ATA_IRQ_MSK S3C_CFATA_REG(0x14) -#define S3C_ATA_CFG S3C_CFATA_REG(0x18) - -#define S3C_ATA_MDMA_TIME S3C_CFATA_REG(0x28) -#define S3C_ATA_PIO_TIME S3C_CFATA_REG(0x2c) -#define S3C_ATA_UDMA_TIME S3C_CFATA_REG(0x30) -#define S3C_ATA_XFR_NUM S3C_CFATA_REG(0x34) -#define S3C_ATA_XFR_CNT S3C_CFATA_REG(0x38) -#define S3C_ATA_TBUF_START S3C_CFATA_REG(0x3c) -#define S3C_ATA_TBUF_SIZE S3C_CFATA_REG(0x40) -#define S3C_ATA_SBUF_START S3C_CFATA_REG(0x44) -#define S3C_ATA_SBUF_SIZE S3C_CFATA_REG(0x48) -#define S3C_ATA_CADR_TBUF S3C_CFATA_REG(0x4c) -#define S3C_ATA_CADR_SBUF S3C_CFATA_REG(0x50) -#define S3C_ATA_PIO_DTR S3C_CFATA_REG(0x54) -#define S3C_ATA_PIO_FED S3C_CFATA_REG(0x58) -#define S3C_ATA_PIO_SCR S3C_CFATA_REG(0x5c) -#define S3C_ATA_PIO_LLR S3C_CFATA_REG(0x60) -#define S3C_ATA_PIO_LMR S3C_CFATA_REG(0x64) -#define S3C_ATA_PIO_LHR S3C_CFATA_REG(0x68) -#define S3C_ATA_PIO_DVR S3C_CFATA_REG(0x6c) -#define S3C_ATA_PIO_CSD S3C_CFATA_REG(0x70) -#define S3C_ATA_PIO_DAD S3C_CFATA_REG(0x74) -#define S3C_ATA_PIO_READY S3C_CFATA_REG(0x78) -#define S3C_ATA_PIO_RDATA S3C_CFATA_REG(0x7c) - -#define S3C_CFATA_MUX_TRUEIDE 0x01 - -#define S3C_ATA_CFG_SWAP 0x40 -#define S3C_ATA_CFG_IORDYEN 0x02 - -#endif /* __PATA_SAMSUNG_CF_H */ From 3e692a942f6eb0ec0151449e6c5fb88ffc854b6d Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 2 Jan 2014 17:24:03 +0900 Subject: [PATCH 13/20] ata: pata_samsung_cf: Use devm_ioremap_resource() Use devm_ioremap_resource() in order to make the code simpler, and remove redundant return value check of platform_get_resource() because the value is checked by devm_ioremap_resource(). Signed-off-by: Jingoo Han Signed-off-by: Tejun Heo --- drivers/ata/pata_samsung_cf.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c index cd2746b169a9..7d2142fbcbb7 100644 --- a/drivers/ata/pata_samsung_cf.c +++ b/drivers/ata/pata_samsung_cf.c @@ -531,22 +531,10 @@ static int __init pata_s3c_probe(struct platform_device *pdev) info->irq = platform_get_irq(pdev, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(dev, "failed to get mem resource\n"); - return -EINVAL; - } - if (!devm_request_mem_region(dev, res->start, - resource_size(res), DRV_NAME)) { - dev_err(dev, "error requesting register region\n"); - return -EBUSY; - } - - info->ide_addr = devm_ioremap(dev, res->start, resource_size(res)); - if (!info->ide_addr) { - dev_err(dev, "failed to map IO base address\n"); - return -ENOMEM; - } + info->ide_addr = devm_ioremap_resource(dev, res); + if (IS_ERR(info->ide_addr)) + return PTR_ERR(info->ide_addr); info->clk = devm_clk_get(&pdev->dev, "cfcon"); if (IS_ERR(info->clk)) { From ed68a34a22ac310cbf9ea58f30f4076ca146d251 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 6 Jan 2014 10:05:15 +0530 Subject: [PATCH 14/20] ata: pata_samsung_cf: Remove unused macros These macros are not used in the file. Remove them. Signed-off-by: Sachin Kamat Signed-off-by: Tejun Heo --- drivers/ata/pata_samsung_cf.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c index 7d2142fbcbb7..a79566d05666 100644 --- a/drivers/ata/pata_samsung_cf.c +++ b/drivers/ata/pata_samsung_cf.c @@ -31,24 +31,12 @@ #define S3C_CFATA_REG(x) (x) #define S3C_CFATA_MUX S3C_CFATA_REG(0x0) #define S3C_ATA_CTRL S3C_CFATA_REG(0x0) -#define S3C_ATA_STATUS S3C_CFATA_REG(0x4) #define S3C_ATA_CMD S3C_CFATA_REG(0x8) -#define S3C_ATA_SWRST S3C_CFATA_REG(0xc) #define S3C_ATA_IRQ S3C_CFATA_REG(0x10) #define S3C_ATA_IRQ_MSK S3C_CFATA_REG(0x14) #define S3C_ATA_CFG S3C_CFATA_REG(0x18) -#define S3C_ATA_MDMA_TIME S3C_CFATA_REG(0x28) #define S3C_ATA_PIO_TIME S3C_CFATA_REG(0x2c) -#define S3C_ATA_UDMA_TIME S3C_CFATA_REG(0x30) -#define S3C_ATA_XFR_NUM S3C_CFATA_REG(0x34) -#define S3C_ATA_XFR_CNT S3C_CFATA_REG(0x38) -#define S3C_ATA_TBUF_START S3C_CFATA_REG(0x3c) -#define S3C_ATA_TBUF_SIZE S3C_CFATA_REG(0x40) -#define S3C_ATA_SBUF_START S3C_CFATA_REG(0x44) -#define S3C_ATA_SBUF_SIZE S3C_CFATA_REG(0x48) -#define S3C_ATA_CADR_TBUF S3C_CFATA_REG(0x4c) -#define S3C_ATA_CADR_SBUF S3C_CFATA_REG(0x50) #define S3C_ATA_PIO_DTR S3C_CFATA_REG(0x54) #define S3C_ATA_PIO_FED S3C_CFATA_REG(0x58) #define S3C_ATA_PIO_SCR S3C_CFATA_REG(0x5c) @@ -58,7 +46,6 @@ #define S3C_ATA_PIO_DVR S3C_CFATA_REG(0x6c) #define S3C_ATA_PIO_CSD S3C_CFATA_REG(0x70) #define S3C_ATA_PIO_DAD S3C_CFATA_REG(0x74) -#define S3C_ATA_PIO_READY S3C_CFATA_REG(0x78) #define S3C_ATA_PIO_RDATA S3C_CFATA_REG(0x7c) #define S3C_CFATA_MUX_TRUEIDE 0x01 From b1f5c73bd5a4752efb7d7af019034044b08aafe9 Mon Sep 17 00:00:00 2001 From: Simon Guinot Date: Tue, 14 Jan 2014 20:04:39 +0100 Subject: [PATCH 15/20] ata: sata_mv: introduce compatible string "marvell, armada-370-sata" The sata_mv driver supports the SATA IP found in several Marvell SoCs. As some new SATA registers have been introduced with the Armada 370/XP SoCs, a way to identify them is needed. This patch introduces a new compatible string for the SATA IP found in Armada 370/XP SoCs. Signed-off-by: Simon Guinot Cc: Thomas Petazzoni Cc: Jason Cooper Cc: Andrew Lunn Cc: Gregory Clement Cc: Sebastian Hesselbarth Cc: Lior Amsalem Cc: stable@vger.kernel.org # v3.6+ Acked-by: Jason Cooper Signed-off-by: Tejun Heo --- Documentation/devicetree/bindings/ata/marvell.txt | 2 +- drivers/ata/sata_mv.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/ata/marvell.txt b/Documentation/devicetree/bindings/ata/marvell.txt index b5cdd20cde9c..1c8351604d38 100644 --- a/Documentation/devicetree/bindings/ata/marvell.txt +++ b/Documentation/devicetree/bindings/ata/marvell.txt @@ -1,7 +1,7 @@ * Marvell Orion SATA Required Properties: -- compatibility : "marvell,orion-sata" +- compatibility : "marvell,orion-sata" or "marvell,armada-370-sata" - reg : Address range of controller - interrupts : Interrupt controller is using - nr-ports : Number of SATA ports in use. diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 56be31819897..4ec5368c10f7 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -4209,6 +4209,7 @@ static int mv_platform_resume(struct platform_device *pdev) #ifdef CONFIG_OF static struct of_device_id mv_sata_dt_ids[] = { + { .compatible = "marvell,armada-370-sata", }, { .compatible = "marvell,orion-sata", }, {}, }; From 9013d64e661fc2a37a1742670202171c27fef4b5 Mon Sep 17 00:00:00 2001 From: Lior Amsalem Date: Tue, 14 Jan 2014 20:09:57 +0100 Subject: [PATCH 16/20] ata: sata_mv: fix disk hotplug for Armada 370/XP SoCs On Armada 370/XP SoCs, once a disk is removed from a SATA port, then the re-plug events are not detected by the sata_mv driver. This patch fixes the issue by updating the PHY speed in the LP_PHY_CTL register (0x58) according to the SControl speed. Note that this fix is only applied if the compatible string "marvell,armada-370-sata" is found in the SATA DT node. Fixes: 9ae6f740b49f ("arm: mach-mvebu: add support for Armada 370 and Armada XP with DT") Signed-off-by: Lior Amsalem Signed-off-by: Nadav Haklai Signed-off-by: Simon Guinot Cc: Thomas Petazzoni Cc: Jason Cooper Cc: Andrew Lunn Cc: Gregory Clement Cc: Sebastian Hesselbarth Cc: stable@vger.kernel.org # v3.6+ Acked-by: Jason Cooper Signed-off-by: Tejun Heo --- drivers/ata/sata_mv.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 4ec5368c10f7..dc9d4b1ea4ec 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -304,6 +304,7 @@ enum { MV5_LTMODE = 0x30, MV5_PHY_CTL = 0x0C, SATA_IFCFG = 0x050, + LP_PHY_CTL = 0x058, MV_M2_PREAMP_MASK = 0x7e0, @@ -431,6 +432,7 @@ enum { MV_HP_CUT_THROUGH = (1 << 10), /* can use EDMA cut-through */ MV_HP_FLAG_SOC = (1 << 11), /* SystemOnChip, no PCI */ MV_HP_QUIRK_LED_BLINK_EN = (1 << 12), /* is led blinking enabled? */ + MV_HP_FIX_LP_PHY_CTL = (1 << 13), /* fix speed in LP_PHY_CTL ? */ /* Port private flags (pp_flags) */ MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */ @@ -1358,6 +1360,7 @@ static int mv_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val) if (ofs != 0xffffffffU) { void __iomem *addr = mv_ap_base(link->ap) + ofs; + struct mv_host_priv *hpriv = link->ap->host->private_data; if (sc_reg_in == SCR_CONTROL) { /* * Workaround for 88SX60x1 FEr SATA#26: @@ -1374,6 +1377,18 @@ static int mv_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val) */ if ((val & 0xf) == 1 || (readl(addr) & 0xf) == 1) val |= 0xf000; + + if (hpriv->hp_flags & MV_HP_FIX_LP_PHY_CTL) { + void __iomem *lp_phy_addr = + mv_ap_base(link->ap) + LP_PHY_CTL; + /* + * Set PHY speed according to SControl speed. + */ + if ((val & 0xf0) == 0x10) + writelfl(0x7, lp_phy_addr); + else + writelfl(0x227, lp_phy_addr); + } } writelfl(val, addr); return 0; @@ -4110,6 +4125,15 @@ static int mv_platform_probe(struct platform_device *pdev) if (rc) goto err; + /* + * To allow disk hotplug on Armada 370/XP SoCs, the PHY speed must be + * updated in the LP_PHY_CTL register. + */ + if (pdev->dev.of_node && + of_device_is_compatible(pdev->dev.of_node, + "marvell,armada-370-sata")) + hpriv->hp_flags |= MV_HP_FIX_LP_PHY_CTL; + /* initialize adapter */ rc = mv_init_host(host); if (rc) From a96cc303e42ad7830dde929aad0046e448a05505 Mon Sep 17 00:00:00 2001 From: Simon Guinot Date: Tue, 14 Jan 2014 20:10:27 +0100 Subject: [PATCH 17/20] ARM: mvebu: update the SATA compatible string for Armada 370/XP This patch updates the Armada 370/XP SATA node with the new compatible string "marvell,armada-370-sata". Signed-off-by: Simon Guinot Cc: Thomas Petazzoni Cc: Jason Cooper Cc: Andrew Lunn Cc: Gregory Clement Cc: Sebastian Hesselbarth Cc: Lior Amsalem Cc: stable@vger.kernel.org # v3.6+ Acked-by: Jason Cooper Signed-off-by: Tejun Heo --- arch/arm/boot/dts/armada-370-xp.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi index 00d6a798c705..df141a1d6448 100644 --- a/arch/arm/boot/dts/armada-370-xp.dtsi +++ b/arch/arm/boot/dts/armada-370-xp.dtsi @@ -152,7 +152,7 @@ }; sata@a0000 { - compatible = "marvell,orion-sata"; + compatible = "marvell,armada-370-sata"; reg = <0xa0000 0x5000>; interrupts = <55>; clocks = <&gateclk 15>, <&gateclk 30>; From ecd75ad514d73efc1bbcc5f10a13566c3ace5f53 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 16 Jan 2014 09:47:17 -0500 Subject: [PATCH 18/20] libata: disable LPM for some WD SATA-I devices For some reason, some early WD drives spin up and down drives erratically when the link is put into slumber mode which can reduce the life expectancy of the device significantly. Unfortunately, we don't have full list of devices and given the nature of the issue it'd be better to err on the side of false positives than the other way around. Let's disable LPM on all WD devices which match one of the known problematic model prefixes and are SATA-I. As horkage list doesn't support matching SATA capabilities, this is implemented as two horkages - WD_BROKEN_LPM and NOLPM. The former is set for the known prefixes and sets the latter if the matched device is SATA-I. Note that this isn't optimal as this disables all LPM operations and partial link power state reportedly works fine on these; however, the way LPM is implemented in libata makes it difficult to precisely map libata LPM setting to specific link power state. Well, these devices are already fairly outdated. Let's just disable whole LPM for now. Signed-off-by: Tejun Heo Reported-and-tested-by: Nikos Barkas Reported-and-tested-by: Ioannis Barkas References: https://bugzilla.kernel.org/show_bug.cgi?id=57211 Cc: stable@vger.kernel.org --- drivers/ata/libata-core.c | 27 +++++++++++++++++++++++++++ drivers/ata/libata-scsi.c | 18 +++++++++++++++--- include/linux/libata.h | 2 ++ 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 1393a5890ed5..1a3dbd1b196e 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2222,6 +2222,16 @@ int ata_dev_configure(struct ata_device *dev) if (rc) return rc; + /* some WD SATA-1 drives have issues with LPM, turn on NOLPM for them */ + if ((dev->horkage & ATA_HORKAGE_WD_BROKEN_LPM) && + (id[ATA_ID_SATA_CAPABILITY] & 0xe) == 0x2) + dev->horkage |= ATA_HORKAGE_NOLPM; + + if (dev->horkage & ATA_HORKAGE_NOLPM) { + ata_dev_warn(dev, "LPM support broken, forcing max_power\n"); + dev->link->ap->target_lpm_policy = ATA_LPM_MAX_POWER; + } + /* let ACPI work its magic */ rc = ata_acpi_on_devcfg(dev); if (rc) @@ -4216,6 +4226,23 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "Micron_M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, { "Crucial_CT???M500SSD1", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, + /* + * Some WD SATA-I drives spin up and down erratically when the link + * is put into the slumber mode. We don't have full list of the + * affected devices. Disable LPM if the device matches one of the + * known prefixes and is SATA-1. As a side effect LPM partial is + * lost too. + * + * https://bugzilla.kernel.org/show_bug.cgi?id=57211 + */ + { "WDC WD800JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM }, + { "WDC WD1200JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM }, + { "WDC WD1600JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM }, + { "WDC WD2000JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM }, + { "WDC WD2500JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM }, + { "WDC WD3000JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM }, + { "WDC WD3200JD-*", NULL, ATA_HORKAGE_WD_BROKEN_LPM }, + /* End Marker */ { } }; diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 176f62950e3d..75ef9527603e 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -111,12 +111,14 @@ static const char *ata_lpm_policy_names[] = { [ATA_LPM_MIN_POWER] = "min_power", }; -static ssize_t ata_scsi_lpm_store(struct device *dev, +static ssize_t ata_scsi_lpm_store(struct device *device, struct device_attribute *attr, const char *buf, size_t count) { - struct Scsi_Host *shost = class_to_shost(dev); + struct Scsi_Host *shost = class_to_shost(device); struct ata_port *ap = ata_shost_to_port(shost); + struct ata_link *link; + struct ata_device *dev; enum ata_lpm_policy policy; unsigned long flags; @@ -132,10 +134,20 @@ static ssize_t ata_scsi_lpm_store(struct device *dev, return -EINVAL; spin_lock_irqsave(ap->lock, flags); + + ata_for_each_link(link, ap, EDGE) { + ata_for_each_dev(dev, &ap->link, ENABLED) { + if (dev->horkage & ATA_HORKAGE_NOLPM) { + count = -EOPNOTSUPP; + goto out_unlock; + } + } + } + ap->target_lpm_policy = policy; ata_port_schedule_eh(ap); +out_unlock: spin_unlock_irqrestore(ap->lock, flags); - return count; } diff --git a/include/linux/libata.h b/include/linux/libata.h index 9b503376738f..bec6dbe939a0 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -419,6 +419,8 @@ enum { ATA_HORKAGE_MAX_SEC_LBA48 = (1 << 17), /* Set max sects to 65535 */ ATA_HORKAGE_ATAPI_DMADIR = (1 << 18), /* device requires dmadir */ ATA_HORKAGE_NO_NCQ_TRIM = (1 << 19), /* don't use queued TRIM */ + ATA_HORKAGE_NOLPM = (1 << 20), /* don't use LPM */ + ATA_HORKAGE_WD_BROKEN_LPM = (1 << 21), /* some WDs have broken LPM */ /* DMA mask for user DMA control: User visible values; DO NOT renumber */ From 3a3a8cf51df49e61dce7e623fb2bcc1a9e560efe Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 19 Jan 2014 00:48:44 +0100 Subject: [PATCH 19/20] sata-highbank: Remove unnecessary ahci_platform.h include The sata-highbank driver is a complete standalone sata driver, which does not use ahci_platform.c / ahci_platform_data in any way. Signed-off-by: Hans de Goede Signed-off-by: Tejun Heo --- drivers/ata/sata_highbank.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c index ea3b3dc10f33..870b11eadc6d 100644 --- a/drivers/ata/sata_highbank.c +++ b/drivers/ata/sata_highbank.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include From b7db4f2e15603c394da56a0536a33669f4c87c4f Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 26 Dec 2013 18:25:41 +0100 Subject: [PATCH 20/20] SATA: MV: Add support for the optional PHYs Some Marvell SoCs have a SATA PHY which can be powered off, in order to save power. Make use of the generic phy framework to control these phys. Signed-off-by: Andrew Lunn Signed-off-by: Tejun Heo --- drivers/ata/sata_mv.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index dc9d4b1ea4ec..20a7517bd339 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -564,6 +565,12 @@ struct mv_host_priv { */ struct clk *clk; struct clk **port_clks; + /* + * Some devices have a SATA PHY which can be enabled/disabled + * in order to save power. These are optional: if the platform + * devices does not have any phy, they won't be used. + */ + struct phy **port_phys; /* * These consistent DMA memory pools give us guaranteed * alignment for hardware-accessed data structures, @@ -4091,6 +4098,11 @@ static int mv_platform_probe(struct platform_device *pdev) GFP_KERNEL); if (!hpriv->port_clks) return -ENOMEM; + hpriv->port_phys = devm_kzalloc(&pdev->dev, + sizeof(struct phy *) * n_ports, + GFP_KERNEL); + if (!hpriv->port_phys) + return -ENOMEM; host->private_data = hpriv; hpriv->n_ports = n_ports; hpriv->board_idx = chip_soc; @@ -4112,6 +4124,17 @@ static int mv_platform_probe(struct platform_device *pdev) hpriv->port_clks[port] = clk_get(&pdev->dev, port_number); if (!IS_ERR(hpriv->port_clks[port])) clk_prepare_enable(hpriv->port_clks[port]); + + sprintf(port_number, "port%d", port); + hpriv->port_phys[port] = devm_phy_get(&pdev->dev, port_number); + if (IS_ERR(hpriv->port_phys[port])) { + rc = PTR_ERR(hpriv->port_phys[port]); + hpriv->port_phys[port] = NULL; + if ((rc != -EPROBE_DEFER) && (rc != -ENODEV)) + dev_warn(&pdev->dev, "error getting phy"); + goto err; + } else + phy_power_on(hpriv->port_phys[port]); } /* @@ -4156,6 +4179,8 @@ err: clk_disable_unprepare(hpriv->port_clks[port]); clk_put(hpriv->port_clks[port]); } + if (hpriv->port_phys[port]) + phy_power_off(hpriv->port_phys[port]); } return rc; @@ -4185,6 +4210,8 @@ static int mv_platform_remove(struct platform_device *pdev) clk_disable_unprepare(hpriv->port_clks[port]); clk_put(hpriv->port_clks[port]); } + if (hpriv->port_phys[port]) + phy_power_off(hpriv->port_phys[port]); } return 0; }