ahci: imx: add the imx6qp ahci sata support
authorRichard Zhu <hongxing.zhu@nxp.com>
Mon, 19 Mar 2018 02:02:18 +0000 (10:02 +0800)
committerTejun Heo <tj@kernel.org>
Mon, 19 Mar 2018 14:34:08 +0000 (07:34 -0700)
- 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 <hongxing.zhu@nxp.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Documentation/devicetree/bindings/ata/imx-sata.txt
drivers/ata/ahci_imx.c
include/linux/mfd/syscon/imx6q-iomuxc-gpr.h

index a3d14719e478ad865c0a032a5ae5f01b979598d5..781f887517626ad83dc4ce010399dd41946d6bba 100644 (file)
@@ -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
index a58bcc069c54f5a6dcc4ccca7e7821f4163bd279..577458fe4aa980ef9ce3f6d01cdbe300fbff336e 100644 (file)
@@ -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(
index c8e0164c54236f9e32edf33b7e6c961a26540e2f..e06f5f79eaef8e0dd8ce446b811406edf6704662 100644 (file)
 #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)