xref: /rk3399_rockchip-uboot/cmd/fdc.c (revision 52b1eaf93d6b55e1467f97b8eefdc2f8b6031c43)
12e192b24SSimon Glass /*
22e192b24SSimon Glass  * (C) Copyright 2001
32e192b24SSimon Glass  * Denis Peter, MPL AG, d.peter@mpl.ch.
42e192b24SSimon Glass  *
52e192b24SSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
62e192b24SSimon Glass  */
72e192b24SSimon Glass /*
82e192b24SSimon Glass  * Floppy Disk support
92e192b24SSimon Glass  */
102e192b24SSimon Glass 
112e192b24SSimon Glass #include <common.h>
122e192b24SSimon Glass #include <config.h>
132e192b24SSimon Glass #include <command.h>
142e192b24SSimon Glass #include <image.h>
152e192b24SSimon Glass 
162e192b24SSimon Glass 
172e192b24SSimon Glass #undef	FDC_DEBUG
182e192b24SSimon Glass 
192e192b24SSimon Glass #ifdef	FDC_DEBUG
202e192b24SSimon Glass #define	PRINTF(fmt,args...)	printf (fmt ,##args)
212e192b24SSimon Glass #else
222e192b24SSimon Glass #define PRINTF(fmt,args...)
232e192b24SSimon Glass #endif
242e192b24SSimon Glass 
252e192b24SSimon Glass /*#if defined(CONFIG_CMD_DATE) */
262e192b24SSimon Glass /*#include <rtc.h> */
272e192b24SSimon Glass /*#endif */
282e192b24SSimon Glass 
292e192b24SSimon Glass typedef struct {
302e192b24SSimon Glass 	int		flags;		/* connected drives ect */
312e192b24SSimon Glass 	unsigned long	blnr;		/* Logical block nr */
322e192b24SSimon Glass 	uchar		drive;		/* drive no */
332e192b24SSimon Glass 	uchar		cmdlen;		/* cmd length */
342e192b24SSimon Glass 	uchar		cmd[16];	/* cmd desc */
352e192b24SSimon Glass 	uchar		dma;		/* if > 0 dma enabled */
362e192b24SSimon Glass 	uchar		result[11];	/* status information */
372e192b24SSimon Glass 	uchar		resultlen;	/* lenght of result */
382e192b24SSimon Glass } FDC_COMMAND_STRUCT;
392e192b24SSimon Glass 
402e192b24SSimon Glass /* flags: only the lower 8bit used:
412e192b24SSimon Glass  * bit 0 if set drive 0 is present
422e192b24SSimon Glass  * bit 1 if set drive 1 is present
432e192b24SSimon Glass  * bit 2 if set drive 2 is present
442e192b24SSimon Glass  * bit 3 if set drive 3 is present
452e192b24SSimon Glass  * bit 4 if set disk in drive 0 is inserted
462e192b24SSimon Glass  * bit 5 if set disk in drive 1 is inserted
472e192b24SSimon Glass  * bit 6 if set disk in drive 2 is inserted
482e192b24SSimon Glass  * bit 7 if set disk in drive 4 is inserted
492e192b24SSimon Glass  */
502e192b24SSimon Glass 
512e192b24SSimon Glass /* cmd indexes */
522e192b24SSimon Glass #define COMMAND			0
532e192b24SSimon Glass #define DRIVE			1
542e192b24SSimon Glass #define CONFIG0			1
552e192b24SSimon Glass #define SPEC_HUTSRT		1
562e192b24SSimon Glass #define TRACK			2
572e192b24SSimon Glass #define CONFIG1			2
582e192b24SSimon Glass #define SPEC_HLT		2
592e192b24SSimon Glass #define HEAD			3
602e192b24SSimon Glass #define CONFIG2			3
612e192b24SSimon Glass #define SECTOR			4
622e192b24SSimon Glass #define SECTOR_SIZE		5
632e192b24SSimon Glass #define LAST_TRACK		6
642e192b24SSimon Glass #define GAP			7
652e192b24SSimon Glass #define DTL			8
662e192b24SSimon Glass /* result indexes */
672e192b24SSimon Glass #define STATUS_0		0
682e192b24SSimon Glass #define STATUS_PCN		1
692e192b24SSimon Glass #define STATUS_1		1
702e192b24SSimon Glass #define STATUS_2		2
712e192b24SSimon Glass #define STATUS_TRACK		3
722e192b24SSimon Glass #define STATUS_HEAD		4
732e192b24SSimon Glass #define STATUS_SECT		5
742e192b24SSimon Glass #define STATUS_SECT_SIZE	6
752e192b24SSimon Glass 
762e192b24SSimon Glass 
772e192b24SSimon Glass /* Register addresses */
782e192b24SSimon Glass #define FDC_BASE	0x3F0
792e192b24SSimon Glass #define FDC_SRA		FDC_BASE + 0	/* Status Register A */
802e192b24SSimon Glass #define FDC_SRB		FDC_BASE + 1	/* Status Register B */
812e192b24SSimon Glass #define FDC_DOR		FDC_BASE + 2	/* Digital Output Register */
822e192b24SSimon Glass #define FDC_TDR		FDC_BASE + 3	/* Tape Drive Register */
832e192b24SSimon Glass #define FDC_DSR		FDC_BASE + 4	/* Data rate Register */
842e192b24SSimon Glass #define FDC_MSR		FDC_BASE + 4	/* Main Status Register */
852e192b24SSimon Glass #define FDC_FIFO	FDC_BASE + 5	/* FIFO */
862e192b24SSimon Glass #define FDC_DIR		FDC_BASE + 6	/* Digital Input Register */
872e192b24SSimon Glass #define FDC_CCR		FDC_BASE + 7	/* Configuration Control */
882e192b24SSimon Glass /* Commands */
892e192b24SSimon Glass #define FDC_CMD_SENSE_INT	0x08
902e192b24SSimon Glass #define FDC_CMD_CONFIGURE	0x13
912e192b24SSimon Glass #define FDC_CMD_SPECIFY		0x03
922e192b24SSimon Glass #define FDC_CMD_RECALIBRATE	0x07
932e192b24SSimon Glass #define FDC_CMD_READ		0x06
942e192b24SSimon Glass #define FDC_CMD_READ_TRACK	0x02
952e192b24SSimon Glass #define FDC_CMD_READ_ID		0x0A
962e192b24SSimon Glass #define FDC_CMD_DUMP_REG	0x0E
972e192b24SSimon Glass #define FDC_CMD_SEEK		0x0F
982e192b24SSimon Glass 
992e192b24SSimon Glass #define FDC_CMD_SENSE_INT_LEN	0x01
1002e192b24SSimon Glass #define FDC_CMD_CONFIGURE_LEN	0x04
1012e192b24SSimon Glass #define FDC_CMD_SPECIFY_LEN	0x03
1022e192b24SSimon Glass #define FDC_CMD_RECALIBRATE_LEN	0x02
1032e192b24SSimon Glass #define FDC_CMD_READ_LEN	0x09
1042e192b24SSimon Glass #define FDC_CMD_READ_TRACK_LEN	0x09
1052e192b24SSimon Glass #define FDC_CMD_READ_ID_LEN	0x02
1062e192b24SSimon Glass #define FDC_CMD_DUMP_REG_LEN	0x01
1072e192b24SSimon Glass #define FDC_CMD_SEEK_LEN	0x03
1082e192b24SSimon Glass 
1092e192b24SSimon Glass #define FDC_FIFO_THR		0x0C
1102e192b24SSimon Glass #define FDC_FIFO_DIS		0x00
1112e192b24SSimon Glass #define FDC_IMPLIED_SEEK	0x01
1122e192b24SSimon Glass #define FDC_POLL_DIS		0x00
1132e192b24SSimon Glass #define FDC_PRE_TRK		0x00
1142e192b24SSimon Glass #define FDC_CONFIGURE		FDC_FIFO_THR | (FDC_POLL_DIS<<4) | (FDC_FIFO_DIS<<5) | (FDC_IMPLIED_SEEK << 6)
1152e192b24SSimon Glass #define FDC_MFM_MODE		0x01 /* MFM enable */
1162e192b24SSimon Glass #define FDC_SKIP_MODE		0x00 /* skip enable */
1172e192b24SSimon Glass 
1182e192b24SSimon Glass #define FDC_TIME_OUT 100000 /* time out */
1192e192b24SSimon Glass #define	FDC_RW_RETRIES		3 /* read write retries */
1202e192b24SSimon Glass #define FDC_CAL_RETRIES		3 /* calibration and seek retries */
1212e192b24SSimon Glass 
1222e192b24SSimon Glass 
1232e192b24SSimon Glass /* Disk structure */
1242e192b24SSimon Glass typedef struct  {
1252e192b24SSimon Glass 	unsigned int size;	/* nr of sectors total */
1262e192b24SSimon Glass 	unsigned int sect;	/* sectors per track */
1272e192b24SSimon Glass 	unsigned int head;	/* nr of heads */
1282e192b24SSimon Glass 	unsigned int track;	/* nr of tracks */
1292e192b24SSimon Glass 	unsigned int stretch;	/* !=0 means double track steps */
1302e192b24SSimon Glass 	unsigned char	gap;	/* gap1 size */
1312e192b24SSimon Glass 	unsigned char	rate;	/* data rate. |= 0x40 for perpendicular */
1322e192b24SSimon Glass 	unsigned char	spec1;	/* stepping rate, head unload time */
1332e192b24SSimon Glass 	unsigned char	fmt_gap;/* gap2 size */
1342e192b24SSimon Glass 	unsigned char hlt;	/* head load time */
1352e192b24SSimon Glass 	unsigned char sect_code;/* Sector Size code */
1362e192b24SSimon Glass 	const char	* name;	/* used only for predefined formats */
1372e192b24SSimon Glass } FD_GEO_STRUCT;
1382e192b24SSimon Glass 
1392e192b24SSimon Glass 
1402e192b24SSimon Glass /* supported Floppy types (currently only one) */
1412e192b24SSimon Glass const static FD_GEO_STRUCT floppy_type[2] = {
1422e192b24SSimon Glass 	{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,16,2,"H1440" },	/*  7 1.44MB 3.5"   */
1432e192b24SSimon Glass 	{    0, 0,0, 0,0,0x00,0x00,0x00,0x00, 0,0,NULL    },	/*  end of table    */
1442e192b24SSimon Glass };
1452e192b24SSimon Glass 
1462e192b24SSimon Glass static FDC_COMMAND_STRUCT cmd; /* global command struct */
1472e192b24SSimon Glass 
1482e192b24SSimon Glass /* If the boot drive number is undefined, we assume it's drive 0             */
1492e192b24SSimon Glass #ifndef CONFIG_SYS_FDC_DRIVE_NUMBER
1502e192b24SSimon Glass #define CONFIG_SYS_FDC_DRIVE_NUMBER 0
1512e192b24SSimon Glass #endif
1522e192b24SSimon Glass 
1532e192b24SSimon Glass /* Hardware access */
1542e192b24SSimon Glass #ifndef CONFIG_SYS_ISA_IO_STRIDE
1552e192b24SSimon Glass #define CONFIG_SYS_ISA_IO_STRIDE 1
1562e192b24SSimon Glass #endif
1572e192b24SSimon Glass 
1582e192b24SSimon Glass #ifndef CONFIG_SYS_ISA_IO_OFFSET
1592e192b24SSimon Glass #define CONFIG_SYS_ISA_IO_OFFSET 0
1602e192b24SSimon Glass #endif
1612e192b24SSimon Glass 
1622e192b24SSimon Glass /* Supporting Functions */
1632e192b24SSimon Glass /* reads a Register of the FDC */
read_fdc_reg(unsigned int addr)1642e192b24SSimon Glass unsigned char read_fdc_reg(unsigned int addr)
1652e192b24SSimon Glass {
1662e192b24SSimon Glass 	volatile unsigned char *val =
1672e192b24SSimon Glass 		(volatile unsigned char *)(CONFIG_SYS_ISA_IO_BASE_ADDRESS +
1682e192b24SSimon Glass 					   (addr * CONFIG_SYS_ISA_IO_STRIDE) +
1692e192b24SSimon Glass 					   CONFIG_SYS_ISA_IO_OFFSET);
1702e192b24SSimon Glass 
1712e192b24SSimon Glass 	return val [0];
1722e192b24SSimon Glass }
1732e192b24SSimon Glass 
1742e192b24SSimon Glass /* writes a Register of the FDC */
write_fdc_reg(unsigned int addr,unsigned char val)1752e192b24SSimon Glass void write_fdc_reg(unsigned int addr, unsigned char val)
1762e192b24SSimon Glass {
1772e192b24SSimon Glass 	volatile unsigned char *tmp =
1782e192b24SSimon Glass 		(volatile unsigned char *)(CONFIG_SYS_ISA_IO_BASE_ADDRESS +
1792e192b24SSimon Glass 					   (addr * CONFIG_SYS_ISA_IO_STRIDE) +
1802e192b24SSimon Glass 					   CONFIG_SYS_ISA_IO_OFFSET);
1812e192b24SSimon Glass 	tmp[0]=val;
1822e192b24SSimon Glass }
1832e192b24SSimon Glass 
1842e192b24SSimon Glass /* waits for an interrupt (polling) */
wait_for_fdc_int(void)1852e192b24SSimon Glass int wait_for_fdc_int(void)
1862e192b24SSimon Glass {
1872e192b24SSimon Glass 	unsigned long timeout;
1882e192b24SSimon Glass 	timeout = FDC_TIME_OUT;
1892e192b24SSimon Glass 	while((read_fdc_reg(FDC_SRA)&0x80)==0) {
1902e192b24SSimon Glass 		timeout--;
1912e192b24SSimon Glass 		udelay(10);
192*eae4b2b6SVagrant Cascadian 		if(timeout==0) /* timeout occurred */
1932e192b24SSimon Glass 			return false;
1942e192b24SSimon Glass 	}
1952e192b24SSimon Glass 	return true;
1962e192b24SSimon Glass }
1972e192b24SSimon Glass 
1982e192b24SSimon Glass /* reads a byte from the FIFO of the FDC and checks direction and RQM bit
1992e192b24SSimon Glass    of the MSR. returns -1 if timeout, or byte if ok */
read_fdc_byte(void)2002e192b24SSimon Glass int read_fdc_byte(void)
2012e192b24SSimon Glass {
2022e192b24SSimon Glass 	unsigned long timeout;
2032e192b24SSimon Glass 	timeout = FDC_TIME_OUT;
2042e192b24SSimon Glass 	while((read_fdc_reg(FDC_MSR)&0xC0)!=0xC0) {
2052e192b24SSimon Glass 		/* direction out and ready */
2062e192b24SSimon Glass 		udelay(10);
2072e192b24SSimon Glass 		timeout--;
208*eae4b2b6SVagrant Cascadian 		if(timeout==0) /* timeout occurred */
2092e192b24SSimon Glass 			return -1;
2102e192b24SSimon Glass 	}
2112e192b24SSimon Glass 	return read_fdc_reg(FDC_FIFO);
2122e192b24SSimon Glass }
2132e192b24SSimon Glass 
2142e192b24SSimon Glass /* if the direction of the FIFO is wrong, this routine is used to
2152e192b24SSimon Glass    empty the FIFO. Should _not_ be used */
fdc_need_more_output(void)2162e192b24SSimon Glass int fdc_need_more_output(void)
2172e192b24SSimon Glass {
2182e192b24SSimon Glass 	unsigned char c;
2192e192b24SSimon Glass 	while((read_fdc_reg(FDC_MSR)&0xC0)==0xC0)	{
2202e192b24SSimon Glass 			c=(unsigned char)read_fdc_byte();
2212e192b24SSimon Glass 			printf("Error: more output: %x\n",c);
2222e192b24SSimon Glass 	}
2232e192b24SSimon Glass 	return true;
2242e192b24SSimon Glass }
2252e192b24SSimon Glass 
2262e192b24SSimon Glass 
2272e192b24SSimon Glass /* writes a byte to the FIFO of the FDC and checks direction and RQM bit
2282e192b24SSimon Glass    of the MSR */
write_fdc_byte(unsigned char val)2292e192b24SSimon Glass int write_fdc_byte(unsigned char val)
2302e192b24SSimon Glass {
2312e192b24SSimon Glass 	unsigned long timeout;
2322e192b24SSimon Glass 	timeout = FDC_TIME_OUT;
2332e192b24SSimon Glass 	while((read_fdc_reg(FDC_MSR)&0xC0)!=0x80) {
2342e192b24SSimon Glass 		/* direction in and ready for byte */
2352e192b24SSimon Glass 		timeout--;
2362e192b24SSimon Glass 		udelay(10);
2372e192b24SSimon Glass 		fdc_need_more_output();
238*eae4b2b6SVagrant Cascadian 		if(timeout==0) /* timeout occurred */
2392e192b24SSimon Glass 			return false;
2402e192b24SSimon Glass 	}
2412e192b24SSimon Glass 	write_fdc_reg(FDC_FIFO,val);
2422e192b24SSimon Glass 	return true;
2432e192b24SSimon Glass }
2442e192b24SSimon Glass 
2452e192b24SSimon Glass /* sets up all FDC commands and issues it to the FDC. If
2462e192b24SSimon Glass    the command causes direct results (no Execution Phase)
2472e192b24SSimon Glass    the result is be read as well. */
2482e192b24SSimon Glass 
fdc_issue_cmd(FDC_COMMAND_STRUCT * pCMD,FD_GEO_STRUCT * pFG)2492e192b24SSimon Glass int fdc_issue_cmd(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG)
2502e192b24SSimon Glass {
2512e192b24SSimon Glass 	int i;
2522e192b24SSimon Glass 	unsigned long head,track,sect,timeout;
2532e192b24SSimon Glass 	track = pCMD->blnr / (pFG->sect * pFG->head); /* track nr */
2542e192b24SSimon Glass 	sect =  pCMD->blnr % (pFG->sect * pFG->head); /* remaining blocks */
2552e192b24SSimon Glass 	head = sect / pFG->sect; /* head nr */
2562e192b24SSimon Glass 	sect =  sect % pFG->sect; /* remaining blocks */
2572e192b24SSimon Glass 	sect++; /* sectors are 1 based */
2582e192b24SSimon Glass 	PRINTF("Cmd 0x%02x Track %ld, Head %ld, Sector %ld, Drive %d (blnr %ld)\n",
2592e192b24SSimon Glass 		pCMD->cmd[0],track,head,sect,pCMD->drive,pCMD->blnr);
2602e192b24SSimon Glass 
2612e192b24SSimon Glass 	if(head|=0) { /* max heads = 2 */
2622e192b24SSimon Glass 		pCMD->cmd[DRIVE]=pCMD->drive | 0x04; /* head 1 */
2632e192b24SSimon Glass 		pCMD->cmd[HEAD]=(unsigned char) head; /* head register */
2642e192b24SSimon Glass 	}
2652e192b24SSimon Glass 	else {
2662e192b24SSimon Glass 		pCMD->cmd[DRIVE]=pCMD->drive; /* head 0 */
2672e192b24SSimon Glass 		pCMD->cmd[HEAD]=(unsigned char) head; /* head register */
2682e192b24SSimon Glass 	}
2692e192b24SSimon Glass 	pCMD->cmd[TRACK]=(unsigned char) track; /* track */
2702e192b24SSimon Glass 	switch (pCMD->cmd[COMMAND]) {
2712e192b24SSimon Glass 		case FDC_CMD_READ:
2722e192b24SSimon Glass 			pCMD->cmd[SECTOR]=(unsigned char) sect; /* sector */
2732e192b24SSimon Glass 			pCMD->cmd[SECTOR_SIZE]=pFG->sect_code; /* sector size code */
2742e192b24SSimon Glass 			pCMD->cmd[LAST_TRACK]=pFG->sect; /* End of track */
2752e192b24SSimon Glass 			pCMD->cmd[GAP]=pFG->gap; /* gap */
2762e192b24SSimon Glass 			pCMD->cmd[DTL]=0xFF; /* DTL */
2772e192b24SSimon Glass 			pCMD->cmdlen=FDC_CMD_READ_LEN;
2782e192b24SSimon Glass 			pCMD->cmd[COMMAND]|=(FDC_MFM_MODE<<6); /* set MFM bit */
2792e192b24SSimon Glass 			pCMD->cmd[COMMAND]|=(FDC_SKIP_MODE<<5); /* set Skip bit */
2802e192b24SSimon Glass 			pCMD->resultlen=0;  /* result only after execution */
2812e192b24SSimon Glass 			break;
2822e192b24SSimon Glass 		case FDC_CMD_SEEK:
2832e192b24SSimon Glass 			pCMD->cmdlen=FDC_CMD_SEEK_LEN;
2842e192b24SSimon Glass 			pCMD->resultlen=0;  /* no result */
2852e192b24SSimon Glass 			break;
2862e192b24SSimon Glass 		case FDC_CMD_CONFIGURE:
2872e192b24SSimon Glass 			pCMD->cmd[CONFIG0]=0;
2882e192b24SSimon Glass 			pCMD->cmd[CONFIG1]=FDC_CONFIGURE; /* FIFO Threshold, Poll, Enable FIFO */
2892e192b24SSimon Glass 			pCMD->cmd[CONFIG2]=FDC_PRE_TRK;	/* Precompensation Track */
2902e192b24SSimon Glass 			pCMD->cmdlen=FDC_CMD_CONFIGURE_LEN;
2912e192b24SSimon Glass 			pCMD->resultlen=0;  /* no result */
2922e192b24SSimon Glass 			break;
2932e192b24SSimon Glass 		case FDC_CMD_SPECIFY:
2942e192b24SSimon Glass 			pCMD->cmd[SPEC_HUTSRT]=pFG->spec1;
2952e192b24SSimon Glass 			pCMD->cmd[SPEC_HLT]=(pFG->hlt)<<1; /* head load time */
2962e192b24SSimon Glass 			if(pCMD->dma==0)
2972e192b24SSimon Glass 				pCMD->cmd[SPEC_HLT]|=0x1; /* no dma */
2982e192b24SSimon Glass 			pCMD->cmdlen=FDC_CMD_SPECIFY_LEN;
2992e192b24SSimon Glass 			pCMD->resultlen=0;  /* no result */
3002e192b24SSimon Glass 			break;
3012e192b24SSimon Glass 		case FDC_CMD_DUMP_REG:
3022e192b24SSimon Glass 			pCMD->cmdlen=FDC_CMD_DUMP_REG_LEN;
3032e192b24SSimon Glass 			pCMD->resultlen=10;  /* 10 byte result */
3042e192b24SSimon Glass 			break;
3052e192b24SSimon Glass 		case FDC_CMD_READ_ID:
3062e192b24SSimon Glass 			pCMD->cmd[COMMAND]|=(FDC_MFM_MODE<<6); /* set MFM bit */
3072e192b24SSimon Glass 			pCMD->cmdlen=FDC_CMD_READ_ID_LEN;
3082e192b24SSimon Glass 			pCMD->resultlen=7;  /* 7 byte result */
3092e192b24SSimon Glass 			break;
3102e192b24SSimon Glass 		case FDC_CMD_RECALIBRATE:
3112e192b24SSimon Glass 			pCMD->cmd[DRIVE]&=0x03; /* don't set the head bit */
3122e192b24SSimon Glass 			pCMD->cmdlen=FDC_CMD_RECALIBRATE_LEN;
3132e192b24SSimon Glass 			pCMD->resultlen=0;  /* no result */
3142e192b24SSimon Glass 			break;
3152e192b24SSimon Glass 			break;
3162e192b24SSimon Glass 		case FDC_CMD_SENSE_INT:
3172e192b24SSimon Glass 			pCMD->cmdlen=FDC_CMD_SENSE_INT_LEN;
3182e192b24SSimon Glass 			pCMD->resultlen=2;
3192e192b24SSimon Glass 			break;
3202e192b24SSimon Glass 	}
3212e192b24SSimon Glass 	for(i=0;i<pCMD->cmdlen;i++) {
3222e192b24SSimon Glass 		/* PRINTF("write cmd%d = 0x%02X\n",i,pCMD->cmd[i]); */
3232e192b24SSimon Glass 		if (write_fdc_byte(pCMD->cmd[i]) == false) {
3242e192b24SSimon Glass 			PRINTF("Error: timeout while issue cmd%d\n",i);
3252e192b24SSimon Glass 			return false;
3262e192b24SSimon Glass 		}
3272e192b24SSimon Glass 	}
3282e192b24SSimon Glass 	timeout=FDC_TIME_OUT;
3292e192b24SSimon Glass 	for(i=0;i<pCMD->resultlen;i++) {
3302e192b24SSimon Glass 		while((read_fdc_reg(FDC_MSR)&0xC0)!=0xC0) {
3312e192b24SSimon Glass 			timeout--;
3322e192b24SSimon Glass 			if(timeout==0) {
3332e192b24SSimon Glass 				PRINTF(" timeout while reading result%d MSR=0x%02X\n",i,read_fdc_reg(FDC_MSR));
3342e192b24SSimon Glass 				return false;
3352e192b24SSimon Glass 			}
3362e192b24SSimon Glass 		}
3372e192b24SSimon Glass 		pCMD->result[i]=(unsigned char)read_fdc_byte();
3382e192b24SSimon Glass 	}
3392e192b24SSimon Glass 	return true;
3402e192b24SSimon Glass }
3412e192b24SSimon Glass 
3422e192b24SSimon Glass /* selects the drive assigned in the cmd structur and
3432e192b24SSimon Glass    switches on the Motor */
select_fdc_drive(FDC_COMMAND_STRUCT * pCMD)3442e192b24SSimon Glass void select_fdc_drive(FDC_COMMAND_STRUCT *pCMD)
3452e192b24SSimon Glass {
3462e192b24SSimon Glass 	unsigned char val;
3472e192b24SSimon Glass 
3482e192b24SSimon Glass 	val=(1<<(4+pCMD->drive))|pCMD->drive|0xC; /* set reset, dma gate and motor bits */
3492e192b24SSimon Glass 	if((read_fdc_reg(FDC_DOR)&val)!=val) {
3502e192b24SSimon Glass 		write_fdc_reg(FDC_DOR,val);
3512e192b24SSimon Glass 		for(val=0;val<255;val++)
3522e192b24SSimon Glass 			udelay(500); /* wait some time to start motor */
3532e192b24SSimon Glass 	}
3542e192b24SSimon Glass }
3552e192b24SSimon Glass 
3562e192b24SSimon Glass /* switches off the Motor of the specified drive */
stop_fdc_drive(FDC_COMMAND_STRUCT * pCMD)3572e192b24SSimon Glass void stop_fdc_drive(FDC_COMMAND_STRUCT *pCMD)
3582e192b24SSimon Glass {
3592e192b24SSimon Glass 	unsigned char val;
3602e192b24SSimon Glass 
3612e192b24SSimon Glass 	val=(1<<(4+pCMD->drive))|pCMD->drive; /* sets motor bits */
3622e192b24SSimon Glass 	write_fdc_reg(FDC_DOR,(read_fdc_reg(FDC_DOR)&~val));
3632e192b24SSimon Glass }
3642e192b24SSimon Glass 
3652e192b24SSimon Glass /* issues a recalibrate command, waits for interrupt and
3662e192b24SSimon Glass  * issues a sense_interrupt */
fdc_recalibrate(FDC_COMMAND_STRUCT * pCMD,FD_GEO_STRUCT * pFG)3672e192b24SSimon Glass int fdc_recalibrate(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG)
3682e192b24SSimon Glass {
3692e192b24SSimon Glass 	pCMD->cmd[COMMAND]=FDC_CMD_RECALIBRATE;
3702e192b24SSimon Glass 	if (fdc_issue_cmd(pCMD, pFG) == false)
3712e192b24SSimon Glass 		return false;
3722e192b24SSimon Glass 	while (wait_for_fdc_int() != true);
3732e192b24SSimon Glass 
3742e192b24SSimon Glass 	pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT;
3752e192b24SSimon Glass 	return(fdc_issue_cmd(pCMD,pFG));
3762e192b24SSimon Glass }
3772e192b24SSimon Glass 
3782e192b24SSimon Glass /* issues a recalibrate command, waits for interrupt and
3792e192b24SSimon Glass  * issues a sense_interrupt */
fdc_seek(FDC_COMMAND_STRUCT * pCMD,FD_GEO_STRUCT * pFG)3802e192b24SSimon Glass int fdc_seek(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG)
3812e192b24SSimon Glass {
3822e192b24SSimon Glass 	pCMD->cmd[COMMAND]=FDC_CMD_SEEK;
3832e192b24SSimon Glass 	if (fdc_issue_cmd(pCMD, pFG) == false)
3842e192b24SSimon Glass 		return false;
3852e192b24SSimon Glass 	while (wait_for_fdc_int() != true);
3862e192b24SSimon Glass 
3872e192b24SSimon Glass 	pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT;
3882e192b24SSimon Glass 	return(fdc_issue_cmd(pCMD,pFG));
3892e192b24SSimon Glass }
3902e192b24SSimon Glass 
3912e192b24SSimon Glass /* terminates current command, by not servicing the FIFO
3922e192b24SSimon Glass  * waits for interrupt and fills in the result bytes */
fdc_terminate(FDC_COMMAND_STRUCT * pCMD)3932e192b24SSimon Glass int fdc_terminate(FDC_COMMAND_STRUCT *pCMD)
3942e192b24SSimon Glass {
3952e192b24SSimon Glass 	int i;
3962e192b24SSimon Glass 	for(i=0;i<100;i++)
3972e192b24SSimon Glass 		udelay(500); /* wait 500usec for fifo overrun */
398*eae4b2b6SVagrant Cascadian 	while((read_fdc_reg(FDC_SRA)&0x80)==0x00); /* wait as long as no int has occurred */
3992e192b24SSimon Glass 	for(i=0;i<7;i++) {
4002e192b24SSimon Glass 		pCMD->result[i]=(unsigned char)read_fdc_byte();
4012e192b24SSimon Glass 	}
4022e192b24SSimon Glass 	return true;
4032e192b24SSimon Glass }
4042e192b24SSimon Glass 
4052e192b24SSimon Glass /* reads data from FDC, seek commands are issued automatic */
fdc_read_data(unsigned char * buffer,unsigned long blocks,FDC_COMMAND_STRUCT * pCMD,FD_GEO_STRUCT * pFG)4062e192b24SSimon Glass int fdc_read_data(unsigned char *buffer, unsigned long blocks,FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG)
4072e192b24SSimon Glass {
4082e192b24SSimon Glass   /* first seek to start address */
4092e192b24SSimon Glass 	unsigned long len,readblk,i,timeout,ii,offset;
4102e192b24SSimon Glass 	unsigned char c,retriesrw,retriescal;
4112e192b24SSimon Glass 	unsigned char *bufferw; /* working buffer */
4122e192b24SSimon Glass 	int sect_size;
4132e192b24SSimon Glass 	int flags;
4142e192b24SSimon Glass 
4152e192b24SSimon Glass 	flags=disable_interrupts(); /* switch off all Interrupts */
4162e192b24SSimon Glass 	select_fdc_drive(pCMD); /* switch on drive */
4172e192b24SSimon Glass 	sect_size=0x080<<pFG->sect_code;
4182e192b24SSimon Glass 	retriesrw=0;
4192e192b24SSimon Glass 	retriescal=0;
4202e192b24SSimon Glass 	offset=0;
4212e192b24SSimon Glass 	if (fdc_seek(pCMD, pFG) == false) {
4222e192b24SSimon Glass 		stop_fdc_drive(pCMD);
4232e192b24SSimon Glass 		if (flags)
4242e192b24SSimon Glass 			enable_interrupts();
4252e192b24SSimon Glass 		return false;
4262e192b24SSimon Glass 	}
4272e192b24SSimon Glass 	if((pCMD->result[STATUS_0]&0x20)!=0x20) {
4282e192b24SSimon Glass 		printf("Seek error Status: %02X\n",pCMD->result[STATUS_0]);
4292e192b24SSimon Glass 		stop_fdc_drive(pCMD);
4302e192b24SSimon Glass 		if (flags)
4312e192b24SSimon Glass 			enable_interrupts();
4322e192b24SSimon Glass 		return false;
4332e192b24SSimon Glass 	}
4342e192b24SSimon Glass 	/* now determine the next seek point */
4352e192b24SSimon Glass 	/*	lastblk=pCMD->blnr + blocks; */
4362e192b24SSimon Glass 	/*	readblk=(pFG->head*pFG->sect)-(pCMD->blnr%(pFG->head*pFG->sect)); */
4372e192b24SSimon Glass 	readblk=pFG->sect-(pCMD->blnr%pFG->sect);
4382e192b24SSimon Glass 	PRINTF("1st nr of block possible read %ld start %ld\n",readblk,pCMD->blnr);
4392e192b24SSimon Glass 	if(readblk>blocks) /* is end within 1st track */
4402e192b24SSimon Glass 		readblk=blocks; /* yes, correct it */
4412e192b24SSimon Glass 	PRINTF("we read %ld blocks start %ld\n",readblk,pCMD->blnr);
4422e192b24SSimon Glass 	bufferw = &buffer[0]; /* setup working buffer */
4432e192b24SSimon Glass 	do {
4442e192b24SSimon Glass retryrw:
4452e192b24SSimon Glass 		len=sect_size * readblk;
4462e192b24SSimon Glass 		pCMD->cmd[COMMAND]=FDC_CMD_READ;
4472e192b24SSimon Glass 		if (fdc_issue_cmd(pCMD, pFG) == false) {
4482e192b24SSimon Glass 			stop_fdc_drive(pCMD);
4492e192b24SSimon Glass 			if (flags)
4502e192b24SSimon Glass 				enable_interrupts();
4512e192b24SSimon Glass 			return false;
4522e192b24SSimon Glass 		}
4532e192b24SSimon Glass 		for (i=0;i<len;i++) {
4542e192b24SSimon Glass 			timeout=FDC_TIME_OUT;
4552e192b24SSimon Glass 			do {
4562e192b24SSimon Glass 				c=read_fdc_reg(FDC_MSR);
4572e192b24SSimon Glass 				if((c&0xC0)==0xC0) {
4582e192b24SSimon Glass 					bufferw[i]=read_fdc_reg(FDC_FIFO);
4592e192b24SSimon Glass 					break;
4602e192b24SSimon Glass 				}
4612e192b24SSimon Glass 				if((c&0xC0)==0x80) { /* output */
462a6f70a3dSVagrant Cascadian 					PRINTF("Transfer error transferred: at %ld, MSR=%02X\n",i,c);
4632e192b24SSimon Glass 					if(i>6) {
4642e192b24SSimon Glass 						for(ii=0;ii<7;ii++) {
4652e192b24SSimon Glass 							pCMD->result[ii]=bufferw[(i-7+ii)];
4662e192b24SSimon Glass 						} /* for */
4672e192b24SSimon Glass 					}
4682e192b24SSimon Glass 					if(retriesrw++>FDC_RW_RETRIES) {
4692e192b24SSimon Glass 						if (retriescal++>FDC_CAL_RETRIES) {
4702e192b24SSimon Glass 							stop_fdc_drive(pCMD);
4712e192b24SSimon Glass 							if (flags)
4722e192b24SSimon Glass 								enable_interrupts();
4732e192b24SSimon Glass 							return false;
4742e192b24SSimon Glass 						}
4752e192b24SSimon Glass 						else {
4762e192b24SSimon Glass 							PRINTF(" trying to recalibrate Try %d\n",retriescal);
4772e192b24SSimon Glass 							if (fdc_recalibrate(pCMD, pFG) == false) {
4782e192b24SSimon Glass 								stop_fdc_drive(pCMD);
4792e192b24SSimon Glass 								if (flags)
4802e192b24SSimon Glass 									enable_interrupts();
4812e192b24SSimon Glass 								return false;
4822e192b24SSimon Glass 							}
4832e192b24SSimon Glass 							retriesrw=0;
4842e192b24SSimon Glass 							goto retrycal;
4852e192b24SSimon Glass 						} /* else >FDC_CAL_RETRIES */
4862e192b24SSimon Glass 					}
4872e192b24SSimon Glass 					else {
4882e192b24SSimon Glass 						PRINTF("Read retry %d\n",retriesrw);
4892e192b24SSimon Glass 						goto retryrw;
4902e192b24SSimon Glass 					} /* else >FDC_RW_RETRIES */
4912e192b24SSimon Glass 				}/* if output */
4922e192b24SSimon Glass 				timeout--;
4932e192b24SSimon Glass 			} while (true);
4942e192b24SSimon Glass 		} /* for len */
4952e192b24SSimon Glass 		/* the last sector of a track or all data has been read,
4962e192b24SSimon Glass 		 * we need to get the results */
4972e192b24SSimon Glass 		fdc_terminate(pCMD);
4982e192b24SSimon Glass 		offset+=(sect_size*readblk); /* set up buffer pointer */
4992e192b24SSimon Glass 		bufferw = &buffer[offset];
5002e192b24SSimon Glass 		pCMD->blnr+=readblk; /* update current block nr */
5012e192b24SSimon Glass 		blocks-=readblk; /* update blocks */
5022e192b24SSimon Glass 		if(blocks==0)
5032e192b24SSimon Glass 			break; /* we are finish */
5042e192b24SSimon Glass 		/* setup new read blocks */
5052e192b24SSimon Glass 		/*	readblk=pFG->head*pFG->sect; */
5062e192b24SSimon Glass 		readblk=pFG->sect;
5072e192b24SSimon Glass 		if(readblk>blocks)
5082e192b24SSimon Glass 			readblk=blocks;
5092e192b24SSimon Glass retrycal:
5102e192b24SSimon Glass 		/* a seek is necessary */
5112e192b24SSimon Glass 		if (fdc_seek(pCMD, pFG) == false) {
5122e192b24SSimon Glass 			stop_fdc_drive(pCMD);
5132e192b24SSimon Glass 			if (flags)
5142e192b24SSimon Glass 				enable_interrupts();
5152e192b24SSimon Glass 			return false;
5162e192b24SSimon Glass 		}
5172e192b24SSimon Glass 		if((pCMD->result[STATUS_0]&0x20)!=0x20) {
5182e192b24SSimon Glass 			PRINTF("Seek error Status: %02X\n",pCMD->result[STATUS_0]);
5192e192b24SSimon Glass 			stop_fdc_drive(pCMD);
5202e192b24SSimon Glass 			return false;
5212e192b24SSimon Glass 		}
5222e192b24SSimon Glass 	} while (true); /* start over */
5232e192b24SSimon Glass 	stop_fdc_drive(pCMD); /* switch off drive */
5242e192b24SSimon Glass 	if (flags)
5252e192b24SSimon Glass 		enable_interrupts();
5262e192b24SSimon Glass 	return true;
5272e192b24SSimon Glass }
5282e192b24SSimon Glass 
5292e192b24SSimon Glass /* Scan all drives and check if drive is present and disk is inserted */
fdc_check_drive(FDC_COMMAND_STRUCT * pCMD,FD_GEO_STRUCT * pFG)5302e192b24SSimon Glass int fdc_check_drive(FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG)
5312e192b24SSimon Glass {
5322e192b24SSimon Glass 	int i,drives,state;
5332e192b24SSimon Glass   /* OK procedure of data book is satisfied.
5342e192b24SSimon Glass 	 * trying to get some information over the drives */
5352e192b24SSimon Glass 	state=0; /* no drives, no disks */
5362e192b24SSimon Glass 	for(drives=0;drives<4;drives++) {
5372e192b24SSimon Glass 		pCMD->drive=drives;
5382e192b24SSimon Glass 		select_fdc_drive(pCMD);
5392e192b24SSimon Glass 		pCMD->blnr=0; /* set to the 1st block */
5402e192b24SSimon Glass 		if (fdc_recalibrate(pCMD, pFG) == false)
5412e192b24SSimon Glass 			continue;
5422e192b24SSimon Glass 		if((pCMD->result[STATUS_0]&0x10)==0x10)
5432e192b24SSimon Glass 			continue;
5442e192b24SSimon Glass 		/* ok drive connected check for disk */
5452e192b24SSimon Glass 		state|=(1<<drives);
5462e192b24SSimon Glass 		pCMD->blnr=pFG->size; /* set to the last block */
5472e192b24SSimon Glass 		if (fdc_seek(pCMD, pFG) == false)
5482e192b24SSimon Glass 			continue;
5492e192b24SSimon Glass 		pCMD->blnr=0; /* set to the 1st block */
5502e192b24SSimon Glass 		if (fdc_recalibrate(pCMD, pFG) == false)
5512e192b24SSimon Glass 			continue;
5522e192b24SSimon Glass 		pCMD->cmd[COMMAND]=FDC_CMD_READ_ID;
5532e192b24SSimon Glass 		if (fdc_issue_cmd(pCMD, pFG) == false)
5542e192b24SSimon Glass 			continue;
5552e192b24SSimon Glass 		state|=(0x10<<drives);
5562e192b24SSimon Glass 	}
5572e192b24SSimon Glass 	stop_fdc_drive(pCMD);
5582e192b24SSimon Glass 	for(i=0;i<4;i++) {
5592e192b24SSimon Glass 		PRINTF("Floppy Drive %d %sconnected %sDisk inserted %s\n",i,
5602e192b24SSimon Glass 			((state&(1<<i))==(1<<i)) ? "":"not ",
5612e192b24SSimon Glass 			((state&(0x10<<i))==(0x10<<i)) ? "":"no ",
5622e192b24SSimon Glass 			((state&(0x10<<i))==(0x10<<i)) ? pFG->name : "");
5632e192b24SSimon Glass 	}
5642e192b24SSimon Glass 	pCMD->flags=state;
5652e192b24SSimon Glass 	return true;
5662e192b24SSimon Glass }
5672e192b24SSimon Glass 
5682e192b24SSimon Glass 
5692e192b24SSimon Glass /**************************************************************************
5702e192b24SSimon Glass * int fdc_setup
5712e192b24SSimon Glass * setup the fdc according the datasheet
5722e192b24SSimon Glass * assuming in PS2 Mode
5732e192b24SSimon Glass */
fdc_setup(int drive,FDC_COMMAND_STRUCT * pCMD,FD_GEO_STRUCT * pFG)5742e192b24SSimon Glass int fdc_setup(int drive, FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG)
5752e192b24SSimon Glass {
5762e192b24SSimon Glass 	int i;
5772e192b24SSimon Glass 
5782e192b24SSimon Glass #ifdef CONFIG_SYS_FDC_HW_INIT
5792e192b24SSimon Glass 	fdc_hw_init ();
5802e192b24SSimon Glass #endif
5812e192b24SSimon Glass 	/* first, we reset the FDC via the DOR */
5822e192b24SSimon Glass 	write_fdc_reg(FDC_DOR,0x00);
5832e192b24SSimon Glass 	for(i=0; i<255; i++) /* then we wait some time */
5842e192b24SSimon Glass 		udelay(500);
5852e192b24SSimon Glass 	/* then, we clear the reset in the DOR */
5862e192b24SSimon Glass 	pCMD->drive=drive;
5872e192b24SSimon Glass 	select_fdc_drive(pCMD);
5882e192b24SSimon Glass 	/* initialize the CCR */
5892e192b24SSimon Glass 	write_fdc_reg(FDC_CCR,pFG->rate);
5902e192b24SSimon Glass 	/* then initialize the DSR */
5912e192b24SSimon Glass 	write_fdc_reg(FDC_DSR,pFG->rate);
5922e192b24SSimon Glass 	if (wait_for_fdc_int() == false) {
5932e192b24SSimon Glass 			PRINTF("Time Out after writing CCR\n");
5942e192b24SSimon Glass 			return false;
5952e192b24SSimon Glass 	}
5962e192b24SSimon Glass 	/* now issue sense Interrupt and status command
5972e192b24SSimon Glass 	 * assuming only one drive present (drive 0) */
5982e192b24SSimon Glass 	pCMD->dma=0; /* we don't use any dma at all */
5992e192b24SSimon Glass 	for(i=0;i<4;i++) {
6002e192b24SSimon Glass 		/* issue sense interrupt for all 4 possible drives */
6012e192b24SSimon Glass 		pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT;
6022e192b24SSimon Glass 		if (fdc_issue_cmd(pCMD, pFG) == false) {
6032e192b24SSimon Glass 			PRINTF("Sense Interrupt for drive %d failed\n",i);
6042e192b24SSimon Glass 		}
6052e192b24SSimon Glass 	}
6062e192b24SSimon Glass 	/* issue the configure command */
6072e192b24SSimon Glass 	pCMD->drive=drive;
6082e192b24SSimon Glass 	select_fdc_drive(pCMD);
6092e192b24SSimon Glass 	pCMD->cmd[COMMAND]=FDC_CMD_CONFIGURE;
6102e192b24SSimon Glass 	if (fdc_issue_cmd(pCMD, pFG) == false) {
6112e192b24SSimon Glass 		PRINTF(" configure timeout\n");
6122e192b24SSimon Glass 		stop_fdc_drive(pCMD);
6132e192b24SSimon Glass 		return false;
6142e192b24SSimon Glass 	}
6152e192b24SSimon Glass 	/* issue specify command */
6162e192b24SSimon Glass 	pCMD->cmd[COMMAND]=FDC_CMD_SPECIFY;
6172e192b24SSimon Glass 	if (fdc_issue_cmd(pCMD, pFG) == false) {
6182e192b24SSimon Glass 		PRINTF(" specify timeout\n");
6192e192b24SSimon Glass 		stop_fdc_drive(pCMD);
6202e192b24SSimon Glass 		return false;
6212e192b24SSimon Glass 
6222e192b24SSimon Glass 	}
6232e192b24SSimon Glass 	/* then, we clear the reset in the DOR */
6242e192b24SSimon Glass 	/* fdc_check_drive(pCMD,pFG);	*/
6252e192b24SSimon Glass 	/*	write_fdc_reg(FDC_DOR,0x04); */
6262e192b24SSimon Glass 
6272e192b24SSimon Glass 	return true;
6282e192b24SSimon Glass }
6292e192b24SSimon Glass 
6302e192b24SSimon Glass /****************************************************************************
6312e192b24SSimon Glass  * main routine do_fdcboot
6322e192b24SSimon Glass  */
do_fdcboot(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])6332e192b24SSimon Glass int do_fdcboot (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
6342e192b24SSimon Glass {
6352e192b24SSimon Glass 	FD_GEO_STRUCT *pFG = (FD_GEO_STRUCT *)floppy_type;
6362e192b24SSimon Glass 	FDC_COMMAND_STRUCT *pCMD = &cmd;
6372e192b24SSimon Glass 	unsigned long addr,imsize;
6382e192b24SSimon Glass #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
6392e192b24SSimon Glass 	image_header_t *hdr;  /* used for fdc boot */
6402e192b24SSimon Glass #endif
6412e192b24SSimon Glass 	unsigned char boot_drive;
6422e192b24SSimon Glass 	int i,nrofblk;
6432e192b24SSimon Glass #if defined(CONFIG_FIT)
6442e192b24SSimon Glass 	const void *fit_hdr = NULL;
6452e192b24SSimon Glass #endif
6462e192b24SSimon Glass 
6472e192b24SSimon Glass 	switch (argc) {
6482e192b24SSimon Glass 	case 1:
6492e192b24SSimon Glass 		addr = CONFIG_SYS_LOAD_ADDR;
6502e192b24SSimon Glass 		boot_drive=CONFIG_SYS_FDC_DRIVE_NUMBER;
6512e192b24SSimon Glass 		break;
6522e192b24SSimon Glass 	case 2:
6532e192b24SSimon Glass 		addr = simple_strtoul(argv[1], NULL, 16);
6542e192b24SSimon Glass 		boot_drive=CONFIG_SYS_FDC_DRIVE_NUMBER;
6552e192b24SSimon Glass 		break;
6562e192b24SSimon Glass 	case 3:
6572e192b24SSimon Glass 		addr = simple_strtoul(argv[1], NULL, 16);
6582e192b24SSimon Glass 		boot_drive=simple_strtoul(argv[2], NULL, 10);
6592e192b24SSimon Glass 		break;
6602e192b24SSimon Glass 	default:
6612e192b24SSimon Glass 		return CMD_RET_USAGE;
6622e192b24SSimon Glass 	}
6632e192b24SSimon Glass 	/* setup FDC and scan for drives  */
6642e192b24SSimon Glass 	if (fdc_setup(boot_drive, pCMD, pFG) == false) {
6652e192b24SSimon Glass 		printf("\n** Error in setup FDC **\n");
6662e192b24SSimon Glass 		return 1;
6672e192b24SSimon Glass 	}
6682e192b24SSimon Glass 	if (fdc_check_drive(pCMD, pFG) == false) {
6692e192b24SSimon Glass 		printf("\n** Error in check_drives **\n");
6702e192b24SSimon Glass 		return 1;
6712e192b24SSimon Glass 	}
6722e192b24SSimon Glass 	if((pCMD->flags&(1<<boot_drive))==0) {
6732e192b24SSimon Glass 		/* drive not available */
6742e192b24SSimon Glass 		printf("\n** Drive %d not availabe **\n",boot_drive);
6752e192b24SSimon Glass 		return 1;
6762e192b24SSimon Glass 	}
6772e192b24SSimon Glass 	if((pCMD->flags&(0x10<<boot_drive))==0) {
6782e192b24SSimon Glass 		/* no disk inserted */
6792e192b24SSimon Glass 		printf("\n** No disk inserted in drive %d **\n",boot_drive);
6802e192b24SSimon Glass 		return 1;
6812e192b24SSimon Glass 	}
6822e192b24SSimon Glass 	/* ok, we have a valid source */
6832e192b24SSimon Glass 	pCMD->drive=boot_drive;
6842e192b24SSimon Glass 	/* read first block */
6852e192b24SSimon Glass 	pCMD->blnr=0;
6862e192b24SSimon Glass 	if (fdc_read_data((unsigned char *)addr, 1, pCMD, pFG) == false) {
6872e192b24SSimon Glass 		printf("\nRead error:");
6882e192b24SSimon Glass 		for(i=0;i<7;i++)
6892e192b24SSimon Glass 			printf("result%d: 0x%02X\n",i,pCMD->result[i]);
6902e192b24SSimon Glass 		return 1;
6912e192b24SSimon Glass 	}
6922e192b24SSimon Glass 
6932e192b24SSimon Glass 	switch (genimg_get_format ((void *)addr)) {
6942e192b24SSimon Glass #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
6952e192b24SSimon Glass 	case IMAGE_FORMAT_LEGACY:
6962e192b24SSimon Glass 		hdr = (image_header_t *)addr;
6972e192b24SSimon Glass 		image_print_contents (hdr);
6982e192b24SSimon Glass 
6992e192b24SSimon Glass 		imsize = image_get_image_size (hdr);
7002e192b24SSimon Glass 		break;
7012e192b24SSimon Glass #endif
7022e192b24SSimon Glass #if defined(CONFIG_FIT)
7032e192b24SSimon Glass 	case IMAGE_FORMAT_FIT:
7042e192b24SSimon Glass 		fit_hdr = (const void *)addr;
7052e192b24SSimon Glass 		puts ("Fit image detected...\n");
7062e192b24SSimon Glass 
7072e192b24SSimon Glass 		imsize = fit_get_size (fit_hdr);
7082e192b24SSimon Glass 		break;
7092e192b24SSimon Glass #endif
7102e192b24SSimon Glass 	default:
7112e192b24SSimon Glass 		puts ("** Unknown image type\n");
7122e192b24SSimon Glass 		return 1;
7132e192b24SSimon Glass 	}
7142e192b24SSimon Glass 
7152e192b24SSimon Glass 	nrofblk=imsize/512;
7162e192b24SSimon Glass 	if((imsize%512)>0)
7172e192b24SSimon Glass 		nrofblk++;
7182e192b24SSimon Glass 	printf("Loading %ld Bytes (%d blocks) at 0x%08lx..\n",imsize,nrofblk,addr);
7192e192b24SSimon Glass 	pCMD->blnr=0;
7202e192b24SSimon Glass 	if (fdc_read_data((unsigned char *)addr, nrofblk, pCMD, pFG) == false) {
7212e192b24SSimon Glass 		/* read image block */
7222e192b24SSimon Glass 		printf("\nRead error:");
7232e192b24SSimon Glass 		for(i=0;i<7;i++)
7242e192b24SSimon Glass 			printf("result%d: 0x%02X\n",i,pCMD->result[i]);
7252e192b24SSimon Glass 		return 1;
7262e192b24SSimon Glass 	}
7272e192b24SSimon Glass 	printf("OK %ld Bytes loaded.\n",imsize);
7282e192b24SSimon Glass 
7292e192b24SSimon Glass 	flush_cache (addr, imsize);
7302e192b24SSimon Glass 
7312e192b24SSimon Glass #if defined(CONFIG_FIT)
7322e192b24SSimon Glass 	/* This cannot be done earlier, we need complete FIT image in RAM first */
7332e192b24SSimon Glass 	if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) {
7342e192b24SSimon Glass 		if (!fit_check_format (fit_hdr)) {
7352e192b24SSimon Glass 			puts ("** Bad FIT image format\n");
7362e192b24SSimon Glass 			return 1;
7372e192b24SSimon Glass 		}
7382e192b24SSimon Glass 		fit_print_contents (fit_hdr);
7392e192b24SSimon Glass 	}
7402e192b24SSimon Glass #endif
7412e192b24SSimon Glass 
7422e192b24SSimon Glass 	/* Loading ok, update default load address */
7432e192b24SSimon Glass 	load_addr = addr;
7442e192b24SSimon Glass 
7452e192b24SSimon Glass 	return bootm_maybe_autostart(cmdtp, argv[0]);
7462e192b24SSimon Glass }
7472e192b24SSimon Glass 
7482e192b24SSimon Glass U_BOOT_CMD(
7492e192b24SSimon Glass 	fdcboot,	3,	1,	do_fdcboot,
7502e192b24SSimon Glass 	"boot from floppy device",
7512e192b24SSimon Glass 	"loadAddr drive"
7522e192b24SSimon Glass );
753