Blame view

cmd/fdc.c 20.5 KB
3863585bb   wdenk   Initial revision
1
2
3
4
  /*
   * (C) Copyright 2001
   * Denis Peter, MPL AG, d.peter@mpl.ch.
   *
1a4596601   Wolfgang Denk   Add GPL-2.0+ SPDX...
5
   * SPDX-License-Identifier:	GPL-2.0+
3863585bb   wdenk   Initial revision
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   */
  /*
   * Floppy Disk support
   */
  
  #include <common.h>
  #include <config.h>
  #include <command.h>
  #include <image.h>
  
  
  #undef	FDC_DEBUG
  
  #ifdef	FDC_DEBUG
  #define	PRINTF(fmt,args...)	printf (fmt ,##args)
  #else
  #define PRINTF(fmt,args...)
  #endif
baa26db41   Jon Loeliger   common/cmd_[af]*:...
24
  /*#if defined(CONFIG_CMD_DATE) */
8bde7f776   wdenk   * Code cleanup:
25
26
  /*#include <rtc.h> */
  /*#endif */
3863585bb   wdenk   Initial revision
27

3863585bb   wdenk   Initial revision
28
  typedef struct {
53677ef18   Wolfgang Denk   Big white-space c...
29
30
31
32
33
34
35
36
  	int		flags;		/* connected drives ect */
  	unsigned long	blnr;		/* Logical block nr */
  	uchar		drive;		/* drive no */
  	uchar		cmdlen;		/* cmd length */
  	uchar		cmd[16];	/* cmd desc */
  	uchar		dma;		/* if > 0 dma enabled */
  	uchar		result[11];	/* status information */
  	uchar		resultlen;	/* lenght of result */
3863585bb   wdenk   Initial revision
37
  } FDC_COMMAND_STRUCT;
53677ef18   Wolfgang Denk   Big white-space c...
38

3863585bb   wdenk   Initial revision
39
40
41
42
43
44
45
46
47
48
  /* flags: only the lower 8bit used:
   * bit 0 if set drive 0 is present
   * bit 1 if set drive 1 is present
   * bit 2 if set drive 2 is present
   * bit 3 if set drive 3 is present
   * bit 4 if set disk in drive 0 is inserted
   * bit 5 if set disk in drive 1 is inserted
   * bit 6 if set disk in drive 2 is inserted
   * bit 7 if set disk in drive 4 is inserted
   */
3863585bb   wdenk   Initial revision
49
  /* cmd indexes */
53677ef18   Wolfgang Denk   Big white-space c...
50
51
  #define COMMAND			0
  #define DRIVE			1
3863585bb   wdenk   Initial revision
52
  #define CONFIG0			1
53677ef18   Wolfgang Denk   Big white-space c...
53
54
  #define SPEC_HUTSRT		1
  #define TRACK			2
3863585bb   wdenk   Initial revision
55
56
  #define CONFIG1			2
  #define SPEC_HLT		2
53677ef18   Wolfgang Denk   Big white-space c...
57
  #define HEAD			3
3863585bb   wdenk   Initial revision
58
  #define CONFIG2			3
53677ef18   Wolfgang Denk   Big white-space c...
59
60
61
62
63
  #define SECTOR			4
  #define SECTOR_SIZE		5
  #define LAST_TRACK		6
  #define GAP			7
  #define DTL			8
3863585bb   wdenk   Initial revision
64
  /* result indexes */
53677ef18   Wolfgang Denk   Big white-space c...
65
66
67
68
69
70
71
72
  #define STATUS_0		0
  #define STATUS_PCN		1
  #define STATUS_1		1
  #define STATUS_2		2
  #define STATUS_TRACK		3
  #define STATUS_HEAD		4
  #define STATUS_SECT		5
  #define STATUS_SECT_SIZE	6
3863585bb   wdenk   Initial revision
73
74
75
76
77
78
79
80
81
82
83
84
85
86
  
  
  /* Register addresses */
  #define FDC_BASE	0x3F0
  #define FDC_SRA		FDC_BASE + 0	/* Status Register A */
  #define FDC_SRB		FDC_BASE + 1	/* Status Register B */
  #define FDC_DOR		FDC_BASE + 2	/* Digital Output Register */
  #define FDC_TDR		FDC_BASE + 3	/* Tape Drive Register */
  #define FDC_DSR		FDC_BASE + 4	/* Data rate Register */
  #define FDC_MSR		FDC_BASE + 4	/* Main Status Register */
  #define FDC_FIFO	FDC_BASE + 5	/* FIFO */
  #define FDC_DIR		FDC_BASE + 6	/* Digital Input Register */
  #define FDC_CCR		FDC_BASE + 7	/* Configuration Control */
  /* Commands */
53677ef18   Wolfgang Denk   Big white-space c...
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
  #define FDC_CMD_SENSE_INT	0x08
  #define FDC_CMD_CONFIGURE	0x13
  #define FDC_CMD_SPECIFY		0x03
  #define FDC_CMD_RECALIBRATE	0x07
  #define FDC_CMD_READ		0x06
  #define FDC_CMD_READ_TRACK	0x02
  #define FDC_CMD_READ_ID		0x0A
  #define FDC_CMD_DUMP_REG	0x0E
  #define FDC_CMD_SEEK		0x0F
  
  #define FDC_CMD_SENSE_INT_LEN	0x01
  #define FDC_CMD_CONFIGURE_LEN	0x04
  #define FDC_CMD_SPECIFY_LEN	0x03
  #define FDC_CMD_RECALIBRATE_LEN	0x02
  #define FDC_CMD_READ_LEN	0x09
  #define FDC_CMD_READ_TRACK_LEN	0x09
  #define FDC_CMD_READ_ID_LEN	0x02
  #define FDC_CMD_DUMP_REG_LEN	0x01
  #define FDC_CMD_SEEK_LEN	0x03
  
  #define FDC_FIFO_THR		0x0C
  #define FDC_FIFO_DIS		0x00
