]>
Commit | Line | Data |
---|---|---|
c609719b WD |
1 | /* |
2 | * (C) Copyright 2000-2002 | |
3 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
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 | /* | |
26 | * IDE support | |
27 | */ | |
28 | #include <common.h> | |
29 | #include <config.h> | |
30 | #include <watchdog.h> | |
31 | #include <command.h> | |
32 | #include <image.h> | |
33 | #include <asm/byteorder.h> | |
34 | #if defined(CONFIG_IDE_8xx_DIRECT) || defined(CONFIG_IDE_PCMCIA) | |
35 | # include <pcmcia.h> | |
36 | #endif | |
37 | #ifdef CONFIG_8xx | |
38 | # include <mpc8xx.h> | |
39 | #endif | |
40 | #include <ide.h> | |
41 | #include <ata.h> | |
c609719b WD |
42 | #ifdef CONFIG_STATUS_LED |
43 | # include <status_led.h> | |
44 | #endif | |
15647dc7 | 45 | #ifndef __PPC__ |
2262cfee | 46 | #include <asm/io.h> |
15647dc7 WD |
47 | #ifdef __MIPS__ |
48 | /* Macros depend on this variable */ | |
49 | static unsigned long mips_io_port_base = 0; | |
50 | #endif | |
2262cfee | 51 | #endif |
c609719b WD |
52 | |
53 | #ifdef CONFIG_SHOW_BOOT_PROGRESS | |
54 | # include <status_led.h> | |
55 | # define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg) | |
56 | #else | |
57 | # define SHOW_BOOT_PROGRESS(arg) | |
58 | #endif | |
59 | ||
60 | ||
61 | #undef IDE_DEBUG | |
62 | ||
c7de829c | 63 | |
c609719b WD |
64 | #ifdef IDE_DEBUG |
65 | #define PRINTF(fmt,args...) printf (fmt ,##args) | |
66 | #else | |
67 | #define PRINTF(fmt,args...) | |
68 | #endif | |
69 | ||
70 | #if (CONFIG_COMMANDS & CFG_CMD_IDE) | |
71 | ||
15647dc7 | 72 | #ifdef CONFIG_IDE_8xx_DIRECT |
c609719b WD |
73 | /* Timings for IDE Interface |
74 | * | |
75 | * SETUP / LENGTH / HOLD - cycles valid for 50 MHz clk | |
76 | * 70 165 30 PIO-Mode 0, [ns] | |
77 | * 4 9 2 [Cycles] | |
78 | * 50 125 20 PIO-Mode 1, [ns] | |
79 | * 3 7 2 [Cycles] | |
80 | * 30 100 15 PIO-Mode 2, [ns] | |
81 | * 2 6 1 [Cycles] | |
82 | * 30 80 10 PIO-Mode 3, [ns] | |
83 | * 2 5 1 [Cycles] | |
84 | * 25 70 10 PIO-Mode 4, [ns] | |
85 | * 2 4 1 [Cycles] | |
86 | */ | |
87 | ||
88 | const static pio_config_t pio_config_ns [IDE_MAX_PIO_MODE+1] = | |
89 | { | |
90 | /* Setup Length Hold */ | |
91 | { 70, 165, 30 }, /* PIO-Mode 0, [ns] */ | |
92 | { 50, 125, 20 }, /* PIO-Mode 1, [ns] */ | |
93 | { 30, 101, 15 }, /* PIO-Mode 2, [ns] */ | |
94 | { 30, 80, 10 }, /* PIO-Mode 3, [ns] */ | |
95 | { 25, 70, 10 }, /* PIO-Mode 4, [ns] */ | |
96 | }; | |
97 | ||
98 | static pio_config_t pio_config_clk [IDE_MAX_PIO_MODE+1]; | |
99 | ||
100 | #ifndef CFG_PIO_MODE | |
101 | #define CFG_PIO_MODE 0 /* use a relaxed default */ | |
102 | #endif | |
103 | static int pio_mode = CFG_PIO_MODE; | |
104 | ||
105 | /* Make clock cycles and always round up */ | |
106 | ||
107 | #define PCMCIA_MK_CLKS( t, T ) (( (t) * (T) + 999U ) / 1000U ) | |
108 | ||
15647dc7 WD |
109 | #endif /* CONFIG_IDE_8xx_DIRECT */ |
110 | ||
c609719b WD |
111 | /* ------------------------------------------------------------------------- */ |
112 | ||
113 | /* Current I/O Device */ | |
114 | static int curr_device = -1; | |
115 | ||
116 | /* Current offset for IDE0 / IDE1 bus access */ | |
117 | ulong ide_bus_offset[CFG_IDE_MAXBUS] = { | |
118 | #if defined(CFG_ATA_IDE0_OFFSET) | |
119 | CFG_ATA_IDE0_OFFSET, | |
120 | #endif | |
121 | #if defined(CFG_ATA_IDE1_OFFSET) && (CFG_IDE_MAXBUS > 1) | |
122 | CFG_ATA_IDE1_OFFSET, | |
123 | #endif | |
124 | }; | |
125 | ||
15647dc7 | 126 | |
c609719b WD |
127 | #define ATA_CURR_BASE(dev) (CFG_ATA_BASE_ADDR+ide_bus_offset[IDE_BUS(dev)]) |
128 | ||
c7de829c | 129 | #ifndef CONFIG_AMIGAONEG3SE |
c609719b | 130 | static int ide_bus_ok[CFG_IDE_MAXBUS]; |
c7de829c WD |
131 | #else |
132 | static int ide_bus_ok[CFG_IDE_MAXBUS] = {0,}; | |
133 | #endif | |
c609719b WD |
134 | |
135 | static block_dev_desc_t ide_dev_desc[CFG_IDE_MAXDEVICE]; | |
136 | /* ------------------------------------------------------------------------- */ | |
137 | ||
138 | #ifdef CONFIG_IDE_LED | |
1f53a416 | 139 | #ifndef CONFIG_KUP4K |
c609719b WD |
140 | static void ide_led (uchar led, uchar status); |
141 | #else | |
1f53a416 WD |
142 | extern void ide_led (uchar led, uchar status); |
143 | #endif | |
144 | #else | |
c7de829c | 145 | #ifndef CONFIG_AMIGAONEG3SE |
c609719b | 146 | #define ide_led(a,b) /* dummy */ |
c7de829c WD |
147 | #else |
148 | extern void ide_led(uchar led, uchar status); | |
149 | #define LED_IDE1 1 | |
150 | #define LED_IDE2 2 | |
151 | #define CONFIG_IDE_LED 1 | |
152 | #define DEVICE_LED(x) 1 | |
153 | #endif | |
c609719b WD |
154 | #endif |
155 | ||
156 | #ifdef CONFIG_IDE_RESET | |
157 | static void ide_reset (void); | |
158 | #else | |
159 | #define ide_reset() /* dummy */ | |
160 | #endif | |
161 | ||
162 | static void ide_ident (block_dev_desc_t *dev_desc); | |
163 | static uchar ide_wait (int dev, ulong t); | |
164 | ||
165 | #define IDE_TIME_OUT 2000 /* 2 sec timeout */ | |
166 | ||
167 | #define ATAPI_TIME_OUT 7000 /* 7 sec timeout (5 sec seems to work...) */ | |
168 | ||
169 | #define IDE_SPIN_UP_TIME_OUT 5000 /* 5 sec spin-up timeout */ | |
170 | ||
2262cfee WD |
171 | static void __inline__ ide_outb(int dev, int port, unsigned char val); |
172 | static unsigned char __inline__ ide_inb(int dev, int port); | |
c609719b WD |
173 | static void input_data(int dev, ulong *sect_buf, int words); |
174 | static void output_data(int dev, ulong *sect_buf, int words); | |
175 | static void ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len); | |
176 | ||
177 | ||
178 | #ifdef CONFIG_ATAPI | |
179 | static void atapi_inquiry(block_dev_desc_t *dev_desc); | |
180 | ulong atapi_read (int device, ulong blknr, ulong blkcnt, ulong *buffer); | |
181 | #endif | |
182 | ||
183 | ||
184 | #ifdef CONFIG_IDE_8xx_DIRECT | |
185 | static void set_pcmcia_timing (int pmode); | |
c609719b WD |
186 | #endif |
187 | ||
188 | /* ------------------------------------------------------------------------- */ | |
189 | ||
190 | int do_ide (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) | |
191 | { | |
192 | int rcode = 0; | |
193 | ||
194 | switch (argc) { | |
195 | case 0: | |
196 | case 1: | |
197 | printf ("Usage:\n%s\n", cmdtp->usage); | |
198 | return 1; | |
199 | case 2: | |
200 | if (strncmp(argv[1],"res",3) == 0) { | |
201 | puts ("\nReset IDE" | |
202 | #ifdef CONFIG_IDE_8xx_DIRECT | |
203 | " on PCMCIA " PCMCIA_SLOT_MSG | |
204 | #endif | |
205 | ": "); | |
206 | ||
207 | ide_init (); | |
208 | return 0; | |
209 | } else if (strncmp(argv[1],"inf",3) == 0) { | |
210 | int i; | |
211 | ||
212 | putc ('\n'); | |
213 | ||
214 | for (i=0; i<CFG_IDE_MAXDEVICE; ++i) { | |
215 | if (ide_dev_desc[i].type==DEV_TYPE_UNKNOWN) | |
216 | continue; /* list only known devices */ | |
217 | printf ("IDE device %d: ", i); | |
218 | dev_print(&ide_dev_desc[i]); | |
219 | } | |
220 | return 0; | |
221 | ||
222 | } else if (strncmp(argv[1],"dev",3) == 0) { | |
223 | if ((curr_device < 0) || (curr_device >= CFG_IDE_MAXDEVICE)) { | |
224 | puts ("\nno IDE devices available\n"); | |
225 | return 1; | |
226 | } | |
227 | printf ("\nIDE device %d: ", curr_device); | |
228 | dev_print(&ide_dev_desc[curr_device]); | |
229 | return 0; | |
230 | } else if (strncmp(argv[1],"part",4) == 0) { | |
231 | int dev, ok; | |
232 | ||
233 | for (ok=0, dev=0; dev<CFG_IDE_MAXDEVICE; ++dev) { | |
234 | if (ide_dev_desc[dev].part_type!=PART_TYPE_UNKNOWN) { | |
235 | ++ok; | |
236 | if (dev) | |
237 | putc ('\n'); | |
238 | print_part(&ide_dev_desc[dev]); | |
239 | } | |
240 | } | |
241 | if (!ok) { | |
242 | puts ("\nno IDE devices available\n"); | |
243 | rcode ++; | |
244 | } | |
245 | return rcode; | |
246 | } | |
247 | printf ("Usage:\n%s\n", cmdtp->usage); | |
248 | return 1; | |
249 | case 3: | |
250 | if (strncmp(argv[1],"dev",3) == 0) { | |
251 | int dev = (int)simple_strtoul(argv[2], NULL, 10); | |
252 | ||
253 | printf ("\nIDE device %d: ", dev); | |
254 | if (dev >= CFG_IDE_MAXDEVICE) { | |
255 | puts ("unknown device\n"); | |
256 | return 1; | |
257 | } | |
258 | dev_print(&ide_dev_desc[dev]); | |
259 | /*ide_print (dev);*/ | |
260 | ||
261 | if (ide_dev_desc[dev].type == DEV_TYPE_UNKNOWN) { | |
262 | return 1; | |
263 | } | |
264 | ||
265 | curr_device = dev; | |
266 | ||
267 | puts ("... is now current device\n"); | |
268 | ||
269 | return 0; | |
270 | } else if (strncmp(argv[1],"part",4) == 0) { | |
271 | int dev = (int)simple_strtoul(argv[2], NULL, 10); | |
272 | ||
273 | if (ide_dev_desc[dev].part_type!=PART_TYPE_UNKNOWN) { | |
274 | print_part(&ide_dev_desc[dev]); | |
275 | } else { | |
276 | printf ("\nIDE device %d not available\n", dev); | |
277 | rcode = 1; | |
278 | } | |
279 | return rcode; | |
280 | #if 0 | |
281 | } else if (strncmp(argv[1],"pio",4) == 0) { | |
282 | int mode = (int)simple_strtoul(argv[2], NULL, 10); | |
283 | ||
284 | if ((mode >= 0) && (mode <= IDE_MAX_PIO_MODE)) { | |
285 | puts ("\nSetting "); | |
286 | pio_mode = mode; | |
287 | ide_init (); | |
288 | } else { | |
289 | printf ("\nInvalid PIO mode %d (0 ... %d only)\n", | |
290 | mode, IDE_MAX_PIO_MODE); | |
291 | } | |
292 | return; | |
293 | #endif | |
294 | } | |
295 | ||
296 | printf ("Usage:\n%s\n", cmdtp->usage); | |
297 | return 1; | |
298 | default: | |
299 | /* at least 4 args */ | |
300 | ||
301 | if (strcmp(argv[1],"read") == 0) { | |
302 | ulong addr = simple_strtoul(argv[2], NULL, 16); | |
303 | ulong blk = simple_strtoul(argv[3], NULL, 16); | |
304 | ulong cnt = simple_strtoul(argv[4], NULL, 16); | |
305 | ulong n; | |
306 | ||
307 | printf ("\nIDE read: device %d block # %ld, count %ld ... ", | |
308 | curr_device, blk, cnt); | |
309 | ||
310 | n = ide_dev_desc[curr_device].block_read (curr_device, | |
311 | blk, cnt, | |
312 | (ulong *)addr); | |
313 | /* flush cache after read */ | |
314 | flush_cache (addr, cnt*ide_dev_desc[curr_device].blksz); | |
315 | ||
316 | printf ("%ld blocks read: %s\n", | |
317 | n, (n==cnt) ? "OK" : "ERROR"); | |
318 | if (n==cnt) { | |
319 | return 0; | |
320 | } else { | |
321 | return 1; | |
322 | } | |
323 | } else if (strcmp(argv[1],"write") == 0) { | |
324 | ulong addr = simple_strtoul(argv[2], NULL, 16); | |
325 | ulong blk = simple_strtoul(argv[3], NULL, 16); | |
326 | ulong cnt = simple_strtoul(argv[4], NULL, 16); | |
327 | ulong n; | |
328 | ||
329 | printf ("\nIDE write: device %d block # %ld, count %ld ... ", | |
330 | curr_device, blk, cnt); | |
331 | ||
332 | n = ide_write (curr_device, blk, cnt, (ulong *)addr); | |
333 | ||
334 | printf ("%ld blocks written: %s\n", | |
335 | n, (n==cnt) ? "OK" : "ERROR"); | |
336 | if (n==cnt) { | |
337 | return 0; | |
338 | } else { | |
339 | return 1; | |
340 | } | |
341 | } else { | |
342 | printf ("Usage:\n%s\n", cmdtp->usage); | |
343 | rcode = 1; | |
344 | } | |
345 | ||
346 | return rcode; | |
347 | } | |
348 | } | |
349 | ||
350 | int do_diskboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) | |
351 | { | |
352 | char *boot_device = NULL; | |
353 | char *ep; | |
354 | int dev, part = 0; | |
355 | ulong cnt; | |
356 | ulong addr; | |
357 | disk_partition_t info; | |
358 | image_header_t *hdr; | |
359 | int rcode = 0; | |
360 | ||
361 | switch (argc) { | |
362 | case 1: | |
363 | addr = CFG_LOAD_ADDR; | |
364 | boot_device = getenv ("bootdevice"); | |
365 | break; | |
366 | case 2: | |
367 | addr = simple_strtoul(argv[1], NULL, 16); | |
368 | boot_device = getenv ("bootdevice"); | |
369 | break; | |
370 | case 3: | |
371 | addr = simple_strtoul(argv[1], NULL, 16); | |
372 | boot_device = argv[2]; | |
373 | break; | |
374 | default: | |
375 | printf ("Usage:\n%s\n", cmdtp->usage); | |
376 | SHOW_BOOT_PROGRESS (-1); | |
377 | return 1; | |
378 | } | |
379 | ||
380 | if (!boot_device) { | |
381 | puts ("\n** No boot device **\n"); | |
382 | SHOW_BOOT_PROGRESS (-1); | |
383 | return 1; | |
384 | } | |
385 | ||
386 | dev = simple_strtoul(boot_device, &ep, 16); | |
387 | ||
388 | if (ide_dev_desc[dev].type==DEV_TYPE_UNKNOWN) { | |
389 | printf ("\n** Device %d not available\n", dev); | |
390 | SHOW_BOOT_PROGRESS (-1); | |
391 | return 1; | |
392 | } | |
393 | ||
394 | if (*ep) { | |
395 | if (*ep != ':') { | |
396 | puts ("\n** Invalid boot device, use `dev[:part]' **\n"); | |
397 | SHOW_BOOT_PROGRESS (-1); | |
398 | return 1; | |
399 | } | |
400 | part = simple_strtoul(++ep, NULL, 16); | |
401 | } | |
402 | if (get_partition_info (&ide_dev_desc[dev], part, &info)) { | |
403 | SHOW_BOOT_PROGRESS (-1); | |
404 | return 1; | |
405 | } | |
4532cb69 WD |
406 | if ((strncmp(info.type, BOOT_PART_TYPE, sizeof(info.type)) != 0) && |
407 | (strncmp(info.type, BOOT_PART_COMP, sizeof(info.type)) != 0)) { | |
c609719b WD |
408 | printf ("\n** Invalid partition type \"%.32s\"" |
409 | " (expect \"" BOOT_PART_TYPE "\")\n", | |
410 | info.type); | |
411 | SHOW_BOOT_PROGRESS (-1); | |
412 | return 1; | |
413 | } | |
414 | ||
415 | printf ("\nLoading from IDE device %d, partition %d: " | |
416 | "Name: %.32s Type: %.32s\n", | |
417 | dev, part, info.name, info.type); | |
418 | ||
419 | PRINTF ("First Block: %ld, # of blocks: %ld, Block Size: %ld\n", | |
420 | info.start, info.size, info.blksz); | |
421 | ||
422 | if (ide_dev_desc[dev].block_read (dev, info.start, 1, (ulong *)addr) != 1) { | |
423 | printf ("** Read error on %d:%d\n", dev, part); | |
424 | SHOW_BOOT_PROGRESS (-1); | |
425 | return 1; | |
426 | } | |
427 | ||
428 | hdr = (image_header_t *)addr; | |
429 | ||
430 | if (ntohl(hdr->ih_magic) == IH_MAGIC) { | |
431 | ||
432 | print_image_hdr (hdr); | |
433 | ||
434 | cnt = (ntohl(hdr->ih_size) + sizeof(image_header_t)); | |
435 | cnt += info.blksz - 1; | |
436 | cnt /= info.blksz; | |
437 | cnt -= 1; | |
438 | } else { | |
439 | printf("\n** Bad Magic Number **\n"); | |
440 | SHOW_BOOT_PROGRESS (-1); | |
441 | return 1; | |
442 | } | |
443 | ||
444 | if (ide_dev_desc[dev].block_read (dev, info.start+1, cnt, | |
445 | (ulong *)(addr+info.blksz)) != cnt) { | |
446 | printf ("** Read error on %d:%d\n", dev, part); | |
447 | SHOW_BOOT_PROGRESS (-1); | |
448 | return 1; | |
449 | } | |
450 | ||
451 | ||
452 | /* Loading ok, update default load address */ | |
453 | ||
454 | load_addr = addr; | |
455 | ||
456 | /* Check if we should attempt an auto-start */ | |
457 | if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) { | |
458 | char *local_args[2]; | |
459 | extern int do_bootm (cmd_tbl_t *, int, int, char *[]); | |
460 | ||
461 | local_args[0] = argv[0]; | |
462 | local_args[1] = NULL; | |
463 | ||
464 | printf ("Automatic boot of image at addr 0x%08lX ...\n", addr); | |
465 | ||
466 | do_bootm (cmdtp, 0, 1, local_args); | |
467 | rcode = 1; | |
468 | } | |
469 | return rcode; | |
470 | } | |
471 | ||
472 | /* ------------------------------------------------------------------------- */ | |
473 | ||
474 | void ide_init (void) | |
475 | { | |
c609719b WD |
476 | |
477 | #ifdef CONFIG_IDE_8xx_DIRECT | |
15647dc7 | 478 | DECLARE_GLOBAL_DATA_PTR; |
c609719b WD |
479 | volatile immap_t *immr = (immap_t *)CFG_IMMR; |
480 | volatile pcmconf8xx_t *pcmp = &(immr->im_pcmcia); | |
481 | #endif | |
482 | unsigned char c; | |
483 | int i, bus; | |
c7de829c WD |
484 | #ifdef CONFIG_AMIGAONEG3SE |
485 | unsigned int max_bus_scan; | |
486 | unsigned int ata_reset_time; | |
487 | char *s; | |
488 | #endif | |
c609719b WD |
489 | |
490 | #ifdef CONFIG_IDE_8xx_PCCARD | |
491 | extern int pcmcia_on (void); | |
6069ff26 | 492 | extern int ide_devices_found; /* Initialized in check_ide_device() */ |
c609719b WD |
493 | |
494 | WATCHDOG_RESET(); | |
495 | ||
6069ff26 | 496 | ide_devices_found = 0; |
c609719b | 497 | /* initialize the PCMCIA IDE adapter card */ |
6069ff26 WD |
498 | pcmcia_on(); |
499 | if (!ide_devices_found) | |
c609719b WD |
500 | return; |
501 | udelay (1000000); /* 1 s */ | |
502 | #endif /* CONFIG_IDE_8xx_PCCARD */ | |
503 | ||
504 | WATCHDOG_RESET(); | |
505 | ||
15647dc7 | 506 | #ifdef CONFIG_IDE_8xx_DIRECT |
c609719b WD |
507 | /* Initialize PIO timing tables */ |
508 | for (i=0; i <= IDE_MAX_PIO_MODE; ++i) { | |
509 | pio_config_clk[i].t_setup = PCMCIA_MK_CLKS(pio_config_ns[i].t_setup, | |
510 | gd->bus_clk); | |
511 | pio_config_clk[i].t_length = PCMCIA_MK_CLKS(pio_config_ns[i].t_length, | |
512 | gd->bus_clk); | |
513 | pio_config_clk[i].t_hold = PCMCIA_MK_CLKS(pio_config_ns[i].t_hold, | |
514 | gd->bus_clk); | |
515 | PRINTF ("PIO Mode %d: setup=%2d ns/%d clk" | |
516 | " len=%3d ns/%d clk" | |
517 | " hold=%2d ns/%d clk\n", | |
518 | i, | |
519 | pio_config_ns[i].t_setup, pio_config_clk[i].t_setup, | |
520 | pio_config_ns[i].t_length, pio_config_clk[i].t_length, | |
521 | pio_config_ns[i].t_hold, pio_config_clk[i].t_hold); | |
522 | } | |
15647dc7 | 523 | #endif /* CONFIG_IDE_8xx_DIRECT */ |
c609719b WD |
524 | |
525 | /* Reset the IDE just to be sure. | |
526 | * Light LED's to show | |
527 | */ | |
528 | ide_led ((LED_IDE1 | LED_IDE2), 1); /* LED's on */ | |
529 | ide_reset (); /* ATAPI Drives seems to need a proper IDE Reset */ | |
530 | ||
531 | #ifdef CONFIG_IDE_8xx_DIRECT | |
532 | /* PCMCIA / IDE initialization for common mem space */ | |
533 | pcmp->pcmc_pgcrb = 0; | |
c609719b WD |
534 | |
535 | /* start in PIO mode 0 - most relaxed timings */ | |
536 | pio_mode = 0; | |
537 | set_pcmcia_timing (pio_mode); | |
15647dc7 | 538 | #endif /* CONFIG_IDE_8xx_DIRECT */ |
c609719b WD |
539 | |
540 | /* | |
541 | * Wait for IDE to get ready. | |
542 | * According to spec, this can take up to 31 seconds! | |
543 | */ | |
c7de829c | 544 | #ifndef CONFIG_AMIGAONEG3SE |
c609719b WD |
545 | for (bus=0; bus<CFG_IDE_MAXBUS; ++bus) { |
546 | int dev = bus * (CFG_IDE_MAXDEVICE / CFG_IDE_MAXBUS); | |
c7de829c WD |
547 | #else |
548 | s = getenv("ide_maxbus"); | |
549 | if (s) | |
550 | max_bus_scan = simple_strtol(s, NULL, 10); | |
551 | else | |
552 | max_bus_scan = CFG_IDE_MAXBUS; | |
553 | ||
554 | for (bus=0; bus<max_bus_scan; ++bus) { | |
555 | int dev = bus * (CFG_IDE_MAXDEVICE / max_bus_scan); | |
556 | #endif | |
c609719b | 557 | |
6069ff26 WD |
558 | #ifdef CONFIG_IDE_8xx_PCCARD |
559 | /* Skip non-ide devices from probing */ | |
560 | if ((ide_devices_found & (1 << bus)) == 0) { | |
561 | ide_led ((LED_IDE1 | LED_IDE2), 0); /* LED's off */ | |
562 | continue; | |
563 | } | |
564 | #endif | |
c609719b WD |
565 | printf ("Bus %d: ", bus); |
566 | ||
567 | ide_bus_ok[bus] = 0; | |
568 | ||
569 | /* Select device | |
570 | */ | |
571 | udelay (100000); /* 100 ms */ | |
2262cfee | 572 | ide_outb (dev, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(dev)); |
c609719b | 573 | udelay (100000); /* 100 ms */ |
c7de829c WD |
574 | #ifdef CONFIG_AMIGAONEG3SE |
575 | ata_reset_time = ATA_RESET_TIME; | |
576 | s = getenv("ide_reset_timeout"); | |
577 | if (s) ata_reset_time = 2*simple_strtol(s, NULL, 10); | |
578 | #endif | |
c609719b WD |
579 | i = 0; |
580 | do { | |
581 | udelay (10000); /* 10 ms */ | |
582 | ||
2262cfee | 583 | c = ide_inb (dev, ATA_STATUS); |
c609719b | 584 | i++; |
c7de829c WD |
585 | #ifdef CONFIG_AMIGAONEG3SE |
586 | if (i > (ata_reset_time * 100)) { | |
587 | #else | |
c609719b | 588 | if (i > (ATA_RESET_TIME * 100)) { |
c7de829c | 589 | #endif |
c609719b WD |
590 | puts ("** Timeout **\n"); |
591 | ide_led ((LED_IDE1 | LED_IDE2), 0); /* LED's off */ | |
c7de829c WD |
592 | #ifdef CONFIG_AMIGAONEG3SE |
593 | /* If this is the second bus, the first one was OK */ | |
594 | if (bus != 0) | |
595 | { | |
596 | ide_bus_ok[bus] = 0; | |
597 | goto skip_bus; | |
598 | } | |
599 | #endif | |
c609719b WD |
600 | return; |
601 | } | |
602 | if ((i >= 100) && ((i%100)==0)) { | |
603 | putc ('.'); | |
604 | } | |
605 | } while (c & ATA_STAT_BUSY); | |
606 | ||
607 | if (c & (ATA_STAT_BUSY | ATA_STAT_FAULT)) { | |
608 | puts ("not available "); | |
609 | PRINTF ("Status = 0x%02X ", c); | |
610 | #ifndef CONFIG_ATAPI /* ATAPI Devices do not set DRDY */ | |
611 | } else if ((c & ATA_STAT_READY) == 0) { | |
612 | puts ("not available "); | |
613 | PRINTF ("Status = 0x%02X ", c); | |
614 | #endif | |
615 | } else { | |
616 | puts ("OK "); | |
617 | ide_bus_ok[bus] = 1; | |
618 | } | |
619 | WATCHDOG_RESET(); | |
620 | } | |
c7de829c WD |
621 | |
622 | #ifdef CONFIG_AMIGAONEG3SE | |
623 | skip_bus: | |
624 | #endif | |
c609719b WD |
625 | putc ('\n'); |
626 | ||
627 | ide_led ((LED_IDE1 | LED_IDE2), 0); /* LED's off */ | |
628 | ||
629 | curr_device = -1; | |
630 | for (i=0; i<CFG_IDE_MAXDEVICE; ++i) { | |
631 | #ifdef CONFIG_IDE_LED | |
632 | int led = (IDE_BUS(i) == 0) ? LED_IDE1 : LED_IDE2; | |
633 | #endif | |
634 | ide_dev_desc[i].if_type=IF_TYPE_IDE; | |
635 | ide_dev_desc[i].dev=i; | |
636 | ide_dev_desc[i].part_type=PART_TYPE_UNKNOWN; | |
637 | ide_dev_desc[i].blksz=0; | |
638 | ide_dev_desc[i].lba=0; | |
639 | ide_dev_desc[i].block_read=ide_read; | |
640 | if (!ide_bus_ok[IDE_BUS(i)]) | |
641 | continue; | |
642 | ide_led (led, 1); /* LED on */ | |
643 | ide_ident(&ide_dev_desc[i]); | |
644 | ide_led (led, 0); /* LED off */ | |
645 | dev_print(&ide_dev_desc[i]); | |
646 | /* ide_print (i); */ | |
647 | if ((ide_dev_desc[i].lba > 0) && (ide_dev_desc[i].blksz > 0)) { | |
648 | init_part (&ide_dev_desc[i]); /* initialize partition type */ | |
649 | if (curr_device < 0) | |
650 | curr_device = i; | |
651 | } | |
652 | } | |
653 | WATCHDOG_RESET(); | |
654 | } | |
655 | ||
656 | /* ------------------------------------------------------------------------- */ | |
657 | ||
658 | block_dev_desc_t * ide_get_dev(int dev) | |
659 | { | |
660 | return ((block_dev_desc_t *)&ide_dev_desc[dev]); | |
661 | } | |
662 | ||
663 | ||
664 | #ifdef CONFIG_IDE_8xx_DIRECT | |
665 | ||
666 | static void | |
667 | set_pcmcia_timing (int pmode) | |
668 | { | |
669 | volatile immap_t *immr = (immap_t *)CFG_IMMR; | |
670 | volatile pcmconf8xx_t *pcmp = &(immr->im_pcmcia); | |
671 | ulong timings; | |
672 | ||
673 | PRINTF ("Set timing for PIO Mode %d\n", pmode); | |
674 | ||
675 | timings = PCMCIA_SHT(pio_config_clk[pmode].t_hold) | |
676 | | PCMCIA_SST(pio_config_clk[pmode].t_setup) | |
677 | | PCMCIA_SL (pio_config_clk[pmode].t_length) | |
678 | ; | |
679 | ||
680 | /* IDE 0 | |
681 | */ | |
682 | pcmp->pcmc_pbr0 = CFG_PCMCIA_PBR0; | |
683 | pcmp->pcmc_por0 = CFG_PCMCIA_POR0 | |
684 | #if (CFG_PCMCIA_POR0 != 0) | |
685 | | timings | |
686 | #endif | |
687 | ; | |
688 | PRINTF ("PBR0: %08x POR0: %08x\n", pcmp->pcmc_pbr0, pcmp->pcmc_por0); | |
689 | ||
690 | pcmp->pcmc_pbr1 = CFG_PCMCIA_PBR1; | |
691 | pcmp->pcmc_por1 = CFG_PCMCIA_POR1 | |
692 | #if (CFG_PCMCIA_POR1 != 0) | |
693 | | timings | |
694 | #endif | |
695 | ; | |
696 | PRINTF ("PBR1: %08x POR1: %08x\n", pcmp->pcmc_pbr1, pcmp->pcmc_por1); | |
697 | ||
698 | pcmp->pcmc_pbr2 = CFG_PCMCIA_PBR2; | |
699 | pcmp->pcmc_por2 = CFG_PCMCIA_POR2 | |
700 | #if (CFG_PCMCIA_POR2 != 0) | |
701 | | timings | |
702 | #endif | |
703 | ; | |
704 | PRINTF ("PBR2: %08x POR2: %08x\n", pcmp->pcmc_pbr2, pcmp->pcmc_por2); | |
705 | ||
706 | pcmp->pcmc_pbr3 = CFG_PCMCIA_PBR3; | |
707 | pcmp->pcmc_por3 = CFG_PCMCIA_POR3 | |
708 | #if (CFG_PCMCIA_POR3 != 0) | |
709 | | timings | |
710 | #endif | |
711 | ; | |
712 | PRINTF ("PBR3: %08x POR3: %08x\n", pcmp->pcmc_pbr3, pcmp->pcmc_por3); | |
713 | ||
714 | /* IDE 1 | |
715 | */ | |
716 | pcmp->pcmc_pbr4 = CFG_PCMCIA_PBR4; | |
717 | pcmp->pcmc_por4 = CFG_PCMCIA_POR4 | |
718 | #if (CFG_PCMCIA_POR4 != 0) | |
719 | | timings | |
720 | #endif | |
721 | ; | |
722 | PRINTF ("PBR4: %08x POR4: %08x\n", pcmp->pcmc_pbr4, pcmp->pcmc_por4); | |
723 | ||
724 | pcmp->pcmc_pbr5 = CFG_PCMCIA_PBR5; | |
725 | pcmp->pcmc_por5 = CFG_PCMCIA_POR5 | |
726 | #if (CFG_PCMCIA_POR5 != 0) | |
727 | | timings | |
728 | #endif | |
729 | ; | |
730 | PRINTF ("PBR5: %08x POR5: %08x\n", pcmp->pcmc_pbr5, pcmp->pcmc_por5); | |
731 | ||
732 | pcmp->pcmc_pbr6 = CFG_PCMCIA_PBR6; | |
733 | pcmp->pcmc_por6 = CFG_PCMCIA_POR6 | |
734 | #if (CFG_PCMCIA_POR6 != 0) | |
735 | | timings | |
736 | #endif | |
737 | ; | |
738 | PRINTF ("PBR6: %08x POR6: %08x\n", pcmp->pcmc_pbr6, pcmp->pcmc_por6); | |
739 | ||
740 | pcmp->pcmc_pbr7 = CFG_PCMCIA_PBR7; | |
741 | pcmp->pcmc_por7 = CFG_PCMCIA_POR7 | |
742 | #if (CFG_PCMCIA_POR7 != 0) | |
743 | | timings | |
744 | #endif | |
745 | ; | |
746 | PRINTF ("PBR7: %08x POR7: %08x\n", pcmp->pcmc_pbr7, pcmp->pcmc_por7); | |
747 | ||
748 | } | |
749 | ||
750 | #endif /* CONFIG_IDE_8xx_DIRECT */ | |
751 | ||
752 | /* ------------------------------------------------------------------------- */ | |
753 | ||
2262cfee | 754 | #ifdef __PPC__ |
c609719b | 755 | static void __inline__ |
2262cfee | 756 | ide_outb(int dev, int port, unsigned char val) |
c609719b WD |
757 | { |
758 | /* Ensure I/O operations complete */ | |
759 | __asm__ volatile("eieio"); | |
760 | *((uchar *)(ATA_CURR_BASE(dev)+port)) = val; | |
761 | #if 0 | |
2262cfee | 762 | printf ("ide_outb: 0x%08lx <== 0x%02x\n", ATA_CURR_BASE(dev)+port, val); |
c609719b WD |
763 | #endif |
764 | } | |
2262cfee WD |
765 | #else /* ! __PPC__ */ |
766 | static void __inline__ | |
767 | ide_outb(int dev, int port, unsigned char val) | |
768 | { | |
15647dc7 | 769 | outb(val, ATA_CURR_BASE(dev)+port); |
2262cfee WD |
770 | } |
771 | #endif /* __PPC__ */ | |
772 | ||
c609719b | 773 | |
2262cfee | 774 | #ifdef __PPC__ |
c609719b | 775 | static unsigned char __inline__ |
2262cfee | 776 | ide_inb(int dev, int port) |
c609719b WD |
777 | { |
778 | uchar val; | |
779 | /* Ensure I/O operations complete */ | |
780 | __asm__ volatile("eieio"); | |
781 | val = *((uchar *)(ATA_CURR_BASE(dev)+port)); | |
782 | #if 0 | |
2262cfee | 783 | printf ("ide_inb: 0x%08lx ==> 0x%02x\n", ATA_CURR_BASE(dev)+port, val); |
c609719b WD |
784 | #endif |
785 | return (val); | |
786 | } | |
2262cfee WD |
787 | #else /* ! __PPC__ */ |
788 | static unsigned char __inline__ | |
789 | ide_inb(int dev, int port) | |
790 | { | |
15647dc7 | 791 | return inb(ATA_CURR_BASE(dev)+port); |
2262cfee WD |
792 | } |
793 | #endif /* __PPC__ */ | |
c609719b | 794 | |
2262cfee | 795 | #ifdef __PPC__ |
cceb871f | 796 | # ifdef CONFIG_AMIGAONEG3SE |
c7de829c WD |
797 | static void |
798 | output_data_short(int dev, ulong *sect_buf, int words) | |
799 | { | |
800 | ushort *dbuf; | |
801 | volatile ushort *pbuf; | |
8bde7f77 | 802 | |
c7de829c WD |
803 | pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG); |
804 | dbuf = (ushort *)sect_buf; | |
805 | while (words--) { | |
806 | __asm__ volatile ("eieio"); | |
807 | *pbuf = *dbuf++; | |
808 | __asm__ volatile ("eieio"); | |
809 | } | |
810 | ||
811 | if (words&1) | |
812 | *pbuf = 0; | |
813 | } | |
cceb871f | 814 | # endif /* CONFIG_AMIGAONEG3SE */ |
5da627a4 | 815 | #endif /* __PPC_ */ |
c7de829c | 816 | |
5da627a4 WD |
817 | /* We only need to swap data if we are running on a big endian cpu. */ |
818 | /* But Au1x00 cpu:s already swaps data in big endian mode! */ | |
819 | #if defined(__LITTLE_ENDIAN) || defined(CONFIG_AU1X00) | |
820 | #define input_swap_data(x,y,z) input_data(x,y,z) | |
821 | #else | |
c609719b WD |
822 | static void |
823 | input_swap_data(int dev, ulong *sect_buf, int words) | |
824 | { | |
825 | volatile ushort *pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG); | |
826 | ushort *dbuf = (ushort *)sect_buf; | |
827 | ||
828 | while (words--) { | |
829 | *dbuf++ = ld_le16(pbuf); | |
830 | *dbuf++ = ld_le16(pbuf); | |
831 | } | |
832 | } | |
5da627a4 | 833 | #endif /* __LITTLE_ENDIAN || CONFIG_AU1X00 */ |
2262cfee WD |
834 | |
835 | ||
2262cfee | 836 | #ifdef __PPC__ |
c609719b WD |
837 | static void |
838 | output_data(int dev, ulong *sect_buf, int words) | |
839 | { | |
840 | ushort *dbuf; | |
841 | volatile ushort *pbuf; | |
842 | ||
843 | pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG); | |
844 | dbuf = (ushort *)sect_buf; | |
845 | while (words--) { | |
846 | __asm__ volatile ("eieio"); | |
847 | *pbuf = *dbuf++; | |
848 | __asm__ volatile ("eieio"); | |
849 | *pbuf = *dbuf++; | |
850 | } | |
851 | } | |
2262cfee WD |
852 | #else /* ! __PPC__ */ |
853 | static void | |
854 | output_data(int dev, ulong *sect_buf, int words) | |
855 | { | |
15647dc7 | 856 | outsw(ATA_CURR_BASE(dev)+ATA_DATA_REG, sect_buf, words<<1); |
2262cfee WD |
857 | } |
858 | #endif /* __PPC__ */ | |
c609719b | 859 | |
2262cfee | 860 | #ifdef __PPC__ |
c609719b WD |
861 | static void |
862 | input_data(int dev, ulong *sect_buf, int words) | |
863 | { | |
864 | ushort *dbuf; | |
865 | volatile ushort *pbuf; | |
866 | ||
867 | pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG); | |
868 | dbuf = (ushort *)sect_buf; | |
869 | while (words--) { | |
870 | __asm__ volatile ("eieio"); | |
871 | *dbuf++ = *pbuf; | |
872 | __asm__ volatile ("eieio"); | |
873 | *dbuf++ = *pbuf; | |
874 | } | |
875 | } | |
2262cfee WD |
876 | #else /* ! __PPC__ */ |
877 | static void | |
878 | input_data(int dev, ulong *sect_buf, int words) | |
879 | { | |
15647dc7 | 880 | insw(ATA_CURR_BASE(dev)+ATA_DATA_REG, sect_buf, words << 1); |
2262cfee WD |
881 | } |
882 | ||
883 | #endif /* __PPC__ */ | |
c609719b | 884 | |
c7de829c WD |
885 | #ifdef CONFIG_AMIGAONEG3SE |
886 | static void | |
887 | input_data_short(int dev, ulong *sect_buf, int words) | |
888 | { | |
889 | ushort *dbuf; | |
890 | volatile ushort *pbuf; | |
891 | ||
892 | pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG); | |
893 | dbuf = (ushort *)sect_buf; | |
894 | while (words--) { | |
895 | __asm__ volatile ("eieio"); | |
896 | *dbuf++ = *pbuf; | |
897 | __asm__ volatile ("eieio"); | |
898 | } | |
899 | ||
900 | if (words&1) | |
901 | { | |
902 | ushort dummy; | |
903 | dummy = *pbuf; | |
904 | } | |
905 | } | |
906 | #endif | |
907 | ||
c609719b WD |
908 | /* ------------------------------------------------------------------------- |
909 | */ | |
910 | static void ide_ident (block_dev_desc_t *dev_desc) | |
911 | { | |
912 | ulong iobuf[ATA_SECTORWORDS]; | |
913 | unsigned char c; | |
914 | hd_driveid_t *iop = (hd_driveid_t *)iobuf; | |
915 | ||
c7de829c WD |
916 | #ifdef CONFIG_AMIGAONEG3SE |
917 | int max_bus_scan; | |
918 | int retries = 0; | |
919 | char *s; | |
920 | int do_retry = 0; | |
921 | #endif | |
922 | ||
c609719b WD |
923 | #if 0 |
924 | int mode, cycle_time; | |
925 | #endif | |
926 | int device; | |
927 | device=dev_desc->dev; | |
928 | printf (" Device %d: ", device); | |
929 | ||
c7de829c WD |
930 | #ifdef CONFIG_AMIGAONEG3SE |
931 | s = getenv("ide_maxbus"); | |
932 | if (s) { | |
933 | max_bus_scan = simple_strtol(s, NULL, 10); | |
934 | } else { | |
935 | max_bus_scan = CFG_IDE_MAXBUS; | |
936 | } | |
937 | if (device >= max_bus_scan*2) { | |
938 | dev_desc->type=DEV_TYPE_UNKNOWN; | |
939 | return; | |
940 | } | |
941 | #endif | |
942 | ||
c609719b WD |
943 | ide_led (DEVICE_LED(device), 1); /* LED on */ |
944 | /* Select device | |
945 | */ | |
2262cfee | 946 | ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); |
c609719b WD |
947 | dev_desc->if_type=IF_TYPE_IDE; |
948 | #ifdef CONFIG_ATAPI | |
c7de829c WD |
949 | |
950 | #ifdef CONFIG_AMIGAONEG3SE | |
951 | do_retry = 0; | |
952 | retries = 0; | |
953 | ||
954 | /* Warning: This will be tricky to read */ | |
955 | while (retries <= 1) | |
956 | { | |
957 | #endif /* CONFIG_AMIGAONEG3SE */ | |
958 | ||
c609719b | 959 | /* check signature */ |
2262cfee WD |
960 | if ((ide_inb(device,ATA_SECT_CNT) == 0x01) && |
961 | (ide_inb(device,ATA_SECT_NUM) == 0x01) && | |
962 | (ide_inb(device,ATA_CYL_LOW) == 0x14) && | |
963 | (ide_inb(device,ATA_CYL_HIGH) == 0xEB)) { | |
c609719b WD |
964 | /* ATAPI Signature found */ |
965 | dev_desc->if_type=IF_TYPE_ATAPI; | |
966 | /* Start Ident Command | |
967 | */ | |
2262cfee | 968 | ide_outb (device, ATA_COMMAND, ATAPI_CMD_IDENT); |
c609719b WD |
969 | /* |
970 | * Wait for completion - ATAPI devices need more time | |
971 | * to become ready | |
972 | */ | |
973 | c = ide_wait (device, ATAPI_TIME_OUT); | |
974 | } | |
975 | else | |
976 | #endif | |
977 | { | |
978 | /* Start Ident Command | |
979 | */ | |
2262cfee | 980 | ide_outb (device, ATA_COMMAND, ATA_CMD_IDENT); |
c609719b WD |
981 | |
982 | /* Wait for completion | |
983 | */ | |
984 | c = ide_wait (device, IDE_TIME_OUT); | |
985 | } | |
986 | ide_led (DEVICE_LED(device), 0); /* LED off */ | |
987 | ||
988 | if (((c & ATA_STAT_DRQ) == 0) || | |
989 | ((c & (ATA_STAT_FAULT|ATA_STAT_ERR)) != 0) ) { | |
c7de829c WD |
990 | #ifdef CONFIG_AMIGAONEG3SE |
991 | if (retries == 0) { | |
992 | do_retry = 1; | |
993 | } else { | |
994 | dev_desc->type=DEV_TYPE_UNKNOWN; | |
995 | return; | |
996 | } | |
997 | #else | |
c609719b WD |
998 | dev_desc->type=DEV_TYPE_UNKNOWN; |
999 | return; | |
c7de829c WD |
1000 | #endif /* CONFIG_AMIGAONEG3SE */ |
1001 | } | |
1002 | ||
1003 | #ifdef CONFIG_AMIGAONEG3SE | |
1004 | s = getenv("ide_doreset"); | |
1005 | if (s && strcmp(s, "on") == 0 && 1 == do_retry) { | |
1006 | /* Need to soft reset the device in case it's an ATAPI... */ | |
1007 | PRINTF("Retrying...\n"); | |
1008 | ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); | |
1009 | udelay(100000); | |
1010 | ide_outb (device, ATA_COMMAND, 0x08); | |
1011 | udelay (100000); /* 100 ms */ | |
1012 | retries++; | |
1013 | } else { | |
1014 | retries = 100; | |
c609719b | 1015 | } |
c7de829c WD |
1016 | } /* see above - ugly to read */ |
1017 | #endif /* CONFIG_AMIGAONEG3SE */ | |
c609719b WD |
1018 | |
1019 | input_swap_data (device, iobuf, ATA_SECTORWORDS); | |
1020 | ||
1021 | ident_cpy (dev_desc->revision, iop->fw_rev, sizeof(dev_desc->revision)); | |
1022 | ident_cpy (dev_desc->vendor, iop->model, sizeof(dev_desc->vendor)); | |
1023 | ident_cpy (dev_desc->product, iop->serial_no, sizeof(dev_desc->product)); | |
1024 | ||
1025 | if ((iop->config & 0x0080)==0x0080) | |
1026 | dev_desc->removable = 1; | |
1027 | else | |
1028 | dev_desc->removable = 0; | |
1029 | ||
1030 | #if 0 | |
1031 | /* | |
1032 | * Drive PIO mode autoselection | |
1033 | */ | |
1034 | mode = iop->tPIO; | |
1035 | ||
1036 | printf ("tPIO = 0x%02x = %d\n",mode, mode); | |
1037 | if (mode > 2) { /* 2 is maximum allowed tPIO value */ | |
1038 | mode = 2; | |
1039 | PRINTF ("Override tPIO -> 2\n"); | |
1040 | } | |
1041 | if (iop->field_valid & 2) { /* drive implements ATA2? */ | |
1042 | PRINTF ("Drive implements ATA2\n"); | |
1043 | if (iop->capability & 8) { /* drive supports use_iordy? */ | |
1044 | cycle_time = iop->eide_pio_iordy; | |
1045 | } else { | |
1046 | cycle_time = iop->eide_pio; | |
1047 | } | |
1048 | PRINTF ("cycle time = %d\n", cycle_time); | |
1049 | mode = 4; | |
1050 | if (cycle_time > 120) mode = 3; /* 120 ns for PIO mode 4 */ | |
1051 | if (cycle_time > 180) mode = 2; /* 180 ns for PIO mode 3 */ | |
1052 | if (cycle_time > 240) mode = 1; /* 240 ns for PIO mode 4 */ | |
1053 | if (cycle_time > 383) mode = 0; /* 383 ns for PIO mode 4 */ | |
1054 | } | |
1055 | printf ("PIO mode to use: PIO %d\n", mode); | |
1056 | #endif /* 0 */ | |
1057 | ||
1058 | #ifdef CONFIG_ATAPI | |
1059 | if (dev_desc->if_type==IF_TYPE_ATAPI) { | |
1060 | atapi_inquiry(dev_desc); | |
1061 | return; | |
1062 | } | |
1063 | #endif /* CONFIG_ATAPI */ | |
1064 | ||
1065 | /* swap shorts */ | |
1066 | dev_desc->lba = (iop->lba_capacity << 16) | (iop->lba_capacity >> 16); | |
1067 | /* assuming HD */ | |
1068 | dev_desc->type=DEV_TYPE_HARDDISK; | |
1069 | dev_desc->blksz=ATA_BLOCKSIZE; | |
1070 | dev_desc->lun=0; /* just to fill something in... */ | |
1071 | ||
1072 | #if 0 /* only used to test the powersaving mode, | |
1073 | * if enabled, the drive goes after 5 sec | |
1074 | * in standby mode */ | |
2262cfee | 1075 | ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); |
c609719b | 1076 | c = ide_wait (device, IDE_TIME_OUT); |
2262cfee WD |
1077 | ide_outb (device, ATA_SECT_CNT, 1); |
1078 | ide_outb (device, ATA_LBA_LOW, 0); | |
1079 | ide_outb (device, ATA_LBA_MID, 0); | |
1080 | ide_outb (device, ATA_LBA_HIGH, 0); | |
1081 | ide_outb (device, ATA_DEV_HD, ATA_LBA | | |
c609719b | 1082 | ATA_DEVICE(device)); |
2262cfee | 1083 | ide_outb (device, ATA_COMMAND, 0xe3); |
c609719b WD |
1084 | udelay (50); |
1085 | c = ide_wait (device, IDE_TIME_OUT); /* can't take over 500 ms */ | |
1086 | #endif | |
1087 | } | |
1088 | ||
1089 | ||
1090 | /* ------------------------------------------------------------------------- */ | |
1091 | ||
1092 | ulong ide_read (int device, ulong blknr, ulong blkcnt, ulong *buffer) | |
1093 | { | |
1094 | ulong n = 0; | |
1095 | unsigned char c; | |
1096 | unsigned char pwrsave=0; /* power save */ | |
1097 | ||
1098 | PRINTF ("ide_read dev %d start %lX, blocks %lX buffer at %lX\n", | |
1099 | device, blknr, blkcnt, (ulong)buffer); | |
1100 | ||
1101 | ide_led (DEVICE_LED(device), 1); /* LED on */ | |
1102 | ||
1103 | /* Select device | |
1104 | */ | |
2262cfee | 1105 | ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); |
c609719b WD |
1106 | c = ide_wait (device, IDE_TIME_OUT); |
1107 | ||
1108 | if (c & ATA_STAT_BUSY) { | |
1109 | printf ("IDE read: device %d not ready\n", device); | |
1110 | goto IDE_READ_E; | |
1111 | } | |
1112 | ||
1113 | /* first check if the drive is in Powersaving mode, if yes, | |
1114 | * increase the timeout value */ | |
2262cfee | 1115 | ide_outb (device, ATA_COMMAND, ATA_CMD_CHK_PWR); |
c609719b WD |
1116 | udelay (50); |
1117 | ||
1118 | c = ide_wait (device, IDE_TIME_OUT); /* can't take over 500 ms */ | |
1119 | ||
1120 | if (c & ATA_STAT_BUSY) { | |
1121 | printf ("IDE read: device %d not ready\n", device); | |
1122 | goto IDE_READ_E; | |
1123 | } | |
1124 | if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) { | |
1125 | printf ("No Powersaving mode %X\n", c); | |
1126 | } else { | |
2262cfee | 1127 | c = ide_inb(device,ATA_SECT_CNT); |
c609719b WD |
1128 | PRINTF("Powersaving %02X\n",c); |
1129 | if(c==0) | |
1130 | pwrsave=1; | |
1131 | } | |
1132 | ||
1133 | ||
1134 | while (blkcnt-- > 0) { | |
1135 | ||
1136 | c = ide_wait (device, IDE_TIME_OUT); | |
1137 | ||
1138 | if (c & ATA_STAT_BUSY) { | |
1139 | printf ("IDE read: device %d not ready\n", device); | |
1140 | break; | |
1141 | } | |
1142 | ||
2262cfee WD |
1143 | ide_outb (device, ATA_SECT_CNT, 1); |
1144 | ide_outb (device, ATA_LBA_LOW, (blknr >> 0) & 0xFF); | |
1145 | ide_outb (device, ATA_LBA_MID, (blknr >> 8) & 0xFF); | |
1146 | ide_outb (device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF); | |
1147 | ide_outb (device, ATA_DEV_HD, ATA_LBA | | |
c609719b WD |
1148 | ATA_DEVICE(device) | |
1149 | ((blknr >> 24) & 0xF) ); | |
2262cfee | 1150 | ide_outb (device, ATA_COMMAND, ATA_CMD_READ); |
c609719b WD |
1151 | |
1152 | udelay (50); | |
1153 | ||
1154 | if(pwrsave) { | |
1155 | c = ide_wait (device, IDE_SPIN_UP_TIME_OUT); /* may take up to 4 sec */ | |
1156 | pwrsave=0; | |
1157 | } else { | |
1158 | c = ide_wait (device, IDE_TIME_OUT); /* can't take over 500 ms */ | |
1159 | } | |
1160 | ||
1161 | if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) { | |
1162 | printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n", | |
1163 | device, blknr, c); | |
1164 | break; | |
1165 | } | |
1166 | ||
1167 | input_data (device, buffer, ATA_SECTORWORDS); | |
2262cfee | 1168 | (void) ide_inb (device, ATA_STATUS); /* clear IRQ */ |
c609719b WD |
1169 | |
1170 | ++n; | |
1171 | ++blknr; | |
1172 | buffer += ATA_SECTORWORDS; | |
1173 | } | |
1174 | IDE_READ_E: | |
1175 | ide_led (DEVICE_LED(device), 0); /* LED off */ | |
1176 | return (n); | |
1177 | } | |
1178 | ||
1179 | /* ------------------------------------------------------------------------- */ | |
1180 | ||
1181 | ||
1182 | ulong ide_write (int device, ulong blknr, ulong blkcnt, ulong *buffer) | |
1183 | { | |
1184 | ulong n = 0; | |
1185 | unsigned char c; | |
1186 | ||
1187 | ide_led (DEVICE_LED(device), 1); /* LED on */ | |
1188 | ||
1189 | /* Select device | |
1190 | */ | |
2262cfee | 1191 | ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); |
c609719b WD |
1192 | |
1193 | while (blkcnt-- > 0) { | |
1194 | ||
1195 | c = ide_wait (device, IDE_TIME_OUT); | |
1196 | ||
1197 | if (c & ATA_STAT_BUSY) { | |
1198 | printf ("IDE read: device %d not ready\n", device); | |
1199 | goto WR_OUT; | |
1200 | } | |
1201 | ||
2262cfee WD |
1202 | ide_outb (device, ATA_SECT_CNT, 1); |
1203 | ide_outb (device, ATA_LBA_LOW, (blknr >> 0) & 0xFF); | |
1204 | ide_outb (device, ATA_LBA_MID, (blknr >> 8) & 0xFF); | |
1205 | ide_outb (device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF); | |
1206 | ide_outb (device, ATA_DEV_HD, ATA_LBA | | |
c609719b WD |
1207 | ATA_DEVICE(device) | |
1208 | ((blknr >> 24) & 0xF) ); | |
2262cfee | 1209 | ide_outb (device, ATA_COMMAND, ATA_CMD_WRITE); |
c609719b WD |
1210 | |
1211 | udelay (50); | |
1212 | ||
1213 | c = ide_wait (device, IDE_TIME_OUT); /* can't take over 500 ms */ | |
1214 | ||
1215 | if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) { | |
1216 | printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n", | |
1217 | device, blknr, c); | |
1218 | goto WR_OUT; | |
1219 | } | |
1220 | ||
1221 | output_data (device, buffer, ATA_SECTORWORDS); | |
2262cfee | 1222 | c = ide_inb (device, ATA_STATUS); /* clear IRQ */ |
c609719b WD |
1223 | ++n; |
1224 | ++blknr; | |
1225 | buffer += ATA_SECTORWORDS; | |
1226 | } | |
1227 | WR_OUT: | |
1228 | ide_led (DEVICE_LED(device), 0); /* LED off */ | |
1229 | return (n); | |
1230 | } | |
1231 | ||
1232 | /* ------------------------------------------------------------------------- */ | |
1233 | ||
1234 | /* | |
1235 | * copy src to dest, skipping leading and trailing blanks and null | |
1236 | * terminate the string | |
1237 | */ | |
1238 | static void ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len) | |
1239 | { | |
1240 | int start,end; | |
1241 | ||
1242 | start=0; | |
1243 | while (start<len) { | |
1244 | if (src[start]!=' ') | |
1245 | break; | |
1246 | start++; | |
1247 | } | |
1248 | end=len-1; | |
1249 | while (end>start) { | |
1250 | if (src[end]!=' ') | |
1251 | break; | |
1252 | end--; | |
1253 | } | |
1254 | for ( ; start<=end; start++) { | |
1255 | *dest++=src[start]; | |
1256 | } | |
1257 | *dest='\0'; | |
1258 | } | |
1259 | ||
1260 | /* ------------------------------------------------------------------------- */ | |
1261 | ||
1262 | /* | |
1263 | * Wait until Busy bit is off, or timeout (in ms) | |
1264 | * Return last status | |
1265 | */ | |
1266 | static uchar ide_wait (int dev, ulong t) | |
1267 | { | |
1268 | ulong delay = 10 * t; /* poll every 100 us */ | |
1269 | uchar c; | |
1270 | ||
2262cfee | 1271 | while ((c = ide_inb(dev, ATA_STATUS)) & ATA_STAT_BUSY) { |
c609719b WD |
1272 | udelay (100); |
1273 | if (delay-- == 0) { | |
1274 | break; | |
1275 | } | |
1276 | } | |
1277 | return (c); | |
1278 | } | |
1279 | ||
1280 | /* ------------------------------------------------------------------------- */ | |
1281 | ||
1282 | #ifdef CONFIG_IDE_RESET | |
1283 | extern void ide_set_reset(int idereset); | |
1284 | ||
1285 | static void ide_reset (void) | |
1286 | { | |
1287 | #if defined(CFG_PB_12V_ENABLE) || defined(CFG_PB_IDE_MOTOR) | |
1288 | volatile immap_t *immr = (immap_t *)CFG_IMMR; | |
1289 | #endif | |
1290 | int i; | |
1291 | ||
1292 | curr_device = -1; | |
1293 | for (i=0; i<CFG_IDE_MAXBUS; ++i) | |
1294 | ide_bus_ok[i] = 0; | |
1295 | for (i=0; i<CFG_IDE_MAXDEVICE; ++i) | |
1296 | ide_dev_desc[i].type = DEV_TYPE_UNKNOWN; | |
1297 | ||
1298 | ide_set_reset (1); /* assert reset */ | |
1299 | ||
1300 | WATCHDOG_RESET(); | |
1301 | ||
1302 | #ifdef CFG_PB_12V_ENABLE | |
1303 | immr->im_cpm.cp_pbdat &= ~(CFG_PB_12V_ENABLE); /* 12V Enable output OFF */ | |
1304 | immr->im_cpm.cp_pbpar &= ~(CFG_PB_12V_ENABLE); | |
1305 | immr->im_cpm.cp_pbodr &= ~(CFG_PB_12V_ENABLE); | |
1306 | immr->im_cpm.cp_pbdir |= CFG_PB_12V_ENABLE; | |
1307 | ||
1308 | /* wait 500 ms for the voltage to stabilize | |
1309 | */ | |
1310 | for (i=0; i<500; ++i) { | |
1311 | udelay (1000); | |
1312 | } | |
1313 | ||
1314 | immr->im_cpm.cp_pbdat |= CFG_PB_12V_ENABLE; /* 12V Enable output ON */ | |
1315 | #endif /* CFG_PB_12V_ENABLE */ | |
1316 | ||
1317 | #ifdef CFG_PB_IDE_MOTOR | |
1318 | /* configure IDE Motor voltage monitor pin as input */ | |
1319 | immr->im_cpm.cp_pbpar &= ~(CFG_PB_IDE_MOTOR); | |
1320 | immr->im_cpm.cp_pbodr &= ~(CFG_PB_IDE_MOTOR); | |
1321 | immr->im_cpm.cp_pbdir &= ~(CFG_PB_IDE_MOTOR); | |
1322 | ||
1323 | /* wait up to 1 s for the motor voltage to stabilize | |
1324 | */ | |
1325 | for (i=0; i<1000; ++i) { | |
1326 | if ((immr->im_cpm.cp_pbdat & CFG_PB_IDE_MOTOR) != 0) { | |
1327 | break; | |
1328 | } | |
1329 | udelay (1000); | |
1330 | } | |
1331 | ||
1332 | if (i == 1000) { /* Timeout */ | |
1333 | printf ("\nWarning: 5V for IDE Motor missing\n"); | |
1334 | # ifdef CONFIG_STATUS_LED | |
1335 | # ifdef STATUS_LED_YELLOW | |
1336 | status_led_set (STATUS_LED_YELLOW, STATUS_LED_ON ); | |
1337 | # endif | |
1338 | # ifdef STATUS_LED_GREEN | |
1339 | status_led_set (STATUS_LED_GREEN, STATUS_LED_OFF); | |
1340 | # endif | |
1341 | # endif /* CONFIG_STATUS_LED */ | |
1342 | } | |
1343 | #endif /* CFG_PB_IDE_MOTOR */ | |
1344 | ||
1345 | WATCHDOG_RESET(); | |
1346 | ||
1347 | /* de-assert RESET signal */ | |
1348 | ide_set_reset(0); | |
1349 | ||
1350 | /* wait 250 ms */ | |
1351 | for (i=0; i<250; ++i) { | |
1352 | udelay (1000); | |
1353 | } | |
1354 | } | |
1355 | ||
1356 | #endif /* CONFIG_IDE_RESET */ | |
1357 | ||
1358 | /* ------------------------------------------------------------------------- */ | |
1359 | ||
1f53a416 | 1360 | #if defined(CONFIG_IDE_LED) && !defined(CONFIG_AMIGAONEG3SE) && !defined(CONFIG_KUP4K) |
c609719b WD |
1361 | |
1362 | static uchar led_buffer = 0; /* Buffer for current LED status */ | |
1363 | ||
1364 | static void ide_led (uchar led, uchar status) | |
1365 | { | |
1366 | uchar *led_port = LED_PORT; | |
1367 | ||
1368 | if (status) { /* switch LED on */ | |
1369 | led_buffer |= led; | |
1370 | } else { /* switch LED off */ | |
1371 | led_buffer &= ~led; | |
1372 | } | |
1373 | ||
1374 | *led_port = led_buffer; | |
1375 | } | |
1376 | ||
1377 | #endif /* CONFIG_IDE_LED */ | |
1378 | ||
1379 | /* ------------------------------------------------------------------------- */ | |
1380 | ||
1381 | #ifdef CONFIG_ATAPI | |
1382 | /**************************************************************************** | |
1383 | * ATAPI Support | |
1384 | */ | |
1385 | ||
1386 | ||
c609719b WD |
1387 | #undef ATAPI_DEBUG |
1388 | ||
1389 | #ifdef ATAPI_DEBUG | |
1390 | #define AT_PRINTF(fmt,args...) printf (fmt ,##args) | |
1391 | #else | |
1392 | #define AT_PRINTF(fmt,args...) | |
1393 | #endif | |
1394 | ||
2262cfee | 1395 | #ifdef __PPC__ |
c609719b WD |
1396 | /* since ATAPI may use commands with not 4 bytes alligned length |
1397 | * we have our own transfer functions, 2 bytes alligned */ | |
1398 | static void | |
1399 | output_data_shorts(int dev, ushort *sect_buf, int shorts) | |
1400 | { | |
1401 | ushort *dbuf; | |
1402 | volatile ushort *pbuf; | |
1403 | ||
1404 | pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG); | |
1405 | dbuf = (ushort *)sect_buf; | |
1406 | while (shorts--) { | |
1407 | __asm__ volatile ("eieio"); | |
1408 | *pbuf = *dbuf++; | |
1409 | } | |
1410 | } | |
1411 | ||
1412 | static void | |
1413 | input_data_shorts(int dev, ushort *sect_buf, int shorts) | |
1414 | { | |
1415 | ushort *dbuf; | |
1416 | volatile ushort *pbuf; | |
1417 | ||
1418 | pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG); | |
1419 | dbuf = (ushort *)sect_buf; | |
1420 | while (shorts--) { | |
1421 | __asm__ volatile ("eieio"); | |
1422 | *dbuf++ = *pbuf; | |
1423 | } | |
1424 | } | |
1425 | ||
2262cfee WD |
1426 | #else /* ! __PPC__ */ |
1427 | static void | |
1428 | output_data_shorts(int dev, ushort *sect_buf, int shorts) | |
1429 | { | |
15647dc7 | 1430 | outsw(ATA_CURR_BASE(dev)+ATA_DATA_REG, sect_buf, shorts); |
2262cfee WD |
1431 | } |
1432 | ||
1433 | ||
1434 | static void | |
1435 | input_data_shorts(int dev, ushort *sect_buf, int shorts) | |
1436 | { | |
15647dc7 | 1437 | insw(ATA_CURR_BASE(dev)+ATA_DATA_REG, sect_buf, shorts); |
2262cfee WD |
1438 | } |
1439 | ||
1440 | #endif /* __PPC__ */ | |
1441 | ||
c609719b WD |
1442 | /* |
1443 | * Wait until (Status & mask) == res, or timeout (in ms) | |
1444 | * Return last status | |
1445 | * This is used since some ATAPI CD ROMs clears their Busy Bit first | |
1446 | * and then they set their DRQ Bit | |
1447 | */ | |
1448 | static uchar atapi_wait_mask (int dev, ulong t,uchar mask, uchar res) | |
1449 | { | |
1450 | ulong delay = 10 * t; /* poll every 100 us */ | |
1451 | uchar c; | |
1452 | ||
2262cfee WD |
1453 | c = ide_inb(dev,ATA_DEV_CTL); /* prevents to read the status before valid */ |
1454 | while (((c = ide_inb(dev, ATA_STATUS)) & mask) != res) { | |
c609719b WD |
1455 | /* break if error occurs (doesn't make sense to wait more) */ |
1456 | if((c & ATA_STAT_ERR)==ATA_STAT_ERR) | |
1457 | break; | |
1458 | udelay (100); | |
1459 | if (delay-- == 0) { | |
1460 | break; | |
1461 | } | |
1462 | } | |
1463 | return (c); | |
1464 | } | |
1465 | ||
1466 | /* | |
1467 | * issue an atapi command | |
1468 | */ | |
1469 | unsigned char atapi_issue(int device,unsigned char* ccb,int ccblen, unsigned char * buffer,int buflen) | |
1470 | { | |
1471 | unsigned char c,err,mask,res; | |
1472 | int n; | |
1473 | ide_led (DEVICE_LED(device), 1); /* LED on */ | |
1474 | ||
1475 | /* Select device | |
1476 | */ | |
1477 | mask = ATA_STAT_BUSY|ATA_STAT_DRQ; | |
1478 | res = 0; | |
c7de829c WD |
1479 | #ifdef CONFIG_AMIGAONEG3SE |
1480 | # warning THF: Removed LBA mode ??? | |
1481 | #endif | |
2262cfee | 1482 | ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); |
c609719b WD |
1483 | c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res); |
1484 | if ((c & mask) != res) { | |
1485 | printf ("ATAPI_ISSUE: device %d not ready status %X\n", device,c); | |
1486 | err=0xFF; | |
1487 | goto AI_OUT; | |
1488 | } | |
1489 | /* write taskfile */ | |
2262cfee | 1490 | ide_outb (device, ATA_ERROR_REG, 0); /* no DMA, no overlaped */ |
c7de829c WD |
1491 | ide_outb (device, ATA_SECT_CNT, 0); |
1492 | ide_outb (device, ATA_SECT_NUM, 0); | |
2262cfee | 1493 | ide_outb (device, ATA_CYL_LOW, (unsigned char)(buflen & 0xFF)); |
c7de829c WD |
1494 | ide_outb (device, ATA_CYL_HIGH, (unsigned char)((buflen>>8) & 0xFF)); |
1495 | #ifdef CONFIG_AMIGAONEG3SE | |
1496 | # warning THF: Removed LBA mode ??? | |
1497 | #endif | |
2262cfee | 1498 | ide_outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); |
c609719b | 1499 | |
2262cfee | 1500 | ide_outb (device, ATA_COMMAND, ATAPI_CMD_PACKET); |
c609719b WD |
1501 | udelay (50); |
1502 | ||
1503 | mask = ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR; | |
1504 | res = ATA_STAT_DRQ; | |
1505 | c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res); | |
1506 | ||
1507 | if ((c & mask) != res) { /* DRQ must be 1, BSY 0 */ | |
1508 | printf ("ATTAPI_ISSUE: Error (no IRQ) before sending ccb dev %d status 0x%02x\n",device,c); | |
1509 | err=0xFF; | |
1510 | goto AI_OUT; | |
1511 | } | |
1512 | ||
1513 | output_data_shorts (device, (unsigned short *)ccb,ccblen/2); /* write command block */ | |
1514 | /* ATAPI Command written wait for completition */ | |
1515 | udelay (5000); /* device must set bsy */ | |
1516 | ||
1517 | mask = ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR; | |
1518 | /* if no data wait for DRQ = 0 BSY = 0 | |
1519 | * if data wait for DRQ = 1 BSY = 0 */ | |
1520 | res=0; | |
1521 | if(buflen) | |
1522 | res = ATA_STAT_DRQ; | |
1523 | c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res); | |
1524 | if ((c & mask) != res ) { | |
1525 | if (c & ATA_STAT_ERR) { | |
2262cfee | 1526 | err=(ide_inb(device,ATA_ERROR_REG))>>4; |
c609719b WD |
1527 | AT_PRINTF("atapi_issue 1 returned sense key %X status %02X\n",err,c); |
1528 | } else { | |
1529 | printf ("ATTAPI_ISSUE: (no DRQ) after sending ccb (%x) status 0x%02x\n", ccb[0],c); | |
1530 | err=0xFF; | |
1531 | } | |
1532 | goto AI_OUT; | |
1533 | } | |
2262cfee | 1534 | n=ide_inb(device, ATA_CYL_HIGH); |
c609719b | 1535 | n<<=8; |
2262cfee | 1536 | n+=ide_inb(device, ATA_CYL_LOW); |
c609719b WD |
1537 | if(n>buflen) { |
1538 | printf("ERROR, transfer bytes %d requested only %d\n",n,buflen); | |
1539 | err=0xff; | |
1540 | goto AI_OUT; | |
1541 | } | |
1542 | if((n==0)&&(buflen<0)) { | |
1543 | printf("ERROR, transfer bytes %d requested %d\n",n,buflen); | |
1544 | err=0xff; | |
1545 | goto AI_OUT; | |
1546 | } | |
1547 | if(n!=buflen) { | |
1548 | AT_PRINTF("WARNING, transfer bytes %d not equal with requested %d\n",n,buflen); | |
1549 | } | |
1550 | if(n!=0) { /* data transfer */ | |
1551 | AT_PRINTF("ATAPI_ISSUE: %d Bytes to transfer\n",n); | |
1552 | /* we transfer shorts */ | |
1553 | n>>=1; | |
1554 | /* ok now decide if it is an in or output */ | |
2262cfee | 1555 | if ((ide_inb(device, ATA_SECT_CNT)&0x02)==0) { |
c609719b WD |
1556 | AT_PRINTF("Write to device\n"); |
1557 | output_data_shorts(device,(unsigned short *)buffer,n); | |
1558 | } else { | |
1559 | AT_PRINTF("Read from device @ %p shorts %d\n",buffer,n); | |
1560 | input_data_shorts(device,(unsigned short *)buffer,n); | |
1561 | } | |
1562 | } | |
1563 | udelay(5000); /* seems that some CD ROMs need this... */ | |
1564 | mask = ATA_STAT_BUSY|ATA_STAT_ERR; | |
1565 | res=0; | |
1566 | c = atapi_wait_mask(device,ATAPI_TIME_OUT,mask,res); | |
1567 | if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) { | |
2262cfee | 1568 | err=(ide_inb(device,ATA_ERROR_REG) >> 4); |
c609719b WD |
1569 | AT_PRINTF("atapi_issue 2 returned sense key %X status %X\n",err,c); |
1570 | } else { | |
1571 | err = 0; | |
1572 | } | |
1573 | AI_OUT: | |
1574 | ide_led (DEVICE_LED(device), 0); /* LED off */ | |
1575 | return (err); | |
1576 | } | |
1577 | ||
1578 | /* | |
1579 | * sending the command to atapi_issue. If an status other than good | |
1580 | * returns, an request_sense will be issued | |
1581 | */ | |
1582 | ||
1583 | #define ATAPI_DRIVE_NOT_READY 100 | |
1584 | #define ATAPI_UNIT_ATTN 10 | |
1585 | ||
1586 | unsigned char atapi_issue_autoreq (int device, | |
1587 | unsigned char* ccb, | |
1588 | int ccblen, | |
1589 | unsigned char *buffer, | |
1590 | int buflen) | |
1591 | { | |
1592 | unsigned char sense_data[18],sense_ccb[12]; | |
1593 | unsigned char res,key,asc,ascq; | |
1594 | int notready,unitattn; | |
1595 | ||
c7de829c WD |
1596 | #ifdef CONFIG_AMIGAONEG3SE |
1597 | char *s; | |
1598 | unsigned int timeout, retrycnt; | |
1599 | ||
1600 | s = getenv("ide_cd_timeout"); | |
1601 | timeout = s ? (simple_strtol(s, NULL, 10)*1000000)/5 : 0; | |
1602 | ||
1603 | retrycnt = 0; | |
1604 | #endif | |
1605 | ||
c609719b WD |
1606 | unitattn=ATAPI_UNIT_ATTN; |
1607 | notready=ATAPI_DRIVE_NOT_READY; | |
1608 | ||
1609 | retry: | |
1610 | res= atapi_issue(device,ccb,ccblen,buffer,buflen); | |
1611 | if (res==0) | |
1612 | return (0); /* Ok */ | |
1613 | ||
1614 | if (res==0xFF) | |
1615 | return (0xFF); /* error */ | |
1616 | ||
1617 | AT_PRINTF("(auto_req)atapi_issue returned sense key %X\n",res); | |
1618 | ||
1619 | memset(sense_ccb,0,sizeof(sense_ccb)); | |
1620 | memset(sense_data,0,sizeof(sense_data)); | |
1621 | sense_ccb[0]=ATAPI_CMD_REQ_SENSE; | |
c7de829c | 1622 | sense_ccb[4]=18; /* allocation Length */ |
c609719b WD |
1623 | |
1624 | res=atapi_issue(device,sense_ccb,12,sense_data,18); | |
1625 | key=(sense_data[2]&0xF); | |
1626 | asc=(sense_data[12]); | |
1627 | ascq=(sense_data[13]); | |
1628 | ||
1629 | AT_PRINTF("ATAPI_CMD_REQ_SENSE returned %x\n",res); | |
1630 | AT_PRINTF(" Sense page: %02X key %02X ASC %02X ASCQ %02X\n", | |
1631 | sense_data[0], | |
1632 | key, | |
1633 | asc, | |
1634 | ascq); | |
1635 | ||
1636 | if((key==0)) | |
1637 | return 0; /* ok device ready */ | |
1638 | ||
1639 | if((key==6)|| (asc==0x29) || (asc==0x28)) { /* Unit Attention */ | |
1640 | if(unitattn-->0) { | |
1641 | udelay(200*1000); | |
1642 | goto retry; | |
1643 | } | |
1644 | printf("Unit Attention, tried %d\n",ATAPI_UNIT_ATTN); | |
1645 | goto error; | |
1646 | } | |
1647 | if((asc==0x4) && (ascq==0x1)) { /* not ready, but will be ready soon */ | |
1648 | if (notready-->0) { | |
1649 | udelay(200*1000); | |
1650 | goto retry; | |
1651 | } | |
1652 | printf("Drive not ready, tried %d times\n",ATAPI_DRIVE_NOT_READY); | |
1653 | goto error; | |
1654 | } | |
1655 | if(asc==0x3a) { | |
1656 | AT_PRINTF("Media not present\n"); | |
1657 | goto error; | |
1658 | } | |
c7de829c WD |
1659 | |
1660 | #ifdef CONFIG_AMIGAONEG3SE | |
1661 | if ((sense_data[2]&0xF)==0x0B) { | |
1662 | AT_PRINTF("ABORTED COMMAND...retry\n"); | |
1663 | if (retrycnt++ < 4) | |
1664 | goto retry; | |
1665 | return (0xFF); | |
1666 | } | |
1667 | ||
1668 | if ((sense_data[2]&0xf) == 0x02 && | |
1669 | sense_data[12] == 0x04 && | |
1670 | sense_data[13] == 0x01 ) { | |
1671 | AT_PRINTF("Waiting for unit to become active\n"); | |
1672 | udelay(timeout); | |
1673 | if (retrycnt++ < 4) | |
1674 | goto retry; | |
1675 | return 0xFF; | |
1676 | } | |
1677 | #endif /* CONFIG_AMIGAONEG3SE */ | |
1678 | ||
c609719b WD |
1679 | printf ("ERROR: Unknown Sense key %02X ASC %02X ASCQ %02X\n",key,asc,ascq); |
1680 | error: | |
1681 | AT_PRINTF ("ERROR Sense key %02X ASC %02X ASCQ %02X\n",key,asc,ascq); | |
1682 | return (0xFF); | |
1683 | } | |
1684 | ||
1685 | ||
c609719b WD |
1686 | static void atapi_inquiry(block_dev_desc_t * dev_desc) |
1687 | { | |
1688 | unsigned char ccb[12]; /* Command descriptor block */ | |
1689 | unsigned char iobuf[64]; /* temp buf */ | |
1690 | unsigned char c; | |
1691 | int device; | |
1692 | ||
1693 | device=dev_desc->dev; | |
1694 | dev_desc->type=DEV_TYPE_UNKNOWN; /* not yet valid */ | |
1695 | dev_desc->block_read=atapi_read; | |
1696 | ||
1697 | memset(ccb,0,sizeof(ccb)); | |
1698 | memset(iobuf,0,sizeof(iobuf)); | |
1699 | ||
1700 | ccb[0]=ATAPI_CMD_INQUIRY; | |
1701 | ccb[4]=40; /* allocation Legnth */ | |
1702 | c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,40); | |
1703 | ||
1704 | AT_PRINTF("ATAPI_CMD_INQUIRY returned %x\n",c); | |
1705 | if (c!=0) | |
1706 | return; | |
1707 | ||
1708 | /* copy device ident strings */ | |
1709 | ident_cpy(dev_desc->vendor,&iobuf[8],8); | |
1710 | ident_cpy(dev_desc->product,&iobuf[16],16); | |
1711 | ident_cpy(dev_desc->revision,&iobuf[32],5); | |
1712 | ||
1713 | dev_desc->lun=0; | |
1714 | dev_desc->lba=0; | |
1715 | dev_desc->blksz=0; | |
1716 | dev_desc->type=iobuf[0] & 0x1f; | |
1717 | ||
1718 | if ((iobuf[1]&0x80)==0x80) | |
1719 | dev_desc->removable = 1; | |
1720 | else | |
1721 | dev_desc->removable = 0; | |
1722 | ||
1723 | memset(ccb,0,sizeof(ccb)); | |
1724 | memset(iobuf,0,sizeof(iobuf)); | |
1725 | ccb[0]=ATAPI_CMD_START_STOP; | |
1726 | ccb[4]=0x03; /* start */ | |
1727 | ||
1728 | c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,0); | |
1729 | ||
1730 | AT_PRINTF("ATAPI_CMD_START_STOP returned %x\n",c); | |
1731 | if (c!=0) | |
1732 | return; | |
1733 | ||
1734 | memset(ccb,0,sizeof(ccb)); | |
1735 | memset(iobuf,0,sizeof(iobuf)); | |
1736 | c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,0); | |
1737 | ||
1738 | AT_PRINTF("ATAPI_CMD_UNIT_TEST_READY returned %x\n",c); | |
1739 | if (c!=0) | |
1740 | return; | |
1741 | ||
1742 | memset(ccb,0,sizeof(ccb)); | |
1743 | memset(iobuf,0,sizeof(iobuf)); | |
1744 | ccb[0]=ATAPI_CMD_READ_CAP; | |
1745 | c=atapi_issue_autoreq(device,ccb,12,(unsigned char *)iobuf,8); | |
1746 | AT_PRINTF("ATAPI_CMD_READ_CAP returned %x\n",c); | |
1747 | if (c!=0) | |
1748 | return; | |
1749 | ||
1750 | AT_PRINTF("Read Cap: LBA %02X%02X%02X%02X blksize %02X%02X%02X%02X\n", | |
1751 | iobuf[0],iobuf[1],iobuf[2],iobuf[3], | |
1752 | iobuf[4],iobuf[5],iobuf[6],iobuf[7]); | |
1753 | ||
1754 | dev_desc->lba =((unsigned long)iobuf[0]<<24) + | |
1755 | ((unsigned long)iobuf[1]<<16) + | |
1756 | ((unsigned long)iobuf[2]<< 8) + | |
1757 | ((unsigned long)iobuf[3]); | |
1758 | dev_desc->blksz=((unsigned long)iobuf[4]<<24) + | |
1759 | ((unsigned long)iobuf[5]<<16) + | |
1760 | ((unsigned long)iobuf[6]<< 8) + | |
1761 | ((unsigned long)iobuf[7]); | |
1762 | return; | |
1763 | } | |
1764 | ||
1765 | ||
1766 | /* | |
1767 | * atapi_read: | |
1768 | * we transfer only one block per command, since the multiple DRQ per | |
1769 | * command is not yet implemented | |
1770 | */ | |
1771 | #define ATAPI_READ_MAX_BYTES 2048 /* we read max 2kbytes */ | |
1772 | #define ATAPI_READ_BLOCK_SIZE 2048 /* assuming CD part */ | |
1773 | #define ATAPI_READ_MAX_BLOCK ATAPI_READ_MAX_BYTES/ATAPI_READ_BLOCK_SIZE /* max blocks */ | |
1774 | ||
1775 | ulong atapi_read (int device, ulong blknr, ulong blkcnt, ulong *buffer) | |
1776 | { | |
1777 | ulong n = 0; | |
1778 | unsigned char ccb[12]; /* Command descriptor block */ | |
1779 | ulong cnt; | |
1780 | ||
1781 | AT_PRINTF("atapi_read dev %d start %lX, blocks %lX buffer at %lX\n", | |
1782 | device, blknr, blkcnt, (ulong)buffer); | |
1783 | ||
1784 | do { | |
1785 | if (blkcnt>ATAPI_READ_MAX_BLOCK) { | |
1786 | cnt=ATAPI_READ_MAX_BLOCK; | |
1787 | } else { | |
1788 | cnt=blkcnt; | |
1789 | } | |
1790 | ccb[0]=ATAPI_CMD_READ_12; | |
1791 | ccb[1]=0; /* reserved */ | |
1792 | ccb[2]=(unsigned char) (blknr>>24) & 0xFF; /* MSB Block */ | |
1793 | ccb[3]=(unsigned char) (blknr>>16) & 0xFF; /* */ | |
1794 | ccb[4]=(unsigned char) (blknr>> 8) & 0xFF; | |
1795 | ccb[5]=(unsigned char) blknr & 0xFF; /* LSB Block */ | |
1796 | ccb[6]=(unsigned char) (cnt >>24) & 0xFF; /* MSB Block count */ | |
1797 | ccb[7]=(unsigned char) (cnt >>16) & 0xFF; | |
1798 | ccb[8]=(unsigned char) (cnt >> 8) & 0xFF; | |
1799 | ccb[9]=(unsigned char) cnt & 0xFF; /* LSB Block */ | |
1800 | ccb[10]=0; /* reserved */ | |
1801 | ccb[11]=0; /* reserved */ | |
1802 | ||
1803 | if (atapi_issue_autoreq(device,ccb,12, | |
1804 | (unsigned char *)buffer, | |
1805 | cnt*ATAPI_READ_BLOCK_SIZE) == 0xFF) { | |
1806 | return (n); | |
1807 | } | |
1808 | n+=cnt; | |
1809 | blkcnt-=cnt; | |
1810 | blknr+=cnt; | |
1811 | buffer+=cnt*(ATAPI_READ_BLOCK_SIZE/4); /* ulong blocksize in ulong */ | |
1812 | } while (blkcnt > 0); | |
1813 | return (n); | |
1814 | } | |
1815 | ||
1816 | /* ------------------------------------------------------------------------- */ | |
1817 | ||
1818 | #endif /* CONFIG_ATAPI */ | |
1819 | ||
0d498393 WD |
1820 | U_BOOT_CMD( |
1821 | ide, 5, 1, do_ide, | |
8bde7f77 WD |
1822 | "ide - IDE sub-system\n", |
1823 | "reset - reset IDE controller\n" | |
1824 | "ide info - show available IDE devices\n" | |
1825 | "ide device [dev] - show or set current device\n" | |
1826 | "ide part [dev] - print partition table of one or all IDE devices\n" | |
1827 | "ide read addr blk# cnt\n" | |
1828 | "ide write addr blk# cnt - read/write `cnt'" | |
1829 | " blocks starting at block `blk#'\n" | |
1830 | " to/from memory address `addr'\n" | |
1831 | ); | |
1832 | ||
0d498393 WD |
1833 | U_BOOT_CMD( |
1834 | diskboot, 3, 1, do_diskboot, | |
8bde7f77 WD |
1835 | "diskboot- boot from IDE device\n", |
1836 | "loadAddr dev:part\n" | |
1837 | ); | |
1838 | ||
c609719b | 1839 | #endif /* CONFIG_COMMANDS & CFG_CMD_IDE */ |