diff options
Diffstat (limited to 'target/linux/layerscape/patches-4.14/801-sata-support-layerscape.patch')
-rw-r--r-- | target/linux/layerscape/patches-4.14/801-sata-support-layerscape.patch | 243 |
1 files changed, 232 insertions, 11 deletions
diff --git a/target/linux/layerscape/patches-4.14/801-sata-support-layerscape.patch b/target/linux/layerscape/patches-4.14/801-sata-support-layerscape.patch index aaf677b564..779127058a 100644 --- a/target/linux/layerscape/patches-4.14/801-sata-support-layerscape.patch +++ b/target/linux/layerscape/patches-4.14/801-sata-support-layerscape.patch @@ -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) |