1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2f2105c61SSimon Glass /*
3f2105c61SSimon Glass * Copyright (C) 2011 Freescale Semiconductor, Inc.
4f2105c61SSimon Glass * Author: Tang Yuantian <b29983@freescale.com>
5f2105c61SSimon Glass */
6f2105c61SSimon Glass
7f2105c61SSimon Glass #include <common.h>
8f2105c61SSimon Glass #include <pci.h>
9f2105c61SSimon Glass #include <command.h>
10f2105c61SSimon Glass #include <asm/byteorder.h>
11f2105c61SSimon Glass #include <malloc.h>
12f2105c61SSimon Glass #include <asm/io.h>
13f2105c61SSimon Glass #include <fis.h>
14f2105c61SSimon Glass #include <sata.h>
15f2105c61SSimon Glass #include <libata.h>
16f2105c61SSimon Glass #include <sata.h>
17f2105c61SSimon Glass #include "sata_sil.h"
18f2105c61SSimon Glass
19f2105c61SSimon Glass /* Convert sectorsize to wordsize */
20f2105c61SSimon Glass #define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2)
21f2105c61SSimon Glass #define virt_to_bus(devno, v) pci_virt_to_mem(devno, (void *) (v))
22f2105c61SSimon Glass
23f2105c61SSimon Glass static struct sata_info sata_info;
24f2105c61SSimon Glass
25f2105c61SSimon Glass static struct pci_device_id supported[] = {
26f2105c61SSimon Glass {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3131},
27f2105c61SSimon Glass {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3132},
28f2105c61SSimon Glass {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3124},
29f2105c61SSimon Glass {}
30f2105c61SSimon Glass };
31f2105c61SSimon Glass
sil_sata_dump_fis(struct sata_fis_d2h * s)32f2105c61SSimon Glass static void sil_sata_dump_fis(struct sata_fis_d2h *s)
33f2105c61SSimon Glass {
34f2105c61SSimon Glass printf("Status FIS dump:\n");
35f2105c61SSimon Glass printf("fis_type: %02x\n", s->fis_type);
36f2105c61SSimon Glass printf("pm_port_i: %02x\n", s->pm_port_i);
37f2105c61SSimon Glass printf("status: %02x\n", s->status);
38f2105c61SSimon Glass printf("error: %02x\n", s->error);
39f2105c61SSimon Glass printf("lba_low: %02x\n", s->lba_low);
40f2105c61SSimon Glass printf("lba_mid: %02x\n", s->lba_mid);
41f2105c61SSimon Glass printf("lba_high: %02x\n", s->lba_high);
42f2105c61SSimon Glass printf("device: %02x\n", s->device);
43f2105c61SSimon Glass printf("lba_low_exp: %02x\n", s->lba_low_exp);
44f2105c61SSimon Glass printf("lba_mid_exp: %02x\n", s->lba_mid_exp);
45f2105c61SSimon Glass printf("lba_high_exp: %02x\n", s->lba_high_exp);
46f2105c61SSimon Glass printf("res1: %02x\n", s->res1);
47f2105c61SSimon Glass printf("sector_count: %02x\n", s->sector_count);
48f2105c61SSimon Glass printf("sector_count_exp: %02x\n", s->sector_count_exp);
49f2105c61SSimon Glass }
50f2105c61SSimon Glass
sata_spd_string(unsigned int speed)51f2105c61SSimon Glass static const char *sata_spd_string(unsigned int speed)
52f2105c61SSimon Glass {
53f2105c61SSimon Glass static const char * const spd_str[] = {
54f2105c61SSimon Glass "1.5 Gbps",
55f2105c61SSimon Glass "3.0 Gbps",
56f2105c61SSimon Glass "6.0 Gbps",
57f2105c61SSimon Glass };
58f2105c61SSimon Glass
59f2105c61SSimon Glass if ((speed - 1) > 2)
60f2105c61SSimon Glass return "<unknown>";
61f2105c61SSimon Glass
62f2105c61SSimon Glass return spd_str[speed - 1];
63f2105c61SSimon Glass }
64f2105c61SSimon Glass
ata_wait_register(void * reg,u32 mask,u32 val,int timeout_msec)65f2105c61SSimon Glass static u32 ata_wait_register(void *reg, u32 mask,
66f2105c61SSimon Glass u32 val, int timeout_msec)
67f2105c61SSimon Glass {
68f2105c61SSimon Glass u32 tmp;
69f2105c61SSimon Glass
70f2105c61SSimon Glass tmp = readl(reg);
71f2105c61SSimon Glass while ((tmp & mask) == val && timeout_msec > 0) {
72f2105c61SSimon Glass mdelay(1);
73f2105c61SSimon Glass timeout_msec--;
74f2105c61SSimon Glass tmp = readl(reg);
75f2105c61SSimon Glass }
76f2105c61SSimon Glass
77f2105c61SSimon Glass return tmp;
78f2105c61SSimon Glass }
79f2105c61SSimon Glass
sil_config_port(void * port)80f2105c61SSimon Glass static void sil_config_port(void *port)
81f2105c61SSimon Glass {
82f2105c61SSimon Glass /* configure IRQ WoC */
83f2105c61SSimon Glass writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
84f2105c61SSimon Glass
85f2105c61SSimon Glass /* zero error counters. */
86f2105c61SSimon Glass writew(0x8000, port + PORT_DECODE_ERR_THRESH);
87f2105c61SSimon Glass writew(0x8000, port + PORT_CRC_ERR_THRESH);
88f2105c61SSimon Glass writew(0x8000, port + PORT_HSHK_ERR_THRESH);
89f2105c61SSimon Glass writew(0x0000, port + PORT_DECODE_ERR_CNT);
90f2105c61SSimon Glass writew(0x0000, port + PORT_CRC_ERR_CNT);
91f2105c61SSimon Glass writew(0x0000, port + PORT_HSHK_ERR_CNT);
92f2105c61SSimon Glass
93f2105c61SSimon Glass /* always use 64bit activation */
94f2105c61SSimon Glass writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
95f2105c61SSimon Glass
96f2105c61SSimon Glass /* clear port multiplier enable and resume bits */
97f2105c61SSimon Glass writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR);
98f2105c61SSimon Glass }
99f2105c61SSimon Glass
sil_init_port(void * port)100f2105c61SSimon Glass static int sil_init_port(void *port)
101f2105c61SSimon Glass {
102f2105c61SSimon Glass u32 tmp;
103f2105c61SSimon Glass
104f2105c61SSimon Glass writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
105f2105c61SSimon Glass ata_wait_register(port + PORT_CTRL_STAT,
106f2105c61SSimon Glass PORT_CS_INIT, PORT_CS_INIT, 100);
107f2105c61SSimon Glass tmp = ata_wait_register(port + PORT_CTRL_STAT,
108f2105c61SSimon Glass PORT_CS_RDY, 0, 100);
109f2105c61SSimon Glass
110f2105c61SSimon Glass if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY)
111f2105c61SSimon Glass return 1;
112f2105c61SSimon Glass
113f2105c61SSimon Glass return 0;
114f2105c61SSimon Glass }
115f2105c61SSimon Glass
sil_read_fis(int dev,int tag,struct sata_fis_d2h * fis)116f2105c61SSimon Glass static void sil_read_fis(int dev, int tag, struct sata_fis_d2h *fis)
117f2105c61SSimon Glass {
118f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv;
119f2105c61SSimon Glass void *port = sata->port;
120f2105c61SSimon Glass struct sil_prb *prb;
121f2105c61SSimon Glass int i;
122f2105c61SSimon Glass u32 *src, *dst;
123f2105c61SSimon Glass
124f2105c61SSimon Glass prb = port + PORT_LRAM + tag * PORT_LRAM_SLOT_SZ;
125f2105c61SSimon Glass src = (u32 *)&prb->fis;
126f2105c61SSimon Glass dst = (u32 *)fis;
127f2105c61SSimon Glass for (i = 0; i < sizeof(struct sata_fis_h2d); i += 4)
128f2105c61SSimon Glass *dst++ = readl(src++);
129f2105c61SSimon Glass }
130f2105c61SSimon Glass
sil_exec_cmd(int dev,struct sil_cmd_block * pcmd,int tag)131f2105c61SSimon Glass static int sil_exec_cmd(int dev, struct sil_cmd_block *pcmd, int tag)
132f2105c61SSimon Glass {
133f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv;
134f2105c61SSimon Glass void *port = sata->port;
135f2105c61SSimon Glass u64 paddr = virt_to_bus(sata->devno, pcmd);
136f2105c61SSimon Glass u32 irq_mask, irq_stat;
137f2105c61SSimon Glass int rc;
138f2105c61SSimon Glass
139f2105c61SSimon Glass writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR);
140f2105c61SSimon Glass
141f2105c61SSimon Glass /* better to add momery barrior here */
142f2105c61SSimon Glass writel((u32)paddr, port + PORT_CMD_ACTIVATE + tag * 8);
143f2105c61SSimon Glass writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + tag * 8 + 4);
144f2105c61SSimon Glass
145f2105c61SSimon Glass irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
146f2105c61SSimon Glass irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask,
147f2105c61SSimon Glass 0, 10000);
148f2105c61SSimon Glass
149f2105c61SSimon Glass /* clear IRQs */
150f2105c61SSimon Glass writel(irq_mask, port + PORT_IRQ_STAT);
151f2105c61SSimon Glass irq_stat >>= PORT_IRQ_RAW_SHIFT;
152f2105c61SSimon Glass
153f2105c61SSimon Glass if (irq_stat & PORT_IRQ_COMPLETE)
154f2105c61SSimon Glass rc = 0;
155f2105c61SSimon Glass else {
156f2105c61SSimon Glass /* force port into known state */
157f2105c61SSimon Glass sil_init_port(port);
158f2105c61SSimon Glass if (irq_stat & PORT_IRQ_ERROR)
159f2105c61SSimon Glass rc = 1; /* error */
160f2105c61SSimon Glass else
161f2105c61SSimon Glass rc = 2; /* busy */
162f2105c61SSimon Glass }
163f2105c61SSimon Glass
164f2105c61SSimon Glass return rc;
165f2105c61SSimon Glass }
166f2105c61SSimon Glass
sil_cmd_set_feature(int dev)167f2105c61SSimon Glass static int sil_cmd_set_feature(int dev)
168f2105c61SSimon Glass {
169f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv;
170f2105c61SSimon Glass struct sil_cmd_block cmdb, *pcmd = &cmdb;
171f2105c61SSimon Glass struct sata_fis_d2h fis;
172f2105c61SSimon Glass u8 udma_cap;
173f2105c61SSimon Glass int ret;
174f2105c61SSimon Glass
175f2105c61SSimon Glass memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block));
176f2105c61SSimon Glass pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
177f2105c61SSimon Glass pcmd->prb.fis.pm_port_c = (1 << 7);
178f2105c61SSimon Glass pcmd->prb.fis.command = ATA_CMD_SET_FEATURES;
179f2105c61SSimon Glass pcmd->prb.fis.features = SETFEATURES_XFER;
180f2105c61SSimon Glass
181f2105c61SSimon Glass /* First check the device capablity */
182f2105c61SSimon Glass udma_cap = (u8)(sata->udma & 0xff);
183f2105c61SSimon Glass debug("udma_cap %02x\n", udma_cap);
184f2105c61SSimon Glass
185f2105c61SSimon Glass if (udma_cap == ATA_UDMA6)
186f2105c61SSimon Glass pcmd->prb.fis.sector_count = XFER_UDMA_6;
187f2105c61SSimon Glass if (udma_cap == ATA_UDMA5)
188f2105c61SSimon Glass pcmd->prb.fis.sector_count = XFER_UDMA_5;
189f2105c61SSimon Glass if (udma_cap == ATA_UDMA4)
190f2105c61SSimon Glass pcmd->prb.fis.sector_count = XFER_UDMA_4;
191f2105c61SSimon Glass if (udma_cap == ATA_UDMA3)
192f2105c61SSimon Glass pcmd->prb.fis.sector_count = XFER_UDMA_3;
193f2105c61SSimon Glass
194f2105c61SSimon Glass ret = sil_exec_cmd(dev, pcmd, 0);
195f2105c61SSimon Glass if (ret) {
196f2105c61SSimon Glass sil_read_fis(dev, 0, &fis);
197f2105c61SSimon Glass printf("Err: exe cmd(0x%x).\n",
198f2105c61SSimon Glass readl(sata->port + PORT_SERROR));
199f2105c61SSimon Glass sil_sata_dump_fis(&fis);
200f2105c61SSimon Glass return 1;
201f2105c61SSimon Glass }
202f2105c61SSimon Glass
203f2105c61SSimon Glass return 0;
204f2105c61SSimon Glass }
205f2105c61SSimon Glass
sil_cmd_identify_device(int dev,u16 * id)206f2105c61SSimon Glass static int sil_cmd_identify_device(int dev, u16 *id)
207f2105c61SSimon Glass {
208f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv;
209f2105c61SSimon Glass struct sil_cmd_block cmdb, *pcmd = &cmdb;
210f2105c61SSimon Glass struct sata_fis_d2h fis;
211f2105c61SSimon Glass int ret;
212f2105c61SSimon Glass
213f2105c61SSimon Glass memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block));
214f2105c61SSimon Glass pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL);
215f2105c61SSimon Glass pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ);
216f2105c61SSimon Glass pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
217f2105c61SSimon Glass pcmd->prb.fis.pm_port_c = (1 << 7);
218f2105c61SSimon Glass pcmd->prb.fis.command = ATA_CMD_ID_ATA;
219f2105c61SSimon Glass pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, id));
220f2105c61SSimon Glass pcmd->sge.cnt = cpu_to_le32(sizeof(id[0]) * ATA_ID_WORDS);
221f2105c61SSimon Glass pcmd->sge.flags = cpu_to_le32(SGE_TRM);
222f2105c61SSimon Glass
223f2105c61SSimon Glass ret = sil_exec_cmd(dev, pcmd, 0);
224f2105c61SSimon Glass if (ret) {
225f2105c61SSimon Glass sil_read_fis(dev, 0, &fis);
226f2105c61SSimon Glass printf("Err: id cmd(0x%x).\n", readl(sata->port + PORT_SERROR));
227f2105c61SSimon Glass sil_sata_dump_fis(&fis);
228f2105c61SSimon Glass return 1;
229f2105c61SSimon Glass }
230f2105c61SSimon Glass ata_swap_buf_le16(id, ATA_ID_WORDS);
231f2105c61SSimon Glass
232f2105c61SSimon Glass return 0;
233f2105c61SSimon Glass }
234f2105c61SSimon Glass
sil_cmd_soft_reset(int dev)235f2105c61SSimon Glass static int sil_cmd_soft_reset(int dev)
236f2105c61SSimon Glass {
237f2105c61SSimon Glass struct sil_cmd_block cmdb, *pcmd = &cmdb;
238f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv;
239f2105c61SSimon Glass struct sata_fis_d2h fis;
240f2105c61SSimon Glass void *port = sata->port;
241f2105c61SSimon Glass int ret;
242f2105c61SSimon Glass
243f2105c61SSimon Glass /* put the port into known state */
244f2105c61SSimon Glass if (sil_init_port(port)) {
245f2105c61SSimon Glass printf("SRST: port %d not ready\n", dev);
246f2105c61SSimon Glass return 1;
247f2105c61SSimon Glass }
248f2105c61SSimon Glass
249f2105c61SSimon Glass memset((void *)&cmdb, 0, sizeof(struct sil_cmd_block));
250f2105c61SSimon Glass
251f2105c61SSimon Glass pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_SRST);
252f2105c61SSimon Glass pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
253f2105c61SSimon Glass pcmd->prb.fis.pm_port_c = 0xf;
254f2105c61SSimon Glass
255f2105c61SSimon Glass ret = sil_exec_cmd(dev, &cmdb, 0);
256f2105c61SSimon Glass if (ret) {
257f2105c61SSimon Glass sil_read_fis(dev, 0, &fis);
258f2105c61SSimon Glass printf("SRST cmd error.\n");
259f2105c61SSimon Glass sil_sata_dump_fis(&fis);
260f2105c61SSimon Glass return 1;
261f2105c61SSimon Glass }
262f2105c61SSimon Glass
263f2105c61SSimon Glass return 0;
264f2105c61SSimon Glass }
265f2105c61SSimon Glass
sil_sata_rw_cmd(int dev,ulong start,ulong blkcnt,u8 * buffer,int is_write)266f2105c61SSimon Glass static ulong sil_sata_rw_cmd(int dev, ulong start, ulong blkcnt,
267f2105c61SSimon Glass u8 *buffer, int is_write)
268f2105c61SSimon Glass {
269f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv;
270f2105c61SSimon Glass struct sil_cmd_block cmdb, *pcmd = &cmdb;
271f2105c61SSimon Glass struct sata_fis_d2h fis;
272f2105c61SSimon Glass u64 block;
273f2105c61SSimon Glass int ret;
274f2105c61SSimon Glass
275f2105c61SSimon Glass block = (u64)start;
276f2105c61SSimon Glass memset(pcmd, 0, sizeof(struct sil_cmd_block));
277f2105c61SSimon Glass pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL);
278f2105c61SSimon Glass pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
279f2105c61SSimon Glass pcmd->prb.fis.pm_port_c = (1 << 7);
280f2105c61SSimon Glass if (is_write) {
281f2105c61SSimon Glass pcmd->prb.fis.command = ATA_CMD_WRITE;
282f2105c61SSimon Glass pcmd->prb.prot = cpu_to_le16(PRB_PROT_WRITE);
283f2105c61SSimon Glass } else {
284f2105c61SSimon Glass pcmd->prb.fis.command = ATA_CMD_READ;
285f2105c61SSimon Glass pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ);
286f2105c61SSimon Glass }
287f2105c61SSimon Glass
288f2105c61SSimon Glass pcmd->prb.fis.device = ATA_LBA;
289f2105c61SSimon Glass pcmd->prb.fis.device |= (block >> 24) & 0xf;
290f2105c61SSimon Glass pcmd->prb.fis.lba_high = (block >> 16) & 0xff;
291f2105c61SSimon Glass pcmd->prb.fis.lba_mid = (block >> 8) & 0xff;
292f2105c61SSimon Glass pcmd->prb.fis.lba_low = block & 0xff;
293f2105c61SSimon Glass pcmd->prb.fis.sector_count = (u8)blkcnt & 0xff;
294f2105c61SSimon Glass
295f2105c61SSimon Glass pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, buffer));
296f2105c61SSimon Glass pcmd->sge.cnt = cpu_to_le32(blkcnt * ATA_SECT_SIZE);
297f2105c61SSimon Glass pcmd->sge.flags = cpu_to_le32(SGE_TRM);
298f2105c61SSimon Glass
299f2105c61SSimon Glass ret = sil_exec_cmd(dev, pcmd, 0);
300f2105c61SSimon Glass if (ret) {
301f2105c61SSimon Glass sil_read_fis(dev, 0, &fis);
302f2105c61SSimon Glass printf("Err: rw cmd(0x%08x).\n",
303f2105c61SSimon Glass readl(sata->port + PORT_SERROR));
304f2105c61SSimon Glass sil_sata_dump_fis(&fis);
305f2105c61SSimon Glass return 1;
306f2105c61SSimon Glass }
307f2105c61SSimon Glass
308f2105c61SSimon Glass return blkcnt;
309f2105c61SSimon Glass }
310f2105c61SSimon Glass
sil_sata_rw_cmd_ext(int dev,ulong start,ulong blkcnt,u8 * buffer,int is_write)311f2105c61SSimon Glass static ulong sil_sata_rw_cmd_ext(int dev, ulong start, ulong blkcnt,
312f2105c61SSimon Glass u8 *buffer, int is_write)
313f2105c61SSimon Glass {
314f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv;
315f2105c61SSimon Glass struct sil_cmd_block cmdb, *pcmd = &cmdb;
316f2105c61SSimon Glass struct sata_fis_d2h fis;
317f2105c61SSimon Glass u64 block;
318f2105c61SSimon Glass int ret;
319f2105c61SSimon Glass
320f2105c61SSimon Glass block = (u64)start;
321f2105c61SSimon Glass memset(pcmd, 0, sizeof(struct sil_cmd_block));
322f2105c61SSimon Glass pcmd->prb.ctrl = cpu_to_le16(PRB_CTRL_PROTOCOL);
323f2105c61SSimon Glass pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
324f2105c61SSimon Glass pcmd->prb.fis.pm_port_c = (1 << 7);
325f2105c61SSimon Glass if (is_write) {
326f2105c61SSimon Glass pcmd->prb.fis.command = ATA_CMD_WRITE_EXT;
327f2105c61SSimon Glass pcmd->prb.prot = cpu_to_le16(PRB_PROT_WRITE);
328f2105c61SSimon Glass } else {
329f2105c61SSimon Glass pcmd->prb.fis.command = ATA_CMD_READ_EXT;
330f2105c61SSimon Glass pcmd->prb.prot = cpu_to_le16(PRB_PROT_READ);
331f2105c61SSimon Glass }
332f2105c61SSimon Glass
333f2105c61SSimon Glass pcmd->prb.fis.lba_high_exp = (block >> 40) & 0xff;
334f2105c61SSimon Glass pcmd->prb.fis.lba_mid_exp = (block >> 32) & 0xff;
335f2105c61SSimon Glass pcmd->prb.fis.lba_low_exp = (block >> 24) & 0xff;
336f2105c61SSimon Glass pcmd->prb.fis.lba_high = (block >> 16) & 0xff;
337f2105c61SSimon Glass pcmd->prb.fis.lba_mid = (block >> 8) & 0xff;
338f2105c61SSimon Glass pcmd->prb.fis.lba_low = block & 0xff;
339f2105c61SSimon Glass pcmd->prb.fis.device = ATA_LBA;
340f2105c61SSimon Glass pcmd->prb.fis.sector_count_exp = (blkcnt >> 8) & 0xff;
341f2105c61SSimon Glass pcmd->prb.fis.sector_count = blkcnt & 0xff;
342f2105c61SSimon Glass
343f2105c61SSimon Glass pcmd->sge.addr = cpu_to_le64(virt_to_bus(sata->devno, buffer));
344f2105c61SSimon Glass pcmd->sge.cnt = cpu_to_le32(blkcnt * ATA_SECT_SIZE);
345f2105c61SSimon Glass pcmd->sge.flags = cpu_to_le32(SGE_TRM);
346f2105c61SSimon Glass
347f2105c61SSimon Glass ret = sil_exec_cmd(dev, pcmd, 0);
348f2105c61SSimon Glass if (ret) {
349f2105c61SSimon Glass sil_read_fis(dev, 0, &fis);
350f2105c61SSimon Glass printf("Err: rw ext cmd(0x%08x).\n",
351f2105c61SSimon Glass readl(sata->port + PORT_SERROR));
352f2105c61SSimon Glass sil_sata_dump_fis(&fis);
353f2105c61SSimon Glass return 1;
354f2105c61SSimon Glass }
355f2105c61SSimon Glass
356f2105c61SSimon Glass return blkcnt;
357f2105c61SSimon Glass }
358f2105c61SSimon Glass
sil_sata_rw_lba28(int dev,ulong blknr,lbaint_t blkcnt,const void * buffer,int is_write)359f2105c61SSimon Glass static ulong sil_sata_rw_lba28(int dev, ulong blknr, lbaint_t blkcnt,
360f2105c61SSimon Glass const void *buffer, int is_write)
361f2105c61SSimon Glass {
362f2105c61SSimon Glass ulong start, blks, max_blks;
363f2105c61SSimon Glass u8 *addr;
364f2105c61SSimon Glass
365f2105c61SSimon Glass start = blknr;
366f2105c61SSimon Glass blks = blkcnt;
367f2105c61SSimon Glass addr = (u8 *)buffer;
368f2105c61SSimon Glass
369f2105c61SSimon Glass max_blks = ATA_MAX_SECTORS;
370f2105c61SSimon Glass do {
371f2105c61SSimon Glass if (blks > max_blks) {
372f2105c61SSimon Glass sil_sata_rw_cmd(dev, start, max_blks, addr, is_write);
373f2105c61SSimon Glass start += max_blks;
374f2105c61SSimon Glass blks -= max_blks;
375f2105c61SSimon Glass addr += ATA_SECT_SIZE * max_blks;
376f2105c61SSimon Glass } else {
377f2105c61SSimon Glass sil_sata_rw_cmd(dev, start, blks, addr, is_write);
378f2105c61SSimon Glass start += blks;
379f2105c61SSimon Glass blks = 0;
380f2105c61SSimon Glass addr += ATA_SECT_SIZE * blks;
381f2105c61SSimon Glass }
382f2105c61SSimon Glass } while (blks != 0);
383f2105c61SSimon Glass
384f2105c61SSimon Glass return blkcnt;
385f2105c61SSimon Glass }
386f2105c61SSimon Glass
sil_sata_rw_lba48(int dev,ulong blknr,lbaint_t blkcnt,const void * buffer,int is_write)387f2105c61SSimon Glass static ulong sil_sata_rw_lba48(int dev, ulong blknr, lbaint_t blkcnt,
388f2105c61SSimon Glass const void *buffer, int is_write)
389f2105c61SSimon Glass {
390f2105c61SSimon Glass ulong start, blks, max_blks;
391f2105c61SSimon Glass u8 *addr;
392f2105c61SSimon Glass
393f2105c61SSimon Glass start = blknr;
394f2105c61SSimon Glass blks = blkcnt;
395f2105c61SSimon Glass addr = (u8 *)buffer;
396f2105c61SSimon Glass
397f2105c61SSimon Glass max_blks = ATA_MAX_SECTORS_LBA48;
398f2105c61SSimon Glass do {
399f2105c61SSimon Glass if (blks > max_blks) {
400f2105c61SSimon Glass sil_sata_rw_cmd_ext(dev, start, max_blks,
401f2105c61SSimon Glass addr, is_write);
402f2105c61SSimon Glass start += max_blks;
403f2105c61SSimon Glass blks -= max_blks;
404f2105c61SSimon Glass addr += ATA_SECT_SIZE * max_blks;
405f2105c61SSimon Glass } else {
406f2105c61SSimon Glass sil_sata_rw_cmd_ext(dev, start, blks,
407f2105c61SSimon Glass addr, is_write);
408f2105c61SSimon Glass start += blks;
409f2105c61SSimon Glass blks = 0;
410f2105c61SSimon Glass addr += ATA_SECT_SIZE * blks;
411f2105c61SSimon Glass }
412f2105c61SSimon Glass } while (blks != 0);
413f2105c61SSimon Glass
414f2105c61SSimon Glass return blkcnt;
415f2105c61SSimon Glass }
416f2105c61SSimon Glass
sil_sata_cmd_flush_cache(int dev)417f2105c61SSimon Glass static void sil_sata_cmd_flush_cache(int dev)
418f2105c61SSimon Glass {
419f2105c61SSimon Glass struct sil_cmd_block cmdb, *pcmd = &cmdb;
420f2105c61SSimon Glass
421f2105c61SSimon Glass memset((void *)pcmd, 0, sizeof(struct sil_cmd_block));
422f2105c61SSimon Glass pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
423f2105c61SSimon Glass pcmd->prb.fis.pm_port_c = (1 << 7);
424f2105c61SSimon Glass pcmd->prb.fis.command = ATA_CMD_FLUSH;
425f2105c61SSimon Glass
426f2105c61SSimon Glass sil_exec_cmd(dev, pcmd, 0);
427f2105c61SSimon Glass }
428f2105c61SSimon Glass
sil_sata_cmd_flush_cache_ext(int dev)429f2105c61SSimon Glass static void sil_sata_cmd_flush_cache_ext(int dev)
430f2105c61SSimon Glass {
431f2105c61SSimon Glass struct sil_cmd_block cmdb, *pcmd = &cmdb;
432f2105c61SSimon Glass
433f2105c61SSimon Glass memset((void *)pcmd, 0, sizeof(struct sil_cmd_block));
434f2105c61SSimon Glass pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
435f2105c61SSimon Glass pcmd->prb.fis.pm_port_c = (1 << 7);
436f2105c61SSimon Glass pcmd->prb.fis.command = ATA_CMD_FLUSH_EXT;
437f2105c61SSimon Glass
438f2105c61SSimon Glass sil_exec_cmd(dev, pcmd, 0);
439f2105c61SSimon Glass }
440f2105c61SSimon Glass
sil_sata_init_wcache(int dev,u16 * id)441f2105c61SSimon Glass static void sil_sata_init_wcache(int dev, u16 *id)
442f2105c61SSimon Glass {
443f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv;
444f2105c61SSimon Glass
445f2105c61SSimon Glass if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id))
446f2105c61SSimon Glass sata->wcache = 1;
447f2105c61SSimon Glass if (ata_id_has_flush(id))
448f2105c61SSimon Glass sata->flush = 1;
449f2105c61SSimon Glass if (ata_id_has_flush_ext(id))
450f2105c61SSimon Glass sata->flush_ext = 1;
451f2105c61SSimon Glass }
452f2105c61SSimon Glass
sil_sata_get_wcache(int dev)453f2105c61SSimon Glass static int sil_sata_get_wcache(int dev)
454f2105c61SSimon Glass {
455f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv;
456f2105c61SSimon Glass
457f2105c61SSimon Glass return sata->wcache;
458f2105c61SSimon Glass }
459f2105c61SSimon Glass
sil_sata_get_flush(int dev)460f2105c61SSimon Glass static int sil_sata_get_flush(int dev)
461f2105c61SSimon Glass {
462f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv;
463f2105c61SSimon Glass
464f2105c61SSimon Glass return sata->flush;
465f2105c61SSimon Glass }
466f2105c61SSimon Glass
sil_sata_get_flush_ext(int dev)467f2105c61SSimon Glass static int sil_sata_get_flush_ext(int dev)
468f2105c61SSimon Glass {
469f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv;
470f2105c61SSimon Glass
471f2105c61SSimon Glass return sata->flush_ext;
472f2105c61SSimon Glass }
473f2105c61SSimon Glass
474f2105c61SSimon Glass /*
475f2105c61SSimon Glass * SATA interface between low level driver and command layer
476f2105c61SSimon Glass */
sata_read(int dev,ulong blknr,lbaint_t blkcnt,void * buffer)477f2105c61SSimon Glass ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer)
478f2105c61SSimon Glass {
479f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv;
480f2105c61SSimon Glass ulong rc;
481f2105c61SSimon Glass
482f2105c61SSimon Glass if (sata->lba48)
483f2105c61SSimon Glass rc = sil_sata_rw_lba48(dev, blknr, blkcnt, buffer, READ_CMD);
484f2105c61SSimon Glass else
485f2105c61SSimon Glass rc = sil_sata_rw_lba28(dev, blknr, blkcnt, buffer, READ_CMD);
486f2105c61SSimon Glass
487f2105c61SSimon Glass return rc;
488f2105c61SSimon Glass }
489f2105c61SSimon Glass
490f2105c61SSimon Glass /*
491f2105c61SSimon Glass * SATA interface between low level driver and command layer
492f2105c61SSimon Glass */
sata_write(int dev,ulong blknr,lbaint_t blkcnt,const void * buffer)493f2105c61SSimon Glass ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer)
494f2105c61SSimon Glass {
495f2105c61SSimon Glass struct sil_sata *sata = sata_dev_desc[dev].priv;
496f2105c61SSimon Glass ulong rc;
497f2105c61SSimon Glass
498f2105c61SSimon Glass if (sata->lba48) {
499f2105c61SSimon Glass rc = sil_sata_rw_lba48(dev, blknr, blkcnt, buffer, WRITE_CMD);
500f2105c61SSimon Glass if (sil_sata_get_wcache(dev) && sil_sata_get_flush_ext(dev))
501f2105c61SSimon Glass sil_sata_cmd_flush_cache_ext(dev);
502f2105c61SSimon Glass } else {
503f2105c61SSimon Glass rc = sil_sata_rw_lba28(dev, blknr, blkcnt, buffer, WRITE_CMD);
504f2105c61SSimon Glass if (sil_sata_get_wcache(dev) && sil_sata_get_flush(dev))
505f2105c61SSimon Glass sil_sata_cmd_flush_cache(dev);
506f2105c61SSimon Glass }
507f2105c61SSimon Glass
508f2105c61SSimon Glass return rc;
509f2105c61SSimon Glass }
510f2105c61SSimon Glass
511f2105c61SSimon Glass /*
512f2105c61SSimon Glass * SATA interface between low level driver and command layer
513f2105c61SSimon Glass */
init_sata(int dev)514f2105c61SSimon Glass int init_sata(int dev)
515f2105c61SSimon Glass {
516f2105c61SSimon Glass static int init_done, idx;
517f2105c61SSimon Glass pci_dev_t devno;
518f2105c61SSimon Glass u16 word;
519f2105c61SSimon Glass
520f2105c61SSimon Glass if (init_done == 1 && dev < sata_info.maxport)
521f2105c61SSimon Glass return 0;
522f2105c61SSimon Glass
523f2105c61SSimon Glass init_done = 1;
524f2105c61SSimon Glass
525f2105c61SSimon Glass /* Find PCI device(s) */
526f2105c61SSimon Glass devno = pci_find_devices(supported, idx++);
527f2105c61SSimon Glass if (devno == -1)
528f2105c61SSimon Glass return 1;
529f2105c61SSimon Glass
530f2105c61SSimon Glass pci_read_config_word(devno, PCI_DEVICE_ID, &word);
531f2105c61SSimon Glass
532f2105c61SSimon Glass /* get the port count */
533f2105c61SSimon Glass word &= 0xf;
534f2105c61SSimon Glass
535f2105c61SSimon Glass sata_info.portbase = sata_info.maxport;
536f2105c61SSimon Glass sata_info.maxport = sata_info.portbase + word;
537f2105c61SSimon Glass sata_info.devno = devno;
538f2105c61SSimon Glass
539f2105c61SSimon Glass /* Read out all BARs */
540f2105c61SSimon Glass sata_info.iobase[0] = (ulong)pci_map_bar(devno,
541f2105c61SSimon Glass PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
542f2105c61SSimon Glass sata_info.iobase[1] = (ulong)pci_map_bar(devno,
543f2105c61SSimon Glass PCI_BASE_ADDRESS_2, PCI_REGION_MEM);
544f2105c61SSimon Glass sata_info.iobase[2] = (ulong)pci_map_bar(devno,
545f2105c61SSimon Glass PCI_BASE_ADDRESS_4, PCI_REGION_MEM);
546f2105c61SSimon Glass
547f2105c61SSimon Glass /* mask out the unused bits */
548f2105c61SSimon Glass sata_info.iobase[0] &= 0xffffff80;
549f2105c61SSimon Glass sata_info.iobase[1] &= 0xfffffc00;
550f2105c61SSimon Glass sata_info.iobase[2] &= 0xffffff80;
551f2105c61SSimon Glass
552f2105c61SSimon Glass /* Enable Bus Mastering and memory region */
553f2105c61SSimon Glass pci_write_config_word(devno, PCI_COMMAND,
554f2105c61SSimon Glass PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
555f2105c61SSimon Glass
556f2105c61SSimon Glass /* Check if mem accesses and Bus Mastering are enabled. */
557f2105c61SSimon Glass pci_read_config_word(devno, PCI_COMMAND, &word);
558f2105c61SSimon Glass if (!(word & PCI_COMMAND_MEMORY) ||
559f2105c61SSimon Glass (!(word & PCI_COMMAND_MASTER))) {
560f2105c61SSimon Glass printf("Error: Can not enable MEM access or Bus Mastering.\n");
561f2105c61SSimon Glass debug("PCI command: %04x\n", word);
562f2105c61SSimon Glass return 1;
563f2105c61SSimon Glass }
564f2105c61SSimon Glass
565f2105c61SSimon Glass /* GPIO off */
566f2105c61SSimon Glass writel(0, (void *)(sata_info.iobase[0] + HOST_FLASH_CMD));
567f2105c61SSimon Glass /* clear global reset & mask interrupts during initialization */
568f2105c61SSimon Glass writel(0, (void *)(sata_info.iobase[0] + HOST_CTRL));
569f2105c61SSimon Glass
570f2105c61SSimon Glass return 0;
571f2105c61SSimon Glass }
572f2105c61SSimon Glass
reset_sata(int dev)573f2105c61SSimon Glass int reset_sata(int dev)
574f2105c61SSimon Glass {
575f2105c61SSimon Glass return 0;
576f2105c61SSimon Glass }
577f2105c61SSimon Glass
578f2105c61SSimon Glass /*
579f2105c61SSimon Glass * SATA interface between low level driver and command layer
580f2105c61SSimon Glass */
scan_sata(int dev)581f2105c61SSimon Glass int scan_sata(int dev)
582f2105c61SSimon Glass {
583f2105c61SSimon Glass unsigned char serial[ATA_ID_SERNO_LEN + 1];
584f2105c61SSimon Glass unsigned char firmware[ATA_ID_FW_REV_LEN + 1];
585f2105c61SSimon Glass unsigned char product[ATA_ID_PROD_LEN + 1];
586f2105c61SSimon Glass struct sil_sata *sata;
587f2105c61SSimon Glass void *port;
588f2105c61SSimon Glass int cnt;
589f2105c61SSimon Glass u16 *id;
590f2105c61SSimon Glass u32 tmp;
591f2105c61SSimon Glass
592f2105c61SSimon Glass if (dev >= sata_info.maxport) {
593f2105c61SSimon Glass printf("SATA#%d is not present\n", dev);
594f2105c61SSimon Glass return 1;
595f2105c61SSimon Glass }
596f2105c61SSimon Glass
597f2105c61SSimon Glass printf("SATA#%d\n", dev);
598f2105c61SSimon Glass port = (void *)sata_info.iobase[1] +
599f2105c61SSimon Glass PORT_REGS_SIZE * (dev - sata_info.portbase);
600f2105c61SSimon Glass
601f2105c61SSimon Glass /* Initial PHY setting */
602f2105c61SSimon Glass writel(0x20c, port + PORT_PHY_CFG);
603f2105c61SSimon Glass
604f2105c61SSimon Glass /* clear port RST */
605f2105c61SSimon Glass tmp = readl(port + PORT_CTRL_STAT);
606f2105c61SSimon Glass if (tmp & PORT_CS_PORT_RST) {
607f2105c61SSimon Glass writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
608f2105c61SSimon Glass tmp = ata_wait_register(port + PORT_CTRL_STAT,
609f2105c61SSimon Glass PORT_CS_PORT_RST, PORT_CS_PORT_RST, 100);
610f2105c61SSimon Glass if (tmp & PORT_CS_PORT_RST)
611f2105c61SSimon Glass printf("Err: Failed to clear port RST\n");
612f2105c61SSimon Glass }
613f2105c61SSimon Glass
614f2105c61SSimon Glass /* Check if device is present */
615f2105c61SSimon Glass for (cnt = 0; cnt < 100; cnt++) {
616f2105c61SSimon Glass tmp = readl(port + PORT_SSTATUS);
617f2105c61SSimon Glass if ((tmp & 0xF) == 0x3)
618f2105c61SSimon Glass break;
619f2105c61SSimon Glass mdelay(1);
620f2105c61SSimon Glass }
621f2105c61SSimon Glass
622f2105c61SSimon Glass tmp = readl(port + PORT_SSTATUS);
623f2105c61SSimon Glass if ((tmp & 0xf) != 0x3) {
624f2105c61SSimon Glass printf(" (No RDY)\n");
625f2105c61SSimon Glass return 1;
626f2105c61SSimon Glass }
627f2105c61SSimon Glass
628f2105c61SSimon Glass /* Wait for port ready */
629f2105c61SSimon Glass tmp = ata_wait_register(port + PORT_CTRL_STAT,
630f2105c61SSimon Glass PORT_CS_RDY, PORT_CS_RDY, 100);
631f2105c61SSimon Glass if ((tmp & PORT_CS_RDY) != PORT_CS_RDY) {
632f2105c61SSimon Glass printf("%d port not ready.\n", dev);
633f2105c61SSimon Glass return 1;
634f2105c61SSimon Glass }
635f2105c61SSimon Glass
636f2105c61SSimon Glass /* configure port */
637f2105c61SSimon Glass sil_config_port(port);
638f2105c61SSimon Glass
639f2105c61SSimon Glass /* Reset port */
640f2105c61SSimon Glass writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
641f2105c61SSimon Glass readl(port + PORT_CTRL_STAT);
642f2105c61SSimon Glass tmp = ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_DEV_RST,
643f2105c61SSimon Glass PORT_CS_DEV_RST, 100);
644f2105c61SSimon Glass if (tmp & PORT_CS_DEV_RST) {
645f2105c61SSimon Glass printf("%d port reset failed.\n", dev);
646f2105c61SSimon Glass return 1;
647f2105c61SSimon Glass }
648f2105c61SSimon Glass
649f2105c61SSimon Glass sata = (struct sil_sata *)malloc(sizeof(struct sil_sata));
650f2105c61SSimon Glass if (!sata) {
651f2105c61SSimon Glass printf("%d no memory.\n", dev);
652f2105c61SSimon Glass return 1;
653f2105c61SSimon Glass }
654f2105c61SSimon Glass memset((void *)sata, 0, sizeof(struct sil_sata));
655f2105c61SSimon Glass
656f2105c61SSimon Glass /* turn on port interrupt */
657f2105c61SSimon Glass tmp = readl((void *)(sata_info.iobase[0] + HOST_CTRL));
658f2105c61SSimon Glass tmp |= (1 << (dev - sata_info.portbase));
659f2105c61SSimon Glass writel(tmp, (void *)(sata_info.iobase[0] + HOST_CTRL));
660f2105c61SSimon Glass
661f2105c61SSimon Glass /* Save the private struct to block device struct */
662f2105c61SSimon Glass sata_dev_desc[dev].priv = (void *)sata;
663f2105c61SSimon Glass sata->port = port;
664f2105c61SSimon Glass sata->devno = sata_info.devno;
665f2105c61SSimon Glass sprintf(sata->name, "SATA#%d", dev);
666f2105c61SSimon Glass sil_cmd_soft_reset(dev);
667f2105c61SSimon Glass tmp = readl(port + PORT_SSTATUS);
668f2105c61SSimon Glass tmp = (tmp >> 4) & 0xf;
669f2105c61SSimon Glass printf(" (%s)\n", sata_spd_string(tmp));
670f2105c61SSimon Glass
671f2105c61SSimon Glass id = (u16 *)malloc(ATA_ID_WORDS * 2);
672f2105c61SSimon Glass if (!id) {
673f2105c61SSimon Glass printf("Id malloc failed\n");
674f2105c61SSimon Glass free((void *)sata);
675f2105c61SSimon Glass return 1;
676f2105c61SSimon Glass }
677f2105c61SSimon Glass sil_cmd_identify_device(dev, id);
678f2105c61SSimon Glass
679f2105c61SSimon Glass #ifdef CONFIG_LBA48
680f2105c61SSimon Glass /* Check if support LBA48 */
681f2105c61SSimon Glass if (ata_id_has_lba48(id)) {
682f2105c61SSimon Glass sata_dev_desc[dev].lba48 = 1;
683f2105c61SSimon Glass sata->lba48 = 1;
684f2105c61SSimon Glass debug("Device supports LBA48\n");
685f2105c61SSimon Glass } else
686f2105c61SSimon Glass debug("Device supports LBA28\n");
687f2105c61SSimon Glass #endif
688f2105c61SSimon Glass
689f2105c61SSimon Glass /* Serial number */
690f2105c61SSimon Glass ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial));
691f2105c61SSimon Glass memcpy(sata_dev_desc[dev].product, serial, sizeof(serial));
692f2105c61SSimon Glass
693f2105c61SSimon Glass /* Firmware version */
694f2105c61SSimon Glass ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware));
695f2105c61SSimon Glass memcpy(sata_dev_desc[dev].revision, firmware, sizeof(firmware));
696f2105c61SSimon Glass
697f2105c61SSimon Glass /* Product model */
698f2105c61SSimon Glass ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product));
699f2105c61SSimon Glass memcpy(sata_dev_desc[dev].vendor, product, sizeof(product));
700f2105c61SSimon Glass
701f2105c61SSimon Glass /* Totoal sectors */
702f2105c61SSimon Glass sata_dev_desc[dev].lba = ata_id_n_sectors(id);
703f2105c61SSimon Glass
704f2105c61SSimon Glass sil_sata_init_wcache(dev, id);
705f2105c61SSimon Glass sil_cmd_set_feature(dev);
706f2105c61SSimon Glass
707f2105c61SSimon Glass #ifdef DEBUG
708f2105c61SSimon Glass sil_cmd_identify_device(dev, id);
709f2105c61SSimon Glass ata_dump_id(id);
710f2105c61SSimon Glass #endif
711f2105c61SSimon Glass free((void *)id);
712f2105c61SSimon Glass
713f2105c61SSimon Glass return 0;
714f2105c61SSimon Glass }
715