xref: /openbmc/u-boot/drivers/block/ide.c (revision 1d6edcbfed2af33c748f2beb399810a0441888da)
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