📄 cmd_ide.c
字号:
/* Reset the IDE just to be sure.
* Light LED's to show
*/
ide_led ((LED_IDE1 | LED_IDE2), 1); /* LED's on */
ide_reset ();
#ifdef CONFIG_IDE_PCMCIA
/* PCMCIA / IDE initialization for common mem space */
pcmp->pcmc_pgcrb = 0;
#endif
/* start in PIO mode 0 - most relaxed timings */
pio_mode = 0;
set_pcmcia_timing (pio_mode);
/*
* Wait for IDE to get ready.
* According to spec, this can take up to 31 seconds!
*/
for (bus=0; bus<CFG_IDE_MAXBUS; ++bus) {
int dev = bus * (CFG_IDE_MAXDEVICE / CFG_IDE_MAXBUS);
printf ("Bus %d: ", bus);
ide_bus_ok[bus] = 0;
/* Select device
*/
udelay (100000); /* 100 ms */
outb (dev, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(dev));
udelay (100000); /* 100 ms */
i = 0;
do {
udelay (10000); /* 10 ms */
c = inb (dev, ATA_STATUS);
++i;
if (i > (ATA_RESET_TIME * 100)) {
puts ("** Timeout **\n");
ide_led ((LED_IDE1 | LED_IDE2), 0); /* LED's off */
return;
}
if ((i >= 100) && ((i%100)==0)) {
putc ('.');
}
} while (c & ATA_STAT_BUSY);
if (c & (ATA_STAT_BUSY | ATA_STAT_FAULT)) {
printf ("Status 0x%02x ", c);
} else if ((c & ATA_STAT_READY) == 0) {
puts ("not available ");
} else {
puts ("OK ");
ide_bus_ok[bus] = 1;
}
}
putc ('\n');
ide_led ((LED_IDE1 | LED_IDE2), 0); /* LED's off */
curr_device = -1;
for (i=0; i<CFG_IDE_MAXDEVICE; ++i) {
#ifdef CONFIG_IDE_LED
int led = (IDE_BUS(i) == 0) ? LED_IDE1 : LED_IDE2;
#endif
if (!ide_bus_ok[IDE_BUS(i)])
continue;
ide_led (led, 1); /* LED on */
ide_ident (i);
ide_led (led, 0); /* LED off */
ide_print (i);
/* make first available device current */
if ((ide_device[i].size > 0) && (curr_device < 0)) {
curr_device = i;
}
}
}
/* ------------------------------------------------------------------------- */
#ifdef CONFIG_IDE_PCMCIA
static void
set_pcmcia_timing (int pmode)
{
volatile immap_t *immr = (immap_t *)CFG_IMMR;
volatile pcmconf8xx_t *pcmp = &(immr->im_pcmcia);
ulong timings;
timings = PCMCIA_SHT(pio_config_clk[pmode].t_hold)
| PCMCIA_SST(pio_config_clk[pmode].t_setup)
| PCMCIA_SL (pio_config_clk[pmode].t_length)
;
/* IDE 0
*/
pcmp->pcmc_pbr0 = CFG_PCMCIA_PBR0;
pcmp->pcmc_por0 = CFG_PCMCIA_POR0
#if (CFG_PCMCIA_POR0 != 0)
| timings
#endif
;
pcmp->pcmc_pbr1 = CFG_PCMCIA_PBR1;
pcmp->pcmc_por1 = CFG_PCMCIA_POR1
#if (CFG_PCMCIA_POR1 != 0)
| timings
#endif
;
pcmp->pcmc_pbr2 = CFG_PCMCIA_PBR2;
pcmp->pcmc_por2 = CFG_PCMCIA_POR2
#if (CFG_PCMCIA_POR2 != 0)
| timings
#endif
;
pcmp->pcmc_pbr3 = CFG_PCMCIA_PBR3;
pcmp->pcmc_por3 = CFG_PCMCIA_POR3
#if (CFG_PCMCIA_POR3 != 0)
| timings
#endif
;
/* IDE 1
*/
pcmp->pcmc_pbr4 = CFG_PCMCIA_PBR4;
pcmp->pcmc_por4 = CFG_PCMCIA_POR4
#if (CFG_PCMCIA_POR4 != 0)
| timings
#endif
;
pcmp->pcmc_pbr5 = CFG_PCMCIA_PBR5;
pcmp->pcmc_por5 = CFG_PCMCIA_POR5
#if (CFG_PCMCIA_POR5 != 0)
| timings
#endif
;
pcmp->pcmc_pbr6 = CFG_PCMCIA_PBR6;
pcmp->pcmc_por6 = CFG_PCMCIA_POR6
#if (CFG_PCMCIA_POR6 != 0)
| timings
#endif
;
pcmp->pcmc_pbr7 = CFG_PCMCIA_PBR7;
pcmp->pcmc_por7 = CFG_PCMCIA_POR7
#if (CFG_PCMCIA_POR7 != 0)
| timings
#endif
;
}
#endif /* CONFIG_IDE_PCMCIA */
/* ------------------------------------------------------------------------- */
static void __inline__
outb(int dev, int port, unsigned char val)
{
/* Ensure I/O operations complete */
__asm__ volatile("eieio");
*((uchar *)(ATA_CURR_BASE(dev)+port)) = val;
#if 0
printf ("OUTB: 0x%08lx <== 0x%02x\n", ATA_CURR_BASE(dev)+port, val);
#endif
}
static unsigned char __inline__
inb(int dev, int port)
{
uchar val;
/* Ensure I/O operations complete */
__asm__ volatile("eieio");
val = *((uchar *)(ATA_CURR_BASE(dev)+port));
#if 0
printf ("INB: 0x%08lx ==> 0x%02x\n", ATA_CURR_BASE(dev)+port, val);
#endif
return (val);
}
static void
input_swap_data(int dev, ulong *sect_buf, int words)
{
volatile ushort *pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
ushort *dbuf = (ushort *)sect_buf;
while (words--) {
*dbuf++ = ld_le16(pbuf);
*dbuf++ = ld_le16(pbuf);
}
}
static void
output_data(int dev, ulong *sect_buf, int words)
{
ushort *dbuf;
volatile ushort *pbuf;
pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
dbuf = (ushort *)sect_buf;
while (words--) {
__asm__ volatile ("eieio");
*pbuf = *dbuf++;
__asm__ volatile ("eieio");
*pbuf = *dbuf++;
}
}
static void
input_data(int dev, ulong *sect_buf, int words)
{
ushort *dbuf;
volatile ushort *pbuf;
pbuf = (ushort *)(ATA_CURR_BASE(dev)+ATA_DATA_REG);
dbuf = (ushort *)sect_buf;
while (words--) {
__asm__ volatile ("eieio");
*dbuf++ = *pbuf;
__asm__ volatile ("eieio");
*dbuf++ = *pbuf;
}
}
/* -------------------------------------------------------------------------
*/
static void ide_ident (int device)
{
ulong iobuf[ATA_SECTORWORDS];
unsigned char c;
hd_driveid_t *iop = (hd_driveid_t *)iobuf;
ide_dev_id_t *idp = &(ide_device[device]);
#if 0
int mode, cycle_time;
#endif
printf (" Device %d: ", device);
ide_led (DEVICE_LED(device), 1); /* LED on */
/* Select device
*/
outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
/* Start Ident Command
*/
outb (device, ATA_COMMAND, ATA_CMD_IDENT);
/* Wait for completion
*/
c = ide_wait (device, 100);
ide_led (DEVICE_LED(device), 0); /* LED off */
if (((c & ATA_STAT_READY) == 0) ||
((c & (ATA_STAT_FAULT|ATA_STAT_ERR)) != 0) ) {
idp->size = 0;
idp->model[0] = idp->serial_no[0] = '\0';
return;
}
input_swap_data (device, iobuf, ATA_SECTORWORDS);
trim_trail (iop->model, sizeof(iop->model));
trim_trail (iop->serial_no, sizeof(iop->serial_no));
#if 0
/*
* Drive PIO mode autoselection
*/
mode = iop->tPIO;
printf ("tPIO = 0x%02x = %d\n",mode, mode);
if (mode > 2) { /* 2 is maximum allowed tPIO value */
mode = 2;
PRINTF ("Override tPIO -> 2\n");
}
if (iop->field_valid & 2) { /* drive implements ATA2? */
PRINTF ("Drive implements ATA2\n");
if (iop->capability & 8) { /* drive supports use_iordy? */
cycle_time = iop->eide_pio_iordy;
} else {
cycle_time = iop->eide_pio;
}
PRINTF ("cycle time = %d\n", cycle_time);
mode = 4;
if (cycle_time > 120) mode = 3; /* 120 ns for PIO mode 4 */
if (cycle_time > 180) mode = 2; /* 180 ns for PIO mode 3 */
if (cycle_time > 240) mode = 1; /* 240 ns for PIO mode 4 */
if (cycle_time > 383) mode = 0; /* 383 ns for PIO mode 4 */
}
printf ("PIO mode to use: PIO %d\n", mode);
#endif
/* swap shorts */
idp->size = (iop->lba_capacity << 16) | (iop->lba_capacity >> 16);
strncpy (idp->model, iop->model, sizeof(idp->model));
strncpy (idp->serial_no, iop->serial_no, sizeof(idp->serial_no));
}
/* ------------------------------------------------------------------------- */
static void ide_print (int device)
{
ldiv_t mb, gb;
ide_dev_id_t *idp = &(ide_device[device]);
if (idp->size == 0) {
puts ("not available\n");
return;
}
mb = ldiv(idp->size, ((1024 * 1024) / 512)); /* MB */
/* round to 1 digit */
mb.rem *= 10 * 512;
mb.rem += 512 * 1024;
mb.rem /= 1024 * 1024;
gb = ldiv(10 * mb.quot + mb.rem, 10240);
gb.rem += 512;
gb.rem /= 1024;
printf ("Model: %s Serial #: %s ", idp->model, idp->serial_no);
printf ("Capacity: %ld.%ld MB = %ld.%ld GB\n",
mb.quot, mb.rem, gb.quot, gb.rem);
}
/* ------------------------------------------------------------------------- */
ulong ide_read (int device, ulong blknr, ulong blkcnt, ulong *buffer)
{
ulong n = 0;
unsigned char c;
ide_led (DEVICE_LED(device), 1); /* LED on */
/* Select device
*/
outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
while (blkcnt-- > 0) {
c = ide_wait (device, 500);
if (c & ATA_STAT_BUSY) {
printf ("IDE read: device %d not ready\n", device);
goto RD_OUT;
}
outb (device, ATA_SECT_CNT, 1);
outb (device, ATA_LBA_LOW, (blknr >> 0) & 0xFF);
outb (device, ATA_LBA_MID, (blknr >> 8) & 0xFF);
outb (device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF);
outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
outb (device, ATA_COMMAND, ATA_CMD_READ);
udelay (50);
c = ide_wait (device, 500); /* can't take over 500 ms */
if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) {
printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
device, blknr, c);
goto RD_OUT;
}
input_data (device, buffer, ATA_SECTORWORDS);
(void) inb (device, ATA_STATUS); /* clear IRQ */
++n;
++blknr;
buffer += ATA_SECTORWORDS;
}
RD_OUT:
ide_led (DEVICE_LED(device), 0); /* LED off */
return (n);
}
/* ------------------------------------------------------------------------- */
ulong ide_write (int device, ulong blknr, ulong blkcnt, ulong *buffer)
{
ulong n = 0;
unsigned char c;
ide_led (DEVICE_LED(device), 1); /* LED on */
/* Select device
*/
outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
while (blkcnt-- > 0) {
c = ide_wait (device, 500);
if (c & ATA_STAT_BUSY) {
printf ("IDE read: device %d not ready\n", device);
goto WR_OUT;
}
outb (device, ATA_SECT_CNT, 1);
outb (device, ATA_LBA_LOW, (blknr >> 0) & 0xFF);
outb (device, ATA_LBA_MID, (blknr >> 8) & 0xFF);
outb (device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF);
outb (device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
outb (device, ATA_COMMAND, ATA_CMD_WRITE);
udelay (50);
c = ide_wait (device, 500); /* can't take over 500 ms */
if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) {
printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
device, blknr, c);
goto WR_OUT;
}
output_data (device, buffer, ATA_SECTORWORDS);
c = inb (device, ATA_STATUS); /* clear IRQ */
++n;
++blknr;
buffer += ATA_SECTORWORDS;
}
WR_OUT:
ide_led (DEVICE_LED(device), 0); /* LED off */
return (n);
}
/* ------------------------------------------------------------------------- */
/* Trim trailing blanks, and NUL-terminate string
*/
static void trim_trail (unsigned char *str, unsigned int len)
{
unsigned char *p = str + len - 1;
while (len-- > 0) {
*p-- = '\0';
if (*p != ' ') {
return;
}
}
}
/* ------------------------------------------------------------------------- */
/*
* Wait until Busy bit is off, or timeout (in ms)
* Return last status
*/
static uchar ide_wait (int dev, ulong t)
{
ulong delay = 10 * t; /* poll every 100 us */
uchar c;
while ((c = inb(dev, ATA_STATUS)) & ATA_STAT_BUSY) {
udelay (100);
if (delay-- == 0) {
break;
}
}
return (c);
}
/* ------------------------------------------------------------------------- */
#ifdef CONFIG_IDE_RESET
static void ide_reset (void)
{
int i;
volatile immap_t *immr = (immap_t *)CFG_IMMR;
curr_device = -1;
for (i=0; i<CFG_IDE_MAXBUS; ++i)
ide_bus_ok[i] = 0;
for (i=0; i<CFG_IDE_MAXDEVICE; ++i)
ide_device[i].size = 0;
#if defined(CFG_PC_IDE_RESET)
/* Configure PC for IDE Reset Pin
*/
immr->im_ioport.iop_pcdat &= ~(CFG_PC_IDE_RESET); /* Set reset bit */
immr->im_ioport.iop_pcpar &= ~(CFG_PC_IDE_RESET);
immr->im_ioport.iop_pcso &= ~(CFG_PC_IDE_RESET);
immr->im_ioport.iop_pcdir |= CFG_PC_IDE_RESET; /* Make output */
/* assert IDE RESET signal */
immr->im_ioport.iop_pcdat &= ~(CFG_PC_IDE_RESET);
udelay (20000);
/* de-assert RESET signal of IDE */
immr->im_ioport.iop_pcdat |= CFG_PC_IDE_RESET;
#else
#error IDE reset pin not configured
#endif
udelay (100000);
}
#endif /* CONFIG_IDE_RESET */
/* ------------------------------------------------------------------------- */
#ifdef CONFIG_IDE_LED
static uchar led_buffer = 0; /* Buffer for current LED status */
static void ide_led (uchar led, uchar status)
{
uchar *led_port = LED_PORT;
if (status) { /* switch LED on */
led_buffer |= led;
} else { /* switch LED off */
led_buffer &= ~led;
}
*led_port = led_buffer;
}
#endif /* CONFIG_IDE_LED */
/* ------------------------------------------------------------------------- */
#endif /* CONFIG_COMMANDS & CFG_CMD_IDE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -