Blame view

cmd/fdc.c 20.5 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0+
3863585bb   wdenk   Initial revision
2
3
4
  /*
   * (C) Copyright 2001
   * Denis Peter, MPL AG, d.peter@mpl.ch.
3863585bb   wdenk   Initial revision
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   */
  /*
   * 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]*:...
23
  /*#if defined(CONFIG_CMD_DATE) */
8bde7f776   wdenk   * Code cleanup:
24
25
  /*#include <rtc.h> */
  /*#endif */
3863585bb   wdenk   Initial revision
26

3863585bb   wdenk   Initial revision
27
  typedef struct {
53677ef18   Wolfgang Denk   Big white-space c...
28
29
30
31
32
33
34
35
  	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
36
  } FDC_COMMAND_STRUCT;
53677ef18   Wolfgang Denk   Big white-space c...
37

3863585bb   wdenk   Initial revision
38
39
40
41
42
43
44
45
46
47
  /* 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
48
  /* cmd indexes */
53677ef18   Wolfgang Denk   Big white-space c...
49
50
  #define COMMAND			0
  #define DRIVE			1
3863585bb   wdenk   Initial revision
51
  #define CONFIG0			1
53677ef18   Wolfgang Denk   Big white-space c...
52
53
  #define SPEC_HUTSRT		1
  #define TRACK			2
3863585bb   wdenk   Initial revision
54
55
  #define CONFIG1			2
  #define SPEC_HLT		2
53677ef18   Wolfgang Denk   Big white-space c...
56
  #define HEAD			3
3863585bb   wdenk   Initial revision
57
  #define CONFIG2			3
53677ef18   Wolfgang Denk   Big white-space c...
58
59
60
61
62
  #define SECTOR			4
  #define SECTOR_SIZE		5
  #define LAST_TRACK		6
  #define GAP			7
  #define DTL			8
3863585bb   wdenk   Initial revision
63
  /* result indexes */
53677ef18   Wolfgang Denk   Big white-space c...
64
65
66
67
68
69
70
71
  #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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  
  
  /* 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...
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  #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
108
  #define FDC_IMPLIED_SEEK	0x01
53677ef18   Wolfgang Denk   Big white-space c...
109
110
111
112
113
  #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
114
115
116
117
118
119
120
121
  
  #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...
122
123
124
125
126
127
128
129
130
131
132
133
  	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
134
135
136
137
138
139
140
141
142
143
  } 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,...
144
  /* If the boot drive number is undefined, we assume it's drive 0             */
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
145
146
  #ifndef CONFIG_SYS_FDC_DRIVE_NUMBER
  #define CONFIG_SYS_FDC_DRIVE_NUMBER 0
7f6c2cbc2   wdenk   * Vince Husovsky,...
147
148
149
  #endif
  
  /* Hardware access */
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
150
151
  #ifndef CONFIG_SYS_ISA_IO_STRIDE
  #define CONFIG_SYS_ISA_IO_STRIDE 1
7f6c2cbc2   wdenk   * Vince Husovsky,...
152
  #endif
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
153
154
  #ifndef CONFIG_SYS_ISA_IO_OFFSET
  #define CONFIG_SYS_ISA_IO_OFFSET 0
7f6c2cbc2   wdenk   * Vince Husovsky,...
155
  #endif
3863585bb   wdenk   Initial revision
156
157
158
159
  /* Supporting Functions */
  /* reads a Register of the FDC */
  unsigned char read_fdc_reg(unsigned int addr)
  {
2262cfeef   wdenk   * Patch by Daniel...
160
  	volatile unsigned char *val =
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
161
162
163
  		(volatile unsigned char *)(CONFIG_SYS_ISA_IO_BASE_ADDRESS +
  					   (addr * CONFIG_SYS_ISA_IO_STRIDE) +
  					   CONFIG_SYS_ISA_IO_OFFSET);
8bde7f776   wdenk   * Code cleanup:
164

7f6c2cbc2   wdenk   * Vince Husovsky,...
165
  	return val [0];
3863585bb   wdenk   Initial revision
166
167
168
169
170
  }
  
  /* writes a Register of the FDC */
  void write_fdc_reg(unsigned int addr, unsigned char val)
  {
8bde7f776   wdenk   * Code cleanup:
171
  	volatile unsigned char *tmp =
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
172
173
174
  		(volatile unsigned char *)(CONFIG_SYS_ISA_IO_BASE_ADDRESS +
  					   (addr * CONFIG_SYS_ISA_IO_STRIDE) +
  					   CONFIG_SYS_ISA_IO_OFFSET);
7f6c2cbc2   wdenk   * Vince Husovsky,...
175
  	tmp[0]=val;
3863585bb   wdenk   Initial revision
176
177
178
179
180
181
182
183
184
185
  }
  
  /* 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 "...
186
  		if(timeout==0) /* timeout occurred */
