ff5ae9ceeec3628b8f0dfe686ec8e7e99201e388
[openwrt/staging/ynezz.git] /
1 From 73f7122003fca0d08142370e5b6c25783a7b43e9 Mon Sep 17 00:00:00 2001
2 From: Peng Ma <peng.ma@nxp.com>
3 Date: Wed, 15 May 2019 05:52:44 +0000
4 Subject: [PATCH] ahci: qoriq: workaround for errata A-379364 on lx2160a
5
6 There is a erratum on lx2160a which is: "SATA link is
7 going down sometime during sata initialization"
8 The workaround for it is to reset the lane. This patch
9 implements this workaround.
10 This erratum only exists on lx2160 Rev1, will be addressed
11 on Rev2 and later.
12
13 Signed-off-by: Peng Ma <peng.ma@nxp.com>
14 ---
15 drivers/ata/ahci_qoriq.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++
16 1 file changed, 144 insertions(+)
17
18 --- a/drivers/ata/ahci_qoriq.c
19 +++ b/drivers/ata/ahci_qoriq.c
20 @@ -48,6 +48,27 @@
21 #define ECC_DIS_ARMV8_CH2 0x80000000
22 #define ECC_DIS_LS1088A 0x40000000
23
24 +/* errata for lx2160 */
25 +#define RCWSR29_BASE 0x1E00170
26 +#define SERDES2_BASE 0x1EB0000
27 +#define DEVICE_CONFIG_REG_BASE 0x1E00000
28 +#define SERDES2_LNAX_RX_CR(x) (0x840 + (0x100 * (x)))
29 +#define SERDES2_LNAX_RX_CBR(x) (0x8C0 + (0x100 * (x)))
30 +#define SYS_VER_REG 0xA4
31 +#define LN_RX_RST 0x80000010
32 +#define LN_RX_RST_DONE 0x3
33 +#define LN_RX_MASK 0xf
34 +#define LX2160A_VER1 0x1
35 +
36 +#define SERDES2_LNAA 0
37 +#define SERDES2_LNAB 1
38 +#define SERDES2_LNAC 2
39 +#define SERDES2_LNAD 3
40 +#define SERDES2_LNAE 4
41 +#define SERDES2_LNAF 5
42 +#define SERDES2_LNAG 6
43 +#define SERDES2_LNAH 7
44 +
45 enum ahci_qoriq_type {
46 AHCI_LS1021A,
47 AHCI_LS1028A,
48 @@ -87,6 +108,126 @@ static const struct acpi_device_id ahci_
49 };
50 MODULE_DEVICE_TABLE(acpi, ahci_qoriq_acpi_match);
51
52 +static void fsl_sata_errata_379364(bool select)
53 +{
54 + int val = 0;
55 + void __iomem *rcw_base = NULL;
56 + void __iomem *serdes_base = NULL;
57 + void __iomem *dev_con_base = NULL;
58 +
59 + if (select) {
60 + dev_con_base = ioremap(DEVICE_CONFIG_REG_BASE, PAGE_SIZE);
61 + if (!dev_con_base)
62 + return;
63 +
64 + val = (readl(dev_con_base + SYS_VER_REG) & GENMASK(7, 4)) >> 4;
65 + if (val != LX2160A_VER1)
66 + goto dev_unmap;
67 +
68 + /*
69 + * Add few msec delay.
70 + * Check for corresponding serdes lane RST_DONE .
71 + * apply lane reset.
72 + */
73 +
74 + serdes_base = ioremap(SERDES2_BASE, PAGE_SIZE);
75 + if (!serdes_base)
76 + goto dev_unmap;
77 +
78 + rcw_base = ioremap(RCWSR29_BASE, PAGE_SIZE);
79 + if (!rcw_base)
80 + goto serdes_unmap;
81 +
82 + msleep(20);
83 +
84 + val = (readl(rcw_base) & GENMASK(25, 21)) >> 21;
85 +
86 + switch (val) {
87 + case 1:
88 + if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAC)) &
89 + LN_RX_MASK) != LN_RX_RST_DONE)
90 + writel(LN_RX_RST, serdes_base +
91 + SERDES2_LNAX_RX_CR(SERDES2_LNAC));
92 + if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAD)) &
93 + LN_RX_MASK) != LN_RX_RST_DONE)
94 + writel(LN_RX_RST, serdes_base +
95 + SERDES2_LNAX_RX_CR(SERDES2_LNAD));
96 + break;
97 +
98 + case 4:
99 + if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAG)) &
100 + LN_RX_MASK) != LN_RX_RST_DONE)
101 + writel(LN_RX_RST, serdes_base +
102 + SERDES2_LNAX_RX_CR(SERDES2_LNAG));
103 + if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAH)) &
104 + LN_RX_MASK) != LN_RX_RST_DONE)
105 + writel(LN_RX_RST, serdes_base +
106 + SERDES2_LNAX_RX_CR(SERDES2_LNAH));
107 + break;
108 +
109 + case 5:
110 + if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAE)) &
111 + LN_RX_MASK) != LN_RX_RST_DONE)
112 + writel(LN_RX_RST, serdes_base +
113 + SERDES2_LNAX_RX_CR(SERDES2_LNAE));
114 + if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAF)) &
115 + LN_RX_MASK) != LN_RX_RST_DONE)
116 + writel(LN_RX_RST, serdes_base +
117 + SERDES2_LNAX_RX_CR(SERDES2_LNAF));
118 + if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAG)) &
119 + LN_RX_MASK) != LN_RX_RST_DONE)
120 + writel(LN_RX_RST, serdes_base +
121 + SERDES2_LNAX_RX_CR(SERDES2_LNAG));
122 + if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAH)) &
123 + LN_RX_MASK) != LN_RX_RST_DONE)
124 + writel(LN_RX_RST, serdes_base +
125 + SERDES2_LNAX_RX_CR(SERDES2_LNAH));
126 + break;
127 +
128 + case 8:
129 + if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAC)) &
130 + LN_RX_MASK) != LN_RX_RST_DONE)
131 + writel(LN_RX_RST, serdes_base +
132 + SERDES2_LNAX_RX_CR(SERDES2_LNAC));
133 + if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAD)) &
134 + LN_RX_MASK) != LN_RX_RST_DONE)
135 + writel(LN_RX_RST, serdes_base +
136 + SERDES2_LNAX_RX_CR(SERDES2_LNAD));
137 + if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAE)) &
138 + LN_RX_MASK) != LN_RX_RST_DONE)
139 + writel(LN_RX_RST, serdes_base +
140 + SERDES2_LNAX_RX_CR(SERDES2_LNAE));
141 + if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAF)) &
142 + LN_RX_MASK) != LN_RX_RST_DONE)
143 + writel(LN_RX_RST, serdes_base +
144 + SERDES2_LNAX_RX_CR(SERDES2_LNAF));
145 + break;
146 +
147 + case 12:
148 + if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAG)) &
149 + LN_RX_MASK) != LN_RX_RST_DONE)
150 + writel(LN_RX_RST, serdes_base +
151 + SERDES2_LNAX_RX_CR(SERDES2_LNAG));
152 + if ((readl(serdes_base + SERDES2_LNAX_RX_CBR(SERDES2_LNAH)) &
153 + LN_RX_MASK) != LN_RX_RST_DONE)
154 + writel(LN_RX_RST, serdes_base +
155 + SERDES2_LNAX_RX_CR(SERDES2_LNAH));
156 + break;
157 +
158 + default:
159 + break;
160 + }
161 + } else {
162 + return;
163 + }
164 +
165 + iounmap(rcw_base);
166 +serdes_unmap:
167 + iounmap(serdes_base);
168 +dev_unmap:
169 + iounmap(dev_con_base);
170 +}
171 +
172 static int ahci_qoriq_hardreset(struct ata_link *link, unsigned int *class,
173 unsigned long deadline)
174 {
175 @@ -102,6 +243,7 @@ static int ahci_qoriq_hardreset(struct a
176 bool online;
177 int rc;
178 bool ls1021a_workaround = (qoriq_priv->type == AHCI_LS1021A);
179 + bool lx2160a_workaround = (qoriq_priv->type == AHCI_LX2160A);
180
181 DPRINTK("ENTER\n");
182
183 @@ -128,6 +270,8 @@ static int ahci_qoriq_hardreset(struct a
184 tf.command = ATA_BUSY;
185 ata_tf_to_fis(&tf, 0, 0, d2h_fis);
186
187 + fsl_sata_errata_379364(lx2160a_workaround);
188 +
189 rc = sata_link_hardreset(link, timing, deadline, &online,
190 ahci_check_ready);
191