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