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