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