aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-5.4/815-sata-0002-ahci-qoriq-workaround-for-errata-A-379364-on-lx2160a.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/layerscape/patches-5.4/815-sata-0002-ahci-qoriq-workaround-for-errata-A-379364-on-lx2160a.patch')
-rw-r--r--target/linux/layerscape/patches-5.4/815-sata-0002-ahci-qoriq-workaround-for-errata-A-379364-on-lx2160a.patch191
1 files changed, 191 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-5.4/815-sata-0002-ahci-qoriq-workaround-for-errata-A-379364-on-lx2160a.patch b/target/linux/layerscape/patches-5.4/815-sata-0002-ahci-qoriq-workaround-for-errata-A-379364-on-lx2160a.patch
new file mode 100644
index 0000000000..ff5ae9ceee
--- /dev/null
+++ b/target/linux/layerscape/patches-5.4/815-sata-0002-ahci-qoriq-workaround-for-errata-A-379364-on-lx2160a.patch
@@ -0,0 +1,191 @@
+From 73f7122003fca0d08142370e5b6c25783a7b43e9 Mon Sep 17 00:00:00 2001
+From: Peng Ma <peng.ma@nxp.com>
+Date: Wed, 15 May 2019 05:52:44 +0000
+Subject: [PATCH] ahci: qoriq: workaround for errata A-379364 on lx2160a
+
+There is a erratum on lx2160a which is: "SATA link is
+going down sometime during sata initialization"
+The workaround for it is to reset the lane. This patch
+implements this workaround.
+This erratum only exists on lx2160 Rev1, will be addressed
+on Rev2 and later.
+
+Signed-off-by: Peng Ma <peng.ma@nxp.com>
+---
+ drivers/ata/ahci_qoriq.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 144 insertions(+)
+
+--- a/drivers/ata/ahci_qoriq.c
++++ b/drivers/ata/ahci_qoriq.c
+@@ -48,6 +48,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_LS1028A,
+@@ -87,6 +108,126 @@ static const struct acpi_device_id ahci_
+ };
+ MODULE_DEVICE_TABLE(acpi, ahci_qoriq_acpi_match);
+
++static void fsl_sata_errata_379364(bool select)
++{
++ int val = 0;
++ void __iomem *rcw_base = NULL;
++ void __iomem *serdes_base = NULL;
++ void __iomem *dev_con_base = NULL;
++
++ if (select) {
++ dev_con_base = ioremap(DEVICE_CONFIG_REG_BASE, PAGE_SIZE);
++ if (!dev_con_base)
++ 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)
++ goto dev_unmap;
++
++ rcw_base = ioremap(RCWSR29_BASE, PAGE_SIZE);
++ if (!rcw_base)
++ goto serdes_unmap;
++
++ msleep(20);
++
++ 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;
++ }
++ } else {
++ return;
++ }
++
++ iounmap(rcw_base);
++serdes_unmap:
++ iounmap(serdes_base);
++dev_unmap:
++ iounmap(dev_con_base);
++}
++
+ static int ahci_qoriq_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+ {
+@@ -102,6 +243,7 @@ static int ahci_qoriq_hardreset(struct a
+ bool online;
+ int rc;
+ bool ls1021a_workaround = (qoriq_priv->type == AHCI_LS1021A);
++ bool lx2160a_workaround = (qoriq_priv->type == AHCI_LX2160A);
+
+ DPRINTK("ENTER\n");
+
+@@ -128,6 +270,8 @@ static int ahci_qoriq_hardreset(struct a
+ tf.command = ATA_BUSY;
+ ata_tf_to_fis(&tf, 0, 0, d2h_fis);
+
++ fsl_sata_errata_379364(lx2160a_workaround);
++
+ rc = sata_link_hardreset(link, timing, deadline, &online,
+ ahci_check_ready);
+