layerscape: update patches-4.14 to LSDK 19.03
[openwrt/staging/ynezz.git] / target / linux / layerscape / patches-4.14 / 801-sata-support-layerscape.patch
index aaf677b56432d55e00dd639340b40b32ba37ba43..779127058ac141d3b8411f66c9b3df8df7ac0e82 100644 (file)
@@ -1,15 +1,33 @@
-From 918f966af1f0e42ff8ac298e1d7d02e67afcfab4 Mon Sep 17 00:00:00 2001
+From 71fb63c92eae3f9197e2343ed5ed3676440789e1 Mon Sep 17 00:00:00 2001
 From: Biwen Li <biwen.li@nxp.com>
-Date: Tue, 30 Oct 2018 18:27:42 +0800
-Subject: [PATCH 18/40] sata: support layerscape
+Date: Wed, 17 Apr 2019 18:59:01 +0800
+Subject: [PATCH] sata: support layerscape
+
 This is an integrated patch of sata for layerscape
 
-Signed-off-by: Tang Yuantian <andy.tang@nxp.com>
 Signed-off-by: Biwen Li <biwen.li@nxp.com>
+Signed-off-by: Peng Ma <peng.ma@nxp.com>
+Signed-off-by: Tang Yuantian <andy.tang@nxp.com>
 ---
- drivers/ata/ahci_qoriq.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
+ drivers/ata/ahci.h        |   7 ++
+ drivers/ata/ahci_qoriq.c  | 168 ++++++++++++++++++++++++++++++++++++++
+ drivers/ata/libata-core.c |   3 +
+ 3 files changed, 178 insertions(+)
 
+--- a/drivers/ata/ahci.h
++++ b/drivers/ata/ahci.h
+@@ -445,4 +445,11 @@ static inline int ahci_nr_ports(u32 cap)
+       return (cap & 0x1f) + 1;
+ }
++#ifdef CONFIG_AHCI_QORIQ
++extern void fsl_sata_errata_379364(struct ata_link *link);
++#else
++static void fsl_sata_errata_379364(struct ata_link *link)
++{}
++#endif
++
+ #endif /* _AHCI_H */
 --- a/drivers/ata/ahci_qoriq.c
 +++ b/drivers/ata/ahci_qoriq.c
 @@ -35,6 +35,8 @@
@@ -21,7 +39,190 @@ Signed-off-by: Biwen Li <biwen.li@nxp.com>
  #define AHCI_PORT_TRANS_CFG   0x08000029
  #define AHCI_PORT_AXICC_CFG   0x3fffffff
  
