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