472d54605   York Sun   Consolidate bool ...
187
  			return false;
3863585bb   wdenk   Initial revision
188
  	}
472d54605   York Sun   Consolidate bool ...
189
  	return true;
3863585bb   wdenk   Initial revision
190
  }
3863585bb   wdenk   Initial revision
191
192
193
194
195
196
197
198
199
200
  /* 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 "...
201
  		if(timeout==0) /* timeout occurred */
3863585bb   wdenk   Initial revision
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
  			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 ...
217
  	return true;
3863585bb   wdenk   Initial revision
218
219
220
221
222
223
224
225
226
227
228
229
230
231
  }
  
  
  /* 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 "...
232
  		if(timeout==0) /* timeout occurred */
472d54605   York Sun   Consolidate bool ...
233
  			return false;
3863585bb   wdenk   Initial revision
234
235
  	}
  	write_fdc_reg(FDC_FIFO,val);
472d54605   York Sun   Consolidate bool ...
236
  	return true;
3863585bb   wdenk   Initial revision
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  }
  
  /* 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...
252
253
254
  	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,...
255

3863585bb   wdenk   Initial revision
256
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
  	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...
284
  			pCMD->cmd[CONFIG2]=FDC_PRE_TRK;	/* Precompensation Track */
3863585bb   wdenk   Initial revision
285
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
  			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 ...
319
  		if (write_fdc_byte(pCMD->cmd[i]) == false) {
3863585bb   wdenk   Initial revision
320
321
  			PRINTF("Error: timeout while issue cmd%d
  ",i);
472d54605   York Sun   Consolidate bool ...
322
  			return false;
3863585bb   wdenk   Initial revision
323
324
325
326
327
328
329
330
331
  		}
  	}
  	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 ...
332
  				return false;
3863585bb   wdenk   Initial revision
333
334
335
336
  			}
  		}
  		pCMD->result[i]=(unsigned char)read_fdc_byte();
  	}
472d54605   York Sun   Consolidate bool ...
337
  	return true;
3863585bb   wdenk   Initial revision
338
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
  }
  
  /* 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 ...
368
369
370
  	if (fdc_issue_cmd(pCMD, pFG) == false)
  		return false;
  	while (wait_for_fdc_int() != true);
3863585bb   wdenk   Initial revision
371
372
373
374
375
376
377
378
379
  	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 ...
380
381
382
  	if (fdc_issue_cmd(pCMD, pFG) == false)
  		return false;
  	while (wait_for_fdc_int() != true);
3863585bb   wdenk   Initial revision
383
384
385
  	pCMD->cmd[COMMAND]=FDC_CMD_SENSE_INT;
  	return(fdc_issue_cmd(pCMD,pFG));
  }
3863585bb   wdenk   Initial revision
386
387
388
389
390
391
392
  /* 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 "...
393
  	while((read_fdc_reg(FDC_SRA)&0x80)==0x00); /* wait as long as no int has occurred */
3863585bb   wdenk   Initial revision
394
395
396
  	for(i=0;i<7;i++) {
  		pCMD->result[i]=(unsigned char)read_fdc_byte();
  	}
472d54605   York Sun   Consolidate bool ...
397
  	return true;
3863585bb   wdenk   Initial revision
398
399
400
401
402
403
  }
  
  /* 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:...
404
405
  	unsigned long len,readblk,i,timeout,ii,offset;
  	unsigned char c,retriesrw,retriescal;
3863585bb   wdenk   Initial revision
406
407
408
409
410
411
412
413
414
415
  	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 ...
416
  	if (fdc_seek(pCMD, pFG) == false) {
3863585bb   wdenk   Initial revision
417
  		stop_fdc_drive(pCMD);
4ec6e4a88   Wolfgang Denk   common/cmd_fdc.c:...
418
419
  		if (flags)
  			enable_interrupts();
472d54605   York Sun   Consolidate bool ...
420
  		return false;
3863585bb   wdenk   Initial revision
421
422
423
424
425
  	}
  	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:...
426
427
  		if (flags)
  			enable_interrupts();
472d54605   York Sun   Consolidate bool ...
428
  		return false;
3863585bb   wdenk   Initial revision
429
  	}
3863585bb   wdenk   Initial revision
430
  	/* now determine the next seek point */
