xref: /openbmc/u-boot/cmd/fdc.c (revision 9b5dbe13)
1  /*
2   * (C) Copyright 2001
3   * Denis Peter, MPL AG, d.peter@mpl.ch.
4   *
5   * SPDX-License-Identifier:	GPL-2.0+
6   */
7  /*
8   * Floppy Disk support
9   */
10  
11  #include <common.h>
12  #include <config.h>
13  #include <command.h>
14  #include <image.h>
15  
16  
17  #undef	FDC_DEBUG
18  
19  #ifdef	FDC_DEBUG
20  #define	PRINTF(fmt,args...)	printf (fmt ,##args)
21  #else
22  #define PRINTF(fmt,args...)
23  #endif
24  
25  /*#if defined(CONFIG_CMD_DATE) */
26  /*#include <rtc.h> */
27  /*#endif */
28  
29  typedef struct {
30  	int		flags;		/* connected drives ect */
31  	unsigned long	blnr;		/* Logical block nr */
32  	uchar		drive;		/* drive no */
33  	uchar		cmdlen;		/* cmd length */
34  	uchar		cmd[16];	/* cmd desc */
35  	uchar		dma;		/* if > 0 dma enabled */
36  	uchar		result[11];	/* status information */
37  	uchar		resultlen;	/* lenght of result */
38  } FDC_COMMAND_STRUCT;
39  
40  /* flags: only the lower 8bit used:
41   * bit 0 if set drive 0 is present
42   * bit 1 if set drive 1 is present
43   * bit 2 if set drive 2 is present
44   * bit 3 if set drive 3 is present
45   * bit 4 if set disk in drive 0 is inserted
46   * bit 5 if set disk in drive 1 is inserted
47   * bit 6 if set disk in drive 2 is inserted
48   * bit 7 if set disk in drive 4 is inserted
49   */
50  
51  /* cmd indexes */
52  #define COMMAND			0
53  #define DRIVE			1
54  #define CONFIG0			1
55  #define SPEC_HUTSRT		1
56  #define TRACK			2
57  #define CONFIG1			2
58  #define SPEC_HLT		2
59  #define HEAD			3
60  #define CONFIG2			3
61  #define SECTOR			4
62  #define SECTOR_SIZE		5
63  #define LAST_TRACK		6
64  #define GAP			7
65  #define DTL			8
66  /* result indexes */
67  #define STATUS_0		0
68  #define STATUS_PCN		1
69  #define STATUS_1		1
70  #define STATUS_2		2
71  #define STATUS_TRACK		3
72  #define STATUS_HEAD		4
73  #define STATUS_SECT		5
74  #define STATUS_SECT_SIZE	6
75  
76  
77  /* Register addresses */
78  #define FDC_BASE	0x3F0
79  #define FDC_SRA		FDC_BASE + 0	/* Status Register A */
80  #define FDC_SRB		FDC_BASE + 1	/* Status Register B */
81  #define FDC_DOR		FDC_BASE + 2	/* Digital Output Register */
82  #define FDC_TDR		FDC_BASE + 3	/* Tape Drive Register */
83  #define FDC_DSR		FDC_BASE + 4	/* Data rate Register */
84  #define FDC_MSR		FDC_BASE + 4	/* Main Status Register */
85  #define FDC_FIFO	FDC_BASE + 5	/* FIFO */
86  #define FDC_DIR		FDC_BASE + 6	/* Digital Input Register */
87  #define FDC_CCR		FDC_BASE + 7	/* Configuration Control */
88  /* Commands */
89  #define FDC_CMD_SENSE_INT	0x08
90  #define FDC_CMD_CONFIGURE	0x13
91  #define FDC_CMD_SPECIFY		0x03
92  #define FDC_CMD_RECALIBRATE	0x07
93  #define FDC_CMD_READ		0x06
94  #define FDC_CMD_READ_TRACK	0x02
95  #define FDC_CMD_READ_ID		0x0A
96  #define FDC_CMD_DUMP_REG	0x0E
97  #define FDC_CMD_SEEK		0x0F
98  
99  #define FDC_CMD_SENSE_INT_LEN	0x01
100  #define FDC_CMD_CONFIGURE_LEN	0x04
101  #define FDC_CMD_SPECIFY_LEN	0x03
102  #define FDC_CMD_RECALIBRATE_LEN	0x02
103  #define FDC_CMD_READ_LEN	0x09
104  #define FDC_CMD_READ_TRACK_LEN	0x09
105  #define FDC_CMD_READ_ID_LEN	0x02
106  #define FDC_CMD_DUMP_REG_LEN	0x01
107  #define FDC_CMD_SEEK_LEN	0x03
108  
109  #define FDC_FIFO_THR		0x0C
110  #define FDC_FIFO_DIS		0x00
111  #define FDC_IMPLIED_SEEK	0x01
112  #define FDC_POLL_DIS		0x00
113  #define FDC_PRE_TRK		0x00
114  #define FDC_CONFIGURE		FDC_FIFO_THR | (FDC_POLL_DIS<<4) | (FDC_FIFO_DIS<<5) | (FDC_IMPLIED_SEEK << 6)
115  #define FDC_MFM_MODE		0x01 /* MFM enable */
116  #define FDC_SKIP_MODE		0x00 /* skip enable */
117  
118  #define FDC_TIME_OUT 100000 /* time out */
119  #define	FDC_RW_RETRIES		3 /* read write retries */
120  #define FDC_CAL_RETRIES		3 /* calibration and seek retries */
121  
122  
123  /* Disk structure */
124  typedef struct  {
125  	unsigned int size;	/* nr of sectors total */
126  	unsigned int sect;	/* sectors per track */
127  	unsigned int head;	/* nr of heads */
128  	unsigned int track;	/* nr of tracks */
129  	unsigned int stretch;	/* !=0 means double track steps */
130  	unsigned char	gap;	/* gap1 size */
131  	unsigned char	rate;	/* data rate. |= 0x40 for perpendicular */
132  	unsigned char	spec1;	/* stepping rate, head unload time */
133  	unsigned char	fmt_gap;/* gap2 size */
134  	unsigned char hlt;	/* head load time */
135  	unsigned char sect_code;/* Sector Size code */
136  	const char	* name;	/* used only for predefined formats */
137  } FD_GEO_STRUCT;
138  
139  
140  /* supported Floppy types (currently only one) */
141  const static FD_GEO_STRUCT floppy_type[2] = {
142  	{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,16,2,"H1440" },	/*  7 1.44MB 3.5"   */
143  	{    0, 0,0, 0,0,0x00,0x00,0x00,0x00, 0,0,NULL    },	/*  end of table    */
144  };
145  
146  static FDC_COMMAND_STRUCT cmd; /* global command struct */
147  
148  /* If the boot drive number is undefined, we assume it's drive 0             */
149  #ifndef CONFIG_SYS_FDC_DRIVE_NUMBER
150  #define CONFIG_SYS_FDC_DRIVE_NUMBER 0
151  #endif
152  
153  /* Hardware access */
154  #ifndef CONFIG_SYS_ISA_IO_STRIDE
155  #define CONFIG_SYS_ISA_IO_STRIDE 1
156  #endif
157  
158  #ifndef CONFIG_SYS_ISA_IO_OFFSET
159  #define CONFIG_SYS_ISA_IO_OFFSET 0
160  #endif
161  
162  /* Supporting Functions */
163  /* reads a Register of the FDC */
164  unsigned char read_fdc_reg(unsigned int addr)
165  {
166  	volatile unsigned char *val =
167  		(volatile unsigned char *)(CONFIG_SYS_ISA_IO_BASE_ADDRESS +
168  					   (addr * CONFIG_SYS_ISA_IO_STRIDE) +
169  					   CONFIG_SYS_ISA_IO_OFFSET);
170  
171  	return val [0];
172  }
173  
174  /* writes a Register of the FDC */
175  void write_fdc_reg(unsigned int addr, unsigned char val)
176  {
177  	volatile unsigned char *tmp =
178  		(volatile unsigned char *)(CONFIG_SYS_ISA_IO_BASE_ADDRESS +
179  					   (addr * CONFIG_SYS_ISA_IO_STRIDE) +
180  					   CONFIG_SYS_ISA_IO_OFFSET);
181  	tmp[0]=val;
182  }
183  
184  /* waits for an interrupt (polling) */
185  int wait_for_fdc_int(void)
186  {
187  	unsigned long timeout;
188  	timeout = FDC_TIME_OUT;
189  	while((read_fdc_reg(FDC_SRA)&0x80)==0) {
190  		timeout--;
191  		udelay(10);
192  		if(timeout==0) /* timeout occured */
193  			return false;
194  	}
195  	return true;
196  }
197  
198  /* reads a byte from the FIFO of the FDC and checks direction and RQM bit
199     of the MSR. returns -1 if timeout, or byte if ok */
200  int read_fdc_byte(void)
201  {
202  	unsigned long timeout;
203  	timeout = FDC_TIME_OUT;
204  	while((read_fdc_reg(FDC_MSR)&0xC0)!=0xC0) {
205  		/* direction out and ready */
206  		udelay(10);
207  		timeout--;
208  		if(timeout==0) /* timeout occured */
209  			return -1;
210  	}
211  	return read_fdc_reg(FDC_FIFO);
212  }
213  
214  /* if the direction of the FIFO is wrong, this routine is used to
215     empty the FIFO. Should _not_ be used */
216  int fdc_need_more_output(void)
217  {
218  	unsigned char c;
219  	while((read_fdc_reg(FDC_MSR)&0xC0)==0xC0)	{
220  			c=(unsigned char)read_fdc_byte();
221  			printf("Error: more output: %x\n",c);
222  	}
223  	return true;
224  }
225  
226  
227  /* writes a byte to the FIFO of the FDC and checks direction and RQM bit
228     of the MSR */
229  int write_fdc_byte(unsigned char val)
230  {
231  	unsigned long timeout;
232  	timeout = FDC_TIME_OUT;
233  	while((read_fdc_reg(FDC_MSR)&0xC0)!=0x80) {
234  		/* direction in and ready for byte */
235  		timeout--;
236  		udelay(10);
237  		fdc_need_more_output();
238  		if(timeout==0) /* timeout occured */
239  			return false;
240  	}
241  	write_fdc_reg(FDC_FIFO,val);
242  	return true;
243  }
244  
245  /* sets up all FDC commands and issues it to the FDC. If
246     the command causes direct results (no Execution Phase)
247     the result is be read as well. */
248  
249  int fdc_issue_cmd(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG)
250  {
251  	int i;
252  	unsigned long head,track,sect,timeout;
253  	track = pCMD->blnr / (pFG->sect * pFG->head); /* track nr */
254  	sect =  pCMD->blnr % (pFG->sect * pFG->head); /* remaining blocks */
255  	head = sect / pFG->sect; /* head nr */
256  	sect =  sect % pFG->sect; /* remaining blocks */
257  	sect++; /* sectors are 1 based */
258  	PRINTF("Cmd 0x%02x Track %ld, Head %ld, Sector %ld, Drive %d (blnr %ld)\n",
259  		pCMD->cmd[0],track,head,sect,pCMD->drive,pCMD->blnr);
260  
261  	if(head|=0) { /* max heads = 2 */
262  		pCMD->cmd[DRIVE]=pCMD->drive | 0x04; /* head 1 */
263  		pCMD->cmd[HEAD]=(unsigned char) head; /* head register */
264  	}
265  	else {
266  		pCMD->cmd[DRIVE]=pCMD->drive; /* head 0 */
267  		pCMD->cmd[HEAD]=(unsigned char) head; /* head register */
268  	}
269  	pCMD->cmd[TRACK]=(unsigned char) track; /* track */
270  	switch (pCMD->cmd[COMMAND]) {
271  		case FDC_CMD_READ:
272  			pCMD->cmd[SECTOR]=(unsigned char) sect; /* sector */
273  			pCMD->cmd[SECTOR_SIZE]=pFG->sect_code; /* sector size code */
274  			pCMD->cmd[LAST_TRACK]=pFG->sect; /* End of track */
275  			pCMD->cmd[GAP]=pFG->gap; /* gap */
276  			pCMD->cmd[DTL]=0xFF; /* DTL */
277  			pCMD->cmdlen=FDC_CMD_READ_LEN;
278  			pCMD->cmd[COMMAND]|=(FDC_MFM_MODE<<6); /* set MFM bit */
279  			pCMD->cmd[COMMAND]|=(FDC_SKIP_MODE<<5); /* set Skip bit */
280  			pCMD->resultlen=0;  /* result only after execution */
281  			break;
282  		case FDC_CMD_SEEK:
283  			pCMD->cmdlen=FDC_CMD_SEEK_LEN;
284  			pCMD->resultlen=0;  /* no result */
285  			break;
286  		case FDC_CMD_CONFIGURE:
287  			pCMD->cmd[CONFIG0]=0;
288  			pCMD->cmd[CONFIG1]=FDC_CONFIGURE; /* FIFO Threshold, Poll, Enable FIFO */
289  			pCMD->cmd[CONFIG2]=FDC_PRE_TRK;	/* Precompensation Track */
290  			pCMD->cmdlen=FDC_CMD_CONFIGURE_LEN;
291  			pCMD->resultlen=0;  /* no result */
292  			break;
293  		case FDC_CMD_SPECIFY:
294  			pCMD->cmd[SPEC_HUTSRT]=pFG->spec1;
295  			pCMD->cmd[SPEC_HLT]=(pFG->hlt)<<1; /* head load time */
296  			if(pCMD->dma==0)
297  				pCMD->cmd[SPEC_HLT]|=0x1; /* no dma */
298  			pCMD->cmdlen=FDC_CMD_SPECIFY_LEN;
299  			pCMD->resultlen=0;  /* no result */
300  			break;
301  		case FDC_CMD_DUMP_REG:
302  			pCMD->cmdlen=FDC_CMD_DUMP_REG_LEN;
303  			pCMD->resultlen=10;  /* 10 byte result */
304  			break;
305  		case FDC_CMD_READ_ID:
306  			pCMD->cmd[COMMAND]|=(FDC_MFM_MODE<<6); /* set MFM bit */
307  			pCMD->cmdlen=FDC_CMD_READ_ID_LEN;
308  			pCMD->resultlen=7;  /* 7 byte result */
309  			break;
310  		case FDC_CMD_RECALIBRATE:
311  			pCMD->cmd[DRIVE]&=0x03; /* don't set the head bit */
312  			pCMD->cmdlen=FDC_CMD_RECALIBRATE_LEN;
313  			pCMD->resultlen=0;  /* no result */
314  			break;
315  			break;
316  		case FDC_CMD_SENSE_INT:
317  			pCMD->cmdlen=FDC_CMD_SENSE_INT_LEN;
318  			pCMD->resultlen=2;
319  			break;
320  	}
321  	for(i=0;i<pCMD->cmdlen;i++) {
322  		/* PRINTF("write cmd%d = 0x%02X\n",i,pCMD->cmd[i]); */
323  		if (write_fdc_byte(pCMD->cmd[i]) == false) {
324  			PRINTF("Error: timeout while issue cmd%d\n",i);
325  			return false;
326  		}
327  	}
328  	timeout=FDC_TIME_OUT;
329  	for(i=0;i<pCMD->resultlen;i++) {
330  		while((read_fdc_reg(FDC_MSR)&0xC0)!=0xC0) {
331  			timeout--;
332  			if(timeout==0) {
333  				PRINTF(" timeout while reading result%d MSR=0x%02X\n",i,read_fdc_reg(FDC_MSR));
334  				return false;
335  			}
336  		}
337  		pCMD->result[i]=(unsigned char)read_fdc_byte();
338  	}
339  	return true;
340  }
341  
342  /* selects the drive assigned in the cmd structur and
343     switches on the Motor */
344  void select_fdc_drive(FDC_COMMAND_STRUCT *pCMD)
345  {
346  	unsigned char val;
347  
348  	val=(1<<(4+pCMD->drive))|pCMD->drive|0xC; /* set reset, dma gate and motor bits */
349  	if((read_fdc_reg(FDC_DOR)&val)!=val) {
350  		write_fdc_reg(FDC_DOR,val);
351  		for(val=0;val<255;val++)
352  			udelay(500); /* wait some time to start motor */
353  	}
354  }
355  
356  /* switches off the Motor of the specified drive */
357  void stop_fdc_drive(FDC_COMMAND_STRUCT *pCMD)
358  {
359  	unsigned char val;
360  
361  	val=(1<<(4+pCMD->drive))|pCMD->drive; /* sets motor bits */
362  	write_fdc_reg(FDC_DOR,(read_fdc_reg(FDC_DOR)&~val));
363  }
364  
365  /* issues a recalibrate command, waits for interrupt and
366   * issues a sense_interrupt */
367  int fdc_recalibrate(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG)
368  {
369  	pCMD->cmd[COMMAND]=FDC_CMD_RECALIBRATE;
370  	if (fdc_issue_cmd(pCMD, pFG) == false)
371  		return false;
372  	while (wait_for_fdc_int() != true);
373  
374  	pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT;
375  	return(fdc_issue_cmd(pCMD,pFG));
376  }
377  
378  /* issues a recalibrate command, waits for interrupt and
379   * issues a sense_interrupt */
380  int fdc_seek(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG)
381  {
382  	pCMD->cmd[COMMAND]=FDC_CMD_SEEK;
383  	if (fdc_issue_cmd(pCMD, pFG) == false)
384  		return false;
385  	while (wait_for_fdc_int() != true);
386  
387  	pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT;
388  	return(fdc_issue_cmd(pCMD,pFG));
389  }
390  
391  /* terminates current command, by not servicing the FIFO
392   * waits for interrupt and fills in the result bytes */
393  int fdc_terminate(FDC_COMMAND_STRUCT *pCMD)
394  {
395  	int i;
396  	for(i=0;i<100;i++)
397  		udelay(500); /* wait 500usec for fifo overrun */
398  	while((read_fdc_reg(FDC_SRA)&0x80)==0x00); /* wait as long as no int has occured */
399  	for(i=0;i<7;i++) {
400  		pCMD->result[i]=(unsigned char)read_fdc_byte();
401  	}
402  	return true;
403  }
404  
405  /* reads data from FDC, seek commands are issued automatic */
406  int fdc_read_data(unsigned char *buffer, unsigned long blocks,FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG)
407  {
408    /* first seek to start address */
409  	unsigned long len,readblk,i,timeout,ii,offset;
410  	unsigned char c,retriesrw,retriescal;
411  	unsigned char *bufferw; /* working buffer */
412  	int sect_size;
413  	int flags;
414  
415  	flags=disable_interrupts(); /* switch off all Interrupts */
416  	select_fdc_drive(pCMD); /* switch on drive */
417  	sect_size=0x080<<pFG->sect_code;
418  	retriesrw=0;
419  	retriescal=0;
420  	offset=0;
421  	if (fdc_seek(pCMD, pFG) == false) {
422  		stop_fdc_drive(pCMD);
423  		if (flags)
424  			enable_interrupts();
425  		return false;
426  	}
427  	if((pCMD->result[STATUS_0]&0x20)!=0x20) {
428  		printf("Seek error Status: %02X\n",pCMD->result[STATUS_0]);
429  		stop_fdc_drive(pCMD);
430  		if (flags)
431  			enable_interrupts();
432  		return false;
433  	}
434  	/* now determine the next seek point */
435  	/*	lastblk=pCMD->blnr + blocks; */
436  	/*	readblk=(pFG->head*pFG->sect)-(pCMD->blnr%(pFG->head*pFG->sect)); */
437  	readblk=pFG->sect-(pCMD->blnr%pFG->sect);
438  	PRINTF("1st nr of block possible read %ld start %ld\n",readblk,pCMD->blnr);
439  	if(readblk>blocks) /* is end within 1st track */
440  		readblk=blocks; /* yes, correct it */
441  	PRINTF("we read %ld blocks start %ld\n",readblk,pCMD->blnr);
442  	bufferw = &buffer[0]; /* setup working buffer */
443  	do {
444  retryrw:
445  		len=sect_size * readblk;
446  		pCMD->cmd[COMMAND]=FDC_CMD_READ;
447  		if (fdc_issue_cmd(pCMD, pFG) == false) {
448  			stop_fdc_drive(pCMD);
449  			if (flags)
450  				enable_interrupts();
451  			return false;
452  		}
453  		for (i=0;i<len;i++) {
454  			timeout=FDC_TIME_OUT;
455  			do {
456  				c=read_fdc_reg(FDC_MSR);
457  				if((c&0xC0)==0xC0) {
458  					bufferw[i]=read_fdc_reg(FDC_FIFO);
459  					break;
460  				}
461  				if((c&0xC0)==0x80) { /* output */
462  					PRINTF("Transfer error transfered: at %ld, MSR=%02X\n",i,c);
463  					if(i>6) {
464  						for(ii=0;ii<7;ii++) {
465  							pCMD->result[ii]=bufferw[(i-7+ii)];
466  						} /* for */
467  					}
468  					if(retriesrw++>FDC_RW_RETRIES) {
469  						if (retriescal++>FDC_CAL_RETRIES) {
470  							stop_fdc_drive(pCMD);
471  							if (flags)
472  								enable_interrupts();
473  							return false;
474  						}
475  						else {
476  							PRINTF(" trying to recalibrate Try %d\n",retriescal);
477  							if (fdc_recalibrate(pCMD, pFG) == false) {
478  								stop_fdc_drive(pCMD);
479  								if (flags)
480  									enable_interrupts();
481  								return false;
482  							}
483  							retriesrw=0;
484  							goto retrycal;
485  						} /* else >FDC_CAL_RETRIES */
486  					}
487  					else {
488  						PRINTF("Read retry %d\n",retriesrw);
489  						goto retryrw;
490  					} /* else >FDC_RW_RETRIES */
491  				}/* if output */
492  				timeout--;
493  			} while (true);
494  		} /* for len */
495  		/* the last sector of a track or all data has been read,
496  		 * we need to get the results */
497  		fdc_terminate(pCMD);
498  		offset+=(sect_size*readblk); /* set up buffer pointer */
499  		bufferw = &buffer[offset];
500  		pCMD->blnr+=readblk; /* update current block nr */
501  		blocks-=readblk; /* update blocks */
502  		if(blocks==0)
503  			break; /* we are finish */
504  		/* setup new read blocks */
505  		/*	readblk=pFG->head*pFG->sect; */
506  		readblk=pFG->sect;
507  		if(readblk>blocks)
508  			readblk=blocks;
509  retrycal:
510  		/* a seek is necessary */
511  		if (fdc_seek(pCMD, pFG) == false) {
512  			stop_fdc_drive(pCMD);
513  			if (flags)
514  				enable_interrupts();
515  			return false;
516  		}
517  		if((pCMD->result[STATUS_0]&0x20)!=0x20) {
518  			PRINTF("Seek error Status: %02X\n",pCMD->result[STATUS_0]);
519  			stop_fdc_drive(pCMD);
520  			return false;
521  		}
522  	} while (true); /* start over */
523  	stop_fdc_drive(pCMD); /* switch off drive */
524  	if (flags)
525  		enable_interrupts();
526  	return true;
527  }
528  
529  /* Scan all drives and check if drive is present and disk is inserted */
530  int fdc_check_drive(FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG)
531  {
532  	int i,drives,state;
533    /* OK procedure of data book is satisfied.
534  	 * trying to get some information over the drives */
535  	state=0; /* no drives, no disks */
536  	for(drives=0;drives<4;drives++) {
537  		pCMD->drive=drives;
538  		select_fdc_drive(pCMD);
539  		pCMD->blnr=0; /* set to the 1st block */
540  		if (fdc_recalibrate(pCMD, pFG) == false)
541  			continue;
542  		if((pCMD->result[STATUS_0]&0x10)==0x10)
543  			continue;
544  		/* ok drive connected check for disk */
545  		state|=(1<<drives);
546  		pCMD->blnr=pFG->size; /* set to the last block */
547  		if (fdc_seek(pCMD, pFG) == false)
548  			continue;
549  		pCMD->blnr=0; /* set to the 1st block */
550  		if (fdc_recalibrate(pCMD, pFG) == false)
551  			continue;
552  		pCMD->cmd[COMMAND]=FDC_CMD_READ_ID;
553  		if (fdc_issue_cmd(pCMD, pFG) == false)
554  			continue;
555  		state|=(0x10<<drives);
556  	}
557  	stop_fdc_drive(pCMD);
558  	for(i=0;i<4;i++) {
559  		PRINTF("Floppy Drive %d %sconnected %sDisk inserted %s\n",i,
560  			((state&(1<<i))==(1<<i)) ? "":"not ",
561  			((state&(0x10<<i))==(0x10<<i)) ? "":"no ",
562  			((state&(0x10<<i))==(0x10<<i)) ? pFG->name : "");
563  	}
564  	pCMD->flags=state;
565  	return true;
566  }
567  
568  
569  /**************************************************************************
570  * int fdc_setup
571  * setup the fdc according the datasheet
572  * assuming in PS2 Mode
573  */
574  int fdc_setup(int drive, FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG)
575  {
576  	int i;
577  
578  #ifdef CONFIG_SYS_FDC_HW_INIT
579  	fdc_hw_init ();
580  #endif
581  	/* first, we reset the FDC via the DOR */
582  	write_fdc_reg(FDC_DOR,0x00);
583  	for(i=0; i<255; i++) /* then we wait some time */
584  		udelay(500);
585  	/* then, we clear the reset in the DOR */
586  	pCMD->drive=drive;
587  	select_fdc_drive(pCMD);
588  	/* initialize the CCR */
589  	write_fdc_reg(FDC_CCR,pFG->rate);
590  	/* then initialize the DSR */
591  	write_fdc_reg(FDC_DSR,pFG->rate);
592  	if (wait_for_fdc_int() == false) {
593  			PRINTF("Time Out after writing CCR\n");
594  			return false;
595  	}
596  	/* now issue sense Interrupt and status command
597  	 * assuming only one drive present (drive 0) */
598  	pCMD->dma=0; /* we don't use any dma at all */
599  	for(i=0;i<4;i++) {
600  		/* issue sense interrupt for all 4 possible drives */
601  		pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT;
602  		if (fdc_issue_cmd(pCMD, pFG) == false) {
603  			PRINTF("Sense Interrupt for drive %d failed\n",i);
604  		}
605  	}
606  	/* issue the configure command */
607  	pCMD->drive=drive;
608  	select_fdc_drive(pCMD);
609  	pCMD->cmd[COMMAND]=FDC_CMD_CONFIGURE;
610  	if (fdc_issue_cmd(pCMD, pFG) == false) {
611  		PRINTF(" configure timeout\n");
612  		stop_fdc_drive(pCMD);
613  		return false;
614  	}
615  	/* issue specify command */
616  	pCMD->cmd[COMMAND]=FDC_CMD_SPECIFY;
617  	if (fdc_issue_cmd(pCMD, pFG) == false) {
618  		PRINTF(" specify timeout\n");
619  		stop_fdc_drive(pCMD);
620  		return false;
621  
622  	}
623  	/* then, we clear the reset in the DOR */
624  	/* fdc_check_drive(pCMD,pFG);	*/
625  	/*	write_fdc_reg(FDC_DOR,0x04); */
626  
627  	return true;
628  }
629  
630  /****************************************************************************
631   * main routine do_fdcboot
632   */
633  int do_fdcboot (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
634  {
635  	FD_GEO_STRUCT *pFG = (FD_GEO_STRUCT *)floppy_type;
636  	FDC_COMMAND_STRUCT *pCMD = &cmd;
637  	unsigned long addr,imsize;
638  #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
639  	image_header_t *hdr;  /* used for fdc boot */
640  #endif
641  	unsigned char boot_drive;
642  	int i,nrofblk;
643  #if defined(CONFIG_FIT)
644  	const void *fit_hdr = NULL;
645  #endif
646  
647  	switch (argc) {
648  	case 1:
649  		addr = CONFIG_SYS_LOAD_ADDR;
650  		boot_drive=CONFIG_SYS_FDC_DRIVE_NUMBER;
651  		break;
652  	case 2:
653  		addr = simple_strtoul(argv[1], NULL, 16);
654  		boot_drive=CONFIG_SYS_FDC_DRIVE_NUMBER;
655  		break;
656  	case 3:
657  		addr = simple_strtoul(argv[1], NULL, 16);
658  		boot_drive=simple_strtoul(argv[2], NULL, 10);
659  		break;
660  	default:
661  		return CMD_RET_USAGE;
662  	}
663  	/* setup FDC and scan for drives  */
664  	if (fdc_setup(boot_drive, pCMD, pFG) == false) {
665  		printf("\n** Error in setup FDC **\n");
666  		return 1;
667  	}
668  	if (fdc_check_drive(pCMD, pFG) == false) {
669  		printf("\n** Error in check_drives **\n");
670  		return 1;
671  	}
672  	if((pCMD->flags&(1<<boot_drive))==0) {
673  		/* drive not available */
674  		printf("\n** Drive %d not availabe **\n",boot_drive);
675  		return 1;
676  	}
677  	if((pCMD->flags&(0x10<<boot_drive))==0) {
678  		/* no disk inserted */
679  		printf("\n** No disk inserted in drive %d **\n",boot_drive);
680  		return 1;
681  	}
682  	/* ok, we have a valid source */
683  	pCMD->drive=boot_drive;
684  	/* read first block */
685  	pCMD->blnr=0;
686  	if (fdc_read_data((unsigned char *)addr, 1, pCMD, pFG) == false) {
687  		printf("\nRead error:");
688  		for(i=0;i<7;i++)
689  			printf("result%d: 0x%02X\n",i,pCMD->result[i]);
690  		return 1;
691  	}
692  
693  	switch (genimg_get_format ((void *)addr)) {
694  #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
695  	case IMAGE_FORMAT_LEGACY:
696  		hdr = (image_header_t *)addr;
697  		image_print_contents (hdr);
698  
699  		imsize = image_get_image_size (hdr);
700  		break;
701  #endif
702  #if defined(CONFIG_FIT)
703  	case IMAGE_FORMAT_FIT:
704  		fit_hdr = (const void *)addr;
705  		puts ("Fit image detected...\n");
706  
707  		imsize = fit_get_size (fit_hdr);
708  		break;
709  #endif
710  	default:
711  		puts ("** Unknown image type\n");
712  		return 1;
713  	}
714  
715  	nrofblk=imsize/512;
716  	if((imsize%512)>0)
717  		nrofblk++;
718  	printf("Loading %ld Bytes (%d blocks) at 0x%08lx..\n",imsize,nrofblk,addr);
719  	pCMD->blnr=0;
720  	if (fdc_read_data((unsigned char *)addr, nrofblk, pCMD, pFG) == false) {
721  		/* read image block */
722  		printf("\nRead error:");
723  		for(i=0;i<7;i++)
724  			printf("result%d: 0x%02X\n",i,pCMD->result[i]);
725  		return 1;
726  	}
727  	printf("OK %ld Bytes loaded.\n",imsize);
728  
729  	flush_cache (addr, imsize);
730  
731  #if defined(CONFIG_FIT)
732  	/* This cannot be done earlier, we need complete FIT image in RAM first */
733  	if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) {
734  		if (!fit_check_format (fit_hdr)) {
735  			puts ("** Bad FIT image format\n");
736  			return 1;
737  		}
738  		fit_print_contents (fit_hdr);
739  	}
740  #endif
741  
742  	/* Loading ok, update default load address */
743  	load_addr = addr;
744  
745  	return bootm_maybe_autostart(cmdtp, argv[0]);
746  }
747  
748  U_BOOT_CMD(
749  	fdcboot,	3,	1,	do_fdcboot,
750  	"boot from floppy device",
751  	"loadAddr drive"
752  );
753