1*2e192b24SSimon Glass /* 2*2e192b24SSimon Glass * (C) Copyright 2000-2011 3*2e192b24SSimon Glass * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4*2e192b24SSimon Glass * 5*2e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 6*2e192b24SSimon Glass */ 7*2e192b24SSimon Glass 8*2e192b24SSimon Glass /* 9*2e192b24SSimon Glass * IDE support 10*2e192b24SSimon Glass */ 11*2e192b24SSimon Glass 12*2e192b24SSimon Glass #include <common.h> 13*2e192b24SSimon Glass #include <config.h> 14*2e192b24SSimon Glass #include <watchdog.h> 15*2e192b24SSimon Glass #include <command.h> 16*2e192b24SSimon Glass #include <image.h> 17*2e192b24SSimon Glass #include <asm/byteorder.h> 18*2e192b24SSimon Glass #include <asm/io.h> 19*2e192b24SSimon Glass 20*2e192b24SSimon Glass #if defined(CONFIG_IDE_8xx_DIRECT) || defined(CONFIG_IDE_PCMCIA) 21*2e192b24SSimon Glass # include <pcmcia.h> 22*2e192b24SSimon Glass #endif 23*2e192b24SSimon Glass 24*2e192b24SSimon Glass #include <ide.h> 25*2e192b24SSimon Glass #include <ata.h> 26*2e192b24SSimon Glass 27*2e192b24SSimon Glass #ifdef CONFIG_STATUS_LED 28*2e192b24SSimon Glass # include <status_led.h> 29*2e192b24SSimon Glass #endif 30*2e192b24SSimon Glass 31*2e192b24SSimon Glass #ifdef __PPC__ 32*2e192b24SSimon Glass # define EIEIO __asm__ volatile ("eieio") 33*2e192b24SSimon Glass # define SYNC __asm__ volatile ("sync") 34*2e192b24SSimon Glass #else 35*2e192b24SSimon Glass # define EIEIO /* nothing */ 36*2e192b24SSimon Glass # define SYNC /* nothing */ 37*2e192b24SSimon Glass #endif 38*2e192b24SSimon Glass 39*2e192b24SSimon Glass /* ------------------------------------------------------------------------- */ 40*2e192b24SSimon Glass 41*2e192b24SSimon Glass /* Current I/O Device */ 42*2e192b24SSimon Glass static int curr_device = -1; 43*2e192b24SSimon Glass 44*2e192b24SSimon Glass /* Current offset for IDE0 / IDE1 bus access */ 45*2e192b24SSimon Glass ulong ide_bus_offset[CONFIG_SYS_IDE_MAXBUS] = { 46*2e192b24SSimon Glass #if defined(CONFIG_SYS_ATA_IDE0_OFFSET) 47*2e192b24SSimon Glass CONFIG_SYS_ATA_IDE0_OFFSET, 48*2e192b24SSimon Glass #endif 49*2e192b24SSimon Glass #if defined(CONFIG_SYS_ATA_IDE1_OFFSET) && (CONFIG_SYS_IDE_MAXBUS > 1) 50*2e192b24SSimon Glass CONFIG_SYS_ATA_IDE1_OFFSET, 51*2e192b24SSimon Glass #endif 52*2e192b24SSimon Glass }; 53*2e192b24SSimon Glass 54*2e192b24SSimon Glass static int ide_bus_ok[CONFIG_SYS_IDE_MAXBUS]; 55*2e192b24SSimon Glass 56*2e192b24SSimon Glass block_dev_desc_t ide_dev_desc[CONFIG_SYS_IDE_MAXDEVICE]; 57*2e192b24SSimon Glass /* ------------------------------------------------------------------------- */ 58*2e192b24SSimon Glass 59*2e192b24SSimon Glass #ifdef CONFIG_IDE_RESET 60*2e192b24SSimon Glass static void ide_reset (void); 61*2e192b24SSimon Glass #else 62*2e192b24SSimon Glass #define ide_reset() /* dummy */ 63*2e192b24SSimon Glass #endif 64*2e192b24SSimon Glass 65*2e192b24SSimon Glass static void ide_ident (block_dev_desc_t *dev_desc); 66*2e192b24SSimon Glass static uchar ide_wait (int dev, ulong t); 67*2e192b24SSimon Glass 68*2e192b24SSimon Glass #define IDE_TIME_OUT 2000 /* 2 sec timeout */ 69*2e192b24SSimon Glass 70*2e192b24SSimon Glass #define ATAPI_TIME_OUT 7000 /* 7 sec timeout (5 sec seems to work...) */ 71*2e192b24SSimon Glass 72*2e192b24SSimon Glass #define IDE_SPIN_UP_TIME_OUT 5000 /* 5 sec spin-up timeout */ 73*2e192b24SSimon Glass 74*2e192b24SSimon Glass static void ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len); 75*2e192b24SSimon Glass 76*2e192b24SSimon Glass #ifndef CONFIG_SYS_ATA_PORT_ADDR 77*2e192b24SSimon Glass #define CONFIG_SYS_ATA_PORT_ADDR(port) (port) 78*2e192b24SSimon Glass #endif 79*2e192b24SSimon Glass 80*2e192b24SSimon Glass #ifdef CONFIG_ATAPI 81*2e192b24SSimon Glass static void atapi_inquiry(block_dev_desc_t *dev_desc); 82*2e192b24SSimon Glass static ulong atapi_read(block_dev_desc_t *block_dev, lbaint_t blknr, 83*2e192b24SSimon Glass lbaint_t blkcnt, void *buffer); 84*2e192b24SSimon Glass #endif 85*2e192b24SSimon Glass 86*2e192b24SSimon Glass 87*2e192b24SSimon Glass /* ------------------------------------------------------------------------- */ 88*2e192b24SSimon Glass 89*2e192b24SSimon Glass int do_ide(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 90*2e192b24SSimon Glass { 91*2e192b24SSimon Glass int rcode = 0; 92*2e192b24SSimon Glass 93*2e192b24SSimon Glass switch (argc) { 94*2e192b24SSimon Glass case 0: 95*2e192b24SSimon Glass case 1: 96*2e192b24SSimon Glass return CMD_RET_USAGE; 97*2e192b24SSimon Glass case 2: 98*2e192b24SSimon Glass if (strncmp(argv[1], "res", 3) == 0) { 99*2e192b24SSimon Glass puts("\nReset IDE" 100*2e192b24SSimon Glass #ifdef CONFIG_IDE_8xx_DIRECT 101*2e192b24SSimon Glass " on PCMCIA " PCMCIA_SLOT_MSG 102*2e192b24SSimon Glass #endif 103*2e192b24SSimon Glass ": "); 104*2e192b24SSimon Glass 105*2e192b24SSimon Glass ide_init(); 106*2e192b24SSimon Glass return 0; 107*2e192b24SSimon Glass } else if (strncmp(argv[1], "inf", 3) == 0) { 108*2e192b24SSimon Glass int i; 109*2e192b24SSimon Glass 110*2e192b24SSimon Glass putc('\n'); 111*2e192b24SSimon Glass 112*2e192b24SSimon Glass for (i = 0; i < CONFIG_SYS_IDE_MAXDEVICE; ++i) { 113*2e192b24SSimon Glass if (ide_dev_desc[i].type == DEV_TYPE_UNKNOWN) 114*2e192b24SSimon Glass continue; /* list only known devices */ 115*2e192b24SSimon Glass printf("IDE device %d: ", i); 116*2e192b24SSimon Glass dev_print(&ide_dev_desc[i]); 117*2e192b24SSimon Glass } 118*2e192b24SSimon Glass return 0; 119*2e192b24SSimon Glass 120*2e192b24SSimon Glass } else if (strncmp(argv[1], "dev", 3) == 0) { 121*2e192b24SSimon Glass if ((curr_device < 0) 122*2e192b24SSimon Glass || (curr_device >= CONFIG_SYS_IDE_MAXDEVICE)) { 123*2e192b24SSimon Glass puts("\nno IDE devices available\n"); 124*2e192b24SSimon Glass return 1; 125*2e192b24SSimon Glass } 126*2e192b24SSimon Glass printf("\nIDE device %d: ", curr_device); 127*2e192b24SSimon Glass dev_print(&ide_dev_desc[curr_device]); 128*2e192b24SSimon Glass return 0; 129*2e192b24SSimon Glass } else if (strncmp(argv[1], "part", 4) == 0) { 130*2e192b24SSimon Glass int dev, ok; 131*2e192b24SSimon Glass 132*2e192b24SSimon Glass for (ok = 0, dev = 0; 133*2e192b24SSimon Glass dev < CONFIG_SYS_IDE_MAXDEVICE; 134*2e192b24SSimon Glass ++dev) { 135*2e192b24SSimon Glass if (ide_dev_desc[dev].part_type != 136*2e192b24SSimon Glass PART_TYPE_UNKNOWN) { 137*2e192b24SSimon Glass ++ok; 138*2e192b24SSimon Glass if (dev) 139*2e192b24SSimon Glass putc('\n'); 140*2e192b24SSimon Glass print_part(&ide_dev_desc[dev]); 141*2e192b24SSimon Glass } 142*2e192b24SSimon Glass } 143*2e192b24SSimon Glass if (!ok) { 144*2e192b24SSimon Glass puts("\nno IDE devices available\n"); 145*2e192b24SSimon Glass rcode++; 146*2e192b24SSimon Glass } 147*2e192b24SSimon Glass return rcode; 148*2e192b24SSimon Glass } 149*2e192b24SSimon Glass return CMD_RET_USAGE; 150*2e192b24SSimon Glass case 3: 151*2e192b24SSimon Glass if (strncmp(argv[1], "dev", 3) == 0) { 152*2e192b24SSimon Glass int dev = (int) simple_strtoul(argv[2], NULL, 10); 153*2e192b24SSimon Glass 154*2e192b24SSimon Glass printf("\nIDE device %d: ", dev); 155*2e192b24SSimon Glass if (dev >= CONFIG_SYS_IDE_MAXDEVICE) { 156*2e192b24SSimon Glass puts("unknown device\n"); 157*2e192b24SSimon Glass return 1; 158*2e192b24SSimon Glass } 159*2e192b24SSimon Glass dev_print(&ide_dev_desc[dev]); 160*2e192b24SSimon Glass /*ide_print (dev); */ 161*2e192b24SSimon Glass 162*2e192b24SSimon Glass if (ide_dev_desc[dev].type == DEV_TYPE_UNKNOWN) 163*2e192b24SSimon Glass return 1; 164*2e192b24SSimon Glass 165*2e192b24SSimon Glass curr_device = dev; 166*2e192b24SSimon Glass 167*2e192b24SSimon Glass puts("... is now current device\n"); 168*2e192b24SSimon Glass 169*2e192b24SSimon Glass return 0; 170*2e192b24SSimon Glass } else if (strncmp(argv[1], "part", 4) == 0) { 171*2e192b24SSimon Glass int dev = (int) simple_strtoul(argv[2], NULL, 10); 172*2e192b24SSimon Glass 173*2e192b24SSimon Glass if (ide_dev_desc[dev].part_type != PART_TYPE_UNKNOWN) { 174*2e192b24SSimon Glass print_part(&ide_dev_desc[dev]); 175*2e192b24SSimon Glass } else { 176*2e192b24SSimon Glass printf("\nIDE device %d not available\n", 177*2e192b24SSimon Glass dev); 178*2e192b24SSimon Glass rcode = 1; 179*2e192b24SSimon Glass } 180*2e192b24SSimon Glass return rcode; 181*2e192b24SSimon Glass } 182*2e192b24SSimon Glass 183*2e192b24SSimon Glass return CMD_RET_USAGE; 184*2e192b24SSimon Glass default: 185*2e192b24SSimon Glass /* at least 4 args */ 186*2e192b24SSimon Glass 187*2e192b24SSimon Glass if (strcmp(argv[1], "read") == 0) { 188*2e192b24SSimon Glass ulong addr = simple_strtoul(argv[2], NULL, 16); 189*2e192b24SSimon Glass ulong cnt = simple_strtoul(argv[4], NULL, 16); 190*2e192b24SSimon Glass block_dev_desc_t *dev_desc; 191*2e192b24SSimon Glass ulong n; 192*2e192b24SSimon Glass 193*2e192b24SSimon Glass #ifdef CONFIG_SYS_64BIT_LBA 194*2e192b24SSimon Glass lbaint_t blk = simple_strtoull(argv[3], NULL, 16); 195*2e192b24SSimon Glass 196*2e192b24SSimon Glass printf("\nIDE read: device %d block # %lld, count %ld ... ", 197*2e192b24SSimon Glass curr_device, blk, cnt); 198*2e192b24SSimon Glass #else 199*2e192b24SSimon Glass lbaint_t blk = simple_strtoul(argv[3], NULL, 16); 200*2e192b24SSimon Glass 201*2e192b24SSimon Glass printf("\nIDE read: device %d block # %ld, count %ld ... ", 202*2e192b24SSimon Glass curr_device, blk, cnt); 203*2e192b24SSimon Glass #endif 204*2e192b24SSimon Glass 205*2e192b24SSimon Glass dev_desc = &ide_dev_desc[curr_device]; 206*2e192b24SSimon Glass n = dev_desc->block_read(dev_desc, blk, cnt, 207*2e192b24SSimon Glass (ulong *)addr); 208*2e192b24SSimon Glass /* flush cache after read */ 209*2e192b24SSimon Glass flush_cache(addr, 210*2e192b24SSimon Glass cnt * ide_dev_desc[curr_device].blksz); 211*2e192b24SSimon Glass 212*2e192b24SSimon Glass printf("%ld blocks read: %s\n", 213*2e192b24SSimon Glass n, (n == cnt) ? "OK" : "ERROR"); 214*2e192b24SSimon Glass if (n == cnt) 215*2e192b24SSimon Glass return 0; 216*2e192b24SSimon Glass else 217*2e192b24SSimon Glass return 1; 218*2e192b24SSimon Glass } else if (strcmp(argv[1], "write") == 0) { 219*2e192b24SSimon Glass ulong addr = simple_strtoul(argv[2], NULL, 16); 220*2e192b24SSimon Glass ulong cnt = simple_strtoul(argv[4], NULL, 16); 221*2e192b24SSimon Glass ulong n; 222*2e192b24SSimon Glass 223*2e192b24SSimon Glass #ifdef CONFIG_SYS_64BIT_LBA 224*2e192b24SSimon Glass lbaint_t blk = simple_strtoull(argv[3], NULL, 16); 225*2e192b24SSimon Glass 226*2e192b24SSimon Glass printf("\nIDE write: device %d block # %lld, count %ld ... ", 227*2e192b24SSimon Glass curr_device, blk, cnt); 228*2e192b24SSimon Glass #else 229*2e192b24SSimon Glass lbaint_t blk = simple_strtoul(argv[3], NULL, 16); 230*2e192b24SSimon Glass 231*2e192b24SSimon Glass printf("\nIDE write: device %d block # %ld, count %ld ... ", 232*2e192b24SSimon Glass curr_device, blk, cnt); 233*2e192b24SSimon Glass #endif 234*2e192b24SSimon Glass n = ide_write(&ide_dev_desc[curr_device], blk, cnt, 235*2e192b24SSimon Glass (ulong *)addr); 236*2e192b24SSimon Glass 237*2e192b24SSimon Glass printf("%ld blocks written: %s\n", 238*2e192b24SSimon Glass n, (n == cnt) ? "OK" : "ERROR"); 239*2e192b24SSimon Glass if (n == cnt) 240*2e192b24SSimon Glass return 0; 241*2e192b24SSimon Glass else 242*2e192b24SSimon Glass return 1; 243*2e192b24SSimon Glass } else { 244*2e192b24SSimon Glass return CMD_RET_USAGE; 245*2e192b24SSimon Glass } 246*2e192b24SSimon Glass 247*2e192b24SSimon Glass return rcode; 248*2e192b24SSimon Glass } 249*2e192b24SSimon Glass } 250*2e192b24SSimon Glass 251*2e192b24SSimon Glass int do_diskboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 252*2e192b24SSimon Glass { 253*2e192b24SSimon Glass return common_diskboot(cmdtp, "ide", argc, argv); 254*2e192b24SSimon Glass } 255*2e192b24SSimon Glass 256*2e192b24SSimon Glass /* ------------------------------------------------------------------------- */ 257*2e192b24SSimon Glass 258*2e192b24SSimon Glass __weak void ide_led(uchar led, uchar status) 259*2e192b24SSimon Glass { 260*2e192b24SSimon Glass #if defined(CONFIG_IDE_LED) && defined(PER8_BASE) /* required by LED_PORT */ 261*2e192b24SSimon Glass static uchar led_buffer; /* Buffer for current LED status */ 262*2e192b24SSimon Glass 263*2e192b24SSimon Glass uchar *led_port = LED_PORT; 264*2e192b24SSimon Glass 265*2e192b24SSimon Glass if (status) /* switch LED on */ 266*2e192b24SSimon Glass led_buffer |= led; 267*2e192b24SSimon Glass else /* switch LED off */ 268*2e192b24SSimon Glass led_buffer &= ~led; 269*2e192b24SSimon Glass 270*2e192b24SSimon Glass *led_port = led_buffer; 271*2e192b24SSimon Glass #endif 272*2e192b24SSimon Glass } 273*2e192b24SSimon Glass 274*2e192b24SSimon Glass #ifndef CONFIG_IDE_LED /* define LED macros, they are not used anyways */ 275*2e192b24SSimon Glass # define DEVICE_LED(x) 0 276*2e192b24SSimon Glass # define LED_IDE1 1 277*2e192b24SSimon Glass # define LED_IDE2 2 278*2e192b24SSimon Glass #endif 279*2e192b24SSimon Glass 280*2e192b24SSimon Glass /* ------------------------------------------------------------------------- */ 281*2e192b24SSimon Glass 282*2e192b24SSimon Glass __weak void ide_outb(int dev, int port, unsigned char val) 283*2e192b24SSimon Glass { 284*2e192b24SSimon Glass debug("ide_outb (dev= %d, port= 0x%x, val= 0x%02x) : @ 0x%08lx\n", 285*2e192b24SSimon Glass dev, port, val, 286*2e192b24SSimon Glass (ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port))); 287*2e192b24SSimon Glass 288*2e192b24SSimon Glass #if defined(CONFIG_IDE_AHB) 289*2e192b24SSimon Glass if (port) { 290*2e192b24SSimon Glass /* write command */ 291*2e192b24SSimon Glass ide_write_register(dev, port, val); 292*2e192b24SSimon Glass } else { 293*2e192b24SSimon Glass /* write data */ 294*2e192b24SSimon Glass outb(val, (ATA_CURR_BASE(dev))); 295*2e192b24SSimon Glass } 296*2e192b24SSimon Glass #else 297*2e192b24SSimon Glass outb(val, (ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port))); 298*2e192b24SSimon Glass #endif 299*2e192b24SSimon Glass } 300*2e192b24SSimon Glass 301*2e192b24SSimon Glass __weak unsigned char ide_inb(int dev, int port) 302*2e192b24SSimon Glass { 303*2e192b24SSimon Glass uchar val; 304*2e192b24SSimon Glass 305*2e192b24SSimon Glass #if defined(CONFIG_IDE_AHB) 306*2e192b24SSimon Glass val = ide_read_register(dev, port); 307*2e192b24SSimon Glass #else 308*2e192b24SSimon Glass val = inb((ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port))); 309*2e192b24SSimon Glass #endif 310*2e192b24SSimon Glass 311*2e192b24SSimon Glass debug("ide_inb (dev= %d, port= 0x%x) : @ 0x%08lx -> 0x%02x\n", 312*2e192b24SSimon Glass dev, port, 313*2e192b24SSimon Glass (ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port)), val); 314*2e192b24SSimon Glass return val; 315*2e192b24SSimon Glass } 316*2e192b24SSimon Glass 317*2e192b24SSimon Glass void ide_init(void) 318*2e192b24SSimon Glass { 319*2e192b24SSimon Glass unsigned char c; 320*2e192b24SSimon Glass int i, bus; 321*2e192b24SSimon Glass 322*2e192b24SSimon Glass #ifdef CONFIG_IDE_8xx_PCCARD 323*2e192b24SSimon Glass extern int ide_devices_found; /* Initialized in check_ide_device() */ 324*2e192b24SSimon Glass #endif /* CONFIG_IDE_8xx_PCCARD */ 325*2e192b24SSimon Glass 326*2e192b24SSimon Glass #ifdef CONFIG_IDE_PREINIT 327*2e192b24SSimon Glass WATCHDOG_RESET(); 328*2e192b24SSimon Glass 329*2e192b24SSimon Glass if (ide_preinit()) { 330*2e192b24SSimon Glass puts("ide_preinit failed\n"); 331*2e192b24SSimon Glass return; 332*2e192b24SSimon Glass } 333*2e192b24SSimon Glass #endif /* CONFIG_IDE_PREINIT */ 334*2e192b24SSimon Glass 335*2e192b24SSimon Glass WATCHDOG_RESET(); 336*2e192b24SSimon Glass 337*2e192b24SSimon Glass /* 338*2e192b24SSimon Glass * Reset the IDE just to be sure. 339*2e192b24SSimon Glass * Light LED's to show 340*2e192b24SSimon Glass */ 341*2e192b24SSimon Glass ide_led((LED_IDE1 | LED_IDE2), 1); /* LED's on */ 342*2e192b24SSimon Glass 343*2e192b24SSimon Glass /* ATAPI Drives seems to need a proper IDE Reset */ 344*2e192b24SSimon Glass ide_reset(); 345*2e192b24SSimon Glass 346*2e192b24SSimon Glass #ifdef CONFIG_IDE_INIT_POSTRESET 347*2e192b24SSimon Glass WATCHDOG_RESET(); 348*2e192b24SSimon Glass 349*2e192b24SSimon Glass if (ide_init_postreset()) { 350*2e192b24SSimon Glass puts("ide_preinit_postreset failed\n"); 351*2e192b24SSimon Glass return; 352*2e192b24SSimon Glass } 353*2e192b24SSimon Glass #endif /* CONFIG_IDE_INIT_POSTRESET */ 354*2e192b24SSimon Glass 355*2e192b24SSimon Glass /* 356*2e192b24SSimon Glass * Wait for IDE to get ready. 357*2e192b24SSimon Glass * According to spec, this can take up to 31 seconds! 358*2e192b24SSimon Glass */ 359*2e192b24SSimon Glass for (bus = 0; bus < CONFIG_SYS_IDE_MAXBUS; ++bus) { 360*2e192b24SSimon Glass int dev = 361*2e192b24SSimon Glass bus * (CONFIG_SYS_IDE_MAXDEVICE / 362*2e192b24SSimon Glass CONFIG_SYS_IDE_MAXBUS); 363*2e192b24SSimon Glass 364*2e192b24SSimon Glass #ifdef CONFIG_IDE_8xx_PCCARD 365*2e192b24SSimon Glass /* Skip non-ide devices from probing */ 366*2e192b24SSimon Glass if ((ide_devices_found & (1 << bus)) == 0) { 367*2e192b24SSimon Glass ide_led((LED_IDE1 | LED_IDE2), 0); /* LED's off */ 368*2e192b24SSimon Glass continue; 369*2e192b24SSimon Glass } 370*2e192b24SSimon Glass #endif 371*2e192b24SSimon Glass printf("Bus %d: ", bus); 372*2e192b24SSimon Glass 373*2e192b24SSimon Glass ide_bus_ok[bus] = 0; 374*2e192b24SSimon Glass 375*2e192b24SSimon Glass /* Select device 376*2e192b24SSimon Glass */ 377*2e192b24SSimon Glass udelay(100000); /* 100 ms */ 378*2e192b24SSimon Glass ide_outb(dev, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(dev)); 379*2e192b24SSimon Glass udelay(100000); /* 100 ms */ 380*2e192b24SSimon Glass i = 0; 381*2e192b24SSimon Glass do { 382*2e192b24SSimon Glass udelay(10000); /* 10 ms */ 383*2e192b24SSimon Glass 384*2e192b24SSimon Glass c = ide_inb(dev, ATA_STATUS); 385*2e192b24SSimon Glass i++; 386*2e192b24SSimon Glass if (i > (ATA_RESET_TIME * 100)) { 387*2e192b24SSimon Glass puts("** Timeout **\n"); 388*2e192b24SSimon Glass /* LED's off */ 389*2e192b24SSimon Glass ide_led((LED_IDE1 | LED_IDE2), 0); 390*2e192b24SSimon Glass return; 391*2e192b24SSimon Glass } 392*2e192b24SSimon Glass if ((i >= 100) && ((i % 100) == 0)) 393*2e192b24SSimon Glass putc('.'); 394*2e192b24SSimon Glass 395*2e192b24SSimon Glass } while (c & ATA_STAT_BUSY); 396*2e192b24SSimon Glass 397*2e192b24SSimon Glass if (c & (ATA_STAT_BUSY | ATA_STAT_FAULT)) { 398*2e192b24SSimon Glass puts("not available "); 399*2e192b24SSimon Glass debug("Status = 0x%02X ", c); 400*2e192b24SSimon Glass #ifndef CONFIG_ATAPI /* ATAPI Devices do not set DRDY */ 401*2e192b24SSimon Glass } else if ((c & ATA_STAT_READY) == 0) { 402*2e192b24SSimon Glass puts("not available "); 403*2e192b24SSimon Glass debug("Status = 0x%02X ", c); 404*2e192b24SSimon Glass #endif 405*2e192b24SSimon Glass } else { 406*2e192b24SSimon Glass puts("OK "); 407*2e192b24SSimon Glass ide_bus_ok[bus] = 1; 408*2e192b24SSimon Glass } 409*2e192b24SSimon Glass WATCHDOG_RESET(); 410*2e192b24SSimon Glass } 411*2e192b24SSimon Glass 412*2e192b24SSimon Glass putc('\n'); 413*2e192b24SSimon Glass 414*2e192b24SSimon Glass ide_led((LED_IDE1 | LED_IDE2), 0); /* LED's off */ 415*2e192b24SSimon Glass 416*2e192b24SSimon Glass curr_device = -1; 417*2e192b24SSimon Glass for (i = 0; i < CONFIG_SYS_IDE_MAXDEVICE; ++i) { 418*2e192b24SSimon Glass int led = (IDE_BUS(i) == 0) ? LED_IDE1 : LED_IDE2; 419*2e192b24SSimon Glass ide_dev_desc[i].type = DEV_TYPE_UNKNOWN; 420*2e192b24SSimon Glass ide_dev_desc[i].if_type = IF_TYPE_IDE; 421*2e192b24SSimon Glass ide_dev_desc[i].dev = i; 422*2e192b24SSimon Glass ide_dev_desc[i].part_type = PART_TYPE_UNKNOWN; 423*2e192b24SSimon Glass ide_dev_desc[i].blksz = 0; 424*2e192b24SSimon Glass ide_dev_desc[i].log2blksz = 425*2e192b24SSimon Glass LOG2_INVALID(typeof(ide_dev_desc[i].log2blksz)); 426*2e192b24SSimon Glass ide_dev_desc[i].lba = 0; 427*2e192b24SSimon Glass ide_dev_desc[i].block_read = ide_read; 428*2e192b24SSimon Glass ide_dev_desc[i].block_write = ide_write; 429*2e192b24SSimon Glass if (!ide_bus_ok[IDE_BUS(i)]) 430*2e192b24SSimon Glass continue; 431*2e192b24SSimon Glass ide_led(led, 1); /* LED on */ 432*2e192b24SSimon Glass ide_ident(&ide_dev_desc[i]); 433*2e192b24SSimon Glass ide_led(led, 0); /* LED off */ 434*2e192b24SSimon Glass dev_print(&ide_dev_desc[i]); 435*2e192b24SSimon Glass 436*2e192b24SSimon Glass if ((ide_dev_desc[i].lba > 0) && (ide_dev_desc[i].blksz > 0)) { 437*2e192b24SSimon Glass /* initialize partition type */ 438*2e192b24SSimon Glass init_part(&ide_dev_desc[i]); 439*2e192b24SSimon Glass if (curr_device < 0) 440*2e192b24SSimon Glass curr_device = i; 441*2e192b24SSimon Glass } 442*2e192b24SSimon Glass } 443*2e192b24SSimon Glass WATCHDOG_RESET(); 444*2e192b24SSimon Glass } 445*2e192b24SSimon Glass 446*2e192b24SSimon Glass /* ------------------------------------------------------------------------- */ 447*2e192b24SSimon Glass 448*2e192b24SSimon Glass #ifdef CONFIG_PARTITIONS 449*2e192b24SSimon Glass block_dev_desc_t *ide_get_dev(int dev) 450*2e192b24SSimon Glass { 451*2e192b24SSimon Glass return (dev < CONFIG_SYS_IDE_MAXDEVICE) ? &ide_dev_desc[dev] : NULL; 452*2e192b24SSimon Glass } 453*2e192b24SSimon Glass #endif 454*2e192b24SSimon Glass 455*2e192b24SSimon Glass /* ------------------------------------------------------------------------- */ 456*2e192b24SSimon Glass 457*2e192b24SSimon Glass /* We only need to swap data if we are running on a big endian cpu. */ 458*2e192b24SSimon Glass #if defined(__LITTLE_ENDIAN) 459*2e192b24SSimon Glass __weak void ide_input_swap_data(int dev, ulong *sect_buf, int words) 460*2e192b24SSimon Glass { 461*2e192b24SSimon Glass ide_input_data(dev, sect_buf, words); 462*2e192b24SSimon Glass } 463*2e192b24SSimon Glass #else 464*2e192b24SSimon Glass __weak void ide_input_swap_data(int dev, ulong *sect_buf, int words) 465*2e192b24SSimon Glass { 466*2e192b24SSimon Glass volatile ushort *pbuf = 467*2e192b24SSimon Glass (ushort *) (ATA_CURR_BASE(dev) + ATA_DATA_REG); 468*2e192b24SSimon Glass ushort *dbuf = (ushort *) sect_buf; 469*2e192b24SSimon Glass 470*2e192b24SSimon Glass debug("in input swap data base for read is %lx\n", 471*2e192b24SSimon Glass (unsigned long) pbuf); 472*2e192b24SSimon Glass 473*2e192b24SSimon Glass while (words--) { 474*2e192b24SSimon Glass #ifdef __MIPS__ 475*2e192b24SSimon Glass *dbuf++ = swab16p((u16 *) pbuf); 476*2e192b24SSimon Glass *dbuf++ = swab16p((u16 *) pbuf); 477*2e192b24SSimon Glass #else 478*2e192b24SSimon Glass *dbuf++ = ld_le16(pbuf); 479*2e192b24SSimon Glass *dbuf++ = ld_le16(pbuf); 480*2e192b24SSimon Glass #endif /* !MIPS */ 481*2e192b24SSimon Glass } 482*2e192b24SSimon Glass } 483*2e192b24SSimon Glass #endif /* __LITTLE_ENDIAN */ 484*2e192b24SSimon Glass 485*2e192b24SSimon Glass 486*2e192b24SSimon Glass #if defined(CONFIG_IDE_SWAP_IO) 487*2e192b24SSimon Glass __weak void ide_output_data(int dev, const ulong *sect_buf, int words) 488*2e192b24SSimon Glass { 489*2e192b24SSimon Glass ushort *dbuf; 490*2e192b24SSimon Glass volatile ushort *pbuf; 491*2e192b24SSimon Glass 492*2e192b24SSimon Glass pbuf = (ushort *) (ATA_CURR_BASE(dev) + ATA_DATA_REG); 493*2e192b24SSimon Glass dbuf = (ushort *) sect_buf; 494*2e192b24SSimon Glass while (words--) { 495*2e192b24SSimon Glass EIEIO; 496*2e192b24SSimon Glass *pbuf = *dbuf++; 497*2e192b24SSimon Glass EIEIO; 498*2e192b24SSimon Glass *pbuf = *dbuf++; 499*2e192b24SSimon Glass } 500*2e192b24SSimon Glass } 501*2e192b24SSimon Glass #else /* ! CONFIG_IDE_SWAP_IO */ 502*2e192b24SSimon Glass __weak void ide_output_data(int dev, const ulong *sect_buf, int words) 503*2e192b24SSimon Glass { 504*2e192b24SSimon Glass #if defined(CONFIG_IDE_AHB) 505*2e192b24SSimon Glass ide_write_data(dev, sect_buf, words); 506*2e192b24SSimon Glass #else 507*2e192b24SSimon Glass outsw(ATA_CURR_BASE(dev) + ATA_DATA_REG, sect_buf, words << 1); 508*2e192b24SSimon Glass #endif 509*2e192b24SSimon Glass } 510*2e192b24SSimon Glass #endif /* CONFIG_IDE_SWAP_IO */ 511*2e192b24SSimon Glass 512*2e192b24SSimon Glass #if defined(CONFIG_IDE_SWAP_IO) 513*2e192b24SSimon Glass __weak void ide_input_data(int dev, ulong *sect_buf, int words) 514*2e192b24SSimon Glass { 515*2e192b24SSimon Glass ushort *dbuf; 516*2e192b24SSimon Glass volatile ushort *pbuf; 517*2e192b24SSimon Glass 518*2e192b24SSimon Glass pbuf = (ushort *) (ATA_CURR_BASE(dev) + ATA_DATA_REG); 519*2e192b24SSimon Glass dbuf = (ushort *) sect_buf; 520*2e192b24SSimon Glass 521*2e192b24SSimon Glass debug("in input data base for read is %lx\n", (unsigned long) pbuf); 522*2e192b24SSimon Glass 523*2e192b24SSimon Glass while (words--) { 524*2e192b24SSimon Glass EIEIO; 525*2e192b24SSimon Glass *dbuf++ = *pbuf; 526*2e192b24SSimon Glass EIEIO; 527*2e192b24SSimon Glass *dbuf++ = *pbuf; 528*2e192b24SSimon Glass } 529*2e192b24SSimon Glass } 530*2e192b24SSimon Glass #else /* ! CONFIG_IDE_SWAP_IO */ 531*2e192b24SSimon Glass __weak void ide_input_data(int dev, ulong *sect_buf, int words) 532*2e192b24SSimon Glass { 533*2e192b24SSimon Glass #if defined(CONFIG_IDE_AHB) 534*2e192b24SSimon Glass ide_read_data(dev, sect_buf, words); 535*2e192b24SSimon Glass #else 536*2e192b24SSimon Glass insw(ATA_CURR_BASE(dev) + ATA_DATA_REG, sect_buf, words << 1); 537*2e192b24SSimon Glass #endif 538*2e192b24SSimon Glass } 539*2e192b24SSimon Glass 540*2e192b24SSimon Glass #endif /* CONFIG_IDE_SWAP_IO */ 541*2e192b24SSimon Glass 542*2e192b24SSimon Glass /* ------------------------------------------------------------------------- 543*2e192b24SSimon Glass */ 544*2e192b24SSimon Glass static void ide_ident(block_dev_desc_t *dev_desc) 545*2e192b24SSimon Glass { 546*2e192b24SSimon Glass unsigned char c; 547*2e192b24SSimon Glass hd_driveid_t iop; 548*2e192b24SSimon Glass 549*2e192b24SSimon Glass #ifdef CONFIG_ATAPI 550*2e192b24SSimon Glass int retries = 0; 551*2e192b24SSimon Glass #endif 552*2e192b24SSimon Glass int device; 553*2e192b24SSimon Glass 554*2e192b24SSimon Glass device = dev_desc->dev; 555*2e192b24SSimon Glass printf(" Device %d: ", device); 556*2e192b24SSimon Glass 557*2e192b24SSimon Glass ide_led(DEVICE_LED(device), 1); /* LED on */ 558*2e192b24SSimon Glass /* Select device 559*2e192b24SSimon Glass */ 560*2e192b24SSimon Glass ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); 561*2e192b24SSimon Glass dev_desc->if_type = IF_TYPE_IDE; 562*2e192b24SSimon Glass #ifdef CONFIG_ATAPI 563*2e192b24SSimon Glass 564*2e192b24SSimon Glass retries = 0; 565*2e192b24SSimon Glass 566*2e192b24SSimon Glass /* Warning: This will be tricky to read */ 567*2e192b24SSimon Glass while (retries <= 1) { 568*2e192b24SSimon Glass /* check signature */ 569*2e192b24SSimon Glass if ((ide_inb(device, ATA_SECT_CNT) == 0x01) && 570*2e192b24SSimon Glass (ide_inb(device, ATA_SECT_NUM) == 0x01) && 571*2e192b24SSimon Glass (ide_inb(device, ATA_CYL_LOW) == 0x14) && 572*2e192b24SSimon Glass (ide_inb(device, ATA_CYL_HIGH) == 0xEB)) { 573*2e192b24SSimon Glass /* ATAPI Signature found */ 574*2e192b24SSimon Glass dev_desc->if_type = IF_TYPE_ATAPI; 575*2e192b24SSimon Glass /* 576*2e192b24SSimon Glass * Start Ident Command 577*2e192b24SSimon Glass */ 578*2e192b24SSimon Glass ide_outb(device, ATA_COMMAND, ATAPI_CMD_IDENT); 579*2e192b24SSimon Glass /* 580*2e192b24SSimon Glass * Wait for completion - ATAPI devices need more time 581*2e192b24SSimon Glass * to become ready 582*2e192b24SSimon Glass */ 583*2e192b24SSimon Glass c = ide_wait(device, ATAPI_TIME_OUT); 584*2e192b24SSimon Glass } else 585*2e192b24SSimon Glass #endif 586*2e192b24SSimon Glass { 587*2e192b24SSimon Glass /* 588*2e192b24SSimon Glass * Start Ident Command 589*2e192b24SSimon Glass */ 590*2e192b24SSimon Glass ide_outb(device, ATA_COMMAND, ATA_CMD_IDENT); 591*2e192b24SSimon Glass 592*2e192b24SSimon Glass /* 593*2e192b24SSimon Glass * Wait for completion 594*2e192b24SSimon Glass */ 595*2e192b24SSimon Glass c = ide_wait(device, IDE_TIME_OUT); 596*2e192b24SSimon Glass } 597*2e192b24SSimon Glass ide_led(DEVICE_LED(device), 0); /* LED off */ 598*2e192b24SSimon Glass 599*2e192b24SSimon Glass if (((c & ATA_STAT_DRQ) == 0) || 600*2e192b24SSimon Glass ((c & (ATA_STAT_FAULT | ATA_STAT_ERR)) != 0)) { 601*2e192b24SSimon Glass #ifdef CONFIG_ATAPI 602*2e192b24SSimon Glass { 603*2e192b24SSimon Glass /* 604*2e192b24SSimon Glass * Need to soft reset the device 605*2e192b24SSimon Glass * in case it's an ATAPI... 606*2e192b24SSimon Glass */ 607*2e192b24SSimon Glass debug("Retrying...\n"); 608*2e192b24SSimon Glass ide_outb(device, ATA_DEV_HD, 609*2e192b24SSimon Glass ATA_LBA | ATA_DEVICE(device)); 610*2e192b24SSimon Glass udelay(100000); 611*2e192b24SSimon Glass ide_outb(device, ATA_COMMAND, 0x08); 612*2e192b24SSimon Glass udelay(500000); /* 500 ms */ 613*2e192b24SSimon Glass } 614*2e192b24SSimon Glass /* 615*2e192b24SSimon Glass * Select device 616*2e192b24SSimon Glass */ 617*2e192b24SSimon Glass ide_outb(device, ATA_DEV_HD, 618*2e192b24SSimon Glass ATA_LBA | ATA_DEVICE(device)); 619*2e192b24SSimon Glass retries++; 620*2e192b24SSimon Glass #else 621*2e192b24SSimon Glass return; 622*2e192b24SSimon Glass #endif 623*2e192b24SSimon Glass } 624*2e192b24SSimon Glass #ifdef CONFIG_ATAPI 625*2e192b24SSimon Glass else 626*2e192b24SSimon Glass break; 627*2e192b24SSimon Glass } /* see above - ugly to read */ 628*2e192b24SSimon Glass 629*2e192b24SSimon Glass if (retries == 2) /* Not found */ 630*2e192b24SSimon Glass return; 631*2e192b24SSimon Glass #endif 632*2e192b24SSimon Glass 633*2e192b24SSimon Glass ide_input_swap_data(device, (ulong *)&iop, ATA_SECTORWORDS); 634*2e192b24SSimon Glass 635*2e192b24SSimon Glass ident_cpy((unsigned char *) dev_desc->revision, iop.fw_rev, 636*2e192b24SSimon Glass sizeof(dev_desc->revision)); 637*2e192b24SSimon Glass ident_cpy((unsigned char *) dev_desc->vendor, iop.model, 638*2e192b24SSimon Glass sizeof(dev_desc->vendor)); 639*2e192b24SSimon Glass ident_cpy((unsigned char *) dev_desc->product, iop.serial_no, 640*2e192b24SSimon Glass sizeof(dev_desc->product)); 641*2e192b24SSimon Glass #ifdef __LITTLE_ENDIAN 642*2e192b24SSimon Glass /* 643*2e192b24SSimon Glass * firmware revision, model, and serial number have Big Endian Byte 644*2e192b24SSimon Glass * order in Word. Convert all three to little endian. 645*2e192b24SSimon Glass * 646*2e192b24SSimon Glass * See CF+ and CompactFlash Specification Revision 2.0: 647*2e192b24SSimon Glass * 6.2.1.6: Identify Drive, Table 39 for more details 648*2e192b24SSimon Glass */ 649*2e192b24SSimon Glass 650*2e192b24SSimon Glass strswab(dev_desc->revision); 651*2e192b24SSimon Glass strswab(dev_desc->vendor); 652*2e192b24SSimon Glass strswab(dev_desc->product); 653*2e192b24SSimon Glass #endif /* __LITTLE_ENDIAN */ 654*2e192b24SSimon Glass 655*2e192b24SSimon Glass if ((iop.config & 0x0080) == 0x0080) 656*2e192b24SSimon Glass dev_desc->removable = 1; 657*2e192b24SSimon Glass else 658*2e192b24SSimon Glass dev_desc->removable = 0; 659*2e192b24SSimon Glass 660*2e192b24SSimon Glass #ifdef CONFIG_ATAPI 661*2e192b24SSimon Glass if (dev_desc->if_type == IF_TYPE_ATAPI) { 662*2e192b24SSimon Glass atapi_inquiry(dev_desc); 663*2e192b24SSimon Glass return; 664*2e192b24SSimon Glass } 665*2e192b24SSimon Glass #endif /* CONFIG_ATAPI */ 666*2e192b24SSimon Glass 667*2e192b24SSimon Glass #ifdef __BIG_ENDIAN 668*2e192b24SSimon Glass /* swap shorts */ 669*2e192b24SSimon Glass dev_desc->lba = (iop.lba_capacity << 16) | (iop.lba_capacity >> 16); 670*2e192b24SSimon Glass #else /* ! __BIG_ENDIAN */ 671*2e192b24SSimon Glass /* 672*2e192b24SSimon Glass * do not swap shorts on little endian 673*2e192b24SSimon Glass * 674*2e192b24SSimon Glass * See CF+ and CompactFlash Specification Revision 2.0: 675*2e192b24SSimon Glass * 6.2.1.6: Identfy Drive, Table 39, Word Address 57-58 for details. 676*2e192b24SSimon Glass */ 677*2e192b24SSimon Glass dev_desc->lba = iop.lba_capacity; 678*2e192b24SSimon Glass #endif /* __BIG_ENDIAN */ 679*2e192b24SSimon Glass 680*2e192b24SSimon Glass #ifdef CONFIG_LBA48 681*2e192b24SSimon Glass if (iop.command_set_2 & 0x0400) { /* LBA 48 support */ 682*2e192b24SSimon Glass dev_desc->lba48 = 1; 683*2e192b24SSimon Glass dev_desc->lba = (unsigned long long) iop.lba48_capacity[0] | 684*2e192b24SSimon Glass ((unsigned long long) iop.lba48_capacity[1] << 16) | 685*2e192b24SSimon Glass ((unsigned long long) iop.lba48_capacity[2] << 32) | 686*2e192b24SSimon Glass ((unsigned long long) iop.lba48_capacity[3] << 48); 687*2e192b24SSimon Glass } else { 688*2e192b24SSimon Glass dev_desc->lba48 = 0; 689*2e192b24SSimon Glass } 690*2e192b24SSimon Glass #endif /* CONFIG_LBA48 */ 691*2e192b24SSimon Glass /* assuming HD */ 692*2e192b24SSimon Glass dev_desc->type = DEV_TYPE_HARDDISK; 693*2e192b24SSimon Glass dev_desc->blksz = ATA_BLOCKSIZE; 694*2e192b24SSimon Glass dev_desc->log2blksz = LOG2(dev_desc->blksz); 695*2e192b24SSimon Glass dev_desc->lun = 0; /* just to fill something in... */ 696*2e192b24SSimon Glass 697*2e192b24SSimon Glass #if 0 /* only used to test the powersaving mode, 698*2e192b24SSimon Glass * if enabled, the drive goes after 5 sec 699*2e192b24SSimon Glass * in standby mode */ 700*2e192b24SSimon Glass ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); 701*2e192b24SSimon Glass c = ide_wait(device, IDE_TIME_OUT); 702*2e192b24SSimon Glass ide_outb(device, ATA_SECT_CNT, 1); 703*2e192b24SSimon Glass ide_outb(device, ATA_LBA_LOW, 0); 704*2e192b24SSimon Glass ide_outb(device, ATA_LBA_MID, 0); 705*2e192b24SSimon Glass ide_outb(device, ATA_LBA_HIGH, 0); 706*2e192b24SSimon Glass ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); 707*2e192b24SSimon Glass ide_outb(device, ATA_COMMAND, 0xe3); 708*2e192b24SSimon Glass udelay(50); 709*2e192b24SSimon Glass c = ide_wait(device, IDE_TIME_OUT); /* can't take over 500 ms */ 710*2e192b24SSimon Glass #endif 711*2e192b24SSimon Glass } 712*2e192b24SSimon Glass 713*2e192b24SSimon Glass 714*2e192b24SSimon Glass /* ------------------------------------------------------------------------- */ 715*2e192b24SSimon Glass 716*2e192b24SSimon Glass ulong ide_read(block_dev_desc_t *block_dev, lbaint_t blknr, lbaint_t blkcnt, 717*2e192b24SSimon Glass void *buffer) 718*2e192b24SSimon Glass { 719*2e192b24SSimon Glass int device = block_dev->dev; 720*2e192b24SSimon Glass ulong n = 0; 721*2e192b24SSimon Glass unsigned char c; 722*2e192b24SSimon Glass unsigned char pwrsave = 0; /* power save */ 723*2e192b24SSimon Glass 724*2e192b24SSimon Glass #ifdef CONFIG_LBA48 725*2e192b24SSimon Glass unsigned char lba48 = 0; 726*2e192b24SSimon Glass 727*2e192b24SSimon Glass if (blknr & 0x0000fffff0000000ULL) { 728*2e192b24SSimon Glass /* more than 28 bits used, use 48bit mode */ 729*2e192b24SSimon Glass lba48 = 1; 730*2e192b24SSimon Glass } 731*2e192b24SSimon Glass #endif 732*2e192b24SSimon Glass debug("ide_read dev %d start " LBAF ", blocks " LBAF " buffer at %lX\n", 733*2e192b24SSimon Glass device, blknr, blkcnt, (ulong) buffer); 734*2e192b24SSimon Glass 735*2e192b24SSimon Glass ide_led(DEVICE_LED(device), 1); /* LED on */ 736*2e192b24SSimon Glass 737*2e192b24SSimon Glass /* Select device 738*2e192b24SSimon Glass */ 739*2e192b24SSimon Glass ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); 740*2e192b24SSimon Glass c = ide_wait(device, IDE_TIME_OUT); 741*2e192b24SSimon Glass 742*2e192b24SSimon Glass if (c & ATA_STAT_BUSY) { 743*2e192b24SSimon Glass printf("IDE read: device %d not ready\n", device); 744*2e192b24SSimon Glass goto IDE_READ_E; 745*2e192b24SSimon Glass } 746*2e192b24SSimon Glass 747*2e192b24SSimon Glass /* first check if the drive is in Powersaving mode, if yes, 748*2e192b24SSimon Glass * increase the timeout value */ 749*2e192b24SSimon Glass ide_outb(device, ATA_COMMAND, ATA_CMD_CHK_PWR); 750*2e192b24SSimon Glass udelay(50); 751*2e192b24SSimon Glass 752*2e192b24SSimon Glass c = ide_wait(device, IDE_TIME_OUT); /* can't take over 500 ms */ 753*2e192b24SSimon Glass 754*2e192b24SSimon Glass if (c & ATA_STAT_BUSY) { 755*2e192b24SSimon Glass printf("IDE read: device %d not ready\n", device); 756*2e192b24SSimon Glass goto IDE_READ_E; 757*2e192b24SSimon Glass } 758*2e192b24SSimon Glass if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) { 759*2e192b24SSimon Glass printf("No Powersaving mode %X\n", c); 760*2e192b24SSimon Glass } else { 761*2e192b24SSimon Glass c = ide_inb(device, ATA_SECT_CNT); 762*2e192b24SSimon Glass debug("Powersaving %02X\n", c); 763*2e192b24SSimon Glass if (c == 0) 764*2e192b24SSimon Glass pwrsave = 1; 765*2e192b24SSimon Glass } 766*2e192b24SSimon Glass 767*2e192b24SSimon Glass 768*2e192b24SSimon Glass while (blkcnt-- > 0) { 769*2e192b24SSimon Glass 770*2e192b24SSimon Glass c = ide_wait(device, IDE_TIME_OUT); 771*2e192b24SSimon Glass 772*2e192b24SSimon Glass if (c & ATA_STAT_BUSY) { 773*2e192b24SSimon Glass printf("IDE read: device %d not ready\n", device); 774*2e192b24SSimon Glass break; 775*2e192b24SSimon Glass } 776*2e192b24SSimon Glass #ifdef CONFIG_LBA48 777*2e192b24SSimon Glass if (lba48) { 778*2e192b24SSimon Glass /* write high bits */ 779*2e192b24SSimon Glass ide_outb(device, ATA_SECT_CNT, 0); 780*2e192b24SSimon Glass ide_outb(device, ATA_LBA_LOW, (blknr >> 24) & 0xFF); 781*2e192b24SSimon Glass #ifdef CONFIG_SYS_64BIT_LBA 782*2e192b24SSimon Glass ide_outb(device, ATA_LBA_MID, (blknr >> 32) & 0xFF); 783*2e192b24SSimon Glass ide_outb(device, ATA_LBA_HIGH, (blknr >> 40) & 0xFF); 784*2e192b24SSimon Glass #else 785*2e192b24SSimon Glass ide_outb(device, ATA_LBA_MID, 0); 786*2e192b24SSimon Glass ide_outb(device, ATA_LBA_HIGH, 0); 787*2e192b24SSimon Glass #endif 788*2e192b24SSimon Glass } 789*2e192b24SSimon Glass #endif 790*2e192b24SSimon Glass ide_outb(device, ATA_SECT_CNT, 1); 791*2e192b24SSimon Glass ide_outb(device, ATA_LBA_LOW, (blknr >> 0) & 0xFF); 792*2e192b24SSimon Glass ide_outb(device, ATA_LBA_MID, (blknr >> 8) & 0xFF); 793*2e192b24SSimon Glass ide_outb(device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF); 794*2e192b24SSimon Glass 795*2e192b24SSimon Glass #ifdef CONFIG_LBA48 796*2e192b24SSimon Glass if (lba48) { 797*2e192b24SSimon Glass ide_outb(device, ATA_DEV_HD, 798*2e192b24SSimon Glass ATA_LBA | ATA_DEVICE(device)); 799*2e192b24SSimon Glass ide_outb(device, ATA_COMMAND, ATA_CMD_READ_EXT); 800*2e192b24SSimon Glass 801*2e192b24SSimon Glass } else 802*2e192b24SSimon Glass #endif 803*2e192b24SSimon Glass { 804*2e192b24SSimon Glass ide_outb(device, ATA_DEV_HD, ATA_LBA | 805*2e192b24SSimon Glass ATA_DEVICE(device) | ((blknr >> 24) & 0xF)); 806*2e192b24SSimon Glass ide_outb(device, ATA_COMMAND, ATA_CMD_READ); 807*2e192b24SSimon Glass } 808*2e192b24SSimon Glass 809*2e192b24SSimon Glass udelay(50); 810*2e192b24SSimon Glass 811*2e192b24SSimon Glass if (pwrsave) { 812*2e192b24SSimon Glass /* may take up to 4 sec */ 813*2e192b24SSimon Glass c = ide_wait(device, IDE_SPIN_UP_TIME_OUT); 814*2e192b24SSimon Glass pwrsave = 0; 815*2e192b24SSimon Glass } else { 816*2e192b24SSimon Glass /* can't take over 500 ms */ 817*2e192b24SSimon Glass c = ide_wait(device, IDE_TIME_OUT); 818*2e192b24SSimon Glass } 819*2e192b24SSimon Glass 820*2e192b24SSimon Glass if ((c & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) != 821*2e192b24SSimon Glass ATA_STAT_DRQ) { 822*2e192b24SSimon Glass printf("Error (no IRQ) dev %d blk " LBAF ": status " 823*2e192b24SSimon Glass "%#02x\n", device, blknr, c); 824*2e192b24SSimon Glass break; 825*2e192b24SSimon Glass } 826*2e192b24SSimon Glass 827*2e192b24SSimon Glass ide_input_data(device, buffer, ATA_SECTORWORDS); 828*2e192b24SSimon Glass (void) ide_inb(device, ATA_STATUS); /* clear IRQ */ 829*2e192b24SSimon Glass 830*2e192b24SSimon Glass ++n; 831*2e192b24SSimon Glass ++blknr; 832*2e192b24SSimon Glass buffer += ATA_BLOCKSIZE; 833*2e192b24SSimon Glass } 834*2e192b24SSimon Glass IDE_READ_E: 835*2e192b24SSimon Glass ide_led(DEVICE_LED(device), 0); /* LED off */ 836*2e192b24SSimon Glass return (n); 837*2e192b24SSimon Glass } 838*2e192b24SSimon Glass 839*2e192b24SSimon Glass /* ------------------------------------------------------------------------- */ 840*2e192b24SSimon Glass 841*2e192b24SSimon Glass 842*2e192b24SSimon Glass ulong ide_write(block_dev_desc_t *block_dev, lbaint_t blknr, lbaint_t blkcnt, 843*2e192b24SSimon Glass const void *buffer) 844*2e192b24SSimon Glass { 845*2e192b24SSimon Glass int device = block_dev->dev; 846*2e192b24SSimon Glass ulong n = 0; 847*2e192b24SSimon Glass unsigned char c; 848*2e192b24SSimon Glass 849*2e192b24SSimon Glass #ifdef CONFIG_LBA48 850*2e192b24SSimon Glass unsigned char lba48 = 0; 851*2e192b24SSimon Glass 852*2e192b24SSimon Glass if (blknr & 0x0000fffff0000000ULL) { 853*2e192b24SSimon Glass /* more than 28 bits used, use 48bit mode */ 854*2e192b24SSimon Glass lba48 = 1; 855*2e192b24SSimon Glass } 856*2e192b24SSimon Glass #endif 857*2e192b24SSimon Glass 858*2e192b24SSimon Glass ide_led(DEVICE_LED(device), 1); /* LED on */ 859*2e192b24SSimon Glass 860*2e192b24SSimon Glass /* Select device 861*2e192b24SSimon Glass */ 862*2e192b24SSimon Glass ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); 863*2e192b24SSimon Glass 864*2e192b24SSimon Glass while (blkcnt-- > 0) { 865*2e192b24SSimon Glass 866*2e192b24SSimon Glass c = ide_wait(device, IDE_TIME_OUT); 867*2e192b24SSimon Glass 868*2e192b24SSimon Glass if (c & ATA_STAT_BUSY) { 869*2e192b24SSimon Glass printf("IDE read: device %d not ready\n", device); 870*2e192b24SSimon Glass goto WR_OUT; 871*2e192b24SSimon Glass } 872*2e192b24SSimon Glass #ifdef CONFIG_LBA48 873*2e192b24SSimon Glass if (lba48) { 874*2e192b24SSimon Glass /* write high bits */ 875*2e192b24SSimon Glass ide_outb(device, ATA_SECT_CNT, 0); 876*2e192b24SSimon Glass ide_outb(device, ATA_LBA_LOW, (blknr >> 24) & 0xFF); 877*2e192b24SSimon Glass #ifdef CONFIG_SYS_64BIT_LBA 878*2e192b24SSimon Glass ide_outb(device, ATA_LBA_MID, (blknr >> 32) & 0xFF); 879*2e192b24SSimon Glass ide_outb(device, ATA_LBA_HIGH, (blknr >> 40) & 0xFF); 880*2e192b24SSimon Glass #else 881*2e192b24SSimon Glass ide_outb(device, ATA_LBA_MID, 0); 882*2e192b24SSimon Glass ide_outb(device, ATA_LBA_HIGH, 0); 883*2e192b24SSimon Glass #endif 884*2e192b24SSimon Glass } 885*2e192b24SSimon Glass #endif 886*2e192b24SSimon Glass ide_outb(device, ATA_SECT_CNT, 1); 887*2e192b24SSimon Glass ide_outb(device, ATA_LBA_LOW, (blknr >> 0) & 0xFF); 888*2e192b24SSimon Glass ide_outb(device, ATA_LBA_MID, (blknr >> 8) & 0xFF); 889*2e192b24SSimon Glass ide_outb(device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF); 890*2e192b24SSimon Glass 891*2e192b24SSimon Glass #ifdef CONFIG_LBA48 892*2e192b24SSimon Glass if (lba48) { 893*2e192b24SSimon Glass ide_outb(device, ATA_DEV_HD, 894*2e192b24SSimon Glass ATA_LBA | ATA_DEVICE(device)); 895*2e192b24SSimon Glass ide_outb(device, ATA_COMMAND, ATA_CMD_WRITE_EXT); 896*2e192b24SSimon Glass 897*2e192b24SSimon Glass } else 898*2e192b24SSimon Glass #endif 899*2e192b24SSimon Glass { 900*2e192b24SSimon Glass ide_outb(device, ATA_DEV_HD, ATA_LBA | 901*2e192b24SSimon Glass ATA_DEVICE(device) | ((blknr >> 24) & 0xF)); 902*2e192b24SSimon Glass ide_outb(device, ATA_COMMAND, ATA_CMD_WRITE); 903*2e192b24SSimon Glass } 904*2e192b24SSimon Glass 905*2e192b24SSimon Glass udelay(50); 906*2e192b24SSimon Glass 907*2e192b24SSimon Glass /* can't take over 500 ms */ 908*2e192b24SSimon Glass c = ide_wait(device, IDE_TIME_OUT); 909*2e192b24SSimon Glass 910*2e192b24SSimon Glass if ((c & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) != 911*2e192b24SSimon Glass ATA_STAT_DRQ) { 912*2e192b24SSimon Glass printf("Error (no IRQ) dev %d blk " LBAF ": status " 913*2e192b24SSimon Glass "%#02x\n", device, blknr, c); 914*2e192b24SSimon Glass goto WR_OUT; 915*2e192b24SSimon Glass } 916*2e192b24SSimon Glass 917*2e192b24SSimon Glass ide_output_data(device, buffer, ATA_SECTORWORDS); 918*2e192b24SSimon Glass c = ide_inb(device, ATA_STATUS); /* clear IRQ */ 919*2e192b24SSimon Glass ++n; 920*2e192b24SSimon Glass ++blknr; 921*2e192b24SSimon Glass buffer += ATA_BLOCKSIZE; 922*2e192b24SSimon Glass } 923*2e192b24SSimon Glass WR_OUT: 924*2e192b24SSimon Glass ide_led(DEVICE_LED(device), 0); /* LED off */ 925*2e192b24SSimon Glass return (n); 926*2e192b24SSimon Glass } 927*2e192b24SSimon Glass 928*2e192b24SSimon Glass /* ------------------------------------------------------------------------- */ 929*2e192b24SSimon Glass 930*2e192b24SSimon Glass /* 931*2e192b24SSimon Glass * copy src to dest, skipping leading and trailing blanks and null 932*2e192b24SSimon Glass * terminate the string 933*2e192b24SSimon Glass * "len" is the size of available memory including the terminating '\0' 934*2e192b24SSimon Glass */ 935*2e192b24SSimon Glass static void ident_cpy(unsigned char *dst, unsigned char *src, 936*2e192b24SSimon Glass unsigned int len) 937*2e192b24SSimon Glass { 938*2e192b24SSimon Glass unsigned char *end, *last; 939*2e192b24SSimon Glass 940*2e192b24SSimon Glass last = dst; 941*2e192b24SSimon Glass end = src + len - 1; 942*2e192b24SSimon Glass 943*2e192b24SSimon Glass /* reserve space for '\0' */ 944*2e192b24SSimon Glass if (len < 2) 945*2e192b24SSimon Glass goto OUT; 946*2e192b24SSimon Glass 947*2e192b24SSimon Glass /* skip leading white space */ 948*2e192b24SSimon Glass while ((*src) && (src < end) && (*src == ' ')) 949*2e192b24SSimon Glass ++src; 950*2e192b24SSimon Glass 951*2e192b24SSimon Glass /* copy string, omitting trailing white space */ 952*2e192b24SSimon Glass while ((*src) && (src < end)) { 953*2e192b24SSimon Glass *dst++ = *src; 954*2e192b24SSimon Glass if (*src++ != ' ') 955*2e192b24SSimon Glass last = dst; 956*2e192b24SSimon Glass } 957*2e192b24SSimon Glass OUT: 958*2e192b24SSimon Glass *last = '\0'; 959*2e192b24SSimon Glass } 960*2e192b24SSimon Glass 961*2e192b24SSimon Glass /* ------------------------------------------------------------------------- */ 962*2e192b24SSimon Glass 963*2e192b24SSimon Glass /* 964*2e192b24SSimon Glass * Wait until Busy bit is off, or timeout (in ms) 965*2e192b24SSimon Glass * Return last status 966*2e192b24SSimon Glass */ 967*2e192b24SSimon Glass static uchar ide_wait(int dev, ulong t) 968*2e192b24SSimon Glass { 969*2e192b24SSimon Glass ulong delay = 10 * t; /* poll every 100 us */ 970*2e192b24SSimon Glass uchar c; 971*2e192b24SSimon Glass 972*2e192b24SSimon Glass while ((c = ide_inb(dev, ATA_STATUS)) & ATA_STAT_BUSY) { 973*2e192b24SSimon Glass udelay(100); 974*2e192b24SSimon Glass if (delay-- == 0) 975*2e192b24SSimon Glass break; 976*2e192b24SSimon Glass } 977*2e192b24SSimon Glass return (c); 978*2e192b24SSimon Glass } 979*2e192b24SSimon Glass 980*2e192b24SSimon Glass /* ------------------------------------------------------------------------- */ 981*2e192b24SSimon Glass 982*2e192b24SSimon Glass #ifdef CONFIG_IDE_RESET 983*2e192b24SSimon Glass extern void ide_set_reset(int idereset); 984*2e192b24SSimon Glass 985*2e192b24SSimon Glass static void ide_reset(void) 986*2e192b24SSimon Glass { 987*2e192b24SSimon Glass int i; 988*2e192b24SSimon Glass 989*2e192b24SSimon Glass curr_device = -1; 990*2e192b24SSimon Glass for (i = 0; i < CONFIG_SYS_IDE_MAXBUS; ++i) 991*2e192b24SSimon Glass ide_bus_ok[i] = 0; 992*2e192b24SSimon Glass for (i = 0; i < CONFIG_SYS_IDE_MAXDEVICE; ++i) 993*2e192b24SSimon Glass ide_dev_desc[i].type = DEV_TYPE_UNKNOWN; 994*2e192b24SSimon Glass 995*2e192b24SSimon Glass ide_set_reset(1); /* assert reset */ 996*2e192b24SSimon Glass 997*2e192b24SSimon Glass /* the reset signal shall be asserted for et least 25 us */ 998*2e192b24SSimon Glass udelay(25); 999*2e192b24SSimon Glass 1000*2e192b24SSimon Glass WATCHDOG_RESET(); 1001*2e192b24SSimon Glass 1002*2e192b24SSimon Glass /* de-assert RESET signal */ 1003*2e192b24SSimon Glass ide_set_reset(0); 1004*2e192b24SSimon Glass 1005*2e192b24SSimon Glass /* wait 250 ms */ 1006*2e192b24SSimon Glass for (i = 0; i < 250; ++i) 1007*2e192b24SSimon Glass udelay(1000); 1008*2e192b24SSimon Glass } 1009*2e192b24SSimon Glass 1010*2e192b24SSimon Glass #endif /* CONFIG_IDE_RESET */ 1011*2e192b24SSimon Glass 1012*2e192b24SSimon Glass /* ------------------------------------------------------------------------- */ 1013*2e192b24SSimon Glass 1014*2e192b24SSimon Glass #if defined(CONFIG_OF_IDE_FIXUP) 1015*2e192b24SSimon Glass int ide_device_present(int dev) 1016*2e192b24SSimon Glass { 1017*2e192b24SSimon Glass if (dev >= CONFIG_SYS_IDE_MAXBUS) 1018*2e192b24SSimon Glass return 0; 1019*2e192b24SSimon Glass return (ide_dev_desc[dev].type == DEV_TYPE_UNKNOWN ? 0 : 1); 1020*2e192b24SSimon Glass } 1021*2e192b24SSimon Glass #endif 1022*2e192b24SSimon Glass /* ------------------------------------------------------------------------- */ 1023*2e192b24SSimon Glass 1024*2e192b24SSimon Glass #ifdef CONFIG_ATAPI 1025*2e192b24SSimon Glass /**************************************************************************** 1026*2e192b24SSimon Glass * ATAPI Support 1027*2e192b24SSimon Glass */ 1028*2e192b24SSimon Glass 1029*2e192b24SSimon Glass #if defined(CONFIG_IDE_SWAP_IO) 1030*2e192b24SSimon Glass /* since ATAPI may use commands with not 4 bytes alligned length 1031*2e192b24SSimon Glass * we have our own transfer functions, 2 bytes alligned */ 1032*2e192b24SSimon Glass __weak void ide_output_data_shorts(int dev, ushort *sect_buf, int shorts) 1033*2e192b24SSimon Glass { 1034*2e192b24SSimon Glass ushort *dbuf; 1035*2e192b24SSimon Glass volatile ushort *pbuf; 1036*2e192b24SSimon Glass 1037*2e192b24SSimon Glass pbuf = (ushort *) (ATA_CURR_BASE(dev) + ATA_DATA_REG); 1038*2e192b24SSimon Glass dbuf = (ushort *) sect_buf; 1039*2e192b24SSimon Glass 1040*2e192b24SSimon Glass debug("in output data shorts base for read is %lx\n", 1041*2e192b24SSimon Glass (unsigned long) pbuf); 1042*2e192b24SSimon Glass 1043*2e192b24SSimon Glass while (shorts--) { 1044*2e192b24SSimon Glass EIEIO; 1045*2e192b24SSimon Glass *pbuf = *dbuf++; 1046*2e192b24SSimon Glass } 1047*2e192b24SSimon Glass } 1048*2e192b24SSimon Glass 1049*2e192b24SSimon Glass __weak void ide_input_data_shorts(int dev, ushort *sect_buf, int shorts) 1050*2e192b24SSimon Glass { 1051*2e192b24SSimon Glass ushort *dbuf; 1052*2e192b24SSimon Glass volatile ushort *pbuf; 1053*2e192b24SSimon Glass 1054*2e192b24SSimon Glass pbuf = (ushort *) (ATA_CURR_BASE(dev) + ATA_DATA_REG); 1055*2e192b24SSimon Glass dbuf = (ushort *) sect_buf; 1056*2e192b24SSimon Glass 1057*2e192b24SSimon Glass debug("in input data shorts base for read is %lx\n", 1058*2e192b24SSimon Glass (unsigned long) pbuf); 1059*2e192b24SSimon Glass 1060*2e192b24SSimon Glass while (shorts--) { 1061*2e192b24SSimon Glass EIEIO; 1062*2e192b24SSimon Glass *dbuf++ = *pbuf; 1063*2e192b24SSimon Glass } 1064*2e192b24SSimon Glass } 1065*2e192b24SSimon Glass 1066*2e192b24SSimon Glass #else /* ! CONFIG_IDE_SWAP_IO */ 1067*2e192b24SSimon Glass __weak void ide_output_data_shorts(int dev, ushort *sect_buf, int shorts) 1068*2e192b24SSimon Glass { 1069*2e192b24SSimon Glass outsw(ATA_CURR_BASE(dev) + ATA_DATA_REG, sect_buf, shorts); 1070*2e192b24SSimon Glass } 1071*2e192b24SSimon Glass 1072*2e192b24SSimon Glass __weak void ide_input_data_shorts(int dev, ushort *sect_buf, int shorts) 1073*2e192b24SSimon Glass { 1074*2e192b24SSimon Glass insw(ATA_CURR_BASE(dev) + ATA_DATA_REG, sect_buf, shorts); 1075*2e192b24SSimon Glass } 1076*2e192b24SSimon Glass 1077*2e192b24SSimon Glass #endif /* CONFIG_IDE_SWAP_IO */ 1078*2e192b24SSimon Glass 1079*2e192b24SSimon Glass /* 1080*2e192b24SSimon Glass * Wait until (Status & mask) == res, or timeout (in ms) 1081*2e192b24SSimon Glass * Return last status 1082*2e192b24SSimon Glass * This is used since some ATAPI CD ROMs clears their Busy Bit first 1083*2e192b24SSimon Glass * and then they set their DRQ Bit 1084*2e192b24SSimon Glass */ 1085*2e192b24SSimon Glass static uchar atapi_wait_mask(int dev, ulong t, uchar mask, uchar res) 1086*2e192b24SSimon Glass { 1087*2e192b24SSimon Glass ulong delay = 10 * t; /* poll every 100 us */ 1088*2e192b24SSimon Glass uchar c; 1089*2e192b24SSimon Glass 1090*2e192b24SSimon Glass /* prevents to read the status before valid */ 1091*2e192b24SSimon Glass c = ide_inb(dev, ATA_DEV_CTL); 1092*2e192b24SSimon Glass 1093*2e192b24SSimon Glass while (((c = ide_inb(dev, ATA_STATUS)) & mask) != res) { 1094*2e192b24SSimon Glass /* break if error occurs (doesn't make sense to wait more) */ 1095*2e192b24SSimon Glass if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) 1096*2e192b24SSimon Glass break; 1097*2e192b24SSimon Glass udelay(100); 1098*2e192b24SSimon Glass if (delay-- == 0) 1099*2e192b24SSimon Glass break; 1100*2e192b24SSimon Glass } 1101*2e192b24SSimon Glass return (c); 1102*2e192b24SSimon Glass } 1103*2e192b24SSimon Glass 1104*2e192b24SSimon Glass /* 1105*2e192b24SSimon Glass * issue an atapi command 1106*2e192b24SSimon Glass */ 1107*2e192b24SSimon Glass unsigned char atapi_issue(int device, unsigned char *ccb, int ccblen, 1108*2e192b24SSimon Glass unsigned char *buffer, int buflen) 1109*2e192b24SSimon Glass { 1110*2e192b24SSimon Glass unsigned char c, err, mask, res; 1111*2e192b24SSimon Glass int n; 1112*2e192b24SSimon Glass 1113*2e192b24SSimon Glass ide_led(DEVICE_LED(device), 1); /* LED on */ 1114*2e192b24SSimon Glass 1115*2e192b24SSimon Glass /* Select device 1116*2e192b24SSimon Glass */ 1117*2e192b24SSimon Glass mask = ATA_STAT_BUSY | ATA_STAT_DRQ; 1118*2e192b24SSimon Glass res = 0; 1119*2e192b24SSimon Glass ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); 1120*2e192b24SSimon Glass c = atapi_wait_mask(device, ATAPI_TIME_OUT, mask, res); 1121*2e192b24SSimon Glass if ((c & mask) != res) { 1122*2e192b24SSimon Glass printf("ATAPI_ISSUE: device %d not ready status %X\n", device, 1123*2e192b24SSimon Glass c); 1124*2e192b24SSimon Glass err = 0xFF; 1125*2e192b24SSimon Glass goto AI_OUT; 1126*2e192b24SSimon Glass } 1127*2e192b24SSimon Glass /* write taskfile */ 1128*2e192b24SSimon Glass ide_outb(device, ATA_ERROR_REG, 0); /* no DMA, no overlaped */ 1129*2e192b24SSimon Glass ide_outb(device, ATA_SECT_CNT, 0); 1130*2e192b24SSimon Glass ide_outb(device, ATA_SECT_NUM, 0); 1131*2e192b24SSimon Glass ide_outb(device, ATA_CYL_LOW, (unsigned char) (buflen & 0xFF)); 1132*2e192b24SSimon Glass ide_outb(device, ATA_CYL_HIGH, 1133*2e192b24SSimon Glass (unsigned char) ((buflen >> 8) & 0xFF)); 1134*2e192b24SSimon Glass ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device)); 1135*2e192b24SSimon Glass 1136*2e192b24SSimon Glass ide_outb(device, ATA_COMMAND, ATAPI_CMD_PACKET); 1137*2e192b24SSimon Glass udelay(50); 1138*2e192b24SSimon Glass 1139*2e192b24SSimon Glass mask = ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR; 1140*2e192b24SSimon Glass res = ATA_STAT_DRQ; 1141*2e192b24SSimon Glass c = atapi_wait_mask(device, ATAPI_TIME_OUT, mask, res); 1142*2e192b24SSimon Glass 1143*2e192b24SSimon Glass if ((c & mask) != res) { /* DRQ must be 1, BSY 0 */ 1144*2e192b24SSimon Glass printf("ATAPI_ISSUE: Error (no IRQ) before sending ccb dev %d status 0x%02x\n", 1145*2e192b24SSimon Glass device, c); 1146*2e192b24SSimon Glass err = 0xFF; 1147*2e192b24SSimon Glass goto AI_OUT; 1148*2e192b24SSimon Glass } 1149*2e192b24SSimon Glass 1150*2e192b24SSimon Glass /* write command block */ 1151*2e192b24SSimon Glass ide_output_data_shorts(device, (unsigned short *) ccb, ccblen / 2); 1152*2e192b24SSimon Glass 1153*2e192b24SSimon Glass /* ATAPI Command written wait for completition */ 1154*2e192b24SSimon Glass udelay(5000); /* device must set bsy */ 1155*2e192b24SSimon Glass 1156*2e192b24SSimon Glass mask = ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR; 1157*2e192b24SSimon Glass /* 1158*2e192b24SSimon Glass * if no data wait for DRQ = 0 BSY = 0 1159*2e192b24SSimon Glass * if data wait for DRQ = 1 BSY = 0 1160*2e192b24SSimon Glass */ 1161*2e192b24SSimon Glass res = 0; 1162*2e192b24SSimon Glass if (buflen) 1163*2e192b24SSimon Glass res = ATA_STAT_DRQ; 1164*2e192b24SSimon Glass c = atapi_wait_mask(device, ATAPI_TIME_OUT, mask, res); 1165*2e192b24SSimon Glass if ((c & mask) != res) { 1166*2e192b24SSimon Glass if (c & ATA_STAT_ERR) { 1167*2e192b24SSimon Glass err = (ide_inb(device, ATA_ERROR_REG)) >> 4; 1168*2e192b24SSimon Glass debug("atapi_issue 1 returned sense key %X status %02X\n", 1169*2e192b24SSimon Glass err, c); 1170*2e192b24SSimon Glass } else { 1171*2e192b24SSimon Glass printf("ATAPI_ISSUE: (no DRQ) after sending ccb (%x) status 0x%02x\n", 1172*2e192b24SSimon Glass ccb[0], c); 1173*2e192b24SSimon Glass err = 0xFF; 1174*2e192b24SSimon Glass } 1175*2e192b24SSimon Glass goto AI_OUT; 1176*2e192b24SSimon Glass } 1177*2e192b24SSimon Glass n = ide_inb(device, ATA_CYL_HIGH); 1178*2e192b24SSimon Glass n <<= 8; 1179*2e192b24SSimon Glass n += ide_inb(device, ATA_CYL_LOW); 1180*2e192b24SSimon Glass if (n > buflen) { 1181*2e192b24SSimon Glass printf("ERROR, transfer bytes %d requested only %d\n", n, 1182*2e192b24SSimon Glass buflen); 1183*2e192b24SSimon Glass err = 0xff; 1184*2e192b24SSimon Glass goto AI_OUT; 1185*2e192b24SSimon Glass } 1186*2e192b24SSimon Glass if ((n == 0) && (buflen < 0)) { 1187*2e192b24SSimon Glass printf("ERROR, transfer bytes %d requested %d\n", n, buflen); 1188*2e192b24SSimon Glass err = 0xff; 1189*2e192b24SSimon Glass goto AI_OUT; 1190*2e192b24SSimon Glass } 1191*2e192b24SSimon Glass if (n != buflen) { 1192*2e192b24SSimon Glass debug("WARNING, transfer bytes %d not equal with requested %d\n", 1193*2e192b24SSimon Glass n, buflen); 1194*2e192b24SSimon Glass } 1195*2e192b24SSimon Glass if (n != 0) { /* data transfer */ 1196*2e192b24SSimon Glass debug("ATAPI_ISSUE: %d Bytes to transfer\n", n); 1197*2e192b24SSimon Glass /* we transfer shorts */ 1198*2e192b24SSimon Glass n >>= 1; 1199*2e192b24SSimon Glass /* ok now decide if it is an in or output */ 1200*2e192b24SSimon Glass if ((ide_inb(device, ATA_SECT_CNT) & 0x02) == 0) { 1201*2e192b24SSimon Glass debug("Write to device\n"); 1202*2e192b24SSimon Glass ide_output_data_shorts(device, 1203*2e192b24SSimon Glass (unsigned short *) buffer, n); 1204*2e192b24SSimon Glass } else { 1205*2e192b24SSimon Glass debug("Read from device @ %p shorts %d\n", buffer, n); 1206*2e192b24SSimon Glass ide_input_data_shorts(device, 1207*2e192b24SSimon Glass (unsigned short *) buffer, n); 1208*2e192b24SSimon Glass } 1209*2e192b24SSimon Glass } 1210*2e192b24SSimon Glass udelay(5000); /* seems that some CD ROMs need this... */ 1211*2e192b24SSimon Glass mask = ATA_STAT_BUSY | ATA_STAT_ERR; 1212*2e192b24SSimon Glass res = 0; 1213*2e192b24SSimon Glass c = atapi_wait_mask(device, ATAPI_TIME_OUT, mask, res); 1214*2e192b24SSimon Glass if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) { 1215*2e192b24SSimon Glass err = (ide_inb(device, ATA_ERROR_REG) >> 4); 1216*2e192b24SSimon Glass debug("atapi_issue 2 returned sense key %X status %X\n", err, 1217*2e192b24SSimon Glass c); 1218*2e192b24SSimon Glass } else { 1219*2e192b24SSimon Glass err = 0; 1220*2e192b24SSimon Glass } 1221*2e192b24SSimon Glass AI_OUT: 1222*2e192b24SSimon Glass ide_led(DEVICE_LED(device), 0); /* LED off */ 1223*2e192b24SSimon Glass return (err); 1224*2e192b24SSimon Glass } 1225*2e192b24SSimon Glass 1226*2e192b24SSimon Glass /* 1227*2e192b24SSimon Glass * sending the command to atapi_issue. If an status other than good 1228*2e192b24SSimon Glass * returns, an request_sense will be issued 1229*2e192b24SSimon Glass */ 1230*2e192b24SSimon Glass 1231*2e192b24SSimon Glass #define ATAPI_DRIVE_NOT_READY 100 1232*2e192b24SSimon Glass #define ATAPI_UNIT_ATTN 10 1233*2e192b24SSimon Glass 1234*2e192b24SSimon Glass unsigned char atapi_issue_autoreq(int device, 1235*2e192b24SSimon Glass unsigned char *ccb, 1236*2e192b24SSimon Glass int ccblen, 1237*2e192b24SSimon Glass unsigned char *buffer, int buflen) 1238*2e192b24SSimon Glass { 1239*2e192b24SSimon Glass unsigned char sense_data[18], sense_ccb[12]; 1240*2e192b24SSimon Glass unsigned char res, key, asc, ascq; 1241*2e192b24SSimon Glass int notready, unitattn; 1242*2e192b24SSimon Glass 1243*2e192b24SSimon Glass unitattn = ATAPI_UNIT_ATTN; 1244*2e192b24SSimon Glass notready = ATAPI_DRIVE_NOT_READY; 1245*2e192b24SSimon Glass 1246*2e192b24SSimon Glass retry: 1247*2e192b24SSimon Glass res = atapi_issue(device, ccb, ccblen, buffer, buflen); 1248*2e192b24SSimon Glass if (res == 0) 1249*2e192b24SSimon Glass return 0; /* Ok */ 1250*2e192b24SSimon Glass 1251*2e192b24SSimon Glass if (res == 0xFF) 1252*2e192b24SSimon Glass return 0xFF; /* error */ 1253*2e192b24SSimon Glass 1254*2e192b24SSimon Glass debug("(auto_req)atapi_issue returned sense key %X\n", res); 1255*2e192b24SSimon Glass 1256*2e192b24SSimon Glass memset(sense_ccb, 0, sizeof(sense_ccb)); 1257*2e192b24SSimon Glass memset(sense_data, 0, sizeof(sense_data)); 1258*2e192b24SSimon Glass sense_ccb[0] = ATAPI_CMD_REQ_SENSE; 1259*2e192b24SSimon Glass sense_ccb[4] = 18; /* allocation Length */ 1260*2e192b24SSimon Glass 1261*2e192b24SSimon Glass res = atapi_issue(device, sense_ccb, 12, sense_data, 18); 1262*2e192b24SSimon Glass key = (sense_data[2] & 0xF); 1263*2e192b24SSimon Glass asc = (sense_data[12]); 1264*2e192b24SSimon Glass ascq = (sense_data[13]); 1265*2e192b24SSimon Glass 1266*2e192b24SSimon Glass debug("ATAPI_CMD_REQ_SENSE returned %x\n", res); 1267*2e192b24SSimon Glass debug(" Sense page: %02X key %02X ASC %02X ASCQ %02X\n", 1268*2e192b24SSimon Glass sense_data[0], key, asc, ascq); 1269*2e192b24SSimon Glass 1270*2e192b24SSimon Glass if ((key == 0)) 1271*2e192b24SSimon Glass return 0; /* ok device ready */ 1272*2e192b24SSimon Glass 1273*2e192b24SSimon Glass if ((key == 6) || (asc == 0x29) || (asc == 0x28)) { /* Unit Attention */ 1274*2e192b24SSimon Glass if (unitattn-- > 0) { 1275*2e192b24SSimon Glass udelay(200 * 1000); 1276*2e192b24SSimon Glass goto retry; 1277*2e192b24SSimon Glass } 1278*2e192b24SSimon Glass printf("Unit Attention, tried %d\n", ATAPI_UNIT_ATTN); 1279*2e192b24SSimon Glass goto error; 1280*2e192b24SSimon Glass } 1281*2e192b24SSimon Glass if ((asc == 0x4) && (ascq == 0x1)) { 1282*2e192b24SSimon Glass /* not ready, but will be ready soon */ 1283*2e192b24SSimon Glass if (notready-- > 0) { 1284*2e192b24SSimon Glass udelay(200 * 1000); 1285*2e192b24SSimon Glass goto retry; 1286*2e192b24SSimon Glass } 1287*2e192b24SSimon Glass printf("Drive not ready, tried %d times\n", 1288*2e192b24SSimon Glass ATAPI_DRIVE_NOT_READY); 1289*2e192b24SSimon Glass goto error; 1290*2e192b24SSimon Glass } 1291*2e192b24SSimon Glass if (asc == 0x3a) { 1292*2e192b24SSimon Glass debug("Media not present\n"); 1293*2e192b24SSimon Glass goto error; 1294*2e192b24SSimon Glass } 1295*2e192b24SSimon Glass 1296*2e192b24SSimon Glass printf("ERROR: Unknown Sense key %02X ASC %02X ASCQ %02X\n", key, asc, 1297*2e192b24SSimon Glass ascq); 1298*2e192b24SSimon Glass error: 1299*2e192b24SSimon Glass debug("ERROR Sense key %02X ASC %02X ASCQ %02X\n", key, asc, ascq); 1300*2e192b24SSimon Glass return (0xFF); 1301*2e192b24SSimon Glass } 1302*2e192b24SSimon Glass 1303*2e192b24SSimon Glass 1304*2e192b24SSimon Glass static void atapi_inquiry(block_dev_desc_t *dev_desc) 1305*2e192b24SSimon Glass { 1306*2e192b24SSimon Glass unsigned char ccb[12]; /* Command descriptor block */ 1307*2e192b24SSimon Glass unsigned char iobuf[64]; /* temp buf */ 1308*2e192b24SSimon Glass unsigned char c; 1309*2e192b24SSimon Glass int device; 1310*2e192b24SSimon Glass 1311*2e192b24SSimon Glass device = dev_desc->dev; 1312*2e192b24SSimon Glass dev_desc->type = DEV_TYPE_UNKNOWN; /* not yet valid */ 1313*2e192b24SSimon Glass dev_desc->block_read = atapi_read; 1314*2e192b24SSimon Glass 1315*2e192b24SSimon Glass memset(ccb, 0, sizeof(ccb)); 1316*2e192b24SSimon Glass memset(iobuf, 0, sizeof(iobuf)); 1317*2e192b24SSimon Glass 1318*2e192b24SSimon Glass ccb[0] = ATAPI_CMD_INQUIRY; 1319*2e192b24SSimon Glass ccb[4] = 40; /* allocation Legnth */ 1320*2e192b24SSimon Glass c = atapi_issue_autoreq(device, ccb, 12, (unsigned char *) iobuf, 40); 1321*2e192b24SSimon Glass 1322*2e192b24SSimon Glass debug("ATAPI_CMD_INQUIRY returned %x\n", c); 1323*2e192b24SSimon Glass if (c != 0) 1324*2e192b24SSimon Glass return; 1325*2e192b24SSimon Glass 1326*2e192b24SSimon Glass /* copy device ident strings */ 1327*2e192b24SSimon Glass ident_cpy((unsigned char *) dev_desc->vendor, &iobuf[8], 8); 1328*2e192b24SSimon Glass ident_cpy((unsigned char *) dev_desc->product, &iobuf[16], 16); 1329*2e192b24SSimon Glass ident_cpy((unsigned char *) dev_desc->revision, &iobuf[32], 5); 1330*2e192b24SSimon Glass 1331*2e192b24SSimon Glass dev_desc->lun = 0; 1332*2e192b24SSimon Glass dev_desc->lba = 0; 1333*2e192b24SSimon Glass dev_desc->blksz = 0; 1334*2e192b24SSimon Glass dev_desc->log2blksz = LOG2_INVALID(typeof(dev_desc->log2blksz)); 1335*2e192b24SSimon Glass dev_desc->type = iobuf[0] & 0x1f; 1336*2e192b24SSimon Glass 1337*2e192b24SSimon Glass if ((iobuf[1] & 0x80) == 0x80) 1338*2e192b24SSimon Glass dev_desc->removable = 1; 1339*2e192b24SSimon Glass else 1340*2e192b24SSimon Glass dev_desc->removable = 0; 1341*2e192b24SSimon Glass 1342*2e192b24SSimon Glass memset(ccb, 0, sizeof(ccb)); 1343*2e192b24SSimon Glass memset(iobuf, 0, sizeof(iobuf)); 1344*2e192b24SSimon Glass ccb[0] = ATAPI_CMD_START_STOP; 1345*2e192b24SSimon Glass ccb[4] = 0x03; /* start */ 1346*2e192b24SSimon Glass 1347*2e192b24SSimon Glass c = atapi_issue_autoreq(device, ccb, 12, (unsigned char *) iobuf, 0); 1348*2e192b24SSimon Glass 1349*2e192b24SSimon Glass debug("ATAPI_CMD_START_STOP returned %x\n", c); 1350*2e192b24SSimon Glass if (c != 0) 1351*2e192b24SSimon Glass return; 1352*2e192b24SSimon Glass 1353*2e192b24SSimon Glass memset(ccb, 0, sizeof(ccb)); 1354*2e192b24SSimon Glass memset(iobuf, 0, sizeof(iobuf)); 1355*2e192b24SSimon Glass c = atapi_issue_autoreq(device, ccb, 12, (unsigned char *) iobuf, 0); 1356*2e192b24SSimon Glass 1357*2e192b24SSimon Glass debug("ATAPI_CMD_UNIT_TEST_READY returned %x\n", c); 1358*2e192b24SSimon Glass if (c != 0) 1359*2e192b24SSimon Glass return; 1360*2e192b24SSimon Glass 1361*2e192b24SSimon Glass memset(ccb, 0, sizeof(ccb)); 1362*2e192b24SSimon Glass memset(iobuf, 0, sizeof(iobuf)); 1363*2e192b24SSimon Glass ccb[0] = ATAPI_CMD_READ_CAP; 1364*2e192b24SSimon Glass c = atapi_issue_autoreq(device, ccb, 12, (unsigned char *) iobuf, 8); 1365*2e192b24SSimon Glass debug("ATAPI_CMD_READ_CAP returned %x\n", c); 1366*2e192b24SSimon Glass if (c != 0) 1367*2e192b24SSimon Glass return; 1368*2e192b24SSimon Glass 1369*2e192b24SSimon Glass debug("Read Cap: LBA %02X%02X%02X%02X blksize %02X%02X%02X%02X\n", 1370*2e192b24SSimon Glass iobuf[0], iobuf[1], iobuf[2], iobuf[3], 1371*2e192b24SSimon Glass iobuf[4], iobuf[5], iobuf[6], iobuf[7]); 1372*2e192b24SSimon Glass 1373*2e192b24SSimon Glass dev_desc->lba = ((unsigned long) iobuf[0] << 24) + 1374*2e192b24SSimon Glass ((unsigned long) iobuf[1] << 16) + 1375*2e192b24SSimon Glass ((unsigned long) iobuf[2] << 8) + ((unsigned long) iobuf[3]); 1376*2e192b24SSimon Glass dev_desc->blksz = ((unsigned long) iobuf[4] << 24) + 1377*2e192b24SSimon Glass ((unsigned long) iobuf[5] << 16) + 1378*2e192b24SSimon Glass ((unsigned long) iobuf[6] << 8) + ((unsigned long) iobuf[7]); 1379*2e192b24SSimon Glass dev_desc->log2blksz = LOG2(dev_desc->blksz); 1380*2e192b24SSimon Glass #ifdef CONFIG_LBA48 1381*2e192b24SSimon Glass /* ATAPI devices cannot use 48bit addressing (ATA/ATAPI v7) */ 1382*2e192b24SSimon Glass dev_desc->lba48 = 0; 1383*2e192b24SSimon Glass #endif 1384*2e192b24SSimon Glass return; 1385*2e192b24SSimon Glass } 1386*2e192b24SSimon Glass 1387*2e192b24SSimon Glass 1388*2e192b24SSimon Glass /* 1389*2e192b24SSimon Glass * atapi_read: 1390*2e192b24SSimon Glass * we transfer only one block per command, since the multiple DRQ per 1391*2e192b24SSimon Glass * command is not yet implemented 1392*2e192b24SSimon Glass */ 1393*2e192b24SSimon Glass #define ATAPI_READ_MAX_BYTES 2048 /* we read max 2kbytes */ 1394*2e192b24SSimon Glass #define ATAPI_READ_BLOCK_SIZE 2048 /* assuming CD part */ 1395*2e192b24SSimon Glass #define ATAPI_READ_MAX_BLOCK (ATAPI_READ_MAX_BYTES/ATAPI_READ_BLOCK_SIZE) 1396*2e192b24SSimon Glass 1397*2e192b24SSimon Glass ulong atapi_read(block_dev_desc_t *block_dev, lbaint_t blknr, lbaint_t blkcnt, 1398*2e192b24SSimon Glass void *buffer) 1399*2e192b24SSimon Glass { 1400*2e192b24SSimon Glass int device = block_dev->dev; 1401*2e192b24SSimon Glass ulong n = 0; 1402*2e192b24SSimon Glass unsigned char ccb[12]; /* Command descriptor block */ 1403*2e192b24SSimon Glass ulong cnt; 1404*2e192b24SSimon Glass 1405*2e192b24SSimon Glass debug("atapi_read dev %d start " LBAF " blocks " LBAF " buffer at %lX\n", 1406*2e192b24SSimon Glass device, blknr, blkcnt, (ulong) buffer); 1407*2e192b24SSimon Glass 1408*2e192b24SSimon Glass do { 1409*2e192b24SSimon Glass if (blkcnt > ATAPI_READ_MAX_BLOCK) 1410*2e192b24SSimon Glass cnt = ATAPI_READ_MAX_BLOCK; 1411*2e192b24SSimon Glass else 1412*2e192b24SSimon Glass cnt = blkcnt; 1413*2e192b24SSimon Glass 1414*2e192b24SSimon Glass ccb[0] = ATAPI_CMD_READ_12; 1415*2e192b24SSimon Glass ccb[1] = 0; /* reserved */ 1416*2e192b24SSimon Glass ccb[2] = (unsigned char) (blknr >> 24) & 0xFF; /* MSB Block */ 1417*2e192b24SSimon Glass ccb[3] = (unsigned char) (blknr >> 16) & 0xFF; /* */ 1418*2e192b24SSimon Glass ccb[4] = (unsigned char) (blknr >> 8) & 0xFF; 1419*2e192b24SSimon Glass ccb[5] = (unsigned char) blknr & 0xFF; /* LSB Block */ 1420*2e192b24SSimon Glass ccb[6] = (unsigned char) (cnt >> 24) & 0xFF; /* MSB Block cnt */ 1421*2e192b24SSimon Glass ccb[7] = (unsigned char) (cnt >> 16) & 0xFF; 1422*2e192b24SSimon Glass ccb[8] = (unsigned char) (cnt >> 8) & 0xFF; 1423*2e192b24SSimon Glass ccb[9] = (unsigned char) cnt & 0xFF; /* LSB Block */ 1424*2e192b24SSimon Glass ccb[10] = 0; /* reserved */ 1425*2e192b24SSimon Glass ccb[11] = 0; /* reserved */ 1426*2e192b24SSimon Glass 1427*2e192b24SSimon Glass if (atapi_issue_autoreq(device, ccb, 12, 1428*2e192b24SSimon Glass (unsigned char *) buffer, 1429*2e192b24SSimon Glass cnt * ATAPI_READ_BLOCK_SIZE) 1430*2e192b24SSimon Glass == 0xFF) { 1431*2e192b24SSimon Glass return (n); 1432*2e192b24SSimon Glass } 1433*2e192b24SSimon Glass n += cnt; 1434*2e192b24SSimon Glass blkcnt -= cnt; 1435*2e192b24SSimon Glass blknr += cnt; 1436*2e192b24SSimon Glass buffer += (cnt * ATAPI_READ_BLOCK_SIZE); 1437*2e192b24SSimon Glass } while (blkcnt > 0); 1438*2e192b24SSimon Glass return (n); 1439*2e192b24SSimon Glass } 1440*2e192b24SSimon Glass 1441*2e192b24SSimon Glass /* ------------------------------------------------------------------------- */ 1442*2e192b24SSimon Glass 1443*2e192b24SSimon Glass #endif /* CONFIG_ATAPI */ 1444*2e192b24SSimon Glass 1445*2e192b24SSimon Glass U_BOOT_CMD(ide, 5, 1, do_ide, 1446*2e192b24SSimon Glass "IDE sub-system", 1447*2e192b24SSimon Glass "reset - reset IDE controller\n" 1448*2e192b24SSimon Glass "ide info - show available IDE devices\n" 1449*2e192b24SSimon Glass "ide device [dev] - show or set current device\n" 1450*2e192b24SSimon Glass "ide part [dev] - print partition table of one or all IDE devices\n" 1451*2e192b24SSimon Glass "ide read addr blk# cnt\n" 1452*2e192b24SSimon Glass "ide write addr blk# cnt - read/write `cnt'" 1453*2e192b24SSimon Glass " blocks starting at block `blk#'\n" 1454*2e192b24SSimon Glass " to/from memory address `addr'"); 1455*2e192b24SSimon Glass 1456*2e192b24SSimon Glass U_BOOT_CMD(diskboot, 3, 1, do_diskboot, 1457*2e192b24SSimon Glass "boot from IDE device", "loadAddr dev:part"); 1458