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