3863585bb   wdenk   Initial revision
109
  #define FDC_IMPLIED_SEEK	0x01
53677ef18   Wolfgang Denk   Big white-space c...
110
111
112
113
114
  #define FDC_POLL_DIS		0x00
  #define FDC_PRE_TRK		0x00
  #define FDC_CONFIGURE		FDC_FIFO_THR | (FDC_POLL_DIS<<4) | (FDC_FIFO_DIS<<5) | (FDC_IMPLIED_SEEK << 6)
  #define FDC_MFM_MODE		0x01 /* MFM enable */
  #define FDC_SKIP_MODE		0x00 /* skip enable */
3863585bb   wdenk   Initial revision
115
116
117
118
119
120
121
122
  
  #define FDC_TIME_OUT 100000 /* time out */
  #define	FDC_RW_RETRIES		3 /* read write retries */
  #define FDC_CAL_RETRIES		3 /* calibration and seek retries */
  
  
  /* Disk structure */
  typedef struct  {
53677ef18   Wolfgang Denk   Big white-space c...
123
124
125
126
127
128
129
130
131
132
133
134
  	unsigned int size;	/* nr of sectors total */
  	unsigned int sect;	/* sectors per track */
  	unsigned int head;	/* nr of heads */
  	unsigned int track;	/* nr of tracks */
  	unsigned int stretch;	/* !=0 means double track steps */
  	unsigned char	gap;	/* gap1 size */
  	unsigned char	rate;	/* data rate. |= 0x40 for perpendicular */
  	unsigned char	spec1;	/* stepping rate, head unload time */
  	unsigned char	fmt_gap;/* gap2 size */
  	unsigned char hlt;	/* head load time */
  	unsigned char sect_code;/* Sector Size code */
  	const char	* name;	/* used only for predefined formats */
3863585bb   wdenk   Initial revision
135
136
137
138
139
140
141
142
143
144
  } FD_GEO_STRUCT;
  
  
  /* supported Floppy types (currently only one) */
  const static FD_GEO_STRUCT floppy_type[2] = {
  	{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,16,2,"H1440" },	/*  7 1.44MB 3.5"   */
  	{    0, 0,0, 0,0,0x00,0x00,0x00,0x00, 0,0,NULL    },	/*  end of table    */
  };
  
  static FDC_COMMAND_STRUCT cmd; /* global command struct */
7f6c2cbc2   wdenk   * Vince Husovsky,...
145
  /* If the boot drive number is undefined, we assume it's drive 0             */
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
146
147
  #ifndef CONFIG_SYS_FDC_DRIVE_NUMBER
  #define CONFIG_SYS_FDC_DRIVE_NUMBER 0
7f6c2cbc2   wdenk   * Vince Husovsky,...
148
149
150
  #endif
  
  /* Hardware access */
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
151
152
  #ifndef CONFIG_SYS_ISA_IO_STRIDE
  #define CONFIG_SYS_ISA_IO_STRIDE 1
7f6c2cbc2   wdenk   * Vince Husovsky,...
153
  #endif
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
154
155
  #ifndef CONFIG_SYS_ISA_IO_OFFSET
  #define CONFIG_SYS_ISA_IO_OFFSET 0
7f6c2cbc2   wdenk   * Vince Husovsky,...
156
  #endif
3863585bb   wdenk   Initial revision
157
158
159
160
  /* Supporting Functions */
  /* reads a Register of the FDC */
  unsigned char read_fdc_reg(unsigned int addr)
  {
2262cfeef   wdenk   * Patch by Daniel...
161
  	volatile unsigned char *val =
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
162
163
164
  		(volatile unsigned char *)(CONFIG_SYS_ISA_IO_BASE_ADDRESS +
  					   (addr * CONFIG_SYS_ISA_IO_STRIDE) +
  					   CONFIG_SYS_ISA_IO_OFFSET);
8bde7f776   wdenk   * Code cleanup:
165

7f6c2cbc2   wdenk   * Vince Husovsky,...
166
  	return val [0];
3863585bb   wdenk   Initial revision
167
168
169
170
171
  }
  
  /* writes a Register of the FDC */
  void write_fdc_reg(unsigned int addr, unsigned char val)
  {
8bde7f776   wdenk   * Code cleanup:
172
  	volatile unsigned char *tmp =
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
173
174
175
  		(volatile unsigned char *)(CONFIG_SYS_ISA_IO_BASE_ADDRESS +
  					   (addr * CONFIG_SYS_ISA_IO_STRIDE) +
  					   CONFIG_SYS_ISA_IO_OFFSET);
7f6c2cbc2   wdenk   * Vince Husovsky,...
176
  	tmp[0]=val;
3863585bb   wdenk   Initial revision
177
178
179
180
181
182
183
184
185
186
  }
  
  /* waits for an interrupt (polling) */
  int wait_for_fdc_int(void)
  {
  	unsigned long timeout;
  	timeout = FDC_TIME_OUT;
  	while((read_fdc_reg(FDC_SRA)&0x80)==0) {
  		timeout--;
  		udelay(10);
eae4b2b67   Vagrant Cascadian   Fix spelling of "...
187
  		if(timeout==0) /* timeout occurred */
472d54605   York Sun   Consolidate bool ...
188
  			return false;
3863585bb   wdenk   Initial revision
189
  	}
472d54605   York Sun   Consolidate bool ...
190
  	return true;
3863585bb   wdenk   Initial revision
191
  }