4ec6e4a88   Wolfgang Denk   common/cmd_fdc.c:...
431
  	/*	lastblk=pCMD->blnr + blocks; */
3863585bb   wdenk   Initial revision
432
433
434
435
436
437
438
439
  	/*	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...
440
  	bufferw = &buffer[0]; /* setup working buffer */
3863585bb   wdenk   Initial revision
441
442
443
444
  	do {
  retryrw:
  		len=sect_size * readblk;
  		pCMD->cmd[COMMAND]=FDC_CMD_READ;
472d54605   York Sun   Consolidate bool ...
445
  		if (fdc_issue_cmd(pCMD, pFG) == false) {
3863585bb   wdenk   Initial revision
446
  			stop_fdc_drive(pCMD);
4ec6e4a88   Wolfgang Denk   common/cmd_fdc.c:...
447
448
  			if (flags)
  				enable_interrupts();
472d54605   York Sun   Consolidate bool ...
449
  			return false;
3863585bb   wdenk   Initial revision
450
451
452
453
454
455
456
457
458
459
  		}
  		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 "...
460
461
  					PRINTF("Transfer error transferred: at %ld, MSR=%02X
  ",i,c);
3863585bb   wdenk   Initial revision
462
463
464
465
466
467
468
469
  					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:...
470
471
  							if (flags)
  								enable_interrupts();
472d54605   York Sun   Consolidate bool ...
472
  							return false;
3863585bb   wdenk   Initial revision
473
474
475
476
  						}
  						else {
  							PRINTF(" trying to recalibrate Try %d
  ",retriescal);
472d54605   York Sun   Consolidate bool ...
477
  							if (fdc_recalibrate(pCMD, pFG) == false) {
3863585bb   wdenk   Initial revision
478
  								stop_fdc_drive(pCMD);
4ec6e4a88   Wolfgang Denk   common/cmd_fdc.c:...
479
480
  								if (flags)
  									enable_interrupts();
472d54605   York Sun   Consolidate bool ...
481
  								return false;
3863585bb   wdenk   Initial revision
482
483
484
485
486
487
488
489
490
491
492
493
  							}
  							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 ...
494
  			} while (true);
3863585bb   wdenk   Initial revision
495
496
497
498
499
  		} /* 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...
500
  		bufferw = &buffer[offset];
3863585bb   wdenk   Initial revision
501
502
503
504
505
506
507
508
509
510
511
  		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 ...
512
  		if (fdc_seek(pCMD, pFG) == false) {
3863585bb   wdenk   Initial revision
513
  			stop_fdc_drive(pCMD);
4ec6e4a88   Wolfgang Denk   common/cmd_fdc.c:...
514
515
  			if (flags)
  				enable_interrupts();
472d54605   York Sun   Consolidate bool ...
516
  			return false;
3863585bb   wdenk   Initial revision
517
518
519
520
521
  		}
  		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 ...
522
  			return false;
3863585bb   wdenk   Initial revision
523
  		}
472d54605   York Sun   Consolidate bool ...
524
  	} while (true); /* start over */
3863585bb   wdenk   Initial revision
525
  	stop_fdc_drive(pCMD); /* switch off drive */
4ec6e4a88   Wolfgang Denk   common/cmd_fdc.c:...
526
527
  	if (flags)
  		enable_interrupts();
472d54605   York Sun   Consolidate bool ...
528
  	return true;
3863585bb   wdenk   Initial revision
529
530
531
532
533
534
535
536
537
538
539
540
541
  }
  
  /* 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 ...
542
  		if (fdc_recalibrate(pCMD, pFG) == false)
7f6c2cbc2   wdenk   * Vince Husovsky,...
543
  			continue;
3863585bb   wdenk   Initial revision
544
  		if((pCMD->result[STATUS_0]&0x10)==0x10)
7f6c2cbc2   wdenk   * Vince Husovsky,...
545
  			continue;
3863585bb   wdenk   Initial revision
546
547
548
  		/* ok drive connected check for disk */
  		state|=(1<<drives);
  		pCMD->blnr=pFG->size; /* set to the last block */
472d54605   York Sun   Consolidate bool ...
549
  		if (fdc_seek(pCMD, pFG) == false)
7f6c2cbc2   wdenk   * Vince Husovsky,...
550
  			continue;
3863585bb   wdenk   Initial revision
551
  		pCMD->blnr=0; /* set to the 1st block */
472d54605   York Sun   Consolidate bool ...
552
  		if (fdc_recalibrate(pCMD, pFG) == false)
7f6c2cbc2   wdenk   * Vince Husovsky,...
553
  			continue;
