1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2fc843a02SSimon Glass /*
3fc843a02SSimon Glass * (C) Copyright 2000-2011
4fc843a02SSimon Glass * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5fc843a02SSimon Glass */
6fc843a02SSimon Glass
7fc843a02SSimon Glass #include <common.h>
8fc843a02SSimon Glass #include <ata.h>
9fc843a02SSimon Glass #include <dm.h>
10fc843a02SSimon Glass #include <ide.h>
11fc843a02SSimon Glass #include <watchdog.h>
12fc843a02SSimon Glass #include <asm/io.h>
13fc843a02SSimon Glass
14fc843a02SSimon Glass #ifdef __PPC__
15fc843a02SSimon Glass # define EIEIO __asm__ volatile ("eieio")
16fc843a02SSimon Glass # define SYNC __asm__ volatile ("sync")
17fc843a02SSimon Glass #else
18fc843a02SSimon Glass # define EIEIO /* nothing */
19fc843a02SSimon Glass # define SYNC /* nothing */
20fc843a02SSimon Glass #endif
21fc843a02SSimon Glass
22fc843a02SSimon Glass /* Current offset for IDE0 / IDE1 bus access */
23fc843a02SSimon Glass ulong ide_bus_offset[CONFIG_SYS_IDE_MAXBUS] = {
24fc843a02SSimon Glass #if defined(CONFIG_SYS_ATA_IDE0_OFFSET)
25fc843a02SSimon Glass CONFIG_SYS_ATA_IDE0_OFFSET,
26fc843a02SSimon Glass #endif
27fc843a02SSimon Glass #if defined(CONFIG_SYS_ATA_IDE1_OFFSET) && (CONFIG_SYS_IDE_MAXBUS > 1)
28fc843a02SSimon Glass CONFIG_SYS_ATA_IDE1_OFFSET,
29fc843a02SSimon Glass #endif
30fc843a02SSimon Glass };
31fc843a02SSimon Glass
32fc843a02SSimon Glass static int ide_bus_ok[CONFIG_SYS_IDE_MAXBUS];
33fc843a02SSimon Glass
34fc843a02SSimon Glass struct blk_desc ide_dev_desc[CONFIG_SYS_IDE_MAXDEVICE];
35fc843a02SSimon Glass
36fc843a02SSimon Glass #define IDE_TIME_OUT 2000 /* 2 sec timeout */
37fc843a02SSimon Glass
38fc843a02SSimon Glass #define ATAPI_TIME_OUT 7000 /* 7 sec timeout (5 sec seems to work...) */
39fc843a02SSimon Glass
40fc843a02SSimon Glass #define IDE_SPIN_UP_TIME_OUT 5000 /* 5 sec spin-up timeout */
41fc843a02SSimon Glass
42fc843a02SSimon Glass #ifndef CONFIG_SYS_ATA_PORT_ADDR
43fc843a02SSimon Glass #define CONFIG_SYS_ATA_PORT_ADDR(port) (port)
44fc843a02SSimon Glass #endif
45fc843a02SSimon Glass
46fc843a02SSimon Glass #ifdef CONFIG_IDE_RESET
47fc843a02SSimon Glass extern void ide_set_reset(int idereset);
48fc843a02SSimon Glass
ide_reset(void)49fc843a02SSimon Glass static void ide_reset(void)
50fc843a02SSimon Glass {
51fc843a02SSimon Glass int i;
52fc843a02SSimon Glass
53fc843a02SSimon Glass for (i = 0; i < CONFIG_SYS_IDE_MAXBUS; ++i)
54fc843a02SSimon Glass ide_bus_ok[i] = 0;
55fc843a02SSimon Glass for (i = 0; i < CONFIG_SYS_IDE_MAXDEVICE; ++i)
56fc843a02SSimon Glass ide_dev_desc[i].type = DEV_TYPE_UNKNOWN;
57fc843a02SSimon Glass
58fc843a02SSimon Glass ide_set_reset(1); /* assert reset */
59fc843a02SSimon Glass
60fc843a02SSimon Glass /* the reset signal shall be asserted for et least 25 us */
61fc843a02SSimon Glass udelay(25);
62fc843a02SSimon Glass
63fc843a02SSimon Glass WATCHDOG_RESET();
64fc843a02SSimon Glass
65fc843a02SSimon Glass /* de-assert RESET signal */
66fc843a02SSimon Glass ide_set_reset(0);
67fc843a02SSimon Glass
68fc843a02SSimon Glass /* wait 250 ms */
69fc843a02SSimon Glass for (i = 0; i < 250; ++i)
70fc843a02SSimon Glass udelay(1000);
71fc843a02SSimon Glass }
72fc843a02SSimon Glass #else
73fc843a02SSimon Glass #define ide_reset() /* dummy */
74fc843a02SSimon Glass #endif /* CONFIG_IDE_RESET */
75fc843a02SSimon Glass
76fc843a02SSimon Glass /*
77fc843a02SSimon Glass * Wait until Busy bit is off, or timeout (in ms)
78fc843a02SSimon Glass * Return last status
79fc843a02SSimon Glass */
ide_wait(int dev,ulong t)80fc843a02SSimon Glass static uchar ide_wait(int dev, ulong t)
81fc843a02SSimon Glass {
82fc843a02SSimon Glass ulong delay = 10 * t; /* poll every 100 us */
83fc843a02SSimon Glass uchar c;
84fc843a02SSimon Glass
85fc843a02SSimon Glass while ((c = ide_inb(dev, ATA_STATUS)) & ATA_STAT_BUSY) {
86fc843a02SSimon Glass udelay(100);
87fc843a02SSimon Glass if (delay-- == 0)
88fc843a02SSimon Glass break;
89fc843a02SSimon Glass }
90fc843a02SSimon Glass return c;
91fc843a02SSimon Glass }
92fc843a02SSimon Glass
93fc843a02SSimon Glass /*
94fc843a02SSimon Glass * copy src to dest, skipping leading and trailing blanks and null
95fc843a02SSimon Glass * terminate the string
96fc843a02SSimon Glass * "len" is the size of available memory including the terminating '\0'
97fc843a02SSimon Glass */
ident_cpy(unsigned char * dst,unsigned char * src,unsigned int len)98fc843a02SSimon Glass static void ident_cpy(unsigned char *dst, unsigned char *src,
99fc843a02SSimon Glass unsigned int len)
100fc843a02SSimon Glass {
101fc843a02SSimon Glass unsigned char *end, *last;
102fc843a02SSimon Glass
103fc843a02SSimon Glass last = dst;
104fc843a02SSimon Glass end = src + len - 1;
105fc843a02SSimon Glass
106fc843a02SSimon Glass /* reserve space for '\0' */
107fc843a02SSimon Glass if (len < 2)
108fc843a02SSimon Glass goto OUT;
109fc843a02SSimon Glass
110fc843a02SSimon Glass /* skip leading white space */
111fc843a02SSimon Glass while ((*src) && (src < end) && (*src == ' '))
112fc843a02SSimon Glass ++src;
113fc843a02SSimon Glass
114fc843a02SSimon Glass /* copy string, omitting trailing white space */
115fc843a02SSimon Glass while ((*src) && (src < end)) {
116fc843a02SSimon Glass *dst++ = *src;
117fc843a02SSimon Glass if (*src++ != ' ')
118fc843a02SSimon Glass last = dst;
119fc843a02SSimon Glass }
120fc843a02SSimon Glass OUT:
121fc843a02SSimon Glass *last = '\0';
122fc843a02SSimon Glass }
123fc843a02SSimon Glass
124fc843a02SSimon Glass #ifdef CONFIG_ATAPI
125fc843a02SSimon Glass /****************************************************************************
126fc843a02SSimon Glass * ATAPI Support
127fc843a02SSimon Glass */
128fc843a02SSimon Glass
129fc843a02SSimon Glass #if defined(CONFIG_IDE_SWAP_IO)
130fc843a02SSimon Glass /* since ATAPI may use commands with not 4 bytes alligned length
131fc843a02SSimon Glass * we have our own transfer functions, 2 bytes alligned */
ide_output_data_shorts(int dev,ushort * sect_buf,int shorts)132fc843a02SSimon Glass __weak void ide_output_data_shorts(int dev, ushort *sect_buf, int shorts)
133fc843a02SSimon Glass {
134fc843a02SSimon Glass ushort *dbuf;
135fc843a02SSimon Glass volatile ushort *pbuf;
136fc843a02SSimon Glass
137fc843a02SSimon Glass pbuf = (ushort *)(ATA_CURR_BASE(dev) + ATA_DATA_REG);
138fc843a02SSimon Glass dbuf = (ushort *)sect_buf;
139fc843a02SSimon Glass
140fc843a02SSimon Glass debug("in output data shorts base for read is %lx\n",
141fc843a02SSimon Glass (unsigned long) pbuf);
142fc843a02SSimon Glass
143fc843a02SSimon Glass while (shorts--) {
144fc843a02SSimon Glass EIEIO;
145fc843a02SSimon Glass *pbuf = *dbuf++;
146fc843a02SSimon Glass }
147fc843a02SSimon Glass }
148fc843a02SSimon Glass
ide_input_data_shorts(int dev,ushort * sect_buf,int shorts)149fc843a02SSimon Glass __weak void ide_input_data_shorts(int dev, ushort *sect_buf, int shorts)
150fc843a02SSimon Glass {
151fc843a02SSimon Glass ushort *dbuf;
152fc843a02SSimon Glass volatile ushort *pbuf;
153fc843a02SSimon Glass
154fc843a02SSimon Glass pbuf = (ushort *)(ATA_CURR_BASE(dev) + ATA_DATA_REG);
155fc843a02SSimon Glass dbuf = (ushort *)sect_buf;
156fc843a02SSimon Glass
157fc843a02SSimon Glass debug("in input data shorts base for read is %lx\n",
158fc843a02SSimon Glass (unsigned long) pbuf);
159fc843a02SSimon Glass
160fc843a02SSimon Glass while (shorts--) {
161fc843a02SSimon Glass EIEIO;
162fc843a02SSimon Glass *dbuf++ = *pbuf;
163fc843a02SSimon Glass }
164fc843a02SSimon Glass }
165fc843a02SSimon Glass
166fc843a02SSimon Glass #else /* ! CONFIG_IDE_SWAP_IO */
ide_output_data_shorts(int dev,ushort * sect_buf,int shorts)167fc843a02SSimon Glass __weak void ide_output_data_shorts(int dev, ushort *sect_buf, int shorts)
168fc843a02SSimon Glass {
169fc843a02SSimon Glass outsw(ATA_CURR_BASE(dev) + ATA_DATA_REG, sect_buf, shorts);
170fc843a02SSimon Glass }
171fc843a02SSimon Glass
ide_input_data_shorts(int dev,ushort * sect_buf,int shorts)172fc843a02SSimon Glass __weak void ide_input_data_shorts(int dev, ushort *sect_buf, int shorts)
173fc843a02SSimon Glass {
174fc843a02SSimon Glass insw(ATA_CURR_BASE(dev) + ATA_DATA_REG, sect_buf, shorts);
175fc843a02SSimon Glass }
176fc843a02SSimon Glass
177fc843a02SSimon Glass #endif /* CONFIG_IDE_SWAP_IO */
178fc843a02SSimon Glass
179fc843a02SSimon Glass /*
180fc843a02SSimon Glass * Wait until (Status & mask) == res, or timeout (in ms)
181fc843a02SSimon Glass * Return last status
182fc843a02SSimon Glass * This is used since some ATAPI CD ROMs clears their Busy Bit first
183fc843a02SSimon Glass * and then they set their DRQ Bit
184fc843a02SSimon Glass */
atapi_wait_mask(int dev,ulong t,uchar mask,uchar res)185fc843a02SSimon Glass static uchar atapi_wait_mask(int dev, ulong t, uchar mask, uchar res)
186fc843a02SSimon Glass {
187fc843a02SSimon Glass ulong delay = 10 * t; /* poll every 100 us */
188fc843a02SSimon Glass uchar c;
189fc843a02SSimon Glass
190fc843a02SSimon Glass /* prevents to read the status before valid */
191fc843a02SSimon Glass c = ide_inb(dev, ATA_DEV_CTL);
192fc843a02SSimon Glass
193fc843a02SSimon Glass while (((c = ide_inb(dev, ATA_STATUS)) & mask) != res) {
194fc843a02SSimon Glass /* break if error occurs (doesn't make sense to wait more) */
195fc843a02SSimon Glass if ((c & ATA_STAT_ERR) == ATA_STAT_ERR)
196fc843a02SSimon Glass break;
197fc843a02SSimon Glass udelay(100);
198fc843a02SSimon Glass if (delay-- == 0)
199fc843a02SSimon Glass break;
200fc843a02SSimon Glass }
201fc843a02SSimon Glass return c;
202fc843a02SSimon Glass }
203fc843a02SSimon Glass
204fc843a02SSimon Glass /*
205fc843a02SSimon Glass * issue an atapi command
206fc843a02SSimon Glass */
atapi_issue(int device,unsigned char * ccb,int ccblen,unsigned char * buffer,int buflen)207fc843a02SSimon Glass unsigned char atapi_issue(int device, unsigned char *ccb, int ccblen,
208fc843a02SSimon Glass unsigned char *buffer, int buflen)
209fc843a02SSimon Glass {
210fc843a02SSimon Glass unsigned char c, err, mask, res;
211fc843a02SSimon Glass int n;
212fc843a02SSimon Glass
213fc843a02SSimon Glass /* Select device
214fc843a02SSimon Glass */
215fc843a02SSimon Glass mask = ATA_STAT_BUSY | ATA_STAT_DRQ;
216fc843a02SSimon Glass res = 0;
217fc843a02SSimon Glass ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
218fc843a02SSimon Glass c = atapi_wait_mask(device, ATAPI_TIME_OUT, mask, res);
219fc843a02SSimon Glass if ((c & mask) != res) {
220fc843a02SSimon Glass printf("ATAPI_ISSUE: device %d not ready status %X\n", device,
221fc843a02SSimon Glass c);
222fc843a02SSimon Glass err = 0xFF;
223fc843a02SSimon Glass goto AI_OUT;
224fc843a02SSimon Glass }
225fc843a02SSimon Glass /* write taskfile */
226fc843a02SSimon Glass ide_outb(device, ATA_ERROR_REG, 0); /* no DMA, no overlaped */
227fc843a02SSimon Glass ide_outb(device, ATA_SECT_CNT, 0);
228fc843a02SSimon Glass ide_outb(device, ATA_SECT_NUM, 0);
229fc843a02SSimon Glass ide_outb(device, ATA_CYL_LOW, (unsigned char) (buflen & 0xFF));
230fc843a02SSimon Glass ide_outb(device, ATA_CYL_HIGH,
231fc843a02SSimon Glass (unsigned char) ((buflen >> 8) & 0xFF));
232fc843a02SSimon Glass ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
233fc843a02SSimon Glass
234fc843a02SSimon Glass ide_outb(device, ATA_COMMAND, ATAPI_CMD_PACKET);
235fc843a02SSimon Glass udelay(50);
236fc843a02SSimon Glass
237fc843a02SSimon Glass mask = ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR;
238fc843a02SSimon Glass res = ATA_STAT_DRQ;
239fc843a02SSimon Glass c = atapi_wait_mask(device, ATAPI_TIME_OUT, mask, res);
240fc843a02SSimon Glass
241fc843a02SSimon Glass if ((c & mask) != res) { /* DRQ must be 1, BSY 0 */
242fc843a02SSimon Glass printf("ATAPI_ISSUE: Error (no IRQ) before sending ccb dev %d status 0x%02x\n",
243fc843a02SSimon Glass device, c);
244fc843a02SSimon Glass err = 0xFF;
245fc843a02SSimon Glass goto AI_OUT;
246fc843a02SSimon Glass }
247fc843a02SSimon Glass
248fc843a02SSimon Glass /* write command block */
249fc843a02SSimon Glass ide_output_data_shorts(device, (unsigned short *)ccb, ccblen / 2);
250fc843a02SSimon Glass
251fc843a02SSimon Glass /* ATAPI Command written wait for completition */
252fc843a02SSimon Glass udelay(5000); /* device must set bsy */
253fc843a02SSimon Glass
254fc843a02SSimon Glass mask = ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR;
255fc843a02SSimon Glass /*
256fc843a02SSimon Glass * if no data wait for DRQ = 0 BSY = 0
257fc843a02SSimon Glass * if data wait for DRQ = 1 BSY = 0
258fc843a02SSimon Glass */
259fc843a02SSimon Glass res = 0;
260fc843a02SSimon Glass if (buflen)
261fc843a02SSimon Glass res = ATA_STAT_DRQ;
262fc843a02SSimon Glass c = atapi_wait_mask(device, ATAPI_TIME_OUT, mask, res);
263fc843a02SSimon Glass if ((c & mask) != res) {
264fc843a02SSimon Glass if (c & ATA_STAT_ERR) {
265fc843a02SSimon Glass err = (ide_inb(device, ATA_ERROR_REG)) >> 4;
266fc843a02SSimon Glass debug("atapi_issue 1 returned sense key %X status %02X\n",
267fc843a02SSimon Glass err, c);
268fc843a02SSimon Glass } else {
269fc843a02SSimon Glass printf("ATAPI_ISSUE: (no DRQ) after sending ccb (%x) status 0x%02x\n",
270fc843a02SSimon Glass ccb[0], c);
271fc843a02SSimon Glass err = 0xFF;
272fc843a02SSimon Glass }
273fc843a02SSimon Glass goto AI_OUT;
274fc843a02SSimon Glass }
275fc843a02SSimon Glass n = ide_inb(device, ATA_CYL_HIGH);
276fc843a02SSimon Glass n <<= 8;
277fc843a02SSimon Glass n += ide_inb(device, ATA_CYL_LOW);
278fc843a02SSimon Glass if (n > buflen) {
279fc843a02SSimon Glass printf("ERROR, transfer bytes %d requested only %d\n", n,
280fc843a02SSimon Glass buflen);
281fc843a02SSimon Glass err = 0xff;
282fc843a02SSimon Glass goto AI_OUT;
283fc843a02SSimon Glass }
284fc843a02SSimon Glass if ((n == 0) && (buflen < 0)) {
285fc843a02SSimon Glass printf("ERROR, transfer bytes %d requested %d\n", n, buflen);
286fc843a02SSimon Glass err = 0xff;
287fc843a02SSimon Glass goto AI_OUT;
288fc843a02SSimon Glass }
289fc843a02SSimon Glass if (n != buflen) {
290fc843a02SSimon Glass debug("WARNING, transfer bytes %d not equal with requested %d\n",
291fc843a02SSimon Glass n, buflen);
292fc843a02SSimon Glass }
293fc843a02SSimon Glass if (n != 0) { /* data transfer */
294fc843a02SSimon Glass debug("ATAPI_ISSUE: %d Bytes to transfer\n", n);
295fc843a02SSimon Glass /* we transfer shorts */
296fc843a02SSimon Glass n >>= 1;
297fc843a02SSimon Glass /* ok now decide if it is an in or output */
298fc843a02SSimon Glass if ((ide_inb(device, ATA_SECT_CNT) & 0x02) == 0) {
299fc843a02SSimon Glass debug("Write to device\n");
300fc843a02SSimon Glass ide_output_data_shorts(device, (unsigned short *)buffer,
301fc843a02SSimon Glass n);
302fc843a02SSimon Glass } else {
303fc843a02SSimon Glass debug("Read from device @ %p shorts %d\n", buffer, n);
304fc843a02SSimon Glass ide_input_data_shorts(device, (unsigned short *)buffer,
305fc843a02SSimon Glass n);
306fc843a02SSimon Glass }
307fc843a02SSimon Glass }
308fc843a02SSimon Glass udelay(5000); /* seems that some CD ROMs need this... */
309fc843a02SSimon Glass mask = ATA_STAT_BUSY | ATA_STAT_ERR;
310fc843a02SSimon Glass res = 0;
311fc843a02SSimon Glass c = atapi_wait_mask(device, ATAPI_TIME_OUT, mask, res);
312fc843a02SSimon Glass if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) {
313fc843a02SSimon Glass err = (ide_inb(device, ATA_ERROR_REG) >> 4);
314fc843a02SSimon Glass debug("atapi_issue 2 returned sense key %X status %X\n", err,
315fc843a02SSimon Glass c);
316fc843a02SSimon Glass } else {
317fc843a02SSimon Glass err = 0;
318fc843a02SSimon Glass }
319fc843a02SSimon Glass AI_OUT:
320fc843a02SSimon Glass return err;
321fc843a02SSimon Glass }
322fc843a02SSimon Glass
323fc843a02SSimon Glass /*
324fc843a02SSimon Glass * sending the command to atapi_issue. If an status other than good
325fc843a02SSimon Glass * returns, an request_sense will be issued
326fc843a02SSimon Glass */
327fc843a02SSimon Glass
328fc843a02SSimon Glass #define ATAPI_DRIVE_NOT_READY 100
329fc843a02SSimon Glass #define ATAPI_UNIT_ATTN 10
330fc843a02SSimon Glass
atapi_issue_autoreq(int device,unsigned char * ccb,int ccblen,unsigned char * buffer,int buflen)331fc843a02SSimon Glass unsigned char atapi_issue_autoreq(int device,
332fc843a02SSimon Glass unsigned char *ccb,
333fc843a02SSimon Glass int ccblen,
334fc843a02SSimon Glass unsigned char *buffer, int buflen)
335fc843a02SSimon Glass {
336fc843a02SSimon Glass unsigned char sense_data[18], sense_ccb[12];
337fc843a02SSimon Glass unsigned char res, key, asc, ascq;
338fc843a02SSimon Glass int notready, unitattn;
339fc843a02SSimon Glass
340fc843a02SSimon Glass unitattn = ATAPI_UNIT_ATTN;
341fc843a02SSimon Glass notready = ATAPI_DRIVE_NOT_READY;
342fc843a02SSimon Glass
343fc843a02SSimon Glass retry:
344fc843a02SSimon Glass res = atapi_issue(device, ccb, ccblen, buffer, buflen);
345fc843a02SSimon Glass if (res == 0)
346fc843a02SSimon Glass return 0; /* Ok */
347fc843a02SSimon Glass
348fc843a02SSimon Glass if (res == 0xFF)
349fc843a02SSimon Glass return 0xFF; /* error */
350fc843a02SSimon Glass
351fc843a02SSimon Glass debug("(auto_req)atapi_issue returned sense key %X\n", res);
352fc843a02SSimon Glass
353fc843a02SSimon Glass memset(sense_ccb, 0, sizeof(sense_ccb));
354fc843a02SSimon Glass memset(sense_data, 0, sizeof(sense_data));
355fc843a02SSimon Glass sense_ccb[0] = ATAPI_CMD_REQ_SENSE;
356fc843a02SSimon Glass sense_ccb[4] = 18; /* allocation Length */
357fc843a02SSimon Glass
358fc843a02SSimon Glass res = atapi_issue(device, sense_ccb, 12, sense_data, 18);
359fc843a02SSimon Glass key = (sense_data[2] & 0xF);
360fc843a02SSimon Glass asc = (sense_data[12]);
361fc843a02SSimon Glass ascq = (sense_data[13]);
362fc843a02SSimon Glass
363fc843a02SSimon Glass debug("ATAPI_CMD_REQ_SENSE returned %x\n", res);
364fc843a02SSimon Glass debug(" Sense page: %02X key %02X ASC %02X ASCQ %02X\n",
365fc843a02SSimon Glass sense_data[0], key, asc, ascq);
366fc843a02SSimon Glass
367fc843a02SSimon Glass if ((key == 0))
368fc843a02SSimon Glass return 0; /* ok device ready */
369fc843a02SSimon Glass
370fc843a02SSimon Glass if ((key == 6) || (asc == 0x29) || (asc == 0x28)) { /* Unit Attention */
371fc843a02SSimon Glass if (unitattn-- > 0) {
372fc843a02SSimon Glass udelay(200 * 1000);
373fc843a02SSimon Glass goto retry;
374fc843a02SSimon Glass }
375fc843a02SSimon Glass printf("Unit Attention, tried %d\n", ATAPI_UNIT_ATTN);
376fc843a02SSimon Glass goto error;
377fc843a02SSimon Glass }
378fc843a02SSimon Glass if ((asc == 0x4) && (ascq == 0x1)) {
379fc843a02SSimon Glass /* not ready, but will be ready soon */
380fc843a02SSimon Glass if (notready-- > 0) {
381fc843a02SSimon Glass udelay(200 * 1000);
382fc843a02SSimon Glass goto retry;
383fc843a02SSimon Glass }
384fc843a02SSimon Glass printf("Drive not ready, tried %d times\n",
385fc843a02SSimon Glass ATAPI_DRIVE_NOT_READY);
386fc843a02SSimon Glass goto error;
387fc843a02SSimon Glass }
388fc843a02SSimon Glass if (asc == 0x3a) {
389fc843a02SSimon Glass debug("Media not present\n");
390fc843a02SSimon Glass goto error;
391fc843a02SSimon Glass }
392fc843a02SSimon Glass
393fc843a02SSimon Glass printf("ERROR: Unknown Sense key %02X ASC %02X ASCQ %02X\n", key, asc,
394fc843a02SSimon Glass ascq);
395fc843a02SSimon Glass error:
396fc843a02SSimon Glass debug("ERROR Sense key %02X ASC %02X ASCQ %02X\n", key, asc, ascq);
397fc843a02SSimon Glass return 0xFF;
398fc843a02SSimon Glass }
399fc843a02SSimon Glass
400fc843a02SSimon Glass /*
401fc843a02SSimon Glass * atapi_read:
402fc843a02SSimon Glass * we transfer only one block per command, since the multiple DRQ per
403fc843a02SSimon Glass * command is not yet implemented
404fc843a02SSimon Glass */
405fc843a02SSimon Glass #define ATAPI_READ_MAX_BYTES 2048 /* we read max 2kbytes */
406fc843a02SSimon Glass #define ATAPI_READ_BLOCK_SIZE 2048 /* assuming CD part */
407fc843a02SSimon Glass #define ATAPI_READ_MAX_BLOCK (ATAPI_READ_MAX_BYTES/ATAPI_READ_BLOCK_SIZE)
408fc843a02SSimon Glass
atapi_read(struct blk_desc * block_dev,lbaint_t blknr,lbaint_t blkcnt,void * buffer)409fc843a02SSimon Glass ulong atapi_read(struct blk_desc *block_dev, lbaint_t blknr, lbaint_t blkcnt,
410fc843a02SSimon Glass void *buffer)
411fc843a02SSimon Glass {
412fc843a02SSimon Glass int device = block_dev->devnum;
413fc843a02SSimon Glass ulong n = 0;
414fc843a02SSimon Glass unsigned char ccb[12]; /* Command descriptor block */
415fc843a02SSimon Glass ulong cnt;
416fc843a02SSimon Glass
417fc843a02SSimon Glass debug("atapi_read dev %d start " LBAF " blocks " LBAF
418fc843a02SSimon Glass " buffer at %lX\n", device, blknr, blkcnt, (ulong) buffer);
419fc843a02SSimon Glass
420fc843a02SSimon Glass do {
421fc843a02SSimon Glass if (blkcnt > ATAPI_READ_MAX_BLOCK)
422fc843a02SSimon Glass cnt = ATAPI_READ_MAX_BLOCK;
423fc843a02SSimon Glass else
424fc843a02SSimon Glass cnt = blkcnt;
425fc843a02SSimon Glass
426fc843a02SSimon Glass ccb[0] = ATAPI_CMD_READ_12;
427fc843a02SSimon Glass ccb[1] = 0; /* reserved */
428fc843a02SSimon Glass ccb[2] = (unsigned char) (blknr >> 24) & 0xFF; /* MSB Block */
429fc843a02SSimon Glass ccb[3] = (unsigned char) (blknr >> 16) & 0xFF; /* */
430fc843a02SSimon Glass ccb[4] = (unsigned char) (blknr >> 8) & 0xFF;
431fc843a02SSimon Glass ccb[5] = (unsigned char) blknr & 0xFF; /* LSB Block */
432fc843a02SSimon Glass ccb[6] = (unsigned char) (cnt >> 24) & 0xFF; /* MSB Block cnt */
433fc843a02SSimon Glass ccb[7] = (unsigned char) (cnt >> 16) & 0xFF;
434fc843a02SSimon Glass ccb[8] = (unsigned char) (cnt >> 8) & 0xFF;
435fc843a02SSimon Glass ccb[9] = (unsigned char) cnt & 0xFF; /* LSB Block */
436fc843a02SSimon Glass ccb[10] = 0; /* reserved */
437fc843a02SSimon Glass ccb[11] = 0; /* reserved */
438fc843a02SSimon Glass
439fc843a02SSimon Glass if (atapi_issue_autoreq(device, ccb, 12,
440fc843a02SSimon Glass (unsigned char *)buffer,
441fc843a02SSimon Glass cnt * ATAPI_READ_BLOCK_SIZE)
442fc843a02SSimon Glass == 0xFF) {
443fc843a02SSimon Glass return n;
444fc843a02SSimon Glass }
445fc843a02SSimon Glass n += cnt;
446fc843a02SSimon Glass blkcnt -= cnt;
447fc843a02SSimon Glass blknr += cnt;
448fc843a02SSimon Glass buffer += (cnt * ATAPI_READ_BLOCK_SIZE);
449fc843a02SSimon Glass } while (blkcnt > 0);
450fc843a02SSimon Glass return n;
451fc843a02SSimon Glass }
452fc843a02SSimon Glass
atapi_inquiry(struct blk_desc * dev_desc)453fc843a02SSimon Glass static void atapi_inquiry(struct blk_desc *dev_desc)
454fc843a02SSimon Glass {
455fc843a02SSimon Glass unsigned char ccb[12]; /* Command descriptor block */
456fc843a02SSimon Glass unsigned char iobuf[64]; /* temp buf */
457fc843a02SSimon Glass unsigned char c;
458fc843a02SSimon Glass int device;
459fc843a02SSimon Glass
460fc843a02SSimon Glass device = dev_desc->devnum;
461fc843a02SSimon Glass dev_desc->type = DEV_TYPE_UNKNOWN; /* not yet valid */
46252a1c2c6SBin Meng #ifndef CONFIG_BLK
463fc843a02SSimon Glass dev_desc->block_read = atapi_read;
46452a1c2c6SBin Meng #endif
465fc843a02SSimon Glass
466fc843a02SSimon Glass memset(ccb, 0, sizeof(ccb));
467fc843a02SSimon Glass memset(iobuf, 0, sizeof(iobuf));
468fc843a02SSimon Glass
469fc843a02SSimon Glass ccb[0] = ATAPI_CMD_INQUIRY;
470fc843a02SSimon Glass ccb[4] = 40; /* allocation Legnth */
471fc843a02SSimon Glass c = atapi_issue_autoreq(device, ccb, 12, (unsigned char *)iobuf, 40);
472fc843a02SSimon Glass
473fc843a02SSimon Glass debug("ATAPI_CMD_INQUIRY returned %x\n", c);
474fc843a02SSimon Glass if (c != 0)
475fc843a02SSimon Glass return;
476fc843a02SSimon Glass
477fc843a02SSimon Glass /* copy device ident strings */
478fc843a02SSimon Glass ident_cpy((unsigned char *)dev_desc->vendor, &iobuf[8], 8);
479fc843a02SSimon Glass ident_cpy((unsigned char *)dev_desc->product, &iobuf[16], 16);
480fc843a02SSimon Glass ident_cpy((unsigned char *)dev_desc->revision, &iobuf[32], 5);
481fc843a02SSimon Glass
482fc843a02SSimon Glass dev_desc->lun = 0;
483fc843a02SSimon Glass dev_desc->lba = 0;
484fc843a02SSimon Glass dev_desc->blksz = 0;
485fc843a02SSimon Glass dev_desc->log2blksz = LOG2_INVALID(typeof(dev_desc->log2blksz));
486fc843a02SSimon Glass dev_desc->type = iobuf[0] & 0x1f;
487fc843a02SSimon Glass
488fc843a02SSimon Glass if ((iobuf[1] & 0x80) == 0x80)
489fc843a02SSimon Glass dev_desc->removable = 1;
490fc843a02SSimon Glass else
491fc843a02SSimon Glass dev_desc->removable = 0;
492fc843a02SSimon Glass
493fc843a02SSimon Glass memset(ccb, 0, sizeof(ccb));
494fc843a02SSimon Glass memset(iobuf, 0, sizeof(iobuf));
495fc843a02SSimon Glass ccb[0] = ATAPI_CMD_START_STOP;
496fc843a02SSimon Glass ccb[4] = 0x03; /* start */
497fc843a02SSimon Glass
498fc843a02SSimon Glass c = atapi_issue_autoreq(device, ccb, 12, (unsigned char *)iobuf, 0);
499fc843a02SSimon Glass
500fc843a02SSimon Glass debug("ATAPI_CMD_START_STOP returned %x\n", c);
501fc843a02SSimon Glass if (c != 0)
502fc843a02SSimon Glass return;
503fc843a02SSimon Glass
504fc843a02SSimon Glass memset(ccb, 0, sizeof(ccb));
505fc843a02SSimon Glass memset(iobuf, 0, sizeof(iobuf));
506fc843a02SSimon Glass c = atapi_issue_autoreq(device, ccb, 12, (unsigned char *)iobuf, 0);
507fc843a02SSimon Glass
508fc843a02SSimon Glass debug("ATAPI_CMD_UNIT_TEST_READY returned %x\n", c);
509fc843a02SSimon Glass if (c != 0)
510fc843a02SSimon Glass return;
511fc843a02SSimon Glass
512fc843a02SSimon Glass memset(ccb, 0, sizeof(ccb));
513fc843a02SSimon Glass memset(iobuf, 0, sizeof(iobuf));
514fc843a02SSimon Glass ccb[0] = ATAPI_CMD_READ_CAP;
515fc843a02SSimon Glass c = atapi_issue_autoreq(device, ccb, 12, (unsigned char *)iobuf, 8);
516fc843a02SSimon Glass debug("ATAPI_CMD_READ_CAP returned %x\n", c);
517fc843a02SSimon Glass if (c != 0)
518fc843a02SSimon Glass return;
519fc843a02SSimon Glass
520fc843a02SSimon Glass debug("Read Cap: LBA %02X%02X%02X%02X blksize %02X%02X%02X%02X\n",
521fc843a02SSimon Glass iobuf[0], iobuf[1], iobuf[2], iobuf[3],
522fc843a02SSimon Glass iobuf[4], iobuf[5], iobuf[6], iobuf[7]);
523fc843a02SSimon Glass
524fc843a02SSimon Glass dev_desc->lba = ((unsigned long) iobuf[0] << 24) +
525fc843a02SSimon Glass ((unsigned long) iobuf[1] << 16) +
526fc843a02SSimon Glass ((unsigned long) iobuf[2] << 8) + ((unsigned long) iobuf[3]);
527fc843a02SSimon Glass dev_desc->blksz = ((unsigned long) iobuf[4] << 24) +
528fc843a02SSimon Glass ((unsigned long) iobuf[5] << 16) +
529fc843a02SSimon Glass ((unsigned long) iobuf[6] << 8) + ((unsigned long) iobuf[7]);
530fc843a02SSimon Glass dev_desc->log2blksz = LOG2(dev_desc->blksz);
531fc843a02SSimon Glass #ifdef CONFIG_LBA48
532fc843a02SSimon Glass /* ATAPI devices cannot use 48bit addressing (ATA/ATAPI v7) */
533fc843a02SSimon Glass dev_desc->lba48 = 0;
534fc843a02SSimon Glass #endif
535fc843a02SSimon Glass return;
536fc843a02SSimon Glass }
537fc843a02SSimon Glass
538fc843a02SSimon Glass #endif /* CONFIG_ATAPI */
539fc843a02SSimon Glass
ide_ident(struct blk_desc * dev_desc)540fc843a02SSimon Glass static void ide_ident(struct blk_desc *dev_desc)
541fc843a02SSimon Glass {
542fc843a02SSimon Glass unsigned char c;
543fc843a02SSimon Glass hd_driveid_t iop;
544fc843a02SSimon Glass
545fc843a02SSimon Glass #ifdef CONFIG_ATAPI
546fc843a02SSimon Glass int retries = 0;
547fc843a02SSimon Glass #endif
548fc843a02SSimon Glass int device;
549fc843a02SSimon Glass
550fc843a02SSimon Glass device = dev_desc->devnum;
551fc843a02SSimon Glass printf(" Device %d: ", device);
552fc843a02SSimon Glass
553fc843a02SSimon Glass /* Select device
554fc843a02SSimon Glass */
555fc843a02SSimon Glass ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
556fc843a02SSimon Glass dev_desc->if_type = IF_TYPE_IDE;
557fc843a02SSimon Glass #ifdef CONFIG_ATAPI
558fc843a02SSimon Glass
559fc843a02SSimon Glass retries = 0;
560fc843a02SSimon Glass
561fc843a02SSimon Glass /* Warning: This will be tricky to read */
562fc843a02SSimon Glass while (retries <= 1) {
563fc843a02SSimon Glass /* check signature */
564fc843a02SSimon Glass if ((ide_inb(device, ATA_SECT_CNT) == 0x01) &&
565fc843a02SSimon Glass (ide_inb(device, ATA_SECT_NUM) == 0x01) &&
566fc843a02SSimon Glass (ide_inb(device, ATA_CYL_LOW) == 0x14) &&
567fc843a02SSimon Glass (ide_inb(device, ATA_CYL_HIGH) == 0xEB)) {
568fc843a02SSimon Glass /* ATAPI Signature found */
569fc843a02SSimon Glass dev_desc->if_type = IF_TYPE_ATAPI;
570fc843a02SSimon Glass /*
571fc843a02SSimon Glass * Start Ident Command
572fc843a02SSimon Glass */
573fc843a02SSimon Glass ide_outb(device, ATA_COMMAND, ATAPI_CMD_IDENT);
574fc843a02SSimon Glass /*
575fc843a02SSimon Glass * Wait for completion - ATAPI devices need more time
576fc843a02SSimon Glass * to become ready
577fc843a02SSimon Glass */
578fc843a02SSimon Glass c = ide_wait(device, ATAPI_TIME_OUT);
579fc843a02SSimon Glass } else
580fc843a02SSimon Glass #endif
581fc843a02SSimon Glass {
582fc843a02SSimon Glass /*
583fc843a02SSimon Glass * Start Ident Command
584fc843a02SSimon Glass */
585fc843a02SSimon Glass ide_outb(device, ATA_COMMAND, ATA_CMD_IDENT);
586fc843a02SSimon Glass
587fc843a02SSimon Glass /*
588fc843a02SSimon Glass * Wait for completion
589fc843a02SSimon Glass */
590fc843a02SSimon Glass c = ide_wait(device, IDE_TIME_OUT);
591fc843a02SSimon Glass }
592fc843a02SSimon Glass
593fc843a02SSimon Glass if (((c & ATA_STAT_DRQ) == 0) ||
594fc843a02SSimon Glass ((c & (ATA_STAT_FAULT | ATA_STAT_ERR)) != 0)) {
595fc843a02SSimon Glass #ifdef CONFIG_ATAPI
596fc843a02SSimon Glass {
597fc843a02SSimon Glass /*
598fc843a02SSimon Glass * Need to soft reset the device
599fc843a02SSimon Glass * in case it's an ATAPI...
600fc843a02SSimon Glass */
601fc843a02SSimon Glass debug("Retrying...\n");
602fc843a02SSimon Glass ide_outb(device, ATA_DEV_HD,
603fc843a02SSimon Glass ATA_LBA | ATA_DEVICE(device));
604fc843a02SSimon Glass udelay(100000);
605fc843a02SSimon Glass ide_outb(device, ATA_COMMAND, 0x08);
606fc843a02SSimon Glass udelay(500000); /* 500 ms */
607fc843a02SSimon Glass }
608fc843a02SSimon Glass /*
609fc843a02SSimon Glass * Select device
610fc843a02SSimon Glass */
611fc843a02SSimon Glass ide_outb(device, ATA_DEV_HD,
612fc843a02SSimon Glass ATA_LBA | ATA_DEVICE(device));
613fc843a02SSimon Glass retries++;
614fc843a02SSimon Glass #else
615fc843a02SSimon Glass return;
616fc843a02SSimon Glass #endif
617fc843a02SSimon Glass }
618fc843a02SSimon Glass #ifdef CONFIG_ATAPI
619fc843a02SSimon Glass else
620fc843a02SSimon Glass break;
621fc843a02SSimon Glass } /* see above - ugly to read */
622fc843a02SSimon Glass
623fc843a02SSimon Glass if (retries == 2) /* Not found */
624fc843a02SSimon Glass return;
625fc843a02SSimon Glass #endif
626fc843a02SSimon Glass
627fc843a02SSimon Glass ide_input_swap_data(device, (ulong *)&iop, ATA_SECTORWORDS);
628fc843a02SSimon Glass
629fc843a02SSimon Glass ident_cpy((unsigned char *)dev_desc->revision, iop.fw_rev,
630fc843a02SSimon Glass sizeof(dev_desc->revision));
631fc843a02SSimon Glass ident_cpy((unsigned char *)dev_desc->vendor, iop.model,
632fc843a02SSimon Glass sizeof(dev_desc->vendor));
633fc843a02SSimon Glass ident_cpy((unsigned char *)dev_desc->product, iop.serial_no,
634fc843a02SSimon Glass sizeof(dev_desc->product));
635fc843a02SSimon Glass #ifdef __LITTLE_ENDIAN
636fc843a02SSimon Glass /*
637fc843a02SSimon Glass * firmware revision, model, and serial number have Big Endian Byte
638fc843a02SSimon Glass * order in Word. Convert all three to little endian.
639fc843a02SSimon Glass *
640fc843a02SSimon Glass * See CF+ and CompactFlash Specification Revision 2.0:
641fc843a02SSimon Glass * 6.2.1.6: Identify Drive, Table 39 for more details
642fc843a02SSimon Glass */
643fc843a02SSimon Glass
644fc843a02SSimon Glass strswab(dev_desc->revision);
645fc843a02SSimon Glass strswab(dev_desc->vendor);
646fc843a02SSimon Glass strswab(dev_desc->product);
647fc843a02SSimon Glass #endif /* __LITTLE_ENDIAN */
648fc843a02SSimon Glass
649fc843a02SSimon Glass if ((iop.config & 0x0080) == 0x0080)
650fc843a02SSimon Glass dev_desc->removable = 1;
651fc843a02SSimon Glass else
652fc843a02SSimon Glass dev_desc->removable = 0;
653fc843a02SSimon Glass
654fc843a02SSimon Glass #ifdef CONFIG_ATAPI
655fc843a02SSimon Glass if (dev_desc->if_type == IF_TYPE_ATAPI) {
656fc843a02SSimon Glass atapi_inquiry(dev_desc);
657fc843a02SSimon Glass return;
658fc843a02SSimon Glass }
659fc843a02SSimon Glass #endif /* CONFIG_ATAPI */
660fc843a02SSimon Glass
661fc843a02SSimon Glass #ifdef __BIG_ENDIAN
662fc843a02SSimon Glass /* swap shorts */
663fc843a02SSimon Glass dev_desc->lba = (iop.lba_capacity << 16) | (iop.lba_capacity >> 16);
664fc843a02SSimon Glass #else /* ! __BIG_ENDIAN */
665fc843a02SSimon Glass /*
666fc843a02SSimon Glass * do not swap shorts on little endian
667fc843a02SSimon Glass *
668fc843a02SSimon Glass * See CF+ and CompactFlash Specification Revision 2.0:
669fc843a02SSimon Glass * 6.2.1.6: Identfy Drive, Table 39, Word Address 57-58 for details.
670fc843a02SSimon Glass */
671fc843a02SSimon Glass dev_desc->lba = iop.lba_capacity;
672fc843a02SSimon Glass #endif /* __BIG_ENDIAN */
673fc843a02SSimon Glass
674fc843a02SSimon Glass #ifdef CONFIG_LBA48
675fc843a02SSimon Glass if (iop.command_set_2 & 0x0400) { /* LBA 48 support */
676fc843a02SSimon Glass dev_desc->lba48 = 1;
677fc843a02SSimon Glass dev_desc->lba = (unsigned long long) iop.lba48_capacity[0] |
678fc843a02SSimon Glass ((unsigned long long) iop.lba48_capacity[1] << 16) |
679fc843a02SSimon Glass ((unsigned long long) iop.lba48_capacity[2] << 32) |
680fc843a02SSimon Glass ((unsigned long long) iop.lba48_capacity[3] << 48);
681fc843a02SSimon Glass } else {
682fc843a02SSimon Glass dev_desc->lba48 = 0;
683fc843a02SSimon Glass }
684fc843a02SSimon Glass #endif /* CONFIG_LBA48 */
685fc843a02SSimon Glass /* assuming HD */
686fc843a02SSimon Glass dev_desc->type = DEV_TYPE_HARDDISK;
687fc843a02SSimon Glass dev_desc->blksz = ATA_BLOCKSIZE;
688fc843a02SSimon Glass dev_desc->log2blksz = LOG2(dev_desc->blksz);
689fc843a02SSimon Glass dev_desc->lun = 0; /* just to fill something in... */
690fc843a02SSimon Glass
691fc843a02SSimon Glass #if 0 /* only used to test the powersaving mode,
692fc843a02SSimon Glass * if enabled, the drive goes after 5 sec
693fc843a02SSimon Glass * in standby mode */
694fc843a02SSimon Glass ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
695fc843a02SSimon Glass c = ide_wait(device, IDE_TIME_OUT);
696fc843a02SSimon Glass ide_outb(device, ATA_SECT_CNT, 1);
697fc843a02SSimon Glass ide_outb(device, ATA_LBA_LOW, 0);
698fc843a02SSimon Glass ide_outb(device, ATA_LBA_MID, 0);
699fc843a02SSimon Glass ide_outb(device, ATA_LBA_HIGH, 0);
700fc843a02SSimon Glass ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
701fc843a02SSimon Glass ide_outb(device, ATA_COMMAND, 0xe3);
702fc843a02SSimon Glass udelay(50);
703fc843a02SSimon Glass c = ide_wait(device, IDE_TIME_OUT); /* can't take over 500 ms */
704fc843a02SSimon Glass #endif
705fc843a02SSimon Glass }
706fc843a02SSimon Glass
ide_outb(int dev,int port,unsigned char val)707fc843a02SSimon Glass __weak void ide_outb(int dev, int port, unsigned char val)
708fc843a02SSimon Glass {
709fc843a02SSimon Glass debug("ide_outb (dev= %d, port= 0x%x, val= 0x%02x) : @ 0x%08lx\n",
710fc843a02SSimon Glass dev, port, val,
711fc843a02SSimon Glass (ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port)));
712fc843a02SSimon Glass
713fc843a02SSimon Glass #if defined(CONFIG_IDE_AHB)
714fc843a02SSimon Glass if (port) {
715fc843a02SSimon Glass /* write command */
716fc843a02SSimon Glass ide_write_register(dev, port, val);
717fc843a02SSimon Glass } else {
718fc843a02SSimon Glass /* write data */
719fc843a02SSimon Glass outb(val, (ATA_CURR_BASE(dev)));
720fc843a02SSimon Glass }
721fc843a02SSimon Glass #else
722fc843a02SSimon Glass outb(val, (ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port)));
723fc843a02SSimon Glass #endif
724fc843a02SSimon Glass }
725fc843a02SSimon Glass
ide_inb(int dev,int port)726fc843a02SSimon Glass __weak unsigned char ide_inb(int dev, int port)
727fc843a02SSimon Glass {
728fc843a02SSimon Glass uchar val;
729fc843a02SSimon Glass
730fc843a02SSimon Glass #if defined(CONFIG_IDE_AHB)
731fc843a02SSimon Glass val = ide_read_register(dev, port);
732fc843a02SSimon Glass #else
733fc843a02SSimon Glass val = inb((ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port)));
734fc843a02SSimon Glass #endif
735fc843a02SSimon Glass
736fc843a02SSimon Glass debug("ide_inb (dev= %d, port= 0x%x) : @ 0x%08lx -> 0x%02x\n",
737fc843a02SSimon Glass dev, port,
738fc843a02SSimon Glass (ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port)), val);
739fc843a02SSimon Glass return val;
740fc843a02SSimon Glass }
741fc843a02SSimon Glass
ide_init(void)742fc843a02SSimon Glass void ide_init(void)
743fc843a02SSimon Glass {
744fc843a02SSimon Glass unsigned char c;
745fc843a02SSimon Glass int i, bus;
746fc843a02SSimon Glass
747fc843a02SSimon Glass #ifdef CONFIG_IDE_PREINIT
748fc843a02SSimon Glass WATCHDOG_RESET();
749fc843a02SSimon Glass
750fc843a02SSimon Glass if (ide_preinit()) {
751fc843a02SSimon Glass puts("ide_preinit failed\n");
752fc843a02SSimon Glass return;
753fc843a02SSimon Glass }
754fc843a02SSimon Glass #endif /* CONFIG_IDE_PREINIT */
755fc843a02SSimon Glass
756fc843a02SSimon Glass WATCHDOG_RESET();
757fc843a02SSimon Glass
758fc843a02SSimon Glass /* ATAPI Drives seems to need a proper IDE Reset */
759fc843a02SSimon Glass ide_reset();
760fc843a02SSimon Glass
761fc843a02SSimon Glass /*
762fc843a02SSimon Glass * Wait for IDE to get ready.
763fc843a02SSimon Glass * According to spec, this can take up to 31 seconds!
764fc843a02SSimon Glass */
765fc843a02SSimon Glass for (bus = 0; bus < CONFIG_SYS_IDE_MAXBUS; ++bus) {
766fc843a02SSimon Glass int dev =
767fc843a02SSimon Glass bus * (CONFIG_SYS_IDE_MAXDEVICE /
768fc843a02SSimon Glass CONFIG_SYS_IDE_MAXBUS);
769fc843a02SSimon Glass
770fc843a02SSimon Glass printf("Bus %d: ", bus);
771fc843a02SSimon Glass
772fc843a02SSimon Glass ide_bus_ok[bus] = 0;
773fc843a02SSimon Glass
774fc843a02SSimon Glass /* Select device
775fc843a02SSimon Glass */
776fc843a02SSimon Glass udelay(100000); /* 100 ms */
777fc843a02SSimon Glass ide_outb(dev, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(dev));
778fc843a02SSimon Glass udelay(100000); /* 100 ms */
779fc843a02SSimon Glass i = 0;
780fc843a02SSimon Glass do {
781fc843a02SSimon Glass udelay(10000); /* 10 ms */
782fc843a02SSimon Glass
783fc843a02SSimon Glass c = ide_inb(dev, ATA_STATUS);
784fc843a02SSimon Glass i++;
785fc843a02SSimon Glass if (i > (ATA_RESET_TIME * 100)) {
786fc843a02SSimon Glass puts("** Timeout **\n");
787fc843a02SSimon Glass return;
788fc843a02SSimon Glass }
789fc843a02SSimon Glass if ((i >= 100) && ((i % 100) == 0))
790fc843a02SSimon Glass putc('.');
791fc843a02SSimon Glass
792fc843a02SSimon Glass } while (c & ATA_STAT_BUSY);
793fc843a02SSimon Glass
794fc843a02SSimon Glass if (c & (ATA_STAT_BUSY | ATA_STAT_FAULT)) {
795fc843a02SSimon Glass puts("not available ");
796fc843a02SSimon Glass debug("Status = 0x%02X ", c);
797fc843a02SSimon Glass #ifndef CONFIG_ATAPI /* ATAPI Devices do not set DRDY */
798fc843a02SSimon Glass } else if ((c & ATA_STAT_READY) == 0) {
799fc843a02SSimon Glass puts("not available ");
800fc843a02SSimon Glass debug("Status = 0x%02X ", c);
801fc843a02SSimon Glass #endif
802fc843a02SSimon Glass } else {
803fc843a02SSimon Glass puts("OK ");
804fc843a02SSimon Glass ide_bus_ok[bus] = 1;
805fc843a02SSimon Glass }
806fc843a02SSimon Glass WATCHDOG_RESET();
807fc843a02SSimon Glass }
808fc843a02SSimon Glass
809fc843a02SSimon Glass putc('\n');
810fc843a02SSimon Glass
811fc843a02SSimon Glass for (i = 0; i < CONFIG_SYS_IDE_MAXDEVICE; ++i) {
812fc843a02SSimon Glass ide_dev_desc[i].type = DEV_TYPE_UNKNOWN;
813fc843a02SSimon Glass ide_dev_desc[i].if_type = IF_TYPE_IDE;
814fc843a02SSimon Glass ide_dev_desc[i].devnum = i;
815fc843a02SSimon Glass ide_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
816fc843a02SSimon Glass ide_dev_desc[i].blksz = 0;
817fc843a02SSimon Glass ide_dev_desc[i].log2blksz =
818fc843a02SSimon Glass LOG2_INVALID(typeof(ide_dev_desc[i].log2blksz));
819fc843a02SSimon Glass ide_dev_desc[i].lba = 0;
820fc843a02SSimon Glass #ifndef CONFIG_BLK
821fc843a02SSimon Glass ide_dev_desc[i].block_read = ide_read;
822fc843a02SSimon Glass ide_dev_desc[i].block_write = ide_write;
823fc843a02SSimon Glass #endif
824fc843a02SSimon Glass if (!ide_bus_ok[IDE_BUS(i)])
825fc843a02SSimon Glass continue;
826fc843a02SSimon Glass ide_ident(&ide_dev_desc[i]);
827fc843a02SSimon Glass dev_print(&ide_dev_desc[i]);
828fc843a02SSimon Glass
82968e6f221SBin Meng #ifndef CONFIG_BLK
830fc843a02SSimon Glass if ((ide_dev_desc[i].lba > 0) && (ide_dev_desc[i].blksz > 0)) {
831fc843a02SSimon Glass /* initialize partition type */
832fc843a02SSimon Glass part_init(&ide_dev_desc[i]);
833fc843a02SSimon Glass }
83468e6f221SBin Meng #endif
835fc843a02SSimon Glass }
836fc843a02SSimon Glass WATCHDOG_RESET();
83768e6f221SBin Meng
83868e6f221SBin Meng #ifdef CONFIG_BLK
83968e6f221SBin Meng struct udevice *dev;
84068e6f221SBin Meng
84168e6f221SBin Meng uclass_first_device(UCLASS_IDE, &dev);
84268e6f221SBin Meng #endif
843fc843a02SSimon Glass }
844fc843a02SSimon Glass
845fc843a02SSimon Glass /* We only need to swap data if we are running on a big endian cpu. */
846fc843a02SSimon Glass #if defined(__LITTLE_ENDIAN)
ide_input_swap_data(int dev,ulong * sect_buf,int words)847fc843a02SSimon Glass __weak void ide_input_swap_data(int dev, ulong *sect_buf, int words)
848fc843a02SSimon Glass {
849fc843a02SSimon Glass ide_input_data(dev, sect_buf, words);
850fc843a02SSimon Glass }
851fc843a02SSimon Glass #else
ide_input_swap_data(int dev,ulong * sect_buf,int words)852fc843a02SSimon Glass __weak void ide_input_swap_data(int dev, ulong *sect_buf, int words)
853fc843a02SSimon Glass {
854fc843a02SSimon Glass volatile ushort *pbuf =
855fc843a02SSimon Glass (ushort *)(ATA_CURR_BASE(dev) + ATA_DATA_REG);
856fc843a02SSimon Glass ushort *dbuf = (ushort *)sect_buf;
857fc843a02SSimon Glass
858fc843a02SSimon Glass debug("in input swap data base for read is %lx\n",
859fc843a02SSimon Glass (unsigned long) pbuf);
860fc843a02SSimon Glass
861fc843a02SSimon Glass while (words--) {
862fc843a02SSimon Glass #ifdef __MIPS__
863fc843a02SSimon Glass *dbuf++ = swab16p((u16 *)pbuf);
864fc843a02SSimon Glass *dbuf++ = swab16p((u16 *)pbuf);
865fc843a02SSimon Glass #else
866fc843a02SSimon Glass *dbuf++ = ld_le16(pbuf);
867fc843a02SSimon Glass *dbuf++ = ld_le16(pbuf);
868fc843a02SSimon Glass #endif /* !MIPS */
869fc843a02SSimon Glass }
870fc843a02SSimon Glass }
871fc843a02SSimon Glass #endif /* __LITTLE_ENDIAN */
872fc843a02SSimon Glass
873fc843a02SSimon Glass
874fc843a02SSimon Glass #if defined(CONFIG_IDE_SWAP_IO)
ide_output_data(int dev,const ulong * sect_buf,int words)875fc843a02SSimon Glass __weak void ide_output_data(int dev, const ulong *sect_buf, int words)
876fc843a02SSimon Glass {
877fc843a02SSimon Glass ushort *dbuf;
878fc843a02SSimon Glass volatile ushort *pbuf;
879fc843a02SSimon Glass
880fc843a02SSimon Glass pbuf = (ushort *)(ATA_CURR_BASE(dev) + ATA_DATA_REG);
881fc843a02SSimon Glass dbuf = (ushort *)sect_buf;
882fc843a02SSimon Glass while (words--) {
883fc843a02SSimon Glass EIEIO;
884fc843a02SSimon Glass *pbuf = *dbuf++;
885fc843a02SSimon Glass EIEIO;
886fc843a02SSimon Glass *pbuf = *dbuf++;
887fc843a02SSimon Glass }
888fc843a02SSimon Glass }
889fc843a02SSimon Glass #else /* ! CONFIG_IDE_SWAP_IO */
ide_output_data(int dev,const ulong * sect_buf,int words)890fc843a02SSimon Glass __weak void ide_output_data(int dev, const ulong *sect_buf, int words)
891fc843a02SSimon Glass {
892fc843a02SSimon Glass #if defined(CONFIG_IDE_AHB)
893fc843a02SSimon Glass ide_write_data(dev, sect_buf, words);
894fc843a02SSimon Glass #else
895fc843a02SSimon Glass outsw(ATA_CURR_BASE(dev) + ATA_DATA_REG, sect_buf, words << 1);
896fc843a02SSimon Glass #endif
897fc843a02SSimon Glass }
898fc843a02SSimon Glass #endif /* CONFIG_IDE_SWAP_IO */
899fc843a02SSimon Glass
900fc843a02SSimon Glass #if defined(CONFIG_IDE_SWAP_IO)
ide_input_data(int dev,ulong * sect_buf,int words)901fc843a02SSimon Glass __weak void ide_input_data(int dev, ulong *sect_buf, int words)
902fc843a02SSimon Glass {
903fc843a02SSimon Glass ushort *dbuf;
904fc843a02SSimon Glass volatile ushort *pbuf;
905fc843a02SSimon Glass
906fc843a02SSimon Glass pbuf = (ushort *)(ATA_CURR_BASE(dev) + ATA_DATA_REG);
907fc843a02SSimon Glass dbuf = (ushort *)sect_buf;
908fc843a02SSimon Glass
909fc843a02SSimon Glass debug("in input data base for read is %lx\n", (unsigned long) pbuf);
910fc843a02SSimon Glass
911fc843a02SSimon Glass while (words--) {
912fc843a02SSimon Glass EIEIO;
913fc843a02SSimon Glass *dbuf++ = *pbuf;
914fc843a02SSimon Glass EIEIO;
915fc843a02SSimon Glass *dbuf++ = *pbuf;
916fc843a02SSimon Glass }
917fc843a02SSimon Glass }
918fc843a02SSimon Glass #else /* ! CONFIG_IDE_SWAP_IO */
ide_input_data(int dev,ulong * sect_buf,int words)919fc843a02SSimon Glass __weak void ide_input_data(int dev, ulong *sect_buf, int words)
920fc843a02SSimon Glass {
921fc843a02SSimon Glass #if defined(CONFIG_IDE_AHB)
922fc843a02SSimon Glass ide_read_data(dev, sect_buf, words);
923fc843a02SSimon Glass #else
924fc843a02SSimon Glass insw(ATA_CURR_BASE(dev) + ATA_DATA_REG, sect_buf, words << 1);
925fc843a02SSimon Glass #endif
926fc843a02SSimon Glass }
927fc843a02SSimon Glass
928fc843a02SSimon Glass #endif /* CONFIG_IDE_SWAP_IO */
929fc843a02SSimon Glass
930fc843a02SSimon Glass #ifdef CONFIG_BLK
ide_read(struct udevice * dev,lbaint_t blknr,lbaint_t blkcnt,void * buffer)931fc843a02SSimon Glass ulong ide_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
932fc843a02SSimon Glass void *buffer)
933fc843a02SSimon Glass #else
934fc843a02SSimon Glass ulong ide_read(struct blk_desc *block_dev, lbaint_t blknr, lbaint_t blkcnt,
935fc843a02SSimon Glass void *buffer)
936fc843a02SSimon Glass #endif
937fc843a02SSimon Glass {
938fc843a02SSimon Glass #ifdef CONFIG_BLK
939fc843a02SSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
940fc843a02SSimon Glass #endif
941fc843a02SSimon Glass int device = block_dev->devnum;
942fc843a02SSimon Glass ulong n = 0;
943fc843a02SSimon Glass unsigned char c;
944fc843a02SSimon Glass unsigned char pwrsave = 0; /* power save */
945fc843a02SSimon Glass
946fc843a02SSimon Glass #ifdef CONFIG_LBA48
947fc843a02SSimon Glass unsigned char lba48 = 0;
948fc843a02SSimon Glass
949fc843a02SSimon Glass if (blknr & 0x0000fffff0000000ULL) {
950fc843a02SSimon Glass /* more than 28 bits used, use 48bit mode */
951fc843a02SSimon Glass lba48 = 1;
952fc843a02SSimon Glass }
953fc843a02SSimon Glass #endif
954fc843a02SSimon Glass debug("ide_read dev %d start " LBAF ", blocks " LBAF " buffer at %lX\n",
955fc843a02SSimon Glass device, blknr, blkcnt, (ulong) buffer);
956fc843a02SSimon Glass
957fc843a02SSimon Glass /* Select device
958fc843a02SSimon Glass */
959fc843a02SSimon Glass ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
960fc843a02SSimon Glass c = ide_wait(device, IDE_TIME_OUT);
961fc843a02SSimon Glass
962fc843a02SSimon Glass if (c & ATA_STAT_BUSY) {
963fc843a02SSimon Glass printf("IDE read: device %d not ready\n", device);
964fc843a02SSimon Glass goto IDE_READ_E;
965fc843a02SSimon Glass }
966fc843a02SSimon Glass
967fc843a02SSimon Glass /* first check if the drive is in Powersaving mode, if yes,
968fc843a02SSimon Glass * increase the timeout value */
969fc843a02SSimon Glass ide_outb(device, ATA_COMMAND, ATA_CMD_CHK_PWR);
970fc843a02SSimon Glass udelay(50);
971fc843a02SSimon Glass
972fc843a02SSimon Glass c = ide_wait(device, IDE_TIME_OUT); /* can't take over 500 ms */
973fc843a02SSimon Glass
974fc843a02SSimon Glass if (c & ATA_STAT_BUSY) {
975fc843a02SSimon Glass printf("IDE read: device %d not ready\n", device);
976fc843a02SSimon Glass goto IDE_READ_E;
977fc843a02SSimon Glass }
978fc843a02SSimon Glass if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) {
979fc843a02SSimon Glass printf("No Powersaving mode %X\n", c);
980fc843a02SSimon Glass } else {
981fc843a02SSimon Glass c = ide_inb(device, ATA_SECT_CNT);
982fc843a02SSimon Glass debug("Powersaving %02X\n", c);
983fc843a02SSimon Glass if (c == 0)
984fc843a02SSimon Glass pwrsave = 1;
985fc843a02SSimon Glass }
986fc843a02SSimon Glass
987fc843a02SSimon Glass
988fc843a02SSimon Glass while (blkcnt-- > 0) {
989fc843a02SSimon Glass c = ide_wait(device, IDE_TIME_OUT);
990fc843a02SSimon Glass
991fc843a02SSimon Glass if (c & ATA_STAT_BUSY) {
992fc843a02SSimon Glass printf("IDE read: device %d not ready\n", device);
993fc843a02SSimon Glass break;
994fc843a02SSimon Glass }
995fc843a02SSimon Glass #ifdef CONFIG_LBA48
996fc843a02SSimon Glass if (lba48) {
997fc843a02SSimon Glass /* write high bits */
998fc843a02SSimon Glass ide_outb(device, ATA_SECT_CNT, 0);
999fc843a02SSimon Glass ide_outb(device, ATA_LBA_LOW, (blknr >> 24) & 0xFF);
1000fc843a02SSimon Glass #ifdef CONFIG_SYS_64BIT_LBA
1001fc843a02SSimon Glass ide_outb(device, ATA_LBA_MID, (blknr >> 32) & 0xFF);
1002fc843a02SSimon Glass ide_outb(device, ATA_LBA_HIGH, (blknr >> 40) & 0xFF);
1003fc843a02SSimon Glass #else
1004fc843a02SSimon Glass ide_outb(device, ATA_LBA_MID, 0);
1005fc843a02SSimon Glass ide_outb(device, ATA_LBA_HIGH, 0);
1006fc843a02SSimon Glass #endif
1007fc843a02SSimon Glass }
1008fc843a02SSimon Glass #endif
1009fc843a02SSimon Glass ide_outb(device, ATA_SECT_CNT, 1);
1010fc843a02SSimon Glass ide_outb(device, ATA_LBA_LOW, (blknr >> 0) & 0xFF);
1011fc843a02SSimon Glass ide_outb(device, ATA_LBA_MID, (blknr >> 8) & 0xFF);
1012fc843a02SSimon Glass ide_outb(device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF);
1013fc843a02SSimon Glass
1014fc843a02SSimon Glass #ifdef CONFIG_LBA48
1015fc843a02SSimon Glass if (lba48) {
1016fc843a02SSimon Glass ide_outb(device, ATA_DEV_HD,
1017fc843a02SSimon Glass ATA_LBA | ATA_DEVICE(device));
1018fc843a02SSimon Glass ide_outb(device, ATA_COMMAND, ATA_CMD_READ_EXT);
1019fc843a02SSimon Glass
1020fc843a02SSimon Glass } else
1021fc843a02SSimon Glass #endif
1022fc843a02SSimon Glass {
1023fc843a02SSimon Glass ide_outb(device, ATA_DEV_HD, ATA_LBA |
1024fc843a02SSimon Glass ATA_DEVICE(device) | ((blknr >> 24) & 0xF));
1025fc843a02SSimon Glass ide_outb(device, ATA_COMMAND, ATA_CMD_READ);
1026fc843a02SSimon Glass }
1027fc843a02SSimon Glass
1028fc843a02SSimon Glass udelay(50);
1029fc843a02SSimon Glass
1030fc843a02SSimon Glass if (pwrsave) {
1031fc843a02SSimon Glass /* may take up to 4 sec */
1032fc843a02SSimon Glass c = ide_wait(device, IDE_SPIN_UP_TIME_OUT);
1033fc843a02SSimon Glass pwrsave = 0;
1034fc843a02SSimon Glass } else {
1035fc843a02SSimon Glass /* can't take over 500 ms */
1036fc843a02SSimon Glass c = ide_wait(device, IDE_TIME_OUT);
1037fc843a02SSimon Glass }
1038fc843a02SSimon Glass
1039fc843a02SSimon Glass if ((c & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) !=
1040fc843a02SSimon Glass ATA_STAT_DRQ) {
1041fc843a02SSimon Glass printf("Error (no IRQ) dev %d blk " LBAF
1042fc843a02SSimon Glass ": status %#02x\n", device, blknr, c);
1043fc843a02SSimon Glass break;
1044fc843a02SSimon Glass }
1045fc843a02SSimon Glass
1046fc843a02SSimon Glass ide_input_data(device, buffer, ATA_SECTORWORDS);
1047fc843a02SSimon Glass (void) ide_inb(device, ATA_STATUS); /* clear IRQ */
1048fc843a02SSimon Glass
1049fc843a02SSimon Glass ++n;
1050fc843a02SSimon Glass ++blknr;
1051fc843a02SSimon Glass buffer += ATA_BLOCKSIZE;
1052fc843a02SSimon Glass }
1053fc843a02SSimon Glass IDE_READ_E:
1054fc843a02SSimon Glass return n;
1055fc843a02SSimon Glass }
1056fc843a02SSimon Glass
1057fc843a02SSimon Glass #ifdef CONFIG_BLK
ide_write(struct udevice * dev,lbaint_t blknr,lbaint_t blkcnt,const void * buffer)1058fc843a02SSimon Glass ulong ide_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
1059fc843a02SSimon Glass const void *buffer)
1060fc843a02SSimon Glass #else
1061fc843a02SSimon Glass ulong ide_write(struct blk_desc *block_dev, lbaint_t blknr, lbaint_t blkcnt,
1062fc843a02SSimon Glass const void *buffer)
1063fc843a02SSimon Glass #endif
1064fc843a02SSimon Glass {
1065fc843a02SSimon Glass #ifdef CONFIG_BLK
1066fc843a02SSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
1067fc843a02SSimon Glass #endif
1068fc843a02SSimon Glass int device = block_dev->devnum;
1069fc843a02SSimon Glass ulong n = 0;
1070fc843a02SSimon Glass unsigned char c;
1071fc843a02SSimon Glass
1072fc843a02SSimon Glass #ifdef CONFIG_LBA48
1073fc843a02SSimon Glass unsigned char lba48 = 0;
1074fc843a02SSimon Glass
1075fc843a02SSimon Glass if (blknr & 0x0000fffff0000000ULL) {
1076fc843a02SSimon Glass /* more than 28 bits used, use 48bit mode */
1077fc843a02SSimon Glass lba48 = 1;
1078fc843a02SSimon Glass }
1079fc843a02SSimon Glass #endif
1080fc843a02SSimon Glass
1081fc843a02SSimon Glass /* Select device
1082fc843a02SSimon Glass */
1083fc843a02SSimon Glass ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
1084fc843a02SSimon Glass
1085fc843a02SSimon Glass while (blkcnt-- > 0) {
1086fc843a02SSimon Glass c = ide_wait(device, IDE_TIME_OUT);
1087fc843a02SSimon Glass
1088fc843a02SSimon Glass if (c & ATA_STAT_BUSY) {
1089fc843a02SSimon Glass printf("IDE read: device %d not ready\n", device);
1090fc843a02SSimon Glass goto WR_OUT;
1091fc843a02SSimon Glass }
1092fc843a02SSimon Glass #ifdef CONFIG_LBA48
1093fc843a02SSimon Glass if (lba48) {
1094fc843a02SSimon Glass /* write high bits */
1095fc843a02SSimon Glass ide_outb(device, ATA_SECT_CNT, 0);
1096fc843a02SSimon Glass ide_outb(device, ATA_LBA_LOW, (blknr >> 24) & 0xFF);
1097fc843a02SSimon Glass #ifdef CONFIG_SYS_64BIT_LBA
1098fc843a02SSimon Glass ide_outb(device, ATA_LBA_MID, (blknr >> 32) & 0xFF);
1099fc843a02SSimon Glass ide_outb(device, ATA_LBA_HIGH, (blknr >> 40) & 0xFF);
1100fc843a02SSimon Glass #else
1101fc843a02SSimon Glass ide_outb(device, ATA_LBA_MID, 0);
1102fc843a02SSimon Glass ide_outb(device, ATA_LBA_HIGH, 0);
1103fc843a02SSimon Glass #endif
1104fc843a02SSimon Glass }
1105fc843a02SSimon Glass #endif
1106fc843a02SSimon Glass ide_outb(device, ATA_SECT_CNT, 1);
1107fc843a02SSimon Glass ide_outb(device, ATA_LBA_LOW, (blknr >> 0) & 0xFF);
1108fc843a02SSimon Glass ide_outb(device, ATA_LBA_MID, (blknr >> 8) & 0xFF);
1109fc843a02SSimon Glass ide_outb(device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF);
1110fc843a02SSimon Glass
1111fc843a02SSimon Glass #ifdef CONFIG_LBA48
1112fc843a02SSimon Glass if (lba48) {
1113fc843a02SSimon Glass ide_outb(device, ATA_DEV_HD,
1114fc843a02SSimon Glass ATA_LBA | ATA_DEVICE(device));
1115fc843a02SSimon Glass ide_outb(device, ATA_COMMAND, ATA_CMD_WRITE_EXT);
1116fc843a02SSimon Glass
1117fc843a02SSimon Glass } else
1118fc843a02SSimon Glass #endif
1119fc843a02SSimon Glass {
1120fc843a02SSimon Glass ide_outb(device, ATA_DEV_HD, ATA_LBA |
1121fc843a02SSimon Glass ATA_DEVICE(device) | ((blknr >> 24) & 0xF));
1122fc843a02SSimon Glass ide_outb(device, ATA_COMMAND, ATA_CMD_WRITE);
1123fc843a02SSimon Glass }
1124fc843a02SSimon Glass
1125fc843a02SSimon Glass udelay(50);
1126fc843a02SSimon Glass
1127fc843a02SSimon Glass /* can't take over 500 ms */
1128fc843a02SSimon Glass c = ide_wait(device, IDE_TIME_OUT);
1129fc843a02SSimon Glass
1130fc843a02SSimon Glass if ((c & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) !=
1131fc843a02SSimon Glass ATA_STAT_DRQ) {
1132fc843a02SSimon Glass printf("Error (no IRQ) dev %d blk " LBAF
1133fc843a02SSimon Glass ": status %#02x\n", device, blknr, c);
1134fc843a02SSimon Glass goto WR_OUT;
1135fc843a02SSimon Glass }
1136fc843a02SSimon Glass
1137fc843a02SSimon Glass ide_output_data(device, buffer, ATA_SECTORWORDS);
1138fc843a02SSimon Glass c = ide_inb(device, ATA_STATUS); /* clear IRQ */
1139fc843a02SSimon Glass ++n;
1140fc843a02SSimon Glass ++blknr;
1141fc843a02SSimon Glass buffer += ATA_BLOCKSIZE;
1142fc843a02SSimon Glass }
1143fc843a02SSimon Glass WR_OUT:
1144fc843a02SSimon Glass return n;
1145fc843a02SSimon Glass }
1146fc843a02SSimon Glass
1147fc843a02SSimon Glass #if defined(CONFIG_OF_IDE_FIXUP)
ide_device_present(int dev)1148fc843a02SSimon Glass int ide_device_present(int dev)
1149fc843a02SSimon Glass {
1150fc843a02SSimon Glass if (dev >= CONFIG_SYS_IDE_MAXBUS)
1151fc843a02SSimon Glass return 0;
1152fc843a02SSimon Glass return ide_dev_desc[dev].type == DEV_TYPE_UNKNOWN ? 0 : 1;
1153fc843a02SSimon Glass }
1154fc843a02SSimon Glass #endif
1155fc843a02SSimon Glass
1156fc843a02SSimon Glass #ifdef CONFIG_BLK
ide_blk_probe(struct udevice * udev)115768e6f221SBin Meng static int ide_blk_probe(struct udevice *udev)
115868e6f221SBin Meng {
115968e6f221SBin Meng struct blk_desc *desc = dev_get_uclass_platdata(udev);
116068e6f221SBin Meng
116168e6f221SBin Meng /* fill in device vendor/product/rev strings */
116268e6f221SBin Meng strncpy(desc->vendor, ide_dev_desc[desc->devnum].vendor,
116368e6f221SBin Meng BLK_VEN_SIZE);
116468e6f221SBin Meng desc->vendor[BLK_VEN_SIZE] = '\0';
116568e6f221SBin Meng strncpy(desc->product, ide_dev_desc[desc->devnum].product,
116668e6f221SBin Meng BLK_PRD_SIZE);
116768e6f221SBin Meng desc->product[BLK_PRD_SIZE] = '\0';
116868e6f221SBin Meng strncpy(desc->revision, ide_dev_desc[desc->devnum].revision,
116968e6f221SBin Meng BLK_REV_SIZE);
117068e6f221SBin Meng desc->revision[BLK_REV_SIZE] = '\0';
117168e6f221SBin Meng
117268e6f221SBin Meng return 0;
117368e6f221SBin Meng }
117468e6f221SBin Meng
1175fc843a02SSimon Glass static const struct blk_ops ide_blk_ops = {
1176fc843a02SSimon Glass .read = ide_read,
1177fc843a02SSimon Glass .write = ide_write,
1178fc843a02SSimon Glass };
1179fc843a02SSimon Glass
1180fc843a02SSimon Glass U_BOOT_DRIVER(ide_blk) = {
1181fc843a02SSimon Glass .name = "ide_blk",
1182fc843a02SSimon Glass .id = UCLASS_BLK,
1183fc843a02SSimon Glass .ops = &ide_blk_ops,
118468e6f221SBin Meng .probe = ide_blk_probe,
118568e6f221SBin Meng };
118668e6f221SBin Meng
ide_probe(struct udevice * udev)118768e6f221SBin Meng static int ide_probe(struct udevice *udev)
118868e6f221SBin Meng {
118968e6f221SBin Meng struct udevice *blk_dev;
119068e6f221SBin Meng char name[20];
119168e6f221SBin Meng int blksz;
119268e6f221SBin Meng lbaint_t size;
119368e6f221SBin Meng int i;
119468e6f221SBin Meng int ret;
119568e6f221SBin Meng
119668e6f221SBin Meng for (i = 0; i < CONFIG_SYS_IDE_MAXDEVICE; i++) {
119768e6f221SBin Meng if (ide_dev_desc[i].type != DEV_TYPE_UNKNOWN) {
119868e6f221SBin Meng sprintf(name, "blk#%d", i);
119968e6f221SBin Meng
120068e6f221SBin Meng blksz = ide_dev_desc[i].blksz;
120168e6f221SBin Meng size = blksz * ide_dev_desc[i].lba;
12021f4adab8SBin Meng
12031f4adab8SBin Meng /*
12041f4adab8SBin Meng * With CDROM, if there is no CD inserted, blksz will
12051f4adab8SBin Meng * be zero, don't bother to create IDE block device.
12061f4adab8SBin Meng */
12071f4adab8SBin Meng if (!blksz)
12081f4adab8SBin Meng continue;
120968e6f221SBin Meng ret = blk_create_devicef(udev, "ide_blk", name,
121068e6f221SBin Meng IF_TYPE_IDE, i,
121168e6f221SBin Meng blksz, size, &blk_dev);
121268e6f221SBin Meng if (ret)
121368e6f221SBin Meng return ret;
121468e6f221SBin Meng }
121568e6f221SBin Meng }
121668e6f221SBin Meng
121768e6f221SBin Meng return 0;
121868e6f221SBin Meng }
121968e6f221SBin Meng
122068e6f221SBin Meng U_BOOT_DRIVER(ide) = {
122168e6f221SBin Meng .name = "ide",
122268e6f221SBin Meng .id = UCLASS_IDE,
122368e6f221SBin Meng .probe = ide_probe,
122468e6f221SBin Meng };
122568e6f221SBin Meng
122668e6f221SBin Meng struct pci_device_id ide_supported[] = {
122768e6f221SBin Meng { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_IDE << 8, 0xffff00) },
122868e6f221SBin Meng { }
122968e6f221SBin Meng };
123068e6f221SBin Meng
123168e6f221SBin Meng U_BOOT_PCI_DEVICE(ide, ide_supported);
123268e6f221SBin Meng
123368e6f221SBin Meng UCLASS_DRIVER(ide) = {
123468e6f221SBin Meng .name = "ide",
123568e6f221SBin Meng .id = UCLASS_IDE,
1236fc843a02SSimon Glass };
1237fc843a02SSimon Glass #else
1238fc843a02SSimon Glass U_BOOT_LEGACY_BLK(ide) = {
1239fc843a02SSimon Glass .if_typename = "ide",
1240fc843a02SSimon Glass .if_type = IF_TYPE_IDE,
1241fc843a02SSimon Glass .max_devs = CONFIG_SYS_IDE_MAXDEVICE,
1242fc843a02SSimon Glass .desc = ide_dev_desc,
1243fc843a02SSimon Glass };
1244fc843a02SSimon Glass #endif
1245