Blame view

drivers/ata/dwc_ahsata.c 25.7 KB
9f472e654   Stefano Babic   SATA: add driver ...
1
2
3
4
  /*
   * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
   * Terry Lv <r65388@freescale.com>
   *
1a4596601   Wolfgang Denk   Add GPL-2.0+ SPDX...
5
   * SPDX-License-Identifier:	GPL-2.0+
9f472e654   Stefano Babic   SATA: add driver ...
6
   */
0f07df430   Simon Glass   dm: sata: dw_sata...
7
  #include <common.h>
9f472e654   Stefano Babic   SATA: add driver ...
8
  #include <ahci.h>
c893f1e6e   Simon Glass   dm: sata: dwc_ahs...
9
10
  #include <dm.h>
  #include <dwc_ahsata.h>
9f472e654   Stefano Babic   SATA: add driver ...
11
  #include <fis.h>
0f07df430   Simon Glass   dm: sata: dw_sata...
12
  #include <libata.h>
9f472e654   Stefano Babic   SATA: add driver ...
13
  #include <malloc.h>
752126a05   Simon Glass   dm: sata: dw_sata...
14
  #include <memalign.h>
0f07df430   Simon Glass   dm: sata: dw_sata...
15
  #include <sata.h>
9f472e654   Stefano Babic   SATA: add driver ...
16
  #include <asm/io.h>
9f472e654   Stefano Babic   SATA: add driver ...
17
  #include <asm/arch/clock.h>
ca84d72d1   Tim Harvey   dwc_ahsata: retur...
18
  #include <asm/arch/sys_proto.h>
0f07df430   Simon Glass   dm: sata: dw_sata...
19
20
21
  #include <linux/bitops.h>
  #include <linux/ctype.h>
  #include <linux/errno.h>
90abb28fc   Simon Glass   dm: sata: dw_sata...
22
  #include "dwc_ahsata_priv.h"
9f472e654   Stefano Babic   SATA: add driver ...
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
  
  struct sata_port_regs {
  	u32 clb;
  	u32 clbu;
  	u32 fb;
  	u32 fbu;
  	u32 is;
  	u32 ie;
  	u32 cmd;
  	u32 res1[1];
  	u32 tfd;
  	u32 sig;
  	u32 ssts;
  	u32 sctl;
  	u32 serr;
  	u32 sact;
  	u32 ci;
  	u32 sntf;
  	u32 res2[1];
  	u32 dmacr;
  	u32 res3[1];
  	u32 phycr;
  	u32 physr;
  };
  
  struct sata_host_regs {
  	u32 cap;
  	u32 ghc;
  	u32 is;
  	u32 pi;
  	u32 vs;
  	u32 ccc_ctl;
  	u32 ccc_ports;
  	u32 res1[2];
  	u32 cap2;
  	u32 res2[30];
  	u32 bistafr;
  	u32 bistcr;
  	u32 bistfctr;
  	u32 bistsr;
  	u32 bistdecr;
  	u32 res3[2];
  	u32 oobr;
  	u32 res4[8];
  	u32 timer1ms;
  	u32 res5[1];
  	u32 gparam1r;
  	u32 gparam2r;
  	u32 pparamr;
  	u32 testr;
  	u32 versionr;
  	u32 idr;
  };
  
  #define MAX_DATA_BYTES_PER_SG  (4 * 1024 * 1024)
  #define MAX_BYTES_PER_TRANS (AHCI_MAX_SG * MAX_DATA_BYTES_PER_SG)
  
  #define writel_with_flush(a, b)	do { writel(a, b); readl(b); } while (0)
fa31377ef   Tang Yuantian   ahci: Fix compili...
81
  static inline void __iomem *ahci_port_base(void __iomem *base, u32 port)
9f472e654   Stefano Babic   SATA: add driver ...
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  {
  	return base + 0x100 + (port * 0x80);
  }
  
  static int waiting_for_cmd_completed(u8 *offset,
  					int timeout_msec,
  					u32 sign)
  {
  	int i;
  	u32 status;
  
  	for (i = 0;
  		((status = readl(offset)) & sign) && i < timeout_msec;
  		++i)
  		mdelay(1);
  
  	return (i < timeout_msec) ? 0 : -1;
  }
09bb951bf   Simon Glass   dm: sata: dw_sata...
100
  static int ahci_setup_oobr(struct ahci_uc_priv *uc_priv, int clk)
9f472e654   Stefano Babic   SATA: add driver ...
101
  {
4b640dbca   Simon Glass   dm: sata: dw_sata...
102
  	struct sata_host_regs *host_mmio = uc_priv->mmio_base;
9f472e654   Stefano Babic   SATA: add driver ...
103

3e59c30fc   Simon Glass   dm: sata: dw_sata...
104
105
  	writel(SATA_HOST_OOBR_WE, &host_mmio->oobr);
  	writel(0x02060b14, &host_mmio->oobr);
9f472e654   Stefano Babic   SATA: add driver ...
106
107
108
  
  	return 0;
  }
09bb951bf   Simon Glass   dm: sata: dw_sata...
109
  static int ahci_host_init(struct ahci_uc_priv *uc_priv)
