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