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