9f472e654   Stefano Babic   SATA: add driver ...
110
111
112
113
  {
  	u32 tmp, cap_save, num_ports;
  	int i, j, timeout = 1000;
  	struct sata_port_regs *port_mmio = NULL;
4b640dbca   Simon Glass   dm: sata: dw_sata...
114
  	struct sata_host_regs *host_mmio = uc_priv->mmio_base;
9f472e654   Stefano Babic   SATA: add driver ...
115
  	int clk = mxc_get_clock(MXC_SATA_CLK);
3e59c30fc   Simon Glass   dm: sata: dw_sata...
116
  	cap_save = readl(&host_mmio->cap);
9f472e654   Stefano Babic   SATA: add driver ...
117
118
119
  	cap_save |= SATA_HOST_CAP_SSS;
  
  	/* global controller reset */
3e59c30fc   Simon Glass   dm: sata: dw_sata...
120
  	tmp = readl(&host_mmio->ghc);
9f472e654   Stefano Babic   SATA: add driver ...
121
  	if ((tmp & SATA_HOST_GHC_HR) == 0)
3e59c30fc   Simon Glass   dm: sata: dw_sata...
122
  		writel_with_flush(tmp | SATA_HOST_GHC_HR, &host_mmio->ghc);
9f472e654   Stefano Babic   SATA: add driver ...
123

3e59c30fc   Simon Glass   dm: sata: dw_sata...
124
  	while ((readl(&host_mmio->ghc) & SATA_HOST_GHC_HR) && --timeout)
9f472e654   Stefano Babic   SATA: add driver ...
125
126
127
128
129
130
131
132
133
  		;
  
  	if (timeout <= 0) {
  		debug("controller reset failed (0x%x)
  ", tmp);
  		return -1;
  	}
  
  	/* Set timer 1ms */
3e59c30fc   Simon Glass   dm: sata: dw_sata...
134
  	writel(clk / 1000, &host_mmio->timer1ms);
9f472e654   Stefano Babic   SATA: add driver ...
135

09bb951bf   Simon Glass   dm: sata: dw_sata...
136
  	ahci_setup_oobr(uc_priv, 0);
9f472e654   Stefano Babic   SATA: add driver ...
137

3e59c30fc   Simon Glass   dm: sata: dw_sata...
138
139
  	writel_with_flush(SATA_HOST_GHC_AE, &host_mmio->ghc);
  	writel(cap_save, &host_mmio->cap);
9f472e654   Stefano Babic   SATA: add driver ...
140
  	num_ports = (cap_save & SATA_HOST_CAP_NP_MASK) + 1;
3e59c30fc   Simon Glass   dm: sata: dw_sata...
141
  	writel_with_flush((1 << num_ports) - 1, &host_mmio->pi);
9f472e654   Stefano Babic   SATA: add driver ...
142
143
144
145
146
147
148
  
  	/*
  	 * Determine which Ports are implemented by the DWC_ahsata,
  	 * by reading the PI register. This bit map value aids the
  	 * software to determine how many Ports are available and
  	 * which Port registers need to be initialized.
  	 */
3e59c30fc   Simon Glass   dm: sata: dw_sata...
149
150
  	uc_priv->cap = readl(&host_mmio->cap);
  	uc_priv->port_map = readl(&host_mmio->pi);
9f472e654   Stefano Babic   SATA: add driver ...
151
152
  
  	/* Determine how many command slots the HBA supports */
09bb951bf   Simon Glass   dm: sata: dw_sata...
153
  	uc_priv->n_ports = (uc_priv->cap & SATA_HOST_CAP_NP_MASK) + 1;
9f472e654   Stefano Babic   SATA: add driver ...
154
155
156
  
  	debug("cap 0x%x  port_map 0x%x  n_ports %d
  ",
09bb951bf   Simon Glass   dm: sata: dw_sata...
157
  		uc_priv->cap, uc_priv->port_map, uc_priv->n_ports);
9f472e654   Stefano Babic   SATA: add driver ...
158

09bb951bf   Simon Glass   dm: sata: dw_sata...
159
160
  	for (i = 0; i < uc_priv->n_ports; i++) {
  		uc_priv->port[i].port_mmio = ahci_port_base(host_mmio, i);
4b640dbca   Simon Glass   dm: sata: dw_sata...
161
  		port_mmio = uc_priv->port[i].port_mmio;
9f472e654   Stefano Babic   SATA: add driver ...
162
163
  
  		/* Ensure that the DWC_ahsata is in idle state */
3e59c30fc   Simon Glass   dm: sata: dw_sata...
164
  		tmp = readl(&port_mmio->cmd);
9f472e654   Stefano Babic   SATA: add driver ...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
  
  		/*
  		 * When P#CMD.ST, P#CMD.CR, P#CMD.FRE and P#CMD.FR
  		 * are all cleared, the Port is in an idle state.
  		 */
  		if (tmp & (SATA_PORT_CMD_CR | SATA_PORT_CMD_FR |
  			SATA_PORT_CMD_FRE | SATA_PORT_CMD_ST)) {
  
  			/*
  			 * System software places a Port into the idle state by
  			 * clearing P#CMD.ST and waiting for P#CMD.CR to return
  			 * 0 when read.
  			 */
  			tmp &= ~SATA_PORT_CMD_ST;
3e59c30fc   Simon Glass   dm: sata: dw_sata...
179
  			writel_with_flush(tmp, &port_mmio->cmd);
9f472e654   Stefano Babic   SATA: add driver ...
180
181
182
183
184
185
186
187
  
  			/*
  			 * spec says 500 msecs for each bit, so
  			 * this is slightly incorrect.
  			 */
  			mdelay(500);
  
  			timeout = 1000;
3e59c30fc   Simon Glass   dm: sata: dw_sata...
188
  			while ((readl(&port_mmio->cmd) & SATA_PORT_CMD_CR)
9f472e654   Stefano Babic   SATA: add driver ...
189
190
191
192
193
194
195
196
197
198
199
  				&& --timeout)
  				;
  
  			if (timeout <= 0) {
  				debug("port reset failed (0x%x)
  ", tmp);
  				return -1;
  			}
  		}
  
  		/* Spin-up device */
3e59c30fc   Simon Glass   dm: sata: dw_sata...
200
201
  		tmp = readl(&port_mmio->cmd);
  		writel((tmp | SATA_PORT_CMD_SUD), &port_mmio->cmd);
9f472e654   Stefano Babic   SATA: add driver ...
202
203
204
  
  		/* Wait for spin-up to finish */
  		timeout = 1000;
3e59c30fc   Simon Glass   dm: sata: dw_sata...
205
  		while (!(readl(&port_mmio->cmd) | SATA_PORT_CMD_SUD)
9f472e654   Stefano Babic   SATA: add driver ...
206
207
208
209
210
211
212
213
214
215
  			&& --timeout)
  			;
  		if (timeout <= 0) {
  			debug("Spin-Up can't finish!
  ");
  			return -1;
  		}
  
  		for (j = 0; j < 100; ++j) {
  			mdelay(10);
3e59c30fc   Simon Glass   dm: sata: dw_sata...
216
  			tmp = readl(&port_mmio->ssts);
9f472e654   Stefano Babic   SATA: add driver ...
217
218
219
220
221
222
223
  			if (((tmp & SATA_PORT_SSTS_DET_MASK) == 0x3) ||
  				((tmp & SATA_PORT_SSTS_DET_MASK) == 0x1))
  				break;
  		}
  
  		/* Wait for COMINIT bit 26 (DIAG_X) in SERR */
  		timeout = 1000;
876f435b6   Ye Li   MLK-20240-2 sata:...
224
  		while (!(readl(&port_mmio->serr) & SATA_PORT_SERR_DIAG_X)
9f472e654   Stefano Babic   SATA: add driver ...
225
226
227
228
229
230
231
232
233
234
235
236
237
  			&& --timeout)
  			;
  		if (timeout <= 0) {
  			debug("Can't find DIAG_X set!
  ");
  			return -1;
  		}
  
  		/*
  		 * For each implemented Port, clear the P#SERR
  		 * register, by writing ones to each implemented\
  		 * bit location.
  		 */
3e59c30fc   Simon Glass   dm: sata: dw_sata...
238
  		tmp = readl(&port_mmio->serr);
9f472e654   Stefano Babic   SATA: add driver ...
239
240
241
  		debug("P#SERR 0x%x
  ",
  				tmp);
3e59c30fc   Simon Glass   dm: sata: dw_sata...
242
  		writel(tmp, &port_mmio->serr);
9f472e654   Stefano Babic   SATA: add driver ...
243
244
  
  		/* Ack any pending irq events for this port */
3e59c30fc   Simon Glass   dm: sata: dw_sata...
245
  		tmp = readl(&host_mmio->is);
9f472e654   Stefano Babic   SATA: add driver ...
246
247
248
  		debug("IS 0x%x
  ", tmp);
  		if (tmp)
3e59c30fc   Simon Glass   dm: sata: dw_sata...
249
  			writel(tmp, &host_mmio->is);
9f472e654   Stefano Babic   SATA: add driver ...
250

3e59c30fc   Simon Glass   dm: sata: dw_sata...
251
  		writel(1 << i, &host_mmio->is);
9f472e654   Stefano Babic   SATA: add driver ...
252
253
  
  		/* set irq mask (enables interrupts) */
3e59c30fc   Simon Glass   dm: sata: dw_sata...
254
  		writel(DEF_PORT_IRQ, &port_mmio->ie);
9f472e654   Stefano Babic   SATA: add driver ...
255
256
  
  		/* register linkup ports */
3e59c30fc   Simon Glass   dm: sata: dw_sata...
257
  		tmp = readl(&port_mmio->ssts);
9f472e654   Stefano Babic   SATA: add driver ...
258
259
260
  		debug("Port %d status: 0x%x
  ", i, tmp);
  		if ((tmp & SATA_PORT_SSTS_DET_MASK) == 0x03)
09bb951bf   Simon Glass   dm: sata: dw_sata...
261
  			uc_priv->link_port_map |= (0x01 << i);
9f472e654   Stefano Babic   SATA: add driver ...
262
  	}
3e59c30fc   Simon Glass   dm: sata: dw_sata...
263
  	tmp = readl(&host_mmio->ghc);
9f472e654   Stefano Babic   SATA: add driver ...
264
265
  	debug("GHC 0x%x
  ", tmp);
3e59c30fc   Simon Glass   dm: sata: dw_sata...
266
267
  	writel(tmp | SATA_HOST_GHC_IE, &host_mmio->ghc);
  	tmp = readl(&host_mmio->ghc);
9f472e654   Stefano Babic   SATA: add driver ...
268
269
270
271
272
  	debug("GHC 0x%x
  ", tmp);
  
  	return 0;
  }
09bb951bf   Simon Glass   dm: sata: dw_sata...
273
  static void ahci_print_info(struct ahci_uc_priv *uc_priv)
9f472e654   Stefano Babic   SATA: add driver ...
274
  {
4b640dbca   Simon Glass   dm: sata: dw_sata...
275
  	struct sata_host_regs *host_mmio = uc_priv->mmio_base;
9f472e654   Stefano Babic   SATA: add driver ...
276
277
278
  	u32 vers, cap, impl, speed;
  	const char *speed_s;
  	const char *scc_s;
3e59c30fc   Simon Glass   dm: sata: dw_sata...
279
  	vers = readl(&host_mmio->vs);
09bb951bf   Simon Glass   dm: sata: dw_sata...
280
281
  	cap = uc_priv->cap;
  	impl = uc_priv->port_map;
9f472e654   Stefano Babic   SATA: add driver ...
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
  
  	speed = (cap & SATA_HOST_CAP_ISS_MASK)
  		>> SATA_HOST_CAP_ISS_OFFSET;
  	if (speed == 1)
  		speed_s = "1.5";
  	else if (speed == 2)
  		speed_s = "3";
  	else
  		speed_s = "?";
  
  	scc_s = "SATA";
  
  	printf("AHCI %02x%02x.%02x%02x "
  		"%u slots %u ports %s Gbps 0x%x impl %s mode
  ",
  		(vers >> 24) & 0xff,
  		(vers >> 16) & 0xff,
  		(vers >> 8) & 0xff,
  		vers & 0xff,
  		((cap >> 8) & 0x1f) + 1,
  		(cap & 0x1f) + 1,
  		speed_s,
  		impl,
  		scc_s);
  
  	printf("flags: "
  		"%s%s%s%s%s%s"
  		"%s%s%s%s%s%s%s
  ",
  		cap & (1 << 31) ? "64bit " : "",
  		cap & (1 << 30) ? "ncq " : "",
  		cap & (1 << 28) ? "ilck " : "",
  		cap & (1 << 27) ? "stag " : "",
  		cap & (1 << 26) ? "pm " : "",
  		cap & (1 << 25) ? "led " : "",
  		cap & (1 << 24) ? "clo " : "",
  		cap & (1 << 19) ? "nz " : "",
  		cap & (1 << 18) ? "only " : "",
  		cap & (1 << 17) ? "pmp " : "",
  		cap & (1 << 15) ? "pio " : "",
  		cap & (1 << 14) ? "slum " : "",
  		cap & (1 << 13) ? "part " : "");
  }
09bb951bf   Simon Glass   dm: sata: dw_sata...
325
326
  static int ahci_fill_sg(struct ahci_uc_priv *uc_priv, u8 port,
  			unsigned char *buf, int buf_len)
9f472e654   Stefano Babic   SATA: add driver ...
327
  {
3e59c30fc   Simon Glass   dm: sata: dw_sata...
328
  	struct ahci_ioports *pp = &uc_priv->port[port];
9f472e654   Stefano Babic   SATA: add driver ...
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
  	struct ahci_sg *ahci_sg = pp->cmd_tbl_sg;
  	u32 sg_count, max_bytes;
  	int i;
  
  	max_bytes = MAX_DATA_BYTES_PER_SG;
  	sg_count = ((buf_len - 1) / max_bytes) + 1;
  	if (sg_count > AHCI_MAX_SG) {
  		printf("Error:Too much sg!
  ");
  		return -1;
  	}
  
  	for (i = 0; i < sg_count; i++) {
  		ahci_sg->addr =
  			cpu_to_le32((u32)buf + i * max_bytes);
  		ahci_sg->addr_hi = 0;
  		ahci_sg->flags_size = cpu_to_le32(0x3fffff &
  					(buf_len < max_bytes
  					? (buf_len - 1)
  					: (max_bytes - 1)));
  		ahci_sg++;
  		buf_len -= max_bytes;
  	}
  
  	return sg_count;
  }
  
  static void ahci_fill_cmd_slot(struct ahci_ioports *pp, u32 cmd_slot, u32 opts)
  {
  	struct ahci_cmd_hdr *cmd_hdr = (struct ahci_cmd_hdr *)(pp->cmd_slot +
  					AHCI_CMD_SLOT_SZ * cmd_slot);
  
  	memset(cmd_hdr, 0, AHCI_CMD_SLOT_SZ);
  	cmd_hdr->opts = cpu_to_le32(opts);
  	cmd_hdr->status = 0;
fa31377ef   Tang Yuantian   ahci: Fix compili...
364
365
366
367
368
  	pp->cmd_slot->tbl_addr = cpu_to_le32((u32)pp->cmd_tbl & 0xffffffff);
  #ifdef CONFIG_PHYS_64BIT
  	pp->cmd_slot->tbl_addr_hi =
  	    cpu_to_le32((u32)(((pp->cmd_tbl) >> 16) >> 16));
  #endif
9f472e654   Stefano Babic   SATA: add driver ...
369
370
371
  }
  
  #define AHCI_GET_CMD_SLOT(c) ((c) ? ffs(c) : 0)
09bb951bf   Simon Glass   dm: sata: dw_sata...
372
373
374
  static int ahci_exec_ata_cmd(struct ahci_uc_priv *uc_priv, u8 port,
  			     struct sata_fis_h2d *cfis, u8 *buf, u32 buf_len,
  			     s32 is_write)
9f472e654   Stefano Babic   SATA: add driver ...
375
  {
3e59c30fc   Simon Glass   dm: sata: dw_sata...
376
  	struct ahci_ioports *pp = &uc_priv->port[port];
4b640dbca   Simon Glass   dm: sata: dw_sata...
377
  	struct sata_port_regs *port_mmio = pp->port_mmio;
9f472e654   Stefano Babic   SATA: add driver ...
378
379
  	u32 opts;
  	int sg_count = 0, cmd_slot = 0;
3e59c30fc   Simon Glass   dm: sata: dw_sata...
380
  	cmd_slot = AHCI_GET_CMD_SLOT(readl(&port_mmio->ci));
9f472e654   Stefano Babic   SATA: add driver ...
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
  	if (32 == cmd_slot) {
  		printf("Can't find empty command slot!
  ");
  		return 0;
  	}
  
  	/* Check xfer length */
  	if (buf_len > MAX_BYTES_PER_TRANS) {
  		printf("Max transfer length is %dB
  \r",
  			MAX_BYTES_PER_TRANS);
  		return 0;
  	}
  
  	memcpy((u8 *)(pp->cmd_tbl), cfis, sizeof(struct sata_fis_h2d));
  	if (buf && buf_len)
09bb951bf   Simon Glass   dm: sata: dw_sata...
397
  		sg_count = ahci_fill_sg(uc_priv, port, buf, buf_len);
9f472e654   Stefano Babic   SATA: add driver ...
398
  	opts = (sizeof(struct sata_fis_h2d) >> 2) | (sg_count << 16);
2dbe64ca2   Eric Nelson   dwc_ahsata: Allow...
399
  	if (is_write) {
9f472e654   Stefano Babic   SATA: add driver ...
400
  		opts |= 0x40;
2dbe64ca2   Eric Nelson   dwc_ahsata: Allow...
401
402
  		flush_cache((ulong)buf, buf_len);
  	}
9f472e654   Stefano Babic   SATA: add driver ...
403
  	ahci_fill_cmd_slot(pp, cmd_slot, opts);
2dbe64ca2   Eric Nelson   dwc_ahsata: Allow...
404
  	flush_cache((int)(pp->cmd_slot), AHCI_PORT_PRIV_DMA_SZ);
3e59c30fc   Simon Glass   dm: sata: dw_sata...
405
  	writel_with_flush(1 << cmd_slot, &port_mmio->ci);
9f472e654   Stefano Babic   SATA: add driver ...
406

3e59c30fc   Simon Glass   dm: sata: dw_sata...
407
408
  	if (waiting_for_cmd_completed((u8 *)&port_mmio->ci, 10000,
  				      0x1 << cmd_slot)) {
9f472e654   Stefano Babic   SATA: add driver ...
409
410
411
412
  		printf("timeout exit!
  ");
  		return -1;
  	}
2dbe64ca2   Eric Nelson   dwc_ahsata: Allow...
413
414
  	invalidate_dcache_range((int)(pp->cmd_slot),
  				(int)(pp->cmd_slot)+AHCI_PORT_PRIV_DMA_SZ);
9f472e654   Stefano Babic   SATA: add driver ...
415
416
417
  	debug("ahci_exec_ata_cmd: %d byte transferred.
  ",
  	      pp->cmd_slot->status);
2dbe64ca2   Eric Nelson   dwc_ahsata: Allow...
418
419
  	if (!is_write)
  		invalidate_dcache_range((ulong)buf, (ulong)buf+buf_len);
9f472e654   Stefano Babic   SATA: add driver ...
420
421
422
  
  	return buf_len;
  }
47c0f3692   Simon Glass   dm: sata: dw_sata...
423
  static void ahci_set_feature(struct ahci_uc_priv *uc_priv, u8 port)
9f472e654   Stefano Babic   SATA: add driver ...
424
  {
2dbe64ca2   Eric Nelson   dwc_ahsata: Allow...
425
426
  	struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN);
  	struct sata_fis_h2d *cfis = &h2d;
9f472e654   Stefano Babic   SATA: add driver ...
427
428
429
430
431
432
  
  	memset(cfis, 0, sizeof(struct sata_fis_h2d));
  	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
  	cfis->pm_port_c = 1 << 7;
  	cfis->command = ATA_CMD_SET_FEATURES;
  	cfis->features = SETFEATURES_XFER;
09bb951bf   Simon Glass   dm: sata: dw_sata...
433
  	cfis->sector_count = ffs(uc_priv->udma_mask + 1) + 0x3e;
9f472e654   Stefano Babic   SATA: add driver ...
434

09bb951bf   Simon Glass   dm: sata: dw_sata...
435
  	ahci_exec_ata_cmd(uc_priv, port, cfis, NULL, 0, READ_CMD);
9f472e654   Stefano Babic   SATA: add driver ...
436
  }
09bb951bf   Simon Glass   dm: sata: dw_sata...
437
  static int ahci_port_start(struct ahci_uc_priv *uc_priv, u8 port)
9f472e654   Stefano Babic   SATA: add driver ...
438
  {
3e59c30fc   Simon Glass   dm: sata: dw_sata...
439
  	struct ahci_ioports *pp = &uc_priv->port[port];
4b640dbca   Simon Glass   dm: sata: dw_sata...
440
  	struct sata_port_regs *port_mmio = pp->port_mmio;
9f472e654   Stefano Babic   SATA: add driver ...
441
442
443
444
445
446
  	u32 port_status;
  	u32 mem;
  	int timeout = 10000000;
  
  	debug("Enter start port: %d
  ", port);
3e59c30fc   Simon Glass   dm: sata: dw_sata...
447
  	port_status = readl(&port_mmio->ssts);
9f472e654   Stefano Babic   SATA: add driver ...
448
449
450
451
452
453
454
455
456
457
  	debug("Port %d status: %x
  ", port, port_status);
  	if ((port_status & 0xf) != 0x03) {
  		printf("No Link on this port!
  ");
  		return -1;
  	}
  
  	mem = (u32)malloc(AHCI_PORT_PRIV_DMA_SZ + 1024);
  	if (!mem) {
9f472e654   Stefano Babic   SATA: add driver ...
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
  		printf("No mem for table!
  ");
  		return -ENOMEM;
  	}
  
  	mem = (mem + 0x400) & (~0x3ff);	/* Aligned to 1024-bytes */
  	memset((u8 *)mem, 0, AHCI_PORT_PRIV_DMA_SZ);
  
  	/*
  	 * First item in chunk of DMA memory: 32-slot command table,
  	 * 32 bytes each in size
  	 */
  	pp->cmd_slot = (struct ahci_cmd_hdr *)mem;
  	debug("cmd_slot = 0x%x
  ", (unsigned int) pp->cmd_slot);
  	mem += (AHCI_CMD_SLOT_SZ * DWC_AHSATA_MAX_CMD_SLOTS);
  
  	/*
  	 * Second item: Received-FIS area, 256-Byte aligned
  	 */
  	pp->rx_fis = mem;
  	mem += AHCI_RX_FIS_SZ;
  
  	/*
  	 * Third item: data area for storing a single command
  	 * and its scatter-gather table
  	 */
  	pp->cmd_tbl = mem;
fa31377ef   Tang Yuantian   ahci: Fix compili...
486
487
  	debug("cmd_tbl_dma = 0x%lx
  ", pp->cmd_tbl);
9f472e654   Stefano Babic   SATA: add driver ...
488
489
  
  	mem += AHCI_CMD_TBL_HDR;
3e59c30fc   Simon Glass   dm: sata: dw_sata...
490
  	writel_with_flush(0x00004444, &port_mmio->dmacr);
9f472e654   Stefano Babic   SATA: add driver ...
491
  	pp->cmd_tbl_sg = (struct ahci_sg *)mem;
3e59c30fc   Simon Glass   dm: sata: dw_sata...
492
493
  	writel_with_flush((u32)pp->cmd_slot, &port_mmio->clb);
  	writel_with_flush(pp->rx_fis, &port_mmio->fb);
9f472e654   Stefano Babic   SATA: add driver ...
494
495
  
  	/* Enable FRE */
3e59c30fc   Simon Glass   dm: sata: dw_sata...
496
497
  	writel_with_flush((SATA_PORT_CMD_FRE | readl(&port_mmio->cmd)),
  			  &port_mmio->cmd);
9f472e654   Stefano Babic   SATA: add driver ...
498
499
  
  	/* Wait device ready */
3e59c30fc   Simon Glass   dm: sata: dw_sata...
500
  	while ((readl(&port_mmio->tfd) & (SATA_PORT_TFD_STS_ERR |
9f472e654   Stefano Babic   SATA: add driver ...
501
502
503
504
505
506
507
508
509
510
511
512
  		SATA_PORT_TFD_STS_DRQ | SATA_PORT_TFD_STS_BSY))
  		&& --timeout)
  		;
  	if (timeout <= 0) {
  		debug("Device not ready for BSY, DRQ and"
  			"ERR in TFD!
  ");
  		return -1;
  	}
  
  	writel_with_flush(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX |
  			  PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP |
3e59c30fc   Simon Glass   dm: sata: dw_sata...
513
  			  PORT_CMD_START, &port_mmio->cmd);
9f472e654   Stefano Babic   SATA: add driver ...
514
515
516
517
518
519
  
  	debug("Exit start port %d
  ", port);
  
  	return 0;
  }
47c0f3692   Simon Glass   dm: sata: dw_sata...
520
  static void dwc_ahsata_print_info(struct blk_desc *pdev)
9f472e654   Stefano Babic   SATA: add driver ...
521
  {
9f472e654   Stefano Babic   SATA: add driver ...
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
  	printf("SATA Device Info:
  \r");
  #ifdef CONFIG_SYS_64BIT_LBA
  	printf("S/N: %s
  \rProduct model number: %s
  \r"
  		"Firmware version: %s
  \rCapacity: %lld sectors
  \r",
  		pdev->product, pdev->vendor, pdev->revision, pdev->lba);
  #else
  	printf("S/N: %s
  \rProduct model number: %s
  \r"
  		"Firmware version: %s
  \rCapacity: %ld sectors
  \r",
  		pdev->product, pdev->vendor, pdev->revision, pdev->lba);
  #endif
  }
47c0f3692   Simon Glass   dm: sata: dw_sata...
542
  static void dwc_ahsata_identify(struct ahci_uc_priv *uc_priv, u16 *id)
9f472e654   Stefano Babic   SATA: add driver ...
543
  {
2dbe64ca2   Eric Nelson   dwc_ahsata: Allow...
544
545
  	struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN);
  	struct sata_fis_h2d *cfis = &h2d;
09bb951bf   Simon Glass   dm: sata: dw_sata...
546
  	u8 port = uc_priv->hard_port_no;
9f472e654   Stefano Babic   SATA: add driver ...
547
548
549
550
551
552
  
  	memset(cfis, 0, sizeof(struct sata_fis_h2d));
  
  	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
  	cfis->pm_port_c = 0x80; /* is command */
  	cfis->command = ATA_CMD_ID_ATA;
09bb951bf   Simon Glass   dm: sata: dw_sata...
553
554
  	ahci_exec_ata_cmd(uc_priv, port, cfis, (u8 *)id, ATA_ID_WORDS * 2,
  			  READ_CMD);
9f472e654   Stefano Babic   SATA: add driver ...
555
556
  	ata_swap_buf_le16(id, ATA_ID_WORDS);
  }
47c0f3692   Simon Glass   dm: sata: dw_sata...
557
  static void dwc_ahsata_xfer_mode(struct ahci_uc_priv *uc_priv, u16 *id)
9f472e654   Stefano Babic   SATA: add driver ...
558
  {
09bb951bf   Simon Glass   dm: sata: dw_sata...
559
560
561
562
  	uc_priv->pio_mask = id[ATA_ID_PIO_MODES];
  	uc_priv->udma_mask = id[ATA_ID_UDMA_MODES];
  	debug("pio %04x, udma %04x
  \r", uc_priv->pio_mask, uc_priv->udma_mask);
9f472e654   Stefano Babic   SATA: add driver ...
563
  }
47c0f3692   Simon Glass   dm: sata: dw_sata...
564
565
  static u32 dwc_ahsata_rw_cmd(struct ahci_uc_priv *uc_priv, u32 start,
  			     u32 blkcnt, u8 *buffer, int is_write)
9f472e654   Stefano Babic   SATA: add driver ...
566
  {
2dbe64ca2   Eric Nelson   dwc_ahsata: Allow...
567
568
  	struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN);
  	struct sata_fis_h2d *cfis = &h2d;
09bb951bf   Simon Glass   dm: sata: dw_sata...
569
  	u8 port = uc_priv->hard_port_no;
9f472e654   Stefano Babic   SATA: add driver ...
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
  	u32 block;
  
  	block = start;
  
  	memset(cfis, 0, sizeof(struct sata_fis_h2d));
  
  	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
  	cfis->pm_port_c = 0x80; /* is command */
  	cfis->command = (is_write) ? ATA_CMD_WRITE : ATA_CMD_READ;
  	cfis->device = ATA_LBA;
  
  	cfis->device |= (block >> 24) & 0xf;
  	cfis->lba_high = (block >> 16) & 0xff;
  	cfis->lba_mid = (block >> 8) & 0xff;
  	cfis->lba_low = block & 0xff;
  	cfis->sector_count = (u8)(blkcnt & 0xff);
09bb951bf   Simon Glass   dm: sata: dw_sata...
586
587
  	if (ahci_exec_ata_cmd(uc_priv, port, cfis, buffer,
  			      ATA_SECT_SIZE * blkcnt, is_write) > 0)
9f472e654   Stefano Babic   SATA: add driver ...
588
589
590
591
  		return blkcnt;
  	else
  		return 0;
  }
47c0f3692   Simon Glass   dm: sata: dw_sata...
592
  static void dwc_ahsata_flush_cache(struct ahci_uc_priv *uc_priv)
9f472e654   Stefano Babic   SATA: add driver ...
593
  {
2dbe64ca2   Eric Nelson   dwc_ahsata: Allow...
594
595
  	struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN);
  	struct sata_fis_h2d *cfis = &h2d;
09bb951bf   Simon Glass   dm: sata: dw_sata...
596
  	u8 port = uc_priv->hard_port_no;
9f472e654   Stefano Babic   SATA: add driver ...
597
598
599
600
601
602
  
  	memset(cfis, 0, sizeof(struct sata_fis_h2d));
  
  	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
  	cfis->pm_port_c = 0x80; /* is command */
  	cfis->command = ATA_CMD_FLUSH;
09bb951bf   Simon Glass   dm: sata: dw_sata...
603
  	ahci_exec_ata_cmd(uc_priv, port, cfis, NULL, 0, 0);
9f472e654   Stefano Babic   SATA: add driver ...
604
  }
47c0f3692   Simon Glass   dm: sata: dw_sata...
605
606
  static u32 dwc_ahsata_rw_cmd_ext(struct ahci_uc_priv *uc_priv, u32 start,
  				 lbaint_t blkcnt, u8 *buffer, int is_write)
9f472e654   Stefano Babic   SATA: add driver ...
607
  {
2dbe64ca2   Eric Nelson   dwc_ahsata: Allow...
608
609
  	struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN);
  	struct sata_fis_h2d *cfis = &h2d;
09bb951bf   Simon Glass   dm: sata: dw_sata...
610
  	u8 port = uc_priv->hard_port_no;
9f472e654   Stefano Babic   SATA: add driver ...
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
  	u64 block;
  
  	block = (u64)start;
  
  	memset(cfis, 0, sizeof(struct sata_fis_h2d));
  
  	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
  	cfis->pm_port_c = 0x80; /* is command */
  
  	cfis->command = (is_write) ? ATA_CMD_WRITE_EXT
  				 : ATA_CMD_READ_EXT;
  
  	cfis->lba_high_exp = (block >> 40) & 0xff;
  	cfis->lba_mid_exp = (block >> 32) & 0xff;
  	cfis->lba_low_exp = (block >> 24) & 0xff;
  	cfis->lba_high = (block >> 16) & 0xff;
  	cfis->lba_mid = (block >> 8) & 0xff;
  	cfis->lba_low = block & 0xff;
  	cfis->device = ATA_LBA;
  	cfis->sector_count_exp = (blkcnt >> 8) & 0xff;
  	cfis->sector_count = blkcnt & 0xff;
09bb951bf   Simon Glass   dm: sata: dw_sata...
632
633
  	if (ahci_exec_ata_cmd(uc_priv, port, cfis, buffer,
  			      ATA_SECT_SIZE * blkcnt, is_write) > 0)
9f472e654   Stefano Babic   SATA: add driver ...
634
635
636
637
  		return blkcnt;
  	else
  		return 0;
  }
47c0f3692   Simon Glass   dm: sata: dw_sata...
638
  static void dwc_ahsata_flush_cache_ext(struct ahci_uc_priv *uc_priv)
9f472e654   Stefano Babic   SATA: add driver ...
639
  {
2dbe64ca2   Eric Nelson   dwc_ahsata: Allow...
640
641
  	struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN);
  	struct sata_fis_h2d *cfis = &h2d;
09bb951bf   Simon Glass   dm: sata: dw_sata...
642
  	u8 port = uc_priv->hard_port_no;
9f472e654   Stefano Babic   SATA: add driver ...
643
644
645
646
647
648
  
  	memset(cfis, 0, sizeof(struct sata_fis_h2d));
  
  	cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D;
  	cfis->pm_port_c = 0x80; /* is command */
  	cfis->command = ATA_CMD_FLUSH_EXT;
09bb951bf   Simon Glass   dm: sata: dw_sata...
649
  	ahci_exec_ata_cmd(uc_priv, port, cfis, NULL, 0, 0);
9f472e654   Stefano Babic   SATA: add driver ...
650
  }
47c0f3692   Simon Glass   dm: sata: dw_sata...
651
  static void dwc_ahsata_init_wcache(struct ahci_uc_priv *uc_priv, u16 *id)
9f472e654   Stefano Babic   SATA: add driver ...
652
  {
9f472e654   Stefano Babic   SATA: add driver ...
653
  	if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id))
09bb951bf   Simon Glass   dm: sata: dw_sata...
654
  		uc_priv->flags |= SATA_FLAG_WCACHE;
9f472e654   Stefano Babic   SATA: add driver ...
655
  	if (ata_id_has_flush(id))
09bb951bf   Simon Glass   dm: sata: dw_sata...
656
  		uc_priv->flags |= SATA_FLAG_FLUSH;
9f472e654   Stefano Babic   SATA: add driver ...
657
  	if (ata_id_has_flush_ext(id))
09bb951bf   Simon Glass   dm: sata: dw_sata...
658
  		uc_priv->flags |= SATA_FLAG_FLUSH_EXT;
9f472e654   Stefano Babic   SATA: add driver ...
659
  }
47c0f3692   Simon Glass   dm: sata: dw_sata...
660
661
662
  static u32 ata_low_level_rw_lba48(struct ahci_uc_priv *uc_priv, u32 blknr,
  				  lbaint_t blkcnt, const void *buffer,
  				  int is_write)
9f472e654   Stefano Babic   SATA: add driver ...
663
664
665
666
667
668
669
670
671
672
673
674
675
  {
  	u32 start, blks;
  	u8 *addr;
  	int max_blks;
  
  	start = blknr;
  	blks = blkcnt;
  	addr = (u8 *)buffer;
  
  	max_blks = ATA_MAX_SECTORS_LBA48;
  
  	do {
  		if (blks > max_blks) {
47c0f3692   Simon Glass   dm: sata: dw_sata...
676
677
678
  			if (max_blks != dwc_ahsata_rw_cmd_ext(uc_priv, start,
  							      max_blks, addr,
  							      is_write))
9f472e654   Stefano Babic   SATA: add driver ...
679
680
681
682
683
  				return 0;
  			start += max_blks;
  			blks -= max_blks;
  			addr += ATA_SECT_SIZE * max_blks;
  		} else {
47c0f3692   Simon Glass   dm: sata: dw_sata...
684
685
  			if (blks != dwc_ahsata_rw_cmd_ext(uc_priv, start, blks,
  							  addr, is_write))
9f472e654   Stefano Babic   SATA: add driver ...
686
687
688
689
690
691
692
693
694
  				return 0;
  			start += blks;
  			blks = 0;
  			addr += ATA_SECT_SIZE * blks;
  		}
  	} while (blks != 0);
  
  	return blkcnt;
  }
47c0f3692   Simon Glass   dm: sata: dw_sata...
695
696
697
  static u32 ata_low_level_rw_lba28(struct ahci_uc_priv *uc_priv, u32 blknr,
  				  lbaint_t blkcnt, const void *buffer,
  				  int is_write)
9f472e654   Stefano Babic   SATA: add driver ...
698
699
700
701
702
703
704
705
706
707
708
709
  {
  	u32 start, blks;
  	u8 *addr;
  	int max_blks;
  
  	start = blknr;
  	blks = blkcnt;
  	addr = (u8 *)buffer;
  
  	max_blks = ATA_MAX_SECTORS;
  	do {
  		if (blks > max_blks) {
47c0f3692   Simon Glass   dm: sata: dw_sata...
710
711
712
  			if (max_blks != dwc_ahsata_rw_cmd(uc_priv, start,
  							  max_blks, addr,
  							  is_write))
9f472e654   Stefano Babic   SATA: add driver ...
713
714
715
716
717
  				return 0;
  			start += max_blks;
  			blks -= max_blks;
  			addr += ATA_SECT_SIZE * max_blks;
  		} else {
47c0f3692   Simon Glass   dm: sata: dw_sata...
718
719
  			if (blks != dwc_ahsata_rw_cmd(uc_priv, start, blks,
  						      addr, is_write))
9f472e654   Stefano Babic   SATA: add driver ...
720
721
722
723
724
725
726
727
728
  				return 0;
  			start += blks;
  			blks = 0;
  			addr += ATA_SECT_SIZE * blks;
  		}
  	} while (blks != 0);
  
  	return blkcnt;
  }
752126a05   Simon Glass   dm: sata: dw_sata...
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
  static int dwc_ahci_start_ports(struct ahci_uc_priv *uc_priv)
  {
  	u32 linkmap;
  	int i;
  
  	linkmap = uc_priv->link_port_map;
  
  	if (0 == linkmap) {
  		printf("No port device detected!
  ");
  		return -ENXIO;
  	}
  
  	for (i = 0; i < uc_priv->n_ports; i++) {
  		if ((linkmap >> i) && ((linkmap >> i) & 0x01)) {
  			if (ahci_port_start(uc_priv, (u8)i)) {
  				printf("Can not start port %d
  ", i);
  				return 1;
  			}
  			uc_priv->hard_port_no = i;
  			break;
  		}
  	}
  
  	return 0;
  }
  
  static int dwc_ahsata_scan_common(struct ahci_uc_priv *uc_priv,
  				  struct blk_desc *pdev)
  {
  	u8 serial[ATA_ID_SERNO_LEN + 1] = { 0 };
  	u8 firmware[ATA_ID_FW_REV_LEN + 1] = { 0 };
  	u8 product[ATA_ID_PROD_LEN + 1] = { 0 };
  	u64 n_sectors;
  	u8 port = uc_priv->hard_port_no;
  	ALLOC_CACHE_ALIGN_BUFFER(u16, id, ATA_ID_WORDS);
  
  	/* Identify device to get information */
  	dwc_ahsata_identify(uc_priv, id);
  
  	/* Serial number */
  	ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial));
  	memcpy(pdev->product, serial, sizeof(serial));
  
  	/* Firmware version */
  	ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware));
  	memcpy(pdev->revision, firmware, sizeof(firmware));
  
  	/* Product model */
  	ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product));
  	memcpy(pdev->vendor, product, sizeof(product));
  
  	/* Totoal sectors */
  	n_sectors = ata_id_n_sectors(id);
  	pdev->lba = (u32)n_sectors;
  
  	pdev->type = DEV_TYPE_HARDDISK;
  	pdev->blksz = ATA_SECT_SIZE;
  	pdev->lun = 0;
  
  	/* Check if support LBA48 */
  	if (ata_id_has_lba48(id)) {
  		pdev->lba48 = 1;
  		debug("Device support LBA48
  \r");
  	}
  
  	/* Get the NCQ queue depth from device */
  	uc_priv->flags &= (~SATA_FLAG_Q_DEP_MASK);
  	uc_priv->flags |= ata_id_queue_depth(id);
  
  	/* Get the xfer mode from device */
  	dwc_ahsata_xfer_mode(uc_priv, id);
  
  	/* Get the write cache status from device */
  	dwc_ahsata_init_wcache(uc_priv, id);
  
  	/* Set the xfer mode to highest speed */
  	ahci_set_feature(uc_priv, port);
  
  	dwc_ahsata_print_info(pdev);
  
  	return 0;
  }
  
  /*
   * SATA interface between low level driver and command layer
   */
  static ulong sata_read_common(struct ahci_uc_priv *uc_priv,
  			      struct blk_desc *desc, ulong blknr,
  			      lbaint_t blkcnt, void *buffer)
  {
  	u32 rc;
  
  	if (desc->lba48)
  		rc = ata_low_level_rw_lba48(uc_priv, blknr, blkcnt, buffer,
  					    READ_CMD);
  	else
  		rc = ata_low_level_rw_lba28(uc_priv, blknr, blkcnt, buffer,
  					    READ_CMD);
  
  	return rc;
  }
  
  static ulong sata_write_common(struct ahci_uc_priv *uc_priv,
  			       struct blk_desc *desc, ulong blknr,
  			       lbaint_t blkcnt, const void *buffer)
  {
  	u32 rc;
  	u32 flags = uc_priv->flags;
  
  	if (desc->lba48) {
  		rc = ata_low_level_rw_lba48(uc_priv, blknr, blkcnt, buffer,
  					    WRITE_CMD);
  		if ((flags & SATA_FLAG_WCACHE) && (flags & SATA_FLAG_FLUSH_EXT))
  			dwc_ahsata_flush_cache_ext(uc_priv);
  	} else {
  		rc = ata_low_level_rw_lba28(uc_priv, blknr, blkcnt, buffer,
  					    WRITE_CMD);
  		if ((flags & SATA_FLAG_WCACHE) && (flags & SATA_FLAG_FLUSH))
  			dwc_ahsata_flush_cache(uc_priv);
  	}
  
  	return rc;
  }
c893f1e6e   Simon Glass   dm: sata: dwc_ahs...
855
  #if !CONFIG_IS_ENABLED(AHCI)
036a803e1   Simon Glass   dm: sata: dw_sata...
856
857
858
859
860
861
  static int ahci_init_one(int pdev)
  {
  	int rc;
  	struct ahci_uc_priv *uc_priv = NULL;
  
  	uc_priv = malloc(sizeof(struct ahci_uc_priv));
8f52ef83d   Ye Li   MLK-20240-1 sata:...
862
863
  	if (!uc_priv)
  		return -ENOMEM;
036a803e1   Simon Glass   dm: sata: dw_sata...
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
  	memset(uc_priv, 0, sizeof(struct ahci_uc_priv));
  	uc_priv->dev = pdev;
  
  	uc_priv->host_flags = ATA_FLAG_SATA
  				| ATA_FLAG_NO_LEGACY
  				| ATA_FLAG_MMIO
  				| ATA_FLAG_PIO_DMA
  				| ATA_FLAG_NO_ATAPI;
  
  	uc_priv->mmio_base = (void __iomem *)CONFIG_DWC_AHSATA_BASE_ADDR;
  
  	/* initialize adapter */
  	rc = ahci_host_init(uc_priv);
  	if (rc)
  		goto err_out;
  
  	ahci_print_info(uc_priv);
  
  	/* Save the uc_private struct to block device struct */
  	sata_dev_desc[pdev].priv = uc_priv;
  
  	return 0;
  
  err_out:
8f52ef83d   Ye Li   MLK-20240-1 sata:...
888
889
  	if (uc_priv)
  		free(uc_priv);
036a803e1   Simon Glass   dm: sata: dw_sata...
890
891
  	return rc;
  }
c5273acf5   Simon Glass   dm: sata: dw_sata...
892
893
  int init_sata(int dev)
  {
09bb951bf   Simon Glass   dm: sata: dw_sata...
894
  	struct ahci_uc_priv *uc_priv = NULL;
c5273acf5   Simon Glass   dm: sata: dw_sata...
895
896
897
898
899
900
901
902
903
904
905
906
  
  #if defined(CONFIG_MX6)
  	if (!is_mx6dq() && !is_mx6dqp())
  		return 1;
  #endif
  	if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) {
  		printf("The sata index %d is out of ranges
  \r", dev);
  		return -1;
  	}
  
  	ahci_init_one(dev);
4b640dbca   Simon Glass   dm: sata: dw_sata...
907
  	uc_priv = sata_dev_desc[dev].priv;
c5273acf5   Simon Glass   dm: sata: dw_sata...
908

752126a05   Simon Glass   dm: sata: dw_sata...
909
  	return dwc_ahci_start_ports(uc_priv) ? 1 : 0;
c5273acf5   Simon Glass   dm: sata: dw_sata...
910
911
912
913
  }
  
  int reset_sata(int dev)
  {
09bb951bf   Simon Glass   dm: sata: dw_sata...
914
  	struct ahci_uc_priv *uc_priv;
c5273acf5   Simon Glass   dm: sata: dw_sata...
915
916
917
918
919
920
921
  	struct sata_host_regs *host_mmio;
  
  	if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) {
  		printf("The sata index %d is out of ranges
  \r", dev);
  		return -1;
  	}
4b640dbca   Simon Glass   dm: sata: dw_sata...
922
  	uc_priv = sata_dev_desc[dev].priv;
09bb951bf   Simon Glass   dm: sata: dw_sata...
923
  	if (NULL == uc_priv)
c5273acf5   Simon Glass   dm: sata: dw_sata...
924
925
  		/* not initialized, so nothing to reset */
  		return 0;
4b640dbca   Simon Glass   dm: sata: dw_sata...
926
  	host_mmio = uc_priv->mmio_base;
c5273acf5   Simon Glass   dm: sata: dw_sata...
927
928
929
  	setbits_le32(&host_mmio->ghc, SATA_HOST_GHC_HR);
  	while (readl(&host_mmio->ghc) & SATA_HOST_GHC_HR)
  		udelay(100);
148488728   Ye Li   MLK-14930-2 dwc_a...
930
931
  	free(uc_priv);
  	memset(&sata_dev_desc[dev], 0, sizeof(struct blk_desc));
c5273acf5   Simon Glass   dm: sata: dw_sata...
932
933
  	return 0;
  }
dc383dd58   Nikita Kiryanov   sata: dwc_ahsata:...
934
935
936
  int sata_port_status(int dev, int port)
  {
  	struct sata_port_regs *port_mmio;
09bb951bf   Simon Glass   dm: sata: dw_sata...
937
  	struct ahci_uc_priv *uc_priv = NULL;
dc383dd58   Nikita Kiryanov   sata: dwc_ahsata:...
938
939
940
941
942
943
  
  	if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1))
  		return -EINVAL;
  
  	if (sata_dev_desc[dev].priv == NULL)
  		return -ENODEV;
4b640dbca   Simon Glass   dm: sata: dw_sata...
944
945
  	uc_priv = sata_dev_desc[dev].priv;
  	port_mmio = uc_priv->port[port].port_mmio;
dc383dd58   Nikita Kiryanov   sata: dwc_ahsata:...
946

3e59c30fc   Simon Glass   dm: sata: dw_sata...
947
  	return readl(&port_mmio->ssts) & SATA_PORT_SSTS_DET_MASK;
dc383dd58   Nikita Kiryanov   sata: dwc_ahsata:...
948
  }
9f472e654   Stefano Babic   SATA: add driver ...
949
950
951
  /*
   * SATA interface between low level driver and command layer
   */
dac875710   Tom Rini   dwc_ahsata: Make ...
952
  ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer)
9f472e654   Stefano Babic   SATA: add driver ...
953
  {
47c0f3692   Simon Glass   dm: sata: dw_sata...
954
  	struct ahci_uc_priv *uc_priv = sata_dev_desc[dev].priv;
9f472e654   Stefano Babic   SATA: add driver ...
955

752126a05   Simon Glass   dm: sata: dw_sata...
956
957
  	return sata_read_common(uc_priv, &sata_dev_desc[dev], blknr, blkcnt,
  				buffer);
9f472e654   Stefano Babic   SATA: add driver ...
958
  }
dac875710   Tom Rini   dwc_ahsata: Make ...
959
  ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer)
9f472e654   Stefano Babic   SATA: add driver ...
960
  {
4b640dbca   Simon Glass   dm: sata: dw_sata...
961
  	struct ahci_uc_priv *uc_priv = sata_dev_desc[dev].priv;
9f472e654   Stefano Babic   SATA: add driver ...
962

752126a05   Simon Glass   dm: sata: dw_sata...
963
964
  	return sata_write_common(uc_priv, &sata_dev_desc[dev], blknr, blkcnt,
  				 buffer);
9f472e654   Stefano Babic   SATA: add driver ...
965
966
967
968
  }
  
  int scan_sata(int dev)
  {
4b640dbca   Simon Glass   dm: sata: dw_sata...
969
  	struct ahci_uc_priv *uc_priv = sata_dev_desc[dev].priv;
3e59c30fc   Simon Glass   dm: sata: dw_sata...
970
  	struct blk_desc *pdev = &sata_dev_desc[dev];
9f472e654   Stefano Babic   SATA: add driver ...
971

752126a05   Simon Glass   dm: sata: dw_sata...
972
  	return dwc_ahsata_scan_common(uc_priv, pdev);
9f472e654   Stefano Babic   SATA: add driver ...
973
  }
c893f1e6e   Simon Glass   dm: sata: dwc_ahs...
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
  #endif /* CONFIG_IS_ENABLED(AHCI) */
  
  #if CONFIG_IS_ENABLED(AHCI)
  
  int dwc_ahsata_port_status(struct udevice *dev, int port)
  {
  	struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev);
  	struct sata_port_regs *port_mmio;
  
  	port_mmio = uc_priv->port[port].port_mmio;
  	return readl(&port_mmio->ssts) & SATA_PORT_SSTS_DET_MASK ? 0 : -ENXIO;
  }
  
  int dwc_ahsata_bus_reset(struct udevice *dev)
  {
  	struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev);
  	struct sata_host_regs *host_mmio = uc_priv->mmio_base;
  
  	setbits_le32(&host_mmio->ghc, SATA_HOST_GHC_HR);
  	while (readl(&host_mmio->ghc) & SATA_HOST_GHC_HR)
  		udelay(100);
  
  	return 0;
  }
  
  int dwc_ahsata_scan(struct udevice *dev)
  {
  	struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev);
  	struct blk_desc *desc;
  	struct udevice *blk;
  	int ret;
  
  	/*
  	* Create only one block device and do detection
  	* to make sure that there won't be a lot of
  	* block devices created
  	*/
  	device_find_first_child(dev, &blk);
  	if (!blk) {
  		ret = blk_create_devicef(dev, "dwc_ahsata_blk", "blk",
  					 IF_TYPE_SATA, -1, 512, 0, &blk);
  		if (ret) {
  			debug("Can't create device
  ");
  			return ret;
  		}
  	}
  
  	desc = dev_get_uclass_platdata(blk);
  	ret = dwc_ahsata_scan_common(uc_priv, desc);
  	if (ret) {
  		debug("%s: Failed to scan bus
  ", __func__);
  		return ret;
  	}
  
  	return 0;
  }
  
  int dwc_ahsata_probe(struct udevice *dev)
  {
  	struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev);
  	int ret;
  
  	uc_priv->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
  			ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_NO_ATAPI;
  	uc_priv->mmio_base = (void __iomem *)dev_read_addr(dev);
  
  	/* initialize adapter */
  	ret = ahci_host_init(uc_priv);
  	if (ret)
  		return ret;
  
  	ahci_print_info(uc_priv);
  
  	return dwc_ahci_start_ports(uc_priv);
  }
  
  static ulong dwc_ahsata_read(struct udevice *blk, lbaint_t blknr,
  			     lbaint_t blkcnt, void *buffer)
  {
  	struct blk_desc *desc = dev_get_uclass_platdata(blk);
  	struct udevice *dev = dev_get_parent(blk);
  	struct ahci_uc_priv *uc_priv;
  
  	uc_priv = dev_get_uclass_priv(dev);
  	return sata_read_common(uc_priv, desc, blknr, blkcnt, buffer);
  }
  
  static ulong dwc_ahsata_write(struct udevice *blk, lbaint_t blknr,
  			      lbaint_t blkcnt, const void *buffer)
  {
  	struct blk_desc *desc = dev_get_uclass_platdata(blk);
  	struct udevice *dev = dev_get_parent(blk);
  	struct ahci_uc_priv *uc_priv;
  
  	uc_priv = dev_get_uclass_priv(dev);
  	return sata_write_common(uc_priv, desc, blknr, blkcnt, buffer);
  }
  
  static const struct blk_ops dwc_ahsata_blk_ops = {
  	.read	= dwc_ahsata_read,
  	.write	= dwc_ahsata_write,
  };
  
  U_BOOT_DRIVER(dwc_ahsata_blk) = {
  	.name		= "dwc_ahsata_blk",
  	.id		= UCLASS_BLK,
  	.ops		= &dwc_ahsata_blk_ops,
  };
  
  #endif