blob: 17db64009cb2aac1911510c872de18bc1cc77da0 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Tang Yuantian4511ccc2011-10-07 19:26:58 +00002/*
3 * Copyright (C) 2011 Freescale Semiconductor, Inc.
Peng Ma96f336c2019-11-19 06:17:40 +00004 * Copyright 2019 NXP
Tang Yuantian4511ccc2011-10-07 19:26:58 +00005 * Author: Tang Yuantian <b29983@freescale.com>
Tang Yuantian4511ccc2011-10-07 19:26:58 +00006 */
7
8#include <common.h>
Simon Glass63334482019-11-14 12:57:39 -07009#include <cpu_func.h>
Simon Glass0f2af882020-05-10 11:40:05 -060010#include <log.h>
Tang Yuantian4511ccc2011-10-07 19:26:58 +000011#include <pci.h>
12#include <command.h>
13#include <asm/byteorder.h>
14#include <malloc.h>
15#include <asm/io.h>
16#include <fis.h>
Pavel Herrmann9e9f6282012-09-27 23:18:04 +000017#include <sata.h>
Tang Yuantian4511ccc2011-10-07 19:26:58 +000018#include <libata.h>
Kim Phillips03487482012-10-29 13:34:40 +000019#include <sata.h>
Peng Ma96f336c2019-11-19 06:17:40 +000020
21#if CONFIG_IS_ENABLED(BLK)
22#include <dm.h>
23#include <blk.h>
Peng Ma17dd2612019-12-04 10:36:42 +000024#include <dm/device-internal.h>
Peng Ma96f336c2019-11-19 06:17:40 +000025#endif
26
Tang Yuantian4511ccc2011-10-07 19:26:58 +000027#include "sata_sil.h"
28
Tang Yuantian4511ccc2011-10-07 19:26:58 +000029#define virt_to_bus(devno, v) pci_virt_to_mem(devno, (void *) (v))
30
Peng Ma96f336c2019-11-19 06:17:40 +000031/* just compatible ahci_ops */
32struct sil_ops {
33 int *rev0;
34 int *rev1;
35 int (*scan)(struct udevice *dev);
36};
37
Tang Yuantian4511ccc2011-10-07 19:26:58 +000038static struct sata_info sata_info;
39
40static struct pci_device_id supported[] = {
Peng Ma96f336c2019-11-19 06:17:40 +000041 { PCI_DEVICE(PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3131) },
42 { PCI_DEVICE(PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3132) },
43 { PCI_DEVICE(PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3124) },
Tang Yuantian4511ccc2011-10-07 19:26:58 +000044 {}
45};
46
47static void sil_sata_dump_fis(struct sata_fis_d2h *s)
48{
49 printf("Status FIS dump:\n");
50 printf("fis_type: %02x\n", s->fis_type);
51 printf("pm_port_i: %02x\n", s->pm_port_i);
52 printf("status: %02x\n", s->status);
53 printf("error: %02x\n", s->error);
54 printf("lba_low: %02x\n", s->lba_low);
55 printf("lba_mid: %02x\n", s->lba_mid);
56 printf("lba_high: %02x\n", s->lba_high);
57 printf("device: %02x\n", s->device);
58 printf("lba_low_exp: %02x\n", s->lba_low_exp);
59 printf("lba_mid_exp: %02x\n", s->lba_mid_exp);
60 printf("lba_high_exp: %02x\n", s->lba_high_exp);
61 printf("res1: %02x\n", s->res1);
62 printf("sector_count: %02x\n", s->sector_count);
63 printf("sector_count_exp: %02x\n", s->sector_count_exp);
64}
65
66static const char *sata_spd_string(unsigned int speed)
67{
68 static const char * const spd_str[] = {
69 "1.5 Gbps",
70 "3.0 Gbps",
71 "6.0 Gbps",
72 };
73
74 if ((speed - 1) > 2)
75 return "<unknown>";
76
77 return spd_str[speed - 1];
78}
79
80static u32 ata_wait_register(void *reg, u32 mask,
81 u32 val, int timeout_msec)
82{
83 u32 tmp;
84
85 tmp = readl(reg);
86 while ((tmp & mask) == val && timeout_msec > 0) {
87 mdelay(1);
88 timeout_msec--;
89 tmp = readl(reg);
90 }
91
92 return tmp;
93}
94
95static void sil_config_port(void *port)
96{
97 /* configure IRQ WoC */
98 writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
99
100 /* zero error counters. */
101 writew(0x8000, port + PORT_DECODE_ERR_THRESH);
102 writew(0x8000, port + PORT_CRC_ERR_THRESH);
103 writew(0x8000, port + PORT_HSHK_ERR_THRESH);
104 writew(0x0000, port + PORT_DECODE_ERR_CNT);
105 writew(0x0000, port + PORT_CRC_ERR_CNT);
106 writew(0x0000, port + PORT_HSHK_ERR_CNT);
107
108 /* always use 64bit activation */
109 writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
110
111 /* clear port multiplier enable and resume bits */
112 writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR);
113}
114
115static int sil_init_port(void *port)
116{
117 u32 tmp;
118
119 writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
120 ata_wait_register(port + PORT_CTRL_STAT,
121 PORT_CS_INIT, PORT_CS_INIT, 100);
122 tmp = ata_wait_register(port + PORT_CTRL_STAT,
123 PORT_CS_RDY, 0, 100);
124
125 if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY)
126 return 1;
127
128 return 0;
129}
130
Peng Ma96f336c2019-11-19 06:17:40 +0000131static void sil_read_fis(struct sil_sata *sata, int tag,
132 struct sata_fis_d2h *fis)
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000133{
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000134 void *port = sata->port;
135 struct sil_prb *prb;
136 int i;
137 u32 *src, *dst;
138
139 prb = port + PORT_LRAM + tag * PORT_LRAM_SLOT_SZ;
140 src = (u32 *)&prb->fis;
141 dst = (u32 *)fis;
142 for (i = 0; i < sizeof(struct sata_fis_h2d); i += 4)
143 *dst++ = readl(src++);
144}
145
Peng Ma96f336c2019-11-19 06:17:40 +0000146static int sil_exec_cmd(struct sil_sata *sata, struct sil_cmd_block *pcmd,
147 int tag)
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000148{
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000149 void *port = sata->port;
150 u64 paddr = virt_to_bus(sata->devno, pcmd);
151 u32 irq_mask, irq_stat;
152 int rc;
153
154 writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR);
155
156 /* better to add momery barrior here */
157 writel((u32)paddr, port + PORT_CMD_ACTIVATE + tag * 8);
158 writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + tag * 8 + 4);
159
160 irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
161 irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask,
162 0, 10000);
163
164 /* clear IRQs */
165 writel(irq_mask, port + PORT_IRQ_STAT);
166 irq_stat >>= PORT_IRQ_RAW_SHIFT;
167
168 if (irq_stat & PORT_IRQ_COMPLETE)
169 rc = 0;
170 else {
171 /* force port into known state */
172 sil_init_port(port);
173 if (irq_stat & PORT_IRQ_ERROR)
174 rc = 1; /* error */
175 else
176 rc = 2; /* busy */
177 }
178
179 return rc;
180}
181
Peng Ma96f336c2019-11-19 06:17:40 +0000182static int sil_cmd_set_feature(struct sil_sata *sata)
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000183{
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000184 struct sil_cmd_block cmdb, *pcmd = &cmdb;
185 struct sata_fis_d2h fis;
186 u8 udma_cap;
187 int ret;
188
189 memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block));
190 pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
191 pcmd->prb.fis.pm_port_c = (1 << 7);
192 pcmd->prb.fis.command = ATA_CMD_SET_FEATURES;
193 pcmd->prb.fis.features = SETFEATURES_XFER;
194
195 /* First check the device capablity */
196 udma_cap = (u8)(sata->udma & 0xff);
197 debug("udma_cap %02x\n", udma_cap);
198
199 if (udma_cap == ATA_UDMA6)
200 pcmd->prb.fis.sector_count = XFER_UDMA_6;
201 if (udma_cap == ATA_UDMA5)
202 pcmd->prb.fis.sector_count = XFER_UDMA_5;
203 if (udma_cap == ATA_UDMA4)
204 pcmd->prb.fis.sector_count = XFER_UDMA_4;
205 if (udma_cap == ATA_UDMA3)
206 pcmd->prb.fis.sector_count = XFER_UDMA_3;
207
Peng Ma96f336c2019-11-19 06:17:40 +0000208 ret = sil_exec_cmd(sata, pcmd, 0);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000209 if (ret) {
Peng Ma96f336c2019-11-19 06:17:40 +0000210 sil_read_fis(sata, 0, &fis);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000211 printf("Err: exe cmd(0x%x).\n",
212 readl(sata->port + PORT_SERROR));
213 sil_sata_dump_fis(&fis);
214 return 1;
215 }
216
217 return 0;
218}
219
Peng Ma96f336c2019-11-19 06:17:40 +0000220static void sil_sata_init_wcache(struct sil_sata *sata, u16 *id)
221{
222 if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id))
223 sata->wcache = 1;
224 if (ata_id_has_flush(id))
225 sata->flush = 1;
226 if (ata_id_has_flush_ext(id))
227 sata->flush_ext = 1;
228}
229
230static void sil_sata_set_feature_by_id(struct sil_sata *sata, u16 *id)
231{
232#ifdef CONFIG_LBA48
233 /* Check if support LBA48 */
234 if (ata_id_has_lba48(id)) {
235 sata->lba48 = 1;
236 debug("Device supports LBA48\n");
237 } else {
238 debug("Device supports LBA28\n");
239 }
240#endif
241
242 sil_sata_init_wcache(sata, id);
243 sil_cmd_set_feature(sata);
244}
245
246static int sil_cmd_identify_device(struct sil_sata *sata, u16 *id)
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000247{
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000248 struct sil_cmd_block cmdb, *pcmd = &cmdb;
249 struct sata_fis_d2h fis;
250 int ret;
251
252 memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block));
253 pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL);
254 pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ);
255 pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
256 pcmd->prb.fis.pm_port_c = (1 << 7);
257 pcmd->prb.fis.command = ATA_CMD_ID_ATA;
258 pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, id));
259 pcmd->sge.cnt = cpu_to_le32(sizeof(id[0]) * ATA_ID_WORDS);
260 pcmd->sge.flags = cpu_to_le32(SGE_TRM);
261
Peng Ma96f336c2019-11-19 06:17:40 +0000262 ret = sil_exec_cmd(sata, pcmd, 0);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000263 if (ret) {
Peng Ma96f336c2019-11-19 06:17:40 +0000264 sil_read_fis(sata, 0, &fis);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000265 printf("Err: id cmd(0x%x).\n", readl(sata->port + PORT_SERROR));
266 sil_sata_dump_fis(&fis);
267 return 1;
268 }
269 ata_swap_buf_le16(id, ATA_ID_WORDS);
270
271 return 0;
272}
273
Peng Ma96f336c2019-11-19 06:17:40 +0000274static int sil_cmd_soft_reset(struct sil_sata *sata)
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000275{
276 struct sil_cmd_block cmdb, *pcmd = &cmdb;
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000277 struct sata_fis_d2h fis;
278 void *port = sata->port;
279 int ret;
280
281 /* put the port into known state */
282 if (sil_init_port(port)) {
Peng Ma96f336c2019-11-19 06:17:40 +0000283 printf("SRST: port %d not ready\n", sata->id);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000284 return 1;
285 }
286
287 memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block));
288
289 pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_SRST);
290 pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
291 pcmd->prb.fis.pm_port_c = 0xf;
292
Peng Ma96f336c2019-11-19 06:17:40 +0000293 ret = sil_exec_cmd(sata, &cmdb, 0);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000294 if (ret) {
Peng Ma96f336c2019-11-19 06:17:40 +0000295 sil_read_fis(sata, 0, &fis);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000296 printf("SRST cmd error.\n");
297 sil_sata_dump_fis(&fis);
298 return 1;
299 }
300
301 return 0;
302}
303
Peng Ma96f336c2019-11-19 06:17:40 +0000304static ulong sil_sata_rw_cmd(struct sil_sata *sata, ulong start, ulong blkcnt,
305 u8 *buffer, int is_write)
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000306{
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000307 struct sil_cmd_block cmdb, *pcmd = &cmdb;
308 struct sata_fis_d2h fis;
309 u64 block;
310 int ret;
311
312 block = (u64)start;
313 memset(pcmd, 0, sizeof(struct sil_cmd_block));
314 pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL);
315 pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
316 pcmd->prb.fis.pm_port_c = (1 << 7);
317 if (is_write) {
318 pcmd->prb.fis.command = ATA_CMD_WRITE;
319 pcmd->prb.prot = cpu_to_le16(PRB_PROT_WRITE);
320 } else {
321 pcmd->prb.fis.command = ATA_CMD_READ;
322 pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ);
323 }
324
325 pcmd->prb.fis.device = ATA_LBA;
326 pcmd->prb.fis.device |= (block >> 24) & 0xf;
327 pcmd->prb.fis.lba_high = (block >> 16) & 0xff;
328 pcmd->prb.fis.lba_mid = (block >> 8) & 0xff;
329 pcmd->prb.fis.lba_low = block & 0xff;
330 pcmd->prb.fis.sector_count = (u8)blkcnt & 0xff;
331
332 pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, buffer));
333 pcmd->sge.cnt = cpu_to_le32(blkcnt * ATA_SECT_SIZE);
334 pcmd->sge.flags = cpu_to_le32(SGE_TRM);
335
Peng Ma96f336c2019-11-19 06:17:40 +0000336 ret = sil_exec_cmd(sata, pcmd, 0);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000337 if (ret) {
Peng Ma96f336c2019-11-19 06:17:40 +0000338 sil_read_fis(sata, 0, &fis);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000339 printf("Err: rw cmd(0x%08x).\n",
340 readl(sata->port + PORT_SERROR));
341 sil_sata_dump_fis(&fis);
342 return 1;
343 }
344
345 return blkcnt;
346}
347
Peng Ma96f336c2019-11-19 06:17:40 +0000348static ulong sil_sata_rw_cmd_ext(struct sil_sata *sata, ulong start,
349 ulong blkcnt, u8 *buffer, int is_write)
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000350{
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000351 struct sil_cmd_block cmdb, *pcmd = &cmdb;
352 struct sata_fis_d2h fis;
353 u64 block;
354 int ret;
355
356 block = (u64)start;
357 memset(pcmd, 0, sizeof(struct sil_cmd_block));
358 pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL);
359 pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
360 pcmd->prb.fis.pm_port_c = (1 << 7);
361 if (is_write) {
362 pcmd->prb.fis.command = ATA_CMD_WRITE_EXT;
363 pcmd->prb.prot = cpu_to_le16(PRB_PROT_WRITE);
364 } else {
365 pcmd->prb.fis.command = ATA_CMD_READ_EXT;
366 pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ);
367 }
368
369 pcmd->prb.fis.lba_high_exp = (block >> 40) & 0xff;
370 pcmd->prb.fis.lba_mid_exp = (block >> 32) & 0xff;
371 pcmd->prb.fis.lba_low_exp = (block >> 24) & 0xff;
372 pcmd->prb.fis.lba_high = (block >> 16) & 0xff;
373 pcmd->prb.fis.lba_mid = (block >> 8) & 0xff;
374 pcmd->prb.fis.lba_low = block & 0xff;
375 pcmd->prb.fis.device = ATA_LBA;
376 pcmd->prb.fis.sector_count_exp = (blkcnt >> 8) & 0xff;
377 pcmd->prb.fis.sector_count = blkcnt & 0xff;
378
379 pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, buffer));
380 pcmd->sge.cnt = cpu_to_le32(blkcnt * ATA_SECT_SIZE);
381 pcmd->sge.flags = cpu_to_le32(SGE_TRM);
382
Peng Ma96f336c2019-11-19 06:17:40 +0000383 ret = sil_exec_cmd(sata, pcmd, 0);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000384 if (ret) {
Peng Ma96f336c2019-11-19 06:17:40 +0000385 sil_read_fis(sata, 0, &fis);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000386 printf("Err: rw ext cmd(0x%08x).\n",
387 readl(sata->port + PORT_SERROR));
388 sil_sata_dump_fis(&fis);
389 return 1;
390 }
391
392 return blkcnt;
393}
394
Peng Ma96f336c2019-11-19 06:17:40 +0000395static ulong sil_sata_rw_lba28(struct sil_sata *sata, ulong blknr,
396 lbaint_t blkcnt, const void *buffer,
397 int is_write)
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000398{
399 ulong start, blks, max_blks;
400 u8 *addr;
401
402 start = blknr;
403 blks = blkcnt;
404 addr = (u8 *)buffer;
405
406 max_blks = ATA_MAX_SECTORS;
407 do {
408 if (blks > max_blks) {
Peng Ma96f336c2019-11-19 06:17:40 +0000409 sil_sata_rw_cmd(sata, start, max_blks, addr, is_write);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000410 start += max_blks;
411 blks -= max_blks;
412 addr += ATA_SECT_SIZE * max_blks;
413 } else {
Peng Ma96f336c2019-11-19 06:17:40 +0000414 sil_sata_rw_cmd(sata, start, blks, addr, is_write);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000415 start += blks;
416 blks = 0;
417 addr += ATA_SECT_SIZE * blks;
418 }
419 } while (blks != 0);
420
421 return blkcnt;
422}
423
Peng Ma96f336c2019-11-19 06:17:40 +0000424static ulong sil_sata_rw_lba48(struct sil_sata *sata, ulong blknr,
425 lbaint_t blkcnt, const void *buffer,
426 int is_write)
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000427{
428 ulong start, blks, max_blks;
429 u8 *addr;
430
431 start = blknr;
432 blks = blkcnt;
433 addr = (u8 *)buffer;
434
435 max_blks = ATA_MAX_SECTORS_LBA48;
436 do {
437 if (blks > max_blks) {
Peng Ma96f336c2019-11-19 06:17:40 +0000438 sil_sata_rw_cmd_ext(sata, start, max_blks,
439 addr, is_write);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000440 start += max_blks;
441 blks -= max_blks;
442 addr += ATA_SECT_SIZE * max_blks;
443 } else {
Peng Ma96f336c2019-11-19 06:17:40 +0000444 sil_sata_rw_cmd_ext(sata, start, blks,
445 addr, is_write);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000446 start += blks;
447 blks = 0;
448 addr += ATA_SECT_SIZE * blks;
449 }
450 } while (blks != 0);
451
452 return blkcnt;
453}
454
Peng Ma96f336c2019-11-19 06:17:40 +0000455static void sil_sata_cmd_flush_cache(struct sil_sata *sata)
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000456{
457 struct sil_cmd_block cmdb, *pcmd = &cmdb;
458
459 memset((void *)pcmd, 0, sizeof(struct sil_cmd_block));
460 pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
461 pcmd->prb.fis.pm_port_c = (1 << 7);
462 pcmd->prb.fis.command = ATA_CMD_FLUSH;
463
Peng Ma96f336c2019-11-19 06:17:40 +0000464 sil_exec_cmd(sata, pcmd, 0);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000465}
466
Peng Ma96f336c2019-11-19 06:17:40 +0000467static void sil_sata_cmd_flush_cache_ext(struct sil_sata *sata)
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000468{
469 struct sil_cmd_block cmdb, *pcmd = &cmdb;
470
471 memset((void *)pcmd, 0, sizeof(struct sil_cmd_block));
472 pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
473 pcmd->prb.fis.pm_port_c = (1 << 7);
474 pcmd->prb.fis.command = ATA_CMD_FLUSH_EXT;
475
Peng Ma96f336c2019-11-19 06:17:40 +0000476 sil_exec_cmd(sata, pcmd, 0);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000477}
478
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000479/*
480 * SATA interface between low level driver and command layer
481 */
Peng Ma96f336c2019-11-19 06:17:40 +0000482#if !CONFIG_IS_ENABLED(BLK)
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000483ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer)
484{
Peng Ma96f336c2019-11-19 06:17:40 +0000485 struct sil_sata *sata = (struct sil_sata *)sata_dev_desc[dev].priv;
486#else
487static ulong sata_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
488 void *buffer)
489{
490 struct sil_sata_priv *priv = dev_get_platdata(dev);
491 int port_number = priv->port_num;
492 struct sil_sata *sata = priv->sil_sata_desc[port_number];
493#endif
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000494 ulong rc;
495
496 if (sata->lba48)
Peng Ma96f336c2019-11-19 06:17:40 +0000497 rc = sil_sata_rw_lba48(sata, blknr, blkcnt, buffer, READ_CMD);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000498 else
Peng Ma96f336c2019-11-19 06:17:40 +0000499 rc = sil_sata_rw_lba28(sata, blknr, blkcnt, buffer, READ_CMD);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000500
501 return rc;
502}
503
504/*
505 * SATA interface between low level driver and command layer
506 */
Peng Ma96f336c2019-11-19 06:17:40 +0000507#if !CONFIG_IS_ENABLED(BLK)
Tom Rini4835e132012-09-29 07:57:25 -0700508ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer)
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000509{
Peng Ma96f336c2019-11-19 06:17:40 +0000510 struct sil_sata *sata = (struct sil_sata *)sata_dev_desc[dev].priv;
511#else
512ulong sata_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
513 const void *buffer)
514{
515 struct sil_sata_priv *priv = dev_get_platdata(dev);
516 int port_number = priv->port_num;
517 struct sil_sata *sata = priv->sil_sata_desc[port_number];
518#endif
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000519 ulong rc;
520
521 if (sata->lba48) {
Peng Ma96f336c2019-11-19 06:17:40 +0000522 rc = sil_sata_rw_lba48(sata, blknr, blkcnt, buffer, WRITE_CMD);
523 if (sata->wcache && sata->flush_ext)
524 sil_sata_cmd_flush_cache_ext(sata);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000525 } else {
Peng Ma96f336c2019-11-19 06:17:40 +0000526 rc = sil_sata_rw_lba28(sata, blknr, blkcnt, buffer, WRITE_CMD);
527 if (sata->wcache && sata->flush)
528 sil_sata_cmd_flush_cache(sata);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000529 }
530
531 return rc;
532}
533
Peng Ma96f336c2019-11-19 06:17:40 +0000534#if !CONFIG_IS_ENABLED(BLK)
535static int sil_init_sata(int dev)
Nikita Kiryanovb9666d62014-11-21 12:47:23 +0200536{
Peng Ma96f336c2019-11-19 06:17:40 +0000537#else
538static int sil_init_sata(struct udevice *uc_dev, int dev)
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000539{
Peng Ma96f336c2019-11-19 06:17:40 +0000540 struct sil_sata_priv *priv = dev_get_platdata(uc_dev);
541#endif
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000542 struct sil_sata *sata;
543 void *port;
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000544 u32 tmp;
Peng Ma96f336c2019-11-19 06:17:40 +0000545 int cnt;
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000546
Peng Ma96f336c2019-11-19 06:17:40 +0000547 printf("SATA#%d:\n", dev);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000548
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000549 port = (void *)sata_info.iobase[1] +
550 PORT_REGS_SIZE * (dev - sata_info.portbase);
551
552 /* Initial PHY setting */
553 writel(0x20c, port + PORT_PHY_CFG);
554
555 /* clear port RST */
556 tmp = readl(port + PORT_CTRL_STAT);
557 if (tmp & PORT_CS_PORT_RST) {
558 writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
559 tmp = ata_wait_register(port + PORT_CTRL_STAT,
560 PORT_CS_PORT_RST, PORT_CS_PORT_RST, 100);
561 if (tmp & PORT_CS_PORT_RST)
562 printf("Err: Failed to clear port RST\n");
563 }
564
565 /* Check if device is present */
566 for (cnt = 0; cnt < 100; cnt++) {
567 tmp = readl(port + PORT_SSTATUS);
568 if ((tmp & 0xF) == 0x3)
569 break;
570 mdelay(1);
571 }
572
573 tmp = readl(port + PORT_SSTATUS);
574 if ((tmp & 0xf) != 0x3) {
575 printf(" (No RDY)\n");
576 return 1;
577 }
578
579 /* Wait for port ready */
580 tmp = ata_wait_register(port + PORT_CTRL_STAT,
581 PORT_CS_RDY, PORT_CS_RDY, 100);
582 if ((tmp & PORT_CS_RDY) != PORT_CS_RDY) {
583 printf("%d port not ready.\n", dev);
584 return 1;
585 }
586
587 /* configure port */
588 sil_config_port(port);
589
590 /* Reset port */
591 writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
592 readl(port + PORT_CTRL_STAT);
593 tmp = ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_DEV_RST,
594 PORT_CS_DEV_RST, 100);
595 if (tmp & PORT_CS_DEV_RST) {
596 printf("%d port reset failed.\n", dev);
597 return 1;
598 }
599
600 sata = (struct sil_sata *)malloc(sizeof(struct sil_sata));
601 if (!sata) {
602 printf("%d no memory.\n", dev);
603 return 1;
604 }
605 memset((void *)sata, 0, sizeof(struct sil_sata));
606
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000607 /* Save the private struct to block device struct */
Peng Ma96f336c2019-11-19 06:17:40 +0000608#if !CONFIG_IS_ENABLED(BLK)
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000609 sata_dev_desc[dev].priv = (void *)sata;
Peng Ma96f336c2019-11-19 06:17:40 +0000610#else
611 priv->sil_sata_desc[dev] = sata;
612 priv->port_num = dev;
613#endif
614 sata->id = dev;
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000615 sata->port = port;
616 sata->devno = sata_info.devno;
617 sprintf(sata->name, "SATA#%d", dev);
Peng Ma96f336c2019-11-19 06:17:40 +0000618 sil_cmd_soft_reset(sata);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000619 tmp = readl(port + PORT_SSTATUS);
620 tmp = (tmp >> 4) & 0xf;
621 printf(" (%s)\n", sata_spd_string(tmp));
622
Peng Ma96f336c2019-11-19 06:17:40 +0000623 return 0;
624}
625
626#if !CONFIG_IS_ENABLED(BLK)
627/*
628 * SATA interface between low level driver and command layer
629 */
630int init_sata(int dev)
631{
632 static int init_done, idx;
633 pci_dev_t devno;
634 u16 word;
635
636 if (init_done == 1 && dev < sata_info.maxport)
637 goto init_start;
638
639 init_done = 1;
640
641 /* Find PCI device(s) */
642 devno = pci_find_devices(supported, idx++);
643 if (devno == -1)
644 return 1;
645
646 pci_read_config_word(devno, PCI_DEVICE_ID, &word);
647
648 /* get the port count */
649 word &= 0xf;
650
651 sata_info.portbase = 0;
652 sata_info.maxport = sata_info.portbase + word;
653 sata_info.devno = devno;
654
655 /* Read out all BARs */
656 sata_info.iobase[0] = (ulong)pci_map_bar(devno,
657 PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
658 sata_info.iobase[1] = (ulong)pci_map_bar(devno,
659 PCI_BASE_ADDRESS_2, PCI_REGION_MEM);
660
661 /* mask out the unused bits */
662 sata_info.iobase[0] &= 0xffffff80;
663 sata_info.iobase[1] &= 0xfffffc00;
664
665 /* Enable Bus Mastering and memory region */
666 pci_write_config_word(devno, PCI_COMMAND,
667 PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
668
669 /* Check if mem accesses and Bus Mastering are enabled. */
670 pci_read_config_word(devno, PCI_COMMAND, &word);
671 if (!(word & PCI_COMMAND_MEMORY) ||
672 (!(word & PCI_COMMAND_MASTER))) {
673 printf("Error: Can not enable MEM access or Bus Mastering.\n");
674 debug("PCI command: %04x\n", word);
675 return 1;
676 }
677
678 /* GPIO off */
679 writel(0, (void *)(sata_info.iobase[0] + HOST_FLASH_CMD));
680 /* clear global reset & mask interrupts during initialization */
681 writel(0, (void *)(sata_info.iobase[0] + HOST_CTRL));
682
683init_start:
684 return sil_init_sata(dev);
685}
686
687int reset_sata(int dev)
688{
689 return 0;
690}
691
692/*
693 * SATA interface between low level driver and command layer
694 */
695int scan_sata(int dev)
696{
697 struct sil_sata *sata = (struct sil_sata *)sata_dev_desc[dev].priv;
698#else
699static int scan_sata(struct udevice *blk_dev, int dev)
700{
701 struct blk_desc *desc = dev_get_uclass_platdata(blk_dev);
702 struct sil_sata_priv *priv = dev_get_platdata(blk_dev);
703 struct sil_sata *sata = priv->sil_sata_desc[dev];
704#endif
705 unsigned char serial[ATA_ID_SERNO_LEN + 1];
706 unsigned char firmware[ATA_ID_FW_REV_LEN + 1];
707 unsigned char product[ATA_ID_PROD_LEN + 1];
708 u16 *id;
709
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000710 id = (u16 *)malloc(ATA_ID_WORDS * 2);
711 if (!id) {
712 printf("Id malloc failed\n");
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000713 return 1;
714 }
Peng Ma96f336c2019-11-19 06:17:40 +0000715 sil_cmd_identify_device(sata, id);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000716
Peng Ma96f336c2019-11-19 06:17:40 +0000717 sil_sata_set_feature_by_id(sata, id);
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000718
719 /* Serial number */
720 ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial));
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000721
722 /* Firmware version */
723 ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware));
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000724
725 /* Product model */
726 ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product));
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000727
Peng Ma96f336c2019-11-19 06:17:40 +0000728#if !CONFIG_IS_ENABLED(BLK)
729 memcpy(sata_dev_desc[dev].product, serial, sizeof(serial));
730 memcpy(sata_dev_desc[dev].revision, firmware, sizeof(firmware));
731 memcpy(sata_dev_desc[dev].vendor, product, sizeof(product));
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000732 /* Totoal sectors */
733 sata_dev_desc[dev].lba = ata_id_n_sectors(id);
Peng Ma96f336c2019-11-19 06:17:40 +0000734#ifdef CONFIG_LBA48
735 sata_dev_desc[dev].lba48 = sata->lba48;
736#endif
737#else
738 memcpy(desc->product, serial, sizeof(serial));
739 memcpy(desc->revision, firmware, sizeof(firmware));
740 memcpy(desc->vendor, product, sizeof(product));
741 desc->lba = ata_id_n_sectors(id);
742#ifdef CONFIG_LBA48
743 desc->lba48 = sata->lba48;
744#endif
745#endif
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000746
747#ifdef DEBUG
Tang Yuantian4511ccc2011-10-07 19:26:58 +0000748 ata_dump_id(id);
749#endif
750 free((void *)id);
751
752 return 0;
753}
Peng Ma96f336c2019-11-19 06:17:40 +0000754
755#if CONFIG_IS_ENABLED(BLK)
756static const struct blk_ops sata_sil_blk_ops = {
757 .read = sata_read,
758 .write = sata_write,
759};
760
761U_BOOT_DRIVER(sata_sil_driver) = {
762 .name = "sata_sil_blk",
763 .id = UCLASS_BLK,
764 .ops = &sata_sil_blk_ops,
765 .platdata_auto_alloc_size = sizeof(struct sil_sata_priv),
766};
767
Peng Ma17dd2612019-12-04 10:36:42 +0000768static int sil_unbind_device(struct udevice *dev)
769{
770 int ret;
771
772 ret = device_remove(dev, DM_REMOVE_NORMAL);
773 if (ret)
774 return ret;
775
776 ret = device_unbind(dev);
777 if (ret)
778 return ret;
779
780 return 0;
781}
782
Peng Ma96f336c2019-11-19 06:17:40 +0000783static int sil_pci_probe(struct udevice *dev)
784{
785 struct udevice *blk;
Peng Ma17dd2612019-12-04 10:36:42 +0000786 int failed_number;
Peng Ma96f336c2019-11-19 06:17:40 +0000787 char sata_name[10];
788 pci_dev_t devno;
789 u16 word;
790 int ret;
791 int i;
792
Peng Ma17dd2612019-12-04 10:36:42 +0000793 failed_number = 0;
794
Peng Ma96f336c2019-11-19 06:17:40 +0000795 /* Get PCI device number */
796 devno = dm_pci_get_bdf(dev);
797 if (devno == -1)
798 return 1;
799
800 dm_pci_read_config16(dev, PCI_DEVICE_ID, &word);
801
802 /* get the port count */
803 word &= 0xf;
804
805 sata_info.portbase = 0;
806 sata_info.maxport = sata_info.portbase + word;
807 sata_info.devno = devno;
808
809 /* Read out all BARs */
810 sata_info.iobase[0] = (ulong)dm_pci_map_bar(dev,
811 PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
812 sata_info.iobase[1] = (ulong)dm_pci_map_bar(dev,
813 PCI_BASE_ADDRESS_2, PCI_REGION_MEM);
814
815 /* mask out the unused bits */
816 sata_info.iobase[0] &= 0xffffff80;
817 sata_info.iobase[1] &= 0xfffffc00;
818
819 /* Enable Bus Mastering and memory region */
820 dm_pci_write_config16(dev, PCI_COMMAND,
821 PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
822
823 /* Check if mem accesses and Bus Mastering are enabled. */
824 dm_pci_read_config16(dev, PCI_COMMAND, &word);
825 if (!(word & PCI_COMMAND_MEMORY) ||
826 (!(word & PCI_COMMAND_MASTER))) {
827 printf("Error: Can not enable MEM access or Bus Mastering.\n");
828 debug("PCI command: %04x\n", word);
829 return 1;
830 }
831
832 /* GPIO off */
833 writel(0, (void *)(sata_info.iobase[0] + HOST_FLASH_CMD));
834 /* clear global reset & mask interrupts during initialization */
835 writel(0, (void *)(sata_info.iobase[0] + HOST_CTRL));
836
837 for (i = sata_info.portbase; i < sata_info.maxport; i++) {
838 snprintf(sata_name, sizeof(sata_name), "sil_sata%d", i);
839 ret = blk_create_devicef(dev, "sata_sil_blk", sata_name,
840 IF_TYPE_SATA, -1, 512, 0, &blk);
841 if (ret) {
842 debug("Can't create device\n");
843 return ret;
844 }
845
846 ret = sil_init_sata(blk, i);
Peng Ma17dd2612019-12-04 10:36:42 +0000847 if (ret) {
848 ret = sil_unbind_device(blk);
849 if (ret)
850 return ret;
851
852 failed_number++;
853 continue;
854 }
Peng Ma96f336c2019-11-19 06:17:40 +0000855
856 ret = scan_sata(blk, i);
Peng Ma17dd2612019-12-04 10:36:42 +0000857 if (ret) {
858 ret = sil_unbind_device(blk);
859 if (ret)
860 return ret;
861
862 failed_number++;
863 continue;
864 }
865 }
866
867 if (failed_number == sata_info.maxport)
868 return -ENODEV;
869 else
870 return 0;
871}
872
873static int sil_pci_remove(struct udevice *dev)
874{
875 int i;
876 struct sil_sata *sata;
877 struct sil_sata_priv *priv;
878
879 priv = dev_get_priv(dev);
880
881 for (i = sata_info.portbase; i < sata_info.maxport; i++) {
882 sata = priv->sil_sata_desc[i];
883 if (sata)
884 free(sata);
Peng Ma96f336c2019-11-19 06:17:40 +0000885 }
886
887 return 0;
888}
889
890static int sata_sil_scan(struct udevice *dev)
891{
892 /* Nothing to do here */
893
894 return 0;
895}
896
897struct sil_ops sata_sil_ops = {
898 .scan = sata_sil_scan,
899};
900
901static const struct udevice_id sil_pci_ids[] = {
902 { .compatible = "sil-pci-sample" },
903 { }
904};
905
906U_BOOT_DRIVER(sil_ahci_pci) = {
907 .name = "sil_ahci_pci",
908 .id = UCLASS_AHCI,
909 .of_match = sil_pci_ids,
910 .ops = &sata_sil_ops,
911 .probe = sil_pci_probe,
Peng Ma17dd2612019-12-04 10:36:42 +0000912 .remove = sil_pci_remove,
Peng Ma96f336c2019-11-19 06:17:40 +0000913 .priv_auto_alloc_size = sizeof(struct sil_sata_priv),
914};
915
916U_BOOT_PCI_DEVICE(sil_ahci_pci, supported);
917#endif