3863585bb   wdenk   Initial revision
554
  		pCMD->cmd[COMMAND]=FDC_CMD_READ_ID;
472d54605   York Sun   Consolidate bool ...
555
  		if (fdc_issue_cmd(pCMD, pFG) == false)
7f6c2cbc2   wdenk   * Vince Husovsky,...
556
  			continue;
3863585bb   wdenk   Initial revision
557
558
559
560
561
562
563
564
565
566
567
  		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 ...
568
  	return true;
3863585bb   wdenk   Initial revision
569
570
571
572
573
574
575
576
  }
  
  
  /**************************************************************************
  * int fdc_setup
  * setup the fdc according the datasheet
  * assuming in PS2 Mode
  */
2262cfeef   wdenk   * Patch by Daniel...
577
  int fdc_setup(int drive, FDC_COMMAND_STRUCT *pCMD, FD_GEO_STRUCT *pFG)
3863585bb   wdenk   Initial revision
578
  {
3863585bb   wdenk   Initial revision
579
  	int i;
7f6c2cbc2   wdenk   * Vince Husovsky,...
580

6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
581
  #ifdef CONFIG_SYS_FDC_HW_INIT
8bde7f776   wdenk   * Code cleanup:
582
  	fdc_hw_init ();
7f6c2cbc2   wdenk   * Vince Husovsky,...
583
  #endif
3863585bb   wdenk   Initial revision
584
585
586
587
588
  	/* 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...
589
  	pCMD->drive=drive;
3863585bb   wdenk   Initial revision
590
591
592
593
594
  	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 ...
595
  	if (wait_for_fdc_int() == false) {
3863585bb   wdenk   Initial revision
596
597
  			PRINTF("Time Out after writing CCR
  ");
472d54605   York Sun   Consolidate bool ...
598
  			return false;
3863585bb   wdenk   Initial revision
599
600
601
602
603
604
605
  	}
  	/* 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 ...
606
  		if (fdc_issue_cmd(pCMD, pFG) == false) {
3863585bb   wdenk   Initial revision
607
608
609
610
  			PRINTF("Sense Interrupt for drive %d failed
  ",i);
  		}
  	}
2262cfeef   wdenk   * Patch by Daniel...
611
612
  	/* issue the configure command */
  	pCMD->drive=drive;
3863585bb   wdenk   Initial revision
613
614
  	select_fdc_drive(pCMD);
  	pCMD->cmd[COMMAND]=FDC_CMD_CONFIGURE;
472d54605   York Sun   Consolidate bool ...
615
  	if (fdc_issue_cmd(pCMD, pFG) == false) {
3863585bb   wdenk   Initial revision
616
617
618
  		PRINTF(" configure timeout
  ");
  		stop_fdc_drive(pCMD);
472d54605   York Sun   Consolidate bool ...
619
  		return false;
3863585bb   wdenk   Initial revision
620
621
622
  	}
  	/* issue specify command */
  	pCMD->cmd[COMMAND]=FDC_CMD_SPECIFY;
472d54605   York Sun   Consolidate bool ...
623
  	if (fdc_issue_cmd(pCMD, pFG) == false) {
3863585bb   wdenk   Initial revision
624
625
626
  		PRINTF(" specify timeout
  ");
  		stop_fdc_drive(pCMD);
472d54605   York Sun   Consolidate bool ...
627
  		return false;
3863585bb   wdenk   Initial revision
628
629
630
631
632
  
  	}
  	/* then, we clear the reset in the DOR */
  	/* fdc_check_drive(pCMD,pFG);	*/
  	/*	write_fdc_reg(FDC_DOR,0x04); */
c7de829c7   wdenk   * Patch by Thomas...
633

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

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

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

3863585bb   wdenk   Initial revision
734
735
736
737
738
739
  	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 ...
740
  	if (fdc_read_data((unsigned char *)addr, nrofblk, pCMD, pFG) == false) {
3863585bb   wdenk   Initial revision
741
742
743
744
745
746
747
748
749
750
751
752
  		/* 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
753

09475f752   Marian Balakowicz   [new uImage] Add ...
754
755
  #if defined(CONFIG_FIT)
  	/* This cannot be done earlier, we need complete FIT image in RAM first */
3bab76a26   Marian Balakowicz   Delay FIT format ...
756
757
758
759
760
761
762
763
  	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 ...
764
765
766
  #endif
  
  	/* Loading ok, update default load address */
3863585bb   wdenk   Initial revision
767
  	load_addr = addr;
09475f752   Marian Balakowicz   [new uImage] Add ...
768

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