Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/ata/ahci_qoriq.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Freescale QorIQ AHCI SATA platform driver
4
*
5
* Copyright 2015 Freescale, Inc.
6
* Tang Yuantian <[email protected]>
7
*/
8
9
#include <linux/acpi.h>
10
#include <linux/kernel.h>
11
#include <linux/module.h>
12
#include <linux/pm.h>
13
#include <linux/ahci_platform.h>
14
#include <linux/device.h>
15
#include <linux/of.h>
16
#include <linux/platform_device.h>
17
#include <linux/libata.h>
18
#include "ahci.h"
19
20
#define DRV_NAME "ahci-qoriq"
21
22
/* port register definition */
23
#define PORT_PHY1 0xA8
24
#define PORT_PHY2 0xAC
25
#define PORT_PHY3 0xB0
26
#define PORT_PHY4 0xB4
27
#define PORT_PHY5 0xB8
28
#define PORT_AXICC 0xBC
29
#define PORT_TRANS 0xC8
30
31
/* port register default value */
32
#define AHCI_PORT_PHY_1_CFG 0xa003fffe
33
#define AHCI_PORT_PHY2_CFG 0x28184d1f
34
#define AHCI_PORT_PHY3_CFG 0x0e081509
35
#define AHCI_PORT_TRANS_CFG 0x08000029
36
#define AHCI_PORT_AXICC_CFG 0x3fffffff
37
38
/* for ls1021a */
39
#define LS1021A_PORT_PHY2 0x28183414
40
#define LS1021A_PORT_PHY3 0x0e080e06
41
#define LS1021A_PORT_PHY4 0x064a080b
42
#define LS1021A_PORT_PHY5 0x2aa86470
43
#define LS1021A_AXICC_ADDR 0xC0
44
45
#define SATA_ECC_DISABLE 0x00020000
46
#define ECC_DIS_ARMV8_CH2 0x80000000
47
#define ECC_DIS_LS1088A 0x40000000
48
49
enum ahci_qoriq_type {
50
AHCI_LS1021A,
51
AHCI_LS1028A,
52
AHCI_LS1043A,
53
AHCI_LS2080A,
54
AHCI_LS1046A,
55
AHCI_LS1088A,
56
AHCI_LS2088A,
57
AHCI_LX2160A,
58
};
59
60
struct ahci_qoriq_priv {
61
struct ccsr_ahci *reg_base;
62
enum ahci_qoriq_type type;
63
void __iomem *ecc_addr;
64
bool is_dmacoherent;
65
};
66
67
static bool ecc_initialized;
68
69
static const struct of_device_id ahci_qoriq_of_match[] = {
70
{ .compatible = "fsl,ls1021a-ahci", .data = (void *)AHCI_LS1021A},
71
{ .compatible = "fsl,ls1028a-ahci", .data = (void *)AHCI_LS1028A},
72
{ .compatible = "fsl,ls1043a-ahci", .data = (void *)AHCI_LS1043A},
73
{ .compatible = "fsl,ls2080a-ahci", .data = (void *)AHCI_LS2080A},
74
{ .compatible = "fsl,ls1046a-ahci", .data = (void *)AHCI_LS1046A},
75
{ .compatible = "fsl,ls1088a-ahci", .data = (void *)AHCI_LS1088A},
76
{ .compatible = "fsl,ls2088a-ahci", .data = (void *)AHCI_LS2088A},
77
{ .compatible = "fsl,lx2160a-ahci", .data = (void *)AHCI_LX2160A},
78
{ /* sentinel */ }
79
};
80
MODULE_DEVICE_TABLE(of, ahci_qoriq_of_match);
81
82
static const struct acpi_device_id ahci_qoriq_acpi_match[] = {
83
{"NXP0004", .driver_data = (kernel_ulong_t)AHCI_LX2160A},
84
{ }
85
};
86
MODULE_DEVICE_TABLE(acpi, ahci_qoriq_acpi_match);
87
88
static int ahci_qoriq_hardreset(struct ata_link *link, unsigned int *class,
89
unsigned long deadline)
90
{
91
const unsigned int *timing = sata_ehc_deb_timing(&link->eh_context);
92
void __iomem *port_mmio = ahci_port_base(link->ap);
93
u32 px_cmd, px_is, px_val;
94
struct ata_port *ap = link->ap;
95
struct ahci_port_priv *pp = ap->private_data;
96
struct ahci_host_priv *hpriv = ap->host->private_data;
97
struct ahci_qoriq_priv *qoriq_priv = hpriv->plat_data;
98
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
99
struct ata_taskfile tf;
100
bool online;
101
int rc;
102
bool ls1021a_workaround = (qoriq_priv->type == AHCI_LS1021A);
103
104
hpriv->stop_engine(ap);
105
106
/*
107
* There is a errata on ls1021a Rev1.0 and Rev2.0 which is:
108
* A-009042: The device detection initialization sequence
109
* mistakenly resets some registers.
110
*
111
* Workaround for this is:
112
* The software should read and store PxCMD and PxIS values
113
* before issuing the device detection initialization sequence.
114
* After the sequence is complete, software should restore the
115
* PxCMD and PxIS with the stored values.
116
*/
117
if (ls1021a_workaround) {
118
px_cmd = readl(port_mmio + PORT_CMD);
119
px_is = readl(port_mmio + PORT_IRQ_STAT);
120
}
121
122
/* clear D2H reception area to properly wait for D2H FIS */
123
ata_tf_init(link->device, &tf);
124
tf.status = ATA_BUSY;
125
ata_tf_to_fis(&tf, 0, 0, d2h_fis);
126
127
rc = sata_link_hardreset(link, timing, deadline, &online,
128
ahci_check_ready);
129
130
/* restore the PxCMD and PxIS on ls1021 */
131
if (ls1021a_workaround) {
132
px_val = readl(port_mmio + PORT_CMD);
133
if (px_val != px_cmd)
134
writel(px_cmd, port_mmio + PORT_CMD);
135
136
px_val = readl(port_mmio + PORT_IRQ_STAT);
137
if (px_val != px_is)
138
writel(px_is, port_mmio + PORT_IRQ_STAT);
139
}
140
141
hpriv->start_engine(ap);
142
143
if (online)
144
*class = ahci_dev_classify(ap);
145
return rc;
146
}
147
148
static struct ata_port_operations ahci_qoriq_ops = {
149
.inherits = &ahci_ops,
150
.reset.hardreset = ahci_qoriq_hardreset,
151
};
152
153
static const struct ata_port_info ahci_qoriq_port_info = {
154
.flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
155
.pio_mask = ATA_PIO4,
156
.udma_mask = ATA_UDMA6,
157
.port_ops = &ahci_qoriq_ops,
158
};
159
160
static const struct scsi_host_template ahci_qoriq_sht = {
161
AHCI_SHT(DRV_NAME),
162
};
163
164
static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
165
{
166
struct ahci_qoriq_priv *qpriv = hpriv->plat_data;
167
void __iomem *reg_base = hpriv->mmio;
168
169
switch (qpriv->type) {
170
case AHCI_LS1021A:
171
if (!(qpriv->ecc_addr || ecc_initialized))
172
return -EINVAL;
173
else if (qpriv->ecc_addr && !ecc_initialized)
174
writel(SATA_ECC_DISABLE, qpriv->ecc_addr);
175
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
176
writel(LS1021A_PORT_PHY2, reg_base + PORT_PHY2);
177
writel(LS1021A_PORT_PHY3, reg_base + PORT_PHY3);
178
writel(LS1021A_PORT_PHY4, reg_base + PORT_PHY4);
179
writel(LS1021A_PORT_PHY5, reg_base + PORT_PHY5);
180
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
181
if (qpriv->is_dmacoherent)
182
writel(AHCI_PORT_AXICC_CFG,
183
reg_base + LS1021A_AXICC_ADDR);
184
break;
185
186
case AHCI_LS1043A:
187
if (!(qpriv->ecc_addr || ecc_initialized))
188
return -EINVAL;
189
else if (qpriv->ecc_addr && !ecc_initialized)
190
writel(readl(qpriv->ecc_addr) |
191
ECC_DIS_ARMV8_CH2,
192
qpriv->ecc_addr);
193
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
194
writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2);
195
writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3);
196
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
197
if (qpriv->is_dmacoherent)
198
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
199
break;
200
201
case AHCI_LS2080A:
202
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
203
writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2);
204
writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3);
205
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
206
if (qpriv->is_dmacoherent)
207
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
208
break;
209
210
case AHCI_LS1046A:
211
if (!(qpriv->ecc_addr || ecc_initialized))
212
return -EINVAL;
213
else if (qpriv->ecc_addr && !ecc_initialized)
214
writel(readl(qpriv->ecc_addr) |
215
ECC_DIS_ARMV8_CH2,
216
qpriv->ecc_addr);
217
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
218
writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2);
219
writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3);
220
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
221
if (qpriv->is_dmacoherent)
222
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
223
break;
224
225
case AHCI_LS1028A:
226
case AHCI_LS1088A:
227
case AHCI_LX2160A:
228
if (!(qpriv->ecc_addr || ecc_initialized))
229
return -EINVAL;
230
else if (qpriv->ecc_addr && !ecc_initialized)
231
writel(readl(qpriv->ecc_addr) |
232
ECC_DIS_LS1088A,
233
qpriv->ecc_addr);
234
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
235
writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2);
236
writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3);
237
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
238
if (qpriv->is_dmacoherent)
239
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
240
break;
241
242
case AHCI_LS2088A:
243
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
244
writel(AHCI_PORT_PHY2_CFG, reg_base + PORT_PHY2);
245
writel(AHCI_PORT_PHY3_CFG, reg_base + PORT_PHY3);
246
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
247
if (qpriv->is_dmacoherent)
248
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
249
break;
250
}
251
252
ecc_initialized = true;
253
return 0;
254
}
255
256
static int ahci_qoriq_probe(struct platform_device *pdev)
257
{
258
struct device_node *np = pdev->dev.of_node;
259
const struct acpi_device_id *acpi_id;
260
struct device *dev = &pdev->dev;
261
struct ahci_host_priv *hpriv;
262
struct ahci_qoriq_priv *qoriq_priv;
263
const struct of_device_id *of_id;
264
struct resource *res;
265
int rc;
266
267
hpriv = ahci_platform_get_resources(pdev, 0);
268
if (IS_ERR(hpriv))
269
return PTR_ERR(hpriv);
270
271
of_id = of_match_node(ahci_qoriq_of_match, np);
272
acpi_id = acpi_match_device(ahci_qoriq_acpi_match, &pdev->dev);
273
if (!(of_id || acpi_id))
274
return -ENODEV;
275
276
qoriq_priv = devm_kzalloc(dev, sizeof(*qoriq_priv), GFP_KERNEL);
277
if (!qoriq_priv)
278
return -ENOMEM;
279
280
if (of_id)
281
qoriq_priv->type = (unsigned long)of_id->data;
282
else
283
qoriq_priv->type = (enum ahci_qoriq_type)acpi_id->driver_data;
284
285
if (unlikely(!ecc_initialized)) {
286
res = platform_get_resource_byname(pdev,
287
IORESOURCE_MEM,
288
"sata-ecc");
289
if (res) {
290
qoriq_priv->ecc_addr =
291
devm_ioremap_resource(dev, res);
292
if (IS_ERR(qoriq_priv->ecc_addr))
293
return PTR_ERR(qoriq_priv->ecc_addr);
294
}
295
}
296
297
if (device_get_dma_attr(&pdev->dev) == DEV_DMA_COHERENT)
298
qoriq_priv->is_dmacoherent = true;
299
300
rc = ahci_platform_enable_resources(hpriv);
301
if (rc)
302
return rc;
303
304
hpriv->plat_data = qoriq_priv;
305
rc = ahci_qoriq_phy_init(hpriv);
306
if (rc)
307
goto disable_resources;
308
309
rc = ahci_platform_init_host(pdev, hpriv, &ahci_qoriq_port_info,
310
&ahci_qoriq_sht);
311
if (rc)
312
goto disable_resources;
313
314
return 0;
315
316
disable_resources:
317
ahci_platform_disable_resources(hpriv);
318
319
return rc;
320
}
321
322
#ifdef CONFIG_PM_SLEEP
323
static int ahci_qoriq_resume(struct device *dev)
324
{
325
struct ata_host *host = dev_get_drvdata(dev);
326
struct ahci_host_priv *hpriv = host->private_data;
327
int rc;
328
329
rc = ahci_platform_enable_resources(hpriv);
330
if (rc)
331
return rc;
332
333
rc = ahci_qoriq_phy_init(hpriv);
334
if (rc)
335
goto disable_resources;
336
337
rc = ahci_platform_resume_host(dev);
338
if (rc)
339
goto disable_resources;
340
341
/* We resumed so update PM runtime state */
342
pm_runtime_disable(dev);
343
pm_runtime_set_active(dev);
344
pm_runtime_enable(dev);
345
346
return 0;
347
348
disable_resources:
349
ahci_platform_disable_resources(hpriv);
350
351
return rc;
352
}
353
#endif
354
355
static SIMPLE_DEV_PM_OPS(ahci_qoriq_pm_ops, ahci_platform_suspend,
356
ahci_qoriq_resume);
357
358
static struct platform_driver ahci_qoriq_driver = {
359
.probe = ahci_qoriq_probe,
360
.remove = ata_platform_remove_one,
361
.driver = {
362
.name = DRV_NAME,
363
.of_match_table = ahci_qoriq_of_match,
364
.acpi_match_table = ahci_qoriq_acpi_match,
365
.pm = &ahci_qoriq_pm_ops,
366
},
367
};
368
module_platform_driver(ahci_qoriq_driver);
369
370
MODULE_DESCRIPTION("Freescale QorIQ AHCI SATA platform driver");
371
MODULE_AUTHOR("Tang Yuantian <[email protected]>");
372
MODULE_LICENSE("GPL");
373
374