*/
#include <mpc8xx_irq.h>
#include <ppcboot.h>
+#include <config.h> /* for PIO mode selection */
#include <command.h>
#include <image.h>
#include <ide.h>
#include <cmd_disk.h>
#include <mpc8xx.h>
+/* stdlib.h causes some compatibility problems; should fixe these! -- wd */
+#ifndef __ldiv_t_defined
+typedef struct {
+ long int quot; /* Quotient */
+ long int rem; /* Remainder */
+} ldiv_t;
+extern ldiv_t ldiv (long int __numer, long int __denom);
+# define __ldiv_t_defined 1
+#endif
+
+#ifdef DEBUG
+#define PRINTF(fmt,args...) do { \
+ printf (fmt ,##args); \
+ } while (0)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
#if (CONFIG_COMMANDS & CFG_CMD_IDE)
+/* Timings for IDE Interface
+ *
+ * SETUP / LENGTH / HOLD - cycles valid for 50 MHz clk
+ * 70 165 30 PIO-Mode 0, [ns]
+ * 4 9 2 [Cycles]
+ * 50 125 20 PIO-Mode 1, [ns]
+ * 3 7 2 [Cycles]
+ * 30 100 15 PIO-Mode 2, [ns]
+ * 2 6 1 [Cycles]
+ * 30 80 10 PIO-Mode 3, [ns]
+ * 2 5 1 [Cycles]
+ * 25 70 10 PIO-Mode 4, [ns]
+ * 2 4 1 [Cycles]
+ */
+
+const static pio_config_t pio_config_ns [IDE_MAX_PIO_MODE+1] =
+{
+ /* Setup Length Hold */
+ { 70, 165, 30 }, /* PIO-Mode 0, [ns] */
+ { 50, 125, 20 }, /* PIO-Mode 1, [ns] */
+ { 30, 101, 15 }, /* PIO-Mode 2, [ns] */
+ { 30, 80, 10 }, /* PIO-Mode 3, [ns] */
+ { 25, 70, 10 }, /* PIO-Mode 4, [ns] */
+};
+
+static pio_config_t pio_config_clk [IDE_MAX_PIO_MODE+1];
+
+#ifndef CFG_PIO_MODE
+#define CFG_PIO_MODE 0 /* use a relaxed default */
+#endif
+static int pio_mode = CFG_PIO_MODE;
+
+/* Make clock cycles and always round up */
+
+#define PCMCIA_MK_CLKS( t, T ) (( (t) * (T) + 999U ) / 1000U )
+
/* ------------------------------------------------------------------------- */
/*
static void input_data(int dev, ulong *sect_buf, int words);
static void output_data(int dev, ulong *sect_buf, int words);
static void trim_trail (unsigned char *str, unsigned int len);
+static void set_pcmcia_timing (int pmode);
/* ------------------------------------------------------------------------- */
return;
case 2:
if (strncmp(argv[1],"res",3) == 0) {
- printf ("\nReset IDE on PCMCIA " PCMCIA_SLOT_MSG ": ");
+ puts ("\nReset IDE on PCMCIA " PCMCIA_SLOT_MSG ": ");
- ide_init();
+ ide_init(bd);
return;
} else if (strncmp(argv[1],"inf",3) == 0) {
int i;
- printf ("\n");
+ putc ('\n');
for (i=0; i<IDE_MAXDEVICE; ++i) {
printf ("IDE device %d: ", i);
} else if (strncmp(argv[1],"dev",3) == 0) {
if ((curr_device < 0) || (curr_device >= IDE_MAXDEVICE)) {
- printf ("\nno IDE devices available\n");
+ puts ("\nno IDE devices available\n");
return;
}
printf ("\nIDE device %d: ", curr_device);
if (ide_device[dev].size) {
++ok;
if (dev)
- printf ("\n");
+ putc ('\n');
print_part_mac (dev);
}
}
if (!ok)
- printf ("\nno IDE devices available\n");
+ puts ("\nno IDE devices available\n");
return;
}
printf ("Usage:\n%s\n", cmdtp->usage);
printf ("\nIDE device %d: ", dev);
if (dev >= IDE_MAXDEVICE) {
- printf ("unknown device\n");
+ puts ("unknown device\n");
return;
}
curr_device = dev;
- printf ("... is now current device\n");
+ puts ("... is now current device\n");
return;
} else if (strncmp(argv[1],"part",4) == 0) {
printf ("\nIDE device %d not available\n", dev);
}
return;
+#if 0
+ } else if (strncmp(argv[1],"pio",4) == 0) {
+ int mode = (int)simple_strtoul(argv[2], NULL, 10);
+
+ if ((mode >= 0) && (mode <= IDE_MAX_PIO_MODE)) {
+ puts ("\nSetting ");
+ pio_mode = mode;
+ ide_init (bd);
+ } else {
+ printf ("\nInvalid PIO mode %d (0 ... %d only)\n",
+ mode, IDE_MAX_PIO_MODE);
+ }
+ return;
+#endif
}
printf ("Usage:\n%s\n", cmdtp->usage);
}
if (!boot_device) {
- printf ("\n** No boot device **\n");
+ puts ("\n** No boot device **\n");
return;
}
if (*ep) {
if (*ep != ':') {
- printf ("\n** Invalid boot device, use `dev[:part]' **\n");
+ puts ("\n** Invalid boot device, use `dev[:part]' **\n");
return;
}
part = simple_strtoul(++ep, NULL, 16);
printf ("\nLoading from IDE device %d, partition %d: "
"Name: %.32s Type: %.32s\n",
dev, part, info.name, info.type);
-#ifdef DEBUG
- printf ("First Block: %ld, # of blocks: %ld, Block Size: %ld\n",
+
+ PRINTF ("First Block: %ld, # of blocks: %ld, Block Size: %ld\n",
info.start, info.size, info.blksz);
-#endif
if (ide_read (dev, info.start, 1, (ulong *)addr) != 1) {
printf ("** Read error on %d:%d\n", dev, part);
/* ------------------------------------------------------------------------- */
-void ide_init (void)
+void ide_init (bd_t *bd)
{
- immap_t *immr = (immap_t *)CFG_IMMR;
+ volatile immap_t *immr = (immap_t *)CFG_IMMR;
volatile pcmconf8xx_t *pcmp = &(immr->im_pcmcia);
unsigned char c;
int i, bus;
- /* Configure PC for IDE Reset Pin
- */
- immr->im_ioport.iop_pcdat &= ~(PC_IDE_RESET); /* Set reset bit */
- immr->im_ioport.iop_pcpar &= ~(PC_IDE_RESET);
- immr->im_ioport.iop_pcso &= ~(PC_IDE_RESET);
- immr->im_ioport.iop_pcdir |= PC_IDE_RESET; /* Make output */
+ /* Initialize PIO timing tables */
+ for (i=0; i <= IDE_MAX_PIO_MODE; ++i) {
+ pio_config_clk[i].t_setup = PCMCIA_MK_CLKS(pio_config_ns[i].t_setup,
+ bd->bi_busfreq);
+ pio_config_clk[i].t_length = PCMCIA_MK_CLKS(pio_config_ns[i].t_length,
+ bd->bi_busfreq);
+ pio_config_clk[i].t_hold = PCMCIA_MK_CLKS(pio_config_ns[i].t_hold,
+ bd->bi_busfreq);
+ PRINTF ("PIO Mode %d: setup=%2d ns/%d clk"
+ " len=%3d ns/%d clk"
+ " hold=%2d ns/%d clk\n",
+ i,
+ pio_config_ns[i].t_setup, pio_config_clk[i].t_setup,
+ pio_config_ns[i].t_length, pio_config_clk[i].t_length,
+ pio_config_ns[i].t_hold, pio_config_clk[i].t_hold);
+ }
+
/* Reset the IDE just to be sure.
* Light LED's to show
/* PCMCIA / IDE initialization for common mem space */
pcmp->pcmc_pgcrb = 0;
- /* IDE 1
- */
- pcmp->pcmc_pbr0 = CFG_PCMCIA_PBR0;
- pcmp->pcmc_por0 = CFG_PCMCIA_POR0;
-
- pcmp->pcmc_pbr1 = CFG_PCMCIA_PBR1;
- pcmp->pcmc_por1 = CFG_PCMCIA_POR1;
-
- pcmp->pcmc_pbr2 = CFG_PCMCIA_PBR2;
- pcmp->pcmc_por2 = CFG_PCMCIA_POR2;
-
- pcmp->pcmc_pbr3 = CFG_PCMCIA_PBR3;
- pcmp->pcmc_por3 = CFG_PCMCIA_POR3;
-
- /* IDE 2
- */
- pcmp->pcmc_pbr4 = CFG_PCMCIA_PBR4;
- pcmp->pcmc_por4 = CFG_PCMCIA_POR4;
-
- pcmp->pcmc_pbr5 = CFG_PCMCIA_PBR5;
- pcmp->pcmc_por5 = CFG_PCMCIA_POR5;
-
- pcmp->pcmc_pbr6 = CFG_PCMCIA_PBR6;
- pcmp->pcmc_por6 = CFG_PCMCIA_POR6;
-
- pcmp->pcmc_pbr7 = CFG_PCMCIA_PBR7;
- pcmp->pcmc_por7 = CFG_PCMCIA_POR7;
+ /* start in PIO mode 0 - most relaxed timings */
+ pio_mode = 0;
+ set_pcmcia_timing (pio_mode);
/*
* Wait for IDE to get ready.
/* Select device
*/
- udelay (20000); /* 20 ms */
+ udelay (100000); /* 100 ms */
outb (dev, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(dev));
- udelay (10000);
+ udelay (100000); /* 100 ms */
i = 0;
do {
c = inb (dev, ATA_STATUS);
++i;
if (i > (ATA_RESET_TIME * 100)) {
- printf ("** Timeout **\n");
+ puts ("** Timeout **\n");
ide_led ((LED_IDE1 | LED_IDE2), 0); /* LED's off */
return;
}
if ((i >= 100) && ((i%100)==0)) {
- printf (".");
+ 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) {
- printf ("not available ");
+ puts ("not available ");
} else {
- printf ("OK ");
+ puts ("OK ");
ide_bus_ok[bus] = 1;
}
}
- printf ("\n");
+ putc ('\n');
ide_led ((LED_IDE1 | LED_IDE2), 0); /* LED's off */
/* ------------------------------------------------------------------------- */
+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
+ ;
+
+}
+
+/* ------------------------------------------------------------------------- */
+
static void __inline__
outb(int dev, int port, unsigned char val)
{
}
}
-/* ------------------------------------------------------------------------- */
-
+/* -------------------------------------------------------------------------
+ */
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);
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);
static void ide_print (int device)
{
+ ldiv_t mb, gb;
ide_dev_id_t *idp = &(ide_device[device]);
if (idp->size == 0) {
- printf ("not available\n");
+ 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: %lu MB = %lu GB\n",
- (idp->size / 2) >> 10, (idp->size / 2) >> 20);
+ printf ("Capacity: %ld.%ld MB = %ld.%ld GB\n",
+ mb.quot, mb.rem, gb.quot, gb.rem);
}
/* ------------------------------------------------------------------------- */
static void ide_reset (void)
{
- immap_t *immr = (immap_t *)CFG_IMMR;
+ int i;
+ volatile immap_t *immr = (immap_t *)CFG_IMMR;
+
+ curr_device = -1;
+ for (i=0; i<IDE_MAXBUS; ++i)
+ ide_bus_ok[i] = 0;
+ for (i=0; i<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 &= ~(PC_IDE_RESET);
+ immr->im_ioport.iop_pcdat &= ~(CFG_PC_IDE_RESET);
udelay (20000);
/* de-assert RESET signal of IDE */
- immr->im_ioport.iop_pcdat |= PC_IDE_RESET;
+ immr->im_ioport.iop_pcdat |= CFG_PC_IDE_RESET;
+#else
+#error IDE reset pin not configured
+#endif
udelay (100000);
}