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