Commit ffc664e80dfb2e17de0df5ad39e91a02e9c361bc
Committed by
Wolfgang Denk
1 parent
8e9bb43429
Exists in
master
and in
54 other branches
ata: add the libata support
add simple libata support in u-boot Signed-off-by: Dave Liu <daveliu@freescale.com>
Showing 3 changed files with 364 additions and 0 deletions Side-by-side Diff
drivers/block/Makefile
drivers/block/libata.c
1 | +/* | |
2 | + * Copyright (C) 2008 Freescale Semiconductor, Inc. | |
3 | + * Dave Liu <daveliu@freescale.com> | |
4 | + * port from the libata of linux kernel | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or | |
7 | + * modify it under the terms of the GNU General Public License as | |
8 | + * published by the Free Software Foundation; either version 2 of | |
9 | + * the License, or (at your option) any later version. | |
10 | + * | |
11 | + * This program is distributed in the hope that it will be useful, | |
12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | + * GNU General Public License for more details. | |
15 | + * | |
16 | + * You should have received a copy of the GNU General Public License | |
17 | + * along with this program; if not, write to the Free Software | |
18 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
19 | + * MA 02111-1307 USA | |
20 | + * | |
21 | + */ | |
22 | + | |
23 | +#include <libata.h> | |
24 | + | |
25 | +u64 ata_id_n_sectors(u16 *id) | |
26 | +{ | |
27 | + if (ata_id_has_lba(id)) { | |
28 | + if (ata_id_has_lba48(id)) | |
29 | + return ata_id_u64(id, ATA_ID_LBA48_SECTORS); | |
30 | + else | |
31 | + return ata_id_u32(id, ATA_ID_LBA_SECTORS); | |
32 | + } else { | |
33 | + return 0; | |
34 | + } | |
35 | +} | |
36 | + | |
37 | +u32 ata_dev_classify(u32 sig) | |
38 | +{ | |
39 | + u8 lbam, lbah; | |
40 | + | |
41 | + lbam = (sig >> 16) & 0xff; | |
42 | + lbah = (sig >> 24) & 0xff; | |
43 | + | |
44 | + if (((lbam == 0) && (lbah == 0)) || | |
45 | + ((lbam == 0x3c) && (lbah == 0xc3))) | |
46 | + return ATA_DEV_ATA; | |
47 | + | |
48 | + if ((lbam == 0x14) && (lbah == 0xeb)) | |
49 | + return ATA_DEV_ATAPI; | |
50 | + | |
51 | + if ((lbam == 0x69) && (lbah == 0x96)) | |
52 | + return ATA_DEV_PMP; | |
53 | + | |
54 | + return ATA_DEV_UNKNOWN; | |
55 | +} | |
56 | + | |
57 | +static void ata_id_string(const u16 *id, unsigned char *s, | |
58 | + unsigned int ofs, unsigned int len) | |
59 | +{ | |
60 | + unsigned int c; | |
61 | + | |
62 | + while (len > 0) { | |
63 | + c = id[ofs] >> 8; | |
64 | + *s = c; | |
65 | + s++; | |
66 | + | |
67 | + c = id[ofs] & 0xff; | |
68 | + *s = c; | |
69 | + s++; | |
70 | + | |
71 | + ofs++; | |
72 | + len -= 2; | |
73 | + } | |
74 | +} | |
75 | + | |
76 | +void ata_id_c_string(const u16 *id, unsigned char *s, | |
77 | + unsigned int ofs, unsigned int len) | |
78 | +{ | |
79 | + unsigned char *p; | |
80 | + | |
81 | + ata_id_string(id, s, ofs, len - 1); | |
82 | + | |
83 | + p = s + strnlen((char *)s, len - 1); | |
84 | + while (p > s && p[-1] == ' ') | |
85 | + p--; | |
86 | + *p = '\0'; | |
87 | +} | |
88 | + | |
89 | +void ata_dump_id(u16 *id) | |
90 | +{ | |
91 | + unsigned char serial[ATA_ID_SERNO_LEN + 1]; | |
92 | + unsigned char firmware[ATA_ID_FW_REV_LEN + 1]; | |
93 | + unsigned char product[ATA_ID_PROD_LEN + 1]; | |
94 | + u64 n_sectors; | |
95 | + | |
96 | + /* Serial number */ | |
97 | + ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); | |
98 | + printf("S/N: %s\n\r", serial); | |
99 | + | |
100 | + /* Firmware version */ | |
101 | + ata_id_c_string(id, firmware, ATA_ID_FW_REV, sizeof(firmware)); | |
102 | + printf("Firmware version: %s\n\r", firmware); | |
103 | + | |
104 | + /* Product model */ | |
105 | + ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); | |
106 | + printf("Product model number: %s\n\r", product); | |
107 | + | |
108 | + /* Total sectors of device */ | |
109 | + n_sectors = ata_id_n_sectors(id); | |
110 | + printf("Capablity: %d sectors\n\r", n_sectors); | |
111 | + | |
112 | + printf("id[49]: capabilities ==0x%04x\n" | |
113 | + "id[53]: field valid ==0x%04x\n" | |
114 | + "id[63]: mwdma ==0x%04x\n" | |
115 | + "id[64]: pio ==0x%04x\n" | |
116 | + "id[75]: queue depth ==0x%04x\n", | |
117 | + id[49], | |
118 | + id[53], | |
119 | + id[63], | |
120 | + id[64], | |
121 | + id[75]); | |
122 | + | |
123 | + printf("id[76]: sata capablity ==0x%04x\n" | |
124 | + "id[78]: sata features supported ==0x%04x\n" | |
125 | + "id[79]: sata features enable ==0x%04x\n", | |
126 | + id[76], | |
127 | + id[78], | |
128 | + id[79]); | |
129 | + | |
130 | + printf("id[80]: major version ==0x%04x\n" | |
131 | + "id[81]: minor version ==0x%04x\n" | |
132 | + "id[82]: command set supported 1 ==0x%04x\n" | |
133 | + "id[83]: command set supported 2 ==0x%04x\n" | |
134 | + "id[84]: command set extension ==0x%04x\n", | |
135 | + id[80], | |
136 | + id[81], | |
137 | + id[82], | |
138 | + id[83], | |
139 | + id[84]); | |
140 | + printf("id[85]: command set enable 1 ==0x%04x\n" | |
141 | + "id[86]: command set enable 2 ==0x%04x\n" | |
142 | + "id[87]: command set default ==0x%04x\n" | |
143 | + "id[88]: udma ==0x%04x\n" | |
144 | + "id[93]: hardware reset result ==0x%04x\n", | |
145 | + id[85], | |
146 | + id[86], | |
147 | + id[87], | |
148 | + id[88], | |
149 | + id[93]); | |
150 | +} | |
151 | + | |
152 | +void ata_swap_buf_le16(u16 *buf, unsigned int buf_words) | |
153 | +{ | |
154 | + unsigned int i; | |
155 | + | |
156 | + for (i = 0; i < buf_words; i++) | |
157 | + buf[i] = le16_to_cpu(buf[i]); | |
158 | +} |
include/libata.h
1 | +/* | |
2 | + * Copyright (C) 2008 Freescale Semiconductor, Inc. | |
3 | + * Dave Liu <daveliu@freescale.com> | |
4 | + * port from libata of linux kernel | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or | |
7 | + * modify it under the terms of the GNU General Public License as | |
8 | + * published by the Free Software Foundation; either version 2 of | |
9 | + * the License, or (at your option) any later version. | |
10 | + * | |
11 | + * This program is distributed in the hope that it will be useful, | |
12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | + * GNU General Public License for more details. | |
15 | + * | |
16 | + * You should have received a copy of the GNU General Public License | |
17 | + * along with this program; if not, write to the Free Software | |
18 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
19 | + * MA 02111-1307 USA | |
20 | + * | |
21 | + */ | |
22 | + | |
23 | +#ifndef __LIBATA_H__ | |
24 | +#define __LIBATA_H__ | |
25 | + | |
26 | +#include <common.h> | |
27 | + | |
28 | +/* command | |
29 | + */ | |
30 | +enum ata_cmd { | |
31 | + /* non-NCQ command */ | |
32 | + ATA_CMD_DEV_RESET = 0x08, /* ATAPI device reset */ | |
33 | + ATA_CMD_FLUSH_CACHE = 0xE7, | |
34 | + ATA_CMD_FLUSH_CACHE_EXT = 0xEA, | |
35 | + ATA_CMD_ID_ATA = 0xEC, | |
36 | + ATA_CMD_ID_ATAPI = 0xA1, | |
37 | + ATA_CMD_READ_DMA = 0xC8, | |
38 | + ATA_CMD_READ_DMA_EXT = 0x25, | |
39 | + ATA_CMD_WRITE_DMA = 0xCA, | |
40 | + ATA_CMD_WRITE_DMA_EXT = 0x35, | |
41 | + ATA_CMD_PIO_READ = 0x20, | |
42 | + ATA_CMD_PIO_READ_EXT = 0x24, | |
43 | + ATA_CMD_PIO_WRITE = 0x30, | |
44 | + ATA_CMD_PIO_WRITE_EXT = 0x34, | |
45 | + ATA_CMD_SET_FEATURES = 0xEF, | |
46 | + | |
47 | + /* NCQ command */ | |
48 | + ATA_CMD_READ_FPDMA_QUEUED = 0x60, | |
49 | + ATA_CMD_WRITE_FPDMA_QUEUED = 0x61, | |
50 | +}; | |
51 | + | |
52 | +/* SETFEATURES stuff | |
53 | + */ | |
54 | +enum ata_set_features { | |
55 | + /* SETFEATURES stuff */ | |
56 | + SETFEATURES_XFER = 0x03, | |
57 | + XFER_UDMA_7 = 0x47, | |
58 | + XFER_UDMA_6 = 0x46, | |
59 | + XFER_UDMA_5 = 0x45, | |
60 | + XFER_UDMA_4 = 0x44, | |
61 | + XFER_UDMA_3 = 0x43, | |
62 | + XFER_UDMA_2 = 0x42, | |
63 | + XFER_UDMA_1 = 0x41, | |
64 | + XFER_UDMA_0 = 0x40, | |
65 | + XFER_MW_DMA_4 = 0x24, /* CFA only */ | |
66 | + XFER_MW_DMA_3 = 0x23, /* CFA only */ | |
67 | + XFER_MW_DMA_2 = 0x22, | |
68 | + XFER_MW_DMA_1 = 0x21, | |
69 | + XFER_MW_DMA_0 = 0x20, | |
70 | + XFER_PIO_6 = 0x0E, /* CFA only */ | |
71 | + XFER_PIO_5 = 0x0D, /* CFA only */ | |
72 | + XFER_PIO_4 = 0x0C, | |
73 | + XFER_PIO_3 = 0x0B, | |
74 | + XFER_PIO_2 = 0x0A, | |
75 | + XFER_PIO_1 = 0x09, | |
76 | + XFER_PIO_0 = 0x08, | |
77 | + XFER_PIO_SLOW = 0x00, | |
78 | + | |
79 | + SETFEATURES_WC_ON = 0x02, /* Enable write cache */ | |
80 | + SETFEATURES_WC_OFF = 0x82, /* Disable write cache */ | |
81 | + | |
82 | + SETFEATURES_SPINUP = 0x07, /* Spin-up drive */ | |
83 | +}; | |
84 | + | |
85 | +enum ata_protocol { | |
86 | + ATA_PROT_UNKNOWN, /* unknown */ | |
87 | + ATA_PROT_NODATA, /* no data */ | |
88 | + ATA_PROT_PIO, /* PIO data xfer */ | |
89 | + ATA_PROT_DMA, /* DMA */ | |
90 | + ATA_PROT_NCQ, /* NCQ */ | |
91 | + ATA_PROT_ATAPI, /* packet command, PIO data xfer */ | |
92 | + ATA_PROT_ATAPI_NODATA, /* packet command, no data */ | |
93 | + ATA_PROT_ATAPI_DMA, /* packet command, DMA */ | |
94 | +}; | |
95 | + | |
96 | +enum ata_dev_typed { | |
97 | + ATA_DEV_ATA, /* ATA device */ | |
98 | + ATA_DEV_ATAPI, /* ATAPI device */ | |
99 | + ATA_DEV_PMP, /* Port Multiplier Port */ | |
100 | + ATA_DEV_UNKNOWN, /* unknown */ | |
101 | +}; | |
102 | + | |
103 | +enum { | |
104 | + ATA_SECT_SIZE = 512, | |
105 | + ATA_MAX_SECTORS_128 = 128, | |
106 | + ATA_MAX_SECTORS = 256, | |
107 | + ATA_MAX_SECTORS_LBA48 = 65535, | |
108 | + | |
109 | + /* bits in ATA command block registers */ | |
110 | + ATA_HOB = (1 << 7), /* LBA48 selector */ | |
111 | + ATA_NIEN = (1 << 1), /* disable-irq flag */ | |
112 | + ATA_LBA = (1 << 6), /* LBA28 selector */ | |
113 | + ATA_DEV1 = (1 << 4), /* Select Device 1 (slave) */ | |
114 | + ATA_BUSY = (1 << 7), /* BSY status bit */ | |
115 | + ATA_DRDY = (1 << 6), /* device ready */ | |
116 | + ATA_DF = (1 << 5), /* device fault */ | |
117 | + ATA_DRQ = (1 << 3), /* data request i/o */ | |
118 | + ATA_ERR = (1 << 0), /* have an error */ | |
119 | + ATA_SRST = (1 << 2), /* software reset */ | |
120 | + ATA_ICRC = (1 << 7), /* interface CRC error */ | |
121 | + ATA_UNC = (1 << 6), /* uncorrectable media error */ | |
122 | + ATA_IDNF = (1 << 4), /* ID not found */ | |
123 | + ATA_ABORTED = (1 << 2), /* command aborted */ | |
124 | + | |
125 | + ATA_ID_WORDS = 256, | |
126 | + ATA_ID_SERNO = 10, | |
127 | + ATA_ID_FW_REV = 23, | |
128 | + ATA_ID_PROD = 27, | |
129 | + ATA_ID_FIELD_VALID = 53, | |
130 | + ATA_ID_LBA_SECTORS = 60, | |
131 | + ATA_ID_MWDMA_MODES = 63, | |
132 | + ATA_ID_PIO_MODES = 64, | |
133 | + ATA_ID_QUEUE_DEPTH = 75, | |
134 | + ATA_ID_SATA_CAP = 76, | |
135 | + ATA_ID_SATA_FEATURES = 78, | |
136 | + ATA_ID_SATA_FEATURES_EN = 79, | |
137 | + ATA_ID_MAJOR_VER = 80, | |
138 | + ATA_ID_MINOR_VER = 81, | |
139 | + ATA_ID_UDMA_MODES = 88, | |
140 | + ATA_ID_LBA48_SECTORS = 100, | |
141 | + | |
142 | + ATA_ID_SERNO_LEN = 20, | |
143 | + ATA_ID_FW_REV_LEN = 8, | |
144 | + ATA_ID_PROD_LEN = 40, | |
145 | + | |
146 | + ATA_PIO3 = (1 << 0), | |
147 | + ATA_PIO4 = ATA_PIO3 | (1 << 1), | |
148 | + | |
149 | + ATA_UDMA0 = (1 << 0), | |
150 | + ATA_UDMA1 = ATA_UDMA0 | (1 << 1), | |
151 | + ATA_UDMA2 = ATA_UDMA1 | (1 << 2), | |
152 | + ATA_UDMA3 = ATA_UDMA2 | (1 << 3), | |
153 | + ATA_UDMA4 = ATA_UDMA3 | (1 << 4), | |
154 | + ATA_UDMA5 = ATA_UDMA4 | (1 << 5), | |
155 | + ATA_UDMA6 = ATA_UDMA5 | (1 << 6), | |
156 | + ATA_UDMA7 = ATA_UDMA6 | (1 << 7), | |
157 | +}; | |
158 | + | |
159 | +#define ata_id_is_ata(id) (((id)[0] & (1 << 15)) == 0) | |
160 | +#define ata_id_wcache_enabled(id) ((id)[85] & (1 << 5)) | |
161 | +#define ata_id_has_fua(id) ((id)[84] & (1 << 6)) | |
162 | +#define ata_id_has_flush(id) ((id)[83] & (1 << 12)) | |
163 | +#define ata_id_has_flush_ext(id) ((id)[83] & (1 << 13)) | |
164 | +#define ata_id_has_lba48(id) ((id)[83] & (1 << 10)) | |
165 | +#define ata_id_has_wcache(id) ((id)[82] & (1 << 5)) | |
166 | +#define ata_id_has_lba(id) ((id)[49] & (1 << 9)) | |
167 | +#define ata_id_has_dma(id) ((id)[49] & (1 << 8)) | |
168 | +#define ata_id_has_ncq(id) ((id)[76] & (1 << 8)) | |
169 | +#define ata_id_queue_depth(id) (((id)[75] & 0x1f) + 1) | |
170 | + | |
171 | +#define ata_id_u32(id,n) \ | |
172 | + (((u32) (id)[(n) + 1] << 16) | ((u32) (id)[(n)])) | |
173 | +#define ata_id_u64(id,n) \ | |
174 | + ( ((u64) (id)[(n) + 3] << 48) | \ | |
175 | + ((u64) (id)[(n) + 2] << 32) | \ | |
176 | + ((u64) (id)[(n) + 1] << 16) | \ | |
177 | + ((u64) (id)[(n) + 0]) ) | |
178 | + | |
179 | + | |
180 | +static inline unsigned int ata_id_major_version(const u16 *id) | |
181 | +{ | |
182 | + unsigned int mver; | |
183 | + | |
184 | + if (id[ATA_ID_MAJOR_VER] == 0xFFFF) | |
185 | + return 0; | |
186 | + | |
187 | + for (mver = 14; mver >= 1; mver--) | |
188 | + if (id[ATA_ID_MAJOR_VER] & (1 << mver)) | |
189 | + break; | |
190 | + return mver; | |
191 | +} | |
192 | + | |
193 | +static inline int ata_id_is_sata(const u16 *id) | |
194 | +{ | |
195 | + return ata_id_major_version(id) >= 5 && id[93] == 0; | |
196 | +} | |
197 | + | |
198 | +u64 ata_id_n_sectors(u16 *id); | |
199 | +u32 ata_dev_classify(u32 sig); | |
200 | +void ata_id_c_string(const u16 *id, unsigned char *s, | |
201 | + unsigned int ofs, unsigned int len); | |
202 | +void ata_dump_id(u16 *id); | |
203 | +void ata_swap_buf_le16(u16 *buf, unsigned int buf_words); | |
204 | + | |
205 | +#endif /* __LIBATA_H__ */ |