-@@ -183,6 +185,8 @@ static int ahci_qoriq_phy_init(struct ah
+@@ -49,6 +51,27 @@
+ #define ECC_DIS_ARMV8_CH2     0x80000000
+ #define ECC_DIS_LS1088A               0x40000000
++/* errata for lx2160 */
++#define RCWSR29_BASE                  0x1E00170
++#define SERDES2_BASE                  0x1EB0000
++#define DEVICE_CONFIG_REG_BASE                0x1E00000
++#define SERDES2_LNAX_RX_CR(x)         (0x840 + (0x100 * (x)))
++#define SERDES2_LNAX_RX_CBR(x)                (0x8C0 + (0x100 * (x)))
++#define SYS_VER_REG                   0xA4
++#define LN_RX_RST                     0x80000010
++#define LN_RX_RST_DONE                        0x3
++#define LN_RX_MASK                    0xf
++#define LX2160A_VER1                  0x1
++
++#define SERDES2_LNAA 0
++#define SERDES2_LNAB 1
++#define SERDES2_LNAC 2
++#define SERDES2_LNAD 3
++#define SERDES2_LNAE 4
++#define SERDES2_LNAF 5
++#define SERDES2_LNAG 6
++#define SERDES2_LNAH 7
++
+ enum ahci_qoriq_type {
+       AHCI_LS1021A,
+       AHCI_LS1043A,
+@@ -56,6 +79,7 @@ enum ahci_qoriq_type {
+       AHCI_LS1046A,
+       AHCI_LS1088A,
+       AHCI_LS2088A,
++      AHCI_LX2160A,
+ };
+ struct ahci_qoriq_priv {
+@@ -72,6 +96,7 @@ static const struct of_device_id ahci_qo
+       { .compatible = "fsl,ls1046a-ahci", .data = (void *)AHCI_LS1046A},
+       { .compatible = "fsl,ls1088a-ahci", .data = (void *)AHCI_LS1088A},
+       { .compatible = "fsl,ls2088a-ahci", .data = (void *)AHCI_LS2088A},
++      { .compatible = "fsl,lx2160a-ahci", .data = (void *)AHCI_LX2160A},
+       {},
+ };
+ MODULE_DEVICE_TABLE(of, ahci_qoriq_of_match);
+@@ -156,6 +181,138 @@ static struct scsi_host_template ahci_qo
+       AHCI_SHT(DRV_NAME),
+ };
++void fsl_sata_errata_379364(struct ata_link *link)
++{
++      struct ata_port *ap = link->ap;
++      struct ahci_host_priv *hpriv = ap->host->private_data;
++      struct ahci_qoriq_priv *qoriq_priv = hpriv->plat_data;
++      bool lx2160a_workaround = (qoriq_priv->type == AHCI_LX2160A);
++
++      int val = 0;
++      void __iomem *rcw_base = NULL;
++      void __iomem *serdes_base = NULL;
++      void __iomem *dev_con_base = NULL;
++
++      if (!lx2160a_workaround)
++              return;
++      else {
++              dev_con_base = ioremap(DEVICE_CONFIG_REG_BASE, PAGE_SIZE);
++              if (!dev_con_base) {
++                      ata_link_err(link, "device config ioremap failed\n");
++                      return;
++              }
++
++              val = (readl(dev_con_base + SYS_VER_REG) & GENMASK(7, 4)) >> 4;
++              if (val != LX2160A_VER1)
++                      goto dev_unmap;
++
++              /*
++               * Add few msec delay.
++               * Check for corresponding serdes lane RST_DONE .
++               * apply lane reset.
++               */
++
++              serdes_base = ioremap(SERDES2_BASE, PAGE_SIZE);
++              if (!serdes_base) {
++                      ata_link_err(link, "serdes ioremap failed\n");
++                      goto dev_unmap;
++              }
++
++              rcw_base = ioremap(RCWSR29_BASE, PAGE_SIZE);
++              if (!rcw_base) {
++                      ata_link_err(link, "rcw ioremap failed\n");
++                      goto serdes_unmap;
++              }
++
++              ata_msleep(link->ap, 1);
++
++              val = (readl(rcw_base) & GENMASK(25, 21)) >> 21;
++
++              switch (val) {
++              case 1:
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAC)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAC));
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAD)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAD));
++                      break;
++
++              case 4:
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAG)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAG));
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAH)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAH));
++                      break;
++
++              case 5:
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAE)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAE));
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAF)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAF));
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAG)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAG));
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAH)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAH));
++                      break;
++
++              case 8:
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAC)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAC));
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAD)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAD));
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAE)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAE));
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAF)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAF));
++                      break;
++
++              case 12:
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAG)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAG));
++                      if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAH)) &
++                              LN_RX_MASK) != LN_RX_RST_DONE)
++                              writel(LN_RX_RST, serdes_base +
++                                      SERDES2_LNAX_RX_CR(SERDES2_LNAH));
++                      break;
++
++              default:
++                      break;
++              }
++      }
++
++      iounmap(rcw_base);
++serdes_unmap:
++      iounmap(serdes_base);
++dev_unmap:
++      iounmap(dev_con_base);
++}
++
++
+ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
+ {
+       struct ahci_qoriq_priv *qpriv = hpriv->plat_data;
+@@ -183,13 +340,18 @@ static int ahci_qoriq_phy_init(struct ah
                writel(readl(qpriv->ecc_addr) | ECC_DIS_ARMV8_CH2,
                                qpriv->ecc_addr);
                writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
@@ -30,16 +231,17 @@ Signed-off-by: Biwen Li <biwen.li@nxp.com>
                writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
                if (qpriv->is_dmacoherent)
                        writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
-@@ -190,6 +194,8 @@ static int ahci_qoriq_phy_init(struct ah
+               break;
  
        case AHCI_LS2080A:
++      case AHCI_LX2160A:
                writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
 +              writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2);
 +              writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3);
                writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
                if (qpriv->is_dmacoherent)
                        writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
-@@ -201,6 +207,8 @@ static int ahci_qoriq_phy_init(struct ah
+@@ -201,6 +363,8 @@ static int ahci_qoriq_phy_init(struct ah
                writel(readl(qpriv->ecc_addr) | ECC_DIS_ARMV8_CH2,
                                qpriv->ecc_addr);
                writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
@@ -48,7 +250,7 @@ Signed-off-by: Biwen Li <biwen.li@nxp.com>
                writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
                if (qpriv->is_dmacoherent)
                        writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
-@@ -212,6 +220,8 @@ static int ahci_qoriq_phy_init(struct ah
+@@ -212,6 +376,8 @@ static int ahci_qoriq_phy_init(struct ah
                writel(readl(qpriv->ecc_addr) | ECC_DIS_LS1088A,
                       qpriv->ecc_addr);
                writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
@@ -57,7 +259,7 @@ Signed-off-by: Biwen Li <biwen.li@nxp.com>
                writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
                if (qpriv->is_dmacoherent)
                        writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
-@@ -219,6 +229,8 @@ static int ahci_qoriq_phy_init(struct ah
+@@ -219,6 +385,8 @@ static int ahci_qoriq_phy_init(struct ah
  
        case AHCI_LS2088A:
                writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
@@ -66,3 +268,22 @@ Signed-off-by: Biwen Li <biwen.li@nxp.com>
                writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
                if (qpriv->is_dmacoherent)
                        writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -76,6 +76,7 @@
+ #define CREATE_TRACE_POINTS
+ #include <trace/events/libata.h>
++#include "ahci.h"
+ #include "libata.h"
+ #include "libata-transport.h"
+@@ -4119,6 +4120,8 @@ int sata_link_hardreset(struct ata_link
+        */
+       ata_msleep(link->ap, 1);
++      fsl_sata_errata_379364(link);
++
+       /* bring link back */
+       rc = sata_link_resume(link, timing, deadline);
+       if (rc)