xref: /openbmc/u-boot/drivers/ata/fsl_sata.c (revision e8f80a5a)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2f2105c61SSimon Glass /*
3f2105c61SSimon Glass  * Copyright (C) 2008,2010 Freescale Semiconductor, Inc.
4f2105c61SSimon Glass  *		Dave Liu <daveliu@freescale.com>
5f2105c61SSimon Glass  */
6f2105c61SSimon Glass 
7f2105c61SSimon Glass #include <common.h>
8f2105c61SSimon Glass #include <command.h>
9f2105c61SSimon Glass #include <console.h>
10f2105c61SSimon Glass #include <asm/io.h>
11f2105c61SSimon Glass #include <asm/processor.h>
12f2105c61SSimon Glass #include <asm/fsl_serdes.h>
13f2105c61SSimon Glass #include <malloc.h>
14f2105c61SSimon Glass #include <libata.h>
15f2105c61SSimon Glass #include <fis.h>
16f2105c61SSimon Glass #include <sata.h>
17f2105c61SSimon Glass #include "fsl_sata.h"
18f2105c61SSimon Glass 
19f2105c61SSimon Glass #ifndef CONFIG_SYS_SATA1_FLAGS
20f2105c61SSimon Glass 	#define CONFIG_SYS_SATA1_FLAGS	FLAGS_DMA
21f2105c61SSimon Glass #endif
22f2105c61SSimon Glass #ifndef CONFIG_SYS_SATA2_FLAGS
23f2105c61SSimon Glass 	#define CONFIG_SYS_SATA2_FLAGS	FLAGS_DMA
24f2105c61SSimon Glass #endif
25f2105c61SSimon Glass 
26f2105c61SSimon Glass static struct fsl_sata_info fsl_sata_info[] = {
27f2105c61SSimon Glass #ifdef CONFIG_SATA1
28f2105c61SSimon Glass 	{CONFIG_SYS_SATA1, CONFIG_SYS_SATA1_FLAGS},
29f2105c61SSimon Glass #else
30f2105c61SSimon Glass 	{0, 0},
31f2105c61SSimon Glass #endif
32f2105c61SSimon Glass #ifdef CONFIG_SATA2
33f2105c61SSimon Glass 	{CONFIG_SYS_SATA2, CONFIG_SYS_SATA2_FLAGS},
34f2105c61SSimon Glass #else
35f2105c61SSimon Glass 	{0, 0},
36f2105c61SSimon Glass #endif
37f2105c61SSimon Glass };
38f2105c61SSimon Glass 
sdelay(unsigned long sec)39f2105c61SSimon Glass static inline void sdelay(unsigned long sec)
40f2105c61SSimon Glass {
41f2105c61SSimon Glass 	unsigned long i;
42f2105c61SSimon Glass 	for (i = 0; i < sec; i++)
43f2105c61SSimon Glass 		mdelay(1000);
44f2105c61SSimon Glass }
45f2105c61SSimon Glass 
fsl_sata_dump_sfis(struct sata_fis_d2h * s)46f2105c61SSimon Glass static void fsl_sata_dump_sfis(struct sata_fis_d2h *s)
47f2105c61SSimon Glass {
48f2105c61SSimon Glass 	printf("Status FIS dump:\n\r");
49f2105c61SSimon Glass 	printf("fis_type:		%02x\n\r", s->fis_type);
50f2105c61SSimon Glass 	printf("pm_port_i:		%02x\n\r", s->pm_port_i);
51f2105c61SSimon Glass 	printf("status:			%02x\n\r", s->status);
52f2105c61SSimon Glass 	printf("error:			%02x\n\r", s->error);
53f2105c61SSimon Glass 	printf("lba_low:		%02x\n\r", s->lba_low);
54f2105c61SSimon Glass 	printf("lba_mid:		%02x\n\r", s->lba_mid);
55f2105c61SSimon Glass 	printf("lba_high:		%02x\n\r", s->lba_high);
56f2105c61SSimon Glass 	printf("device:			%02x\n\r", s->device);
57f2105c61SSimon Glass 	printf("lba_low_exp:		%02x\n\r", s->lba_low_exp);
58f2105c61SSimon Glass 	printf("lba_mid_exp:		%02x\n\r", s->lba_mid_exp);
59f2105c61SSimon Glass 	printf("lba_high_exp:		%02x\n\r", s->lba_high_exp);
60f2105c61SSimon Glass 	printf("res1:			%02x\n\r", s->res1);
61f2105c61SSimon Glass 	printf("sector_count:		%02x\n\r", s->sector_count);
62f2105c61SSimon Glass 	printf("sector_count_exp:	%02x\n\r", s->sector_count_exp);
63f2105c61SSimon Glass }
64f2105c61SSimon Glass 
ata_wait_register(unsigned __iomem * addr,u32 mask,u32 val,u32 timeout_msec)65f2105c61SSimon Glass static int ata_wait_register(unsigned __iomem *addr, u32 mask,
66f2105c61SSimon Glass 			 u32 val, u32 timeout_msec)
67f2105c61SSimon Glass {
68f2105c61SSimon Glass 	int i;
69f2105c61SSimon Glass 	u32 temp;
70f2105c61SSimon Glass 
71f2105c61SSimon Glass 	for (i = 0; (((temp = in_le32(addr)) & mask) != val)
72f2105c61SSimon Glass 			 && i < timeout_msec; i++)
73f2105c61SSimon Glass 		mdelay(1);
74f2105c61SSimon Glass 	return (i < timeout_msec) ? 0 : -1;
75f2105c61SSimon Glass }
76f2105c61SSimon Glass 
init_sata(int dev)77f2105c61SSimon Glass int init_sata(int dev)
78f2105c61SSimon Glass {
79f2105c61SSimon Glass 	u32 length, align;
80f2105c61SSimon Glass 	cmd_hdr_tbl_t *cmd_hdr;
81f2105c61SSimon Glass 	u32 cda;
82f2105c61SSimon Glass 	u32 val32;
83f2105c61SSimon Glass 	fsl_sata_reg_t __iomem *reg;
84f2105c61SSimon Glass 	u32 sig;
85f2105c61SSimon Glass 	int i;
86f2105c61SSimon Glass 	fsl_sata_t *sata;
87f2105c61SSimon Glass 
88f2105c61SSimon Glass 	if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) {
89f2105c61SSimon Glass 		printf("the sata index %d is out of ranges\n\r", dev);
90f2105c61SSimon Glass 		return -1;
91f2105c61SSimon Glass 	}
92f2105c61SSimon Glass 
93f2105c61SSimon Glass #ifdef CONFIG_MPC85xx
94f2105c61SSimon Glass 	if ((dev == 0) && (!is_serdes_configured(SATA1))) {
95f2105c61SSimon Glass 		printf("SATA%d [dev = %d] is not enabled\n", dev+1, dev);
96f2105c61SSimon Glass 		return -1;
97f2105c61SSimon Glass 	}
98f2105c61SSimon Glass 	if ((dev == 1) && (!is_serdes_configured(SATA2))) {
99f2105c61SSimon Glass 		printf("SATA%d [dev = %d] is not enabled\n", dev+1, dev);
100f2105c61SSimon Glass 		return -1;
101f2105c61SSimon Glass 	}
102f2105c61SSimon Glass #endif
103f2105c61SSimon Glass 
104f2105c61SSimon Glass 	/* Allocate SATA device driver struct */
105f2105c61SSimon Glass 	sata = (fsl_sata_t *)malloc(sizeof(fsl_sata_t));
106f2105c61SSimon Glass 	if (!sata) {
107f2105c61SSimon Glass 		printf("alloc the sata device struct failed\n\r");
108f2105c61SSimon Glass 		return -1;
109f2105c61SSimon Glass 	}
110f2105c61SSimon Glass 	/* Zero all of the device driver struct */
111f2105c61SSimon Glass 	memset((void *)sata, 0, sizeof(fsl_sata_t));
112f2105c61SSimon Glass 
113f2105c61SSimon Glass 	/* Save the private struct to block device struct */
114f2105c61SSimon Glass 	sata_dev_desc[dev].priv = (void *)sata;
115f2105c61SSimon Glass 
116f2105c61SSimon Glass 	snprintf(sata->name, 12, "SATA%d", dev);
117f2105c61SSimon Glass 
118f2105c61SSimon Glass 	/* Set the controller register base address to device struct */
119f2105c61SSimon Glass 	reg = (fsl_sata_reg_t *)(fsl_sata_info[dev].sata_reg_base);
120f2105c61SSimon Glass 	sata->reg_base = reg;
121f2105c61SSimon Glass 
122f2105c61SSimon Glass 	/* Allocate the command header table, 4 bytes aligned */
123f2105c61SSimon Glass 	length = sizeof(struct cmd_hdr_tbl);
124f2105c61SSimon Glass 	align = SATA_HC_CMD_HDR_TBL_ALIGN;
125f2105c61SSimon Glass 	sata->cmd_hdr_tbl_offset = (void *)malloc(length + align);
126f2105c61SSimon Glass 	if (!sata->cmd_hdr_tbl_offset) {
127f2105c61SSimon Glass 		printf("alloc the command header failed\n\r");
128f2105c61SSimon Glass 		return -1;
129f2105c61SSimon Glass 	}
130f2105c61SSimon Glass 
131f2105c61SSimon Glass 	cmd_hdr = (cmd_hdr_tbl_t *)(((u32)sata->cmd_hdr_tbl_offset + align)
132f2105c61SSimon Glass 						& ~(align - 1));
133f2105c61SSimon Glass 	sata->cmd_hdr = cmd_hdr;
134f2105c61SSimon Glass 
135f2105c61SSimon Glass 	/* Zero all of the command header table */
136f2105c61SSimon Glass 	memset((void *)sata->cmd_hdr_tbl_offset, 0, length + align);
137f2105c61SSimon Glass 
138f2105c61SSimon Glass 	/* Allocate command descriptor for all command */
139f2105c61SSimon Glass 	length = sizeof(struct cmd_desc) * SATA_HC_MAX_CMD;
140f2105c61SSimon Glass 	align = SATA_HC_CMD_DESC_ALIGN;
141f2105c61SSimon Glass 	sata->cmd_desc_offset = (void *)malloc(length + align);
142f2105c61SSimon Glass 	if (!sata->cmd_desc_offset) {
143f2105c61SSimon Glass 		printf("alloc the command descriptor failed\n\r");
144f2105c61SSimon Glass 		return -1;
145f2105c61SSimon Glass 	}
146f2105c61SSimon Glass 	sata->cmd_desc = (cmd_desc_t *)(((u32)sata->cmd_desc_offset + align)
147f2105c61SSimon Glass 						& ~(align - 1));
148f2105c61SSimon Glass 	/* Zero all of command descriptor */
149f2105c61SSimon Glass 	memset((void *)sata->cmd_desc_offset, 0, length + align);
150f2105c61SSimon Glass 
151f2105c61SSimon Glass 	/* Link the command descriptor to command header */
152f2105c61SSimon Glass 	for (i = 0; i < SATA_HC_MAX_CMD; i++) {
153f2105c61SSimon Glass 		cda = ((u32)sata->cmd_desc + SATA_HC_CMD_DESC_SIZE * i)
154f2105c61SSimon Glass 					 & ~(CMD_HDR_CDA_ALIGN - 1);
155f2105c61SSimon Glass 		cmd_hdr->cmd_slot[i].cda = cpu_to_le32(cda);
156f2105c61SSimon Glass 	}
157f2105c61SSimon Glass 
158f2105c61SSimon Glass 	/* To have safe state, force the controller offline */
159f2105c61SSimon Glass 	val32 = in_le32(&reg->hcontrol);
160f2105c61SSimon Glass 	val32 &= ~HCONTROL_ONOFF;
161f2105c61SSimon Glass 	val32 |= HCONTROL_FORCE_OFFLINE;
162f2105c61SSimon Glass 	out_le32(&reg->hcontrol, val32);
163f2105c61SSimon Glass 
164f2105c61SSimon Glass 	/* Wait the controller offline */
165f2105c61SSimon Glass 	ata_wait_register(&reg->hstatus, HSTATUS_ONOFF, 0, 1000);
166f2105c61SSimon Glass 
167f2105c61SSimon Glass 	/* Set the command header base address to CHBA register to tell DMA */
168f2105c61SSimon Glass 	out_le32(&reg->chba, (u32)cmd_hdr & ~0x3);
169f2105c61SSimon Glass 
170f2105c61SSimon Glass 	/* Snoop for the command header */
171f2105c61SSimon Glass 	val32 = in_le32(&reg->hcontrol);
172f2105c61SSimon Glass 	val32 |= HCONTROL_HDR_SNOOP;
173f2105c61SSimon Glass 	out_le32(&reg->hcontrol, val32);
174f2105c61SSimon Glass 
175f2105c61SSimon Glass 	/* Disable all of interrupts */
176f2105c61SSimon Glass 	val32 = in_le32(&reg->hcontrol);
177f2105c61SSimon Glass 	val32 &= ~HCONTROL_INT_EN_ALL;
178f2105c61SSimon Glass 	out_le32(&reg->hcontrol, val32);
179f2105c61SSimon Glass 
180f2105c61SSimon Glass 	/* Clear all of interrupts */
181f2105c61SSimon Glass 	val32 = in_le32(&reg->hstatus);
182f2105c61SSimon Glass 	out_le32(&reg->hstatus, val32);
183f2105c61SSimon Glass 
184f2105c61SSimon Glass 	/* Set the ICC, no interrupt coalescing */
185f2105c61SSimon Glass 	out_le32(&reg->icc, 0x01000000);
186f2105c61SSimon Glass 
187f2105c61SSimon Glass 	/* No PM attatched, the SATA device direct connect */
188f2105c61SSimon Glass 	out_le32(&reg->cqpmp, 0);
189f2105c61SSimon Glass 
190f2105c61SSimon Glass 	/* Clear SError register */
191f2105c61SSimon Glass 	val32 = in_le32(&reg->serror);
192f2105c61SSimon Glass 	out_le32(&reg->serror, val32);
193f2105c61SSimon Glass 
194f2105c61SSimon Glass 	/* Clear CER register */
195f2105c61SSimon Glass 	val32 = in_le32(&reg->cer);
196f2105c61SSimon Glass 	out_le32(&reg->cer, val32);
197f2105c61SSimon Glass 
198f2105c61SSimon Glass 	/* Clear DER register */
199f2105c61SSimon Glass 	val32 = in_le32(&reg->der);
200f2105c61SSimon Glass 	out_le32(&reg->der, val32);
201f2105c61SSimon Glass 
202f2105c61SSimon Glass 	/* No device detection or initialization action requested */
203f2105c61SSimon Glass 	out_le32(&reg->scontrol, 0x00000300);
204f2105c61SSimon Glass 
205f2105c61SSimon Glass 	/* Configure the transport layer, default value */
206f2105c61SSimon Glass 	out_le32(&reg->transcfg, 0x08000016);
207f2105c61SSimon Glass 
208f2105c61SSimon Glass 	/* Configure the link layer, default value */
209f2105c61SSimon Glass 	out_le32(&reg->linkcfg, 0x0000ff34);
210f2105c61SSimon Glass 
211f2105c61SSimon Glass 	/* Bring the controller online */
212f2105c61SSimon Glass 	val32 = in_le32(&reg->hcontrol);
213f2105c61SSimon Glass 	val32 |= HCONTROL_ONOFF;
214f2105c61SSimon Glass 	out_le32(&reg->hcontrol, val32);
215f2105c61SSimon Glass 
216f2105c61SSimon Glass 	mdelay(100);
217f2105c61SSimon Glass 
218f2105c61SSimon Glass 	/* print sata device name */
219f2105c61SSimon Glass 	if (!dev)
220f2105c61SSimon Glass 		printf("%s ", sata->name);
221f2105c61SSimon Glass 	else
222f2105c61SSimon Glass 		printf("       %s ", sata->name);
223f2105c61SSimon Glass 
224f2105c61SSimon Glass 	/* Wait PHY RDY signal changed for 500ms */
225f2105c61SSimon Glass 	ata_wait_register(&reg->hstatus, HSTATUS_PHY_RDY,
226f2105c61SSimon Glass 			  HSTATUS_PHY_RDY, 500);
227f2105c61SSimon Glass 
228f2105c61SSimon Glass 	/* Check PHYRDY */
229f2105c61SSimon Glass 	val32 = in_le32(&reg->hstatus);
230f2105c61SSimon Glass 	if (val32 & HSTATUS_PHY_RDY) {
231f2105c61SSimon Glass 		sata->link = 1;
232f2105c61SSimon Glass 	} else {
233f2105c61SSimon Glass 		sata->link = 0;
234f2105c61SSimon Glass 		printf("(No RDY)\n\r");
235f2105c61SSimon Glass 		return -1;
236f2105c61SSimon Glass 	}
237f2105c61SSimon Glass 
238f2105c61SSimon Glass 	/* Wait for signature updated, which is 1st D2H */
239f2105c61SSimon Glass 	ata_wait_register(&reg->hstatus, HSTATUS_SIGNATURE,
240f2105c61SSimon Glass 			  HSTATUS_SIGNATURE, 10000);
241f2105c61SSimon Glass 
242f2105c61SSimon Glass 	if (val32 & HSTATUS_SIGNATURE) {
243f2105c61SSimon Glass 		sig = in_le32(&reg->sig);
244f2105c61SSimon Glass 		debug("Signature updated, the sig =%08x\n\r", sig);
245f2105c61SSimon Glass 		sata->ata_device_type = ata_dev_classify(sig);
246f2105c61SSimon Glass 	}
247f2105c61SSimon Glass 
248f2105c61SSimon Glass 	/* Check the speed */
249f2105c61SSimon Glass 	val32 = in_le32(&reg->sstatus);
250f2105c61SSimon Glass 	if ((val32 & SSTATUS_SPD_MASK) == SSTATUS_SPD_GEN1)
251f2105c61SSimon Glass 		printf("(1.5 Gbps)\n\r");
252f2105c61SSimon Glass 	else if ((val32 & SSTATUS_SPD_MASK) == SSTATUS_SPD_GEN2)
253f2105c61SSimon Glass 		printf("(3 Gbps)\n\r");
254f2105c61SSimon Glass 
255f2105c61SSimon Glass 	return 0;
256f2105c61SSimon Glass }
257f2105c61SSimon Glass 
reset_sata(int dev)258f2105c61SSimon Glass int reset_sata(int dev)
259f2105c61SSimon Glass {
260f2105c61SSimon Glass 	return 0;
261f2105c61SSimon Glass }
262f2105c61SSimon Glass 
fsl_sata_dump_regs(fsl_sata_reg_t __iomem * reg)263f2105c61SSimon Glass static void fsl_sata_dump_regs(fsl_sata_reg_t __iomem *reg)
264f2105c61SSimon Glass {
265f2105c61SSimon Glass 	printf("\n\rSATA:           %08x\n\r", (u32)reg);
266f2105c61SSimon Glass 	printf("CQR:            %08x\n\r", in_le32(&reg->cqr));
267f2105c61SSimon Glass 	printf("CAR:            %08x\n\r", in_le32(&reg->car));
268f2105c61SSimon Glass 	printf("CCR:            %08x\n\r", in_le32(&reg->ccr));
269f2105c61SSimon Glass 	printf("CER:            %08x\n\r", in_le32(&reg->cer));
270f2105c61SSimon Glass 	printf("CQR:            %08x\n\r", in_le32(&reg->cqr));
271f2105c61SSimon Glass 	printf("DER:            %08x\n\r", in_le32(&reg->der));
272f2105c61SSimon Glass 	printf("CHBA:           %08x\n\r", in_le32(&reg->chba));
273f2105c61SSimon Glass 	printf("HStatus:        %08x\n\r", in_le32(&reg->hstatus));
274f2105c61SSimon Glass 	printf("HControl:       %08x\n\r", in_le32(&reg->hcontrol));
275f2105c61SSimon Glass 	printf("CQPMP:          %08x\n\r", in_le32(&reg->cqpmp));
276f2105c61SSimon Glass 	printf("SIG:            %08x\n\r", in_le32(&reg->sig));
277f2105c61SSimon Glass 	printf("ICC:            %08x\n\r", in_le32(&reg->icc));
278f2105c61SSimon Glass 	printf("SStatus:        %08x\n\r", in_le32(&reg->sstatus));
279f2105c61SSimon Glass 	printf("SError:         %08x\n\r", in_le32(&reg->serror));
280f2105c61SSimon Glass 	printf("SControl:       %08x\n\r", in_le32(&reg->scontrol));
281f2105c61SSimon Glass 	printf("SNotification:  %08x\n\r", in_le32(&reg->snotification));
282f2105c61SSimon Glass 	printf("TransCfg:       %08x\n\r", in_le32(&reg->transcfg));
283f2105c61SSimon Glass 	printf("TransStatus:    %08x\n\r", in_le32(&reg->transstatus));
284f2105c61SSimon Glass 	printf("LinkCfg:        %08x\n\r", in_le32(&reg->linkcfg));
285f2105c61SSimon Glass 	printf("LinkCfg1:       %08x\n\r", in_le32(&reg->linkcfg1));
286f2105c61SSimon Glass 	printf("LinkCfg2:       %08x\n\r", in_le32(&reg->linkcfg2));
287f2105c61SSimon Glass 	printf("LinkStatus:     %08x\n\r", in_le32(&reg->linkstatus));
288f2105c61SSimon Glass 	printf("LinkStatus1:    %08x\n\r", in_le32(&reg->linkstatus1));
289f2105c61SSimon Glass 	printf("PhyCtrlCfg:     %08x\n\r", in_le32(&reg->phyctrlcfg));
290f2105c61SSimon Glass 	printf("SYSPR:          %08x\n\r", in_be32(&reg->syspr));
291f2105c61SSimon Glass }
292f2105c61SSimon Glass 
fsl_ata_exec_ata_cmd(struct fsl_sata * sata,struct sata_fis_h2d * cfis,int is_ncq,int tag,u8 * buffer,u32 len)293f2105c61SSimon Glass static int fsl_ata_exec_ata_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis,
294f2105c61SSimon Glass 				int is_ncq, int tag, u8 *buffer, u32 len)
295f2105c61SSimon Glass {
296f2105c61SSimon Glass 	cmd_hdr_entry_t *cmd_hdr;
297f2105c61SSimon Glass 	cmd_desc_t *cmd_desc;
298f2105c61SSimon Glass 	sata_fis_h2d_t *h2d;
299f2105c61SSimon Glass 	prd_entry_t *prde;
300f2105c61SSimon Glass 	u32 ext_c_ddc;
301f2105c61SSimon Glass 	u32 prde_count;
302f2105c61SSimon Glass 	u32 val32;
303f2105c61SSimon Glass 	u32 ttl;
304f2105c61SSimon Glass 	fsl_sata_reg_t __iomem *reg = sata->reg_base;
305f2105c61SSimon Glass 	int i;
306f2105c61SSimon Glass 
307f2105c61SSimon Glass 	/* Check xfer length */
308f2105c61SSimon Glass 	if (len > SATA_HC_MAX_XFER_LEN) {
309f2105c61SSimon Glass 		printf("max transfer length is 64MB\n\r");
310f2105c61SSimon Glass 		return 0;
311f2105c61SSimon Glass 	}
312f2105c61SSimon Glass 
313f2105c61SSimon Glass 	/* Setup the command descriptor */
314f2105c61SSimon Glass 	cmd_desc = sata->cmd_desc + tag;
315f2105c61SSimon Glass 
316f2105c61SSimon Glass 	/* Get the pointer cfis of command descriptor */
317f2105c61SSimon Glass 	h2d = (sata_fis_h2d_t *)cmd_desc->cfis;
318f2105c61SSimon Glass 
319f2105c61SSimon Glass 	/* Zero the cfis of command descriptor */
320f2105c61SSimon Glass 	memset((void *)h2d, 0, SATA_HC_CMD_DESC_CFIS_SIZE);
321f2105c61SSimon Glass 
322f2105c61SSimon Glass 	/* Copy the cfis from user to command descriptor */
323f2105c61SSimon Glass 	h2d->fis_type = cfis->fis_type;
324f2105c61SSimon Glass 	h2d->pm_port_c = cfis->pm_port_c;
325f2105c61SSimon Glass 	h2d->command = cfis->command;
326f2105c61SSimon Glass 
327f2105c61SSimon Glass 	h2d->features = cfis->features;
328f2105c61SSimon Glass 	h2d->features_exp = cfis->features_exp;
329f2105c61SSimon Glass 
330f2105c61SSimon Glass 	h2d->lba_low = cfis->lba_low;
331f2105c61SSimon Glass 	h2d->lba_mid = cfis->lba_mid;
332f2105c61SSimon Glass 	h2d->lba_high = cfis->lba_high;
333f2105c61SSimon Glass 	h2d->lba_low_exp = cfis->lba_low_exp;
334f2105c61SSimon Glass 	h2d->lba_mid_exp = cfis->lba_mid_exp;
335f2105c61SSimon Glass 	h2d->lba_high_exp = cfis->lba_high_exp;
336f2105c61SSimon Glass 
337f2105c61SSimon Glass 	if (!is_ncq) {
338f2105c61SSimon Glass 		h2d->sector_count = cfis->sector_count;
339f2105c61SSimon Glass 		h2d->sector_count_exp = cfis->sector_count_exp;
340f2105c61SSimon Glass 	} else { /* NCQ */
341f2105c61SSimon Glass 		h2d->sector_count = (u8)(tag << 3);
342f2105c61SSimon Glass 	}
343f2105c61SSimon Glass 
344f2105c61SSimon Glass 	h2d->device = cfis->device;
345f2105c61SSimon Glass 	h2d->control = cfis->control;
346f2105c61SSimon Glass 
347f2105c61SSimon Glass 	/* Setup the PRD table */
348f2105c61SSimon Glass 	prde = (prd_entry_t *)cmd_desc->prdt;
349f2105c61SSimon Glass 	memset((void *)prde, 0, sizeof(struct prdt));
350f2105c61SSimon Glass 
351f2105c61SSimon Glass 	prde_count = 0;
352f2105c61SSimon Glass 	ttl = len;
353f2105c61SSimon Glass 	for (i = 0; i < SATA_HC_MAX_PRD_DIRECT; i++) {
354f2105c61SSimon Glass 		if (!len)
355f2105c61SSimon Glass 			break;
356f2105c61SSimon Glass 		prde->dba = cpu_to_le32((u32)buffer & ~0x3);
357f2105c61SSimon Glass 		debug("dba = %08x\n\r", (u32)buffer);
358f2105c61SSimon Glass 
359f2105c61SSimon Glass 		if (len < PRD_ENTRY_MAX_XFER_SZ) {
360f2105c61SSimon Glass 			ext_c_ddc = PRD_ENTRY_DATA_SNOOP | len;
361f2105c61SSimon Glass 			debug("ext_c_ddc1 = %08x, len = %08x\n\r", ext_c_ddc, len);
362f2105c61SSimon Glass 			prde->ext_c_ddc = cpu_to_le32(ext_c_ddc);
363f2105c61SSimon Glass 			prde_count++;
364f2105c61SSimon Glass 			prde++;
365f2105c61SSimon Glass 			break;
366f2105c61SSimon Glass 		} else {
367f2105c61SSimon Glass 			ext_c_ddc = PRD_ENTRY_DATA_SNOOP; /* 4M bytes */
368f2105c61SSimon Glass 			debug("ext_c_ddc2 = %08x, len = %08x\n\r", ext_c_ddc, len);
369f2105c61SSimon Glass 			prde->ext_c_ddc = cpu_to_le32(ext_c_ddc);
370f2105c61SSimon Glass 			buffer += PRD_ENTRY_MAX_XFER_SZ;
371f2105c61SSimon Glass 			len -= PRD_ENTRY_MAX_XFER_SZ;
372f2105c61SSimon Glass 			prde_count++;
373f2105c61SSimon Glass 			prde++;
374f2105c61SSimon Glass 		}
375f2105c61SSimon Glass 	}
376f2105c61SSimon Glass 
377f2105c61SSimon Glass 	/* Setup the command slot of cmd hdr */
378f2105c61SSimon Glass 	cmd_hdr = (cmd_hdr_entry_t *)&sata->cmd_hdr->cmd_slot[tag];
379f2105c61SSimon Glass 
380f2105c61SSimon Glass 	cmd_hdr->cda = cpu_to_le32((u32)cmd_desc & ~0x3);
381f2105c61SSimon Glass 
382f2105c61SSimon Glass 	val32 = prde_count << CMD_HDR_PRD_ENTRY_SHIFT;
383f2105c61SSimon Glass 	val32 |= sizeof(sata_fis_h2d_t);
384f2105c61SSimon Glass 	cmd_hdr->prde_fis_len = cpu_to_le32(val32);
385f2105c61SSimon Glass 
386f2105c61SSimon Glass 	cmd_hdr->ttl = cpu_to_le32(ttl);
387f2105c61SSimon Glass 
388f2105c61SSimon Glass 	if (!is_ncq) {
389f2105c61SSimon Glass 		val32 = CMD_HDR_ATTR_RES | CMD_HDR_ATTR_SNOOP;
390f2105c61SSimon Glass 	} else {
391f2105c61SSimon Glass 		val32 = CMD_HDR_ATTR_RES | CMD_HDR_ATTR_SNOOP | CMD_HDR_ATTR_FPDMA;
392f2105c61SSimon Glass 	}
393f2105c61SSimon Glass 
394f2105c61SSimon Glass 	tag &= CMD_HDR_ATTR_TAG;
395f2105c61SSimon Glass 	val32 |= tag;
396f2105c61SSimon Glass 
397f2105c61SSimon Glass 	debug("attribute = %08x\n\r", val32);
398f2105c61SSimon Glass 	cmd_hdr->attribute = cpu_to_le32(val32);
399f2105c61SSimon Glass 
400f2105c61SSimon Glass 	/* Make sure cmd desc and cmd slot valid before command issue */
401f2105c61SSimon Glass 	sync();
402f2105c61SSimon Glass 
403f2105c61SSimon Glass 	/* PMP*/
404f2105c61SSimon Glass 	val32 = (u32)(h2d->pm_port_c & 0x0f);
405f2105c61SSimon Glass 	out_le32(&reg->cqpmp, val32);
406f2105c61SSimon Glass 
407f2105c61SSimon Glass 	/* Wait no active */
408f2105c61SSimon Glass 	if (ata_wait_register(&reg->car, (1 << tag), 0, 10000))
409f2105c61SSimon Glass 		printf("Wait no active time out\n\r");
410f2105c61SSimon Glass 
411f2105c61SSimon Glass 	/* Issue command */
412f2105c61SSimon Glass 	if (!(in_le32(&reg->cqr) & (1 << tag))) {
413f2105c61SSimon Glass 		val32 = 1 << tag;
414f2105c61SSimon Glass 		out_le32(&reg->cqr, val32);
415f2105c61SSimon Glass 	}
416f2105c61SSimon Glass 
417f2105c61SSimon Glass 	/* Wait command completed for 10s */
418f2105c61SSimon Glass 	if (ata_wait_register(&reg->ccr, (1 << tag), (1 << tag), 10000)) {
419f2105c61SSimon Glass 		if (!is_ncq)
420f2105c61SSimon Glass 			printf("Non-NCQ command time out\n\r");
421f2105c61SSimon Glass 		else
422f2105c61SSimon Glass 			printf("NCQ command time out\n\r");
423f2105c61SSimon Glass 	}
424f2105c61SSimon Glass 
425f2105c61SSimon Glass 	val32 = in_le32(&reg->cer);
426f2105c61SSimon Glass 
427f2105c61SSimon Glass 	if (val32) {
428f2105c61SSimon Glass 		u32 der;
429f2105c61SSimon Glass 		fsl_sata_dump_sfis((struct sata_fis_d2h *)cmd_desc->sfis);
430f2105c61SSimon Glass 		printf("CE at device\n\r");
431f2105c61SSimon Glass 		fsl_sata_dump_regs(reg);
432f2105c61SSimon Glass 		der = in_le32(&reg->der);
433f2105c61SSimon Glass 		out_le32(&reg->cer, val32);
434f2105c61SSimon Glass 		out_le32(&reg->der, der);
435f2105c61SSimon Glass 	}
436f2105c61SSimon Glass 
437f2105c61SSimon Glass 	/* Clear complete flags */
438f2105c61SSimon Glass 	val32 = in_le32(&reg->ccr);
439f2105c61SSimon Glass 	out_le32(&reg->ccr, val32);
440f2105c61SSimon Glass 
441f2105c61SSimon Glass 	return len;
442f2105c61SSimon Glass }
443f2105c61SSimon Glass 
fsl_ata_exec_reset_cmd(struct fsl_sata * sata,struct sata_fis_h2d * cfis,int tag,u8 * buffer,u32 len)444f2105c61SSimon Glass static int fsl_ata_exec_reset_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis,
445f2105c61SSimon Glass 				 int tag, u8 *buffer, u32 len)
446f2105c61SSimon Glass {
447f2105c61SSimon Glass 	return 0;
448f2105c61SSimon Glass }
449f2105c61SSimon Glass 
fsl_sata_exec_cmd(struct fsl_sata * sata,struct sata_fis_h2d * cfis,enum cmd_type command_type,int tag,u8 * buffer,u32 len)450f2105c61SSimon Glass static int fsl_sata_exec_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis,
451f2105c61SSimon Glass 		 enum cmd_type command_type, int tag, u8 *buffer, u32 len)
452f2105c61SSimon Glass {
453f2105c61SSimon Glass 	int rc;
454f2105c61SSimon Glass 
455f2105c61SSimon Glass 	if (tag > SATA_HC_MAX_CMD || tag < 0) {
456f2105c61SSimon Glass 		printf("tag is out of range, tag=%d\n\r", tag);
457f2105c61SSimon Glass 		return -1;
458f2105c61SSimon Glass 	}
459f2105c61SSimon Glass 
460f2105c61SSimon Glass 	switch (command_type) {
461f2105c61SSimon Glass 	case CMD_ATA:
462f2105c61SSimon Glass 		rc = fsl_ata_exec_ata_cmd(sata, cfis, 0, tag, buffer, len);
463f2105c61SSimon Glass 		return rc;
464f2105c61SSimon Glass 	case CMD_RESET:
465f2105c61SSimon Glass 		rc = fsl_ata_exec_reset_cmd(sata, cfis, tag, buffer, len);
466f2105c61SSimon Glass 		return rc;
467f2105c61SSimon Glass 	case CMD_NCQ:
468f2105c61SSimon Glass 		rc = fsl_ata_exec_ata_cmd(sata, cfis, 1, tag, buffer, len);
469f2105c61SSimon Glass 		return rc;
470f2105c61SSimon Glass 	case CMD_ATAPI:
471f2105c61SSimon Glass 	case CMD_VENDOR_BIST:
472f2105c61SSimon Glass 	case CMD_BIST:
473f2105c61SSimon Glass 		printf("not support now\n\r");
474f2105c61SSimon Glass 		return -1;
475f2105c61SSimon Glass 	default:
476f2105c61SSimon Glass 		break;
477f2105c61SSimon Glass 	}
478f2105c61SSimon Glass 
479f2105c61SSimon Glass 	return -1;
480f2105c61SSimon Glass }
481f2105c61SSimon Glass 
fsl_sata_identify(int dev,u16 * id)482f2105c61SSimon Glass static void fsl_sata_identify(int dev, u16 *id)
483f2105c61SSimon Glass {
484f2105c61SSimon Glass 	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
485f2105c61SSimon Glass 	struct sata_fis_h2d h2d, *cfis = &h2d;
486f2105c61SSimon Glass 
487f2105c61SSimon Glass 	memset(cfis, 0, sizeof(struct sata_fis_h2d));
488f2105c61SSimon Glass 
489f2105c61SSimon Glass 	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
490f2105c61SSimon Glass 	cfis->pm_port_c = 0x80; /* is command */
491f2105c61SSimon Glass 	cfis->command = ATA_CMD_ID_ATA;
492f2105c61SSimon Glass 
493f2105c61SSimon Glass 	fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, (u8 *)id, ATA_ID_WORDS * 2);
494f2105c61SSimon Glass 	ata_swap_buf_le16(id, ATA_ID_WORDS);
495f2105c61SSimon Glass }
496f2105c61SSimon Glass 
fsl_sata_xfer_mode(int dev,u16 * id)497f2105c61SSimon Glass static void fsl_sata_xfer_mode(int dev, u16 *id)
498f2105c61SSimon Glass {
499f2105c61SSimon Glass 	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
500f2105c61SSimon Glass 
501f2105c61SSimon Glass 	sata->pio = id[ATA_ID_PIO_MODES];
502f2105c61SSimon Glass 	sata->mwdma = id[ATA_ID_MWDMA_MODES];
503f2105c61SSimon Glass 	sata->udma = id[ATA_ID_UDMA_MODES];
504f2105c61SSimon Glass 	debug("pio %04x, mwdma %04x, udma %04x\n\r", sata->pio, sata->mwdma, sata->udma);
505f2105c61SSimon Glass }
506f2105c61SSimon Glass 
fsl_sata_set_features(int dev)507f2105c61SSimon Glass static void fsl_sata_set_features(int dev)
508f2105c61SSimon Glass {
509f2105c61SSimon Glass 	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
510f2105c61SSimon Glass 	struct sata_fis_h2d h2d, *cfis = &h2d;
511f2105c61SSimon Glass 	u8 udma_cap;
512f2105c61SSimon Glass 
513f2105c61SSimon Glass 	memset(cfis, 0, sizeof(struct sata_fis_h2d));
514f2105c61SSimon Glass 
515f2105c61SSimon Glass 	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
516f2105c61SSimon Glass 	cfis->pm_port_c = 0x80; /* is command */
517f2105c61SSimon Glass 	cfis->command = ATA_CMD_SET_FEATURES;
518f2105c61SSimon Glass 	cfis->features = SETFEATURES_XFER;
519f2105c61SSimon Glass 
520f2105c61SSimon Glass 	/* First check the device capablity */
521f2105c61SSimon Glass 	udma_cap = (u8)(sata->udma & 0xff);
522f2105c61SSimon Glass 	debug("udma_cap %02x\n\r", udma_cap);
523f2105c61SSimon Glass 
524f2105c61SSimon Glass 	if (udma_cap == ATA_UDMA6)
525f2105c61SSimon Glass 		cfis->sector_count = XFER_UDMA_6;
526f2105c61SSimon Glass 	if (udma_cap == ATA_UDMA5)
527f2105c61SSimon Glass 		cfis->sector_count = XFER_UDMA_5;
528f2105c61SSimon Glass 	if (udma_cap == ATA_UDMA4)
529f2105c61SSimon Glass 		cfis->sector_count = XFER_UDMA_4;
530f2105c61SSimon Glass 	if (udma_cap == ATA_UDMA3)
531f2105c61SSimon Glass 		cfis->sector_count = XFER_UDMA_3;
532f2105c61SSimon Glass 
533f2105c61SSimon Glass 	fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0);
534f2105c61SSimon Glass }
535f2105c61SSimon Glass 
fsl_sata_rw_cmd(int dev,u32 start,u32 blkcnt,u8 * buffer,int is_write)536f2105c61SSimon Glass static u32 fsl_sata_rw_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write)
537f2105c61SSimon Glass {
538f2105c61SSimon Glass 	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
539f2105c61SSimon Glass 	struct sata_fis_h2d h2d, *cfis = &h2d;
540f2105c61SSimon Glass 	u32 block;
541f2105c61SSimon Glass 
542f2105c61SSimon Glass 	block = start;
543f2105c61SSimon Glass 
544f2105c61SSimon Glass 	memset(cfis, 0, sizeof(struct sata_fis_h2d));
545f2105c61SSimon Glass 
546f2105c61SSimon Glass 	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
547f2105c61SSimon Glass 	cfis->pm_port_c = 0x80; /* is command */
548f2105c61SSimon Glass 	cfis->command = (is_write) ? ATA_CMD_WRITE : ATA_CMD_READ;
549f2105c61SSimon Glass 	cfis->device = ATA_LBA;
550f2105c61SSimon Glass 
551f2105c61SSimon Glass 	cfis->device |= (block >> 24) & 0xf;
552f2105c61SSimon Glass 	cfis->lba_high = (block >> 16) & 0xff;
553f2105c61SSimon Glass 	cfis->lba_mid = (block >> 8) & 0xff;
554f2105c61SSimon Glass 	cfis->lba_low = block & 0xff;
555f2105c61SSimon Glass 	cfis->sector_count = (u8)(blkcnt & 0xff);
556f2105c61SSimon Glass 
557f2105c61SSimon Glass 	fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, buffer, ATA_SECT_SIZE * blkcnt);
558f2105c61SSimon Glass 	return blkcnt;
559f2105c61SSimon Glass }
560f2105c61SSimon Glass 
fsl_sata_flush_cache(int dev)561f2105c61SSimon Glass static void fsl_sata_flush_cache(int dev)
562f2105c61SSimon Glass {
563f2105c61SSimon Glass 	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
564f2105c61SSimon Glass 	struct sata_fis_h2d h2d, *cfis = &h2d;
565f2105c61SSimon Glass 
566f2105c61SSimon Glass 	memset(cfis, 0, sizeof(struct sata_fis_h2d));
567f2105c61SSimon Glass 
568f2105c61SSimon Glass 	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
569f2105c61SSimon Glass 	cfis->pm_port_c = 0x80; /* is command */
570f2105c61SSimon Glass 	cfis->command = ATA_CMD_FLUSH;
571f2105c61SSimon Glass 
572f2105c61SSimon Glass 	fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0);
573f2105c61SSimon Glass }
574f2105c61SSimon Glass 
fsl_sata_rw_cmd_ext(int dev,u32 start,u32 blkcnt,u8 * buffer,int is_write)575f2105c61SSimon Glass static u32 fsl_sata_rw_cmd_ext(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write)
576f2105c61SSimon Glass {
577f2105c61SSimon Glass 	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
578f2105c61SSimon Glass 	struct sata_fis_h2d h2d, *cfis = &h2d;
579f2105c61SSimon Glass 	u64 block;
580f2105c61SSimon Glass 
581f2105c61SSimon Glass 	block = (u64)start;
582f2105c61SSimon Glass 
583f2105c61SSimon Glass 	memset(cfis, 0, sizeof(struct sata_fis_h2d));
584f2105c61SSimon Glass 
585f2105c61SSimon Glass 	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
586f2105c61SSimon Glass 	cfis->pm_port_c = 0x80; /* is command */
587f2105c61SSimon Glass 
588f2105c61SSimon Glass 	cfis->command = (is_write) ? ATA_CMD_WRITE_EXT
589f2105c61SSimon Glass 				 : ATA_CMD_READ_EXT;
590f2105c61SSimon Glass 
591f2105c61SSimon Glass 	cfis->lba_high_exp = (block >> 40) & 0xff;
592f2105c61SSimon Glass 	cfis->lba_mid_exp = (block >> 32) & 0xff;
593f2105c61SSimon Glass 	cfis->lba_low_exp = (block >> 24) & 0xff;
594f2105c61SSimon Glass 	cfis->lba_high = (block >> 16) & 0xff;
595f2105c61SSimon Glass 	cfis->lba_mid = (block >> 8) & 0xff;
596f2105c61SSimon Glass 	cfis->lba_low = block & 0xff;
597f2105c61SSimon Glass 	cfis->device = ATA_LBA;
598f2105c61SSimon Glass 	cfis->sector_count_exp = (blkcnt >> 8) & 0xff;
599f2105c61SSimon Glass 	cfis->sector_count = blkcnt & 0xff;
600f2105c61SSimon Glass 
601f2105c61SSimon Glass 	fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, buffer, ATA_SECT_SIZE * blkcnt);
602f2105c61SSimon Glass 	return blkcnt;
603f2105c61SSimon Glass }
604f2105c61SSimon Glass 
fsl_sata_rw_ncq_cmd(int dev,u32 start,u32 blkcnt,u8 * buffer,int is_write)605f2105c61SSimon Glass static u32 fsl_sata_rw_ncq_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer,
606f2105c61SSimon Glass 			       int is_write)
607f2105c61SSimon Glass {
608f2105c61SSimon Glass 	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
609f2105c61SSimon Glass 	struct sata_fis_h2d h2d, *cfis = &h2d;
610f2105c61SSimon Glass 	int ncq_channel;
611f2105c61SSimon Glass 	u64 block;
612f2105c61SSimon Glass 
613f2105c61SSimon Glass 	if (sata->lba48 != 1) {
614f2105c61SSimon Glass 		printf("execute FPDMA command on non-LBA48 hard disk\n\r");
615f2105c61SSimon Glass 		return -1;
616f2105c61SSimon Glass 	}
617f2105c61SSimon Glass 
618f2105c61SSimon Glass 	block = (u64)start;
619f2105c61SSimon Glass 
620f2105c61SSimon Glass 	memset(cfis, 0, sizeof(struct sata_fis_h2d));
621f2105c61SSimon Glass 
622f2105c61SSimon Glass 	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
623f2105c61SSimon Glass 	cfis->pm_port_c = 0x80; /* is command */
624f2105c61SSimon Glass 
625f2105c61SSimon Glass 	cfis->command = (is_write) ? ATA_CMD_FPDMA_WRITE
626f2105c61SSimon Glass 				 : ATA_CMD_FPDMA_READ;
627f2105c61SSimon Glass 
628f2105c61SSimon Glass 	cfis->lba_high_exp = (block >> 40) & 0xff;
629f2105c61SSimon Glass 	cfis->lba_mid_exp = (block >> 32) & 0xff;
630f2105c61SSimon Glass 	cfis->lba_low_exp = (block >> 24) & 0xff;
631f2105c61SSimon Glass 	cfis->lba_high = (block >> 16) & 0xff;
632f2105c61SSimon Glass 	cfis->lba_mid = (block >> 8) & 0xff;
633f2105c61SSimon Glass 	cfis->lba_low = block & 0xff;
634f2105c61SSimon Glass 
635f2105c61SSimon Glass 	cfis->device = ATA_LBA;
636f2105c61SSimon Glass 	cfis->features_exp = (blkcnt >> 8) & 0xff;
637f2105c61SSimon Glass 	cfis->features = blkcnt & 0xff;
638f2105c61SSimon Glass 
639f2105c61SSimon Glass 	if (sata->queue_depth >= SATA_HC_MAX_CMD)
640f2105c61SSimon Glass 		ncq_channel = SATA_HC_MAX_CMD - 1;
641f2105c61SSimon Glass 	else
642f2105c61SSimon Glass 		ncq_channel = sata->queue_depth - 1;
643f2105c61SSimon Glass 
644f2105c61SSimon Glass 	/* Use the latest queue */
645f2105c61SSimon Glass 	fsl_sata_exec_cmd(sata, cfis, CMD_NCQ, ncq_channel, buffer, ATA_SECT_SIZE * blkcnt);
646f2105c61SSimon Glass 	return blkcnt;
647f2105c61SSimon Glass }
648f2105c61SSimon Glass 
fsl_sata_flush_cache_ext(int dev)649f2105c61SSimon Glass static void fsl_sata_flush_cache_ext(int dev)
650f2105c61SSimon Glass {
651f2105c61SSimon Glass 	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
652f2105c61SSimon Glass 	struct sata_fis_h2d h2d, *cfis = &h2d;
653f2105c61SSimon Glass 
654f2105c61SSimon Glass 	memset(cfis, 0, sizeof(struct sata_fis_h2d));
655f2105c61SSimon Glass 
656f2105c61SSimon Glass 	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
657f2105c61SSimon Glass 	cfis->pm_port_c = 0x80; /* is command */
658f2105c61SSimon Glass 	cfis->command = ATA_CMD_FLUSH_EXT;
659f2105c61SSimon Glass 
660f2105c61SSimon Glass 	fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0);
661f2105c61SSimon Glass }
662f2105c61SSimon Glass 
fsl_sata_init_wcache(int dev,u16 * id)663f2105c61SSimon Glass static void fsl_sata_init_wcache(int dev, u16 *id)
664f2105c61SSimon Glass {
665f2105c61SSimon Glass 	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
666f2105c61SSimon Glass 
667f2105c61SSimon Glass 	if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id))
668f2105c61SSimon Glass 		sata->wcache = 1;
669f2105c61SSimon Glass 	if (ata_id_has_flush(id))
670f2105c61SSimon Glass 		sata->flush = 1;
671f2105c61SSimon Glass 	if (ata_id_has_flush_ext(id))
672f2105c61SSimon Glass 		sata->flush_ext = 1;
673f2105c61SSimon Glass }
674f2105c61SSimon Glass 
fsl_sata_get_wcache(int dev)675f2105c61SSimon Glass static int fsl_sata_get_wcache(int dev)
676f2105c61SSimon Glass {
677f2105c61SSimon Glass 	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
678f2105c61SSimon Glass 	return sata->wcache;
679f2105c61SSimon Glass }
680f2105c61SSimon Glass 
fsl_sata_get_flush(int dev)681f2105c61SSimon Glass static int fsl_sata_get_flush(int dev)
682f2105c61SSimon Glass {
683f2105c61SSimon Glass 	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
684f2105c61SSimon Glass 	return sata->flush;
685f2105c61SSimon Glass }
686f2105c61SSimon Glass 
fsl_sata_get_flush_ext(int dev)687f2105c61SSimon Glass static int fsl_sata_get_flush_ext(int dev)
688f2105c61SSimon Glass {
689f2105c61SSimon Glass 	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
690f2105c61SSimon Glass 	return sata->flush_ext;
691f2105c61SSimon Glass }
692f2105c61SSimon Glass 
ata_low_level_rw_lba48(int dev,u32 blknr,lbaint_t blkcnt,const void * buffer,int is_write)693f2105c61SSimon Glass static u32 ata_low_level_rw_lba48(int dev, u32 blknr, lbaint_t blkcnt,
694f2105c61SSimon Glass 		const void *buffer, int is_write)
695f2105c61SSimon Glass {
696f2105c61SSimon Glass 	u32 start, blks;
697f2105c61SSimon Glass 	u8 *addr;
698f2105c61SSimon Glass 	int max_blks;
699f2105c61SSimon Glass 
700f2105c61SSimon Glass 	start = blknr;
701f2105c61SSimon Glass 	blks = blkcnt;
702f2105c61SSimon Glass 	addr = (u8 *)buffer;
703f2105c61SSimon Glass 
704f2105c61SSimon Glass 	max_blks = ATA_MAX_SECTORS_LBA48;
705f2105c61SSimon Glass 	do {
706f2105c61SSimon Glass 		if (blks > max_blks) {
707f2105c61SSimon Glass 			if (fsl_sata_info[dev].flags != FLAGS_FPDMA)
708f2105c61SSimon Glass 				fsl_sata_rw_cmd_ext(dev, start, max_blks, addr, is_write);
709f2105c61SSimon Glass 			else
710f2105c61SSimon Glass 				fsl_sata_rw_ncq_cmd(dev, start, max_blks, addr, is_write);
711f2105c61SSimon Glass 			start += max_blks;
712f2105c61SSimon Glass 			blks -= max_blks;
713f2105c61SSimon Glass 			addr += ATA_SECT_SIZE * max_blks;
714f2105c61SSimon Glass 		} else {
715f2105c61SSimon Glass 			if (fsl_sata_info[dev].flags != FLAGS_FPDMA)
716f2105c61SSimon Glass 				fsl_sata_rw_cmd_ext(dev, start, blks, addr, is_write);
717f2105c61SSimon Glass 			else
718f2105c61SSimon Glass 				fsl_sata_rw_ncq_cmd(dev, start, blks, addr, is_write);
719f2105c61SSimon Glass 			start += blks;
720f2105c61SSimon Glass 			blks = 0;
721f2105c61SSimon Glass 			addr += ATA_SECT_SIZE * blks;
722f2105c61SSimon Glass 		}
723f2105c61SSimon Glass 	} while (blks != 0);
724f2105c61SSimon Glass 
725f2105c61SSimon Glass 	return blkcnt;
726f2105c61SSimon Glass }
727f2105c61SSimon Glass 
ata_low_level_rw_lba28(int dev,u32 blknr,u32 blkcnt,const void * buffer,int is_write)728f2105c61SSimon Glass static u32 ata_low_level_rw_lba28(int dev, u32 blknr, u32 blkcnt,
729f2105c61SSimon Glass 				  const void *buffer, int is_write)
730f2105c61SSimon Glass {
731f2105c61SSimon Glass 	u32 start, blks;
732f2105c61SSimon Glass 	u8 *addr;
733f2105c61SSimon Glass 	int max_blks;
734f2105c61SSimon Glass 
735f2105c61SSimon Glass 	start = blknr;
736f2105c61SSimon Glass 	blks = blkcnt;
737f2105c61SSimon Glass 	addr = (u8 *)buffer;
738f2105c61SSimon Glass 
739f2105c61SSimon Glass 	max_blks = ATA_MAX_SECTORS;
740f2105c61SSimon Glass 	do {
741f2105c61SSimon Glass 		if (blks > max_blks) {
742f2105c61SSimon Glass 			fsl_sata_rw_cmd(dev, start, max_blks, addr, is_write);
743f2105c61SSimon Glass 			start += max_blks;
744f2105c61SSimon Glass 			blks -= max_blks;
745f2105c61SSimon Glass 			addr += ATA_SECT_SIZE * max_blks;
746f2105c61SSimon Glass 		} else {
747f2105c61SSimon Glass 			fsl_sata_rw_cmd(dev, start, blks, addr, is_write);
748f2105c61SSimon Glass 			start += blks;
749f2105c61SSimon Glass 			blks = 0;
750f2105c61SSimon Glass 			addr += ATA_SECT_SIZE * blks;
751f2105c61SSimon Glass 		}
752f2105c61SSimon Glass 	} while (blks != 0);
753f2105c61SSimon Glass 
754f2105c61SSimon Glass 	return blkcnt;
755f2105c61SSimon Glass }
756f2105c61SSimon Glass 
757f2105c61SSimon Glass /*
758f2105c61SSimon Glass  * SATA interface between low level driver and command layer
759f2105c61SSimon Glass  */
sata_read(int dev,ulong blknr,lbaint_t blkcnt,void * buffer)760f2105c61SSimon Glass ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer)
761f2105c61SSimon Glass {
762f2105c61SSimon Glass 	u32 rc;
763f2105c61SSimon Glass 	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
764f2105c61SSimon Glass 
765f2105c61SSimon Glass 	if (sata->lba48)
766f2105c61SSimon Glass 		rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, READ_CMD);
767f2105c61SSimon Glass 	else
768f2105c61SSimon Glass 		rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, buffer, READ_CMD);
769f2105c61SSimon Glass 	return rc;
770f2105c61SSimon Glass }
771f2105c61SSimon Glass 
sata_write(int dev,ulong blknr,lbaint_t blkcnt,const void * buffer)772f2105c61SSimon Glass ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer)
773f2105c61SSimon Glass {
774f2105c61SSimon Glass 	u32 rc;
775f2105c61SSimon Glass 	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
776f2105c61SSimon Glass 
777f2105c61SSimon Glass 	if (sata->lba48) {
778f2105c61SSimon Glass 		rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, WRITE_CMD);
779f2105c61SSimon Glass 		if (fsl_sata_get_wcache(dev) && fsl_sata_get_flush_ext(dev))
780f2105c61SSimon Glass 			fsl_sata_flush_cache_ext(dev);
781f2105c61SSimon Glass 	} else {
782f2105c61SSimon Glass 		rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, buffer, WRITE_CMD);
783f2105c61SSimon Glass 		if (fsl_sata_get_wcache(dev) && fsl_sata_get_flush(dev))
784f2105c61SSimon Glass 			fsl_sata_flush_cache(dev);
785f2105c61SSimon Glass 	}
786f2105c61SSimon Glass 	return rc;
787f2105c61SSimon Glass }
788f2105c61SSimon Glass 
scan_sata(int dev)789f2105c61SSimon Glass int scan_sata(int dev)
790f2105c61SSimon Glass {
791f2105c61SSimon Glass 	fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv;
792f2105c61SSimon Glass 	unsigned char serial[ATA_ID_SERNO_LEN + 1];
793f2105c61SSimon Glass 	unsigned char firmware[ATA_ID_FW_REV_LEN + 1];
794f2105c61SSimon Glass 	unsigned char product[ATA_ID_PROD_LEN + 1];
795f2105c61SSimon Glass 	u16 *id;
796f2105c61SSimon Glass 	u64 n_sectors;
797f2105c61SSimon Glass 
798f2105c61SSimon Glass 	/* if no detected link */
799f2105c61SSimon Glass 	if (!sata->link)
800f2105c61SSimon Glass 		return -1;
801f2105c61SSimon Glass 
802f2105c61SSimon Glass 	id = (u16 *)malloc(ATA_ID_WORDS * 2);
803f2105c61SSimon Glass 	if (!id) {
804f2105c61SSimon Glass 		printf("id malloc failed\n\r");
805f2105c61SSimon Glass 		return -1;
806f2105c61SSimon Glass 	}
807f2105c61SSimon Glass 
808f2105c61SSimon Glass 	/* Identify device to get information */
809f2105c61SSimon Glass 	fsl_sata_identify(dev, id);
810f2105c61SSimon Glass 
811f2105c61SSimon Glass 	/* Serial number */
812f2105c61SSimon Glass 	ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial));
813f2105c61SSimon Glass 	memcpy(sata_dev_desc[dev].product, serial, sizeof(serial));
814f2105c61SSimon Glass 
815f2105c61SSimon Glass 	/* Firmware version */
816f2105c61SSimon Glass 	ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware));
817f2105c61SSimon Glass 	memcpy(sata_dev_desc[dev].revision, firmware, sizeof(firmware));
818f2105c61SSimon Glass 
819f2105c61SSimon Glass 	/* Product model */
820f2105c61SSimon Glass 	ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product));
821f2105c61SSimon Glass 	memcpy(sata_dev_desc[dev].vendor, product, sizeof(product));
822f2105c61SSimon Glass 
823f2105c61SSimon Glass 	/* Totoal sectors */
824f2105c61SSimon Glass 	n_sectors = ata_id_n_sectors(id);
825f2105c61SSimon Glass 	sata_dev_desc[dev].lba = (u32)n_sectors;
826f2105c61SSimon Glass 
827f2105c61SSimon Glass #ifdef CONFIG_LBA48
828f2105c61SSimon Glass 	/* Check if support LBA48 */
829f2105c61SSimon Glass 	if (ata_id_has_lba48(id)) {
830f2105c61SSimon Glass 		sata->lba48 = 1;
831f2105c61SSimon Glass 		debug("Device support LBA48\n\r");
832f2105c61SSimon Glass 	} else
833f2105c61SSimon Glass 		debug("Device supports LBA28\n\r");
834f2105c61SSimon Glass #endif
835f2105c61SSimon Glass 
836f2105c61SSimon Glass 	/* Get the NCQ queue depth from device */
837f2105c61SSimon Glass 	sata->queue_depth = ata_id_queue_depth(id);
838f2105c61SSimon Glass 
839f2105c61SSimon Glass 	/* Get the xfer mode from device */
840f2105c61SSimon Glass 	fsl_sata_xfer_mode(dev, id);
841f2105c61SSimon Glass 
842f2105c61SSimon Glass 	/* Get the write cache status from device */
843f2105c61SSimon Glass 	fsl_sata_init_wcache(dev, id);
844f2105c61SSimon Glass 
845f2105c61SSimon Glass 	/* Set the xfer mode to highest speed */
846f2105c61SSimon Glass 	fsl_sata_set_features(dev);
847f2105c61SSimon Glass #ifdef DEBUG
848f2105c61SSimon Glass 	fsl_sata_identify(dev, id);
849f2105c61SSimon Glass 	ata_dump_id(id);
850f2105c61SSimon Glass #endif
851f2105c61SSimon Glass 	free((void *)id);
852f2105c61SSimon Glass 	return 0;
853f2105c61SSimon Glass }
854