From e5878732a521dd31ea6377875e49adc424503e5b Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Mon, 19 Mar 2018 10:02:18 +0800 Subject: [PATCH] ahci: imx: add the imx6qp ahci sata support - Regarding to imx6q ahci sata, imx6qp ahci sata has the reset mechanism. Add the imx6qp ahci sata support in this commit. - Use the specific reset callback for imx53 sata, and use the default ahci_ops.softreset for the others. Signed-off-by: Richard Zhu Signed-off-by: Tejun Heo --- Documentation/devicetree/bindings/ata/imx-sata.txt | 1 + drivers/ata/ahci_imx.c | 36 +++++++++++++++++++--- include/linux/mfd/syscon/imx6q-iomuxc-gpr.h | 2 ++ 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/ata/imx-sata.txt b/Documentation/devicetree/bindings/ata/imx-sata.txt index a3d1471..781f887 100644 --- a/Documentation/devicetree/bindings/ata/imx-sata.txt +++ b/Documentation/devicetree/bindings/ata/imx-sata.txt @@ -7,6 +7,7 @@ Required properties: - compatible : should be one of the following: - "fsl,imx53-ahci" for i.MX53 SATA controller - "fsl,imx6q-ahci" for i.MX6Q SATA controller + - "fsl,imx6qp-ahci" for i.MX6QP SATA controller - interrupts : interrupt mapping for SATA IRQ - reg : registers mapping - clocks : list of clock specifiers, must contain an entry for each diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index a58bcc0..577458f 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -58,6 +58,7 @@ enum { enum ahci_imx_type { AHCI_IMX53, AHCI_IMX6Q, + AHCI_IMX6QP, }; struct imx_ahci_priv { @@ -188,11 +189,26 @@ static int imx_phy_reg_read(u16 *val, void __iomem *mmio) static int imx_sata_phy_reset(struct ahci_host_priv *hpriv) { + struct imx_ahci_priv *imxpriv = hpriv->plat_data; void __iomem *mmio = hpriv->mmio; int timeout = 10; u16 val; int ret; + if (imxpriv->type == AHCI_IMX6QP) { + /* 6qp adds the sata reset mechanism, use it for 6qp sata */ + regmap_update_bits(imxpriv->gpr, IOMUXC_GPR5, + IMX6Q_GPR5_SATA_SW_PD, 0); + + regmap_update_bits(imxpriv->gpr, IOMUXC_GPR5, + IMX6Q_GPR5_SATA_SW_RST, 0); + udelay(50); + regmap_update_bits(imxpriv->gpr, IOMUXC_GPR5, + IMX6Q_GPR5_SATA_SW_RST, + IMX6Q_GPR5_SATA_SW_RST); + return 0; + } + /* Reset SATA PHY by setting RESET bit of PHY register CLOCK_RESET */ ret = imx_phy_reg_addressing(IMX_CLOCK_RESET, mmio); if (ret) @@ -408,7 +424,7 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv) if (ret < 0) goto disable_regulator; - if (imxpriv->type == AHCI_IMX6Q) { + if (imxpriv->type == AHCI_IMX6Q || imxpriv->type == AHCI_IMX6QP) { /* * set PHY Paremeters, two steps to configure the GPR13, * one write for rest of parameters, mask of first write @@ -459,10 +475,21 @@ static void imx_sata_disable(struct ahci_host_priv *hpriv) if (imxpriv->no_device) return; - if (imxpriv->type == AHCI_IMX6Q) { + switch (imxpriv->type) { + case AHCI_IMX6QP: + regmap_update_bits(imxpriv->gpr, IOMUXC_GPR5, + IMX6Q_GPR5_SATA_SW_PD, + IMX6Q_GPR5_SATA_SW_PD); regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, IMX6Q_GPR13_SATA_MPLL_CLK_EN, !IMX6Q_GPR13_SATA_MPLL_CLK_EN); + break; + + case AHCI_IMX6Q: + regmap_update_bits(imxpriv->gpr, IOMUXC_GPR13, + IMX6Q_GPR13_SATA_MPLL_CLK_EN, + !IMX6Q_GPR13_SATA_MPLL_CLK_EN); + break; } clk_disable_unprepare(imxpriv->sata_ref_clk); @@ -513,7 +540,7 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class, if (imxpriv->type == AHCI_IMX53) ret = ahci_pmp_retry_srst_ops.softreset(link, class, deadline); - else if (imxpriv->type == AHCI_IMX6Q) + else ret = ahci_ops.softreset(link, class, deadline); return ret; @@ -536,6 +563,7 @@ static const struct ata_port_info ahci_imx_port_info = { static const struct of_device_id imx_ahci_of_match[] = { { .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 }, { .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q }, + { .compatible = "fsl,imx6qp-ahci", .data = (void *)AHCI_IMX6QP }, {}, }; MODULE_DEVICE_TABLE(of, imx_ahci_of_match); @@ -743,7 +771,7 @@ static int imx_ahci_probe(struct platform_device *pdev) return PTR_ERR(imxpriv->ahb_clk); } - if (imxpriv->type == AHCI_IMX6Q) { + if (imxpriv->type == AHCI_IMX6Q || imxpriv->type == AHCI_IMX6QP) { u32 reg_value; imxpriv->gpr = syscon_regmap_lookup_by_compatible( diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h index c8e0164..e06f5f7 100644 --- a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h +++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h @@ -243,6 +243,8 @@ #define IMX6Q_GPR4_IPU_RD_CACHE_CTL BIT(0) #define IMX6Q_GPR5_L2_CLK_STOP BIT(8) +#define IMX6Q_GPR5_SATA_SW_PD BIT(10) +#define IMX6Q_GPR5_SATA_SW_RST BIT(11) #define IMX6Q_GPR6_IPU1_ID00_WR_QOS_MASK (0xf << 0) #define IMX6Q_GPR6_IPU1_ID01_WR_QOS_MASK (0xf << 4) -- 2.7.4