3863585bb   wdenk   Initial revision
192
193
194
195
196
197
198
199
200
201
  /* reads a byte from the FIFO of the FDC and checks direction and RQM bit
     of the MSR. returns -1 if timeout, or byte if ok */
  int read_fdc_byte(void)
  {
  	unsigned long timeout;
  	timeout = FDC_TIME_OUT;
  	while((read_fdc_reg(FDC_MSR)&0xC0)!=0xC0) {
  		/* direction out and ready */
  		udelay(10);
  		timeout--;
eae4b2b67   Vagrant Cascadian   Fix spelling of "...
202
  		if(timeout==0) /* timeout occurred */
3863585bb   wdenk   Initial revision
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
  			return -1;
  	}
  	return read_fdc_reg(FDC_FIFO);
  }
  
  /* if the direction of the FIFO is wrong, this routine is used to
     empty the FIFO. Should _not_ be used */
  int fdc_need_more_output(void)
  {
  	unsigned char c;
  	while((read_fdc_reg(FDC_MSR)&0xC0)==0xC0)	{
  			c=(unsigned char)read_fdc_byte();
  			printf("Error: more output: %x
  ",c);
  	}
472d54605   York Sun   Consolidate bool ...
218
  	return true;
3863585bb   wdenk   Initial revision
219
220
221
222
223
224
225
226
227
228
229
230
231
232
  }
  
  
  /* writes a byte to the FIFO of the FDC and checks direction and RQM bit
     of the MSR */
  int write_fdc_byte(unsigned char val)
  {
  	unsigned long timeout;
  	timeout = FDC_TIME_OUT;
  	while((read_fdc_reg(FDC_MSR)&0xC0)!=0x80) {
  		/* direction in and ready for byte */
  		timeout--;
  		udelay(10);
  		fdc_need_more_output();
eae4b2b67   Vagrant Cascadian   Fix spelling of "...
233
  		if(timeout==0) /* timeout occurred */
472d54605   York Sun   Consolidate bool ...
234
  			return false;
3863585bb   wdenk   Initial revision
235
236
  	}
  	write_fdc_reg(FDC_FIFO,val);
472d54605   York Sun   Consolidate bool ...
237
  	return true;
3863585bb   wdenk   Initial revision
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
  }
  
  /* sets up all FDC commands and issues it to the FDC. If
     the command causes direct results (no Execution Phase)
     the result is be read as well. */
  
  int fdc_issue_cmd(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG)
  {
  	int i;
  	unsigned long head,track,sect,timeout;
  	track = pCMD->blnr / (pFG->sect * pFG->head); /* track nr */
  	sect =  pCMD->blnr % (pFG->sect * pFG->head); /* remaining blocks */
  	head = sect / pFG->sect; /* head nr */
  	sect =  sect % pFG->sect; /* remaining blocks */
  	sect++; /* sectors are 1 based */
2262cfeef   wdenk   * Patch by Daniel...
253
254
255
  	PRINTF("Cmd 0x%02x Track %ld, Head %ld, Sector %ld, Drive %d (blnr %ld)
  ",
  		pCMD->cmd[0],track,head,sect,pCMD->drive,pCMD->blnr);
7f6c2cbc2   wdenk   * Vince Husovsky,...
256

3863585bb   wdenk   Initial revision
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
  	if(head|=0) { /* max heads = 2 */
  		pCMD->cmd[DRIVE]=pCMD->drive | 0x04; /* head 1 */
  		pCMD->cmd[HEAD]=(unsigned char) head; /* head register */
  	}
  	else {
  		pCMD->cmd[DRIVE]=pCMD->drive; /* head 0 */
  		pCMD->cmd[HEAD]=(unsigned char) head; /* head register */
  	}
  	pCMD->cmd[TRACK]=(unsigned char) track; /* track */
  	switch (pCMD->cmd[COMMAND]) {
  		case FDC_CMD_READ:
  			pCMD->cmd[SECTOR]=(unsigned char) sect; /* sector */
  			pCMD->cmd[SECTOR_SIZE]=pFG->sect_code; /* sector size code */
  			pCMD->cmd[LAST_TRACK]=pFG->sect; /* End of track */
  			pCMD->cmd[GAP]=pFG->gap; /* gap */
  			pCMD->cmd[DTL]=0xFF; /* DTL */
  			pCMD->cmdlen=FDC_CMD_READ_LEN;
  			pCMD->cmd[COMMAND]|=(FDC_MFM_MODE<<6); /* set MFM bit */
  			pCMD->cmd[COMMAND]|=(FDC_SKIP_MODE<<5); /* set Skip bit */
  			pCMD->resultlen=0;  /* result only after execution */
  			break;
  		case FDC_CMD_SEEK:
  			pCMD->cmdlen=FDC_CMD_SEEK_LEN;
  			pCMD->resultlen=0;  /* no result */
  			break;
  		case FDC_CMD_CONFIGURE:
  			pCMD->cmd[CONFIG0]=0;
  			pCMD->cmd[CONFIG1]=FDC_CONFIGURE; /* FIFO Threshold, Poll, Enable FIFO */
53677ef18   Wolfgang Denk   Big white-space c...
285
  			pCMD->cmd[CONFIG2]=FDC_PRE_TRK;	/* Precompensation Track */
3863585bb   wdenk   Initial revision
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
  			pCMD->cmdlen=FDC_CMD_CONFIGURE_LEN;
  			pCMD->resultlen=0;  /* no result */
  			break;
  		case FDC_CMD_SPECIFY:
  			pCMD->cmd[SPEC_HUTSRT]=pFG->spec1;
  			pCMD->cmd[SPEC_HLT]=(pFG->hlt)<<1; /* head load time */
  			if(pCMD->dma==0)
  				pCMD->cmd[SPEC_HLT]|=0x1; /* no dma */
  			pCMD->cmdlen=FDC_CMD_SPECIFY_LEN;
  			pCMD->resultlen=0;  /* no result */
  			break;
  		case FDC_CMD_DUMP_REG:
  			pCMD->cmdlen=FDC_CMD_DUMP_REG_LEN;
  			pCMD->resultlen=10;  /* 10 byte result */
  			break;
  		case FDC_CMD_READ_ID:
  			pCMD->cmd[COMMAND]|=(FDC_MFM_MODE<<6); /* set MFM bit */
  			pCMD->cmdlen=FDC_CMD_READ_ID_LEN;
  			pCMD->resultlen=7;  /* 7 byte result */
  			break;
  		case FDC_CMD_RECALIBRATE:
  			pCMD->cmd[DRIVE]&=0x03; /* don't set the head bit */
  			pCMD->cmdlen=FDC_CMD_RECALIBRATE_LEN;
  			pCMD->resultlen=0;  /* no result */
  			break;
  			break;
  		case FDC_CMD_SENSE_INT:
  			pCMD->cmdlen=FDC_CMD_SENSE_INT_LEN;
  			pCMD->resultlen=2;
  			break;
  	}
  	for(i=0;i<pCMD->cmdlen;i++) {
  		/* PRINTF("write cmd%d = 0x%02X
  ",i,pCMD->cmd[i]); */
472d54605   York Sun   Consolidate bool ...
320
  		if (write_fdc_byte(pCMD->cmd[i]) == false) {
3863585bb   wdenk   Initial revision
321
322
  			PRINTF("Error: timeout while issue cmd%d
  ",i);
472d54605   York Sun   Consolidate bool ...
323
  			return false;
3863585bb   wdenk   Initial revision
324
325
326
327
328
329
330
331
332
  		}
  	}
  	timeout=FDC_TIME_OUT;
  	for(i=0;i<pCMD->resultlen;i++) {
  		while((read_fdc_reg(FDC_MSR)&0xC0)!=0xC0) {
  			timeout--;
  			if(timeout==0) {
  				PRINTF(" timeout while reading result%d MSR=0x%02X
  ",i,read_fdc_reg(FDC_MSR));
472d54605   York Sun   Consolidate bool ...
333
  				return false;
3863585bb   wdenk   Initial revision
334
335
336
337
  			}
  		}
  		pCMD->result[i]=(unsigned char)read_fdc_byte();
  	}
472d54605   York Sun   Consolidate bool ...
338
  	return true;
3863585bb   wdenk   Initial revision
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
  }
  
  /* selects the drive assigned in the cmd structur and
     switches on the Motor */
  void select_fdc_drive(FDC_COMMAND_STRUCT *pCMD)
  {
  	unsigned char val;
  
  	val=(1<<(4+pCMD->drive))|pCMD->drive|0xC; /* set reset, dma gate and motor bits */
  	if((read_fdc_reg(FDC_DOR)&val)!=val) {
  		write_fdc_reg(FDC_DOR,val);
  		for(val=0;val<255;val++)
  			udelay(500); /* wait some time to start motor */
  	}
  }
  
  /* switches off the Motor of the specified drive */
  void stop_fdc_drive(FDC_COMMAND_STRUCT *pCMD)
  {
  	unsigned char val;
  
  	val=(1<<(4+pCMD->drive))|pCMD->drive; /* sets motor bits */
  	write_fdc_reg(FDC_DOR,(read_fdc_reg(FDC_DOR)&~val));
  }
  
  /* issues a recalibrate command, waits for interrupt and
   * issues a sense_interrupt */
  int fdc_recalibrate(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG)
  {
  	pCMD->cmd[COMMAND]=FDC_CMD_RECALIBRATE;
472d54605   York Sun   Consolidate bool ...
369
370
371
  	if (fdc_issue_cmd(pCMD, pFG) == false)
  		return false;
  	while (wait_for_fdc_int() != true);
3863585bb   wdenk   Initial revision
372
373
374
375
376
377
378
379
380
  	pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT;
  	return(fdc_issue_cmd(pCMD,pFG));
  }
  
  /* issues a recalibrate command, waits for interrupt and
   * issues a sense_interrupt */
  int fdc_seek(FDC_COMMAND_STRUCT *pCMD,FD_GEO_STRUCT *pFG)
  {
  	pCMD->cmd[COMMAND]=FDC_CMD_SEEK;
472d54605   York Sun   Consolidate bool ...
381
382
383
  	if (fdc_issue_cmd(pCMD, pFG) == false)
  		return false;
  	while (wait_for_fdc_int() != true);
3863585bb   wdenk   Initial revision
384
385
386
  	pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT;
  	return(fdc_issue_cmd(pCMD,pFG));
  }
3863585bb   wdenk   Initial revision
387
388
389
390
391
392
393
  /* terminates current command, by not servicing the FIFO
   * waits for interrupt and fills in the result bytes */
  int fdc_terminate(FDC_COMMAND_STRUCT *pCMD)
  {
  	int i;
  	for(i=0;i<100;i++)
  		udelay(500); /* wait 500usec for fifo overrun */
eae4b2b67   Vagrant Cascadian   Fix spelling of "...
394
  	while((read_fdc_reg(FDC_SRA)&0x80)==0x00); /* wait as long as no int has occurred */
3863585bb   wdenk   Initial revision
395
396
397
  	for(i=0;i<7;i++) {
  		pCMD->result[i]=(unsigned char)read_fdc_byte();
  	}
472d54605   York Sun   Consolidate bool ...
398
  	return true;
3863585bb   wdenk   Initial revision
399
400
401
402
403
404
  }
  
  /* reads data from FDC, seek commands are issued automatic */
  int fdc_read_data(unsigned char *buffer, unsigned long blocks,FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG)
  {
    /* first seek to start address */
4ec6e4a88   Wolfgang Denk   common/cmd_fdc.c:...
405
406
  	unsigned long len,readblk,i,timeout,ii,offset;
  	unsigned char c,retriesrw,retriescal;
3863585bb   wdenk   Initial revision
407
408
409
410
411
412
413
414
415
416
  	unsigned char *bufferw; /* working buffer */
  	int sect_size;
  	int flags;
  
  	flags=disable_interrupts(); /* switch off all Interrupts */
  	select_fdc_drive(pCMD); /* switch on drive */
  	sect_size=0x080<<pFG->sect_code;
  	retriesrw=0;
  	retriescal=0;
  	offset=0;
472d54605   York Sun   Consolidate bool ...
417
  	if (fdc_seek(pCMD, pFG) == false) {
3863585bb   wdenk   Initial revision
418
  		stop_fdc_drive(pCMD);
4ec6e4a88   Wolfgang Denk   common/cmd_fdc.c:...
419
420
  		if (flags)
  			enable_interrupts();
472d54605   York Sun   Consolidate bool ...
421
  		return false;
3863585bb   wdenk   Initial revision
422
423
424
425
426
  	}
  	if((pCMD->result[STATUS_0]&0x20)!=0x20) {
  		printf("Seek error Status: %02X
  ",pCMD->result[STATUS_0]);
  		stop_fdc_drive(pCMD);
4ec6e4a88   Wolfgang Denk   common/cmd_fdc.c:...
427
428
  		if (flags)
  			enable_interrupts();
472d54605   York Sun   Consolidate bool ...
429
  		return false;
3863585bb   wdenk   Initial revision
430
  	}
3863585bb   wdenk   Initial revision
431
  	/* now determine the next seek point */
4ec6e4a88   Wolfgang Denk   common/cmd_fdc.c:...
432
  	/*	lastblk=pCMD->blnr + blocks; */
3863585bb   wdenk   Initial revision
433
434
435
436
437
438
439
440
  	/*	readblk=(pFG->head*pFG->sect)-(pCMD->blnr%(pFG->head*pFG->sect)); */
  	readblk=pFG->sect-(pCMD->blnr%pFG->sect);
  	PRINTF("1st nr of block possible read %ld start %ld
  ",readblk,pCMD->blnr);
  	if(readblk>blocks) /* is end within 1st track */
  		readblk=blocks; /* yes, correct it */
  	PRINTF("we read %ld blocks start %ld
  ",readblk,pCMD->blnr);
d0ff51ba5   Wolfgang Denk   Code cleanup: fix...
441
  	bufferw = &buffer[0]; /* setup working buffer */
3863585bb   wdenk   Initial revision
442
443
444
445
  	do {
  retryrw:
  		len=sect_size * readblk;
  		pCMD->cmd[COMMAND]=FDC_CMD_READ;
472d54605   York Sun   Consolidate bool ...
446
  		if (fdc_issue_cmd(pCMD, pFG) == false) {
3863585bb   wdenk   Initial revision
447
  			stop_fdc_drive(pCMD);
4ec6e4a88   Wolfgang Denk   common/cmd_fdc.c:...
448
449
  			if (flags)
  				enable_interrupts();
472d54605   York Sun   Consolidate bool ...
450
  			return false;
3863585bb   wdenk   Initial revision
451
452
453
454
455
456
457
458
459
460
  		}
  		for (i=0;i<len;i++) {
  			timeout=FDC_TIME_OUT;
  			do {
  				c=read_fdc_reg(FDC_MSR);
  				if((c&0xC0)==0xC0) {
  					bufferw[i]=read_fdc_reg(FDC_FIFO);
  					break;
  				}
  				if((c&0xC0)==0x80) { /* output */
a6f70a3d1   Vagrant Cascadian   Fix spelling of "...
461
462
  					PRINTF("Transfer error transferred: at %ld, MSR=%02X
  ",i,c);
3863585bb   wdenk   Initial revision
463
464
465
466
467
468
469
470
  					if(i>6) {
  						for(ii=0;ii<7;ii++) {
  							pCMD->result[ii]=bufferw[(i-7+ii)];
  						} /* for */
  					}
  					if(retriesrw++>FDC_RW_RETRIES) {
  						if (retriescal++>FDC_CAL_RETRIES) {
  							stop_fdc_drive(pCMD);
4ec6e4a88   Wolfgang Denk   common/cmd_fdc.c:...
471
472
  							if (flags)
  								enable_interrupts();
472d54605   York Sun   Consolidate bool ...
473
  							return false;
3863585bb   wdenk   Initial revision
474
475
476
477
  						}
  						else {
  							PRINTF(" trying to recalibrate Try %d
  ",retriescal);
472d54605   York Sun   Consolidate bool ...
478
  							if (fdc_recalibrate(pCMD, pFG) == false) {
3863585bb   wdenk   Initial revision
479
  								stop_fdc_drive(pCMD);
4ec6e4a88   Wolfgang Denk   common/cmd_fdc.c:...
480
481
  								if (flags)
  									enable_interrupts();
472d54605   York Sun   Consolidate bool ...
482
  								return false;
3863585bb   wdenk   Initial revision
483
484
485
486
487
488
489
490
491
492
493
494
  							}
  							retriesrw=0;
  							goto retrycal;
  						} /* else >FDC_CAL_RETRIES */
  					}
  					else {
  						PRINTF("Read retry %d
  ",retriesrw);
  						goto retryrw;
  					} /* else >FDC_RW_RETRIES */
  				}/* if output */
  				timeout--;
472d54605   York Sun   Consolidate bool ...
495
  			} while (true);
3863585bb   wdenk   Initial revision
496
497
498
499
500
  		} /* for len */
  		/* the last sector of a track or all data has been read,
  		 * we need to get the results */
  		fdc_terminate(pCMD);
  		offset+=(sect_size*readblk); /* set up buffer pointer */
d0ff51ba5   Wolfgang Denk   Code cleanup: fix...
501
  		bufferw = &buffer[offset];
3863585bb   wdenk   Initial revision
502
503
504
505
506
507
508
509
510
511
512
  		pCMD->blnr+=readblk; /* update current block nr */
  		blocks-=readblk; /* update blocks */
  		if(blocks==0)
  			break; /* we are finish */
  		/* setup new read blocks */
  		/*	readblk=pFG->head*pFG->sect; */
  		readblk=pFG->sect;
  		if(readblk>blocks)
  			readblk=blocks;
  retrycal:
  		/* a seek is necessary */
472d54605   York Sun   Consolidate bool ...
513
  		if (fdc_seek(pCMD, pFG) == false) {
3863585bb   wdenk   Initial revision
514
  			stop_fdc_drive(pCMD);
4ec6e4a88   Wolfgang Denk   common/cmd_fdc.c:...
515
516
  			if (flags)
  				enable_interrupts();
472d54605   York Sun   Consolidate bool ...
517
  			return false;
3863585bb   wdenk   Initial revision
518
519
520
521
522
  		}
  		if((pCMD->result[STATUS_0]&0x20)!=0x20) {
  			PRINTF("Seek error Status: %02X
  ",pCMD->result[STATUS_0]);
  			stop_fdc_drive(pCMD);
472d54605   York Sun   Consolidate bool ...
523
  			return false;
3863585bb   wdenk   Initial revision
524
  		}
472d54605   York Sun   Consolidate bool ...
525
  	} while (true); /* start over */
3863585bb   wdenk   Initial revision
526
  	stop_fdc_drive(pCMD); /* switch off drive */
4ec6e4a88   Wolfgang Denk   common/cmd_fdc.c:...
527
528
  	if (flags)
  		enable_interrupts();
472d54605   York Sun   Consolidate bool ...
529
  	return true;
3863585bb   wdenk   Initial revision
530
531
532
533
534
535
536
537
538
539
540
541
542
  }
  
  /* Scan all drives and check if drive is present and disk is inserted */
  int fdc_check_drive(FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG)
  {
  	int i,drives,state;
    /* OK procedure of data book is satisfied.
  	 * trying to get some information over the drives */
  	state=0; /* no drives, no disks */
  	for(drives=0;drives<4;drives++) {
  		pCMD->drive=drives;
  		select_fdc_drive(pCMD);
  		pCMD->blnr=0; /* set to the 1st block */
472d54605   York Sun   Consolidate bool ...
543
  		if (fdc_recalibrate(pCMD, pFG) == false)
7f6c2cbc2   wdenk   * Vince Husovsky,...
544
  			continue;
3863585bb   wdenk   Initial revision
545
  		if((pCMD->result[STATUS_0]&0x10)==0x10)
7f6c2cbc2   wdenk   * Vince Husovsky,...
546
  			continue;
3863585bb   wdenk   Initial revision
547
548
549
  		/* ok drive connected check for disk */
  		state|=(1<<drives);
  		pCMD->blnr=pFG->size; /* set to the last block */
472d54605   York Sun   Consolidate bool ...
550
  		if (fdc_seek(pCMD, pFG) == false)
7f6c2cbc2   wdenk   * Vince Husovsky,...
551
  			continue;
3863585bb   wdenk   Initial revision
552
  		pCMD->blnr=0; /* set to the 1st block */
472d54605   York Sun   Consolidate bool ...
553
  		if (fdc_recalibrate(pCMD, pFG) == false)
7f6c2cbc2   wdenk   * Vince Husovsky,...
554
  			continue;
3863585bb   wdenk   Initial revision
555
  		pCMD->cmd[COMMAND]=FDC_CMD_READ_ID;
472d54605   York Sun   Consolidate bool ...
556
  		if (fdc_issue_cmd(pCMD, pFG) == false)
7f6c2cbc2   wdenk   * Vince Husovsky,...
557
  			continue;
3863585bb   wdenk   Initial revision
558
559
560
561
562
563
564
565
566
567
568
  		state|=(0x10<<drives);
  	}
  	stop_fdc_drive(pCMD);
  	for(i=0;i<4;i++) {
  		PRINTF("Floppy Drive %d %sconnected %sDisk inserted %s
  ",i,
  			((state&(1<<i))==(1<<i)) ? "":"not ",
  			((state&(0x10<<i))==(0x10<<i)) ? "":"no ",
  			((state&(0x10<<i))==(0x10<<i)) ? pFG->name : "");
  	}
  	pCMD->flags=state;
472d54605   York Sun   Consolidate bool ...
569
  	return true;
3863585bb   wdenk   Initial revision
570
571
572
573
574
575
576
577
  }
  
  
  /**************************************************************************
  * int fdc_setup
  * setup the fdc according the datasheet
  * assuming in PS2 Mode
  */
2262cfeef   wdenk   * Patch by Daniel...
578
  int fdc_setup(int drive, FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG)
3863585bb   wdenk   Initial revision
579
  {
3863585bb   wdenk   Initial revision
580
  	int i;
7f6c2cbc2   wdenk   * Vince Husovsky,...
581

6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
582
  #ifdef CONFIG_SYS_FDC_HW_INIT
8bde7f776   wdenk   * Code cleanup:
583
  	fdc_hw_init ();
7f6c2cbc2   wdenk   * Vince Husovsky,...
584
  #endif
3863585bb   wdenk   Initial revision
585
586
587
588
589
  	/* first, we reset the FDC via the DOR */
  	write_fdc_reg(FDC_DOR,0x00);
  	for(i=0; i<255; i++) /* then we wait some time */
  		udelay(500);
  	/* then, we clear the reset in the DOR */
2262cfeef   wdenk   * Patch by Daniel...
590
  	pCMD->drive=drive;
3863585bb   wdenk   Initial revision
591
592
593
594
595
  	select_fdc_drive(pCMD);
  	/* initialize the CCR */
  	write_fdc_reg(FDC_CCR,pFG->rate);
  	/* then initialize the DSR */
  	write_fdc_reg(FDC_DSR,pFG->rate);
472d54605   York Sun   Consolidate bool ...
596
  	if (wait_for_fdc_int() == false) {
3863585bb   wdenk   Initial revision
597
598
  			PRINTF("Time Out after writing CCR
  ");
472d54605   York Sun   Consolidate bool ...
599
  			return false;
3863585bb   wdenk   Initial revision
600
601
602
603
604
605
606
  	}
  	/* now issue sense Interrupt and status command
  	 * assuming only one drive present (drive 0) */
  	pCMD->dma=0; /* we don't use any dma at all */
  	for(i=0;i<4;i++) {
  		/* issue sense interrupt for all 4 possible drives */
  		pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT;
472d54605   York Sun   Consolidate bool ...
607
  		if (fdc_issue_cmd(pCMD, pFG) == false) {
3863585bb   wdenk   Initial revision
608
609
610
611
  			PRINTF("Sense Interrupt for drive %d failed
  ",i);
  		}
  	}
2262cfeef   wdenk   * Patch by Daniel...
612
613
  	/* issue the configure command */
  	pCMD->drive=drive;
3863585bb   wdenk   Initial revision
614
615
  	select_fdc_drive(pCMD);
  	pCMD->cmd[COMMAND]=FDC_CMD_CONFIGURE;
472d54605   York Sun   Consolidate bool ...
616
  	if (fdc_issue_cmd(pCMD, pFG) == false) {
3863585bb   wdenk   Initial revision
617
618
619
  		PRINTF(" configure timeout
  ");
  		stop_fdc_drive(pCMD);
472d54605   York Sun   Consolidate bool ...
620
  		return false;
3863585bb   wdenk   Initial revision
621
622
623
  	}
  	/* issue specify command */
  	pCMD->cmd[COMMAND]=FDC_CMD_SPECIFY;
472d54605   York Sun   Consolidate bool ...
624
  	if (fdc_issue_cmd(pCMD, pFG) == false) {
3863585bb   wdenk   Initial revision
625
626
627
  		PRINTF(" specify timeout
  ");
  		stop_fdc_drive(pCMD);
472d54605   York Sun   Consolidate bool ...
628
  		return false;
3863585bb   wdenk   Initial revision
629
630
631
632
633
  
  	}
  	/* then, we clear the reset in the DOR */
  	/* fdc_check_drive(pCMD,pFG);	*/
  	/*	write_fdc_reg(FDC_DOR,0x04); */
c7de829c7   wdenk   * Patch by Thomas...
634

472d54605   York Sun   Consolidate bool ...
635
  	return true;
3863585bb   wdenk   Initial revision
636
  }
2262cfeef   wdenk   * Patch by Daniel...
637

3863585bb   wdenk   Initial revision
638
639
640
  /****************************************************************************
   * main routine do_fdcboot
   */
54841ab50   Wolfgang Denk   Make sure that ar...
641
  int do_fdcboot (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
3863585bb   wdenk   Initial revision
642
643
644
  {
  	FD_GEO_STRUCT *pFG = (FD_GEO_STRUCT *)floppy_type;
  	FDC_COMMAND_STRUCT *pCMD = &cmd;
8bde7f776   wdenk   * Code cleanup:
645
  	unsigned long addr,imsize;
21d29f7f9   Heiko Schocher   bootm: make use o...
646
  #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
3863585bb   wdenk   Initial revision
647
  	image_header_t *hdr;  /* used for fdc boot */
21d29f7f9   Heiko Schocher   bootm: make use o...
648
  #endif
3863585bb   wdenk   Initial revision
649
650
  	unsigned char boot_drive;
  	int i,nrofblk;
09475f752   Marian Balakowicz   [new uImage] Add ...
651
  #if defined(CONFIG_FIT)
3bab76a26   Marian Balakowicz   Delay FIT format ...
652
  	const void *fit_hdr = NULL;
09475f752   Marian Balakowicz   [new uImage] Add ...
653
  #endif
3863585bb   wdenk   Initial revision
654
655
656
  
  	switch (argc) {
  	case 1:
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
657
658
  		addr = CONFIG_SYS_LOAD_ADDR;
  		boot_drive=CONFIG_SYS_FDC_DRIVE_NUMBER;
3863585bb   wdenk   Initial revision
659
660
661
  		break;
  	case 2:
  		addr = simple_strtoul(argv[1], NULL, 16);
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
662
  		boot_drive=CONFIG_SYS_FDC_DRIVE_NUMBER;
3863585bb   wdenk   Initial revision
663
664
665
666
667
668
  		break;
  	case 3:
  		addr = simple_strtoul(argv[1], NULL, 16);
  		boot_drive=simple_strtoul(argv[2], NULL, 10);
  		break;
  	default:
4c12eeb8b   Simon Glass   Convert cmd_usage...
669
  		return CMD_RET_USAGE;
3863585bb   wdenk   Initial revision
670
671
  	}
  	/* setup FDC and scan for drives  */
472d54605   York Sun   Consolidate bool ...
672
  	if (fdc_setup(boot_drive, pCMD, pFG) == false) {
3863585bb   wdenk   Initial revision
673
674
675
676
677
  		printf("
  ** Error in setup FDC **
  ");
  		return 1;
  	}
472d54605   York Sun   Consolidate bool ...
678
  	if (fdc_check_drive(pCMD, pFG) == false) {
3863585bb   wdenk   Initial revision
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
  		printf("
  ** Error in check_drives **
  ");
  		return 1;
  	}
  	if((pCMD->flags&(1<<boot_drive))==0) {
  		/* drive not available */
  		printf("
  ** Drive %d not availabe **
  ",boot_drive);
  		return 1;
  	}
  	if((pCMD->flags&(0x10<<boot_drive))==0) {
  		/* no disk inserted */
  		printf("
  ** No disk inserted in drive %d **
  ",boot_drive);
  		return 1;
  	}
  	/* ok, we have a valid source */
  	pCMD->drive=boot_drive;
  	/* read first block */
  	pCMD->blnr=0;
472d54605   York Sun   Consolidate bool ...
702
  	if (fdc_read_data((unsigned char *)addr, 1, pCMD, pFG) == false) {
3863585bb   wdenk   Initial revision
703
704
705
706
707
708
709
  		printf("
  Read error:");
  		for(i=0;i<7;i++)
  			printf("result%d: 0x%02X
  ",i,pCMD->result[i]);
  		return 1;
  	}
d5934ad77   Marian Balakowicz   [new uImage] Add ...
710

9a4daad0a   Marian Balakowicz   [new uImage] Upda...
711
  	switch (genimg_get_format ((void *)addr)) {
21d29f7f9   Heiko Schocher   bootm: make use o...
712
  #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
d5934ad77   Marian Balakowicz   [new uImage] Add ...
713
714
  	case IMAGE_FORMAT_LEGACY:
  		hdr = (image_header_t *)addr;
d5934ad77   Marian Balakowicz   [new uImage] Add ...
715
716
717
718
  		image_print_contents (hdr);
  
  		imsize = image_get_image_size (hdr);
  		break;
21d29f7f9   Heiko Schocher   bootm: make use o...
719
  #endif
d5934ad77   Marian Balakowicz   [new uImage] Add ...
720
721
  #if defined(CONFIG_FIT)
  	case IMAGE_FORMAT_FIT:
09475f752   Marian Balakowicz   [new uImage] Add ...
722
  		fit_hdr = (const void *)addr;
09475f752   Marian Balakowicz   [new uImage] Add ...
723
724
725
726
727
  		puts ("Fit image detected...
  ");
  
  		imsize = fit_get_size (fit_hdr);
  		break;
d5934ad77   Marian Balakowicz   [new uImage] Add ...
728
729
730
731
  #endif
  	default:
  		puts ("** Unknown image type
  ");
3863585bb   wdenk   Initial revision
732
733
  		return 1;
  	}
3863585bb   wdenk   Initial revision
734

3863585bb   wdenk   Initial revision
735
736
737
738
739
740
  	nrofblk=imsize/512;
  	if((imsize%512)>0)
  		nrofblk++;
  	printf("Loading %ld Bytes (%d blocks) at 0x%08lx..
  ",imsize,nrofblk,addr);
  	pCMD->blnr=0;
472d54605   York Sun   Consolidate bool ...
741
  	if (fdc_read_data((unsigned char *)addr, nrofblk, pCMD, pFG) == false) {
3863585bb   wdenk   Initial revision
742
743
744
745
746
747
748
749
750
751
752
753
  		/* read image block */
  		printf("
  Read error:");
  		for(i=0;i<7;i++)
  			printf("result%d: 0x%02X
  ",i,pCMD->result[i]);
  		return 1;
  	}
  	printf("OK %ld Bytes loaded.
  ",imsize);
  
  	flush_cache (addr, imsize);
3863585bb   wdenk   Initial revision
754

09475f752   Marian Balakowicz   [new uImage] Add ...
755
756
  #if defined(CONFIG_FIT)
  	/* This cannot be done earlier, we need complete FIT image in RAM first */
3bab76a26   Marian Balakowicz   Delay FIT format ...
757
758
759
760
761
762
763
764
  	if (genimg_get_format ((void *)addr) == IMAGE_FORMAT_FIT) {
  		if (!fit_check_format (fit_hdr)) {
  			puts ("** Bad FIT image format
  ");
  			return 1;
  		}
  		fit_print_contents (fit_hdr);
  	}
09475f752   Marian Balakowicz   [new uImage] Add ...
765
766
767
  #endif
  
  	/* Loading ok, update default load address */
3863585bb   wdenk   Initial revision
768
  	load_addr = addr;
09475f752   Marian Balakowicz   [new uImage] Add ...
769

67d668bf9   Mike Frysinger   autostart: unify ...
770
  	return bootm_maybe_autostart(cmdtp, argv[0]);
3863585bb   wdenk   Initial revision
771
  }
0d4983930   wdenk   Patch by Kenneth ...
772
773
  U_BOOT_CMD(
  	fdcboot,	3,	1,	do_fdcboot,
2fb2604d5   Peter Tyser   Command usage cle...
774
  	"boot from floppy device",
a89c33db9   Wolfgang Denk   General help mess...
775
  	"loadAddr drive"
8bde7f776   wdenk   * Code cleanup:
776
  );