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