xref: /openbmc/u-boot/drivers/ata/sata_mv.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2f2105c61SSimon Glass /*
3f2105c61SSimon Glass  * Copyright (C) Excito Elektronik i Skåne AB, 2010.
4f2105c61SSimon Glass  * Author: Tor Krill <tor@excito.com>
5f2105c61SSimon Glass  *
6f2105c61SSimon Glass  * Copyright (C) 2015 Stefan Roese <sr@denx.de>
7f2105c61SSimon Glass  */
8f2105c61SSimon Glass 
9f2105c61SSimon Glass /*
10f2105c61SSimon Glass  * This driver supports the SATA controller of some Mavell SoC's.
11f2105c61SSimon Glass  * Here a (most likely incomplete) list of the supported SoC's:
12f2105c61SSimon Glass  * - Kirkwood
13f2105c61SSimon Glass  * - Armada 370
14f2105c61SSimon Glass  * - Armada XP
15f2105c61SSimon Glass  *
16f2105c61SSimon Glass  * This driver implementation is an alternative to the already available
17f2105c61SSimon Glass  * driver via the "ide" commands interface (drivers/block/mvsata_ide.c).
18f2105c61SSimon Glass  * But this driver only supports PIO mode and as this new driver also
19f2105c61SSimon Glass  * supports transfer via DMA, its much faster.
20f2105c61SSimon Glass  *
21f2105c61SSimon Glass  * Please note, that the newer SoC's (e.g. Armada 38x) are not supported
22f2105c61SSimon Glass  * by this driver. As they have an AHCI compatible SATA controller
23f2105c61SSimon Glass  * integrated.
24f2105c61SSimon Glass  */
25f2105c61SSimon Glass 
26f2105c61SSimon Glass /*
27f2105c61SSimon Glass  * TODO:
28f2105c61SSimon Glass  * Better error recovery
29f2105c61SSimon Glass  * No support for using PRDs (Thus max 64KB transfers)
30f2105c61SSimon Glass  * No NCQ support
31f2105c61SSimon Glass  * No port multiplier support
32f2105c61SSimon Glass  */
33f2105c61SSimon Glass 
34f2105c61SSimon Glass #include <common.h>
35f2105c61SSimon Glass #include <fis.h>
36f2105c61SSimon Glass #include <libata.h>
37f2105c61SSimon Glass #include <malloc.h>
38f2105c61SSimon Glass #include <sata.h>
39f2105c61SSimon Glass #include <linux/errno.h>
40f2105c61SSimon Glass #include <asm/io.h>
41f2105c61SSimon Glass #include <linux/mbus.h>
42f2105c61SSimon Glass 
43f2105c61SSimon Glass #if defined(CONFIG_KIRKWOOD)
44f2105c61SSimon Glass #include <asm/arch/kirkwood.h>
45f2105c61SSimon Glass #define SATAHC_BASE		KW_SATA_BASE
46f2105c61SSimon Glass #else
47f2105c61SSimon Glass #include <asm/arch/soc.h>
48f2105c61SSimon Glass #define SATAHC_BASE		MVEBU_AXP_SATA_BASE
49f2105c61SSimon Glass #endif
50f2105c61SSimon Glass 
51f2105c61SSimon Glass #define SATA0_BASE		(SATAHC_BASE + 0x2000)
52f2105c61SSimon Glass #define SATA1_BASE		(SATAHC_BASE + 0x4000)
53f2105c61SSimon Glass 
54f2105c61SSimon Glass /* EDMA registers */
55f2105c61SSimon Glass #define EDMA_CFG		0x000
56f2105c61SSimon Glass #define EDMA_CFG_NCQ		(1 << 5)
57f2105c61SSimon Glass #define EDMA_CFG_EQUE		(1 << 9)
58f2105c61SSimon Glass #define EDMA_TIMER		0x004
59f2105c61SSimon Glass #define EDMA_IECR		0x008
60f2105c61SSimon Glass #define EDMA_IEMR		0x00c
61f2105c61SSimon Glass #define EDMA_RQBA_HI		0x010
62f2105c61SSimon Glass #define EDMA_RQIPR		0x014
63f2105c61SSimon Glass #define EDMA_RQIPR_IPMASK	(0x1f << 5)
64f2105c61SSimon Glass #define EDMA_RQIPR_IPSHIFT	5
65f2105c61SSimon Glass #define EDMA_RQOPR		0x018
66f2105c61SSimon Glass #define EDMA_RQOPR_OPMASK	(0x1f << 5)
67f2105c61SSimon Glass #define EDMA_RQOPR_OPSHIFT	5
68f2105c61SSimon Glass #define EDMA_RSBA_HI		0x01c
69f2105c61SSimon Glass #define EDMA_RSIPR		0x020
70f2105c61SSimon Glass #define EDMA_RSIPR_IPMASK	(0x1f << 3)
71f2105c61SSimon Glass #define EDMA_RSIPR_IPSHIFT	3
72f2105c61SSimon Glass #define	EDMA_RSOPR		0x024
73f2105c61SSimon Glass #define EDMA_RSOPR_OPMASK	(0x1f << 3)
74f2105c61SSimon Glass #define EDMA_RSOPR_OPSHIFT	3
75f2105c61SSimon Glass #define EDMA_CMD		0x028
76f2105c61SSimon Glass #define EDMA_CMD_ENEDMA		(0x01 << 0)
77f2105c61SSimon Glass #define EDMA_CMD_DISEDMA	(0x01 << 1)
78f2105c61SSimon Glass #define EDMA_CMD_ATARST		(0x01 << 2)
79f2105c61SSimon Glass #define EDMA_CMD_FREEZE		(0x01 << 4)
80f2105c61SSimon Glass #define EDMA_TEST_CTL		0x02c
81f2105c61SSimon Glass #define EDMA_STATUS		0x030
82f2105c61SSimon Glass #define EDMA_IORTO		0x034
83f2105c61SSimon Glass #define EDMA_CDTR		0x040
84f2105c61SSimon Glass #define EDMA_HLTCND		0x060
85f2105c61SSimon Glass #define EDMA_NTSR		0x094
86f2105c61SSimon Glass 
87f2105c61SSimon Glass /* Basic DMA registers */
88f2105c61SSimon Glass #define BDMA_CMD		0x224
89f2105c61SSimon Glass #define BDMA_STATUS		0x228
90f2105c61SSimon Glass #define BDMA_DTLB		0x22c
91f2105c61SSimon Glass #define BDMA_DTHB		0x230
92f2105c61SSimon Glass #define BDMA_DRL		0x234
93f2105c61SSimon Glass #define BDMA_DRH		0x238
94f2105c61SSimon Glass 
95f2105c61SSimon Glass /* SATA Interface registers */
96f2105c61SSimon Glass #define SIR_ICFG		0x050
97f2105c61SSimon Glass #define SIR_CFG_GEN2EN		(0x1 << 7)
98f2105c61SSimon Glass #define SIR_PLL_CFG		0x054
99f2105c61SSimon Glass #define SIR_SSTATUS		0x300
100f2105c61SSimon Glass #define SSTATUS_DET_MASK	(0x0f << 0)
101f2105c61SSimon Glass #define SIR_SERROR		0x304
102f2105c61SSimon Glass #define SIR_SCONTROL		0x308
103f2105c61SSimon Glass #define SIR_SCONTROL_DETEN	(0x01 << 0)
104f2105c61SSimon Glass #define SIR_LTMODE		0x30c
105f2105c61SSimon Glass #define SIR_LTMODE_NELBE	(0x01 << 7)
106f2105c61SSimon Glass #define SIR_PHYMODE3		0x310
107f2105c61SSimon Glass #define SIR_PHYMODE4		0x314
108f2105c61SSimon Glass #define SIR_PHYMODE1		0x32c
109f2105c61SSimon Glass #define SIR_PHYMODE2		0x330
110f2105c61SSimon Glass #define SIR_BIST_CTRL		0x334
111f2105c61SSimon Glass #define SIR_BIST_DW1		0x338
112f2105c61SSimon Glass #define SIR_BIST_DW2		0x33c
113f2105c61SSimon Glass #define SIR_SERR_IRQ_MASK	0x340
114f2105c61SSimon Glass #define SIR_SATA_IFCTRL		0x344
115f2105c61SSimon Glass #define SIR_SATA_TESTCTRL	0x348
116f2105c61SSimon Glass #define SIR_SATA_IFSTATUS	0x34c
117f2105c61SSimon Glass #define SIR_VEND_UNIQ		0x35c
118f2105c61SSimon Glass #define SIR_FIS_CFG		0x360
119f2105c61SSimon Glass #define SIR_FIS_IRQ_CAUSE	0x364
120f2105c61SSimon Glass #define SIR_FIS_IRQ_MASK	0x368
121f2105c61SSimon Glass #define SIR_FIS_DWORD0		0x370
122f2105c61SSimon Glass #define SIR_FIS_DWORD1		0x374
123f2105c61SSimon Glass #define SIR_FIS_DWORD2		0x378
124f2105c61SSimon Glass #define SIR_FIS_DWORD3		0x37c
125f2105c61SSimon Glass #define SIR_FIS_DWORD4		0x380
126f2105c61SSimon Glass #define SIR_FIS_DWORD5		0x384
127f2105c61SSimon Glass #define SIR_FIS_DWORD6		0x388
128f2105c61SSimon Glass #define SIR_PHYM9_GEN2		0x398
129f2105c61SSimon Glass #define SIR_PHYM9_GEN1		0x39c
130f2105c61SSimon Glass #define SIR_PHY_CFG		0x3a0
131f2105c61SSimon Glass #define SIR_PHYCTL		0x3a4
132f2105c61SSimon Glass #define SIR_PHYM10		0x3a8
133f2105c61SSimon Glass #define SIR_PHYM12		0x3b0
134f2105c61SSimon Glass 
135f2105c61SSimon Glass /* Shadow registers */
136f2105c61SSimon Glass #define	PIO_DATA		0x100
137f2105c61SSimon Glass #define PIO_ERR_FEATURES	0x104
138f2105c61SSimon Glass #define PIO_SECTOR_COUNT	0x108
139f2105c61SSimon Glass #define PIO_LBA_LOW		0x10c
140f2105c61SSimon Glass #define PIO_LBA_MID		0x110
141f2105c61SSimon Glass #define PIO_LBA_HI		0x114
142f2105c61SSimon Glass #define PIO_DEVICE		0x118
143f2105c61SSimon Glass #define PIO_CMD_STATUS		0x11c
144f2105c61SSimon Glass #define PIO_STATUS_ERR		(0x01 << 0)
145f2105c61SSimon Glass #define PIO_STATUS_DRQ		(0x01 << 3)
146f2105c61SSimon Glass #define PIO_STATUS_DF		(0x01 << 5)
147f2105c61SSimon Glass #define PIO_STATUS_DRDY		(0x01 << 6)
148f2105c61SSimon Glass #define PIO_STATUS_BSY		(0x01 << 7)
149f2105c61SSimon Glass #define PIO_CTRL_ALTSTAT	0x120
150f2105c61SSimon Glass 
151f2105c61SSimon Glass /* SATAHC arbiter registers */
152f2105c61SSimon Glass #define SATAHC_CFG		0x000
153f2105c61SSimon Glass #define SATAHC_RQOP		0x004
154f2105c61SSimon Glass #define SATAHC_RQIP		0x008
155f2105c61SSimon Glass #define SATAHC_ICT		0x00c
156f2105c61SSimon Glass #define SATAHC_ITT		0x010
157f2105c61SSimon Glass #define SATAHC_ICR		0x014
158f2105c61SSimon Glass #define SATAHC_ICR_PORT0	(0x01 << 0)
159f2105c61SSimon Glass #define SATAHC_ICR_PORT1	(0x01 << 1)
160f2105c61SSimon Glass #define SATAHC_MIC		0x020
161f2105c61SSimon Glass #define SATAHC_MIM		0x024
162f2105c61SSimon Glass #define SATAHC_LED_CFG		0x02c
163f2105c61SSimon Glass 
164f2105c61SSimon Glass #define REQUEST_QUEUE_SIZE	32
165f2105c61SSimon Glass #define RESPONSE_QUEUE_SIZE	REQUEST_QUEUE_SIZE
166f2105c61SSimon Glass 
167f2105c61SSimon Glass struct crqb {
168f2105c61SSimon Glass 	u32 dtb_low;		/* DW0 */
169f2105c61SSimon Glass 	u32 dtb_high;		/* DW1 */
170f2105c61SSimon Glass 	u32 control_flags;	/* DW2 */
171f2105c61SSimon Glass 	u32 drb_count;		/* DW3 */
172f2105c61SSimon Glass 	u32 ata_cmd_feat;	/* DW4 */
173f2105c61SSimon Glass 	u32 ata_addr;		/* DW5 */
174f2105c61SSimon Glass 	u32 ata_addr_exp;	/* DW6 */
175f2105c61SSimon Glass 	u32 ata_sect_count;	/* DW7 */
176f2105c61SSimon Glass };
177f2105c61SSimon Glass 
178f2105c61SSimon Glass #define CRQB_ALIGN			0x400
179f2105c61SSimon Glass 
180f2105c61SSimon Glass #define CRQB_CNTRLFLAGS_DIR		(0x01 << 0)
181f2105c61SSimon Glass #define CRQB_CNTRLFLAGS_DQTAGMASK	(0x1f << 1)
182f2105c61SSimon Glass #define CRQB_CNTRLFLAGS_DQTAGSHIFT	1
183f2105c61SSimon Glass #define CRQB_CNTRLFLAGS_PMPORTMASK	(0x0f << 12)
184f2105c61SSimon Glass #define CRQB_CNTRLFLAGS_PMPORTSHIFT	12
185f2105c61SSimon Glass #define CRQB_CNTRLFLAGS_PRDMODE		(0x01 << 16)
186f2105c61SSimon Glass #define CRQB_CNTRLFLAGS_HQTAGMASK	(0x1f << 17)
187f2105c61SSimon Glass #define CRQB_CNTRLFLAGS_HQTAGSHIFT	17
188f2105c61SSimon Glass 
189f2105c61SSimon Glass #define CRQB_CMDFEAT_CMDMASK		(0xff << 16)
190f2105c61SSimon Glass #define CRQB_CMDFEAT_CMDSHIFT		16
191f2105c61SSimon Glass #define CRQB_CMDFEAT_FEATMASK		(0xff << 16)
192f2105c61SSimon Glass #define CRQB_CMDFEAT_FEATSHIFT		24
193f2105c61SSimon Glass 
194f2105c61SSimon Glass #define CRQB_ADDR_LBA_LOWMASK		(0xff << 0)
195f2105c61SSimon Glass #define CRQB_ADDR_LBA_LOWSHIFT		0
196f2105c61SSimon Glass #define CRQB_ADDR_LBA_MIDMASK		(0xff << 8)
197f2105c61SSimon Glass #define CRQB_ADDR_LBA_MIDSHIFT		8
198f2105c61SSimon Glass #define CRQB_ADDR_LBA_HIGHMASK		(0xff << 16)
199f2105c61SSimon Glass #define CRQB_ADDR_LBA_HIGHSHIFT		16
200f2105c61SSimon Glass #define CRQB_ADDR_DEVICE_MASK		(0xff << 24)
201f2105c61SSimon Glass #define CRQB_ADDR_DEVICE_SHIFT		24
202f2105c61SSimon Glass 
203f2105c61SSimon Glass #define CRQB_ADDR_LBA_LOW_EXP_MASK	(0xff << 0)
204f2105c61SSimon Glass #define CRQB_ADDR_LBA_LOW_EXP_SHIFT	0
205f2105c61SSimon Glass #define CRQB_ADDR_LBA_MID_EXP_MASK	(0xff << 8)
206f2105c61SSimon Glass #define CRQB_ADDR_LBA_MID_EXP_SHIFT	8
207f2105c61SSimon Glass #define CRQB_ADDR_LBA_HIGH_EXP_MASK	(0xff << 16)
208f2105c61SSimon Glass #define CRQB_ADDR_LBA_HIGH_EXP_SHIFT	16
209f2105c61SSimon Glass #define CRQB_ADDR_FEATURE_EXP_MASK	(0xff << 24)
210f2105c61SSimon Glass #define CRQB_ADDR_FEATURE_EXP_SHIFT	24
211f2105c61SSimon Glass 
212f2105c61SSimon Glass #define CRQB_SECTCOUNT_COUNT_MASK	(0xff << 0)
213f2105c61SSimon Glass #define CRQB_SECTCOUNT_COUNT_SHIFT	0
214f2105c61SSimon Glass #define CRQB_SECTCOUNT_COUNT_EXP_MASK	(0xff << 8)
215f2105c61SSimon Glass #define CRQB_SECTCOUNT_COUNT_EXP_SHIFT	8
216f2105c61SSimon Glass 
217f2105c61SSimon Glass #define MVSATA_WIN_CONTROL(w)	(MVEBU_AXP_SATA_BASE + 0x30 + ((w) << 4))
218f2105c61SSimon Glass #define MVSATA_WIN_BASE(w)	(MVEBU_AXP_SATA_BASE + 0x34 + ((w) << 4))
219f2105c61SSimon Glass 
220f2105c61SSimon Glass struct eprd {
221f2105c61SSimon Glass 	u32 phyaddr_low;
222f2105c61SSimon Glass 	u32 bytecount_eot;
223f2105c61SSimon Glass 	u32 phyaddr_hi;
224f2105c61SSimon Glass 	u32 reserved;
225f2105c61SSimon Glass };
226f2105c61SSimon Glass 
227f2105c61SSimon Glass #define EPRD_PHYADDR_MASK	0xfffffffe
228f2105c61SSimon Glass #define EPRD_BYTECOUNT_MASK	0x0000ffff
229f2105c61SSimon Glass #define EPRD_EOT		(0x01 << 31)
230f2105c61SSimon Glass 
231f2105c61SSimon Glass struct crpb {
232f2105c61SSimon Glass 	u32 id;
233f2105c61SSimon Glass 	u32 flags;
234f2105c61SSimon Glass 	u32 timestamp;
235f2105c61SSimon Glass };
236f2105c61SSimon Glass 
237f2105c61SSimon Glass #define CRPB_ALIGN		0x100
238f2105c61SSimon Glass 
239f2105c61SSimon Glass #define READ_CMD		0
240f2105c61SSimon Glass #define WRITE_CMD		1
241f2105c61SSimon Glass 
242f2105c61SSimon Glass /*
243f2105c61SSimon Glass  * Since we don't use PRDs yet max transfer size
244f2105c61SSimon Glass  * is 64KB
245f2105c61SSimon Glass  */
246f2105c61SSimon Glass #define MV_ATA_MAX_SECTORS	(65535 / ATA_SECT_SIZE)
247f2105c61SSimon Glass 
248f2105c61SSimon Glass /* Keep track if hw is initialized or not */
249f2105c61SSimon Glass static u32 hw_init;
250f2105c61SSimon Glass 
251f2105c61SSimon Glass struct mv_priv {
252f2105c61SSimon Glass 	char name[12];
253f2105c61SSimon Glass 	u32 link;
254f2105c61SSimon Glass 	u32 regbase;
255f2105c61SSimon Glass 	u32 queue_depth;
256f2105c61SSimon Glass 	u16 pio;
257f2105c61SSimon Glass 	u16 mwdma;
258f2105c61SSimon Glass 	u16 udma;
259f2105c61SSimon Glass 
260f2105c61SSimon Glass 	void *crqb_alloc;
261f2105c61SSimon Glass 	struct crqb *request;
262f2105c61SSimon Glass 
263f2105c61SSimon Glass 	void *crpb_alloc;
264f2105c61SSimon Glass 	struct crpb *response;
265f2105c61SSimon Glass };
266f2105c61SSimon Glass 
ata_wait_register(u32 * addr,u32 mask,u32 val,u32 timeout_msec)267f2105c61SSimon Glass static int ata_wait_register(u32 *addr, u32 mask, u32 val, u32 timeout_msec)
268f2105c61SSimon Glass {
269f2105c61SSimon Glass 	ulong start;
270f2105c61SSimon Glass 
271f2105c61SSimon Glass 	start = get_timer(0);
272f2105c61SSimon Glass 	do {
273f2105c61SSimon Glass 		if ((in_le32(addr) & mask) == val)
274f2105c61SSimon Glass 			return 0;
275f2105c61SSimon Glass 	} while (get_timer(start) < timeout_msec);
276f2105c61SSimon Glass 
277f2105c61SSimon Glass 	return -ETIMEDOUT;
278f2105c61SSimon Glass }
279f2105c61SSimon Glass 
280f2105c61SSimon Glass /* Cut from sata_mv in linux kernel */
mv_stop_edma_engine(int port)281f2105c61SSimon Glass static int mv_stop_edma_engine(int port)
282f2105c61SSimon Glass {
283f2105c61SSimon Glass 	struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv;
284f2105c61SSimon Glass 	int i;
285f2105c61SSimon Glass 
286f2105c61SSimon Glass 	/* Disable eDMA. The disable bit auto clears. */
287f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_CMD, EDMA_CMD_DISEDMA);
288f2105c61SSimon Glass 
289f2105c61SSimon Glass 	/* Wait for the chip to confirm eDMA is off. */
290f2105c61SSimon Glass 	for (i = 10000; i > 0; i--) {
291f2105c61SSimon Glass 		u32 reg = in_le32(priv->regbase + EDMA_CMD);
292f2105c61SSimon Glass 		if (!(reg & EDMA_CMD_ENEDMA)) {
293f2105c61SSimon Glass 			debug("EDMA stop on port %d succesful\n", port);
294f2105c61SSimon Glass 			return 0;
295f2105c61SSimon Glass 		}
296f2105c61SSimon Glass 		udelay(10);
297f2105c61SSimon Glass 	}
298f2105c61SSimon Glass 	debug("EDMA stop on port %d failed\n", port);
299f2105c61SSimon Glass 	return -1;
300f2105c61SSimon Glass }
301f2105c61SSimon Glass 
mv_start_edma_engine(int port)302f2105c61SSimon Glass static int mv_start_edma_engine(int port)
303f2105c61SSimon Glass {
304f2105c61SSimon Glass 	struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv;
305f2105c61SSimon Glass 	u32 tmp;
306f2105c61SSimon Glass 
307f2105c61SSimon Glass 	/* Check preconditions */
308f2105c61SSimon Glass 	tmp = in_le32(priv->regbase + SIR_SSTATUS);
309f2105c61SSimon Glass 	if ((tmp & SSTATUS_DET_MASK) != 0x03) {
310f2105c61SSimon Glass 		printf("Device error on port: %d\n", port);
311f2105c61SSimon Glass 		return -1;
312f2105c61SSimon Glass 	}
313f2105c61SSimon Glass 
314f2105c61SSimon Glass 	tmp = in_le32(priv->regbase + PIO_CMD_STATUS);
315f2105c61SSimon Glass 	if (tmp & (ATA_BUSY | ATA_DRQ)) {
316f2105c61SSimon Glass 		printf("Device not ready on port: %d\n", port);
317f2105c61SSimon Glass 		return -1;
318f2105c61SSimon Glass 	}
319f2105c61SSimon Glass 
320f2105c61SSimon Glass 	/* Clear interrupt cause */
321f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_IECR, 0x0);
322f2105c61SSimon Glass 
323f2105c61SSimon Glass 	tmp = in_le32(SATAHC_BASE + SATAHC_ICR);
324f2105c61SSimon Glass 	tmp &= ~(port == 0 ? SATAHC_ICR_PORT0 : SATAHC_ICR_PORT1);
325f2105c61SSimon Glass 	out_le32(SATAHC_BASE + SATAHC_ICR, tmp);
326f2105c61SSimon Glass 
327f2105c61SSimon Glass 	/* Configure edma operation */
328f2105c61SSimon Glass 	tmp = in_le32(priv->regbase + EDMA_CFG);
329f2105c61SSimon Glass 	tmp &= ~EDMA_CFG_NCQ;	/* No NCQ */
330f2105c61SSimon Glass 	tmp &= ~EDMA_CFG_EQUE;	/* Dont queue operations */
331f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_CFG, tmp);
332f2105c61SSimon Glass 
333f2105c61SSimon Glass 	out_le32(priv->regbase + SIR_FIS_IRQ_CAUSE, 0x0);
334f2105c61SSimon Glass 
335f2105c61SSimon Glass 	/* Configure fis, set all to no-wait for now */
336f2105c61SSimon Glass 	out_le32(priv->regbase + SIR_FIS_CFG, 0x0);
337f2105c61SSimon Glass 
338f2105c61SSimon Glass 	/* Setup request queue */
339f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_RQBA_HI, 0x0);
340f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_RQIPR, priv->request);
341f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_RQOPR, 0x0);
342f2105c61SSimon Glass 
343f2105c61SSimon Glass 	/* Setup response queue */
344f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_RSBA_HI, 0x0);
345f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_RSOPR, priv->response);
346f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_RSIPR, 0x0);
347f2105c61SSimon Glass 
348f2105c61SSimon Glass 	/* Start edma */
349f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_CMD, EDMA_CMD_ENEDMA);
350f2105c61SSimon Glass 
351f2105c61SSimon Glass 	return 0;
352f2105c61SSimon Glass }
353f2105c61SSimon Glass 
mv_reset_channel(int port)354f2105c61SSimon Glass static int mv_reset_channel(int port)
355f2105c61SSimon Glass {
356f2105c61SSimon Glass 	struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv;
357f2105c61SSimon Glass 
358f2105c61SSimon Glass 	/* Make sure edma is stopped  */
359f2105c61SSimon Glass 	mv_stop_edma_engine(port);
360f2105c61SSimon Glass 
361f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_CMD, EDMA_CMD_ATARST);
362f2105c61SSimon Glass 	udelay(25);		/* allow reset propagation */
363f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_CMD, 0);
364f2105c61SSimon Glass 	mdelay(10);
365f2105c61SSimon Glass 
366f2105c61SSimon Glass 	return 0;
367f2105c61SSimon Glass }
368f2105c61SSimon Glass 
mv_reset_port(int port)369f2105c61SSimon Glass static void mv_reset_port(int port)
370f2105c61SSimon Glass {
371f2105c61SSimon Glass 	struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv;
372f2105c61SSimon Glass 
373f2105c61SSimon Glass 	mv_reset_channel(port);
374f2105c61SSimon Glass 
375f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_CMD, 0x0);
376f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_CFG, 0x101f);
377f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_IECR, 0x0);
378f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_IEMR, 0x0);
379f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_RQBA_HI, 0x0);
380f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_RQIPR, 0x0);
381f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_RQOPR, 0x0);
382f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_RSBA_HI, 0x0);
383f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_RSIPR, 0x0);
384f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_RSOPR, 0x0);
385f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_IORTO, 0xfa);
386f2105c61SSimon Glass }
387f2105c61SSimon Glass 
mv_reset_one_hc(void)388f2105c61SSimon Glass static void mv_reset_one_hc(void)
389f2105c61SSimon Glass {
390f2105c61SSimon Glass 	out_le32(SATAHC_BASE + SATAHC_ICT, 0x00);
391f2105c61SSimon Glass 	out_le32(SATAHC_BASE + SATAHC_ITT, 0x00);
392f2105c61SSimon Glass 	out_le32(SATAHC_BASE + SATAHC_ICR, 0x00);
393f2105c61SSimon Glass }
394f2105c61SSimon Glass 
probe_port(int port)395f2105c61SSimon Glass static int probe_port(int port)
396f2105c61SSimon Glass {
397f2105c61SSimon Glass 	struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv;
398f2105c61SSimon Glass 	int tries, tries2, set15 = 0;
399f2105c61SSimon Glass 	u32 tmp;
400f2105c61SSimon Glass 
401f2105c61SSimon Glass 	debug("Probe port: %d\n", port);
402f2105c61SSimon Glass 
403f2105c61SSimon Glass 	for (tries = 0; tries < 2; tries++) {
404f2105c61SSimon Glass 		/* Clear SError */
405f2105c61SSimon Glass 		out_le32(priv->regbase + SIR_SERROR, 0x0);
406f2105c61SSimon Glass 
407f2105c61SSimon Glass 		/* trigger com-init */
408f2105c61SSimon Glass 		tmp = in_le32(priv->regbase + SIR_SCONTROL);
409f2105c61SSimon Glass 		tmp = (tmp & 0x0f0) | 0x300 | SIR_SCONTROL_DETEN;
410f2105c61SSimon Glass 		out_le32(priv->regbase + SIR_SCONTROL, tmp);
411f2105c61SSimon Glass 
412f2105c61SSimon Glass 		mdelay(1);
413f2105c61SSimon Glass 
414f2105c61SSimon Glass 		tmp = in_le32(priv->regbase + SIR_SCONTROL);
415f2105c61SSimon Glass 		tries2 = 5;
416f2105c61SSimon Glass 		do {
417f2105c61SSimon Glass 			tmp = (tmp & 0x0f0) | 0x300;
418f2105c61SSimon Glass 			out_le32(priv->regbase + SIR_SCONTROL, tmp);
419f2105c61SSimon Glass 			mdelay(10);
420f2105c61SSimon Glass 			tmp = in_le32(priv->regbase + SIR_SCONTROL);
421f2105c61SSimon Glass 		} while ((tmp & 0xf0f) != 0x300 && tries2--);
422f2105c61SSimon Glass 
423f2105c61SSimon Glass 		mdelay(10);
424f2105c61SSimon Glass 
425f2105c61SSimon Glass 		for (tries2 = 0; tries2 < 200; tries2++) {
426f2105c61SSimon Glass 			tmp = in_le32(priv->regbase + SIR_SSTATUS);
427f2105c61SSimon Glass 			if ((tmp & SSTATUS_DET_MASK) == 0x03) {
428f2105c61SSimon Glass 				debug("Found device on port\n");
429f2105c61SSimon Glass 				return 0;
430f2105c61SSimon Glass 			}
431f2105c61SSimon Glass 			mdelay(1);
432f2105c61SSimon Glass 		}
433f2105c61SSimon Glass 
434f2105c61SSimon Glass 		if ((tmp & SSTATUS_DET_MASK) == 0) {
435f2105c61SSimon Glass 			debug("No device attached on port %d\n", port);
436f2105c61SSimon Glass 			return -ENODEV;
437f2105c61SSimon Glass 		}
438f2105c61SSimon Glass 
439f2105c61SSimon Glass 		if (!set15) {
440f2105c61SSimon Glass 			/* Try on 1.5Gb/S */
441f2105c61SSimon Glass 			debug("Try 1.5Gb link\n");
442f2105c61SSimon Glass 			set15 = 1;
443f2105c61SSimon Glass 			out_le32(priv->regbase + SIR_SCONTROL, 0x304);
444f2105c61SSimon Glass 
445f2105c61SSimon Glass 			tmp = in_le32(priv->regbase + SIR_ICFG);
446f2105c61SSimon Glass 			tmp &= ~SIR_CFG_GEN2EN;
447f2105c61SSimon Glass 			out_le32(priv->regbase + SIR_ICFG, tmp);
448f2105c61SSimon Glass 
449f2105c61SSimon Glass 			mv_reset_channel(port);
450f2105c61SSimon Glass 		}
451f2105c61SSimon Glass 	}
452f2105c61SSimon Glass 
453f2105c61SSimon Glass 	debug("Failed to probe port\n");
454f2105c61SSimon Glass 	return -1;
455f2105c61SSimon Glass }
456f2105c61SSimon Glass 
457f2105c61SSimon Glass /* Get request queue in pointer */
get_reqip(int port)458f2105c61SSimon Glass static int get_reqip(int port)
459f2105c61SSimon Glass {
460f2105c61SSimon Glass 	struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv;
461f2105c61SSimon Glass 	u32 tmp;
462f2105c61SSimon Glass 
463f2105c61SSimon Glass 	tmp = in_le32(priv->regbase + EDMA_RQIPR) & EDMA_RQIPR_IPMASK;
464f2105c61SSimon Glass 	tmp = tmp >> EDMA_RQIPR_IPSHIFT;
465f2105c61SSimon Glass 
466f2105c61SSimon Glass 	return tmp;
467f2105c61SSimon Glass }
468f2105c61SSimon Glass 
set_reqip(int port,int reqin)469f2105c61SSimon Glass static void set_reqip(int port, int reqin)
470f2105c61SSimon Glass {
471f2105c61SSimon Glass 	struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv;
472f2105c61SSimon Glass 	u32 tmp;
473f2105c61SSimon Glass 
474f2105c61SSimon Glass 	tmp = in_le32(priv->regbase + EDMA_RQIPR) & ~EDMA_RQIPR_IPMASK;
475f2105c61SSimon Glass 	tmp |= ((reqin << EDMA_RQIPR_IPSHIFT) & EDMA_RQIPR_IPMASK);
476f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_RQIPR, tmp);
477f2105c61SSimon Glass }
478f2105c61SSimon Glass 
479f2105c61SSimon Glass /* Get next available slot, ignoring possible overwrite */
get_next_reqip(int port)480f2105c61SSimon Glass static int get_next_reqip(int port)
481f2105c61SSimon Glass {
482f2105c61SSimon Glass 	int slot = get_reqip(port);
483f2105c61SSimon Glass 	slot = (slot + 1) % REQUEST_QUEUE_SIZE;
484f2105c61SSimon Glass 	return slot;
485f2105c61SSimon Glass }
486f2105c61SSimon Glass 
487f2105c61SSimon Glass /* Get response queue in pointer */
get_rspip(int port)488f2105c61SSimon Glass static int get_rspip(int port)
489f2105c61SSimon Glass {
490f2105c61SSimon Glass 	struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv;
491f2105c61SSimon Glass 	u32 tmp;
492f2105c61SSimon Glass 
493f2105c61SSimon Glass 	tmp = in_le32(priv->regbase + EDMA_RSIPR) & EDMA_RSIPR_IPMASK;
494f2105c61SSimon Glass 	tmp = tmp >> EDMA_RSIPR_IPSHIFT;
495f2105c61SSimon Glass 
496f2105c61SSimon Glass 	return tmp;
497f2105c61SSimon Glass }
498f2105c61SSimon Glass 
499f2105c61SSimon Glass /* Get response queue out pointer */
get_rspop(int port)500f2105c61SSimon Glass static int get_rspop(int port)
501f2105c61SSimon Glass {
502f2105c61SSimon Glass 	struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv;
503f2105c61SSimon Glass 	u32 tmp;
504f2105c61SSimon Glass 
505f2105c61SSimon Glass 	tmp = in_le32(priv->regbase + EDMA_RSOPR) & EDMA_RSOPR_OPMASK;
506f2105c61SSimon Glass 	tmp = tmp >> EDMA_RSOPR_OPSHIFT;
507f2105c61SSimon Glass 	return tmp;
508f2105c61SSimon Glass }
509f2105c61SSimon Glass 
510f2105c61SSimon Glass /* Get next response queue pointer  */
get_next_rspop(int port)511f2105c61SSimon Glass static int get_next_rspop(int port)
512f2105c61SSimon Glass {
513f2105c61SSimon Glass 	return (get_rspop(port) + 1) % RESPONSE_QUEUE_SIZE;
514f2105c61SSimon Glass }
515f2105c61SSimon Glass 
516f2105c61SSimon Glass /* Set response queue pointer */
set_rspop(int port,int reqin)517f2105c61SSimon Glass static void set_rspop(int port, int reqin)
518f2105c61SSimon Glass {
519f2105c61SSimon Glass 	struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv;
520f2105c61SSimon Glass 	u32 tmp;
521f2105c61SSimon Glass 
522f2105c61SSimon Glass 	tmp = in_le32(priv->regbase + EDMA_RSOPR) & ~EDMA_RSOPR_OPMASK;
523f2105c61SSimon Glass 	tmp |= ((reqin << EDMA_RSOPR_OPSHIFT) & EDMA_RSOPR_OPMASK);
524f2105c61SSimon Glass 
525f2105c61SSimon Glass 	out_le32(priv->regbase + EDMA_RSOPR, tmp);
526f2105c61SSimon Glass }
527f2105c61SSimon Glass 
wait_dma_completion(int port,int index,u32 timeout_msec)528f2105c61SSimon Glass static int wait_dma_completion(int port, int index, u32 timeout_msec)
529f2105c61SSimon Glass {
530f2105c61SSimon Glass 	u32 tmp, res;
531f2105c61SSimon Glass 
532f2105c61SSimon Glass 	tmp = port == 0 ? SATAHC_ICR_PORT0 : SATAHC_ICR_PORT1;
533f2105c61SSimon Glass 	res = ata_wait_register((u32 *)(SATAHC_BASE + SATAHC_ICR), tmp,
534f2105c61SSimon Glass 				tmp, timeout_msec);
535f2105c61SSimon Glass 	if (res)
536f2105c61SSimon Glass 		printf("Failed to wait for completion on port %d\n", port);
537f2105c61SSimon Glass 
538f2105c61SSimon Glass 	return res;
539f2105c61SSimon Glass }
540f2105c61SSimon Glass 
process_responses(int port)541f2105c61SSimon Glass static void process_responses(int port)
542f2105c61SSimon Glass {
543f2105c61SSimon Glass #ifdef DEBUG
544f2105c61SSimon Glass 	struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv;
545f2105c61SSimon Glass #endif
546f2105c61SSimon Glass 	u32 tmp;
547f2105c61SSimon Glass 	u32 outind = get_rspop(port);
548f2105c61SSimon Glass 
549f2105c61SSimon Glass 	/* Ack interrupts */
550f2105c61SSimon Glass 	tmp = in_le32(SATAHC_BASE + SATAHC_ICR);
551f2105c61SSimon Glass 	if (port == 0)
552f2105c61SSimon Glass 		tmp &= ~(BIT(0) | BIT(8));
553f2105c61SSimon Glass 	else
554f2105c61SSimon Glass 		tmp &= ~(BIT(1) | BIT(9));
555f2105c61SSimon Glass 	tmp &= ~(BIT(4));
556f2105c61SSimon Glass 	out_le32(SATAHC_BASE + SATAHC_ICR, tmp);
557f2105c61SSimon Glass 
558f2105c61SSimon Glass 	while (get_rspip(port) != outind) {
559f2105c61SSimon Glass #ifdef DEBUG
560f2105c61SSimon Glass 		debug("Response index %d flags %08x on port %d\n", outind,
561f2105c61SSimon Glass 		      priv->response[outind].flags, port);
562f2105c61SSimon Glass #endif
563f2105c61SSimon Glass 		outind = get_next_rspop(port);
564f2105c61SSimon Glass 		set_rspop(port, outind);
565f2105c61SSimon Glass 	}
566f2105c61SSimon Glass }
567f2105c61SSimon Glass 
mv_ata_exec_ata_cmd(int port,struct sata_fis_h2d * cfis,u8 * buffer,u32 len,u32 iswrite)568f2105c61SSimon Glass static int mv_ata_exec_ata_cmd(int port, struct sata_fis_h2d *cfis,
569f2105c61SSimon Glass 			       u8 *buffer, u32 len, u32 iswrite)
570f2105c61SSimon Glass {
571f2105c61SSimon Glass 	struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv;
572f2105c61SSimon Glass 	struct crqb *req;
573f2105c61SSimon Glass 	int slot;
574f2105c61SSimon Glass 	u32 start;
575f2105c61SSimon Glass 
576f2105c61SSimon Glass 	if (len >= 64 * 1024) {
577f2105c61SSimon Glass 		printf("We only support <64K transfers for now\n");
578f2105c61SSimon Glass 		return -1;
579f2105c61SSimon Glass 	}
580f2105c61SSimon Glass 
581f2105c61SSimon Glass 	/* Initialize request */
582f2105c61SSimon Glass 	slot = get_reqip(port);
583f2105c61SSimon Glass 	memset(&priv->request[slot], 0, sizeof(struct crqb));
584f2105c61SSimon Glass 	req = &priv->request[slot];
585f2105c61SSimon Glass 
586f2105c61SSimon Glass 	req->dtb_low = (u32)buffer;
587f2105c61SSimon Glass 
588f2105c61SSimon Glass 	/* Dont use PRDs */
589f2105c61SSimon Glass 	req->control_flags = CRQB_CNTRLFLAGS_PRDMODE;
590f2105c61SSimon Glass 	req->control_flags |= iswrite ? 0 : CRQB_CNTRLFLAGS_DIR;
591f2105c61SSimon Glass 	req->control_flags |=
592f2105c61SSimon Glass 	    ((cfis->pm_port_c << CRQB_CNTRLFLAGS_PMPORTSHIFT)
593f2105c61SSimon Glass 	     & CRQB_CNTRLFLAGS_PMPORTMASK);
594f2105c61SSimon Glass 
595f2105c61SSimon Glass 	req->drb_count = len;
596f2105c61SSimon Glass 
597f2105c61SSimon Glass 	req->ata_cmd_feat = (cfis->command << CRQB_CMDFEAT_CMDSHIFT) &
598f2105c61SSimon Glass 		CRQB_CMDFEAT_CMDMASK;
599f2105c61SSimon Glass 	req->ata_cmd_feat |= (cfis->features << CRQB_CMDFEAT_FEATSHIFT) &
600f2105c61SSimon Glass 		CRQB_CMDFEAT_FEATMASK;
601f2105c61SSimon Glass 
602f2105c61SSimon Glass 	req->ata_addr = (cfis->lba_low << CRQB_ADDR_LBA_LOWSHIFT) &
603f2105c61SSimon Glass 		CRQB_ADDR_LBA_LOWMASK;
604f2105c61SSimon Glass 	req->ata_addr |= (cfis->lba_mid << CRQB_ADDR_LBA_MIDSHIFT) &
605f2105c61SSimon Glass 		CRQB_ADDR_LBA_MIDMASK;
606f2105c61SSimon Glass 	req->ata_addr |= (cfis->lba_high << CRQB_ADDR_LBA_HIGHSHIFT) &
607f2105c61SSimon Glass 		CRQB_ADDR_LBA_HIGHMASK;
608f2105c61SSimon Glass 	req->ata_addr |= (cfis->device << CRQB_ADDR_DEVICE_SHIFT) &
609f2105c61SSimon Glass 		CRQB_ADDR_DEVICE_MASK;
610f2105c61SSimon Glass 
611f2105c61SSimon Glass 	req->ata_addr_exp = (cfis->lba_low_exp << CRQB_ADDR_LBA_LOW_EXP_SHIFT) &
612f2105c61SSimon Glass 		CRQB_ADDR_LBA_LOW_EXP_MASK;
613f2105c61SSimon Glass 	req->ata_addr_exp |=
614f2105c61SSimon Glass 		(cfis->lba_mid_exp << CRQB_ADDR_LBA_MID_EXP_SHIFT) &
615f2105c61SSimon Glass 		CRQB_ADDR_LBA_MID_EXP_MASK;
616f2105c61SSimon Glass 	req->ata_addr_exp |=
617f2105c61SSimon Glass 		(cfis->lba_high_exp << CRQB_ADDR_LBA_HIGH_EXP_SHIFT) &
618f2105c61SSimon Glass 		CRQB_ADDR_LBA_HIGH_EXP_MASK;
619f2105c61SSimon Glass 	req->ata_addr_exp |=
620f2105c61SSimon Glass 		(cfis->features_exp << CRQB_ADDR_FEATURE_EXP_SHIFT) &
621f2105c61SSimon Glass 		CRQB_ADDR_FEATURE_EXP_MASK;
622f2105c61SSimon Glass 
623f2105c61SSimon Glass 	req->ata_sect_count =
624f2105c61SSimon Glass 		(cfis->sector_count << CRQB_SECTCOUNT_COUNT_SHIFT) &
625f2105c61SSimon Glass 		CRQB_SECTCOUNT_COUNT_MASK;
626f2105c61SSimon Glass 	req->ata_sect_count |=
627f2105c61SSimon Glass 		(cfis->sector_count_exp << CRQB_SECTCOUNT_COUNT_EXP_SHIFT) &
628f2105c61SSimon Glass 		CRQB_SECTCOUNT_COUNT_EXP_MASK;
629f2105c61SSimon Glass 
630f2105c61SSimon Glass 	/* Flush data */
631f2105c61SSimon Glass 	start = (u32)req & ~(ARCH_DMA_MINALIGN - 1);
632f2105c61SSimon Glass 	flush_dcache_range(start,
633f2105c61SSimon Glass 			   start + ALIGN(sizeof(*req), ARCH_DMA_MINALIGN));
634f2105c61SSimon Glass 
635f2105c61SSimon Glass 	/* Trigger operation */
636f2105c61SSimon Glass 	slot = get_next_reqip(port);
637f2105c61SSimon Glass 	set_reqip(port, slot);
638f2105c61SSimon Glass 
639f2105c61SSimon Glass 	/* Wait for completion */
640f2105c61SSimon Glass 	if (wait_dma_completion(port, slot, 10000)) {
641f2105c61SSimon Glass 		printf("ATA operation timed out\n");
642f2105c61SSimon Glass 		return -1;
643f2105c61SSimon Glass 	}
644f2105c61SSimon Glass 
645f2105c61SSimon Glass 	process_responses(port);
646f2105c61SSimon Glass 
647f2105c61SSimon Glass 	/* Invalidate data on read */
648f2105c61SSimon Glass 	if (buffer && len) {
649f2105c61SSimon Glass 		start = (u32)buffer & ~(ARCH_DMA_MINALIGN - 1);
650f2105c61SSimon Glass 		invalidate_dcache_range(start,
651f2105c61SSimon Glass 					start + ALIGN(len, ARCH_DMA_MINALIGN));
652f2105c61SSimon Glass 	}
653f2105c61SSimon Glass 
654f2105c61SSimon Glass 	return len;
655f2105c61SSimon Glass }
656f2105c61SSimon Glass 
mv_sata_rw_cmd_ext(int port,lbaint_t start,u32 blkcnt,u8 * buffer,int is_write)657f2105c61SSimon Glass static u32 mv_sata_rw_cmd_ext(int port, lbaint_t start, u32 blkcnt,
658f2105c61SSimon Glass 			      u8 *buffer, int is_write)
659f2105c61SSimon Glass {
660f2105c61SSimon Glass 	struct sata_fis_h2d cfis;
661f2105c61SSimon Glass 	u32 res;
662f2105c61SSimon Glass 	u64 block;
663f2105c61SSimon Glass 
664f2105c61SSimon Glass 	block = (u64)start;
665f2105c61SSimon Glass 
666f2105c61SSimon Glass 	memset(&cfis, 0, sizeof(struct sata_fis_h2d));
667f2105c61SSimon Glass 
668f2105c61SSimon Glass 	cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
669f2105c61SSimon Glass 	cfis.command = (is_write) ? ATA_CMD_WRITE_EXT : ATA_CMD_READ_EXT;
670f2105c61SSimon Glass 
671f2105c61SSimon Glass 	cfis.lba_high_exp = (block >> 40) & 0xff;
672f2105c61SSimon Glass 	cfis.lba_mid_exp = (block >> 32) & 0xff;
673f2105c61SSimon Glass 	cfis.lba_low_exp = (block >> 24) & 0xff;
674f2105c61SSimon Glass 	cfis.lba_high = (block >> 16) & 0xff;
675f2105c61SSimon Glass 	cfis.lba_mid = (block >> 8) & 0xff;
676f2105c61SSimon Glass 	cfis.lba_low = block & 0xff;
677f2105c61SSimon Glass 	cfis.device = ATA_LBA;
678f2105c61SSimon Glass 	cfis.sector_count_exp = (blkcnt >> 8) & 0xff;
679f2105c61SSimon Glass 	cfis.sector_count = blkcnt & 0xff;
680f2105c61SSimon Glass 
681f2105c61SSimon Glass 	res = mv_ata_exec_ata_cmd(port, &cfis, buffer, ATA_SECT_SIZE * blkcnt,
682f2105c61SSimon Glass 				  is_write);
683f2105c61SSimon Glass 
684f2105c61SSimon Glass 	return res >= 0 ? blkcnt : res;
685f2105c61SSimon Glass }
686f2105c61SSimon Glass 
mv_sata_rw_cmd(int port,lbaint_t start,u32 blkcnt,u8 * buffer,int is_write)687f2105c61SSimon Glass static u32 mv_sata_rw_cmd(int port, lbaint_t start, u32 blkcnt, u8 *buffer,
688f2105c61SSimon Glass 			  int is_write)
689f2105c61SSimon Glass {
690f2105c61SSimon Glass 	struct sata_fis_h2d cfis;
691f2105c61SSimon Glass 	lbaint_t block;
692f2105c61SSimon Glass 	u32 res;
693f2105c61SSimon Glass 
694f2105c61SSimon Glass 	block = start;
695f2105c61SSimon Glass 
696f2105c61SSimon Glass 	memset(&cfis, 0, sizeof(struct sata_fis_h2d));
697f2105c61SSimon Glass 
698f2105c61SSimon Glass 	cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
699f2105c61SSimon Glass 	cfis.command = (is_write) ? ATA_CMD_WRITE : ATA_CMD_READ;
700f2105c61SSimon Glass 	cfis.device = ATA_LBA;
701f2105c61SSimon Glass 
702f2105c61SSimon Glass 	cfis.device |= (block >> 24) & 0xf;
703f2105c61SSimon Glass 	cfis.lba_high = (block >> 16) & 0xff;
704f2105c61SSimon Glass 	cfis.lba_mid = (block >> 8) & 0xff;
705f2105c61SSimon Glass 	cfis.lba_low = block & 0xff;
706f2105c61SSimon Glass 	cfis.sector_count = (u8)(blkcnt & 0xff);
707f2105c61SSimon Glass 
708f2105c61SSimon Glass 	res = mv_ata_exec_ata_cmd(port, &cfis, buffer, ATA_SECT_SIZE * blkcnt,
709f2105c61SSimon Glass 				  is_write);
710f2105c61SSimon Glass 
711f2105c61SSimon Glass 	return res >= 0 ? blkcnt : res;
712f2105c61SSimon Glass }
713f2105c61SSimon Glass 
ata_low_level_rw(int dev,lbaint_t blknr,lbaint_t blkcnt,void * buffer,int is_write)714f2105c61SSimon Glass static u32 ata_low_level_rw(int dev, lbaint_t blknr, lbaint_t blkcnt,
715f2105c61SSimon Glass 			    void *buffer, int is_write)
716f2105c61SSimon Glass {
717f2105c61SSimon Glass 	lbaint_t start, blks;
718f2105c61SSimon Glass 	u8 *addr;
719f2105c61SSimon Glass 	int max_blks;
720f2105c61SSimon Glass 
721f2105c61SSimon Glass 	debug("%s: %ld %ld\n", __func__, blknr, blkcnt);
722f2105c61SSimon Glass 
723f2105c61SSimon Glass 	start = blknr;
724f2105c61SSimon Glass 	blks = blkcnt;
725f2105c61SSimon Glass 	addr = (u8 *)buffer;
726f2105c61SSimon Glass 
727f2105c61SSimon Glass 	max_blks = MV_ATA_MAX_SECTORS;
728f2105c61SSimon Glass 	do {
729f2105c61SSimon Glass 		if (blks > max_blks) {
730f2105c61SSimon Glass 			if (sata_dev_desc[dev].lba48) {
731f2105c61SSimon Glass 				mv_sata_rw_cmd_ext(dev, start, max_blks, addr,
732f2105c61SSimon Glass 						   is_write);
733f2105c61SSimon Glass 			} else {
734f2105c61SSimon Glass 				mv_sata_rw_cmd(dev, start, max_blks, addr,
735f2105c61SSimon Glass 					       is_write);
736f2105c61SSimon Glass 			}
737f2105c61SSimon Glass 			start += max_blks;
738f2105c61SSimon Glass 			blks -= max_blks;
739f2105c61SSimon Glass 			addr += ATA_SECT_SIZE * max_blks;
740f2105c61SSimon Glass 		} else {
741f2105c61SSimon Glass 			if (sata_dev_desc[dev].lba48) {
742f2105c61SSimon Glass 				mv_sata_rw_cmd_ext(dev, start, blks, addr,
743f2105c61SSimon Glass 						   is_write);
744f2105c61SSimon Glass 			} else {
745f2105c61SSimon Glass 				mv_sata_rw_cmd(dev, start, blks, addr,
746f2105c61SSimon Glass 					       is_write);
747f2105c61SSimon Glass 			}
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 
mv_ata_exec_ata_cmd_nondma(int port,struct sata_fis_h2d * cfis,u8 * buffer,u32 len,u32 iswrite)757f2105c61SSimon Glass static int mv_ata_exec_ata_cmd_nondma(int port,
758f2105c61SSimon Glass 				      struct sata_fis_h2d *cfis, u8 *buffer,
759f2105c61SSimon Glass 				      u32 len, u32 iswrite)
760f2105c61SSimon Glass {
761f2105c61SSimon Glass 	struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv;
762f2105c61SSimon Glass 	int i;
763f2105c61SSimon Glass 	u16 *tp;
764f2105c61SSimon Glass 
765f2105c61SSimon Glass 	debug("%s\n", __func__);
766f2105c61SSimon Glass 
767f2105c61SSimon Glass 	out_le32(priv->regbase + PIO_SECTOR_COUNT, cfis->sector_count);
768f2105c61SSimon Glass 	out_le32(priv->regbase + PIO_LBA_HI, cfis->lba_high);
769f2105c61SSimon Glass 	out_le32(priv->regbase + PIO_LBA_MID, cfis->lba_mid);
770f2105c61SSimon Glass 	out_le32(priv->regbase + PIO_LBA_LOW, cfis->lba_low);
771f2105c61SSimon Glass 	out_le32(priv->regbase + PIO_ERR_FEATURES, cfis->features);
772f2105c61SSimon Glass 	out_le32(priv->regbase + PIO_DEVICE, cfis->device);
773f2105c61SSimon Glass 	out_le32(priv->regbase + PIO_CMD_STATUS, cfis->command);
774f2105c61SSimon Glass 
775f2105c61SSimon Glass 	if (ata_wait_register((u32 *)(priv->regbase + PIO_CMD_STATUS),
776f2105c61SSimon Glass 			      ATA_BUSY, 0x0, 10000)) {
777f2105c61SSimon Glass 		debug("Failed to wait for completion\n");
778f2105c61SSimon Glass 		return -1;
779f2105c61SSimon Glass 	}
780f2105c61SSimon Glass 
781f2105c61SSimon Glass 	if (len > 0) {
782f2105c61SSimon Glass 		tp = (u16 *)buffer;
783f2105c61SSimon Glass 		for (i = 0; i < len / 2; i++) {
784f2105c61SSimon Glass 			if (iswrite)
785f2105c61SSimon Glass 				out_le16(priv->regbase + PIO_DATA, *tp++);
786f2105c61SSimon Glass 			else
787f2105c61SSimon Glass 				*tp++ = in_le16(priv->regbase + PIO_DATA);
788f2105c61SSimon Glass 		}
789f2105c61SSimon Glass 	}
790f2105c61SSimon Glass 
791f2105c61SSimon Glass 	return len;
792f2105c61SSimon Glass }
793f2105c61SSimon Glass 
mv_sata_identify(int port,u16 * id)794f2105c61SSimon Glass static int mv_sata_identify(int port, u16 *id)
795f2105c61SSimon Glass {
796f2105c61SSimon Glass 	struct sata_fis_h2d h2d;
797f2105c61SSimon Glass 
798f2105c61SSimon Glass 	memset(&h2d, 0, sizeof(struct sata_fis_h2d));
799f2105c61SSimon Glass 
800f2105c61SSimon Glass 	h2d.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
801f2105c61SSimon Glass 	h2d.command = ATA_CMD_ID_ATA;
802f2105c61SSimon Glass 
803f2105c61SSimon Glass 	/* Give device time to get operational */
804f2105c61SSimon Glass 	mdelay(10);
805f2105c61SSimon Glass 
806f2105c61SSimon Glass 	return mv_ata_exec_ata_cmd_nondma(port, &h2d, (u8 *)id,
807f2105c61SSimon Glass 					  ATA_ID_WORDS * 2, READ_CMD);
808f2105c61SSimon Glass }
809f2105c61SSimon Glass 
mv_sata_xfer_mode(int port,u16 * id)810f2105c61SSimon Glass static void mv_sata_xfer_mode(int port, u16 *id)
811f2105c61SSimon Glass {
812f2105c61SSimon Glass 	struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv;
813f2105c61SSimon Glass 
814f2105c61SSimon Glass 	priv->pio = id[ATA_ID_PIO_MODES];
815f2105c61SSimon Glass 	priv->mwdma = id[ATA_ID_MWDMA_MODES];
816f2105c61SSimon Glass 	priv->udma = id[ATA_ID_UDMA_MODES];
817f2105c61SSimon Glass 	debug("pio %04x, mwdma %04x, udma %04x\n", priv->pio, priv->mwdma,
818f2105c61SSimon Glass 	      priv->udma);
819f2105c61SSimon Glass }
820f2105c61SSimon Glass 
mv_sata_set_features(int port)821f2105c61SSimon Glass static void mv_sata_set_features(int port)
822f2105c61SSimon Glass {
823f2105c61SSimon Glass 	struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv;
824f2105c61SSimon Glass 	struct sata_fis_h2d cfis;
825f2105c61SSimon Glass 	u8 udma_cap;
826f2105c61SSimon Glass 
827f2105c61SSimon Glass 	memset(&cfis, 0, sizeof(struct sata_fis_h2d));
828f2105c61SSimon Glass 
829f2105c61SSimon Glass 	cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
830f2105c61SSimon Glass 	cfis.command = ATA_CMD_SET_FEATURES;
831f2105c61SSimon Glass 	cfis.features = SETFEATURES_XFER;
832f2105c61SSimon Glass 
833f2105c61SSimon Glass 	/* First check the device capablity */
834f2105c61SSimon Glass 	udma_cap = (u8) (priv->udma & 0xff);
835f2105c61SSimon Glass 
836f2105c61SSimon Glass 	if (udma_cap == ATA_UDMA6)
837f2105c61SSimon Glass 		cfis.sector_count = XFER_UDMA_6;
838f2105c61SSimon Glass 	if (udma_cap == ATA_UDMA5)
839f2105c61SSimon Glass 		cfis.sector_count = XFER_UDMA_5;
840f2105c61SSimon Glass 	if (udma_cap == ATA_UDMA4)
841f2105c61SSimon Glass 		cfis.sector_count = XFER_UDMA_4;
842f2105c61SSimon Glass 	if (udma_cap == ATA_UDMA3)
843f2105c61SSimon Glass 		cfis.sector_count = XFER_UDMA_3;
844f2105c61SSimon Glass 
845f2105c61SSimon Glass 	mv_ata_exec_ata_cmd_nondma(port, &cfis, NULL, 0, READ_CMD);
846f2105c61SSimon Glass }
847f2105c61SSimon Glass 
mv_sata_spin_down(int dev)848f2105c61SSimon Glass int mv_sata_spin_down(int dev)
849f2105c61SSimon Glass {
850f2105c61SSimon Glass 	struct sata_fis_h2d cfis;
851f2105c61SSimon Glass 	struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[dev].priv;
852f2105c61SSimon Glass 
853f2105c61SSimon Glass 	if (priv->link == 0) {
854f2105c61SSimon Glass 		debug("No device on port: %d\n", dev);
855f2105c61SSimon Glass 		return 1;
856f2105c61SSimon Glass 	}
857f2105c61SSimon Glass 
858f2105c61SSimon Glass 	memset(&cfis, 0, sizeof(struct sata_fis_h2d));
859f2105c61SSimon Glass 
860f2105c61SSimon Glass 	cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
861f2105c61SSimon Glass 	cfis.command = ATA_CMD_STANDBY;
862f2105c61SSimon Glass 
863f2105c61SSimon Glass 	return mv_ata_exec_ata_cmd_nondma(dev, &cfis, NULL, 0, READ_CMD);
864f2105c61SSimon Glass }
865f2105c61SSimon Glass 
mv_sata_spin_up(int dev)866f2105c61SSimon Glass int mv_sata_spin_up(int dev)
867f2105c61SSimon Glass {
868f2105c61SSimon Glass 	struct sata_fis_h2d cfis;
869f2105c61SSimon Glass 	struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[dev].priv;
870f2105c61SSimon Glass 
871f2105c61SSimon Glass 	if (priv->link == 0) {
872f2105c61SSimon Glass 		debug("No device on port: %d\n", dev);
873f2105c61SSimon Glass 		return 1;
874f2105c61SSimon Glass 	}
875f2105c61SSimon Glass 
876f2105c61SSimon Glass 	memset(&cfis, 0, sizeof(struct sata_fis_h2d));
877f2105c61SSimon Glass 
878f2105c61SSimon Glass 	cfis.fis_type = SATA_FIS_TYPE_REGISTER_H2D;
879f2105c61SSimon Glass 	cfis.command = ATA_CMD_IDLE;
880f2105c61SSimon Glass 
881f2105c61SSimon Glass 	return mv_ata_exec_ata_cmd_nondma(dev, &cfis, NULL, 0, READ_CMD);
882f2105c61SSimon Glass }
883f2105c61SSimon Glass 
sata_read(int dev,ulong blknr,lbaint_t blkcnt,void * buffer)884f2105c61SSimon Glass ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer)
885f2105c61SSimon Glass {
886f2105c61SSimon Glass 	return ata_low_level_rw(dev, blknr, blkcnt, buffer, READ_CMD);
887f2105c61SSimon Glass }
888f2105c61SSimon Glass 
sata_write(int dev,ulong blknr,lbaint_t blkcnt,const void * buffer)889f2105c61SSimon Glass ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer)
890f2105c61SSimon Glass {
891f2105c61SSimon Glass 	return ata_low_level_rw(dev, blknr, blkcnt, (void *)buffer, WRITE_CMD);
892f2105c61SSimon Glass }
893f2105c61SSimon Glass 
894f2105c61SSimon Glass /*
895f2105c61SSimon Glass  * Initialize SATA memory windows
896f2105c61SSimon Glass  */
mvsata_ide_conf_mbus_windows(void)897f2105c61SSimon Glass static void mvsata_ide_conf_mbus_windows(void)
898f2105c61SSimon Glass {
899f2105c61SSimon Glass 	const struct mbus_dram_target_info *dram;
900f2105c61SSimon Glass 	int i;
901f2105c61SSimon Glass 
902f2105c61SSimon Glass 	dram = mvebu_mbus_dram_info();
903f2105c61SSimon Glass 
904f2105c61SSimon Glass 	/* Disable windows, Set Size/Base to 0  */
905f2105c61SSimon Glass 	for (i = 0; i < 4; i++) {
906f2105c61SSimon Glass 		writel(0, MVSATA_WIN_CONTROL(i));
907f2105c61SSimon Glass 		writel(0, MVSATA_WIN_BASE(i));
908f2105c61SSimon Glass 	}
909f2105c61SSimon Glass 
910f2105c61SSimon Glass 	for (i = 0; i < dram->num_cs; i++) {
911f2105c61SSimon Glass 		const struct mbus_dram_window *cs = dram->cs + i;
912f2105c61SSimon Glass 		writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) |
913f2105c61SSimon Glass 		       (dram->mbus_dram_target_id << 4) | 1,
914f2105c61SSimon Glass 		       MVSATA_WIN_CONTROL(i));
915f2105c61SSimon Glass 		writel(cs->base & 0xffff0000, MVSATA_WIN_BASE(i));
916f2105c61SSimon Glass 	}
917f2105c61SSimon Glass }
918f2105c61SSimon Glass 
init_sata(int dev)919f2105c61SSimon Glass int init_sata(int dev)
920f2105c61SSimon Glass {
921f2105c61SSimon Glass 	struct mv_priv *priv;
922f2105c61SSimon Glass 
923f2105c61SSimon Glass 	debug("Initialize sata dev: %d\n", dev);
924f2105c61SSimon Glass 
925f2105c61SSimon Glass 	if (dev < 0 || dev >= CONFIG_SYS_SATA_MAX_DEVICE) {
926f2105c61SSimon Glass 		printf("Invalid sata device %d\n", dev);
927f2105c61SSimon Glass 		return -1;
928f2105c61SSimon Glass 	}
929f2105c61SSimon Glass 
930f2105c61SSimon Glass 	priv = (struct mv_priv *)malloc(sizeof(struct mv_priv));
931f2105c61SSimon Glass 	if (!priv) {
932f2105c61SSimon Glass 		printf("Failed to allocate memory for private sata data\n");
933f2105c61SSimon Glass 		return -ENOMEM;
934f2105c61SSimon Glass 	}
935f2105c61SSimon Glass 
936f2105c61SSimon Glass 	memset((void *)priv, 0, sizeof(struct mv_priv));
937f2105c61SSimon Glass 
938f2105c61SSimon Glass 	/* Allocate and align request buffer */
939f2105c61SSimon Glass 	priv->crqb_alloc = malloc(sizeof(struct crqb) * REQUEST_QUEUE_SIZE +
940f2105c61SSimon Glass 				  CRQB_ALIGN);
941f2105c61SSimon Glass 	if (!priv->crqb_alloc) {
942f2105c61SSimon Glass 		printf("Unable to allocate memory for request queue\n");
943f2105c61SSimon Glass 		return -ENOMEM;
944f2105c61SSimon Glass 	}
945f2105c61SSimon Glass 	memset(priv->crqb_alloc, 0,
946f2105c61SSimon Glass 	       sizeof(struct crqb) * REQUEST_QUEUE_SIZE + CRQB_ALIGN);
947f2105c61SSimon Glass 	priv->request = (struct crqb *)(((u32) priv->crqb_alloc + CRQB_ALIGN) &
948f2105c61SSimon Glass 					~(CRQB_ALIGN - 1));
949f2105c61SSimon Glass 
950f2105c61SSimon Glass 	/* Allocate and align response buffer */
951f2105c61SSimon Glass 	priv->crpb_alloc = malloc(sizeof(struct crpb) * REQUEST_QUEUE_SIZE +
952f2105c61SSimon Glass 				  CRPB_ALIGN);
953f2105c61SSimon Glass 	if (!priv->crpb_alloc) {
954f2105c61SSimon Glass 		printf("Unable to allocate memory for response queue\n");
955f2105c61SSimon Glass 		return -ENOMEM;
956f2105c61SSimon Glass 	}
957f2105c61SSimon Glass 	memset(priv->crpb_alloc, 0,
958f2105c61SSimon Glass 	       sizeof(struct crpb) * REQUEST_QUEUE_SIZE + CRPB_ALIGN);
959f2105c61SSimon Glass 	priv->response = (struct crpb *)(((u32) priv->crpb_alloc + CRPB_ALIGN) &
960f2105c61SSimon Glass 					 ~(CRPB_ALIGN - 1));
961f2105c61SSimon Glass 
962f2105c61SSimon Glass 	sata_dev_desc[dev].priv = (void *)priv;
963f2105c61SSimon Glass 
964f2105c61SSimon Glass 	sprintf(priv->name, "SATA%d", dev);
965f2105c61SSimon Glass 
966f2105c61SSimon Glass 	priv->regbase = dev == 0 ? SATA0_BASE : SATA1_BASE;
967f2105c61SSimon Glass 
968f2105c61SSimon Glass 	if (!hw_init) {
969f2105c61SSimon Glass 		debug("Initialize sata hw\n");
970f2105c61SSimon Glass 		hw_init = 1;
971f2105c61SSimon Glass 		mv_reset_one_hc();
972f2105c61SSimon Glass 		mvsata_ide_conf_mbus_windows();
973f2105c61SSimon Glass 	}
974f2105c61SSimon Glass 
975f2105c61SSimon Glass 	mv_reset_port(dev);
976f2105c61SSimon Glass 
977f2105c61SSimon Glass 	if (probe_port(dev)) {
978f2105c61SSimon Glass 		priv->link = 0;
979f2105c61SSimon Glass 		return -ENODEV;
980f2105c61SSimon Glass 	}
981f2105c61SSimon Glass 	priv->link = 1;
982f2105c61SSimon Glass 
983f2105c61SSimon Glass 	return 0;
984f2105c61SSimon Glass }
985f2105c61SSimon Glass 
reset_sata(int dev)986f2105c61SSimon Glass int reset_sata(int dev)
987f2105c61SSimon Glass {
988f2105c61SSimon Glass 	return 0;
989f2105c61SSimon Glass }
990f2105c61SSimon Glass 
scan_sata(int port)991f2105c61SSimon Glass int scan_sata(int port)
992f2105c61SSimon Glass {
993f2105c61SSimon Glass 	unsigned char serial[ATA_ID_SERNO_LEN + 1];
994f2105c61SSimon Glass 	unsigned char firmware[ATA_ID_FW_REV_LEN + 1];
995f2105c61SSimon Glass 	unsigned char product[ATA_ID_PROD_LEN + 1];
996f2105c61SSimon Glass 	u64 n_sectors;
997f2105c61SSimon Glass 	u16 *id;
998f2105c61SSimon Glass 	struct mv_priv *priv = (struct mv_priv *)sata_dev_desc[port].priv;
999f2105c61SSimon Glass 
1000f2105c61SSimon Glass 	if (!priv->link)
1001f2105c61SSimon Glass 		return -ENODEV;
1002f2105c61SSimon Glass 
1003f2105c61SSimon Glass 	id = (u16 *)malloc(ATA_ID_WORDS * 2);
1004f2105c61SSimon Glass 	if (!id) {
1005f2105c61SSimon Glass 		printf("Failed to malloc id data\n");
1006f2105c61SSimon Glass 		return -ENOMEM;
1007f2105c61SSimon Glass 	}
1008f2105c61SSimon Glass 
1009f2105c61SSimon Glass 	mv_sata_identify(port, id);
1010f2105c61SSimon Glass 	ata_swap_buf_le16(id, ATA_ID_WORDS);
1011f2105c61SSimon Glass #ifdef DEBUG
1012f2105c61SSimon Glass 	ata_dump_id(id);
1013f2105c61SSimon Glass #endif
1014f2105c61SSimon Glass 
1015f2105c61SSimon Glass 	/* Serial number */
1016f2105c61SSimon Glass 	ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial));
1017f2105c61SSimon Glass 	memcpy(sata_dev_desc[port].product, serial, sizeof(serial));
1018f2105c61SSimon Glass 
1019f2105c61SSimon Glass 	/* Firmware version */
1020f2105c61SSimon Glass 	ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware));
1021f2105c61SSimon Glass 	memcpy(sata_dev_desc[port].revision, firmware, sizeof(firmware));
1022f2105c61SSimon Glass 
1023f2105c61SSimon Glass 	/* Product model */
1024f2105c61SSimon Glass 	ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product));
1025f2105c61SSimon Glass 	memcpy(sata_dev_desc[port].vendor, product, sizeof(product));
1026f2105c61SSimon Glass 
1027f2105c61SSimon Glass 	/* Total sectors */
1028f2105c61SSimon Glass 	n_sectors = ata_id_n_sectors(id);
1029f2105c61SSimon Glass 	sata_dev_desc[port].lba = n_sectors;
1030f2105c61SSimon Glass 
1031f2105c61SSimon Glass 	/* Check if support LBA48 */
1032f2105c61SSimon Glass 	if (ata_id_has_lba48(id)) {
1033f2105c61SSimon Glass 		sata_dev_desc[port].lba48 = 1;
1034f2105c61SSimon Glass 		debug("Device support LBA48\n");
1035f2105c61SSimon Glass 	}
1036f2105c61SSimon Glass 
1037f2105c61SSimon Glass 	/* Get the NCQ queue depth from device */
1038f2105c61SSimon Glass 	priv->queue_depth = ata_id_queue_depth(id);
1039f2105c61SSimon Glass 
1040f2105c61SSimon Glass 	/* Get the xfer mode from device */
1041f2105c61SSimon Glass 	mv_sata_xfer_mode(port, id);
1042f2105c61SSimon Glass 
1043f2105c61SSimon Glass 	/* Set the xfer mode to highest speed */
1044f2105c61SSimon Glass 	mv_sata_set_features(port);
1045f2105c61SSimon Glass 
1046f2105c61SSimon Glass 	/* Start up */
1047f2105c61SSimon Glass 	mv_start_edma_engine(port);
1048f2105c61SSimon Glass 
1049f2105c61SSimon Glass 	return 0;
1050f2105c61SSimon Glass }
1051