xref: /rk3399_rockchip-uboot/drivers/block/ide.c (revision 1f4adab8733b29f81d21f74e2194bd8ddb80e574)
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